diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 1da75a3d214b..c535291e7e15 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -438,3 +438,5 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE #define NO_INIT_PARAMETER "no-init" #define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.") + +#define LIBVG(function, arguments...) call("./libvg.[world.system_type == "UNIX" ? "so" : "dll"]", function)(arguments) \ No newline at end of file diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 0b783c64e98b..6aad7197b2b3 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -213,7 +213,7 @@ SUBSYSTEM_DEF(ticker) if(GLOB.secret_force_mode != "secret") var/datum/game_mode/smode = config.pick_mode(GLOB.secret_force_mode) if(!smode.can_start()) - message_admins("\blue Unable to force secret [GLOB.secret_force_mode]. [smode.required_players] players and [smode.required_enemies] eligible antagonists needed.") + message_admins("Unable to force secret [GLOB.secret_force_mode]. [smode.required_players] players and [smode.required_enemies] eligible antagonists needed.") else mode = smode diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm index 13b4234622b8..622932d432ad 100644 --- a/code/game/gamemodes/sandbox/h_sandbox.dm +++ b/code/game/gamemodes/sandbox/h_sandbox.dm @@ -114,11 +114,11 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE) if("hsbtobj") if(!admin) return if(GLOB.hsboxspawn) - to_chat(world, "Sandbox: \black[usr.key] has disabled object spawning!") + to_chat(world, "Sandbox: [usr.key] has disabled object spawning!") GLOB.hsboxspawn = FALSE return else - to_chat(world, "Sandbox: \black[usr.key] has enabled object spawning!") + to_chat(world, "Sandbox: [usr.key] has enabled object spawning!") GLOB.hsboxspawn = TRUE return // @@ -128,9 +128,9 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE) if(!admin) return var/sbac = CONFIG_GET(flag/sandbox_autoclose) if(sbac) - to_chat(world, "Sandbox: \black [usr.key] has removed the object spawn limiter.") + to_chat(world, "Sandbox: [usr.key] has removed the object spawn limiter.") else - to_chat(world, "Sandbox: \black [usr.key] has added a limiter to object spawning. The window will now auto-close after use.") + to_chat(world, "Sandbox: [usr.key] has added a limiter to object spawning. The window will now auto-close after use.") CONFIG_SET(flag/sandbox_autoclose, !sbac) return // diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index d0f06e19c829..4881588daa1e 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -53,7 +53,7 @@ if(..()) return if(!is_station_level(z) && !is_centcom_level(z)) //Can only use on centcom and SS13 - to_chat(usr, "Unable to establish a connection: \black You're too far away from the station!") + to_chat(usr, "Unable to establish a connection: You're too far away from the station!") return usr.set_machine(src) @@ -432,7 +432,7 @@ if(..()) return if (z > 6) - to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") + to_chat(user, "Unable to establish a connection: You're too far away from the station!") return user.set_machine(src) diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index ef38fafd7b86..c15db0e63d90 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -29,7 +29,7 @@ /obj/machinery/computer/robotics/interact(mob/user) if (src.z > 6) - to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") + to_chat(user, "Unable to establish a connection: You're too far away from the station!") return user.set_machine(src) var/dat diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 8b08824c4483..d8ff898a7e00 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -58,7 +58,7 @@ if(..()) return if(src.z > 6) - to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") + to_chat(user, "Unable to establish a connection: You're too far away from the station!") return var/dat diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index bce12597ab17..415959b55521 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -390,7 +390,7 @@ Possible to do for anyone motivated enough: if(is_operational() && (!AI || AI.eyeobj.loc == loc))//If the projector has power and client eye is on it if (AI && istype(AI.current, /obj/machinery/holopad)) - to_chat(user, "ERROR: \black Image feed in progress.") + to_chat(user, "ERROR:Image feed in progress.") return var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location. diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 044336e65d77..218404db932b 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -827,7 +827,7 @@ GLOBAL_LIST_EMPTY(PDAs) user.show_message("Analyzing Results for [C]:") if(C.radiation) - user.show_message("\green Radiation Level: \black [C.radiation]") + user.show_message("Radiation Level: [C.radiation]") else user.show_message("No radiation detected.") diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index b8176a4ce784..3486c2dadfac 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -310,7 +310,7 @@ if(result) SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]")) log_admin("[key_name(usr)] turned all humans into [result]", 1) - message_admins("\blue [key_name_admin(usr)] turned all humans into [result]") + message_admins("[key_name_admin(usr)] turned all humans into [result]") var/newtype = GLOB.species_list[result] for(var/mob/living/carbon/human/H in GLOB.carbon_list) H.set_species(newtype) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index a19ab3c10061..8c5c2a6846d5 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -496,7 +496,7 @@ else if(char == "'") if(word != "") - to_chat(usr, "\red SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") return null word = "'" @@ -516,7 +516,7 @@ word += char if(i > len) - to_chat(usr, "\red SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again.") return null query_list += "[word]'" @@ -524,7 +524,7 @@ else if(char == "\"") if(word != "") - to_chat(usr, "\red SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") return null word = "\"" @@ -544,7 +544,7 @@ word += char if(i > len) - to_chat(usr, "\red SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again.") return null query_list += "[word]\"" diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 5c87293b731d..47e3d1d71e73 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -698,7 +698,7 @@ Traitors and the like can also be revived with the previous role mostly intact. change_view(CONFIG_GET(string/default_view)) log_admin("[key_name(usr)] changed their view range to [view].") - //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI + //message_admins("[key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[view]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 90b2e3a02ec8..a85f01c0b084 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -156,10 +156,10 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation) /obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params) if(istype(W, /obj/item/device/multitool)) if(calibrated) - to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.") + to_chat(user, "The gate is already calibrated, there is no work for you to do here.") return else - to_chat(user, "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.") + to_chat(user, "Recalibration successful!: This gate's systems have been fine tuned. Travel to this gate will now be on target.") calibrated = TRUE return @@ -201,7 +201,7 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation) /obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/L) for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant - to_chat(L, "\black The station gate has detected your exile implant and is blocking your entry.") + to_chat(L, "The station gate has detected your exile implant and is blocking your entry.") return TRUE return FALSE diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 193d23e7bfdd..7be4ff1b950f 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -64,6 +64,8 @@ var/list/topiclimiter var/datum/chatOutput/chatOutput + // This gets set by goonchat. + var/encoding = "1252" var/list/credits //lazy list of all credit object bound to this client diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 7ac3724662b1..4cff69762c47 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -83,6 +83,22 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if("setMusicVolume") data = setMusicVolume(arglist(params)) + if("encoding") + var/encoding = href_list["encoding"] + var/static/regex/RE = regex("windows-(874|125\[0-8])") + if (RE.Find(encoding)) + owner.encoding = RE.group[1] + + else if (encoding == "gb2312") + owner.encoding = "2312" + + // This seems to be the result on Japanese locales, but the client still seems to accept 1252. + else if (encoding == "_autodetect") + owner.encoding = "1252" + + else + stack_trace("Unknown encoding received from client: \"[sanitize(encoding)]\". Please report this as a bug.") + if(data) ehjax_send(data = data) @@ -211,6 +227,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic message = replacetext(message, "\n", "
") message = replacetext(message, "\t", "[GLOB.TAB][GLOB.TAB]") + message = to_utf8(message, target) + for(var/I in targets) //Grab us a client if possible var/client/C = grab_client(I) diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index 77aae1148aac..8d03b8acace8 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -572,6 +572,12 @@ if (typeof $ === 'undefined') { } $(function() { + // Detect encoding. + if (document.defaultCharset) + { + runByond("?_src_=chat&proc=encoding&encoding=" + escaper(document.defaultCharset)); + } + $messages = $('#messages'); $subOptions = $('#subOptions'); $subAudio = $('#subAudio'); diff --git a/code/modules/libvg/utf8.dm b/code/modules/libvg/utf8.dm new file mode 100644 index 000000000000..6d7be59eca30 --- /dev/null +++ b/code/modules/libvg/utf8.dm @@ -0,0 +1,69 @@ +// Note about encodings: +// Encodings are passed by number as it's simplest to do it like this (citation needed) +// This may cause some confusion with what codes correspond how. +// +// 874 and 1250-1258 are Windows CodePage encodings. The number corresponds to the CodePage. +// 2312 is gb2312 (Chinese) +/proc/_determine_encoding(var/mob_or_client) + . = "1252" + if (istype(mob_or_client, /client)) + var/client/C = mob_or_client + . = C.encoding + + else if (ismob(mob_or_client)) + var/mob/M = mob_or_client + if (M.client) + . = M.client.encoding + + +/proc/to_utf8(var/message, var/mob_or_client) + return LIBVG("to_utf8", _determine_encoding(mob_or_client), message) + +// Converts a byte string to a UTF-8 string, sanitizes it and caps the length. +/proc/utf8_sanitize(var/message, var/mob_or_client, var/length) + return LIBVG("utf8_sanitize", _determine_encoding(mob_or_client), message, num2text(length)) + +// Get the length (Unicode Scalars) of a UTF-8 string. +/proc/utf8_len(var/message) + return text2num(LIBVG("utf8_len", message)) + +/proc/utf8_byte_len(var/a) + return length(a) + +/proc/utf8_find(var/haystack, var/needle, var/start=1, var/end=0) + return text2num(LIBVG("utf8_find", haystack, needle, "[start]", "[end]")) + +/proc/utf8_copy(var/text, var/start=1, var/end=0) + return LIBVG("utf8_copy", text, "[start]", "[end]") + +/proc/utf8_replace(var/text, var/from, var/to_, var/start=1, var/end=0) + return LIBVG("utf8_replace", text, from, to_, "[start]", "[end]") + +/proc/utf8_index(var/text, var/index) + return LIBVG("utf8_index", text, "[index]") + +/proc/utf8_uppercase(var/text) + return LIBVG("utf8_uppercase", text) + +/proc/utf8_lowercase(var/text) + return LIBVG("utf8_lowercase", text) + +// Removes non-7-bit ASCII characters. +// Useful for things which BYOND touches itself like object names. +/proc/strict_ascii(var/text) + return LIBVG("strict_ascii", text) + +/proc/utf8_capitalize(var/text) + return utf8_uppercase(utf8_index(text, 1)) + utf8_copy(text, 2) + +/proc/utf8_reverse(var/text) + return LIBVG("utf8_reverse", text) + +/proc/utf8_leftpad(var/text, var/count, var/with=" ") + return LIBVG("utf8_leftpad", text, "[count]", with) + +/proc/utf8_is_whitespace(var/text) + return text2num(LIBVG("utf8_is_whitespace", text)) + +/proc/utf8_trim(var/text) + return LIBVG("utf8_trim", text) \ No newline at end of file diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm index 4b159557bcce..8bfd12d08f9a 100644 --- a/code/modules/ninja/suit/suit_initialisation.dm +++ b/code/modules/ninja/suit/suit_initialisation.dm @@ -34,7 +34,7 @@ return lockIcons(U)//Check for icons. U.regenerate_icons() - to_chat(U, "Linking neural-net interface...\nPattern\green GREEN, continuing operation.") + to_chat(U, "Linking neural-net interface...\nPatternGREEN, continuing operation.") addtimer(CALLBACK(src, .proc/ninitialize_five, delay, U), delay) /obj/item/clothing/suit/space/space_ninja/proc/ninitialize_five(delay, mob/living/carbon/human/U) @@ -79,11 +79,11 @@ addtimer(CALLBACK(src, .proc/deinitialize_six, delay, U), delay) /obj/item/clothing/suit/space/space_ninja/proc/deinitialize_six(delay, mob/living/carbon/human/U) - to_chat(U, "Disconnecting neural-net interface...\greenSuccess.") + to_chat(U, "Disconnecting neural-net interface...Success.") addtimer(CALLBACK(src, .proc/deinitialize_seven, delay, U), delay) /obj/item/clothing/suit/space/space_ninja/proc/deinitialize_seven(delay, mob/living/carbon/human/U) - to_chat(U, "Disengaging neural-net interface...\greenSuccess.") + to_chat(U, "Disengaging neural-net interface...Success.") addtimer(CALLBACK(src, .proc/deinitialize_eight, delay, U), delay) /obj/item/clothing/suit/space/space_ninja/proc/deinitialize_eight(delay, mob/living/carbon/human/U) diff --git a/libvg.dll b/libvg.dll new file mode 100644 index 000000000000..606f59bf6161 Binary files /dev/null and b/libvg.dll differ diff --git a/yogstation.dme b/yogstation.dme index 362a970d58f2..fe05b975ca85 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1669,6 +1669,7 @@ #include "code\modules\library\lib_readme.dm" #include "code\modules\library\random_books.dm" #include "code\modules\library\soapstone.dm" +#include "code\modules\libvg\utf8.dm" #include "code\modules\lighting\lighting_area.dm" #include "code\modules\lighting\lighting_atom.dm" #include "code\modules\lighting\lighting_corner.dm"