diff --git a/citadel.dme b/citadel.dme index 7c7f9707d0ac..813c46fd2a40 100644 --- a/citadel.dme +++ b/citadel.dme @@ -43,6 +43,7 @@ #include "code\__DEFINES\chat.dm" #include "code\__DEFINES\chemistry.dm" #include "code\__DEFINES\coloration.dm" +#include "code\__DEFINES\colors.dm" #include "code\__DEFINES\configuration.dm" #include "code\__DEFINES\construction.dm" #include "code\__DEFINES\damage_organs.dm" @@ -377,6 +378,7 @@ #include "code\__HELPERS\atom_movables.dm" #include "code\__HELPERS\chat.dm" #include "code\__HELPERS\coloration.dm" +#include "code\__HELPERS\colors.dm" #include "code\__HELPERS\datum.dm" #include "code\__HELPERS\debugging.dm" #include "code\__HELPERS\do_after.dm" @@ -603,6 +605,7 @@ #include "code\controllers\subsystem\preferences.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\repository.dm" +#include "code\controllers\subsystem\runechat.dm" #include "code\controllers\subsystem\server_maint.dm" #include "code\controllers\subsystem\shuttles.dm" #include "code\controllers\subsystem\simple_networks.dm" @@ -702,6 +705,7 @@ #include "code\datums\category.dm" #include "code\datums\changelog.dm" #include "code\datums\character_profile.dm" +#include "code\datums\chatmessage.dm" #include "code\datums\computerfiles.dm" #include "code\datums\datacore.dm" #include "code\datums\datum.dm" @@ -5381,6 +5385,12 @@ #include "interface\interface.dm" #include "interface\stylesheet.dm" #include "interface\skin.dmf" +#include "interface\fonts\fonts_datum.dm" +#include "interface\fonts\grand_9k.dm" +#include "interface\fonts\pixellari.dm" +#include "interface\fonts\spess_font.dm" +#include "interface\fonts\tiny_unicode.dm" +#include "interface\fonts\vcr_osd_mono.dm" #include "interface\menus\_menus.dm" #include "interface\menus\main.dm" #include "maps\endeavour\endeavour-areas.dm" diff --git a/code/__DEFINES/_lists.dm b/code/__DEFINES/_lists.dm index 0496f1c3ef84..a36dd7f59569 100644 --- a/code/__DEFINES/_lists.dm +++ b/code/__DEFINES/_lists.dm @@ -25,6 +25,12 @@ #define LAZYLEN(L) length(L) ///Sets a list to null #define LAZYNULL(L) L = null +///Adds to the item K the value V, if the list is null it will initialize it +#define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += V; +///This is used to add onto lazy assoc list when the value you're adding is a /list/. This one has extra safety over lazyaddassoc because the value could be null (and thus cant be used to += objects) +#define LAZYADDASSOCLIST(L, K, V) if(!L) { L = list(); } L[K] += list(V); +///Removes the value V from the item K, if the item K is empty will remove it from the list, if the list is empty will set the list to null +#define LAZYREMOVEASSOC(L, K, V) if(L) { if(L[K]) { L[K] -= V; if(!length(L[K])) L -= K; } if(!length(L)) L = null; } /// Null-safe L.Cut() #define LAZYCLEARLIST(L) if(L) L.Cut() /// Null-safe L.Copy() diff --git a/code/__DEFINES/_tick.dm b/code/__DEFINES/_tick.dm index d3d966c35454..21421e207fc8 100644 --- a/code/__DEFINES/_tick.dm +++ b/code/__DEFINES/_tick.dm @@ -32,6 +32,11 @@ /// runs stoplag if tick_usage is above the limit #define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 ) +/// Checks if a sleeping proc is running before or after the master controller +#define RUNNING_BEFORE_MASTER ( Master.last_run != null && Master.last_run != world.time ) +/// Returns true if a verb ought to yield to the MC (IE: queue up to be processed by a subsystem) +#define VERB_SHOULD_YIELD ( TICK_CHECK || RUNNING_BEFORE_MASTER ) + /// Returns true if tick usage is above 95, for high priority usage /// /// * Use for admin functions so they stay responsive and functional during lag. diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm new file mode 100644 index 000000000000..55314e84bd37 --- /dev/null +++ b/code/__DEFINES/colors.dm @@ -0,0 +1,5 @@ + +#define CM_COLOR_SAT_MIN 0.6 +#define CM_COLOR_SAT_MAX 0.7 +#define CM_COLOR_LUM_MIN 0.65 +#define CM_COLOR_LUM_MAX 0.75 diff --git a/code/__DEFINES/controllers/_subsystem-priority.dm b/code/__DEFINES/controllers/_subsystem-priority.dm index 297142ed0734..9662104ecbfd 100644 --- a/code/__DEFINES/controllers/_subsystem-priority.dm +++ b/code/__DEFINES/controllers/_subsystem-priority.dm @@ -49,7 +49,8 @@ #define FIRE_PRIORITY_OVERLAYS 100 #define FIRE_PRIORITY_SMOOTHING 100 #define FIRE_PRIORITY_CHAT 100 -#define FIRE_PRIORITY_INPUT 100 +#define FIRE_PRIORITY_RUNECHAT 100 +#define FIRE_PRIORITY_INPUT 1000 // we dont want to drop user input right? //? Ticker Subsystems - Highest priority // Any subsystem flagged with SS_TICKER is here! diff --git a/code/__DEFINES/controllers/_subsystem.dm b/code/__DEFINES/controllers/_subsystem.dm index f9fce73f1a02..af2219e780e4 100644 --- a/code/__DEFINES/controllers/_subsystem.dm +++ b/code/__DEFINES/controllers/_subsystem.dm @@ -20,13 +20,24 @@ }\ /datum/controller/subsystem/##X +/** + * Defines a timer subsystem. + */ +#define TIMER_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/timer/##X);\ +/datum/controller/subsystem/timer/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ +}\ +/datum/controller/subsystem/timer/##X/fire() {..() /*just so it shows up on the profiler*/} \ +/datum/controller/subsystem/timer/##X + /** * Defines a processing subsystem. */ #define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\ /datum/controller/subsystem/processing/##X/New(){\ - NEW_SS_GLOBAL(SS##X);\ + NEW_SS_GLOBAL(SS##X);\ }\ +/datum/controller/subsystem/processing/##X/fire() {..() /*just so it shows up on the profiler*/} \ /datum/controller/subsystem/processing/##X //* Subsystem flags *// diff --git a/code/__DEFINES/fonts.dm b/code/__DEFINES/fonts.dm index 6349d55d1b5f..f96373cb2999 100644 --- a/code/__DEFINES/fonts.dm +++ b/code/__DEFINES/fonts.dm @@ -23,3 +23,7 @@ /// Emoji icon set #define EMOJI_SET 'icons/ui_icons/emoji/emoji.dmi' #define EMOJI32_SET 'icons/ui_icons/emoji/emoji32.dmi' + +// Font metrics bitfield +/// Include leading A width and trailing C width in GetWidth() or in DrawText() +#define INCLUDE_AC (1<<0) diff --git a/code/__DEFINES/machinery.dm b/code/__DEFINES/machinery.dm index 87eea72002c1..d60072dc8af3 100644 --- a/code/__DEFINES/machinery.dm +++ b/code/__DEFINES/machinery.dm @@ -219,3 +219,14 @@ if (!(DATUM.datum_flags & DF_ISPROCESSING)) {\ #define ORION_GAMER_PAMPHLET -1 //game begins to have a chance to warn sec and med #define ORION_GAMER_REPORT_THRESHOLD 2 + +/// Blank Status Display +#define SD_BLANK 0 +/// Shows the emergency shuttle timer +#define SD_EMERGENCY 1 +/// Shows an arbitrary message, user-set +#define SD_MESSAGE 2 +/// Shows an alert picture (e.g. red alert, radiation, etc.) +#define SD_PICTURE 3 +/// Shows the current station time +#define SD_TIME 4 diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm index 13f660df4292..da537639a19d 100644 --- a/code/__DEFINES/text.dm +++ b/code/__DEFINES/text.dm @@ -3,6 +3,58 @@ /// Removes characters incompatible with file names. #define SANITIZE_FILENAME(text) (GLOB.filename_forbidden_chars.Replace(text, "")) + +//! Maptext +/// Standard maptext +/// Prepares a text to be used for maptext. Use this so it doesn't look hideous. +#define MAPTEXT(text) {"[##text]"} +/// Prepares a text to be used for maptext. Use this so it doesn't look hideous. +#define MAPTEXT_CENTER(text) {"[##text]"} + +/** + * Pixel-perfect scaled fonts for use in the MAP element as defined in skin.dmf + * + * Four sizes to choose from, use the sizes as mentioned below. + * Between the variations and a step there should be an option that fits your use case. + * BYOND uses pt sizing, different than px used in TGUI. Using px will make it look blurry due to poor antialiasing. + * + * Default sizes are prefilled in the macro for ease of use and a consistent visual look. + * To use a step other than the default in the macro, specify it in a span style. + * For example: MAPTEXT_PIXELLARI("Some large maptext here") + */ +/// Large size (ie: context tooltips) - Size options: 12pt 24pt. +#define MAPTEXT_PIXELLARI(text) {"[##text]"} + +/// Standard size (ie: normal runechat) - Size options: 6pt 12pt 18pt. +#define MAPTEXT_GRAND9K(text) {"[##text]"} + +/// Small size. (ie: context subtooltips, spell delays) - Size options: 12pt 24pt. +#define MAPTEXT_TINY_UNICODE(text) {"[##text]"} + +/// Smallest size. (ie: whisper runechat) - Size options: 6pt 12pt 18pt. +#define MAPTEXT_SPESSFONT(text) {"[##text]"} + +/** + * Prepares a text to be used for maptext, using a variable size font. + * + * More flexible but doesn't scale pixel perfect to BYOND icon resolutions. + * (May be blurry.) Can use any size in pt or px. + * + * You MUST Specify the size when using the macro + * For example: MAPTEXT_VCR_OSD_MONO("Some large maptext here") + */ +/// Prepares a text to be used for maptext, using a variable size font. +/// Variable size font. More flexible but doesn't scale pixel perfect to BYOND icon resolutions. (May be blurry.) Can use any size in pt or px. +#define MAPTEXT_VCR_OSD_MONO(text) {"[##text]"} + +/// Macro from Lummox used to get height from a MeasureText proc. +/// resolves the MeasureText() return value once, then resolves the height, then sets return_var to that. +#define WXH_TO_HEIGHT(measurement, return_var) \ + do { \ + var/_measurement = measurement; \ + return_var = text2num(copytext(_measurement, findtextEx(_measurement, "x") + 1)); \ + } while(FALSE); + /* /// Simply removes the < and > characters, and limits the length of the message. #define STRIP_HTML_SIMPLE(text, limit) (GLOB.angular_brackets.Replace(copytext(text, 1, limit), "")) @@ -54,11 +106,3 @@ /// File location for cult shuttle curse descriptions #define CULT_SHUTTLE_CURSE "cult_shuttle_curse.json" */ - -//! Maptext -/// Prepares a text to be used for maptext. Use this so it doesn't look hideous. -#define MAPTEXT(text) {"[##text]"} -/// Prepares a text to be used for maptext. Use this so it doesn't look hideous. -#define MAPTEXT_CENTER(text) {"[##text]"} -/// Macro from Lummox used to get height from a MeasureText proc -#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1)) diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm new file mode 100644 index 000000000000..c592d6356fc8 --- /dev/null +++ b/code/__HELPERS/colors.dm @@ -0,0 +1,48 @@ + +/** + * Gets a color for a name, will return the same color for a given string consistently within a round.atom + * + * Note that this proc aims to produce pastel-ish colors using the HSL colorspace. These seem to be favorable for displaying on the map. + * + * Arguments: + * * name - The name to generate a color for + * * 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/colorize_string(name, sat_shift = 1, lum_shift = 1) + // seed to help randomness + var/static/rseed = rand(1,26) + + // get hsl using the selected 6 characters of the md5 hash + var/hash = copytext(md5(name + GLOB.round_id), rseed, rseed + 6) + var/h = hex2num(copytext(hash, 1, 3)) * (360 / 255) + var/s = (hex2num(copytext(hash, 3, 5)) >> 2) * ((CM_COLOR_SAT_MAX - CM_COLOR_SAT_MIN) / 63) + CM_COLOR_SAT_MIN + var/l = (hex2num(copytext(hash, 5, 7)) >> 2) * ((CM_COLOR_LUM_MAX - CM_COLOR_LUM_MIN) / 63) + CM_COLOR_LUM_MIN + + // adjust for shifts + s = clamp(s * sat_shift, 0, 1) + l = clamp(l * lum_shift, 0, 1) + + // convert to rgb + var/h_int = round(h/60) // mapping each section of H to 60 degree sections + var/c = (1 - abs(2 * l - 1)) * s + var/x = c * (1 - abs((h / 60) % 2 - 1)) + var/m = l - c * 0.5 + x = (x + m) * 255 + c = (c + m) * 255 + m *= 255 + switch(h_int) + if(0) + return "#[num2hex(c, 2)][num2hex(x, 2)][num2hex(m, 2)]" + if(1) + return "#[num2hex(x, 2)][num2hex(c, 2)][num2hex(m, 2)]" + if(2) + return "#[num2hex(m, 2)][num2hex(c, 2)][num2hex(x, 2)]" + if(3) + return "#[num2hex(m, 2)][num2hex(x, 2)][num2hex(c, 2)]" + if(4) + return "#[num2hex(x, 2)][num2hex(m, 2)][num2hex(c, 2)]" + if(5) + return "#[num2hex(c, 2)][num2hex(m, 2)][num2hex(x, 2)]" + +#define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255))) diff --git a/code/controllers/subsystem/runechat.dm b/code/controllers/subsystem/runechat.dm new file mode 100644 index 000000000000..663bb8cf347d --- /dev/null +++ b/code/controllers/subsystem/runechat.dm @@ -0,0 +1,14 @@ +TIMER_SUBSYSTEM_DEF(runechat) + name = "Runechat" + priority = FIRE_PRIORITY_RUNECHAT + + var/list/datum/callback/message_queue = list() + +/datum/controller/subsystem/timer/runechat/fire(resumed) + . = ..() //poggers + while(message_queue.len) + var/datum/callback/queued_message = message_queue[message_queue.len] + queued_message.Invoke() + message_queue.len-- + if(MC_TICK_CHECK) + return diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm new file mode 100644 index 000000000000..dcce696a25fe --- /dev/null +++ b/code/datums/chatmessage.dm @@ -0,0 +1,298 @@ +/// How long the chat message's spawn-in animation will occur for +#define CHAT_MESSAGE_SPAWN_TIME (0.2 SECONDS) +/// How long the chat message will exist prior to any exponential decay +#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 +#define CHAT_MESSAGE_HEIGHT_DECAY 0.9 +/// Approximate height in pixels of an 'average' line, used for height decay +#define CHAT_MESSAGE_APPROX_LHEIGHT 11 +/// Max width of chat message in pixels +#define CHAT_MESSAGE_WIDTH 112 +/// The dimensions of the chat message icons +#define CHAT_MESSAGE_ICON_SIZE 9 + +///Base layer of chat elements +#define CHAT_LAYER 1 +///Highest possible layer of chat elements +#define CHAT_LAYER_MAX 2 +/// Maximum precision of float before rounding errors occur (in this context) +#define CHAT_LAYER_Z_STEP 0.0001 +/// The number of z-layer 'slices' usable by the chat message layering +#define CHAT_LAYER_MAX_Z (CHAT_LAYER_MAX - CHAT_LAYER) / CHAT_LAYER_Z_STEP + +/** + * # Chat Message Overlay + * + * Datum for generating a message overlay on the map + */ +/datum/chatmessage + /// The visual element of the chat message + var/image/message + /// The location in which the message is appearing + var/atom/message_loc + /// The client who heard this message + var/client/owned_by + /// Contains the scheduled destruction time, used for scheduling EOL + var/scheduled_destruction + /// Contains the time that the EOL for the message will be complete, used for qdel scheduling + var/eol_complete + /// Contains the approximate amount of lines for height decay + var/approx_lines + /// 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 + /// 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 + * + * Arguments: + * * text - The text content of the overlay + * * target - The target atom to display the overlay at + * * owner - The mob that owns this overlay, only this mob will be able to view it + * * extra_classes - Extra classes to apply to the span that holds the text + * * lifespan - The lifespan of the message in deciseconds + */ +/datum/chatmessage/New(text, atom/target, mob/owner, list/extra_classes = list(), lifespan = CHAT_MESSAGE_LIFESPAN) + . = ..() + if (!istype(target)) + CRASH("Invalid target given for chatmessage") + if(QDELETED(owner) || !istype(owner) || !owner.client) + stack_trace("/datum/chatmessage created with [isnull(owner) ? "null" : "invalid"] mob owner") + qdel(src) + return + INVOKE_ASYNC(src, PROC_REF(generate_image), text, target, owner, extra_classes, lifespan) + +/datum/chatmessage/Destroy() + if (!QDELING(owned_by)) + 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.seen_messages) + LAZYREMOVEASSOC(owned_by.seen_messages, message_loc, src) + owned_by.images.Remove(message) + + owned_by = null + message_loc = null + message = null + return ..() + +/** + * Calls qdel on the chatmessage when its parent is deleted, used to register qdel signal + */ +/datum/chatmessage/proc/on_parent_qdel() + SIGNAL_HANDLER + qdel(src) + +/** + * Generates a chat message image representation + * + * Arguments: + * * text - The text content of the overlay + * * target - The target atom to display the overlay at + * * owner - The mob that owns this overlay, only this mob will be able to view it + * * extra_classes - Extra classes to apply to the span that holds the text + * * lifespan - The lifespan of the message in deciseconds + */ +/datum/chatmessage/proc/generate_image(text, atom/target, mob/owner, list/extra_classes, lifespan) + // Register client who owns this message + owned_by = owner.client + RegisterSignal(owned_by, COMSIG_PARENT_QDELETING, PROC_REF(on_parent_qdel)) + + // Remove spans in the message from things like the recorder + var/static/regex/span_check = new(@"<\/?span[^>]*>", "gi") + text = replacetext(text, span_check, "") + + // Clip message + var/maxlen = 160 + if (length_char(text) > maxlen) + text = copytext_char(text, 1, maxlen + 1) + "..." // BYOND index moment + + // Get rid of any URL schemes that might cause BYOND to automatically wrap something in an anchor tag + var/static/regex/url_scheme = new(@"[A-Za-z][A-Za-z0-9+-\.]*:\/\/", "g") + text = replacetext(text, url_scheme, "") + + // Reject whitespace + var/static/regex/whitespace = new(@"^\s*$") + if (whitespace.Find(text)) + qdel(src) + return + + // Non mobs speakers can be small + if (!ismob(target)) + extra_classes |= "small" + + // Why are you yelling? + if(copytext_char(text, -2) == "!!") + extra_classes |= "yell" + + var/list/prefixes + var/chat_color_name_to_use = target.get_nametag_name() // use nametag as fallback + + if (ishuman(target)) + var/mob/living/carbon/human/H = target + chat_color_name_to_use = H.get_visible_name() // get ID name if exists + + // 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_name = chat_color_name_to_use + + 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 + var/complete_text = "[text]" + + var/mheight + WXH_TO_HEIGHT(owned_by.MeasureText(complete_text, null, CHAT_MESSAGE_WIDTH), mheight) + + + if(!VERB_SHOULD_YIELD) + return finish_image_generation(mheight, target, owner, complete_text, lifespan) + + var/datum/callback/our_callback = CALLBACK(src, PROC_REF(finish_image_generation), mheight, target, owner, complete_text, lifespan) + SSrunechat.message_queue += our_callback + return + +///finishes the image generation after the MeasureText() call in generate_image(). +///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) + var/starting_height = target.maptext_height + // Translate any existing messages upwards, apply exponential decay factors to timers + message_loc = isturf(target) ? target : get_atom_on_turf(target) + if (owned_by.seen_messages) + var/idx = 1 + var/combined_height = approx_lines + for(var/datum/chatmessage/m as anything in owned_by.seen_messages[message_loc]) + 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 (time_spent >= time_before_fade) + if(m.message.pixel_y < starting_height) + var/max_height = m.message.pixel_y + m.approx_lines * CHAT_MESSAGE_APPROX_LHEIGHT - starting_height + if(max_height > 0) + animate(m.message, pixel_y = m.message.pixel_y + max_height, time = CHAT_MESSAGE_SPAWN_TIME, flags = ANIMATION_PARALLEL) + else if(mheight + starting_height >= m.message.pixel_y) + 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 + if(m.message.pixel_y < starting_height) + var/max_height = m.message.pixel_y + m.approx_lines * CHAT_MESSAGE_APPROX_LHEIGHT - starting_height + if(max_height > 0) + animate(m.message, pixel_y = m.message.pixel_y + max_height, time = CHAT_MESSAGE_SPAWN_TIME, flags = ANIMATION_PARALLEL) + else if(mheight + starting_height >= m.message.pixel_y) + 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) + current_z_idx = 0 + + // Build message image + message = image(loc = message_loc, layer = CHAT_LAYER + CHAT_LAYER_Z_STEP * current_z_idx++) + message.plane = HUD_PLANE + message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART + message.alpha = 0 + message.pixel_y = starting_height + message.pixel_x = -target.base_pixel_x + message.maptext_width = CHAT_MESSAGE_WIDTH + message.maptext_height = mheight * 1.25 // We add extra because some characters are superscript, like actions + 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 + + // Fade in + animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME) + 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) + + // Register with the runechat SS to handle destruction + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(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 + * + * Arguments: + * * speaker - The atom who is saying this message + * * message_language - The language that the message is said in + * * raw_message - The text content of the message + * * spans - Additional classes to be added to the message + */ +/mob/proc/create_chat_message(atom/movable/speaker, datum/prototype/language/message_language, raw_message, list/spans, runechat_flags = NONE) + // Ensure the list we are using, if present, is a copy so we don't modify the list provided to us + spans = spans ? spans.Copy() : list() + + // Check for virtual speakers (aka hearing a message through a radio) + // var/atom/movable/originalSpeaker = speaker + // if (istype(speaker, /atom/movable/virtualspeaker)) + // var/atom/movable/virtualspeaker/v = speaker + // speaker = v.source + // spans |= "virtual-speaker" + + // Ignore virtual speaker (most often radio messages) from ourselves + // if (originalSpeaker != src && speaker == src) + // return + + new /datum/chatmessage(raw_message, speaker, src, spans) + +#undef CHAT_LAYER_MAX_Z +#undef CHAT_LAYER_Z_STEP +#undef CHAT_MESSAGE_APPROX_LHEIGHT +#undef CHAT_MESSAGE_GRACE_PERIOD +#undef CHAT_MESSAGE_EOL_FADE +#undef CHAT_MESSAGE_EXP_DECAY +#undef CHAT_MESSAGE_HEIGHT_DECAY +#undef CHAT_MESSAGE_ICON_SIZE +#undef CHAT_MESSAGE_LIFESPAN +#undef CHAT_MESSAGE_SPAWN_TIME +#undef CHAT_MESSAGE_WIDTH diff --git a/code/game/atoms/_atom.dm b/code/game/atoms/_atom.dm index e4e9097fd3ed..5761d2896d71 100644 --- a/code/game/atoms/_atom.dm +++ b/code/game/atoms/_atom.dm @@ -180,6 +180,14 @@ /// Relative layer - position this atom should be in within things of the same base layer. defaults to 0. var/relative_layer = 0 + //? Chat colors cache + /// Last name used to calculate a color for the chatmessage overlays + var/chat_color_name + /// Last color calculated for the the chatmessage overlays + var/chat_color + /// A luminescence-shifted value of the last color calculated for chatmessage overlays + var/chat_color_darkened + //? Pixel Offsets /// Default pixel x shifting for the atom's icon. var/base_pixel_x = 0 @@ -538,13 +546,26 @@ else return 0 -/// Show a message to all mobs and objects in sight of this atom -/// Use for objects performing visible actions -/// message is output to anyone who can see, e.g. "The [src] does something!" -/// blind_message (optional) is what blind people will hear e.g. "You hear something!" -// todo: refactor +/** + * Generate a visible message from this atom + * + * Show a message to all player mobs who sees this atom + * + * Show a message to the src mob (if the src is a mob) + * + * Use for atoms performing visible actions + * + * message is output to anyone who can see, e.g. `"The [src] does something!"` + * + * Vars: + * * message is the message output to anyone who can see. + * * self_message (optional) is what the src mob sees e.g. "You do something!" + * * blind_message (optional) is what blind people will hear e.g. "You hear something!" + * * range (optional) define how many tiles away the message can be seen. + */ /atom/proc/visible_message(message, self_message, blind_message, range = world.view) var/list/see + //! LEGACY if(isbelly(loc)) var/obj/belly/B = loc @@ -552,6 +573,7 @@ else see = get_hearers_in_view(range, src) //! end + for(var/atom/movable/AM as anything in see) if(ismob(AM)) var/mob/M = AM @@ -561,6 +583,9 @@ M.show_message(message, 1, blind_message, 2) else if(blind_message) M.show_message(blind_message, 2) + + if(!M.is_blind() && M.client) + M.create_chat_message(src, raw_message = message) else AM.show_message(message, 1, blind_message, 2) @@ -568,15 +593,19 @@ /atom/movable/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) return -/// Show a message to all mobs and objects in earshot of this atom -/// Use for objects performing audible actions -/// message is the message output to anyone who can hear. -/// deaf_message (optional) is what deaf people will see. -/// hearing_distance (optional) is the range, how many tiles away the message can be heard. -/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance, datum/prototype/language/lang) - - var/range = hearing_distance || world.view - var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE) +/** + * Show a message to all mobs in earshot of this atom + * + * Use for objects performing audible actions + * + * vars: + * * message is the message output to anyone who can hear. + * * deaf_message (optional) is what deaf people will see. + * * hearing_distance (optional) is the range, how many tiles away the message can be heard. + * * lang (optional) our language + */ +/atom/proc/audible_message(message, deaf_message, hearing_distance = world.view, datum/prototype/language/lang) + var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src), hearing_distance, remote_ghosts = FALSE) var/list/hearing_mobs = hear["mobs"] var/list/hearing_objs = hear["objs"] @@ -585,16 +614,16 @@ var/obj/O = obj O.show_message(message, 2, deaf_message, 1) - var/no_runechat = FALSE for(var/mob in hearing_mobs) var/mob/M = mob var/msg = message if(lang && !(lang.name in M.languages)) msg = lang.scramble(msg) M.show_message(msg, 2, deaf_message, 1) + // code above scrambles it + if(!M.is_blind() && M.client) + M.create_chat_message(src, raw_message = (message ? msg : deaf_message)) heard_to_floating_message += M - if(!no_runechat && ismovable(src)) - INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, animate_chat), (message ? message : deaf_message), null, FALSE, heard_to_floating_message, 30) /atom/movable/proc/dropInto(var/atom/destination) while(istype(destination)) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 62b3b1284c7a..cdc2ab5a7d2d 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -1,58 +1,66 @@ -#define FONT_SIZE "5pt" -#define FONT_COLOR "#09f" -#define FONT_STYLE "Small Fonts" -#define SCROLL_SPEED 2 - // Status display -// (formerly Countdown timer display) -// Use to show shuttle ETA/ETD times -// Alert status -// And arbitrary messages set by comms computer +#define MAX_STATIC_WIDTH 22 +#define FONT_STYLE "12pt 'TinyUnicode'" +#define SCROLL_RATE (0.04 SECONDS) // time per pixel +#define SCROLL_PADDING 2 // how many pixels we chop to make a smooth loop +#define LINE1_X 1 +#define LINE1_Y -4 +#define LINE2_X 1 +#define LINE2_Y -11 +GLOBAL_DATUM_INIT(status_font, /datum/font, new /datum/font/tiny_unicode/size_12pt()) + +/// Status display which can show images and scrolling text. /obj/machinery/status_display + name = "status display" + desc = null icon = 'icons/obj/status_display.dmi' icon_state = "frame" plane = TURF_PLANE layer = ABOVE_TURF_LAYER - name = "status display" anchored = TRUE density = FALSE use_power = USE_POWER_IDLE idle_power_usage = 10 circuit = /obj/item/circuitboard/status_display - var/mode = 1 // 0 = Blank + + + // We store overlays as keys, so multiple displays can use the same object safely + /// String key we use to index the first effect overlay displayed on us + var/message_key_1 + /// String key we use to index the second effect overlay displayed on us + var/message_key_2 + var/current_picture = "" + var/current_mode = 1 // 0 = Blank // 1 = Shuttle timer // 2 = Arbitrary message(s) // 3 = Alert picture // 4 = Supply shuttle timer - - var/picture_state // Icon_state of alert picture var/message1 = "" // Message line 1 var/message2 = "" // Message line 2 - var/index1 // Display index for scrolling messages or 0 if non-scrolling - var/index2 - var/picture = null - var/frequency = FREQ_STATUS_DISPLAYS // Radio frequency - var/friendc = 0 // Track if Friend Computer mode - var/ignore_friendc = 0 + /// Normal text color + var/text_color = "#22ccff" + /// Color for headers, eg. "- ETA -" + var/header_text_color = "#5d5dfc" - maptext_height = 26 - maptext_width = 32 - maptext_y = -1 + var/frequency = FREQ_STATUS_DISPLAYS // Radio frequency - var/const/CHARS_PER_LINE = 5 - var/const/STATUS_DISPLAY_BLANK = 0 - var/const/STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME = 1 - var/const/STATUS_DISPLAY_MESSAGE = 2 - var/const/STATUS_DISPLAY_ALERT = 3 - var/const/STATUS_DISPLAY_TIME = 4 - var/const/STATUS_DISPLAY_CUSTOM = 99 + var/friendc = FALSE + var/last_picture // For when Friend Computer mode is undone var/seclevel = "green" +// Register for radio system +/obj/machinery/status_display/Initialize(mapload, ndir, building) + . = ..() + update_appearance() + if(radio_controller) + radio_controller.add_object(src, frequency) + /obj/machinery/status_display/Destroy() + remove_messages() if(radio_controller) radio_controller.remove_object(src,frequency) return ..() @@ -64,114 +72,202 @@ attack_hand(user) return -// Register for radio system -/obj/machinery/status_display/Initialize(mapload) +/// Immediately change the display to the given picture. +/obj/machinery/status_display/proc/set_picture(state) + if(state != current_picture) + current_picture = state + + update_appearance() + +/// Immediately change the display to the given two lines. +/obj/machinery/status_display/proc/set_messages(line1, line2) + line1 = uppertext(line1) + line2 = uppertext(line2) + + var/message_changed = FALSE + if(line1 != message1) + message1 = line1 + message_changed = TRUE + + if(line2 != message2) + message2 = line2 + message_changed = TRUE + + if(message_changed) + update_appearance() + +/** + * Remove both message objs and null the fields. + * Don't call this in subclasses. + */ +/obj/machinery/status_display/proc/remove_messages() + var/obj/effect/overlay/status_display_text/overlay_1 = get_status_text(message_key_1) + message_key_1 = null + overlay_1?.disown(src) + var/obj/effect/overlay/status_display_text/overlay_2 = get_status_text(message_key_2) + message_key_2 = null + overlay_2?.disown(src) + +// List in the form key -> status display that shows said key +GLOBAL_LIST_EMPTY(key_to_status_display) + +/proc/generate_status_text(line_y, message, x_offset, text_color, header_text_color, line_pair) + var/key = "[line_y]-[message]-[x_offset]-[text_color]-[header_text_color]-[line_pair]" + var/obj/effect/overlay/status_display_text/new_overlay = GLOB.key_to_status_display[key] + if(!new_overlay) + new_overlay = new(null, line_y, message, text_color, header_text_color, x_offset, line_pair, key) + GLOB.key_to_status_display[key] = new_overlay + return new_overlay + +/proc/get_status_text(key) + return GLOB.key_to_status_display[key] + +/** + * Create/update message overlay. + * They must be handled as real objects for the animation to run. + * Don't call this in subclasses. + * Arguments: + * * overlay - the current /obj/effect/overlay/status_display_text instance + * * line_y - The Y offset to render the text. + * * x_offset - Used to offset the text on the X coordinates, not usually needed. + * * message - the new message text. + * Returns new /obj/effect/overlay/status_display_text or null if unchanged. + */ +/obj/machinery/status_display/proc/update_message(current_key, line_y, message, x_offset, line_pair) + var/obj/effect/overlay/status_display_text/current_overlay = get_status_text(current_key) + var/obj/effect/overlay/status_display_text/new_overlay = generate_status_text(line_y, message, x_offset, text_color, header_text_color, line_pair) + + if(current_overlay == new_overlay) + return current_key + + current_overlay?.disown(src) + new_overlay.own(src) + return new_overlay.status_key + +/obj/machinery/status_display/update_appearance(updates=ALL) . = ..() - if(radio_controller) - radio_controller.add_object(src, frequency) + if( \ + (machine_stat & (NOPOWER|BROKEN)) || \ + (current_mode == SD_BLANK) || \ + (current_mode != SD_PICTURE && message1 == "" && message2 == "") \ + ) + set_light(0) + return + set_light(1.5, 0.7, "#CAF0FF") // blue light -// Timed process -/obj/machinery/status_display/process(delta_time) - if(machine_stat & NOPOWER) - remove_display() +/obj/machinery/status_display/update_overlays(updates) + . = ..() + + if(machine_stat & (NOPOWER|BROKEN)) + remove_messages() return + + switch(current_mode) + if(SD_BLANK) + remove_messages() + // Turn off backlight. + return + if(SD_PICTURE) + remove_messages() + . += mutable_appearance('icons/obj/status_display.dmi', current_picture) + if(current_picture == "ai_off") // If the thing's off, don't display the emissive yeah? + return . + else + var/line1_metric + var/line2_metric + var/line_pair + line1_metric = GLOB.status_font.get_metrics(message1) + line2_metric = GLOB.status_font.get_metrics(message2) + line_pair = (line1_metric > line2_metric ? line1_metric : line2_metric) + + message_key_1 = update_message(message_key_1, LINE1_Y, message1, LINE1_X, line_pair) + message_key_2 = update_message(message_key_2, LINE2_Y, message2, LINE2_X, line_pair) + + // Turn off backlight if message is blank + if(message1 == "" && message2 == "") + return + + . += emissive_appearance(icon, "outline", src, alpha = src.alpha) + +/obj/machinery/status_display/process() + if(machine_stat & NOPOWER) + // No power, no processing. + update_appearance() + + if(friendc) + current_mode = SD_PICTURE + set_picture("ai_friend") + return PROCESS_KILL + + switch(current_mode) + if(SD_EMERGENCY) + return display_escape_shuttle_status() + + if(SD_MESSAGE) + return PROCESS_KILL + + if(SD_PICTURE) + set_picture(last_picture) + return PROCESS_KILL + + if(SD_TIME) + // will be constantly updating + set_messages("TIME", stationtime2text()) + return + + return PROCESS_KILL + +/// Update the display and, if necessary, re-enable processing. +/obj/machinery/status_display/proc/update() + if (process(SSobj.wait/10) != PROCESS_KILL) + START_PROCESSING(SSobj, src) + +/obj/machinery/status_display/power_change() + . = ..() update() /obj/machinery/status_display/emp_act(severity) - if(machine_stat & (BROKEN|NOPOWER)) - ..(severity) + . = ..() + if(machine_stat & (NOPOWER|BROKEN)) return + current_mode = SD_PICTURE set_picture("ai_bsod") - ..(severity) - -// Set what is displayed -/obj/machinery/status_display/proc/update() - remove_display() - if(friendc && !ignore_friendc) - set_picture("ai_friend") - return 1 - - switch(mode) - if(STATUS_DISPLAY_BLANK) // Blank - return 1 - if(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) // Emergency shuttle timer - if(!SSemergencyshuttle) - message1 = "-ETA-" - message2 = "Never" // You're here forever. - return 1 - if(SSemergencyshuttle.waiting_to_leave()) - message1 = "-ETD-" - if(SSemergencyshuttle.shuttle.is_launching()) - message2 = "Launch" - else - message2 = get_shuttle_timer_departure() - if(length(message2) > CHARS_PER_LINE) - message2 = "Error" - update_display(message1, message2) - else if(SSemergencyshuttle.has_eta()) - message1 = "-ETA-" - message2 = get_shuttle_timer_arrival() - if(length(message2) > CHARS_PER_LINE) - message2 = "Error" - update_display(message1, message2) - return 1 - if(STATUS_DISPLAY_MESSAGE) // Custom messages - var/line1 - var/line2 - - if(!index1) - line1 = message1 - else - line1 = copytext(message1+"|"+message1, index1, index1+CHARS_PER_LINE) - var/message1_len = length(message1) - index1 += SCROLL_SPEED - if(index1 > message1_len) - index1 -= message1_len - - if(!index2) - line2 = message2 - else - line2 = copytext(message2+"|"+message2, index2, index2+CHARS_PER_LINE) - var/message2_len = length(message2) - index2 += SCROLL_SPEED - if(index2 > message2_len) - index2 -= message2_len - update_display(line1, line2) - return 1 - if(STATUS_DISPLAY_ALERT) - display_alert(seclevel) - return 1 - if(STATUS_DISPLAY_TIME) - message1 = "TIME" - message2 = stationtime2text() - update_display(message1, message2) - return 1 - return 0 - -/obj/machinery/status_display/examine(mob/user, dist) - . = ..(user) - if(mode != STATUS_DISPLAY_BLANK && mode != STATUS_DISPLAY_ALERT) - to_chat(user, "The display says:
\t[sanitize(message1)]
\t[sanitize(message2)]") - -/obj/machinery/status_display/proc/set_message(m1, m2) - if(m1) - index1 = (length(m1) > CHARS_PER_LINE) - message1 = m1 - else - message1 = "" - index1 = 0 - if(m2) - index2 = (length(m2) > CHARS_PER_LINE) - message2 = m2 +/obj/machinery/status_display/examine(mob/user) + . = ..() + var/obj/effect/overlay/status_display_text/message1_overlay = get_status_text(message_key_1) + var/obj/effect/overlay/status_display_text/message2_overlay = get_status_text(message_key_2) + if (message1_overlay || message2_overlay) + . += "The display says:" + if (message1_overlay.message) + . += "\t[html_encode(message1_overlay.message)]" + if (message2_overlay.message) + . += "\t[html_encode(message2_overlay.message)]" + +// Helper procs. +/obj/machinery/status_display/proc/display_escape_shuttle_status() + if(!SSemergencyshuttle.shuttle) + // the shuttle is missing - no processing + set_messages("shutl","not in service") + return PROCESS_KILL + else if(SSemergencyshuttle.waiting_to_leave() || SSemergencyshuttle.has_eta()) + var/line1 = SSemergencyshuttle.has_eta() ? "-ETA-" : "-ETD-" + var/line2 = SSemergencyshuttle.has_eta() ? SSemergencyshuttle.estimate_arrival_time() : SSemergencyshuttle.estimate_launch_time() + + if (line2 < 0) + line2 = "Now" + else + line2 = "[add_zero(num2text((line2 / 60) % 60),2)]:[add_zero(num2text(line2 % 60), 2)]" + + set_messages(line1, line2) else - message2 = "" - index2 = 0 + // don't kill processing, the timer might turn back on + set_messages("", "") /obj/machinery/status_display/proc/display_alert(newlevel) - remove_display() if(seclevel != newlevel) seclevel = newlevel + set_picture("status_display_[seclevel]") switch(seclevel) if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00") if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00") @@ -180,38 +276,8 @@ if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9") if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633") - set_picture("status_display_[seclevel]") - -/obj/machinery/status_display/proc/set_picture(state) - remove_display() - if(!picture || picture_state != state) - picture_state = state - picture = image('icons/obj/status_display.dmi', icon_state=picture_state) - add_overlay(picture) - -/obj/machinery/status_display/proc/update_display(line1, line2) - line1 = uppertext(line1) - line2 = uppertext(line2) - var/new_text = {"
[line1]
[line2]
"} - if(maptext != new_text) - maptext = new_text - -/obj/machinery/status_display/proc/get_shuttle_timer_arrival() - if(!SSemergencyshuttle) - return "Error" - var/timeleft = SSemergencyshuttle.estimate_arrival_time() - if(timeleft < 0) - return "" - return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" - -/obj/machinery/status_display/proc/get_shuttle_timer_departure() - if(!SSemergencyshuttle) - return "Error" - var/timeleft = SSemergencyshuttle.estimate_launch_time() - if(timeleft < 0) - return "" - return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" +// TODO move me to cargo shuttle display /obj/machinery/status_display/proc/get_supply_shuttle_timer() var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle if(!shuttle) @@ -233,24 +299,118 @@ /obj/machinery/status_display/receive_signal(datum/signal/signal) switch(signal.data["command"]) if("blank") - mode = STATUS_DISPLAY_BLANK + current_mode = SD_BLANK + update_appearance() if("shuttle") - mode = STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME + current_mode = SD_EMERGENCY + update_appearance() if("message") - mode = STATUS_DISPLAY_MESSAGE - set_message(signal.data["msg1"], signal.data["msg2"]) + current_mode = SD_MESSAGE + set_messages(signal.data["msg1"], signal.data["msg2"]) if("alert") - mode = STATUS_DISPLAY_ALERT - set_picture(signal.data["picture_state"]) + current_mode = SD_PICTURE + last_picture = signal.data["picture_state"] + set_picture(last_picture) if("time") - mode = STATUS_DISPLAY_TIME + current_mode = SD_TIME + + if("friendcomputer") + friendc = !friendc update() -#undef FONT_SIZE -#undef FONT_COLOR +/** + * Nice overlay to make text smoothly scroll with no client updates after setup. + */ +/obj/effect/overlay/status_display_text + icon = 'icons/obj/status_display.dmi' + vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + // physically shift down to render correctly + pixel_y = -32 + pixel_z = 32 + + /// The message this overlay is displaying. + var/message + /// Amount of usage this overlay is getting + var/use_count = 0 + /// The status key we represent + var/status_key + + // If the line is short enough to not marquee, and it matches this, it's a header. + var/static/regex/header_regex = regex("^-.*-$") + +/obj/effect/overlay/status_display_text/Initialize(mapload, maptext_y, message, text_color, header_text_color, xoffset = 0, line_pair, status_key) + . = ..() + + src.maptext_y = maptext_y + src.message = message + src.status_key = status_key + + var/line_width = GLOB.status_font.get_metrics(message) + + if(line_width > MAX_STATIC_WIDTH) + // Marquee text + var/marquee_message = "[message] [message] [message]" + + // Width of full content. Must of these is never revealed unless the user inputted a single character. + var/full_marquee_width = GLOB.status_font.get_metrics("[marquee_message] ") + // We loop after only this much has passed. + var/looping_marquee_width = (GLOB.status_font.get_metrics("[message] ]") - SCROLL_PADDING) + + maptext = generate_text(marquee_message, center = FALSE, text_color = text_color) + maptext_width = full_marquee_width + maptext_x = 0 + + // Mask off to fit in screen. + add_filter("mask", 1, alpha_mask_filter(icon = icon(icon, "outline"))) + + // Scroll. + var/time = line_pair * SCROLL_RATE + animate(src, maptext_x = (-looping_marquee_width) + MAX_STATIC_WIDTH, time = time, loop = -1) + animate(maptext_x = MAX_STATIC_WIDTH, time = 0) + else + // Centered text + var/color = header_regex.Find(message) ? header_text_color : text_color + maptext = generate_text(message, center = TRUE, text_color = color) + maptext_x = xoffset //Defaults to 0, this would be centered unless overided + +/obj/effect/overlay/status_display_text/Destroy(force) + GLOB.key_to_status_display -= status_key + return ..() + +/** + * Generate the actual maptext. + * Arguments: + * * text - the text to display + * * center - center the text if TRUE, otherwise right-align (the direction the text is coming from) + * * text_color - the text color + */ +/obj/effect/overlay/status_display_text/proc/generate_text(text, center, text_color) + return {"
[text]
"} + +/// Status displays are static, shared by everyone who needs them +/// This marks us as being used by one more guy +/obj/effect/overlay/status_display_text/proc/own(atom/movable/owned_by) + owned_by.vis_contents += src + use_count += 1 + +/// Status displays are static, shared by everyone who needs them +/// This marks us as no longer being used by a guy +/obj/effect/overlay/status_display_text/proc/disown(atom/movable/disowned_by) + disowned_by.vis_contents -= src + use_count -= 1 + if(use_count <= 0) + qdel(src) + + +#undef MAX_STATIC_WIDTH #undef FONT_STYLE -#undef SCROLL_SPEED +#undef SCROLL_RATE +#undef LINE1_X +#undef LINE1_Y +#undef LINE2_X +#undef LINE2_Y +#undef SCROLL_PADDING diff --git a/code/game/machinery/supply_display.dm b/code/game/machinery/supply_display.dm index 28bd81b2b16b..020f2c2fb050 100644 --- a/code/game/machinery/supply_display.dm +++ b/code/game/machinery/supply_display.dm @@ -1,34 +1,40 @@ /obj/machinery/status_display/supply_display - ignore_friendc = TRUE + name = "supply display" + current_mode = SD_MESSAGE + text_color = "#ff9900" + header_text_color = "#fff743" -/obj/machinery/status_display/supply_display/update() - if(!..() && mode == STATUS_DISPLAY_CUSTOM) - message1 = "CARGO" - message2 = "" +/obj/machinery/status_display/supply_display/process() + if(machine_stat & NOPOWER) + // No power, no processing. + update_appearance() + return PROCESS_KILL - var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle - if(!shuttle) - message2 = "Error" - else if(shuttle.has_arrive_time()) - message2 = get_supply_shuttle_timer() - if(length(message2) > CHARS_PER_LINE) - message2 = "Error" - else if(shuttle.is_launching()) - if(shuttle.at_station()) - message2 = "Launch" - else - message2 = "ETA" + var/line1 = "CARGO" + var/line2 + if(!SSsupply.shuttle) + // Might be missing in our first update on initialize before shuttles + // have loaded. Cross our fingers that it will soon return. + line1 = "shutl" + line2 = "not in service" + else if(SSsupply.shuttle.has_arrive_time()) + line2 = get_supply_shuttle_timer() + else if (SSsupply.shuttle.is_launching()) + if(SSsupply.shuttle.at_station()) + line2 = "Launch" else - if(shuttle.at_station()) - message2 = "Docked" - else - message1 = "" - update_display(message1, message2) - return TRUE - return FALSE + line2 = "ETA" + else + if(SSsupply.shuttle.at_station()) + line2 = "Docked" + else + line1 = "" + line2 = "" + + set_messages(line1, line2) /obj/machinery/status_display/supply_display/receive_signal(datum/signal/signal) - if(signal.data["command"] == "supply") - mode = STATUS_DISPLAY_CUSTOM - else - ..(signal) + // we do not care about whatever signal got sent to us as we only do supply shuttle + // and friendc only gets set in receive_signal + return + diff --git a/code/modules/client/client.dm b/code/modules/client/client.dm index 9bbccd20ea69..8a1473a38ce8 100644 --- a/code/modules/client/client.dm +++ b/code/modules/client/client.dm @@ -133,6 +133,9 @@ /// statpanel var/datum/client_statpanel/tgui_stat + /// Messages currently seen by this client + var/list/seen_messages + //* UI - Map *// /// Our action drawer var/datum/action_drawer/action_drawer diff --git a/code/modules/security levels/security levels.dm b/code/modules/security levels/security levels.dm index 8f519ca3af3d..a0f45769ff9a 100644 --- a/code/modules/security levels/security levels.dm +++ b/code/modules/security levels/security levels.dm @@ -75,7 +75,7 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) for(var/obj/machinery/status_display/FA in GLOB.machines) if(FA.z in (LEGACY_MAP_DATUM).contact_levels) FA.display_alert(newlevel) - FA.mode = 3 + FA.current_mode = SD_PICTURE if(level >= SEC_LEVEL_RED) if(SSlegacy_atc.squelched == FALSE) // Do nothing, ATC relay is already off diff --git a/interface/fonts/Grand9K_Pixel.ttf b/interface/fonts/Grand9K_Pixel.ttf new file mode 100644 index 000000000000..cf6fdf44e2ec Binary files /dev/null and b/interface/fonts/Grand9K_Pixel.ttf differ diff --git a/interface/fonts/Pixellari.ttf b/interface/fonts/Pixellari.ttf new file mode 100644 index 000000000000..5a3a3c2b1104 Binary files /dev/null and b/interface/fonts/Pixellari.ttf differ diff --git a/interface/fonts/SpessFont.ttf b/interface/fonts/SpessFont.ttf new file mode 100644 index 000000000000..8f7c7e08d0d8 Binary files /dev/null and b/interface/fonts/SpessFont.ttf differ diff --git a/interface/fonts/TinyUnicode.ttf b/interface/fonts/TinyUnicode.ttf new file mode 100644 index 000000000000..74d0d3e386e6 Binary files /dev/null and b/interface/fonts/TinyUnicode.ttf differ diff --git a/interface/fonts/VCR_OSD_Mono.ttf b/interface/fonts/VCR_OSD_Mono.ttf new file mode 100644 index 000000000000..dcca687a434d Binary files /dev/null and b/interface/fonts/VCR_OSD_Mono.ttf differ diff --git a/interface/fonts/fonts_datum.dm b/interface/fonts/fonts_datum.dm new file mode 100644 index 000000000000..a346706d7fa0 --- /dev/null +++ b/interface/fonts/fonts_datum.dm @@ -0,0 +1,78 @@ +/// A font datum, it exists to define a custom font to use in a span style later. +/datum/font + /// Font name, just so people know what to put in their span style. + var/name + /// The font file we link to. + var/font_family + + /// Font features and metrics + /// Generated by Lummox's dmifontsplus (https://www.byond.com/developer/LummoxJR/DmiFontsPlus) + /// Note: these variable names have been changed, so you can't straight copy/paste from dmifontsplus.exe + + /// list of font size/spacing metrics + var/list/metrics + /// total height of a line + var/height + /// distance above baseline (including whitespace) + var/ascent + /// distance below baseline + var/descent + /// average character width + var/average_width + /// maximum character width + var/max_width + /// extra width, such as from italics, for a line + var/overhang + /// internal leading vertical space, for accent marks + var/in_leading + /// external leading vertical space, just plain blank + var/ex_leading + /// default character (for undefined chars) + var/default_character + /// first character in metrics + var/start + /// last character in metrics + var/end + +/// Get font metrics +/// From Lummox's dmifontsplus (https://www.byond.com/developer/LummoxJR/DmiFontsPlus) +/datum/font/proc/get_metrics(text, flags, first_line) + . = 0 + var/longest = 0 + if(!length(text)) + return + + var/i = 1 + var/idx + while(i <= length(text)) + var/character = text2ascii(text, i++) + if(character <= 10) + if(character <= 7) + . += character // spacers for justification + + if(character <= 9) + continue // soft-break chars + + if(. && idx && !(flags & INCLUDE_AC)) + . -= max(metrics[idx + 3], 0) + + longest = max(longest, . + first_line) + . = 0 + first_line = 0 + idx = 0 + continue + + idx = (character - start) * 3 + if(idx <= 0 || idx >= metrics.len) + idx = (default_character - start) * 3 + + if(!. && !(flags & INCLUDE_AC)) + . -= metrics[idx + 1] + . += metrics[idx + 1] + metrics[idx + 2] + metrics[idx +3] + + if(. && idx && !(flags & INCLUDE_AC)) + . -= max(metrics[idx + 3], 0) + + . = max(. + first_line, longest) + if(. > 0) + . += overhang diff --git a/interface/fonts/grand_9k.dm b/interface/fonts/grand_9k.dm new file mode 100644 index 000000000000..7993d307bcbe --- /dev/null +++ b/interface/fonts/grand_9k.dm @@ -0,0 +1,253 @@ +/// For clean results on map, use only sizing pt, multiples of 6: 6pt 12pt 18pt 24pt etc. - Not for use with px sizing +/// Can be used in TGUI etc, px sizing is pt / 0.75. 6pt = 8px, 12pt = 16px etc. + +/// Base font +/datum/font/grand9k + name = "Grand9K Pixel" + font_family = 'interface/fonts/Grand9K_Pixel.ttf' + +/// For icon overlays +/// Grand9K 6pt metrics generated using Lummox's dmifontsplus (https://www.byond.com/developer/LummoxJR/DmiFontsPlus) +/// Note: these variable names have been changed, so you can't straight copy/paste from dmifontsplus.exe +/datum/font/grand9k/size_6pt + name = "Grand9K Pixel 6pt" + height = 12 + ascent = 10 + descent = 2 + average_width = 4 + max_width = 9 + overhang = 0 + in_leading = 4 + ex_leading = 1 + default_character = 31 + start = 30 + end = 255 + metrics = list( + 0, 5, 1, // char 30 + 0, 5, 1, // char 31 + 0, 1, 1, // char 32 + 0, 1, 1, // char 33 + 0, 3, 1, // char 34 + 0, 6, 1, // char 35 + 0, 5, 1, // char 36 + 0, 7, 1, // char 37 + 0, 5, 1, // char 38 + 0, 1, 1, // char 39 + 0, 3, 1, // char 40 + 0, 3, 1, // char 41 + 0, 5, 1, // char 42 + 0, 5, 1, // char 43 + 0, 1, 1, // char 44 + 0, 4, 1, // char 45 + 0, 1, 1, // char 46 + 0, 3, 1, // char 47 + 0, 5, 1, // char 48 + 0, 2, 1, // char 49 + 0, 5, 1, // char 50 + 0, 4, 1, // char 51 + 0, 5, 1, // char 52 + 0, 5, 1, // char 53 + 0, 5, 1, // char 54 + 0, 5, 1, // char 55 + 0, 5, 1, // char 56 + 0, 5, 1, // char 57 + 0, 1, 1, // char 58 + 0, 1, 1, // char 59 + 0, 4, 1, // char 60 + 0, 4, 1, // char 61 + 0, 4, 1, // char 62 + 0, 4, 1, // char 63 + 0, 7, 1, // char 64 + 0, 5, 1, // char 65 + 0, 5, 1, // char 66 + 0, 4, 1, // char 67 + 0, 5, 1, // char 68 + 0, 4, 1, // char 69 + 0, 4, 1, // char 70 + 0, 5, 1, // char 71 + 0, 5, 1, // char 72 + 0, 1, 1, // char 73 + 0, 5, 1, // char 74 + 0, 5, 1, // char 75 + 0, 5, 1, // char 76 + 0, 5, 1, // char 77 + 0, 5, 1, // char 78 + 0, 5, 1, // char 79 + 0, 5, 1, // char 80 + 0, 6, 1, // char 81 + 0, 5, 1, // char 82 + 0, 5, 1, // char 83 + 0, 5, 1, // char 84 + 0, 5, 1, // char 85 + 0, 5, 1, // char 86 + 0, 5, 1, // char 87 + 0, 5, 1, // char 88 + 0, 5, 1, // char 89 + 0, 5, 1, // char 90 + 0, 3, 1, // char 91 + 0, 3, 1, // char 92 + 0, 3, 1, // char 93 + 0, 5, 1, // char 94 + 0, 4, 0, // char 95 + 0, 2, 1, // char 96 + 0, 4, 1, // char 97 + 0, 4, 1, // char 98 + 0, 3, 1, // char 99 + 0, 4, 1, // char 100 + 0, 4, 1, // char 101 + 0, 4, 1, // char 102 + 0, 4, 1, // char 103 + 0, 4, 1, // char 104 + 0, 1, 1, // char 105 + 0, 3, 1, // char 106 + 0, 4, 1, // char 107 + 0, 1, 1, // char 108 + 0, 5, 1, // char 109 + 0, 4, 1, // char 110 + 0, 4, 1, // char 111 + 0, 4, 1, // char 112 + 0, 4, 1, // char 113 + 0, 4, 1, // char 114 + 0, 4, 1, // char 115 + 0, 4, 1, // char 116 + 0, 4, 1, // char 117 + 0, 5, 1, // char 118 + 0, 5, 1, // char 119 + 0, 5, 1, // char 120 + 0, 4, 1, // char 121 + 0, 5, 1, // char 122 + 0, 4, 1, // char 123 + 0, 1, 1, // char 124 + 0, 4, 1, // char 125 + 0, 6, 1, // char 126 + 0, 5, 1, // char 127 + 0, 5, 1, // char 128 + 0, 5, 1, // char 129 + 0, 1, 1, // char 130 + 0, 5, 1, // char 131 + 0, 3, 1, // char 132 + 0, 5, 1, // char 133 + 0, 5, 1, // char 134 + 0, 5, 1, // char 135 + 0, 5, 1, // char 136 + 0, 5, 1, // char 137 + 0, 5, 1, // char 138 + 0, 3, 1, // char 139 + 0, 6, 1, // char 140 + 0, 5, 1, // char 141 + 0, 5, 1, // char 142 + 0, 5, 1, // char 143 + 0, 5, 1, // char 144 + 0, 1, 1, // char 145 + 0, 1, 1, // char 146 + 0, 3, 1, // char 147 + 0, 3, 1, // char 148 + 0, 1, 1, // char 149 + 0, 5, 1, // char 150 + 0, 5, 1, // char 151 + 0, 5, 1, // char 152 + 0, 8, 1, // char 153 + 0, 4, 1, // char 154 + 0, 3, 1, // char 155 + 0, 5, 1, // char 156 + 0, 5, 1, // char 157 + 0, 5, 1, // char 158 + 0, 5, 1, // char 159 + 0, 1, 1, // char 160 + 0, 1, 1, // char 161 + 0, 4, 1, // char 162 + 0, 5, 1, // char 163 + 0, 5, 1, // char 164 + 0, 5, 1, // char 165 + 0, 1, 1, // char 166 + 0, 5, 1, // char 167 + 0, 3, 1, // char 168 + 0, 8, 1, // char 169 + 0, 5, 1, // char 170 + 0, 6, 1, // char 171 + 0, 4, 1, // char 172 + 0, 5, 1, // char 173 + 0, 8, 1, // char 174 + 0, 5, 1, // char 175 + 0, 3, 1, // char 176 + 0, 5, 1, // char 177 + 0, 5, 1, // char 178 + 0, 5, 1, // char 179 + 0, 2, 1, // char 180 + 0, 4, 1, // char 181 + 0, 5, 1, // char 182 + 0, 1, 1, // char 183 + 0, 2, 1, // char 184 + 0, 5, 1, // char 185 + 0, 5, 1, // char 186 + 0, 6, 1, // char 187 + 0, 5, 1, // char 188 + 0, 5, 1, // char 189 + 0, 5, 1, // char 190 + 0, 4, 1, // char 191 + 0, 5, 1, // char 192 + 0, 5, 1, // char 193 + 0, 5, 1, // char 194 + 0, 6, 0, // char 195 + 0, 5, 1, // char 196 + 0, 5, 1, // char 197 + 0, 6, 1, // char 198 + 0, 4, 1, // char 199 + 0, 4, 1, // char 200 + 0, 4, 1, // char 201 + 0, 4, 1, // char 202 + 0, 4, 1, // char 203 + 1, 2, 0, // char 204 + 0, 2, 1, // char 205 + 0, 3, 0, // char 206 + 0, 3, 0, // char 207 + 0, 6, 1, // char 208 + 0, 6, 0, // char 209 + 0, 5, 1, // char 210 + 0, 5, 1, // char 211 + 0, 5, 1, // char 212 + 0, 6, 1, // char 213 + 0, 5, 1, // char 214 + 0, 5, 1, // char 215 + 0, 5, 1, // char 216 + 0, 5, 1, // char 217 + 0, 5, 1, // char 218 + 0, 5, 1, // char 219 + 0, 5, 1, // char 220 + 0, 5, 1, // char 221 + 0, 5, 1, // char 222 + 0, 5, 1, // char 223 + 0, 4, 1, // char 224 + 0, 4, 1, // char 225 + 0, 4, 1, // char 226 + 0, 4, 1, // char 227 + 0, 4, 1, // char 228 + 0, 4, 1, // char 229 + 0, 5, 1, // char 230 + 0, 3, 1, // char 231 + 0, 4, 1, // char 232 + 0, 4, 1, // char 233 + 0, 4, 1, // char 234 + 0, 4, 1, // char 235 + 0, 2, 1, // char 236 + 1, 2, 0, // char 237 + 0, 3, 0, // char 238 + 0, 3, 0, // char 239 + 0, 5, 0, // char 240 + 0, 4, 1, // char 241 + 0, 4, 1, // char 242 + 0, 4, 1, // char 243 + 0, 4, 1, // char 244 + 0, 4, 1, // char 245 + 0, 4, 1, // char 246 + 0, 5, 1, // char 247 + 0, 4, 1, // char 248 + 0, 4, 1, // char 249 + 0, 4, 1, // char 250 + 0, 4, 1, // char 251 + 0, 4, 1, // char 252 + 0, 4, 1, // char 253 + 0, 4, 1, // char 254 + 0, 4, 1, // char 255 + 226 + ) diff --git a/interface/fonts/license.txt b/interface/fonts/license.txt new file mode 100644 index 000000000000..9aa70fbac2a9 --- /dev/null +++ b/interface/fonts/license.txt @@ -0,0 +1,13 @@ +Grand9K Pixel created by Jayvee Enaguas. Licensed under Creative Commons Attribution 4.0 International (CC BY 4.0) +(https://creativecommons.org/licenses/by/4.0/) (https://www.dafont.com/grand9k-pixel.font) + +Pixellari created by Zacchary Dempsey-Plante. Website indicates free for commercial use. +(https://www.dafont.com/pixellari.font?fpp=200) + +Spess Font created by MTandi (discord) for /tg/station. + +Tiny Unicode created by Jakob Riedle/DuffsDevice. Website indicates free for commercial use. +(https://fontmeme.com/fonts/tiny-unicode-font/) + +VCR OSD Mono created by Riciery Leal/mrmanet. Website indicates 100% free, author confirms it's free for all to use. +(https://www.dafont.com/font-comment.php?file=vcr_osd_mono) diff --git a/interface/fonts/pixellari.dm b/interface/fonts/pixellari.dm new file mode 100644 index 000000000000..24fcd1961fec --- /dev/null +++ b/interface/fonts/pixellari.dm @@ -0,0 +1,252 @@ +/// For clean results on map, use only sizing pt, multiples of 12: 12pt 24pt 48pt etc. - Not for use with px sizing +/// Can be used in TGUI etc, px sizing is pt / 0.75. 12pt = 16px, 24pt = 32px etc. + +/// Base font +/datum/font/pixellari + name = "Pixellari" + font_family = 'interface/fonts/Pixellari.ttf' + +/// For icon overlays +/// Pixellari 12pt metrics generated using Lummox's dmifontsplus (https://www.byond.com/developer/LummoxJR/DmiFontsPlus) +/// Note: these variable names have been changed, so you can't straight copy/paste from dmifontsplus.exe +/datum/font/pixellari/size_12pt + name = "Pixellari 12pt" + height = 16 + ascent = 12 + descent = 4 + average_width = 7 + max_width = 15 + overhang = 0 + in_leading = 0 + ex_leading = 1 + default_character = 31 + start = 30 + end = 255 + metrics = list(\ + 1, 5, 0, /* char 30 */ \ + 1, 5, 0, /* char 31 */ \ + 0, 1, 4, /* char 32 */ \ + 1, 2, 1, /* char 33 */ \ + 1, 5, 1, /* char 34 */ \ + 0, 8, 1, /* char 35 */ \ + 2, 6, 1, /* char 36 */ \ + 0, 13, 1, /* char 37 */ \ + 1, 8, 1, /* char 38 */ \ + 1, 2, 1, /* char 39 */ \ + 1, 3, 1, /* char 40 */ \ + 2, 3, 1, /* char 41 */ \ + 0, 6, 1, /* char 42 */ \ + 1, 6, 1, /* char 43 */ \ + 1, 2, 1, /* char 44 */ \ + 1, 6, 1, /* char 45 */ \ + 1, 2, 1, /* char 46 */ \ + 0, 6, 1, /* char 47 */ \ + 1, 7, 1, /* char 48 */ \ + 2, 6, 1, /* char 49 */ \ + 1, 6, 1, /* char 50 */ \ + 1, 6, 1, /* char 51 */ \ + 1, 7, 1, /* char 52 */ \ + 1, 6, 1, /* char 53 */ \ + 1, 6, 1, /* char 54 */ \ + 1, 7, 1, /* char 55 */ \ + 1, 6, 1, /* char 56 */ \ + 1, 6, 1, /* char 57 */ \ + 1, 2, 1, /* char 58 */ \ + 1, 2, 1, /* char 59 */ \ + 0, 10, 1, /* char 60 */ \ + 1, 6, 1, /* char 61 */ \ + 0, 10, 1, /* char 62 */ \ + 1, 6, 1, /* char 63 */ \ + 1, 12, 1, /* char 64 */ \ + 1, 8, 1, /* char 65 */ \ + 1, 8, 1, /* char 66 */ \ + 2, 7, 1, /* char 67 */ \ + 2, 8, 1, /* char 68 */ \ + 2, 6, 1, /* char 69 */ \ + 2, 6, 1, /* char 70 */ \ + 2, 7, 1, /* char 71 */ \ + 1, 8, 1, /* char 72 */ \ + 1, 4, 1, /* char 73 */ \ + 0, 7, 1, /* char 74 */ \ + 1, 8, 1, /* char 75 */ \ + 1, 6, 1, /* char 76 */ \ + 1, 10, 1, /* char 77 */ \ + 1, 9, 1, /* char 78 */ \ + 2, 8, 1, /* char 79 */ \ + 1, 7, 1, /* char 80 */ \ + 2, 9, 1, /* char 81 */ \ + 1, 8, 1, /* char 82 */ \ + 1, 8, 1, /* char 83 */ \ + 1, 8, 1, /* char 84 */ \ + 2, 8, 1, /* char 85 */ \ + 2, 8, 1, /* char 86 */ \ + 1, 10, 1, /* char 87 */ \ + 1, 8, 1, /* char 88 */ \ + 1, 8, 1, /* char 89 */ \ + 0, 10, 1, /* char 90 */ \ + 1, 3, 1, /* char 91 */ \ + 0, 6, 1, /* char 92 */ \ + 2, 3, 1, /* char 93 */ \ + 0, 7, 1, /* char 94 */ \ + 0, 8, 1, /* char 95 */ \ + 1, 3, 1, /* char 96 */ \ + 1, 6, 1, /* char 97 */ \ + 1, 7, 1, /* char 98 */ \ + 1, 6, 1, /* char 99 */ \ + 1, 7, 1, /* char 100 */ \ + 1, 6, 1, /* char 101 */ \ + 1, 4, 1, /* char 102 */ \ + 1, 7, 1, /* char 103 */ \ + 1, 7, 1, /* char 104 */ \ + 1, 2, 1, /* char 105 */ \ + -1, 4, 1, /* char 106 */ \ + 0, 7, 1, /* char 107 */ \ + 1, 2, 1, /* char 108 */ \ + 1, 10, 1, /* char 109 */ \ + 1, 6, 1, /* char 110 */ \ + 1, 6, 1, /* char 111 */ \ + 1, 7, 1, /* char 112 */ \ + 1, 7, 1, /* char 113 */ \ + 1, 6, 1, /* char 114 */ \ + 1, 6, 1, /* char 115 */ \ + 0, 4, 1, /* char 116 */ \ + 1, 6, 1, /* char 117 */ \ + 1, 6, 1, /* char 118 */ \ + 1, 10, 1, /* char 119 */ \ + 1, 6, 1, /* char 120 */ \ + 1, 6, 1, /* char 121 */ \ + 1, 6, 1, /* char 122 */ \ + 0, 5, 1, /* char 123 */ \ + 1, 2, 1, /* char 124 */ \ + 0, 5, 1, /* char 125 */ \ + 1, 8, 1, /* char 126 */ \ + 1, 5, 0, /* char 127 */ \ + 1, 8, 1, /* char 128 */ \ + 1, 5, 0, /* char 129 */ \ + 1, 5, 0, /* char 130 */ \ + 1, 5, 0, /* char 131 */ \ + 1, 5, 0, /* char 132 */ \ + 1, 5, 0, /* char 133 */ \ + 1, 5, 0, /* char 134 */ \ + 1, 5, 0, /* char 135 */ \ + 1, 5, 0, /* char 136 */ \ + 1, 5, 0, /* char 137 */ \ + 1, 8, 1, /* char 138 */ \ + 1, 5, 0, /* char 139 */ \ + 0, 14, 1, /* char 140 */ \ + 1, 5, 0, /* char 141 */ \ + 0, 10, 1, /* char 142 */ \ + 1, 5, 0, /* char 143 */ \ + 1, 5, 0, /* char 144 */ \ + 1, 5, 0, /* char 145 */ \ + 1, 5, 0, /* char 146 */ \ + 1, 5, 0, /* char 147 */ \ + 1, 5, 0, /* char 148 */ \ + 1, 5, 0, /* char 149 */ \ + 1, 5, 0, /* char 150 */ \ + 1, 5, 0, /* char 151 */ \ + 1, 5, 0, /* char 152 */ \ + 1, 5, 0, /* char 153 */ \ + 1, 6, 1, /* char 154 */ \ + 1, 5, 0, /* char 155 */ \ + 1, 11, 1, /* char 156 */ \ + 1, 5, 0, /* char 157 */ \ + 1, 6, 1, /* char 158 */ \ + 1, 8, 1, /* char 159 */ \ + 0, 1, 4, /* char 160 */ \ + 1, 2, 1, /* char 161 */ \ + 1, 6, 1, /* char 162 */ \ + 0, 8, 1, /* char 163 */ \ + 0, 9, 1, /* char 164 */ \ + 1, 8, 1, /* char 165 */ \ + 1, 2, 1, /* char 166 */ \ + 1, 7, 1, /* char 167 */ \ + 0, 5, 1, /* char 168 */ \ + -1, 12, 1, /* char 169 */ \ + 0, 6, 1, /* char 170 */ \ + 0, 8, 1, /* char 171 */ \ + 1, 8, 1, /* char 172 */ \ + 1, 5, 0, /* char 173 */ \ + -1, 12, 1, /* char 174 */ \ + 2, 4, 1, /* char 175 */ \ + 0, 6, 1, /* char 176 */ \ + 1, 6, 1, /* char 177 */ \ + 0, 5, 1, /* char 178 */ \ + 0, 5, 1, /* char 179 */ \ + 1, 3, 1, /* char 180 */ \ + 1, 6, 1, /* char 181 */ \ + 1, 7, 1, /* char 182 */ \ + 1, 2, 1, /* char 183 */ \ + 1, 3, 1, /* char 184 */ \ + 1, 4, 1, /* char 185 */ \ + 0, 6, 1, /* char 186 */ \ + 0, 8, 1, /* char 187 */ \ + 1, 13, 1, /* char 188 */ \ + 1, 12, 1, /* char 189 */ \ + 0, 13, 1, /* char 190 */ \ + 1, 6, 1, /* char 191 */ \ + 1, 8, 1, /* char 192 */ \ + 1, 8, 1, /* char 193 */ \ + 1, 8, 1, /* char 194 */ \ + 1, 8, 1, /* char 195 */ \ + 1, 8, 1, /* char 196 */ \ + 1, 8, 1, /* char 197 */ \ + 0, 13, 1, /* char 198 */ \ + 2, 7, 1, /* char 199 */ \ + 2, 6, 1, /* char 200 */ \ + 2, 6, 1, /* char 201 */ \ + 2, 6, 1, /* char 202 */ \ + 2, 6, 1, /* char 203 */ \ + 1, 4, 1, /* char 204 */ \ + 1, 4, 1, /* char 205 */ \ + 1, 4, 1, /* char 206 */ \ + 1, 4, 1, /* char 207 */ \ + 0, 10, 1, /* char 208 */ \ + 1, 9, 1, /* char 209 */ \ + 2, 8, 1, /* char 210 */ \ + 2, 8, 1, /* char 211 */ \ + 2, 8, 1, /* char 212 */ \ + 2, 8, 1, /* char 213 */ \ + 2, 8, 1, /* char 214 */ \ + 1, 6, 1, /* char 215 */ \ + -2, 14, 1, /* char 216 */ \ + 2, 8, 1, /* char 217 */ \ + 2, 8, 1, /* char 218 */ \ + 2, 8, 1, /* char 219 */ \ + 2, 8, 1, /* char 220 */ \ + 1, 8, 1, /* char 221 */ \ + 1, 8, 1, /* char 222 */ \ + 1, 8, 1, /* char 223 */ \ + 1, 6, 1, /* char 224 */ \ + 1, 6, 1, /* char 225 */ \ + 1, 6, 1, /* char 226 */ \ + 1, 6, 1, /* char 227 */ \ + 1, 6, 1, /* char 228 */ \ + 1, 6, 1, /* char 229 */ \ + 1, 11, 1, /* char 230 */ \ + 1, 6, 1, /* char 231 */ \ + 1, 6, 1, /* char 232 */ \ + 1, 6, 1, /* char 233 */ \ + 1, 6, 1, /* char 234 */ \ + 1, 6, 1, /* char 235 */ \ + 1, 2, 1, /* char 236 */ \ + 1, 2, 1, /* char 237 */ \ + 0, 4, 1, /* char 238 */ \ + 0, 4, 1, /* char 239 */ \ + 1, 7, 1, /* char 240 */ \ + 1, 6, 1, /* char 241 */ \ + 1, 6, 1, /* char 242 */ \ + 1, 6, 1, /* char 243 */ \ + 1, 6, 1, /* char 244 */ \ + 1, 6, 1, /* char 245 */ \ + 1, 6, 1, /* char 246 */ \ + 1, 6, 1, /* char 247 */ \ + 0, 10, 1, /* char 248 */ \ + 1, 6, 1, /* char 249 */ \ + 1, 6, 1, /* char 250 */ \ + 1, 6, 1, /* char 251 */ \ + 1, 6, 1, /* char 252 */ \ + 1, 6, 1, /* char 253 */ \ + 1, 8, 1, /* char 254 */ \ + 1, 6, 1, /* char 255 */ \ + 226) diff --git a/interface/fonts/spess_font.dm b/interface/fonts/spess_font.dm new file mode 100644 index 000000000000..07e8ea5b3ba6 --- /dev/null +++ b/interface/fonts/spess_font.dm @@ -0,0 +1,252 @@ +/// For clean results on map, use only sizing pt, multiples of 6: 6t 12pt 18pt etc. - Not for use with px sizing +/// Can be used in TGUI etc, px sizing is pt / 0.75. 12pt = 16px, 24pt = 32px etc. + +/// Base font +/datum/font/spessfont + name = "Spess Font" + font_family = 'interface/fonts/SpessFont.ttf' + +/// For icon overlays +/// Spess Font 6pt metrics generated using Lummox's dmifontsplus (https://www.byond.com/developer/LummoxJR/DmiFontsPlus) +/// Note: these variable names have been changed, so you can't straight copy/paste from dmifontsplus.exe +/datum/font/spessfont/size_6pt + name = "Spess Font 6pt" + height = 8 + ascent = 6 + descent = 2 + average_width = 4 + max_width = 6 + overhang = 0 + in_leading = 0 + ex_leading = 0 + default_character = 31 + start = 30 + end = 255 + metrics = list(\ + 0, 1, 0, /* char 30 */ \ + 0, 1, 0, /* char 31 */ \ + 0, 1, 1, /* char 32 */ \ + 0, 1, 1, /* char 33 */ \ + 0, 3, 1, /* char 34 */ \ + 0, 5, 1, /* char 35 */ \ + 0, 3, 1, /* char 36 */ \ + 0, 5, 1, /* char 37 */ \ + 0, 5, 1, /* char 38 */ \ + 0, 1, 1, /* char 39 */ \ + 0, 2, 1, /* char 40 */ \ + 0, 2, 1, /* char 41 */ \ + 0, 3, 1, /* char 42 */ \ + 0, 3, 1, /* char 43 */ \ + 0, 1, 1, /* char 44 */ \ + 0, 3, 1, /* char 45 */ \ + 0, 1, 1, /* char 46 */ \ + 0, 3, 1, /* char 47 */ \ + 0, 4, 1, /* char 48 */ \ + 0, 2, 1, /* char 49 */ \ + 0, 4, 1, /* char 50 */ \ + 0, 4, 1, /* char 51 */ \ + 0, 4, 1, /* char 52 */ \ + 0, 4, 1, /* char 53 */ \ + 0, 4, 1, /* char 54 */ \ + 0, 4, 1, /* char 55 */ \ + 0, 4, 1, /* char 56 */ \ + 0, 4, 1, /* char 57 */ \ + 0, 1, 1, /* char 58 */ \ + 0, 1, 1, /* char 59 */ \ + 0, 3, 1, /* char 60 */ \ + 0, 3, 1, /* char 61 */ \ + 0, 3, 1, /* char 62 */ \ + 0, 3, 1, /* char 63 */ \ + 0, 4, 1, /* char 64 */ \ + 0, 4, 1, /* char 65 */ \ + 0, 4, 1, /* char 66 */ \ + 0, 4, 1, /* char 67 */ \ + 0, 4, 1, /* char 68 */ \ + 0, 4, 1, /* char 69 */ \ + 0, 4, 1, /* char 70 */ \ + 0, 4, 1, /* char 71 */ \ + 0, 4, 1, /* char 72 */ \ + 0, 3, 1, /* char 73 */ \ + 0, 4, 1, /* char 74 */ \ + 0, 4, 1, /* char 75 */ \ + 0, 4, 1, /* char 76 */ \ + 0, 5, 1, /* char 77 */ \ + 0, 4, 1, /* char 78 */ \ + 0, 4, 1, /* char 79 */ \ + 0, 4, 1, /* char 80 */ \ + 0, 4, 1, /* char 81 */ \ + 0, 4, 1, /* char 82 */ \ + 0, 4, 1, /* char 83 */ \ + 0, 5, 1, /* char 84 */ \ + 0, 4, 1, /* char 85 */ \ + 0, 4, 1, /* char 86 */ \ + 0, 5, 1, /* char 87 */ \ + 0, 5, 1, /* char 88 */ \ + 0, 4, 1, /* char 89 */ \ + 0, 4, 1, /* char 90 */ \ + 0, 2, 1, /* char 91 */ \ + 0, 3, 1, /* char 92 */ \ + 0, 2, 1, /* char 93 */ \ + 0, 3, 1, /* char 94 */ \ + 0, 4, 1, /* char 95 */ \ + 0, 2, 1, /* char 96 */ \ + 0, 3, 1, /* char 97 */ \ + 0, 4, 1, /* char 98 */ \ + 0, 3, 1, /* char 99 */ \ + 0, 4, 1, /* char 100 */ \ + 0, 3, 1, /* char 101 */ \ + 0, 2, 1, /* char 102 */ \ + 0, 4, 1, /* char 103 */ \ + 0, 3, 1, /* char 104 */ \ + 0, 1, 1, /* char 105 */ \ + 0, 1, 1, /* char 106 */ \ + 0, 3, 1, /* char 107 */ \ + 0, 1, 1, /* char 108 */ \ + 0, 5, 1, /* char 109 */ \ + 0, 3, 1, /* char 110 */ \ + 0, 4, 1, /* char 111 */ \ + 0, 4, 1, /* char 112 */ \ + 0, 4, 1, /* char 113 */ \ + 0, 2, 1, /* char 114 */ \ + 0, 3, 1, /* char 115 */ \ + 0, 2, 1, /* char 116 */ \ + 0, 3, 1, /* char 117 */ \ + 0, 3, 1, /* char 118 */ \ + 0, 5, 1, /* char 119 */ \ + 0, 3, 1, /* char 120 */ \ + 0, 3, 1, /* char 121 */ \ + 0, 3, 1, /* char 122 */ \ + 0, 3, 1, /* char 123 */ \ + 0, 1, 1, /* char 124 */ \ + 0, 3, 1, /* char 125 */ \ + 0, 4, 1, /* char 126 */ \ + 0, 1, 0, /* char 127 */ \ + 0, 1, 0, /* char 128 */ \ + 0, 1, 0, /* char 129 */ \ + 0, 1, 0, /* char 130 */ \ + 0, 1, 0, /* char 131 */ \ + 0, 1, 0, /* char 132 */ \ + 0, 1, 0, /* char 133 */ \ + 0, 1, 0, /* char 134 */ \ + 0, 1, 0, /* char 135 */ \ + 0, 1, 0, /* char 136 */ \ + 0, 1, 0, /* char 137 */ \ + 0, 1, 0, /* char 138 */ \ + 0, 1, 0, /* char 139 */ \ + 0, 1, 0, /* char 140 */ \ + 0, 1, 0, /* char 141 */ \ + 0, 1, 0, /* char 142 */ \ + 0, 1, 0, /* char 143 */ \ + 0, 1, 0, /* char 144 */ \ + 0, 1, 0, /* char 145 */ \ + 0, 1, 0, /* char 146 */ \ + 0, 1, 0, /* char 147 */ \ + 0, 1, 0, /* char 148 */ \ + 0, 1, 0, /* char 149 */ \ + 0, 1, 0, /* char 150 */ \ + 0, 1, 0, /* char 151 */ \ + 0, 1, 0, /* char 152 */ \ + 0, 1, 0, /* char 153 */ \ + 0, 1, 0, /* char 154 */ \ + 0, 1, 0, /* char 155 */ \ + 0, 1, 0, /* char 156 */ \ + 0, 1, 0, /* char 157 */ \ + 0, 1, 0, /* char 158 */ \ + 0, 1, 0, /* char 159 */ \ + 0, 1, 0, /* char 160 */ \ + 0, 1, 0, /* char 161 */ \ + 0, 1, 0, /* char 162 */ \ + 0, 1, 0, /* char 163 */ \ + 0, 1, 0, /* char 164 */ \ + 0, 1, 0, /* char 165 */ \ + 0, 1, 0, /* char 166 */ \ + 0, 1, 0, /* char 167 */ \ + 0, 1, 0, /* char 168 */ \ + 0, 1, 0, /* char 169 */ \ + 0, 1, 0, /* char 170 */ \ + 0, 1, 0, /* char 171 */ \ + 0, 1, 0, /* char 172 */ \ + 0, 1, 0, /* char 173 */ \ + 0, 1, 0, /* char 174 */ \ + 0, 1, 0, /* char 175 */ \ + 0, 1, 0, /* char 176 */ \ + 0, 1, 0, /* char 177 */ \ + 0, 1, 0, /* char 178 */ \ + 0, 1, 0, /* char 179 */ \ + 0, 1, 0, /* char 180 */ \ + 0, 1, 0, /* char 181 */ \ + 0, 1, 0, /* char 182 */ \ + 0, 1, 0, /* char 183 */ \ + 0, 1, 0, /* char 184 */ \ + 0, 1, 0, /* char 185 */ \ + 0, 1, 0, /* char 186 */ \ + 0, 1, 0, /* char 187 */ \ + 0, 1, 0, /* char 188 */ \ + 0, 1, 0, /* char 189 */ \ + 0, 1, 0, /* char 190 */ \ + 0, 1, 0, /* char 191 */ \ + 0, 1, 0, /* char 192 */ \ + 0, 1, 0, /* char 193 */ \ + 0, 1, 0, /* char 194 */ \ + 0, 1, 0, /* char 195 */ \ + 0, 1, 0, /* char 196 */ \ + 0, 1, 0, /* char 197 */ \ + 0, 1, 0, /* char 198 */ \ + 0, 1, 0, /* char 199 */ \ + 0, 1, 0, /* char 200 */ \ + 0, 1, 0, /* char 201 */ \ + 0, 1, 0, /* char 202 */ \ + 0, 1, 0, /* char 203 */ \ + 0, 1, 0, /* char 204 */ \ + 0, 1, 0, /* char 205 */ \ + 0, 1, 0, /* char 206 */ \ + 0, 1, 0, /* char 207 */ \ + 0, 1, 0, /* char 208 */ \ + 0, 1, 0, /* char 209 */ \ + 0, 1, 0, /* char 210 */ \ + 0, 1, 0, /* char 211 */ \ + 0, 1, 0, /* char 212 */ \ + 0, 1, 0, /* char 213 */ \ + 0, 1, 0, /* char 214 */ \ + 0, 1, 0, /* char 215 */ \ + 0, 1, 0, /* char 216 */ \ + 0, 1, 0, /* char 217 */ \ + 0, 1, 0, /* char 218 */ \ + 0, 1, 0, /* char 219 */ \ + 0, 1, 0, /* char 220 */ \ + 0, 1, 0, /* char 221 */ \ + 0, 1, 0, /* char 222 */ \ + 0, 1, 0, /* char 223 */ \ + 0, 1, 0, /* char 224 */ \ + 0, 1, 0, /* char 225 */ \ + 0, 1, 0, /* char 226 */ \ + 0, 1, 0, /* char 227 */ \ + 0, 1, 0, /* char 228 */ \ + 0, 1, 0, /* char 229 */ \ + 0, 1, 0, /* char 230 */ \ + 0, 1, 0, /* char 231 */ \ + 0, 1, 0, /* char 232 */ \ + 0, 1, 0, /* char 233 */ \ + 0, 1, 0, /* char 234 */ \ + 0, 1, 0, /* char 235 */ \ + 0, 1, 0, /* char 236 */ \ + 0, 1, 0, /* char 237 */ \ + 0, 1, 0, /* char 238 */ \ + 0, 1, 0, /* char 239 */ \ + 0, 1, 0, /* char 240 */ \ + 0, 1, 0, /* char 241 */ \ + 0, 1, 0, /* char 242 */ \ + 0, 1, 0, /* char 243 */ \ + 0, 1, 0, /* char 244 */ \ + 0, 1, 0, /* char 245 */ \ + 0, 1, 0, /* char 246 */ \ + 0, 1, 0, /* char 247 */ \ + 0, 1, 0, /* char 248 */ \ + 0, 1, 0, /* char 249 */ \ + 0, 1, 0, /* char 250 */ \ + 0, 1, 0, /* char 251 */ \ + 0, 1, 0, /* char 252 */ \ + 0, 1, 0, /* char 253 */ \ + 0, 1, 0, /* char 254 */ \ + 0, 1, 0, /* char 255 */ \ + 226) diff --git a/interface/fonts/tiny_unicode.dm b/interface/fonts/tiny_unicode.dm new file mode 100644 index 000000000000..d6af265d5182 --- /dev/null +++ b/interface/fonts/tiny_unicode.dm @@ -0,0 +1,253 @@ +/// For clean results on map, use only sizing pt, multiples of 12: 12pt 24pt 48pt etc. - Not for use with px sizing +/// Can be used in TGUI etc, px sizing is pt / 0.75. 12pt = 16px, 24pt = 32px etc. + +/// Base font +/datum/font/tiny_unicode + name = "TinyUnicode" + font_family = 'interface/fonts/TinyUnicode.ttf' + +/// For icon overlays +/// TinyUnicode 12pt metrics generated using Lummox's dmifontsplus (https://www.byond.com/developer/LummoxJR/DmiFontsPlus) +/// Note: these variable names have been changed, so you can't straight copy/paste from dmifontsplus.exe +/datum/font/tiny_unicode/size_12pt + name = "TinyUnicode 12pt" + height = 13 + ascent = 11 + descent = 2 + average_width = 5 + max_width = 11 + overhang = 0 + in_leading = -3 + ex_leading = 1 + default_character = 31 + start = 30 + end = 255 + metrics = list( + 1, 5, 0, // char 30 + 1, 5, 0, // char 31 + 0, 1, 4, // char 32 + 0, 1, 1, // char 33 + 0, 3, 1, // char 34 + 0, 5, 1, // char 35 + 0, 4, 1, // char 36 + 0, 3, 1, // char 37 + 0, 5, 1, // char 38 + 0, 1, 1, // char 39 + 0, 2, 1, // char 40 + 0, 2, 1, // char 41 + 0, 3, 1, // char 42 + 0, 3, 1, // char 43 + 0, 2, 1, // char 44 + 0, 3, 1, // char 45 + 0, 1, 1, // char 46 + 0, 3, 1, // char 47 + 0, 4, 1, // char 48 + 0, 2, 1, // char 49 + 0, 4, 1, // char 50 + 0, 4, 1, // char 51 + 0, 4, 1, // char 52 + 0, 4, 1, // char 53 + 0, 4, 1, // char 54 + 0, 4, 1, // char 55 + 0, 4, 1, // char 56 + 0, 4, 1, // char 57 + 0, 1, 1, // char 58 + 0, 2, 1, // char 59 + 0, 2, 1, // char 60 + 0, 4, 1, // char 61 + 0, 2, 1, // char 62 + 0, 4, 1, // char 63 + 0, 7, 1, // char 64 + 0, 4, 1, // char 65 + 0, 4, 1, // char 66 + 0, 3, 1, // char 67 + 0, 4, 1, // char 68 + 0, 3, 1, // char 69 + 0, 3, 1, // char 70 + 0, 4, 1, // char 71 + 0, 4, 1, // char 72 + 0, 3, 1, // char 73 + 0, 4, 1, // char 74 + 0, 4, 1, // char 75 + 0, 3, 1, // char 76 + 0, 5, 1, // char 77 + 0, 4, 1, // char 78 + 0, 4, 1, // char 79 + 0, 4, 1, // char 80 + 0, 4, 1, // char 81 + 0, 4, 1, // char 82 + 0, 4, 1, // char 83 + 0, 3, 1, // char 84 + 0, 4, 1, // char 85 + 0, 4, 1, // char 86 + 0, 5, 1, // char 87 + 0, 4, 1, // char 88 + 0, 4, 1, // char 89 + 0, 3, 1, // char 90 + 0, 2, 1, // char 91 + 0, 3, 1, // char 92 + 0, 2, 1, // char 93 + 0, 3, 1, // char 94 + 0, 5, 1, // char 95 + 0, 2, 1, // char 96 + 0, 4, 1, // char 97 + 0, 4, 1, // char 98 + 0, 3, 1, // char 99 + 0, 4, 1, // char 100 + 0, 4, 1, // char 101 + 0, 3, 1, // char 102 + 0, 4, 1, // char 103 + 0, 4, 1, // char 104 + 0, 1, 1, // char 105 + 0, 2, 1, // char 106 + 0, 4, 1, // char 107 + 0, 1, 1, // char 108 + 0, 5, 1, // char 109 + 0, 4, 1, // char 110 + 0, 4, 1, // char 111 + 0, 4, 1, // char 112 + 0, 4, 1, // char 113 + 0, 3, 1, // char 114 + 0, 4, 1, // char 115 + 0, 3, 1, // char 116 + 0, 4, 1, // char 117 + 0, 4, 1, // char 118 + 0, 5, 1, // char 119 + 0, 3, 1, // char 120 + 0, 4, 1, // char 121 + 0, 4, 1, // char 122 + 0, 3, 1, // char 123 + 0, 1, 1, // char 124 + 0, 3, 1, // char 125 + 0, 5, 1, // char 126 + 1, 5, 0, // char 127 + 0, 4, 1, // char 128 + 1, 5, 0, // char 129 + 1, 5, 0, // char 130 + 1, 5, 0, // char 131 + 1, 5, 0, // char 132 + 1, 5, 0, // char 133 + 1, 5, 0, // char 134 + 1, 5, 0, // char 135 + 1, 5, 0, // char 136 + 0, 5, 1, // char 137 + 1, 5, 0, // char 138 + 1, 5, 0, // char 139 + 0, 6, 1, // char 140 + 1, 5, 0, // char 141 + 1, 5, 0, // char 142 + 1, 5, 0, // char 143 + 1, 5, 0, // char 144 + 1, 5, 0, // char 145 + 1, 5, 0, // char 146 + 1, 5, 0, // char 147 + 1, 5, 0, // char 148 + 0, 2, 1, // char 149 + 1, 5, 0, // char 150 + 1, 5, 0, // char 151 + 1, 5, 0, // char 152 + 0, 4, 1, // char 153 + 1, 5, 0, // char 154 + 1, 5, 0, // char 155 + 1, 5, 0, // char 156 + 1, 5, 0, // char 157 + 1, 5, 0, // char 158 + 0, 4, 1, // char 159 + 1, 5, 0, // char 160 + 0, 1, 1, // char 161 + 0, 4, 1, // char 162 + 0, 4, 1, // char 163 + 0, 5, 1, // char 164 + 0, 3, 1, // char 165 + 0, 1, 1, // char 166 + 0, 4, 1, // char 167 + 0, 3, 1, // char 168 + 0, 2, 1, // char 169 + 0, 8, 1, // char 170 + 0, 4, 1, // char 171 + 0, 4, 1, // char 172 + 1, 5, 0, // char 173 + 0, 2, 1, // char 174 + 0, 4, 1, // char 175 + 0, 3, 1, // char 176 + 0, 3, 1, // char 177 + 0, 2, 1, // char 178 + 0, 2, 1, // char 179 + 0, 2, 1, // char 180 + 0, 4, 1, // char 181 + 0, 5, 1, // char 182 + 1, 1, 1, // char 183 + 0, 8, 1, // char 184 + 0, 2, 1, // char 185 + 0, 2, 1, // char 186 + 0, 4, 1, // char 187 + 0, 7, 1, // char 188 + 0, 8, 1, // char 189 + 0, 8, 1, // char 190 + 0, 4, 1, // char 191 + 0, 4, 1, // char 192 + 0, 4, 1, // char 193 + 0, 4, 1, // char 194 + 0, 4, 1, // char 195 + 0, 4, 1, // char 196 + 0, 4, 1, // char 197 + 0, 6, 1, // char 198 + 0, 3, 1, // char 199 + 0, 3, 1, // char 200 + 0, 3, 1, // char 201 + 0, 3, 1, // char 202 + 0, 3, 1, // char 203 + 0, 3, 1, // char 204 + 0, 3, 1, // char 205 + 0, 3, 1, // char 206 + 0, 3, 1, // char 207 + 0, 10, 1, // char 208 + 0, 4, 1, // char 209 + 0, 4, 1, // char 210 + 0, 4, 1, // char 211 + 0, 4, 1, // char 212 + 0, 4, 1, // char 213 + 0, 4, 1, // char 214 + 0, 3, 1, // char 215 + 0, 5, 1, // char 216 + 0, 4, 1, // char 217 + 0, 4, 1, // char 218 + 0, 4, 1, // char 219 + 0, 4, 1, // char 220 + 0, 4, 1, // char 221 + 0, 3, 1, // char 222 + 0, 3, 1, // char 223 + 0, 4, 1, // char 224 + 0, 4, 1, // char 225 + 0, 4, 1, // char 226 + 0, 4, 1, // char 227 + 0, 4, 1, // char 228 + 0, 4, 1, // char 229 + 0, 7, 1, // char 230 + 0, 3, 1, // char 231 + 0, 4, 1, // char 232 + 0, 4, 1, // char 233 + 0, 4, 1, // char 234 + 0, 4, 1, // char 235 + 0, 2, 1, // char 236 + 0, 2, 1, // char 237 + 0, 3, 1, // char 238 + 0, 3, 1, // char 239 + 0, 5, 1, // char 240 + 0, 4, 1, // char 241 + 0, 4, 1, // char 242 + 0, 4, 1, // char 243 + 0, 4, 1, // char 244 + 0, 4, 1, // char 245 + 0, 4, 1, // char 246 + 0, 5, 1, // char 247 + 0, 4, 1, // char 248 + 0, 4, 1, // char 249 + 0, 4, 1, // char 250 + 0, 4, 1, // char 251 + 0, 4, 1, // char 252 + 0, 4, 1, // char 253 + 0, 10, 1, // char 254 + 0, 4, 1, // char 255 + 226 + ) diff --git a/interface/fonts/vcr_osd_mono.dm b/interface/fonts/vcr_osd_mono.dm new file mode 100644 index 000000000000..301d90d2f7ea --- /dev/null +++ b/interface/fonts/vcr_osd_mono.dm @@ -0,0 +1,3 @@ +/datum/font/vcr_osd_mono + name = "VCR OSD Mono" + font_family = 'interface/fonts/VCR_OSD_Mono.ttf' diff --git a/interface/skin.dmf b/interface/skin.dmf index c0f81921d15a..8e9af7916d9e 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -57,12 +57,12 @@ window "mapwindow" size = 640x480 anchor1 = 0,0 anchor2 = 100,100 - font-family = "Arial" - font-size = 7 + font-family = "Grand9K Pixel" + font-size = 6pt is-default = true saved-params = "" on-size = ".on_viewport [[width]] [[height]] [[zoom]] [[letterbox]]" - style = ".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .greentext { color: #00FF00; font-size: 7px; } .redtext { color: #FF0000; font-size: 7px; } .clown { color: #FF69Bf; font-size: 7px; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-size: 6px; }" + style = ".center { text-align: center; } .maptext { font-family: 'Grand9K Pixel'; font-size: 6pt; -dm-text-outline: 1px black; color: white; line-height: 1.0; } .command_headset { font-weight: bold; } .context { font-family: 'Pixellari'; font-size: 12pt; -dm-text-outline: 1px black; } .subcontext { font-family: 'TinyUnicode'; font-size: 12pt; line-height: 0.75; } .small { font-family: 'Spess Font'; font-size: 6pt; line-height: 1.4; } .big { font-family: 'Pixellari'; font-size: 12pt; } .reallybig { font-size: 12pt; } .extremelybig { font-size: 12pt; } .greentext { color: #00FF00; font-size: 6pt; } .redtext { color: #FF0000; font-size: 6pt; } .clown { color: #FF69BF; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-family: 'Spess Font'; font-size: 6pt; line-height: 1.4; }" elem "cutscenebrowser" type = BROWSER pos = 0,0 diff --git a/maps/endeavour/levels/deck3.dmm b/maps/endeavour/levels/deck3.dmm index 647c0eb28ed3..0dcf03bd2452 100644 --- a/maps/endeavour/levels/deck3.dmm +++ b/maps/endeavour/levels/deck3.dmm @@ -19127,7 +19127,6 @@ dir = 1 }, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /turf/simulated/floor/tiled/dark, @@ -21662,7 +21661,6 @@ dir = 1 }, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /turf/simulated/floor/tiled/dark, @@ -24794,7 +24792,6 @@ /area/quartermaster/qm) "qLx" = ( /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /obj/structure/table/wooden_reinforced, @@ -25267,7 +25264,6 @@ /area/quartermaster/qm) "rdv" = ( /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /obj/effect/floor_decal/borderfloorblack{ @@ -30596,7 +30592,6 @@ }, /obj/structure/bed/chair/sofa/black/left, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /turf/simulated/floor/tiled/dark, @@ -33238,7 +33233,6 @@ dir = 1 }, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /turf/simulated/floor/tiled/monodark, @@ -34616,7 +34610,6 @@ dir = 10 }, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 0; pixel_x = -32 }, diff --git a/maps/triumph/levels/deck2.dmm b/maps/triumph/levels/deck2.dmm index 26a4e23c8a4a..f9557bd194d0 100644 --- a/maps/triumph/levels/deck2.dmm +++ b/maps/triumph/levels/deck2.dmm @@ -1589,7 +1589,6 @@ id = "QMLoad2" }, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /obj/machinery/light{ @@ -2892,7 +2891,6 @@ /area/crew_quarters/bar) "iJ" = ( /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = -32 }, /obj/effect/floor_decal/industrial/outline/red, @@ -10992,7 +10990,6 @@ /area/crew_quarters/recreation_area) "Hh" = ( /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = 32 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -12117,7 +12114,6 @@ /obj/structure/ore_box, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/status_display/supply_display{ - mode = 99; pixel_y = -32 }, /turf/simulated/floor/tiled,