mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-26 09:12:29 +00:00
Turned a ton of unmanaged globals into managed globals. Refactored some UT output. Removed some unused things, including vars. Added a test to ensure people don't keep adding new unmanaged vars.
220 lines
8.4 KiB
Plaintext
220 lines
8.4 KiB
Plaintext
// Thanks to Burger from Burgerstation for the foundation for this
|
|
GLOBAL_LIST_INIT(floating_chat_colors, list())
|
|
|
|
///Compute an unique key that is used to associate an image to the client that received said image
|
|
#define STORED_CHAT_TEXT_HASH(client) "[client.ckey]"
|
|
/atom/movable
|
|
/**
|
|
* A lazy list with the following format:
|
|
*
|
|
* * K -> The hash function result of STORED_CHAT_TEXT_HASH, a string
|
|
* * V -> A `/list` of `/image`, the images are the runetext sent to be shown to the various clients (as per the hash function)
|
|
*/
|
|
VAR_PRIVATE/list/stored_chat_text
|
|
|
|
/atom/movable/proc/get_floating_chat_color()
|
|
return get_random_colour(0, 160, 230)
|
|
|
|
/atom/movable/proc/set_floating_chat_color(color)
|
|
GLOB.floating_chat_colors[name] = color
|
|
|
|
/atom/movable/proc/animate_chat(message, datum/language/language, small, list/show_to, duration, override_color)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
var/style //additional style params for the message
|
|
var/fontsize = GENERATE_FLOATING_TEXT_MEDIUM
|
|
if(small)
|
|
fontsize = GENERATE_FLOATING_TEXT_SMALL
|
|
var/limit = 50
|
|
if(copytext(message, length(message) - 1) == "!!")
|
|
fontsize = GENERATE_FLOATING_TEXT_LARGE
|
|
limit = 30
|
|
style += "font-weight: bold;"
|
|
|
|
if(length(message) > limit)
|
|
message = "[copytext_char(message, 1, limit)]..."
|
|
|
|
if(istype(language, /datum/language/noise))
|
|
message = "<font color='#7F7F7F'>*</font> " + uncapitalize(message)
|
|
|
|
if(!GLOB.floating_chat_colors[name])
|
|
GLOB.floating_chat_colors[name] = get_floating_chat_color()
|
|
style += "color: [GLOB.floating_chat_colors[name]];"
|
|
|
|
send_chat_floating_text_to_clients(show_to, message, fontsize, style, duration, language)
|
|
|
|
|
|
/**
|
|
* Generates a floating message image and sent it to the clients
|
|
*
|
|
*
|
|
* * show_to - A `/list` of clients to show the image to
|
|
* * message - A string, the message to show
|
|
* * style - String, a CSS-DM that will be injected in the style of the maptext, MUST be semicolon (;) terminated
|
|
* * duration - Duration in deciseconds to show the message for
|
|
* * language - A `/datum/language`, to appropriately change the image based on the understanding of the mob that receives it
|
|
*/
|
|
/atom/movable/proc/send_chat_floating_text_to_clients(list/client/show_to, message, fontsize, style, duration, datum/language/language)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
// create 2 messages, one that appears if you know the language, and one that appears when you don't know the language
|
|
for(var/client/C in show_to)
|
|
if(!(C.prefs.toggles_secondary & FLOATING_MESSAGES))
|
|
continue
|
|
|
|
var/message_to_put_in_image
|
|
|
|
//See if it needs an understood message, or a gibberish one, to be shown, and generate it
|
|
if(isnull(language) || C.mob.say_understands(null, language))
|
|
message_to_put_in_image = capitalize(message)
|
|
else if(!isnull(language))
|
|
message_to_put_in_image = language.scramble(message)
|
|
|
|
//Generate the image, sent it to the client
|
|
generate_floating_text(message_to_put_in_image, style, fontsize, duration, C)
|
|
|
|
|
|
/**
|
|
* Generates a floating text message and takes care of showing it to the client, and remove it
|
|
*
|
|
*
|
|
* * message - String, the text to put into the floating text
|
|
* * style - String, a CSS-DM that will be injected in the style of the maptext, MUST be semicolon (;) terminated
|
|
* * fontsize - One of the GENERATE_FLOATING_TEXT_* macros defined in `code\__DEFINES\text.dm`, determines the size
|
|
* * duration - Duration in deciseconds to show the message for
|
|
*
|
|
* This process can sleep as it uses the client to measure the size of text, it should only be called inside a non-blocking call chain
|
|
*
|
|
*/
|
|
/atom/movable/proc/generate_floating_text(message, style, fontsize = GENERATE_FLOATING_TEXT_MEDIUM, duration, client/show_to)
|
|
set waitfor = FALSE
|
|
PRIVATE_PROC(TRUE)
|
|
|
|
if(!istype(show_to))
|
|
crash_with("Wrong argument supplied, show_to is not a client!")
|
|
|
|
//No point if the source or the destination of the floating text are deleted
|
|
if(QDELETED(src) || QDELETED(show_to))
|
|
return FALSE
|
|
|
|
var/atom/movable/attached_holder = get_last_atom_before_turf(src)
|
|
var/image/I = image(null, attached_holder, layer = FLY_LAYER)
|
|
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART | PIXEL_SCALE
|
|
|
|
I.plane = HUD_PLANE
|
|
I.layer = UNDER_HUD_LAYER
|
|
I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM
|
|
|
|
I.alpha = 0
|
|
|
|
I.maptext_width = CHAT_MESSAGE_WIDTH
|
|
|
|
I.pixel_y = attached_holder.get_floating_chat_y_offset()
|
|
I.pixel_x = (-round(I.maptext_width/2) + 16) + attached_holder.get_floating_chat_x_offset()
|
|
|
|
//Select the various parameters for the maptext, to ensure pixel-perfect scaling
|
|
var/font_family
|
|
var/font_size
|
|
var/other
|
|
switch(fontsize)
|
|
if(GENERATE_FLOATING_TEXT_SMALL)
|
|
font_family = "Spess Font"
|
|
font_size = 6
|
|
other = "-dm-text-outline: 1px black sharp; line-height: 1.4;"
|
|
if(GENERATE_FLOATING_TEXT_MEDIUM)
|
|
font_family = "Grand9K Pixel"
|
|
font_size = 6
|
|
other = "-dm-text-outline: 1px black sharp;"
|
|
if(GENERATE_FLOATING_TEXT_LARGE)
|
|
font_family = "Grand9K Pixel"
|
|
font_size = 12
|
|
other = "-dm-text-outline: 1.2px black sharp;"
|
|
else
|
|
crash_with("Wrong size specified, use one of the defines!")
|
|
|
|
var/complete_text = "<span class='center'><span style='font-family: \"[font_family]\"; font-size: [font_size]pt; [other] [style] text-align: center;'>[message]</span></span>"
|
|
|
|
I.maptext = complete_text
|
|
|
|
//At this point we enter the wait, we patiently wait for the client to tell us how large
|
|
//the text will be on its screen, as we need that info for the image generation afterwards
|
|
var/mheight = 0
|
|
WXH_TO_HEIGHT(show_to.MeasureText(complete_text, null, CHAT_MESSAGE_WIDTH), mheight)
|
|
|
|
//Then we register a callback to complete the image generation, this is done to avoid
|
|
//the proc waking up at the end of a tick and cause overtime
|
|
SSrunechat.message_queue += CALLBACK(src, PROC_REF(finish_generate_floating_text), I, mheight, show_to, duration)
|
|
|
|
|
|
/**
|
|
* Runs after the calculation of the client for the runechat size measurement,
|
|
* takes care of the last things needed to be set on the image, to display it to the clients,
|
|
* and to register it for removal when it expires
|
|
*
|
|
* Should only, ever be called by the runechat subsystem as a consequence of the `generate_floating_text()` callback insertion
|
|
*/
|
|
/atom/movable/proc/finish_generate_floating_text(image/runetext_image, mheight, client/show_to, lifespan)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
PRIVATE_PROC(TRUE)
|
|
|
|
//The client can go offline, which would cause a runtime below
|
|
//this prevents the runtime, checking for both null and being deleted
|
|
if(QDELETED(show_to))
|
|
return
|
|
|
|
runetext_image.maptext_height = mheight * 1.25
|
|
|
|
var/stored_chat_text_hash_cache = STORED_CHAT_TEXT_HASH(show_to)
|
|
|
|
//Older runetext messages are shifted up so they clear the visual for the new ones
|
|
for(var/image/old in LAZYACCESS(src.stored_chat_text, stored_chat_text_hash_cache))
|
|
animate(old, 2, pixel_y = old.pixel_y + min(runetext_image.maptext_height, 45) + 8)
|
|
|
|
//We register ourself as a stored chat text image
|
|
LAZYADDASSOCLIST(src.stored_chat_text, stored_chat_text_hash_cache, runetext_image)
|
|
|
|
//Send the image to the client, takes care to remove it afterwards
|
|
flick_overlay(runetext_image, list(show_to), (lifespan + 2))
|
|
|
|
//Animation to show the text "appearing up"
|
|
animate(runetext_image, 1, alpha = 255, pixel_y = runetext_image.pixel_y + 23)
|
|
|
|
//Register a timer for our removal from the list
|
|
addtimer(CALLBACK(src, PROC_REF(remove_floating_text), runetext_image, stored_chat_text_hash_cache), lifespan)
|
|
|
|
|
|
/// Gives floating text to src upon holder entering
|
|
/atom/movable/proc/give_floating_text(atom/movable/holder)
|
|
PRIVATE_PROC(TRUE)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
if(!holder)
|
|
return
|
|
for(var/key in holder.stored_chat_text)
|
|
for(var/image/I in holder.stored_chat_text[key])
|
|
I.loc = src
|
|
|
|
/// Returns floating text to holder upon leaving src
|
|
/atom/movable/proc/return_floating_text(atom/movable/holder)
|
|
PRIVATE_PROC(TRUE)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
if(!holder)
|
|
return
|
|
for(var/key in holder.stored_chat_text)
|
|
for(var/image/I in holder.stored_chat_text[key])
|
|
I.loc = holder
|
|
|
|
/atom/movable/proc/remove_floating_text(image/image_to_remove, stored_chat_text_hash)
|
|
PRIVATE_PROC(TRUE)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
var/list/image/client_associated_images = LAZYACCESS(src.stored_chat_text, stored_chat_text_hash)
|
|
if(!(client_associated_images?.Find(image_to_remove)))
|
|
crash_with("Trying to remove a floating text image that is not there!")
|
|
|
|
animate(image_to_remove, 2, pixel_y = image_to_remove.pixel_y + 10, alpha = 0)
|
|
LAZYREMOVEASSOC(src.stored_chat_text, stored_chat_text_hash, image_to_remove)
|
|
|
|
#undef STORED_CHAT_TEXT_HASH
|