From 44399bf7f5bcd6e7a0de9a8bc7038efdb51f1629 Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Sun, 30 May 2021 00:33:10 -0400 Subject: [PATCH] Suggested changes, small opts --- code/__defines/_planes+layers.dm | 1 + code/_helpers/unsorted.dm | 16 ---- code/datums/chat_message.dm | 109 +++++++++++++++++--------- code/game/atoms.dm | 4 +- code/modules/client/client defines.dm | 2 +- code/modules/emotes/emote_mob.dm | 2 +- code/modules/mob/living/say.dm | 107 +++++++++++++------------ code/modules/mob/mob.dm | 2 +- 8 files changed, 132 insertions(+), 111 deletions(-) diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index 111349d887c..551e94183c1 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -124,6 +124,7 @@ What is the naming convention for planes or layers? #define PLANE_PLANETLIGHTING 4 //Lighting on planets #define PLANE_LIGHTING 5 //Where the lighting (and darkness) lives #define PLANE_LIGHTING_ABOVE 6 //For glowy eyes etc. that shouldn't be affected by darkness +#define PLANE_RUNECHAT 7 #define PLANE_GHOSTS 10 //Spooooooooky ghooooooosts #define PLANE_AI_EYE 11 //The AI eye lives here diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index fe2b51195ab..5701521ec52 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -1691,19 +1691,3 @@ GLOBAL_REAL_VAR(list/stack_trace_storage) return "CLIENT: [D]" else return "Unknown data type: [D]" - -/* - is_holder_of(): Returns 1 if A is a holder of B, meaning, A is B.loc or B.loc.loc or B.loc.loc.loc etc. - This is essentially the same as calling (locate(B) in A), but a little clearer as to what you're doing, and locate() has been known to bug out or be extremely slow in the past. -*/ -/proc/is_holder_of(const/atom/movable/A, const/atom/movable/B) - if(istype(A, /turf) || istype(B, /turf)) //Clicking on turfs is a common thing and turfs are also not /atom/movable, so it was causing the assertion to fail. - return 0 - ASSERT(istype(A) && istype(B)) - var/atom/O = B - while(O && !isturf(O)) - if(O == A) - return 1 - O = O.loc - return 0 - \ No newline at end of file diff --git a/code/datums/chat_message.dm b/code/datums/chat_message.dm index 0668380059d..5cd8a9babe7 100644 --- a/code/datums/chat_message.dm +++ b/code/datums/chat_message.dm @@ -14,6 +14,9 @@ #define CHAT_MESSAGE_OBJ 2 #define WXH_TO_HEIGHT(x) text2num(copytext((x), findtextEx((x), "x") + 1)) // thanks lummox +#define CHAT_RUNE_EMOTE 0x1 +#define CHAT_RUNE_RADIO 0x2 + /** * # Chat Message Overlay * @@ -22,7 +25,17 @@ */ // Cached runechat icon -var/runechat_icon = null +var/list/runechat_image_cache = list() + + +/hook/startup/proc/runechat_images() + var/image/radio_image = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio") + runechat_image_cache["radio"] = radio_image + + var/image/emote_image = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "emote") + runechat_image_cache["emote"] = emote_image + + return TRUE /datum/chatmessage /// The visual element of the chat messsage @@ -35,6 +48,8 @@ var/runechat_icon = null var/scheduled_destruction /// Contains the approximate amount of lines for height decay var/approx_lines + /// If we are currently processing animation and cleanup at EOL + var/ending_life /** * Constructs a chat message overlay @@ -48,7 +63,7 @@ var/runechat_icon = null */ /datum/chatmessage/New(text, atom/target, mob/owner, list/extra_classes = null, lifespan = CHAT_MESSAGE_LIFESPAN) . = ..() - if (!istype(target)) + if(!istype(target)) CRASH("Invalid target given for chatmessage") if(!istype(owner) || QDELETED(owner) || !owner.client) stack_trace("/datum/chatmessage created with [isnull(owner) ? "null" : "invalid"] mob owner") @@ -57,10 +72,12 @@ var/runechat_icon = null generate_image(text, target, owner, extra_classes, lifespan) /datum/chatmessage/Destroy() - if (owned_by) - owned_by.seen_messages.Remove(src) + if(owned_by) + LAZYREMOVEASSOC(owned_by.seen_messages, message_loc, src) owned_by.images.Remove(message) UnregisterSignal(owned_by, COMSIG_PARENT_QDELETING) + if(message_loc) + UnregisterSignal(message_loc, COMSIG_PARENT_QDELETING) owned_by = null message_loc = null message = null @@ -78,20 +95,21 @@ var/runechat_icon = null */ /datum/chatmessage/proc/generate_image(text, atom/target, mob/owner, list/extra_classes, lifespan) set waitfor = FALSE + // Register client who owns this message owned_by = owner.client RegisterSignal(owned_by, COMSIG_PARENT_QDELETING, .proc/qdel_self) - var/erp_king = owned_by.is_preference_enabled(/datum/client_preference/runechat_long_messages) - var/maxlen = erp_king ? CHAT_MESSAGE_EXT_LENGTH : CHAT_MESSAGE_LENGTH - var/msgwidth = erp_king ? CHAT_MESSAGE_EXT_WIDTH : CHAT_MESSAGE_WIDTH + var/extra_length = owned_by.is_preference_enabled(/datum/client_preference/runechat_long_messages) + var/maxlen = extra_length ? CHAT_MESSAGE_EXT_LENGTH : CHAT_MESSAGE_LENGTH + var/msgwidth = extra_length ? CHAT_MESSAGE_EXT_WIDTH : CHAT_MESSAGE_WIDTH // Clip message - if (length_char(text) > maxlen) + if(length_char(text) > maxlen) text = copytext_char(text, 1, maxlen + 1) + "..." // BYOND index moment // Calculate target color if not already present - if (!target.chat_color || target.chat_color_name != target.name) + 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_name = target.name @@ -102,56 +120,68 @@ var/runechat_icon = null // Reject whitespace var/static/regex/whitespace = new(@"^\s*$") - if (whitespace.Find(text)) + if(whitespace.Find(text)) qdel(src) return // Non mobs speakers can be small - if (!ismob(target)) + if(!ismob(target)) extra_classes |= "small" // If we heard our name, it's important + // Differnt from our own system of name emphasis, maybe unify var/list/names = splittext(owner.name, " ") for (var/word in names) text = replacetext(text, word, "[word]") - // Append radio icon if comes from a radio - if (extra_classes.Find("spoken_into_radio")) - if (!runechat_icon) - var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio") - runechat_icon = "\icon[r_icon] " - text = runechat_icon + text + var/list/prefixes + + // Append prefixes + if(extra_classes.Find("virtual-speaker")) + LAZYADD(prefixes, "\icon[runechat_image_cache["radio"]]") + if(extra_classes.Find("emote")) + // Icon on both ends? + //var/image/I = runechat_image_cache["emote"] + //text = "\icon[I][text]\icon[I]" + + // Icon on one end? + //LAZYADD(prefixes, "\icon[runechat_image_cache["emote"]]") + + // Asterisks instead? + text = "* [text] *" + + text = "[prefixes?.Join(" ")][text]" // We dim italicized text to make it more distinguishable from regular text var/tgt_color = extra_classes.Find("italics") ? target.chat_color_darkened : target.chat_color + // Approximate text height - // Note we have to replace HTML encoded metacharacters otherwise MeasureText will return a zero height - // BYOND Bug #2563917 - // Construct text - var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g") var/complete_text = "[text]" - var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, msgwidth)) + var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(complete_text, null, msgwidth)) approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT) // Translate any existing messages upwards, apply exponential decay factors to timers message_loc = target - if (owned_by.seen_messages) + RegisterSignal(message_loc, COMSIG_PARENT_QDELETING, .proc/qdel_self) + if(owned_by.seen_messages) var/idx = 1 var/combined_height = approx_lines - for(var/msg in owned_by.seen_messages) + for(var/msg in owned_by.seen_messages[message_loc]) var/datum/chatmessage/m = msg animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME) combined_height += m.approx_lines - var/sched_remaining = m.scheduled_destruction - world.time - if (sched_remaining > CHAT_MESSAGE_SPAWN_TIME) - var/remaining_time = (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height) - m.scheduled_destruction = world.time + remaining_time - spawn(remaining_time) - m.end_of_life() + + if(!m.ending_life) // Don't bother! + var/sched_remaining = m.scheduled_destruction - world.time + if(sched_remaining > CHAT_MESSAGE_SPAWN_TIME) + var/remaining_time = (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height) + m.scheduled_destruction = world.time + remaining_time + spawn(remaining_time) + m.end_of_life() // Build message image message = image(loc = message_loc, layer = ABOVE_MOB_LAYER) - message.plane = PLANE_LIGHTING_ABOVE + message.plane = PLANE_RUNECHAT message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART message.alpha = 0 message.pixel_y = owner.bound_height * 0.95 @@ -160,11 +190,11 @@ var/runechat_icon = null message.maptext_x = (msgwidth - owner.bound_width) * -0.5 message.maptext = complete_text - if (is_holder_of(owner, target)) // Special case, holding an atom speaking (pAI, recorder...) + if(owner.contains(target)) // Special case, holding an atom speaking (pAI, recorder...) message.plane = PLANE_PLAYER_HUD_ABOVE // View the message - owned_by.seen_messages.Add(src) + LAZYADDASSOCLIST(owned_by.seen_messages, message_loc, src) owned_by.images += message animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME) @@ -177,8 +207,9 @@ var/runechat_icon = null * Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion */ /datum/chatmessage/proc/end_of_life(fadetime = CHAT_MESSAGE_EOL_FADE) - if (gc_destroyed) + if(gc_destroyed || ending_life) return + ending_life = TRUE animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL) spawn(fadetime) qdel(src) @@ -207,7 +238,7 @@ var/runechat_icon = null return // Check for virtual speakers (aka hearing a message through a radio) - if (existing_extra_classes.Find("radio")) + if(existing_extra_classes.Find("radio")) return /* Not currently necessary @@ -219,17 +250,17 @@ var/runechat_icon = null var/list/extra_classes = list() extra_classes += existing_extra_classes - if (italics) + if(italics) extra_classes |= "italics" - if (client.is_preference_enabled(/datum/client_preference/runechat_border)) + if(client.is_preference_enabled(/datum/client_preference/runechat_border)) extra_classes |= "black_outline" var/dist = get_dist(src, speaker) switch (dist) - if (4 to 5) + if(4 to 5) extra_classes |= "small" - if (5 to 16) + if(5 to 16) extra_classes |= "very_small" // Display visual above source diff --git a/code/game/atoms.dm b/code/game/atoms.dm index f4117d37e84..fc27bb9f4e0 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -523,7 +523,7 @@ if(M.see_invisible >= invisibility && MOB_CAN_SEE_PLANE(M, plane)) M.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE) if(runemessage != -1) - M.create_chat_message(src, "* [runemessage || message] *", FALSE, list("emote"), audible = FALSE) + M.create_chat_message(src, "[runemessage]", FALSE, list("emote"), audible = FALSE) else if(blind_message) M.show_message(blind_message, AUDIBLE_MESSAGE) @@ -554,7 +554,7 @@ var/msg = message M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) if(runemessage != -1) - M.create_chat_message(src, "* [runemessage || message] *", FALSE, list("emote")) + M.create_chat_message(src, "[runemessage || message]", FALSE, list("emote")) /atom/movable/proc/dropInto(var/atom/destination) while(istype(destination)) diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index abd55097a8c..81ec230f9b6 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -78,4 +78,4 @@ var/connection_timeofday // Runechat messages - var/list/seen_messages = list() + var/list/seen_messages diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm index ef4129ae464..3baccce8e32 100644 --- a/code/modules/emotes/emote_mob.dm +++ b/code/modules/emotes/emote_mob.dm @@ -199,7 +199,7 @@ if(isobserver(M)) message = "[src] ([ghost_follow_link(src, M)]) [input]" M.show_message(message, m_type) - M.create_chat_message(src, "* [runemessage] *", FALSE, list("emote"), (m_type == AUDIBLE_MESSAGE)) + M.create_chat_message(src, "[runemessage]", FALSE, list("emote"), (m_type == AUDIBLE_MESSAGE)) for(var/obj in o_viewers) var/obj/O = obj diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 07ae8377608..cd5919394f8 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -1,57 +1,62 @@ var/list/department_radio_keys = list( - ":r" = "right ear", ".r" = "right ear", - ":l" = "left ear", ".l" = "left ear", - ":i" = "intercom", ".i" = "intercom", - ":h" = "department", ".h" = "department", - ":+" = "special", ".+" = "special", //activate radio-specific special functions - ":c" = "Command", ".c" = "Command", - ":n" = "Science", ".n" = "Science", - ":m" = "Medical", ".m" = "Medical", - ":e" = "Engineering", ".e" = "Engineering", - ":k" = "Response Team", ".k" = "Response Team", - ":s" = "Security", ".s" = "Security", - ":w" = "whisper", ".w" = "whisper", - ":t" = "Mercenary", ".t" = "Mercenary", - ":x" = "Raider", ".x" = "Raider", - ":u" = "Supply", ".u" = "Supply", - ":v" = "Service", ".v" = "Service", - ":p" = "AI Private", ".p" = "AI Private", - ":y" = "Explorer", ".y" = "Explorer", - ":a" = "Talon", ".a" = "Talon", //VOREStation Add, + ":r" = "right ear", ".r" = "right ear", + ":l" = "left ear", ".l" = "left ear", + ":i" = "intercom", ".i" = "intercom", + ":h" = "department", ".h" = "department", + ":+" = "special", ".+" = "special", //activate radio-specific special functions + ":c" = "Command", ".c" = "Command", + ":n" = "Science", ".n" = "Science", + ":m" = "Medical", ".m" = "Medical", + ":e" = "Engineering", ".e" = "Engineering", + ":k" = "Response Team", ".k" = "Response Team", + ":s" = "Security", ".s" = "Security", + ":w" = "whisper", ".w" = "whisper", + ":t" = "Mercenary", ".t" = "Mercenary", + ":x" = "Raider", ".x" = "Raider", + ":u" = "Supply", ".u" = "Supply", + ":v" = "Service", ".v" = "Service", + ":p" = "AI Private", ".p" = "AI Private", + ":y" = "Explorer", ".y" = "Explorer", + ":a" = "Talon", ".a" = "Talon", //VOREStation Add, - ":R" = "right ear", ".R" = "right ear", - ":L" = "left ear", ".L" = "left ear", - ":I" = "intercom", ".I" = "intercom", - ":H" = "department", ".H" = "department", - ":C" = "Command", ".C" = "Command", - ":N" = "Science", ".N" = "Science", - ":M" = "Medical", ".M" = "Medical", - ":E" = "Engineering", ".E" = "Engineering", - ":k" = "Response Team", ".k" = "Response Team", - ":S" = "Security", ".S" = "Security", - ":W" = "whisper", ".W" = "whisper", - ":T" = "Mercenary", ".T" = "Mercenary", - ":X" = "Raider", ".X" = "Raider", - ":U" = "Supply", ".U" = "Supply", - ":V" = "Service", ".V" = "Service", - ":P" = "AI Private", ".P" = "AI Private", - ":Y" = "Explorer", ".Y" = "Explorer", - ":A" = "Talon", ".A" = "Talon", //VOREStation Add, + ":R" = "right ear", ".R" = "right ear", + ":L" = "left ear", ".L" = "left ear", + ":I" = "intercom", ".I" = "intercom", + ":H" = "department", ".H" = "department", + ":C" = "Command", ".C" = "Command", + ":N" = "Science", ".N" = "Science", + ":M" = "Medical", ".M" = "Medical", + ":E" = "Engineering", ".E" = "Engineering", + ":k" = "Response Team", ".k" = "Response Team", + ":S" = "Security", ".S" = "Security", + ":W" = "whisper", ".W" = "whisper", + ":T" = "Mercenary", ".T" = "Mercenary", + ":X" = "Raider", ".X" = "Raider", + ":U" = "Supply", ".U" = "Supply", + ":V" = "Service", ".V" = "Service", + ":P" = "AI Private", ".P" = "AI Private", + ":Y" = "Explorer", ".Y" = "Explorer", + ":A" = "Talon", ".A" = "Talon", //VOREStation Add, - //kinda localization -- rastaf0 - //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. - ":�" = "right ear", ".�" = "right ear", - ":�" = "left ear", ".�" = "left ear", - ":�" = "intercom", ".�" = "intercom", - ":�" = "department", ".�" = "department", - ":�" = "Command", ".�" = "Command", - ":�" = "Science", ".�" = "Science", - ":�" = "Medical", ".�" = "Medical", - ":�" = "Engineering", ".�" = "Engineering", - ":�" = "Security", ".�" = "Security", - ":�" = "whisper", ".�" = "whisper", - ":�" = "Mercenary", ".�" = "Mercenary", - ":�" = "Supply", ".�" = "Supply", + // Cyrillic characters on the same keys on the Russian QWERTY (phonetic) layout + ":к" = "right ear", ".к" = "right ear", + ":д" = "left ear", ".д" = "left ear", + ":ш" = "intercom", ".ш" = "intercom", + ":р" = "department", ".р" = "department", + ":+" = "special", ".+" = "special", //activate radio-specific special functions + ":с" = "Command", ".с" = "Command", + ":т" = "Science", ".т" = "Science", + ":ь" = "Medical", ".ь" = "Medical", + ":у" = "Engineering", ".у" = "Engineering", + ":л" = "Response Team", ".л" = "Response Team", + ":ы" = "Security", ".ы" = "Security", + ":ц" = "whisper", ".ц" = "whisper", + ":е" = "Mercenary", ".е" = "Mercenary", + ":ч" = "Raider", ".ч" = "Raider", + ":г" = "Supply", ".г" = "Supply", + ":м" = "Service", ".м" = "Service", + ":з" = "AI Private", ".з" = "AI Private", + ":н" = "Explorer", ".н" = "Explorer" ) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 6626b689726..547bb19304e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -131,7 +131,7 @@ msg = self_message M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) if(runemessage != -1) - M.create_chat_message(src, "* [runemessage || message] *", FALSE, list("emote"), audible = FALSE) + M.create_chat_message(src, "[runemessage || message]", FALSE, list("emote"), audible = FALSE) /mob/proc/findname(msg) for(var/mob/M in mob_list)