Runescape-y chat on the game world (#26652)

* Runechat WIP

* Runtimes + whispers + speech

* Off by default

* Fixes

* Toggle outlines on the fly

* Actually fix travis + toggle on

* Background colour

* Small fix. Don't merge yet, it runtimes

* Fix runtimes and togglecreep

* ...

* Wrong proc

* rgb

* Fixes
This commit is contained in:
jknpj
2020-06-16 13:35:46 -03:00
committed by GitHub
17 changed files with 399 additions and 13 deletions

View File

@@ -34,3 +34,9 @@
#define SECURITY_POSITIONS list("Head of Security", "Warden", "Detective", "Security Officer")
#define ALWAYSTRUE 2
#define APPEARANCE_UI_IGNORE_ALPHA (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE)
#define SPEECH_MODE_SAY 1
#define SPEECH_MODE_WHISPER 2
#define SPEECH_MODE_FINAL 3

View File

@@ -195,6 +195,7 @@ What is the naming convention for planes or layers?
#define ABOVE_SINGULO_LAYER 7
#define GRAVITYGRID_LAYER 8
#define SNOW_OVERLAY_LAYER 9
#define CHAT_LAYER 12.1
#define GHOST_PLANE 19 // Ghosts show up under lighting, HUD etc.

258
code/datums/chat_message.dm Normal file
View File

@@ -0,0 +1,258 @@
#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.7 // Messages decay at pow(factor, idx in stack)
#define CHAT_MESSAGE_HEIGHT_DECAY 0.6 // 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_MAX_LENGTH 68 // characters
#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
*/
/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) || owner.gcDestroyed || !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)
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)
// Register client who owns this message
owned_by = owner.client
owner.on_destroyed.Add(src, .proc/qdel_self)
// Clip message
var/maxlen = owned_by.prefs.max_chat_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"
// Append radio icon if comes from a radio
if (extra_classes.Find("spoken_into_radio"))
var/image/r_icon = image('icons/chat_icons.dmi', icon_state = "radio")
text = "\icon[r_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 = "<div class='runechatdiv'><span class='center maptext [extra_classes != null ? extra_classes.Join(" ") : ""]' style='color: [tgt_color];'>[text]</span></div>"
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 = CHAT_LAYER)
message.plane = MOB_PLANE
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
// 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()
/datum/chatmessage/proc/qdel_self()
qdel(src)
/**
* 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 (gcDestroyed)
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_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
* * message_mode - Bitflags relating to the mode of the message
*/
/mob/proc/create_chat_message(atom/movable/speaker, datum/language/message_language, raw_message, mode, list/existing_extra_classes)
// Check for virtual speakers (aka hearing a message through a radio)
if (existing_extra_classes.Find("radio"))
return
var/list/extra_classes = list()
extra_classes += existing_extra_classes
if (mode == SPEECH_MODE_WHISPER)
extra_classes |= "small"
if (client.toggle_runechat_outlines)
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"
if (!say_understands(speaker, message_language))
raw_message = message_language.scramble(raw_message)
// Display visual above source
new /datum/chatmessage(raw_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.7
#define CM_COLOR_LUM_MIN 0.65
#define CM_COLOR_LUM_MAX 0.75
/**
* 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)]C8"
if(1)
return "[rgb(x,c,m)]C8"
if(2)
return "[rgb(m,c,x)]C8"
if(3)
return "[rgb(m,x,c)]C8"
if(4)
return "[rgb(x,m,c)]C8"
if(5)
return "[rgb(c,m,x)]C8"
/client/verb/toggle_runechat_outline()
set category = "OOC"
set name = "Toggle Runechat Outlines"
toggle_runechat_outlines = !toggle_runechat_outlines
to_chat(mob, "<span class='notice'>Runechat outlines are now [toggle_runechat_outlines ? "enabled" : "disabled"].</span>")

View File

@@ -1,7 +1,3 @@
#define SPEECH_MODE_SAY 1
#define SPEECH_MODE_WHISPER 2
#define SPEECH_MODE_FINAL 3
/datum/speech
var/name = "" // Displayed name
var/as_name = "" // (as [as_name])
@@ -168,5 +164,7 @@
if(data)
wrapper_classes=data.Copy()
wrapper_classes.Add("radio")
/datum/speech/proc/set_language(var/lang_id)
language = all_languages[lang_id]

View File

@@ -48,6 +48,14 @@ var/global/list/ghdel_profiling = list()
appearance_flags = TILE_BOUND|LONG_GLIDE
var/slowdown_modifier //modified on how fast a person can move over the tile we are on, see turf.dm for more info
/// 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/proc/beam_connect(var/obj/effect/beam/B)
if(!last_beamchecks)

View File

@@ -91,6 +91,9 @@
var/received_credits = FALSE
var/received_roundend_audio = FALSE
// Runechat messages
var/list/seen_messages = list()
var/toggle_runechat_outlines = TRUE
var/list/person_animation_viewers = list()
var/list/item_animation_viewers = list()

View File

@@ -215,6 +215,12 @@ var/const/MAX_SAVE_SLOTS = 16
var/credits = CREDITS_ALWAYS
var/jingle = JINGLE_CLASSIC
// Runscape-like chat
var/mob_chat_on_map = FALSE
var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH
var/obj_chat_on_map = FALSE
var/no_goonchat_for_obj = FALSE
var/client/client
var/saveloaded = 0
@@ -417,6 +423,15 @@ var/const/MAX_SAVE_SLOTS = 16
<a href='?_src_=prefs;preference=credits_volume'><b>[credits_volume]</b></a><br>
<b>Window Flashing</b>
<a href='?_src_=prefs;preference=window_flashing'><b>[(window_flashing) ? "Yes":"No"]</b></a><br>
<center>Runechat prefererences</center>
<b>Chat on map for mobs:</b>
<a href='?_src_=prefs;preference=mob_chat_on_map'>[mob_chat_on_map ? "Enabled" : "Disabled"]</a><br>
<b>Chat on map for objects:</b>
<a href='?_src_=prefs;preference=obj_chat_on_map'>[obj_chat_on_map ? "Enabled" : "Disabled"]</a><br>
<b>No goonchat messages for objects:</b>
<a href='?_src_=prefs;preference=no_goonchat_for_obj'>[no_goonchat_for_obj ? "Enabled" : "Disabled"]</a><br>
<b>Runechat message char limit:</b>
<a href='?_src_=prefs;preference=max_chat_length;task=input'>[max_chat_length]</a><br>
</div>
</div>"}
@@ -1517,6 +1532,19 @@ NOTE: The change will take effect AFTER any current recruiting periods."}
if("typing_indicator")
typing_indicator = !typing_indicator
if ("mob_chat_on_map")
mob_chat_on_map = !mob_chat_on_map
if ("obj_chat_on_map")
obj_chat_on_map = !obj_chat_on_map
if ("max_chat_length")
max_chat_length = input(user, "Choose the max character length of shown Runechat messages. Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", "Character Preference", max_chat_length) as null|num
if ("no_goonchat_for_obj")
no_goonchat_for_obj = !no_goonchat_for_obj
if(user.client.holder)
switch(href_list["preference"])
if("hear_ahelp")

View File

@@ -137,6 +137,10 @@
window_flashing = sanitize_integer(window_flashing, 0, 1, initial(window_flashing))
antag_objectives = sanitize_integer(antag_objectives, 0, 1, initial(antag_objectives))
typing_indicator = sanitize_integer(typing_indicator, 0, 1, initial(typing_indicator))
mob_chat_on_map = sanitize_integer(mob_chat_on_map, 0, 1, initial(mob_chat_on_map))
max_chat_length = sanitize_integer(max_chat_length, 0, CHAT_MESSAGE_MAX_LENGTH, initial(typing_indicator))
obj_chat_on_map = sanitize_integer(obj_chat_on_map, 0, 1, initial(obj_chat_on_map))
no_goonchat_for_obj = sanitize_integer(no_goonchat_for_obj, 0, 1, initial(no_goonchat_for_obj))
initialize_preferences()
return 1
@@ -218,15 +222,15 @@
check.Add("SELECT ckey FROM client WHERE ckey = ?", ckey)
if(check.Execute(db))
if(!check.NextRow())
q.Add("INSERT into client (ckey, ooc_color, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, hear_voicesound, hear_instruments, ambience_volume, credits_volume, window_flashing, antag_objectives, typing_indicator) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",\
ckey, ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, hear_voicesound, hear_instruments, ambience_volume, credits_volume, window_flashing, antag_objectives, typing_indicator)
q.Add("INSERT into client (ckey, ooc_color, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, hear_voicesound, hear_instruments, ambience_volume, credits_volume, window_flashing, antag_objectives, typing_indicator, mob_chat_on_map, max_chat_length, obj_chat_on_map, no_goonchat_for_obj) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, ?)",\
ckey, ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, hear_voicesound, hear_instruments, ambience_volume, credits_volume, window_flashing, antag_objectives, typing_indicator, mob_chat_on_map, max_chat_length, obj_chat_on_map, no_goonchat_for_obj)
if(!q.Execute(db))
message_admins("Error in save_preferences_sqlite [__FILE__] ln:[__LINE__] #: [q.Error()] - [q.ErrorMsg()]")
WARNING("Error in save_preferences_sqlite [__FILE__] ln:[__LINE__] #:[q.Error()] - [q.ErrorMsg()]")
return 0
else
q.Add("UPDATE client SET ooc_color=?,lastchangelog=?,UI_style=?,default_slot=?,toggles=?,UI_style_color=?,UI_style_alpha=?,warns=?,warnbans=?,randomslot=?,volume=?,usewmp=?,special=?,usenanoui=?,tooltips=?,progress_bars=?,space_parallax=?,space_dust=?,parallax_speed=?, stumble=?, attack_animation=?, pulltoggle=?, credits=?, jingle=?, hear_voicesound=?, hear_instruments=?, ambience_volume=?, credits_volume=?, window_flashing=?, antag_objectives=? , typing_indicator=? WHERE ckey = ?",\
ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, hear_voicesound, hear_instruments, ambience_volume, credits_volume, window_flashing, antag_objectives, typing_indicator, ckey)
q.Add("UPDATE client SET ooc_color=?,lastchangelog=?,UI_style=?,default_slot=?,toggles=?,UI_style_color=?,UI_style_alpha=?,warns=?,warnbans=?,randomslot=?,volume=?,usewmp=?,special=?,usenanoui=?,tooltips=?,progress_bars=?,space_parallax=?,space_dust=?,parallax_speed=?, stumble=?, attack_animation=?, pulltoggle=?, credits=?, jingle=?, hear_voicesound=?, hear_instruments=?, ambience_volume=?, credits_volume=?, window_flashing=?, antag_objectives=? , typing_indicator=? , mob_chat_on_map=? , max_chat_length=?, obj_chat_on_map=?, no_goonchat_for_obj=?, WHERE ckey = ?",\
ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, hear_voicesound, hear_instruments, ambience_volume, credits_volume, window_flashing, antag_objectives, typing_indicator, mob_chat_on_map, max_chat_length, obj_chat_on_map,no_goonchat_for_obj, ckey)
if(!q.Execute(db))
message_admins("Error in save_preferences_sqlite [__FILE__] ln:[__LINE__] #: [q.Error()] - [q.ErrorMsg()]")
WARNING("Error in save_preferences_sqlite [__FILE__] ln:[__LINE__] #:[q.Error()] - [q.ErrorMsg()]")
@@ -276,6 +280,10 @@
S["window_flashing"]<< window_flashing
S["antag_objectives"]<< antag_objectives
S["typing_indicator"]<< typing_indicator
S["mob_chat_on_map"] << mob_chat_on_map
S["max_chat_length"] << max_chat_length
S["obj_chat_on_map"] << obj_chat_on_map
S["no_goonchat_for_obj"] << no_goonchat_for_obj
return 1
//saving volume changes

View File

@@ -0,0 +1,33 @@
/datum/migration/sqlite/ss13_prefs/_023
id = 23
name = "Runechat"
/datum/migration/sqlite/ss13_prefs/_023/up()
var/mig1
var/mig2
var/mig3
var/mig4
if(!hasColumn("client","mob_chat_on_map"))
mig1 = execute("ALTER TABLE `client` ADD COLUMN mob_chat_on_map INTEGER DEFAULT 0")
if(!hasColumn("client","max_chat_length"))
mig2 = execute("ALTER TABLE `client` ADD COLUMN max_chat_length INTEGER DEFAULT [CHAT_MESSAGE_MAX_LENGTH]")
if(!hasColumn("client","obj_chat_on_map"))
mig3 = execute("ALTER TABLE `client` ADD COLUMN obj_chat_on_map INTEGER DEFAULT 0")
if(!hasColumn("client","no_goonchat_for_obj"))
mig4 = execute("ALTER TABLE `client` ADD COLUMN no_goonchat_for_obj INTEGER DEFAULT 0")
return mig1 && mig2 && mig3 && mig4
/datum/migration/sqlite/ss13_prefs/_023/down()
var/mig1
var/mig2
var/mig3
var/mig4
if(hasColumn("client","mob_chat_on_map"))
mig1 = execute("ALTER TABLE `client` DROP COLUMN mob_chat_on_map")
if(hasColumn("client","obj_chat_on_map"))
mig2 = execute("ALTER TABLE `client` DROP COLUMN obj_chat_on_map")
if(hasColumn("client","max_chat_length"))
mig3 = execute("ALTER TABLE `client` DROP COLUMN max_chat_length")
if(hasColumn("client","no_goonchat_for_obj"))
mig4 = execute("ALTER TABLE `client` DROP COLUMN no_goonchat_for_obj")
return mig1 && mig2 && mig3 && mig4

View File

@@ -45,5 +45,7 @@
if ((client.prefs.toggles & CHAT_GHOSTRADIO) != CHAT_GHOSTRADIO)
say_testing(src, "/mob/dead/observer/Hear(): CHAT_GHOSTRADIO is disabled, blocking. ([client.prefs.toggles] & [CHAT_GHOSTRADIO]) = [client.prefs.toggles & CHAT_GHOSTRADIO]")
return
if (client?.prefs.mob_chat_on_map && (client.prefs.obj_chat_on_map || ismob(speech.speaker)))
create_chat_message(speech.speaker, speech.language, speech.message, speech.mode, speech.wrapper_classes)
to_chat(src, "<a href='?src=\ref[src];follow=\ref[source]'>(Follow)</a> [rendered_speech]")

View File

@@ -74,6 +74,19 @@ var/list/department_radio_keys = list(
":&" = "borerchat", "#&" = "borerchat", ".&" = "borerchat",
)
var/list/headset_modes = list(
"Response Team",
"Command",
"Service",
"Engineering",
"Security",
"Syndicate",
"Supply",
"Medical",
"Science",
"department",
)
/mob/living/proc/get_default_language()
if(!default_language)
if(languages && languages.len)
@@ -181,6 +194,8 @@ var/list/department_radio_keys = list(
treat_speech(speech)
var/radio_return = get_speech_flags(message_mode)
if (speech_was_spoken_into_radio(message_mode))
speech.wrapper_classes.Add("spoken_into_radio")
if(radio_return & NOPASS) //There's a whisper() message_mode, no need to continue the proc if that is called
whisper(speech.message, speech.language)
returnToPool(speech)
@@ -261,7 +276,16 @@ var/list/department_radio_keys = list(
rendered_message = replacetextEx(rendered_message, "AI", "<i style='color: blue;'>AI</i>")
rendered_message = replacetext(rendered_message, ai.real_name, "<i style='color: blue;'>[ai.real_name]</i>")
// Runechat messages
if (ismob(speech.speaker) && client?.prefs.mob_chat_on_map && stat != UNCONSCIOUS && !is_deaf())
create_chat_message(speech.speaker, speech.language, speech.message, speech.mode, speech.wrapper_classes)
else if (client?.prefs.obj_chat_on_map && stat != UNCONSCIOUS && !is_deaf())
create_chat_message(speech.speaker, speech.language, speech.message, speech.mode, speech.wrapper_classes)
if (ismob(speech.speaker))
show_message(rendered_message, type, deaf_message, deaf_type, src)
else if (!client.prefs.no_goonchat_for_obj || length_char(speech.message) > client?.prefs.max_chat_length) // Objects : only display if no goonchat on map or if the runemessage is too small.
show_message(rendered_message, type, deaf_message, deaf_type, src)
return rendered_message
/mob/living/proc/hear_radio_only()
@@ -454,6 +478,14 @@ var/list/department_radio_keys = list(
return 0
/mob/living/proc/speech_was_spoken_into_radio(var/message_mode)
if (message_mode in headset_modes)
return TRUE
switch (message_mode)
if(MODE_HEADSET, MODE_SECURE_HEADSET, MODE_R_HAND, MODE_L_HAND, MODE_INTERCOM, MODE_BINARY)
return TRUE
return FALSE
/mob/living/proc/radio(var/datum/speech/speech, var/message_mode)
switch(message_mode)
if(MODE_R_HAND)

View File

@@ -1,5 +1,8 @@
#define WORLD_ICON_SIZE 32
#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32
var/world_startup_time
/world
mob = /mob/new_player
turf = /turf/space
@@ -7,11 +10,13 @@
cache_lifespan = 0 //stops player uploaded stuff from being kept in the rsc past the current session
//loop_checks = 0
icon_size = WORLD_ICON_SIZE
#define RECOMMENDED_VERSION 512
#define RECOMMENDED_VERSION 513
var/savefile/panicfile
/world/New()
world_startup_time = world.timeofday
var/extools_path = system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so"
if(fexists(extools_path))
call(extools_path, "maptick_initialize")()
@@ -68,7 +73,7 @@ var/savefile/panicfile
*/
#ifdef BORDER_USE_TURF_EXIT
if(byond_version < RECOMMENDED_VERSION)
warning("Your server's byond version does not meet the recommended requirements for this code. Please update BYOND to atleast 512.1426")
warning("Your server's byond version does not meet the recommended requirements for this code. Please update BYOND to atleast 513.")
#endif
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)

