Port Runechat

This commit is contained in:
Aronai Sieyes
2021-05-29 01:38:36 -04:00
parent e0183093ca
commit ea42ee2303
17 changed files with 414 additions and 31 deletions
+2
View File
@@ -93,6 +93,8 @@ What is the naming convention for planes or layers?
#define BELOW_MOB_LAYER 3.9 // Should be converted to plane swaps
#define ABOVE_MOB_LAYER 4.1 // Should be converted to plane swaps
#define ABOVE_MOB_PLANE -24
// Invisible things plane
#define CLOAKED_PLANE -15
+2
View File
@@ -20,6 +20,8 @@
#define TICKS2DS(T) ((T) TICKS) // Convert ticks to deciseconds
#define DS2NEARESTTICK(DS) TICKS2DS(-round(-(DS2TICKS(DS))))
var/world_startup_time
/proc/get_game_time()
var/global/time_offset = 0
var/global/last_time = 0
+16
View File
@@ -1691,3 +1691,19 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
return "CLIENT: [D]"
else
return "Unknown data type: [D]"
/*
is_holder_of(): Returns 1 if A is a holder of B, meaning, A is B.loc or B.loc.loc or B.loc.loc.loc etc.
This is essentially the same as calling (locate(B) in A), but a little clearer as to what you're doing, and locate() has been known to bug out or be extremely slow in the past.
*/
/proc/is_holder_of(const/atom/movable/A, const/atom/movable/B)
if(istype(A, /turf) || istype(B, /turf)) //Clicking on turfs is a common thing and turfs are also not /atom/movable, so it was causing the assertion to fail.
return 0
ASSERT(istype(A) && istype(B))
var/atom/O = B
while(O && !isturf(O))
if(O == A)
return 1
O = O.loc
return 0
+293
View File
@@ -0,0 +1,293 @@
#define CHAT_MESSAGE_SPAWN_TIME 0.2 SECONDS
#define CHAT_MESSAGE_LIFESPAN 5 SECONDS
#define CHAT_MESSAGE_EOL_FADE 0.7 SECONDS
#define CHAT_MESSAGE_EXP_DECAY 0.8 // Messages decay at pow(factor, idx in stack)
#define CHAT_MESSAGE_HEIGHT_DECAY 0.7 // Increase message decay based on the height of the message
#define CHAT_MESSAGE_APPROX_LHEIGHT 11 // Approximate height in pixels of an 'average' line, used for height decay
#define CHAT_MESSAGE_WIDTH 96 // pixels
#define CHAT_MESSAGE_NORM_LENGTH 68 // characters
#define CHAT_MESSAGE_EXT_LENGTH 150 // characters
#define CHAT_MESSAGE_MOB 1
#define CHAT_MESSAGE_OBJ 2
#define WXH_TO_HEIGHT(x) text2num(copytext((x), findtextEx((x), "x") + 1)) // thanks lummox
/**
* # Chat Message Overlay
*
* Datum for generating a message overlay on the map
* Ported from TGStation; https://github.com/tgstation/tgstation/pull/50608/, author: bobbahbrown
*/
// Cached runechat icon
var/runechat_icon = null
/datum/chatmessage
/// The visual element of the chat messsage
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
var/scheduled_destruction
/// Contains the approximate amount of lines for height decay
var/approx_lines
/**
* 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 = null, lifespan = CHAT_MESSAGE_LIFESPAN)
. = ..()
if (!istype(target))
CRASH("Invalid target given for chatmessage")
if(!istype(owner) || QDELETED(owner) || !owner.client)
stack_trace("/datum/chatmessage created with [isnull(owner) ? "null" : "invalid"] mob owner")
qdel(src)
return
generate_image(text, target, owner, extra_classes, lifespan)
/datum/chatmessage/Destroy()
if (owned_by)
owned_by.seen_messages.Remove(src)
owned_by.images.Remove(message)
UnregisterSignal(owned_by, COMSIG_PARENT_QDELETING)
owned_by = null
message_loc = null
message = null
return ..()
/**
* 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)
set waitfor = FALSE
// Register client who owns this message
owned_by = owner.client
RegisterSignal(owned_by, COMSIG_PARENT_QDELETING, .proc/qdel_self)
// Clip message
var/maxlen = owned_by.is_preference_enabled(/datum/client_preference/runechat_long_messages) ? CHAT_MESSAGE_EXT_LENGTH : CHAT_MESSAGE_NORM_LENGTH
if (length_char(text) > maxlen)
text = copytext_char(text, 1, maxlen + 1) + "..." // BYOND index moment
// Calculate target color if not already present
if (!target.chat_color || target.chat_color_name != target.name)
target.chat_color = colorize_string(target.name)
target.chat_color_darkened = colorize_string(target.name, 0.85, 0.85)
target.chat_color_name = target.name
// 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"
// If we heard our name, it's important
var/list/names = splittext(owner.name, " ")
for (var/word in names)
text = replacetext(text, word, "<b>[word]</b>")
// Append radio icon if comes from a radio
if (extra_classes.Find("spoken_into_radio"))
if (!runechat_icon)
var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio")
runechat_icon = "\icon[r_icon]&nbsp;"
text = runechat_icon + text
// We dim italicized text to make it more distinguishable from regular text
var/tgt_color = extra_classes.Find("italics") ? target.chat_color_darkened : target.chat_color
// Approximate text height
// Note we have to replace HTML encoded metacharacters otherwise MeasureText will return a zero height
// BYOND Bug #2563917
// Construct text
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
var/complete_text = "<span class='center maptext [extra_classes != null ? extra_classes.Join(" ") : ""]' style='color: [tgt_color];'>[text]</span>"
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
// Translate any existing messages upwards, apply exponential decay factors to timers
message_loc = target
if (owned_by.seen_messages)
var/idx = 1
var/combined_height = approx_lines
for(var/msg in owned_by.seen_messages)
var/datum/chatmessage/m = msg
animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME)
combined_height += m.approx_lines
var/sched_remaining = m.scheduled_destruction - world.time
if (sched_remaining > CHAT_MESSAGE_SPAWN_TIME)
var/remaining_time = (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height)
m.scheduled_destruction = world.time + remaining_time
spawn(remaining_time)
m.end_of_life()
// Build message image
message = image(loc = message_loc, layer = ABOVE_MOB_LAYER)
message.plane = PLANE_LIGHTING_ABOVE
message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
message.alpha = 0
message.pixel_y = owner.bound_height * 0.95
message.maptext_width = CHAT_MESSAGE_WIDTH
message.maptext_height = mheight
message.maptext_x = (CHAT_MESSAGE_WIDTH - owner.bound_width) * -0.5
message.maptext = complete_text
if (is_holder_of(owner, target)) // Special case, holding an atom speaking (pAI, recorder...)
message.plane = PLANE_PLAYER_HUD_ABOVE
// View the message
owned_by.seen_messages.Add(src)
owned_by.images += message
animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME)
// Prepare for destruction
scheduled_destruction = world.time + (lifespan - CHAT_MESSAGE_EOL_FADE)
spawn(lifespan - CHAT_MESSAGE_EOL_FADE)
end_of_life()
/**
* Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion
*/
/datum/chatmessage/proc/end_of_life(fadetime = CHAT_MESSAGE_EOL_FADE)
if (gc_destroyed)
return
animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL)
spawn(fadetime)
qdel(src)
/**
* Creates a message overlay at a defined location for a given speaker
*
* Arguments:
* * speaker - The atom who is saying this message
* * message - The text content of the message
* * italics - Decides if this should be small or not, as generally italics text are for whisper/radio overhear
* * existing_extra_classes - Additional classes to add to the message
*/
/mob/proc/create_chat_message(atom/movable/speaker, message, italics, list/existing_extra_classes, audible = TRUE)
if(!client)
return
// Doesn't want to hear
if(ismob(speaker) && !client.is_preference_enabled(/datum/client_preference/runechat_mob))
return
else if(isobj(speaker) && !client.is_preference_enabled(/datum/client_preference/runechat_obj))
return
// Incapable of receiving
if((audible && is_deaf()) || (!audible && is_blind()))
return
// Check for virtual speakers (aka hearing a message through a radio)
if (existing_extra_classes.Find("radio"))
return
/* Not currently necessary
message = strip_html_properly(message)
if(!message)
return
*/
var/list/extra_classes = list()
extra_classes += existing_extra_classes
if (italics)
extra_classes |= "italics"
if (client.is_preference_enabled(/datum/client_preference/runechat_border))
extra_classes |= "black_outline"
var/dist = get_dist(src, speaker)
switch (dist)
if (4 to 5)
extra_classes |= "small"
if (5 to 16)
extra_classes |= "very_small"
// Display visual above source
new /datum/chatmessage(message, speaker, src, extra_classes)
// Tweak these defines to change the available color ranges
#define CM_COLOR_SAT_MIN 0.6
#define CM_COLOR_SAT_MAX 0.95
#define CM_COLOR_LUM_MIN 0.70
#define CM_COLOR_LUM_MAX 0.90
/**
* 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
*/
/datum/chatmessage/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 + "[world_startup_time]"), 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(sat_shift, 0, 1)
l *= clamp(lum_shift, 0, 1)
// convert to rgba
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 rgb(c,x,m)
if(1)
return rgb(x,c,m)
if(2)
return rgb(m,c,x)
if(3)
return rgb(m,x,c)
if(4)
return rgb(x,m,c)
if(5)
return rgb(c,m,x)
/atom/proc/runechat_message(message, range = world.view, italics, list/classes = list(), audible = TRUE)
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src), range, remote_ghosts = FALSE)
var/list/hearing_mobs = hear["mobs"]
for(var/mob in hearing_mobs)
var/mob/M = mob
if(!M.client)
continue
M.create_chat_message(src, message, italics, classes, audible)
+15 -2
View File
@@ -34,6 +34,15 @@
// Track if we are already had initialize() called to prevent double-initialization.
var/initialized = FALSE
/// 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
/// The chat color var, without alpha.
var/chat_color_hover
/atom/New(loc, ...)
// Don't call ..() unless /datum/New() ever exists
@@ -490,7 +499,7 @@
// 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!"
/atom/proc/visible_message(var/message, var/blind_message, var/list/exclude_mobs, var/range = world.view)
/atom/proc/visible_message(var/message, var/blind_message, var/list/exclude_mobs, var/range = world.view, var/runemessage = "<span style='font-size: 1.5em'>👁</span>")
//VOREStation Edit
var/list/see
@@ -513,6 +522,8 @@
var/mob/M = mob
if(M.see_invisible >= invisibility && MOB_CAN_SEE_PLANE(M, plane))
M.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE)
if(runemessage != -1)
M.create_chat_message(src, "* [runemessage || message] *", FALSE, list("emote"), audible = FALSE)
else if(blind_message)
M.show_message(blind_message, AUDIBLE_MESSAGE)
@@ -521,7 +532,7 @@
// 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, var/radio_message)
/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance, var/radio_message, var/runemessage)
var/range = hearing_distance || world.view
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
@@ -542,6 +553,8 @@
var/mob/M = mob
var/msg = message
M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
if(runemessage != -1)
M.create_chat_message(src, "* [runemessage || message] *", FALSE, list("emote"))
/atom/movable/proc/dropInto(var/atom/destination)
while(istype(destination))
+1
View File
@@ -1,5 +1,6 @@
#define RECOMMENDED_VERSION 501
/world/New()
world_startup_time = world.timeofday
to_world_log("Map Loading Complete")
//logs
//VOREStation Edit Start
+1 -2
View File
@@ -324,8 +324,7 @@
var/message = sanitize(input("What do you want the message to be?", "Make Sound") as text|null)
if(!message)
return
for (var/mob/V in hearers(O))
V.show_message(message, 2)
O.audible_message(message)
log_admin("[key_name(usr)] made [O] at [O.x], [O.y], [O.z]. make a sound")
message_admins("<font color='blue'>[key_name_admin(usr)] made [O] at [O.x], [O.y], [O.z]. make a sound.</font>", 1)
feedback_add_details("admin_verb","MS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+3
View File
@@ -76,3 +76,6 @@
var/connection_realtime
///world.timeofday they connected
var/connection_timeofday
// Runechat messages
var/list/seen_messages = list()
@@ -290,6 +290,32 @@ var/list/_client_preferences_by_type
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/runechat_mob
description = "Runechat (Mobs)"
key = "RUNECHAT_MOB"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/runechat_obj
description = "Runechat (Objs)"
key = "RUNECHAT_OBJ"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/runechat_border
description = "Runechat Message Border"
key = "RUNECHAT_BORDER"
enabled_description = "Show"
disabled_description = "Hide"
enabled_by_default = FALSE
/datum/client_preference/runechat_long_messages
description = "Runechat Message Length"
key = "RUNECHAT_LONG"
enabled_description = "ERP KING"
disabled_description = "Normie"
enabled_by_default = FALSE
/datum/client_preference/status_indicators/toggled(mob/preference_mob, enabled)
. = ..()
if(preference_mob && preference_mob.plane_holder)
+10 -7
View File
@@ -103,11 +103,14 @@ var/global/list/emotes_by_key
if(target)
use_1p = replace_target_tokens(use_1p, target)
use_1p = "<span class='emote'>[capitalize(replace_user_tokens(use_1p, user))]</span>"
var/use_3p = get_emote_message_3p(user, target, extra_params)
if(use_3p)
var/prefinal_3p
var/use_3p
var/raw_3p = get_emote_message_3p(user, target, extra_params)
if(raw_3p)
if(target)
use_3p = replace_target_tokens(use_3p, target)
use_3p = "<span class='emote'><b>\The [user]</b> [replace_user_tokens(use_3p, user)]</span>"
raw_3p = replace_target_tokens(raw_3p, target)
prefinal_3p = replace_user_tokens(raw_3p, user)
use_3p = "<span class='emote'><b>\The [user]</b> [prefinal_3p]</span>"
var/use_radio = get_radio_message(user)
if(use_radio)
if(target)
@@ -124,12 +127,12 @@ var/global/list/emotes_by_key
if(isliving(user))
var/mob/living/L = user
if(L.silent)
M.visible_message(message = "[user] opens their mouth silently!", self_message = "You cannot say anything!", blind_message = emote_message_impaired)
M.visible_message(message = "[user] opens their mouth silently!", self_message = "You cannot say anything!", blind_message = emote_message_impaired, runemessage = "opens their mouth silently!")
return
else
M.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, hearing_distance = use_range, radio_message = use_radio)
M.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, hearing_distance = use_range, radio_message = use_radio, runemessage = prefinal_3p)
else
M.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, range = use_range)
M.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, range = use_range, runemessage = prefinal_3p)
do_extra(user, target)
do_sound(user)
+7 -1
View File
@@ -86,7 +86,8 @@
return
if(use_emote.message_type == AUDIBLE_MESSAGE && is_muzzled())
audible_message("<b>\The [src]</b> [use_emote.emote_message_muffled || "makes a muffled sound."]")
var/muffle_message = use_emote.emote_message_muffled || "makes a muffled sound."
audible_message("<b>\The [src]</b> [muffle_message]", runemessage = "* [muffle_message] *")
return
next_emote = world.time + use_emote.emote_delay
@@ -164,9 +165,13 @@
input = message
var/list/formatted
var/runemessage
if(input)
formatted = format_emote(src, message)
message = formatted["pretext"] + formatted["nametext"] + formatted["subtext"]
runemessage = formatted["subtext"]
// This is just personal preference (but I'm objectively right) that custom emotes shouldn't have periods at the end in runechat
runemessage = replacetext(runemessage,".","",length(runemessage),length(runemessage)+1)
else
return
@@ -194,6 +199,7 @@
if(isobserver(M))
message = "<span class='emote'><B>[src]</B> ([ghost_follow_link(src, M)]) [input]</span>"
M.show_message(message, m_type)
M.create_chat_message(src, "* [runemessage] *", FALSE, list("emote"), (m_type == AUDIBLE_MESSAGE))
for(var/obj in o_viewers)
var/obj/O = obj
+1
View File
@@ -116,6 +116,7 @@
message_to_send = "<font size='3'><b>[message_to_send]</b></font>"
on_hear_say(message_to_send)
create_chat_message(speaker, combined["raw"], italics, list())
if(speech_sound && (get_dist(speaker, src) <= world.view && z == speaker.z))
var/turf/source = speaker ? get_turf(speaker) : get_turf(src)
+15 -14
View File
@@ -40,18 +40,18 @@ var/list/department_radio_keys = list(
//kinda localization -- rastaf0
//same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding.
":ê" = "right ear", ".ê" = "right ear",
":ä" = "left ear", ".ä" = "left ear",
":ø" = "intercom", ".ø" = "intercom",
":ð" = "department", ".ð" = "department",
":ñ" = "Command", ".ñ" = "Command",
":ò" = "Science", ".ò" = "Science",
":ü" = "Medical", ".ü" = "Medical",
":ó" = "Engineering", ".ó" = "Engineering",
":û" = "Security", ".û" = "Security",
":ö" = "whisper", ".ö" = "whisper",
":å" = "Mercenary", ".å" = "Mercenary",
":é" = "Supply", ".é" = "Supply",
":" = "right ear", "." = "right ear",
":" = "left ear", "." = "left ear",
":" = "intercom", "." = "intercom",
":" = "department", "." = "department",
":" = "Command", "." = "Command",
":" = "Science", "." = "Science",
":" = "Medical", "." = "Medical",
":" = "Engineering", "." = "Engineering",
":" = "Security", "." = "Security",
":" = "whisper", "." = "whisper",
":" = "Mercenary", "." = "Mercenary",
":" = "Supply", "." = "Supply",
)
@@ -362,16 +362,17 @@ proc/get_radio_key_from_channel(var/channel)
//VOREStation Add End
var/dst = get_dist(get_turf(M),get_turf(src))
var/runechat_enabled = M.client?.is_preference_enabled(/datum/client_preference/runechat_mob)
if(dst <= message_range || (M.stat == DEAD && !forbid_seeing_deadchat)) //Inside normal message range, or dead with ears (handled in the view proc)
if(M.client)
if(M.client && !runechat_enabled)
var/image/I1 = listening[M] || speech_bubble
images_to_clients[I1] |= M.client
M << I1
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol)
if(whispering && !isobserver(M)) //Don't even bother with these unless whispering
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
if(M.client)
if(M.client && !runechat_enabled)
var/image/I2 = listening[M] || speech_bubble
images_to_clients[I2] |= M.client
M << I2
+10 -3
View File
@@ -77,7 +77,7 @@
// message is the message output to anyone who can see e.g. "[src] does something!"
// 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!"
/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null, var/range = world.view)
/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null, var/range = world.view, var/runemessage)
if(self_message)
if(LAZYLEN(exclude_mobs))
exclude_mobs |= src
@@ -87,7 +87,9 @@
// Transfer messages about what we are doing to upstairs
if(shadow)
shadow.visible_message(message, self_message, blind_message, exclude_mobs, range)
. = ..(message, blind_message, exclude_mobs, range) // Really not ideal that atom/visible_message has different arg numbering :(
if(isnull(runemessage))
runemessage = -1
. = ..(message, blind_message, exclude_mobs, range, runemessage) // Really not ideal that atom/visible_message has different arg numbering :(
// Returns an amount of power drawn from the object (-1 if it's not viable).
// If drain_check is set it will not actually drain power, just return a value.
@@ -102,7 +104,7 @@
// self_message (optional) is what the src mob hears.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message, var/radio_message)
/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message, var/radio_message, var/runemessage)
var/range = hearing_distance || world.view
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
@@ -110,6 +112,9 @@
var/list/hearing_mobs = hear["mobs"]
var/list/hearing_objs = hear["objs"]
if(isnull(runemessage))
runemessage = -1 // Symmetry with mob/audible_message, despite the fact this one doesn't call parent. Maybe it should!
if(radio_message)
for(var/obj in hearing_objs)
var/obj/O = obj
@@ -125,6 +130,8 @@
if(self_message && M==src)
msg = self_message
M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
if(runemessage != -1)
M.create_chat_message(src, "* [runemessage || message] *", FALSE, list("emote"), audible = FALSE)
/mob/proc/findname(msg)
for(var/mob/M in mob_list)
@@ -42,7 +42,16 @@
user.client.eye = target_move //if we don't do this, Byond only updates the eye every tick - required for smooth movement
if(world.time > user.next_play_vent)
user.next_play_vent = world.time+30
playsound(src, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
var/turf/T = get_turf(src)
playsound(T, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
var/message = pick(
prob(90);"* clunk *",
prob(90);"* thud *",
prob(90);"* clatter *",
prob(1);"* <span style='font-size:2em'>ඞ</span> *"
)
T.runechat_message(message)
else
if((direction & initialize_directions) || is_type_in_list(src, ventcrawl_machinery) && src.can_crawl_through()) //if we move in a way the pipe can connect, but doesn't - or we're in a vent
user.remove_ventcrawl()
+1 -1
View File
@@ -1282,7 +1282,7 @@ window "mapwindow"
saved-params = "icon-size"
on-show = ".winset\"mainwindow.mainvsplit.left=mapwindow\""
on-hide = ".winset\"mainwindow.mainvsplit.left=\""
style=".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .clown { color: #FF69Bf;} .tajaran {color: #803B56;} .skrell {color: #00CED1;} .solcom {color: #22228B;} .com_srus {color: #7c4848;} .zombie {color: #ff0000;} .soghun {color: #228B22;} .vox {color: #AA00AA;} .diona {color: #804000; font-weight: bold;} .trinary {color: #727272;} .kidan {color: #664205;} .slime {color: #0077AA;} .drask {color: #a3d4eb;} .vulpkanin {color: #B97A57;} .abductor {color: #800080; font-style: italic;} .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; }"
style=".center { text-align: center; } .runechatdiv {background-color: #20202070} .black_outline { -dm-text-outline: 1px black } .boldtext { font-weight: bold; } .maptext { font-family: 'Small Fonts'; font-size: 7px; color: white; line-height: 1.1; } .command_headset { font-weight: bold; font-size: 8px; } .small { font-size: 6px; } .very_small { font-size: 5px;} .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: 7px; font-style: italic; }"
window "outputwindow"
elem "outputwindow"
+1
View File
@@ -308,6 +308,7 @@
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
#include "code\datums\category.dm"
#include "code\datums\chat_message.dm"
#include "code\datums\computerfiles.dm"
#include "code\datums\datacore.dm"
#include "code\datums\datum.dm"