From 96e7032cea673711d805ccc2b3dbaad736c30cd0 Mon Sep 17 00:00:00 2001 From: Koshenko Date: Thu, 12 Oct 2023 17:47:21 -0700 Subject: [PATCH] Manually ports https://github.com/tgstation/tgstation/pull/74428 due to merge conflicts --- code/datums/chatmessage.dm | 80 +++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm index e47b1f3cb4d..193af2f2347 100644 --- a/code/datums/chatmessage.dm +++ b/code/datums/chatmessage.dm @@ -4,6 +4,8 @@ #define CHAT_MESSAGE_LIFESPAN 5 SECONDS /// How long the chat message's end of life fading animation will occur for #define CHAT_MESSAGE_EOL_FADE 0.7 SECONDS +/// Grace period for fade before we actually delete the chat message +#define CHAT_MESSAGE_GRACE_PERIOD (0.2 SECONDS) /// Factor of how much the message index (number of messages) will account to exponential decay #define CHAT_MESSAGE_EXP_DECAY 0.7 /// Factor of how much height will account to exponential decay @@ -50,10 +52,10 @@ var/datum/chatmessage/prev /// The current index used for adjusting the layer of each sequential chat message such that recent messages will overlay older ones var/static/current_z_idx = 0 - /// Contains ID of assigned timer for end_of_life fading event - var/fadertimer = null - /// States if end_of_life is being executed - var/isFading = FALSE + /// When we started animating the message + var/animate_start = 0 + /// Our animation lifespan, how long this message will last + var/animate_lifespan = 0 /** * Constructs a chat message overlay @@ -77,6 +79,8 @@ INVOKE_ASYNC(src, .proc/generate_image, text, target, owner, language, extra_classes, lifespan) /datum/chatmessage/Destroy() + if(REALTIMEOFDAY < animate_start + animate_lifespan) + stack_trace("Del'd before we finished fading, with [(animate_start + animate_lifespan) - REALTIMEOFDAY] time left") if (owned_by) if (owned_by.seen_messages) LAZYREMOVEASSOC(owned_by.seen_messages, message_loc, src) @@ -184,6 +188,7 @@ ///necessary because after that call the proc can resume at the end of the tick and cause overtime. /datum/chatmessage/proc/finish_image_generation(mheight, atom/target, mob/owner, complete_text, lifespan) + var/rough_time = REALTIMEOFDAY approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT) // Translate any existing messages upwards, apply exponential decay factors to timers @@ -192,19 +197,33 @@ var/idx = 1 var/combined_height = approx_lines for(var/datum/chatmessage/m as anything in owned_by.seen_messages[message_loc]) - animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME) + combined_height += m.approx_lines + var/time_spent = rough_time - m.animate_start + var/time_before_fade = m.animate_lifespan - CHAT_MESSAGE_EOL_FADE + // When choosing to update the remaining time we have to be careful not to update the // scheduled time once the EOL has been executed. - if (!m.isFading) - var/sched_remaining = timeleft(m.fadertimer, SSrunechat) - var/remaining_time = max(0, (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height)) - if (remaining_time) - deltimer(m.fadertimer, SSrunechat) - m.fadertimer = addtimer(CALLBACK(m, .proc/end_of_life), remaining_time, TIMER_STOPPABLE|TIMER_DELETE_ME, SSrunechat) - else - m.end_of_life() + if (time_spent >= time_before_fade) + animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME, flags = ANIMATION_PARALLEL) + continue + + var/remaining_time = time_before_fade * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height) + // Ensure we don't accidentially spike alpha up or something silly like that + m.message.alpha = m.get_current_alpha(time_spent) + if (remaining_time > 0) + // Stay faded in for a while, then + animate(m.message, alpha = 255, remaining_time) + // Fade out + animate(alpha = 0, time = CHAT_MESSAGE_EOL_FADE) + m.animate_lifespan = remaining_time + CHAT_MESSAGE_EOL_FADE + else + // Your time has come my son + animate(alpha = 0, time = CHAT_MESSAGE_EOL_FADE) + // We run this after the alpha animate, because we don't want to interrup it, but also don't want to block it by running first + // Sooo instead we do this. bit messy but it fuckin works + animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME, flags = ANIMATION_PARALLEL) // Reset z index if relevant if (current_z_idx >= CHAT_LAYER_MAX_Z) @@ -222,26 +241,32 @@ message.maptext_x = (CHAT_MESSAGE_WIDTH - owner.bound_width) * -0.5 message.maptext = MAPTEXT(complete_text) + animate_start = rough_time + animate_lifespan = lifespan + // View the message LAZYADDASSOCLIST(owned_by.seen_messages, message_loc, src) owned_by.images |= message animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME) - // Register with the runechat SS to handle EOL and destruction - var/duration = lifespan - CHAT_MESSAGE_EOL_FADE - fadertimer = addtimer(CALLBACK(src, .proc/end_of_life), duration, TIMER_STOPPABLE|TIMER_DELETE_ME, SSrunechat) + var/time_before_fade = lifespan - CHAT_MESSAGE_SPAWN_TIME - CHAT_MESSAGE_EOL_FADE + // Stay faded in + animate(alpha = 255, time = time_before_fade) + // Fade out + animate(alpha = 0, time = CHAT_MESSAGE_EOL_FADE) -/** - * Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion, - * sets timer for scheduling deletion - * - * Arguments: - * * fadetime - The amount of time to animate the message's fadeout for - */ -/datum/chatmessage/proc/end_of_life(fadetime = CHAT_MESSAGE_EOL_FADE) - isFading = TRUE - animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL) - addtimer(CALLBACK(GLOBAL_PROC, /proc/qdel, src), fadetime, TIMER_DELETE_ME, SSrunechat) + // Register with the runechat SS to handle destruction + addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, src), lifespan + CHAT_MESSAGE_GRACE_PERIOD, TIMER_DELETE_ME, SSrunechat) + +/datum/chatmessage/proc/get_current_alpha(time_spent) + if(time_spent < CHAT_MESSAGE_SPAWN_TIME) + return (time_spent / CHAT_MESSAGE_SPAWN_TIME) * 255 + + var/time_before_fade = animate_lifespan - CHAT_MESSAGE_EOL_FADE + if(time_spent <= time_before_fade) + return 255 + + return (1 - ((time_spent - time_before_fade) / CHAT_MESSAGE_EOL_FADE)) * 255 /** * Creates a message overlay at a defined location for a given speaker @@ -331,6 +356,7 @@ #undef CHAT_MESSAGE_SPAWN_TIME #undef CHAT_MESSAGE_LIFESPAN #undef CHAT_MESSAGE_EOL_FADE +#undef CHAT_MESSAGE_GRACE_PERIOD #undef CHAT_MESSAGE_EXP_DECAY #undef CHAT_MESSAGE_HEIGHT_DECAY #undef CHAT_MESSAGE_APPROX_LHEIGHT