BIN
icons/chat_icons.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

View File

@@ -782,6 +782,7 @@ window "mapwindow"
text-color = none
is-default = true
saved-params = "icon-size"
style=".center { text-align: center; } .runechatdiv {background-color: #20202070} .black_outline { -dm-text-outline: 1px black } .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: 6px; }"
elem "credits"
type = BROWSER
pos = 0,0

View File

@@ -764,6 +764,7 @@ window "mapwindow"
text-color = none
is-default = true
saved-params = "icon-size"
style=".center { text-align: center; } .runechatdiv {background-color: #20202070} .black_outline { -dm-text-outline: 1px black } .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: 6px; }"
elem "credits"
type = BROWSER
pos = 0,0

View File

@@ -243,6 +243,7 @@
#include "code\datums\ai_laws.dm"
#include "code\datums\alt_control.dm"
#include "code\datums\browser.dm"
#include "code\datums\chat_message.dm"
#include "code\datums\circuits.dm"
#include "code\datums\climate.dm"
#include "code\datums\computerfiles.dm"
@@ -1629,6 +1630,7 @@
#include "code\modules\migrations\SS13_Prefs\020-window_flashing.dm"
#include "code\modules\migrations\SS13_Prefs\021-antag_objectives.dm"
#include "code\modules\migrations\SS13_Prefs\022-say_bubbles.dm"
#include "code\modules\migrations\SS13_Prefs\023-runechat.dm"
#include "code\modules\migrations\SS13_Prefs\_base.dm"
#include "code\modules\mining\abandonedcrates.dm"
#include "code\modules\mining\debug_shit.dm"