diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 13ccf960003..13168a07b45 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,7 +9,6 @@ /code/controllers/subsystems/cargo.dm @Arrow768 /code/datums/api.dm @Arrow768 /code/datums/cargo.dm @Arrow768 -/code/datums/server_greeting.dm @Skull132 /code/datums/discord/ @Skull132 /code/defines/procs/dbcore.dm @Skull132 /code/modules/http/ @Arrow768 @Skull132 diff --git a/.travis.yml b/.travis.yml index 28791ac449b..a57c1fd19f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: BYOND_MINOR="1517" MACRO_COUNT=0 GENDER_COUNT=6 - TO_WORLD_COUNT=223 + TO_WORLD_COUNT=207 FLYWAY_BUILD="5.2.4" NODE_VERSION=10 RUST_G_VERSION="0.4.2a" diff --git a/aurorastation.dme b/aurorastation.dme index e9da2e83ce3..1261a1d7804 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -178,6 +178,7 @@ #include "code\controllers\subsystems\assets.dm" #include "code\controllers\subsystems\battle_monsters.dm" #include "code\controllers\subsystems\cargo.dm" +#include "code\controllers\subsystems\chat.dm" #include "code\controllers\subsystems\chemistry.dm" #include "code\controllers\subsystems\cult.dm" #include "code\controllers\subsystems\documents.dm" @@ -210,6 +211,7 @@ #include "code\controllers\subsystems\overlays.dm" #include "code\controllers\subsystems\pai.dm" #include "code\controllers\subsystems\parallax.dm" +#include "code\controllers\subsystems\ping.dm" #include "code\controllers\subsystems\plants.dm" #include "code\controllers\subsystems\power.dm" #include "code\controllers\subsystems\profiler.dm" @@ -267,7 +269,6 @@ #include "code\datums\position_point_vector.dm" #include "code\datums\progressbar.dm" #include "code\datums\records.dm" -#include "code\datums\server_greeting.dm" #include "code\datums\statistic.dm" #include "code\datums\weakref.dm" #include "code\datums\brain_damage\brain_trauma.dm" @@ -1106,7 +1107,6 @@ #include "code\modules\admin\admin_investigate.dm" #include "code\modules\admin\admin_ranks.dm" #include "code\modules\admin\admin_secrets.dm" -#include "code\modules\admin\admin_server_greeting.dm" #include "code\modules\admin\admin_verbs.dm" #include "code\modules\admin\banjob.dm" #include "code\modules\admin\create_mob.dm" @@ -1300,6 +1300,7 @@ #include "code\modules\client\client defines.dm" #include "code\modules\client\client procs.dm" #include "code\modules\client\client_color.dm" +#include "code\modules\client\darkmode.dm" #include "code\modules\client\movement.dm" #include "code\modules\client\preferences.dm" #include "code\modules\client\preferences_ambience.dm" @@ -1477,6 +1478,7 @@ #include "code\modules\cooking\machinery\cooking_machines\cereal.dm" #include "code\modules\cooking\machinery\cooking_machines\container.dm" #include "code\modules\cooking\machinery\cooking_machines\fryer.dm" +#include "code\modules\cooking\machinery\cooking_machines\grill.dm" #include "code\modules\cooking\machinery\cooking_machines\oven.dm" #include "code\modules\cooking\machinery\cooking_machines\stove.dm" #include "code\modules\cooking\recipes\recipe.dm" @@ -1617,6 +1619,8 @@ #include "code\modules\ghosttrap\trap.dm" #include "code\modules\global_listener\devices.dm" #include "code\modules\global_listener\interfaces.dm" +#include "code\modules\goonchat\_helpers.dm" +#include "code\modules\goonchat\browserOutput.dm" #include "code\modules\hallucinations\hallucinations.dm" #include "code\modules\hallucinations\mob.dm" #include "code\modules\hallucinations\types\basic.dm" diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm index 3c79ab31646..ab75f2d9707 100644 --- a/code/ATMOSPHERICS/components/valve.dm +++ b/code/ATMOSPHERICS/components/valve.dm @@ -240,7 +240,7 @@ return ..() - log_and_message_admins("has [open ? "OPENED" : "closed"] [name].", user) + log_and_message_admins("has [open ? "OPENED" : "closed"] [name].", user) /obj/machinery/atmospherics/valve/digital/AltClick(var/mob/abstract/observer/admin) if (istype(admin)) diff --git a/code/__defines/_macros.dm b/code/__defines/_macros.dm index bb7cad71ae9..3c4b4f9ab81 100644 --- a/code/__defines/_macros.dm +++ b/code/__defines/_macros.dm @@ -79,14 +79,19 @@ #define isprojectile(A) istype(A, /obj/item/projectile) -#define to_chat(target, message) target << message -#define to_world(message) world << message -#define sound_to(target, sound) target << sound +/// General I/O helpers +#define to_target(target, payload) target << (payload) +#define from_target(target, receiver) target >> (receiver) #define to_file(file_entry, file_content) file_entry << file_content -#define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name) -#define send_rsc(target, rsc_content, rsc_name) target << browse_rsc(rsc_content, rsc_name) -#define send_output(target, msg, control) target << output(msg, control) -#define send_link(target, url) target << link(url) + +#define legacy_chat(target, message) to_target(target, message) +#define to_world(message) to_chat(world, message) +#define sound_to(target, sound) to_target(target, sound) +#define to_save(handle, value) to_target(handle, value) //semantics postport: what did they mean by this +#define show_browser(target, browser_content, browser_name) to_target(target, browse(browser_content, browser_name)) +#define send_rsc(target, content, title) to_target(target, browse_rsc(content, title)) +#define send_output(target, msg, control) to_target(target, output(msg, control)) +#define send_link(target, url) to_target(target, link(url)) #define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE) diff --git a/code/__defines/color.dm b/code/__defines/color.dm index 9f4e671dc7a..2c4d1813a8d 100644 --- a/code/__defines/color.dm +++ b/code/__defines/color.dm @@ -118,4 +118,8 @@ #define COLOR_ASSEMBLY_LBLUE "#5D99BE" #define COLOR_ASSEMBLY_BLUE "#38559E" #define COLOR_ASSEMBLY_PURPLE "#6F6192" -#define COLOR_ASSEMBLY_HOT_PINK "#FF69B4" \ No newline at end of file +#define COLOR_ASSEMBLY_HOT_PINK "#FF69B4" + +#define COLOR_DARKMODE_BACKGROUND "#202020" +#define COLOR_DARKMODE_DARKBACKGROUND "#171717" +#define COLOR_DARKMODE_TEXT "#a4bad6" \ No newline at end of file diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 5df065c49be..ba624bd02db 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -442,6 +442,10 @@ Define for getting a bitfield of adjacent turfs that meet a condition. #define CONTAINER_EMPTY 0 #define CONTAINER_SINGLE 1 #define CONTAINER_MANY 2 +//Misc text define. Does 4 spaces. Used as a makeshift tabulator. +#define FOURSPACES "    " +#define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (isclient(I) ? I : (istype(I, /datum/mind) ? I:current?:client : null))) + // check_items/check_reagents/check_fruits return values #define COOK_CHECK_FAIL -1 #define COOK_CHECK_EXTRA 0 diff --git a/code/__defines/subsystem-priority.dm b/code/__defines/subsystem-priority.dm index 9290a7e6d8b..4cea85495d3 100644 --- a/code/__defines/subsystem-priority.dm +++ b/code/__defines/subsystem-priority.dm @@ -22,7 +22,8 @@ #define SS_INIT_SUNLIGHT 2 // Sunlight setup. Creates lots of lighting & SSzcopy updates. #define SS_INIT_LIGHTING 1 // Generation of lighting overlays and pre-bake. May cause openturf updates, should initialize before SSzcopy. #define SS_INIT_ZCOPY 0 // Z-mimic flush. Should run after SSoverlay & SSicon_smooth so it copies the smoothed sprites. -#define SS_INIT_LOBBY -1 // Lobby timer starts here. The lobby timer won't actually start going down until the MC starts ticking, so you probably want this last. +#define SS_INIT_LOBBY -1 // Lobby timer starts here. The lobby timer won't actually start going down until the MC starts ticking, so you probably want this last +#define SS_INIT_CHAT -2 // To ensure chat remains smooth during init. // Something to remember when setting priorities: SS_TICKER runs before Normal, which runs before SS_BACKGROUND. // Each group has its own priority bracket. @@ -47,6 +48,7 @@ #define SS_PRIORITY_LIGHTING 50 // Queued lighting engine updates. #define SS_PRIORITY_MOB 30 // Mob Life(). #define SS_PRIORITY_AIR 30 // ZAS processing. +#define SS_PRIORITY_CHAT 30 // Chat #define SS_PRIORITY_NANOUI 20 // UI updates. #define SS_PRIORITY_VOTE 20 #define SS_PRIORITY_ELECTRONICS 20 // Integrated Electronics processing. @@ -60,6 +62,7 @@ #define SS_PRIORITY_CHEMISTRY 10 // Multi-tick chemical reactions. #define SS_PRIORITY_SHUTTLE 10 // Shuttle movement. #define SS_PRIORITY_AIRFLOW 10 // Handles object movement due to ZAS airflow. +#define SS_PRIORITY_PING 10 #define SS_PRIORITY_ZCOPY 10 // Z-mimic icon generation/updates. // SS_BACKGROUND diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm index 7e91c61534c..08c2f4ad244 100644 --- a/code/_helpers/files.dm +++ b/code/_helpers/files.dm @@ -27,7 +27,7 @@ //Sends resource files to client cache /client/proc/getFiles() for(var/file in args) - to_chat(src, browse_rsc(file)) + send_rsc(src, file, null) /client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm")) var/path = root @@ -51,7 +51,7 @@ var/extension = copytext(path,-4,0) if( !fexists(path) || !(extension in valid_extensions) ) - to_chat(src, "Error: browse_files(): File not found/Invalid file([path]).") + to_chat(src, "Error: browse_files(): File not found/Invalid file([path]).") return return path @@ -65,7 +65,7 @@ /client/proc/file_spam_check() var/time_to_wait = fileaccess_timer - world.time if(time_to_wait > 0) - to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.") + to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.") return 1 fileaccess_timer = world.time + FTPDELAY return 0 diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index df15e18a07b..6bc3970f59f 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -167,7 +167,7 @@ mob Output_Icon() set name = "2. Output Icon" - src<<"Icon is: \icon[getFlatIcon(src)]" + src<<"Icon is: [icon2html(getFlatIcon(src), usr)]" Label_Icon() set name = "3. Label Icon" diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm index 33a660a2333..c5647e5946f 100644 --- a/code/_helpers/mobs.dm +++ b/code/_helpers/mobs.dm @@ -153,11 +153,11 @@ Proc for attack log creation, because really why not /proc/add_logs(mob/user, mob/target, what_done, var/admin=1, var/object=null, var/addition=null) if(user && ismob(user)) - user.attack_log += text("\[[time_stamp()]\] Has [what_done] [target ? "[target.name][(ismob(target) && target.ckey) ? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]") + user.attack_log += text("\[[time_stamp()]\] Has [what_done] [target ? "[target.name][(ismob(target) && target.ckey) ? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]") if(target && ismob(target)) target.attack_log += text("\[[time_stamp()]\] Has been [what_done] by [user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]") if(admin) - log_attack("[user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"] [what_done] [target ? "[target.name][(ismob(target) && target.ckey)? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]",ckey=key_name(user),ckey_target=key_name(target)) + log_attack("[user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"] [what_done] [target ? "[target.name][(ismob(target) && target.ckey)? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]",ckey=key_name(user),ckey_target=key_name(target)) //checks whether this item is a module of the robot it is located in. /proc/is_robot_module(var/obj/item/thing) diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 3771e79f92c..d866fb679ec 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -376,10 +376,25 @@ //For generating neat chat tag-images //The icon var could be local in the proc, but it's a waste of resources // to always create it and then throw it out. -/proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null) +/proc/create_text_tag(var/tagname, var/client/C = null) if(C && (C.prefs.toggles & CHAT_NOICONS)) - return tagdesc - return "[tagdesc]" + return tagname + + var/list/tagname_to_class = list( + "OOC" = "ooc", + "LOOC" = "looc", + "DEV" = "dev", + "ADMIN" = "admin", + "MOD" = "mod", + "DEAD" = "dead", + "PM ->" = "pmin", + "PM <-" = "pmout", + "PM <->" = "pmother", + "HELP" = "help", + "A-OOC" = "aooc" + ) + + return "[tagname]" // For processing simple markup, similar to what Skype and Discord use. // Enabled from a config setting. diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 26823aabf9d..9bc1bb6e1dc 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -85,7 +85,7 @@ avoid code duplication. This includes items that may sometimes act as a standard M.lastattacker = user if(!no_attack_log) - user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" msg_admin_attack("[key_name(user, highlight_special = 1)] attacked [key_name(M, highlight_special = 1)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)]) (JMP)",ckey=key_name(user),ckey_target=key_name(M) ) ///////////////////////// diff --git a/code/controllers/master/failsafe.dm b/code/controllers/master/failsafe.dm index 4040e981f7f..680869ccd74 100644 --- a/code/controllers/master/failsafe.dm +++ b/code/controllers/master/failsafe.dm @@ -4,7 +4,7 @@ * Pretty much pokes the MC to make sure it's still alive. **/ -#define FAILSAFE_MSG(msg) admin_notice("FAILSAFE: [msg]", R_DEBUG|R_ADMIN|R_DEV) +#define FAILSAFE_MSG(msg) admin_notice("FAILSAFE: [msg]", R_DEBUG|R_ADMIN|R_DEV) var/datum/controller/failsafe/Failsafe diff --git a/code/controllers/subsystems/chat.dm b/code/controllers/subsystems/chat.dm new file mode 100644 index 00000000000..e373f4814b5 --- /dev/null +++ b/code/controllers/subsystems/chat.dm @@ -0,0 +1,83 @@ +var/datum/controller/subsystem/chat/SSchat + +/datum/controller/subsystem/chat + name = "Chat" + wait = 1 + flags = SS_FIRE_IN_LOBBY + priority = SS_PRIORITY_CHAT + init_order = SS_INIT_CHAT + var/list/payload = list() + +/datum/controller/subsystem/chat/Initialize() + NEW_SS_GLOBAL(SSchat) + +/datum/controller/subsystem/chat/fire() + for(var/i in payload) + var/client/C = i + to_target(C, output(payload[C], "browseroutput:output")) + payload -= C + + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE, trailing_newline = TRUE) + if(!target || !message) + return + + if(!istext(message)) + CRASH("to_chat called with invalid input type") + + if(target == world) + target = clients + + //Some macros remain in the string even after parsing and fuck up the eventual output + var/original_message = message + message = replacetext(message, "\improper", "") + message = replacetext(message, "\proper", "") + if(handle_whitespace) + message = replacetext(message, "\n", "
") + message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") + if (trailing_newline) + message += "
" + + + //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + //Do the double-encoding here to save nanoseconds + var/twiceEncoded = url_encode(url_encode(message)) + + if(islist(target)) + for(var/I in target) + var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible + + if(!C) + return + + //Send it to the old style output window. + legacy_chat(C, original_message) + + if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. + continue + + if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + continue + + payload[C] += twiceEncoded + + else + var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible + + if(!C) + return + + //Send it to the old style output window. + legacy_chat(C, original_message) + + if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. + return + + if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + return + + payload[C] += twiceEncoded diff --git a/code/controllers/subsystems/garbage-debug.dm b/code/controllers/subsystems/garbage-debug.dm index 2ca625a1e97..73f0842b0db 100644 --- a/code/controllers/subsystems/garbage-debug.dm +++ b/code/controllers/subsystems/garbage-debug.dm @@ -189,7 +189,6 @@ SearchVar(debugobj) SearchVar(mods) SearchVar(gravity_is_on) - SearchVar(server_greeting) SearchVar(awaydestinations) SearchVar(fileaccess_timer) SearchVar(custom_event_msg) diff --git a/code/controllers/subsystems/ping.dm b/code/controllers/subsystems/ping.dm new file mode 100644 index 00000000000..958231c01b7 --- /dev/null +++ b/code/controllers/subsystems/ping.dm @@ -0,0 +1,32 @@ +/datum/controller/subsystem/ping + name = "Ping" + priority = SS_PRIORITY_PING + wait = 3 SECONDS + flags = SS_NO_INIT | SS_FIRE_IN_LOBBY + + var/list/currentrun = list() + +/datum/controller/subsystem/ping/stat_entry() + ..("P:[clients.len]") + + +/datum/controller/subsystem/ping/fire(resumed = 0) + if (!resumed) + src.currentrun = clients.Copy() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + + while (currentrun.len) + var/client/C = currentrun[currentrun.len] + currentrun.len-- + + if (!C || !C.chatOutput || !C.chatOutput.loaded) + if (MC_TICK_CHECK) + return + continue + + // softPang isn't handled anywhere but it'll always reset the opts.lastPang. + C.chatOutput.ehjax_send(data = C.is_afk(29) ? "softPang" : "pang") + if (MC_TICK_CHECK) + return diff --git a/code/controllers/subsystems/theming.dm b/code/controllers/subsystems/theming.dm index ac63e175b4f..5d3fd964273 100644 --- a/code/controllers/subsystems/theming.dm +++ b/code/controllers/subsystems/theming.dm @@ -28,47 +28,8 @@ var/datum/controller/subsystem/theming/SStheming ) ) - var/skin_files = list("Light" = "interface/skin.txt", "Dark" = "interface/dark.txt") - var/skin_themes - /datum/controller/subsystem/theming/New() NEW_SS_GLOBAL(SStheming) - skin_themes = list() - -/datum/controller/subsystem/theming/Initialize(start_timeofday) - for(var/name in skin_files) - skin_themes[name] = list() - var/loaded = file2list(skin_files[name]) - for(var/op in loaded) - var/split = text2list(op, " ") - if(!islist(skin_themes[name][split[1]])) - skin_themes[name][split[1]] = list() - skin_themes[name][split[1]] += split[2] - - for(var/mob/M in mob_list) - if(M.client) - apply_theme_from_perfs(M.client) - ..() - -/datum/controller/subsystem/theming/proc/apply_theme_from_perfs(var/user) - var/client/c - if(ismob(user)) - var/mob/M = user - c = M.client - if(isclient(user)) - c = user - if(!isclient(c)) - return - apply_theme(user, c.prefs.skin_theme) - -/datum/controller/subsystem/theming/proc/apply_theme(var/user, var/theme = "Dark") - if(!isclient(user) && !ismob(user)) - return - var/skin = skin_themes[theme] - if(!skin) - return - for(var/param in skin) - winset(user, param, jointext(skin[param], ";")) /datum/controller/subsystem/theming/proc/get_html_theme(var/mob/user) var/client/cl = null diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index de39a60b37a..3e35b8bebf0 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -244,22 +244,22 @@ var/datum/controller/subsystem/ticker/SSticker var/turf/playerTurf = get_turf(Player) if(emergency_shuttle.departed && emergency_shuttle.evac) if(isNotAdminLevel(playerTurf.z)) - to_chat(Player, "You managed to survive, but were marooned on [station_name()] as [Player.real_name]...") + to_chat(Player, "You managed to survive, but were marooned on [station_name()] as [Player.real_name]...") else - to_chat(Player, "You managed to survive the events on [station_name()] as [Player.real_name].") + to_chat(Player, "You managed to survive the events on [station_name()] as [Player.real_name].") else if(isAdminLevel(playerTurf.z)) - to_chat(Player, "You successfully underwent crew transfer after events on [station_name()] as [Player.real_name].") + to_chat(Player, "You successfully underwent crew transfer after events on [station_name()] as [Player.real_name].") else if(issilicon(Player)) - to_chat(Player, "You remain operational after the events on [station_name()] as [Player.real_name].") + to_chat(Player, "You remain operational after the events on [station_name()] as [Player.real_name].") else - to_chat(Player, "You missed the crew transfer after the events on [station_name()] as [Player.real_name].") + to_chat(Player, "You missed the crew transfer after the events on [station_name()] as [Player.real_name].") else if(istype(Player,/mob/abstract/observer)) var/mob/abstract/observer/O = Player if(!O.started_as_observer) - to_chat(Player, "You did not survive the events on [station_name()]...") + to_chat(Player, "You did not survive the events on [station_name()]...") else - to_chat(Player, "You did not survive the events on [station_name()]...") + to_chat(Player, "You did not survive the events on [station_name()]...") to_world("
") for (var/mob/living/silicon/ai/aiPlayer in mob_list) @@ -331,8 +331,8 @@ var/datum/controller/subsystem/ticker/SSticker m = pick(randomtips) if(m) - to_world("Tip of the round: \ - [html_encode(m)]") + to_world("Tip of the round: \ + [html_encode(m)]") /datum/controller/subsystem/ticker/proc/print_testmerges() var/data = revdata.testmerge_overview() @@ -360,7 +360,7 @@ var/datum/controller/subsystem/ticker/SSticker pregame_timeleft = dynamic_time log_debug("SSticker: dynamic set pregame time [dynamic_time]s was greater than configured autogamemode time, not clamping.") - to_world("Welcome to the pre-game lobby!") + to_world("Welcome to the pre-game lobby!") to_world("Please, setup your character and select ready. Game will start in [pregame_timeleft] seconds.") /datum/controller/subsystem/ticker/proc/setup() @@ -472,8 +472,8 @@ var/datum/controller/subsystem/ticker/SSticker //Deleting Startpoints but we need the ai point to AI-ize people later if (S.name != "AI") qdel(S) - to_world("Enjoy the game!") - to_world(sound('sound/AI/welcome.ogg')) + to_world("Enjoy the game!") + sound_to(world, sound('sound/AI/welcome.ogg')) //Holiday Round-start stuff ~Carn Holiday_Game_Start() @@ -544,18 +544,18 @@ var/datum/controller/subsystem/ticker/SSticker if("mercenary") //Nuke wasn't on station when it blew up flick("intro_nuke",cinematic) sleep(35) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) flick("station_intact_fade_red",cinematic) cinematic.icon_state = "summary_nukefail" else flick("intro_nuke",cinematic) sleep(35) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) //flick("end",cinematic) if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation sleep(50) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) else //station was destroyed if( mode && !override ) @@ -565,25 +565,25 @@ var/datum/controller/subsystem/ticker/SSticker flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red",cinematic) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) cinematic.icon_state = "summary_nukewin" if("AI malfunction") //Malf (screen,explosion,summary) flick("intro_malf",cinematic) sleep(76) flick("station_explode_fade_red",cinematic) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) cinematic.icon_state = "summary_malf" if("blob") //Station nuked (nuke,explosion,summary) flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red",cinematic) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) cinematic.icon_state = "summary_selfdes" else //Station nuked (nuke,explosion,summary) flick("intro_nuke",cinematic) sleep(35) flick("station_explode_fade_red", cinematic) - to_world(sound('sound/effects/explosionfar.ogg')) + sound_to(world, sound('sound/effects/explosionfar.ogg')) cinematic.icon_state = "summary_selfdes" //If its actually the end of the round, wait for it to end. diff --git a/code/controllers/subsystems/vote.dm b/code/controllers/subsystems/vote.dm index 29b6f10dba8..da8179e7a0b 100644 --- a/code/controllers/subsystems/vote.dm +++ b/code/controllers/subsystems/vote.dm @@ -98,13 +98,13 @@ var/datum/controller/subsystem/vote/SSvote else factor = 1.4 choices["Initiate Crew Transfer"]["votes"] = round(choices["Initiate Crew Transfer"]["votes"] * factor) - to_world("Crew Transfer Factor: [factor]") + to_world("Crew Transfer Factor: [factor]") greatest_votes = max(choices["Initiate Crew Transfer"]["votes"], choices["Continue The Round"]["votes"]) if(mode == "crew_transfer") if(round(get_round_duration() / 36000)+12 <= 14) // Credit to Scopes @ oldcode. - to_world("Majority voting rule in effect. 2/3rds majority needed to initiate transfer.") + to_world("Majority voting rule in effect. 2/3rds majority needed to initiate transfer.") choices["Initiate Crew Transfer"]["votes"] = round(choices["Initiate Crew Transfer"]["votes"] - round(total_votes / 3)) greatest_votes = max(choices["Initiate Crew Transfer"]["votes"], choices["Continue The Round"]["votes"]) @@ -143,7 +143,7 @@ var/datum/controller/subsystem/vote/SSvote if(mode == "add_antagonist") antag_add_failed = 1 log_vote(text) - to_world("[text]") + to_world("[text]") /datum/controller/subsystem/vote/proc/result() . = announce_result() @@ -173,7 +173,7 @@ var/datum/controller/subsystem/vote/SSvote if(mode == "gamemode") //fire this even if the vote fails. if(!round_progressing) round_progressing = 1 - to_world("The round will start soon.") + to_world("The round will start soon.") if(restart) to_world("World restarting due to vote...") @@ -287,20 +287,20 @@ var/datum/controller/subsystem/vote/SSvote text += "\n[sanitizeSafe(question)]" log_vote(text) - to_world("[text]\nType vote or click here to place your votes.\nYou have [config.vote_period/10] seconds to vote.") + to_world("[text]\nType vote or click here to place your votes.\nYou have [config.vote_period/10] seconds to vote.") for(var/cc in clients) var/client/C = cc if(C.prefs.asfx_togs & ASFX_VOTE) //Personal mute switch(vote_type) if("crew_transfer") - C << sound('sound/effects/vote.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + sound_to(C, sound('sound/effects/vote.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)) if("gamemode") - C << sound('sound/ambience/vote_alarm.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + sound_to(C, sound('sound/ambience/vote_alarm.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)) if("custom") - C << sound('sound/ambience/vote_alarm.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + sound_to(C, sound('sound/ambience/vote_alarm.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)) if(mode == "gamemode" && round_progressing) round_progressing = 0 - to_world("Round start has been delayed.") + to_world("Round start has been delayed.") SSvueui.check_uis_for_change(src) return 1 return 0 diff --git a/code/controllers/subsystems/zcopy.dm b/code/controllers/subsystems/zcopy.dm index 3d754802779..8bad87999d7 100644 --- a/code/controllers/subsystems/zcopy.dm +++ b/code/controllers/subsystems/zcopy.dm @@ -271,14 +271,14 @@ if (istype(A, /atom/movable/openspace/overlay)) var/atom/movable/openspace/overlay/OO = A var/atom/movable/AA = OO.associated_atom - out += "
  • \icon[A] plane [A.plane], layer [A.layer], depth [OO.depth], associated Z-level [AA.z] - [OO.type] copying [AA] ([AA.type])
  • " + out += "
  • [icon2html(A, usr)] plane [A.plane], layer [A.layer], depth [OO.depth], associated Z-level [AA.z] - [OO.type] copying [AA] ([AA.type])
  • " else if (isturf(A)) if (A == T) - out += "
  • \icon[A] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type]) - SELF
  • " + out += "
  • [icon2html(A, usr)] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type]) - SELF
  • " else // foreign turfs - not visible here, but good for figuring out layering - out += "
  • \icon[A] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type]) - FOREIGN
  • " + out += "
  • [icon2html(A, usr)] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type]) - FOREIGN
  • " else - out += "
  • \icon[A] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type])
  • " + out += "
  • [icon2html(A, usr)] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type])
  • " out += "" diff --git a/code/datums/discord/bot.dm b/code/datums/discord/bot.dm index 0093bfa5e05..a97cb18fd7c 100644 --- a/code/datums/discord/bot.dm +++ b/code/datums/discord/bot.dm @@ -21,9 +21,6 @@ var/datum/discord_bot/discord_bot = null discord_bot.update_channels() - if (config.use_discord_pins && server_greeting) - server_greeting.update_pins() - return 1 /hook/roundstart/proc/alert_no_admins() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 70713840358..10bafcbbb13 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -162,9 +162,9 @@ for(var/datum/objective/O in objectives) out += "Objective #[num]: [O.explanation_text] " if(O.completed) - out += "(complete)" + out += "(complete)" else - out += "(incomplete)" + out += "(incomplete)" out += " \[toggle\]" out += " \[remove\]
    " num++ diff --git a/code/datums/server_greeting.dm b/code/datums/server_greeting.dm deleted file mode 100644 index c0c946e9bcf..00000000000 --- a/code/datums/server_greeting.dm +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Server greeting datum. - * Contains the following information: - * - hashes for the message of the day and staff memos - * - the current message of the day and staff memos - * - the fully parsed welcome screen HTML data - * - * #TODO_LATER: Update this to be reliant on the game, and not an HTML template, whenever we update to TGui. Less hacks involved, then. - */ - -#define MEMOFILE "data/greeting.sav" - -#define OUTDATED_MOTD 1 -#define OUTDATED_MEMO 2 -#define OUTDATED_NOTE 4 - -#define JS_SANITIZE(msg) list2params(list(json_encode(msg))) - -/datum/server_greeting - // Hashes to figure out if we need to display the greeting message. - // These correspond to motd_hash and memo_hash on /datum/preferences for each client. - var/motd_hash = "" - var/memo_hash = "" - - // The stored strings of general subcomponents. - var/motd = "
    No new announcements to showcase.
    " - - var/memo_list[] = list() - var/memo = "
    No memos have been posted.
    " - - // Cached outdated information. - var/list/client_cache = list() - -/datum/server_greeting/New() - ..() - - load_from_file() - -/* - * Populates variables from save file, and loads the raw HTML data. - * Needs to be called at least once for successful initialization. - */ -/datum/server_greeting/proc/load_from_file() - var/savefile/F = new(MEMOFILE) - if (F) - if (F["motd"]) - F["motd"] >> motd - - if (!config.use_discord_pins) - if (F["memo"]) - F["memo"] >> memo_list - - update_data() - -/* - * A helper to regenerate the hashes for all data fields. - * As well as to reparse the staff memo list. - * Separated for the sake of avoiding the duplication of code. - */ -/datum/server_greeting/proc/update_data() - if (motd) - motd_hash = md5(motd) - else - motd = initial(motd) - motd_hash = "" - - if (!config.use_discord_pins) - // The initialization of memos in case use_discord_pins == 1 is done in discord_bot.dm - // Primary reason is to avoid null references when the bot isn't created yet. - if (memo_list.len) - memo = "" - for (var/ckey in memo_list) - var/data = {"

    [ckey] wrote on [memo_list[ckey]["date"]]:
    - [memo_list[ckey]["content"]]

    "} - - memo += data - - memo_hash = md5(memo) - else - memo = initial(memo) - memo_hash = "" - -/datum/server_greeting/proc/update_pins() - set background = 1 - - var/list/temp_list = discord_bot.retreive_pins() - - // A is a number in a string form - // temp_list[A] is a list of lists. - for (var/A in temp_list) - var/list/memos = temp_list[A] - var/flag = text2num(A) - - memo_list += new /datum/memo_datum(memos, flag) - -/* - * Helper to update the MoTD or memo contents. - * Args: - * - var/change string - * - var/new_value mixed - * Returns: - * - 1 upon success - * - 0 upon failure - */ -/datum/server_greeting/proc/update_value(var/change, var/new_value) - if (!change || !new_value) - return 0 - - switch (change) - if ("motd") - motd = new_value - - if ("memo_write") - if (config.use_discord_pins) - return 0 - - memo_list[new_value[1]] = list("date" = time2text(world.realtime, "DD-MMM-YYYY"), "content" = new_value[2]) - - if ("memo_delete") - if (config.use_discord_pins) - return 0 - - if (memo_list[new_value]) - memo_list -= new_value - else - return 0 - - else - return 0 - - var/savefile/F = new(MEMOFILE) - F["motd"] << motd - F["memo"] << memo_list - - update_data() - - return 1 - -/* - * Helper proc to determine whether or not we need to show the greeting window to a user. - * Args: - * - var/user client - * Returns: - * - int - */ -/datum/server_greeting/proc/find_outdated_info(var/client/user, var/force_eval = 0) - if (!user || !user.prefs) - return 0 - - if (!force_eval && !isnull(client_cache[user])) - return client_cache[user] - - var/outdated_info = 0 - - if (motd_hash && user.prefs.motd_hash != motd_hash) - outdated_info |= OUTDATED_MOTD - - if (user.holder && user.prefs.memo_hash != get_memo_hash(user)) - outdated_info |= OUTDATED_MEMO - - if (user.prefs.notifications.len) - outdated_info |= OUTDATED_NOTE - - client_cache[user] = outdated_info - - return outdated_info - -/* - * A proc used to open the server greeting window for a user. - * Args: - * - var/user client - * - var/outdated_info int - */ -/datum/server_greeting/proc/display_to_client(var/client/user) - if (!user) - return - - user.info_sent = 0 - - // Make sure the user has the welcome screen assets. - var/datum/asset/welcome = get_asset_datum(/datum/asset/simple/misc) - welcome.send(user) - - user << browse('html/templates/welcome_screen.html', "window=greeting;size=800x500") - -/* - * A proc used to close the server greeting window for a user. - * Args: - * - var/user client - * - var/reason text - */ -/datum/server_greeting/proc/close_window(var/client/user, var/reason) - if (!user) - return - - if (reason) - to_chat(user, SPAN_NOTICE(reason)) - - user << browse(null, "window=greeting") - -/* - * Sends data to the JS controllers used in the server greeting. - * Also updates the user's preferences, if any of the hashes were out of date. - * Args: - * - var/user client - * - var/outdated_info int - */ -/datum/server_greeting/proc/send_to_javascript(var/client/user) - if (!user) - return - - // This is fine now, because it uses cached information. - var/outdated_info = server_greeting.find_outdated_info(user) - - var/list/data = list("div" = "", "content" = "", "update" = 1, "changeHash" = null) - - if (outdated_info & OUTDATED_NOTE) - to_chat(user, output("#note-placeholder", "greeting.browser:RemoveElement")) - - data["div"] = "#note" - data["update"] = 1 - - for (var/datum/client_notification/a in user.prefs.notifications) - data["content"] = a.get_html() - to_chat(user, output(JS_SANITIZE(data), "greeting.browser:AddContent")) - - if (!user.holder) - to_chat(user, output("#memo-tab", "greeting.browser:RemoveElement")) - else - if (outdated_info & OUTDATED_MEMO) - data["update"] = 1 - data["changeHash"] = get_memo_hash(user) - else - data["update"] = 0 - data["changeHash"] = null - - data["div"] = "#memo" - data["content"] = get_memo_content(user) - to_chat(user, output(JS_SANITIZE(data), "greeting.browser:AddContent")) - - if (outdated_info & OUTDATED_MOTD) - data["update"] = 1 - data["changeHash"] = motd_hash - else - data["update"] = 0 - data["changeHash"] = null - - data["div"] = "#motd" - data["content"] = motd - to_chat(user, output(JS_SANITIZE(data), "greeting.browser:AddContent")) - - data["div"] = "#testmerges" - data["content"] = revdata.greeting_info - - if (revdata.test_merges.len) - data["update"] = 1 - else - data["update"] = 0 - data["changeHash"] = null - to_chat(user, output(JS_SANITIZE(data), "greeting.browser:AddContent")) - -/* - * Basically the Topic proc for the greeting datum. - */ -/datum/server_greeting/proc/handle_call(var/href_list, var/client/C) - if (!href_list || !href_list["command"] || !C) - return - - switch (href_list["command"]) - if ("request_data") - send_to_javascript(C) - -/* - * Gets the appropriate memo hash for the memo system in use. - * Args: - * - var/C client - * Returns: - * - string - */ -/datum/server_greeting/proc/get_memo_hash(var/client/C) - if (!C || !C.holder) - return "" - - if (!config.use_discord_pins) - return memo_hash - - var/joint_checksum = "" - for (var/A in memo_list) - var/datum/memo_datum/memo = A - if (C.holder.rights & memo.flag) - joint_checksum += memo.hash - - return md5(joint_checksum) - -/* - * Gets the appropriate memo content for the memo system in use. - * Args: - * - var/C client - * Returns: - * - string if old memo system is used (config.use_discord_pins = 0) - * - list of strings if new memo system is used - */ -/datum/server_greeting/proc/get_memo_content(var/client/C) - if (!C || !C.holder) - return "" - - if (!config.use_discord_pins) - return memo - - var/list/content = list() - for (var/A in memo_list) - var/datum/memo_datum/memo = A - if (C.holder.rights & memo.flag) - content += memo.contents - - return content - -/datum/memo_datum - var/contents - var/hash - var/flag - -/datum/memo_datum/New(var/list/input = list(), var/_flag) - flag = _flag - - // Yes. This is an unfortunately acceptable way of doing it. - // Why? Because you cannot use numbers as indexes in an assoc list without fucking DM. - var/static/list/flags_to_divs = list("[R_ADMIN]" = "danger", - "[R_MOD]" = "warning", - "[(R_MOD|R_ADMIN)]" = "warning", - "[R_CCIAA]" = "info", - "[R_DEV]" = "info") - - if (input.len) - contents = "
    " - for (var/i = 1, i <= input.len, i++) - contents += "[input[i]["author"]] wrote:
    [nl2br(input[i]["content"])]" - - if (i < input.len) - contents += "
    " - - contents += "
    " - else - contents = "" - - hash = md5(contents) - -#undef OUTDATED_NOTE -#undef OUTDATED_MEMO -#undef OUTDATED_MOTD - -#undef MEMOFILE - -#undef JS_SANITIZE diff --git a/code/datums/uplink/badassery.dm b/code/datums/uplink/badassery.dm index 286672bf358..5e1571bf562 100644 --- a/code/datums/uplink/badassery.dm +++ b/code/datums/uplink/badassery.dm @@ -76,4 +76,4 @@ var/obj/structure/largecrate/C = /obj/structure/largecrate icon = image(initial(C.icon), initial(C.icon_state)) - return "\icon[icon]" + return "[icon2html(icon, usr)]" diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm index fb9f597972d..eb7b5692cf0 100644 --- a/code/datums/uplink/uplink_items.dm +++ b/code/datums/uplink/uplink_items.dm @@ -140,7 +140,7 @@ var/datum/uplink/uplink /datum/uplink_item/item/log_icon() var/obj/I = path - return "\icon[I]" + return "[icon2html(I, usr)]" /******************************** * * @@ -154,7 +154,7 @@ var/datum/uplink/uplink if(!default_abstract_uplink_icon) default_abstract_uplink_icon = image('icons/obj/pda.dmi', "pda-syn") - return "\icon[default_abstract_uplink_icon]" + return "[icon2html(default_abstract_uplink_icon, usr)]" /**************** * Support procs * diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm index 35bb07cbc51..48757205946 100644 --- a/code/datums/wires/camera.dm +++ b/code/datums/wires/camera.dm @@ -64,7 +64,7 @@ var/const/CAMERA_WIRE_NOTHING2 = 32 C.light_disabled = !C.light_disabled if(CAMERA_WIRE_ALARM) - C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") + C.visible_message("[icon2html(C, viewers(get_turf(C)))] *beep*", "[icon2html(C, viewers(get_turf(C)))] *beep*") return /datum/wires/camera/proc/CanDeconstruct() diff --git a/code/datums/wires/ipc_tag_scanner.dm b/code/datums/wires/ipc_tag_scanner.dm index af70b6e8ead..75d7e007a6e 100644 --- a/code/datums/wires/ipc_tag_scanner.dm +++ b/code/datums/wires/ipc_tag_scanner.dm @@ -40,10 +40,10 @@ var/const/TAG_WIRE_HACK = 8 var/obj/item/ipc_tag_scanner/S = holder switch(index) if(TAG_WIRE_POWER) - S.visible_message(SPAN_WARNING("\icon[S] [capitalize_first_letters(S.name)] beeps, \"BOOWEEEP!\"")) + S.visible_message(SPAN_WARNING("[icon2html(S, viewers(get_turf(S)))] [capitalize_first_letters(S.name)] beeps, \"BOOWEEEP!\"")) if(TAG_WIRE_HACK) - S.visible_message(SPAN_WARNING("\icon[S] [capitalize_first_letters(S.name)] beeps, \"BEEYUUP!\"")) + S.visible_message(SPAN_WARNING("[icon2html(S, viewers(get_turf(S)))] [capitalize_first_letters(S.name)] beeps, \"BEEYUUP!\"")) /datum/wires/tag_scanner/CanUse(var/mob/living/L) var/obj/item/ipc_tag_scanner/S = holder diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm index 312e6dd7d9a..71b97357272 100644 --- a/code/datums/wires/mulebot.dm +++ b/code/datums/wires/mulebot.dm @@ -28,15 +28,15 @@ var/const/WIRE_BEACON_RX = 256 // beacon ping recv /datum/wires/mulebot/UpdatePulsed(var/index) switch(index) if(WIRE_POWER1, WIRE_POWER2) - holder.visible_message("\icon[holder] The charge light flickers.") + holder.visible_message("[icon2html(holder, viewers(get_turf(holder)))] The charge light flickers.") if(WIRE_AVOIDANCE) - holder.visible_message("\icon[holder] The external warning lights flash briefly.") + holder.visible_message("[icon2html(holder, viewers(get_turf(holder)))] The external warning lights flash briefly.") if(WIRE_LOADCHECK) - holder.visible_message("\icon[holder] The load platform clunks.") + holder.visible_message("[icon2html(holder, viewers(get_turf(holder)))] The load platform clunks.") if(WIRE_MOTOR1, WIRE_MOTOR2) - holder.visible_message("\icon[holder] The drive motor whines briefly.") + holder.visible_message("[icon2html(holder, viewers(get_turf(holder)))] The drive motor whines briefly.") else - holder.visible_message("\icon[holder] You hear a radio crackle.") + holder.visible_message("[icon2html(holder, viewers(get_turf(holder)))] You hear a radio crackle.") // HELPER PROCS diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm index 857af04db1f..2e085a544bd 100644 --- a/code/datums/wires/particle_accelerator.dm +++ b/code/datums/wires/particle_accelerator.dm @@ -31,7 +31,7 @@ var/const/PARTICLE_LIMIT_POWER_WIRE = 4 // Determines how strong the PA can be. C.add_strength() if(PARTICLE_LIMIT_POWER_WIRE) - C.visible_message("\icon[C][C] makes a large whirring noise.") + C.visible_message("[icon2html(C, viewers(get_turf(C)))][C] makes a large whirring noise.") /datum/wires/particle_acc/control_box/UpdateCut(var/index, var/mended) var/obj/machinery/particle_accelerator/control_box/C = holder diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 30495cd75d1..9e9ab91eaff 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -144,7 +144,7 @@ user.lastattacked = target target.lastattacker = user if(!no_attack_log) - user.attack_log += "\[[time_stamp()]\] Attacked [target.name] ([target.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damagetype)])" + user.attack_log += "\[[time_stamp()]\] Attacked [target.name] ([target.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damagetype)])" target.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damagetype)])" msg_admin_attack("[key_name(user, highlight_special = 1)] attacked [key_name(target, highlight_special = 1)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damagetype)]) (JMP)",ckey=key_name(user),ckey_target=key_name(target) ) ///////////////////////// diff --git a/code/defines/procs/announce.dm b/code/defines/procs/announce.dm index 81175a53783..4136aaa24cf 100644 --- a/code/defines/procs/announce.dm +++ b/code/defines/procs/announce.dm @@ -66,9 +66,9 @@ /datum/announcement/priority/command/MessageAndSound(var/message as text, var/message_title as text, var/message_sound) var/command_title - command_title += "

    [current_map.boss_name] Update

    " + command_title += "

    [current_map.boss_name] Update

    " if (message_title) - command_title += "

    [message_title]

    " + command_title += "

    [message_title]

    " var/command_body command_body += "
    [message]
    " @@ -77,9 +77,9 @@ /datum/announcement/priority/security/MessageAndSound(var/message as text, var/message_title as text, var/message_sound) to_world("[message_title]") - to_world("[message]") + to_world("[message]") if(message_sound) - to_world(message_sound) + sound_to(world, message_sound) /datum/announcement/proc/NewsCast(message as text, message_title as text) if(!newscast) diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm index 8b73541a59c..77c7b333473 100644 --- a/code/game/antagonist/antagonist_print.dm +++ b/code/game/antagonist/antagonist_print.dm @@ -21,12 +21,12 @@ text += "Success!" feedback_add_details(feedback_tag,"[O.type]|SUCCESS") else - text += "Fail." + text += "Fail." feedback_add_details(feedback_tag,"[O.type]|FAIL") failed = 1 num++ if(failed) - text += "
    The [role_text] has failed." + text += "
    The [role_text] has failed." else text += "
    The [role_text] was successful!" @@ -46,7 +46,7 @@ if(O.check_completion()) text += "Success!" else - text += "Fail." + text += "Fail." return text /datum/antagonist/proc/print_special_role_report(var/datum/mind/ply) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index f559a9d78fc..64f7ac6fe7b 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -149,7 +149,7 @@ else f_name += "oil-stained [name][infix]." - to_chat(user, "\icon[src] That's [f_name] [suffix]") + to_chat(user, "[icon2html(src, user)] That's [f_name] [suffix]") to_chat(user, desc) if(ishuman(user)) diff --git a/code/game/gamemodes/cult/items/tome.dm b/code/game/gamemodes/cult/items/tome.dm index b87328ef519..400f0480c62 100644 --- a/code/game/gamemodes/cult/items/tome.dm +++ b/code/game/gamemodes/cult/items/tome.dm @@ -33,7 +33,7 @@ /obj/item/book/tome/proc/attack_admins(var/mob/living/M, var/mob/living/user) M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on them by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used [name] on [M.name] ([M.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used [name] on [M.name] ([M.ckey])") msg_admin_attack("[key_name_admin(user)] used [name] on [M.name] ([M.ckey]) (JMP)",ckey=key_name(user),ckey_target=key_name(M)) diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm index 008dbbfc497..a30112b85a2 100644 --- a/code/game/gamemodes/cult/narsie.dm +++ b/code/game/gamemodes/cult/narsie.dm @@ -44,7 +44,7 @@ var/global/list/narsie_list = list() ..() if(announce) to_world("[uppertext(name)] HAS RISEN") - to_world(sound('sound/effects/narsie.ogg')) + sound_to(world, ('sound/effects/narsie.ogg')) narsie_spawn_animation() diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index 02e29f0c5de..2d229097c8e 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -40,7 +40,7 @@ var/global/universe_has_ended = 0 to_world("You are blinded by a brilliant flash of energy.") - to_world(sound('sound/effects/cascade.ogg')) + sound_to(world, ('sound/effects/cascade.ogg')) for(var/mob/M in player_list) flick("e_flash", M.flash) diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm index 435e8ad2982..f733b6b0b1d 100644 --- a/code/game/gamemodes/events/holidays/Holidays.dm +++ b/code/game/gamemodes/events/holidays/Holidays.dm @@ -144,7 +144,7 @@ var/global/Holiday = null //Run at the start of a round /proc/Holiday_Game_Start() if(Holiday) - to_world("and...") + to_world("and...") to_world("

    Happy [Holiday] Everybody!

    ") switch(Holiday) //special holidays if("Easter") diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 9c2df9aadd3..8f6aa470791 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -592,7 +592,7 @@ var/global/list/additional_antag_types = list() //New message handling post_comm_message("Cent. Com. Status Summary", intercepttext) - to_world(sound('sound/AI/commandreport.ogg')) + sound_to(world, ('sound/AI/commandreport.ogg')) /datum/game_mode/proc/get_players_for_role(var/role, var/antag_id) var/list/players = list() @@ -714,10 +714,10 @@ proc/get_logout_report() continue //Dead mob, ghost abandoned else if(D.can_reenter_corpse) - msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Adminghosted)\n" + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Adminghosted)\n" continue //Lolwhat else - msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n" + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n" continue //Ghosted while alive msg += "" // close the span from right at the top @@ -752,7 +752,7 @@ proc/get_nt_opposed() //Announces objectives/generic antag text. /proc/show_generic_antag_text(var/datum/mind/player) if(player.current) - to_chat(player.current, "You are an antagonist! Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists.") + to_chat(player.current, "You are an antagonist! Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists.") /proc/show_objectives(var/datum/mind/player) diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm index bb0f0e91919..1541f2780b4 100644 --- a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm @@ -173,7 +173,7 @@ // return log_ability_use(user, "advanced encryption hack (SUCCESS - title: [reporttitle])") to_world("New [current_map.company_name] Update available at all communication consoles.") - to_world(sound('sound/AI/commandreport.ogg')) + sound_to(world, ('sound/AI/commandreport.ogg')) post_comm_message(reporttitle, reportbody) /datum/game_mode/malfunction/verb/elite_encryption_hack() diff --git a/code/game/gamemodes/vampire/vampire_datum.dm b/code/game/gamemodes/vampire/vampire_datum.dm index 9e9845632bb..e9b47d1cbb5 100644 --- a/code/game/gamemodes/vampire/vampire_datum.dm +++ b/code/game/gamemodes/vampire/vampire_datum.dm @@ -30,7 +30,7 @@ to_chat(vampire.current, "You have unlocked a new power: [power.name].") to_chat(vampire.current, "[power.desc]") if (power.helptext) - to_chat(vampire.current, "[power.helptext]") + to_chat(vampire.current, "[power.helptext]") // Proc to safely remove blood, without resulting in negative amounts of blood. /datum/vampire/proc/use_blood(var/blood_to_use) diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index b1ddcfc275c..c216dbb53de 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -799,7 +799,7 @@ probability = 80 if (prob(probability)) - to_chat(T, "[pick(emotes)]") + to_chat(T, "[pick(emotes)]") vampire.use_blood(5) diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 8251f574976..7ac5b8749d3 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -128,7 +128,7 @@ if(UNCONSCIOUS) data["stat"] = "Unconscious" if(DEAD) - data["stat"] = "Dead" + data["stat"] = "Dead" data["health"] = occupant.health if(ishuman(occupant)) var/mob/living/carbon/human/H = occupant diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 93781314ac8..bd50d6b2985 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -618,11 +618,11 @@ /obj/machinery/body_scanconsole/proc/format_occupant_data(var/list/occ) - var/dat = "Scan performed at [occ["stationtime"]]
    " - dat += "Occupant Statistics:
    " + var/dat = "Scan performed at [occ["stationtime"]]
    " + dat += "Occupant Statistics:
    " dat += text("Brain Activity: []
    ", occ["brain_activity"]) if (occ["virus_present"]) - dat += "Viral pathogen detected in blood stream.
    " + dat += "Viral pathogen detected in blood stream.
    " dat += text("Blood Pressure: []
    ", occ["blood_pressure"]) dat += text("Blood Oxygenation: []%
    ", occ["blood_oxygenation"]) dat += text("Physical Trauma: []
    ", occ["bruteloss"]) @@ -730,7 +730,7 @@ if(i.get_scarring_level() > 0.01) necrotic += ", [i.get_scarring_results()]" if(i.status & ORGAN_DEAD) - necrotic = ", necrotic and decaying" + necrotic = ", necrotic and decaying" dat += "" dat += "[i.name]N/A[get_internal_damage(i)][infection], [mech][necrotic]" @@ -740,10 +740,10 @@ var/list/species_organs = occ["species_organs"] for(var/organ_name in species_organs) if(!locate(species_organs[organ_name]) in occ["internal_organs"]) - dat += text("No [organ_name] detected.
    ") + dat += text("No [organ_name] detected.
    ") if(occ["sdisabilities"] & BLIND) - dat += text("Cataracts detected.
    ") + dat += text("Cataracts detected.
    ") if(occ["sdisabilities"] & NEARSIGHTED) - dat += text("Retinal misalignment detected.
    ") + dat += text("Retinal misalignment detected.
    ") return dat diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 7ee5ae75ea1..cb1c48ef51b 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -262,7 +262,7 @@ update_flag if (holding) release_log += "Valve was closed by [key_name(admin)] (aghost), stopping the transfer into the [holding]
    " else - release_log += "Valve was closed by [key_name(admin)] (aghost), stopping the transfer into the air
    " + release_log += "Valve was closed by [key_name(admin)] (aghost), stopping the transfer into the air
    " else if (alert(admin, "The release valve is currently closed. Do you want to open it?", "Open the valve?", "Yes", "No") == "No") return @@ -270,7 +270,7 @@ update_flag if (holding) release_log += "Valve was opened by [key_name(admin)] (aghost), starting the transfer into the [holding]
    " else - release_log += "Valve was opened by [key_name(admin)] (aghost), starting the transfer into the air
    " + release_log += "Valve was opened by [key_name(admin)] (aghost), starting the transfer into the air
    " log_open(admin) valve_open = !valve_open @@ -354,12 +354,12 @@ update_flag if (holding) release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
    " else - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
    " + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
    " else if (holding) release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
    " else - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
    " + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
    " log_open() valve_open = !valve_open diff --git a/code/game/machinery/computer/arcade_orion.dm b/code/game/machinery/computer/arcade_orion.dm index 7063aef15dc..698510b76bb 100644 --- a/code/game/machinery/computer/arcade_orion.dm +++ b/code/game/machinery/computer/arcade_orion.dm @@ -455,7 +455,7 @@ to_chat(usr, "You're never going to make it to Orion...") var/mob/living/M = usr M.visible_message("\The [M] starts rapidly deteriorating.") - to_chat(M, browse (null,"window=arcade")) + show_browser(M, null, "window=arcade") for(var/i=0;i<10;i++) sleep(10) M.Stun(5) diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index 7cc34a9cebe..27da1e1acce 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -64,7 +64,7 @@ var/obj/item/paper/monitorkey/MK = new/obj/item/paper/monitorkey MK.forceMove(src.loc) // Will help make emagging the console not so easy to get away with. - MK.info += "

    £%@%(*$%&(£&?*(%&£/{}" + MK.info += "

    £%@%(*$%&(£&?*(%&£/{}" addtimer(CALLBACK(src, .proc/UnmagConsole), 100 * length(linkedServer.decryptkey)) message = rebootmsg update_icon() @@ -100,10 +100,10 @@ if(auth) dat += "

    \[Authenticated\] /" - dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " + dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]" else - dat += "

    \[Unauthenticated\] /" - dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " + dat += "

    \[Unauthenticated\] /" + dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " if(hacking || emag) screen = 2 @@ -130,10 +130,10 @@ dat += "
    [++i]. Modify Spam Filter
    " else for(var/n = ++i; n <= optioncount; n++) - dat += "
    [n]. ---------------
    " + dat += "
    [n]. ---------------
    " if((istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) && (user.mind.special_role && user.mind.original == user)) //Malf/Traitor AIs can bruteforce into the system to gain the Key. - dat += "
    *&@#. Bruteforce Key
    " + dat += "
    *&@#. Bruteforce Key
    " else dat += "
    " diff --git a/code/game/machinery/computer/slotmachine.dm b/code/game/machinery/computer/slotmachine.dm index 46cc6e576ff..80f987d14dd 100644 --- a/code/game/machinery/computer/slotmachine.dm +++ b/code/game/machinery/computer/slotmachine.dm @@ -4,7 +4,7 @@ #define JACKPOT 10000 #define SPIN_TIME 65 #define REEL_DEACTIVATE_DELAY 7 -#define SEVEN "7" +#define SEVEN "7" /obj/machinery/computer/slot_machine name = "slot machine" @@ -24,7 +24,7 @@ var/jackpots = 0 var/list/coinvalues = list() var/list/reels = list(list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0) - var/list/symbols = list(SEVEN = 1, "&" = 2, "@" = 2, "$" = 2, "?" = 2, "#" = 2, "!" = 2, "%" = 2) //if people are winning too much, multiply every number in this list by 2 and see if they are still winning too much. + var/list/symbols = list(SEVEN = 1, "&" = 2, "@" = 2, "$" = 2, "?" = 2, "#" = 2, "!" = 2, "%" = 2) //if people are winning too much, multiply every number in this list by 2 and see if they are still winning too much. light_color = LIGHT_COLOR_BROWN diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index a2037962801..23e8c05a5c7 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -608,7 +608,7 @@ About the new airlock wires panel: else if(duration) //electrify door for the given duration seconds if(usr) LAZYADD(shockedby, "\[[time_stamp()]\] - [usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") + usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") else LAZYADD(shockedby, "\[[time_stamp()]\] - EMP)") message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]." @@ -1004,7 +1004,7 @@ About the new airlock wires panel: else if(!activate) if(issilicon(usr) && !player_is_antag(usr.mind)) to_chat(usr, SPAN_NOTICE("The door bolts will raise in five seconds.")) - src.visible_message("\icon[src.icon] [src] announces, \"Bolts set to raise in FIVE SECONDS.\"") + src.visible_message("[icon2html(src.icon, viewers(get_turf(src)))] [src] announces, \"Bolts set to raise in FIVE SECONDS.\"") addtimer(CALLBACK(src, .proc/unlock), 50) else if(unlock()) to_chat(usr, SPAN_NOTICE("The door bolts have been raised.")) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index ed1c1bd2842..f708acf0a5d 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -417,9 +417,7 @@ /obj/machinery/door/proc/set_broken() stat |= BROKEN - for (var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("[src.name] breaks!" ) + visible_message(SPAN_WARNING("[src] breaks!")) update_icon() return diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index a81757d6c7c..bb5e8da92a3 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -117,7 +117,7 @@ return if(T.get_blood_volume() < 90 && !blood_message_sent) - visible_message("\icon[src] \The [src] flashes a warning light!") + visible_message("[icon2html(src, viewers(get_turf(src)))] \The [src] flashes a warning light!") playsound(src, 'sound/machines/buzz-two.ogg', 50) blood_message_sent = TRUE diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 3246c42faf1..368bf2c33c2 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -286,7 +286,7 @@ Class Procs: /obj/machinery/proc/state(var/msg) for(var/mob/O in hearers(src, null)) - O.show_message("\icon[src] [msg]", 2) + O.show_message("[icon2html(src, O)] [msg]", 2) /obj/machinery/proc/ping(text=null) if (!text) diff --git a/code/game/machinery/mecha_fabricator.dm b/code/game/machinery/mecha_fabricator.dm index 9cb5eb165be..f5bf0d56163 100644 --- a/code/game/machinery/mecha_fabricator.dm +++ b/code/game/machinery/mecha_fabricator.dm @@ -226,7 +226,7 @@ if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis) user.visible_message(SPAN_WARNING("[user] feeds the [target]'s hair into the [src] and flicks it on!"), SPAN_ALERT("You turn the [src] on!")) do_hair_pull(target) - user.attack_log += text("\[[time_stamp()]\] Has fed [target.name]'s ([target.ckey]) hair into a [src].") + user.attack_log += text("\[[time_stamp()]\] Has fed [target.name]'s ([target.ckey]) hair into a [src].") target.attack_log += text("\[[time_stamp()]\] Has had their hair fed into [src] by [user.name] ([user.ckey])") msg_admin_attack("[key_name_admin(user)] fed [key_name_admin(target)] in a [src]. (JMP)",ckey=key_name(user),ckey_target=key_name(target)) else @@ -245,20 +245,20 @@ switch(emagged) if(0) emagged = 0.5 - visible_message("\icon[src] [src] beeps: \"DB error \[Code 0x00F1\]\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps: \"DB error \[Code 0x00F1\]\"") sleep(10) - visible_message("\icon[src] [src] beeps: \"Attempting auto-repair\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps: \"Attempting auto-repair\"") sleep(15) - visible_message("\icon[src] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"") sleep(30) - visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your [current_map.company_name] system operator for future assistance.\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps: \"User DB truncated. Please contact your [current_map.company_name] system operator for future assistance.\"") req_access = null emagged = 1 return 1 if(0.5) - visible_message("\icon[src] [src] beeps: \"DB not responding \[Code 0x0003\]...\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps: \"DB not responding \[Code 0x0003\]...\"") if(1) - visible_message("\icon[src] [src] beeps: \"No records in User DB\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps: \"No records in User DB\"") /obj/machinery/mecha_part_fabricator/proc/update_busy() if(queue.len) diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index 4856af19fe3..27e33ef836c 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -166,7 +166,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co switch(screen) if(0) dat += "Welcome to Newscasting Unit #[src.unit_no].
    Interface & News networks Operational." - dat += "
    Property of Nanotransen Inc" + dat += "
    Property of Nanotransen Inc" if(SSnews.wanted_issue) dat+= "
    Read Wanted Issue" dat+= "

    Create Feed Channel" @@ -184,7 +184,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="
    [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" dat+="
    Censor Feed Stories" dat+="
    Mark Feed Channel with [current_map.company_name] D-Notice" - dat+="

    The newscaster recognises you as: [src.scanned_user]" + dat+="

    The newscaster recognises you as: [src.scanned_user]" if(1) dat+= "Station Feed Channels
    " if( isemptylist(SSnews.network_channels) ) @@ -193,21 +193,21 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) if(FC.is_admin_channel) - dat+="[FC.channel_name]
    " + dat+="[FC.channel_name]
    " else - dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
    " + dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
    " dat+="

    Refresh" dat+="
    Back" if(2) dat+="Creating new Feed Channel..." dat+="
    Channel Name: [src.channel_name]
    " - dat+="Channel Author: [src.scanned_user]
    " + dat+="Channel Author: [src.scanned_user]
    " dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

    " dat+="
    Submit

    Cancel
    " if(3) dat+="Creating new Feed Message..." dat+="
    Receiving Channel: [src.channel_name]
    " //MARK - dat+="Message Author: [src.scanned_user]
    " + dat+="Message Author: [src.scanned_user]
    " dat+="Message Body: [src.msg]
    " dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
    " dat+="Scan Paper: [((src.paper_data || src.paper_name) ? "Paper Scanned" : "No Paper")]
    " @@ -219,17 +219,17 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="Feed Channel [src.channel_name] created successfully.

    " dat+="
    Return
    " if(6) - dat+="ERROR: Could not submit Feed story to Network.

    " + dat+="ERROR: Could not submit Feed story to Network.

    " if(src.channel_name=="") - dat+="ļæ½Invalid receiving channel name.
    " + dat+="ļæ½Invalid receiving channel name.
    " if(src.scanned_user=="Unknown") - dat+="ļæ½Channel author unverified.
    " + dat+="ļæ½Channel author unverified.
    " if(src.msg == "" || src.msg == "\[REDACTED\]") - dat+="ļæ½Invalid message body.
    " + dat+="ļæ½Invalid message body.
    " dat+="
    Return
    " if(7) - dat+="ERROR: Could not submit Feed Channel to Network.

    " + dat+="ERROR: Could not submit Feed Channel to Network.

    " var/list/existing_authors = list() for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) @@ -238,9 +238,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co else existing_authors += FC.author if(src.scanned_user in existing_authors) - dat+="ļæ½There already exists a Feed channel under your name.
    " + dat+="ļæ½There already exists a Feed channel under your name.
    " if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") - dat+="ļæ½Invalid channel name.
    " + dat+="ļæ½Invalid channel name.BR>" var/check = 0 for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) @@ -248,9 +248,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co check = 1 break if(check) - dat+="ļæ½Channel name already in use.
    " + dat+="ļæ½Channel name already in use.
    " if(src.scanned_user=="Unknown") - dat+="ļæ½Channel author unverified.
    " + dat+="ļæ½Channel author unverified.
    " dat+="
    Return
    " if(8) var/total_num=length(SSnews.network_channels) @@ -267,10 +267,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="

    Print Paper" dat+="
    Cancel" if(9) - dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\]
    " + dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\]
    " if(src.viewing_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
    " - dat+="No further feed story additions are allowed while the D-Notice is in effect.

    " + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
    " + dat+="No further feed story additions are allowed while the D-Notice is in effect.

    " else if( isemptylist(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
    " @@ -278,68 +278,68 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co var/i = 0 for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) i++ - dat+="
    [MESSAGE.body] \[Likes: [MESSAGE.likes] Dislikes: [MESSAGE.dislikes]\]
    " + dat+="
    [MESSAGE.body] \[Likes: [MESSAGE.likes] Dislikes: [MESSAGE.dislikes]\]
    " if(MESSAGE.img) - to_chat(usr, browse_rsc(MESSAGE.img, "tmp_photo[i].png")) + send_rsc(usr, MESSAGE.img, "tmp_photo[i].png") dat+="
    " if(MESSAGE.caption) - dat+="[MESSAGE.caption]
    " + dat+="[MESSAGE.caption]
    " dat+="
    " - dat+="View Comments Add Comment Like Story Dislike Story
    " - dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]

    " + dat+="View Comments Add Comment Like Story Dislike Story
    " + dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]

    " dat+="

    Refresh" dat+="
    Back" if(10) dat+="[current_map.company_name] Feed Censorship Tool
    " dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
    " - dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
    " + dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it." dat+="
    Select Feed channel to get Stories from:
    " if(isemptylist(SSnews.network_channels)) dat+="No feed channels found active...
    " else for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) - dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
    " + dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
    " dat+="
    Cancel" if(11) dat+="[current_map.company_name] D-Notice Handler
    " dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" - dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
    " + dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
    " if(isemptylist(SSnews.network_channels)) dat+="No feed channels found active...
    " else for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) - dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
    " + dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
    " dat+="
    Back" if(12) - dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
    " - dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
    " + dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
    " + dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
    " if( isemptylist(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
    " else for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) - dat+="-[MESSAGE.body]
    \[[MESSAGE.message_type] by [MESSAGE.author]\]
    " - dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
    " + dat+="-[MESSAGE.body]
    \[[MESSAGE.message_type] by [MESSAGE.author]\]
    " + dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
    " dat+="
    Back" if(13) - dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
    " + dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
    " dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
    " if(src.viewing_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
    " + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
    " dat+="No further feed story additions are allowed while the D-Notice is in effect.

    " else if( isemptylist(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
    " else for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) - dat+="
    [MESSAGE.body] \[Likes: [MESSAGE.likes] Dislikes: [MESSAGE.dislikes]\]
    " - dat+="View Comments Add Comment Like Story Dislike Story
    " - dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]

    " + dat+="
    [MESSAGE.body] \[Likes: [MESSAGE.likes] Dislikes: [MESSAGE.dislikes]\]
    " + dat+="View Comments Add Comment Like Story Dislike Story
    " + dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]

    " dat+="
    Back" if(14) @@ -351,54 +351,54 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co end_param = 2 if(wanted_already) - dat+="
    A wanted issue is already in Feed Circulation. You can edit or cancel it below.
    " + dat+="
    A wanted issue is already in Feed Circulation. You can edit or cancel it below.
    " dat+="
    " dat+="Criminal Name: [src.channel_name]
    " dat+="Description: [src.msg]
    " dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
    " dat+="Scan Paper: [((src.paper_data || src.paper_name) ? "Paper Scanned" : "No Paper")]
    " if(wanted_already) - dat+="Wanted Issue created by: [SSnews.wanted_issue.backup_author]
    " + dat+="Wanted Issue created by: [SSnews.wanted_issue.backup_author]
    " else - dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
    " + dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
    " dat+="
    [(wanted_already) ? ("Edit Issue") : ("Submit")]" if(wanted_already) dat+="
    Take down Issue" dat+="
    Cancel" if(15) - dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

    " + dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

    " dat+="
    Return
    " if(16) - dat+="ERROR: Wanted Issue rejected by Network.

    " + dat+="ERROR: Wanted Issue rejected by Network.

    " if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") - dat+="ļæ½Invalid name for person wanted.
    " + dat+="ļæ½Invalid name for person wanted.
    " if(src.scanned_user=="Unknown") - dat+="ļæ½Issue author unverified.
    " + dat+="ļæ½Issue author unverified.
    " if(src.msg == "" || src.msg == "\[REDACTED\]") - dat+="ļæ½Invalid description.
    " + dat+="ļæ½Invalid description.
    " dat+="
    Return
    " if(17) dat+="Wanted Issue successfully deleted from Circulation
    " dat+="
    Return
    " if(18) - dat+="-- STATIONWIDE WANTED ISSUE --
    \[Submitted by: [SSnews.wanted_issue.backup_author]\]
    " + dat+="-- STATIONWIDE WANTED ISSUE --
    \[Submitted by: [SSnews.wanted_issue.backup_author]\]
    " dat+="Criminal: [SSnews.wanted_issue.author]
    " dat+="Description: [SSnews.wanted_issue.body]
    " dat+="Photo:: " if(SSnews.wanted_issue.img) - to_chat(usr, browse_rsc(SSnews.wanted_issue.img, "tmp_photow.png")) + send_rsc(usr, SSnews.wanted_issue.img, "tmp_photow.png") dat+="
    " else dat+="None" dat+="

    Back
    " if(19) - dat+="Wanted issue for [src.channel_name] successfully edited.

    " + dat+="Wanted issue for [src.channel_name] successfully edited.

    " dat+="
    Return
    " if(20) - dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

    " + dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

    " dat+="Return" if(21) - dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

    " + dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

    " dat+="Return" if(22) //comments! dat+="Comments:
    " @@ -830,11 +830,11 @@ obj/item/newspaper/attack_self(mob/user as mob) src.pages = 0 switch(screen) if(0) //Cover - dat+="
    The Griffon
    " - dat+="
    [current_map.company_name]-standard newspaper, for use on [current_map.company_name]ļæ½ Space Facilities

    " + dat+="
    The Griffon
    " + dat+="
    [current_map.company_name]-standard newspaper, for use on [current_map.company_name]ļæ½ Space Facilities

    " if(isemptylist(src.news_content)) if(src.important_message) - dat+="Contents:
    " + dat+="Contents:
    " else dat+="Other than the title, the rest of the newspaper is unprinted..." else @@ -842,11 +842,11 @@ obj/item/newspaper/attack_self(mob/user as mob) for(var/datum/feed_channel/NP in src.news_content) src.pages++ if(src.important_message) - dat+="**Important Security Announcement** \[page [src.pages+2]\]
    " + dat+="**Important Security Announcement** \[page [src.pages+2]\]
    " var/temp_page=0 for(var/datum/feed_channel/NP in src.news_content) temp_page++ - dat+="[NP.channel_name] \[page [temp_page+1]\]
    " + dat+="[NP.channel_name] \[page [temp_page+1]\]
    " dat+="" if(scribble_page==curr_page) dat+="
    There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" @@ -855,9 +855,9 @@ obj/item/newspaper/attack_self(mob/user as mob) for(var/datum/feed_channel/NP in src.news_content) src.pages++ //Let's get it right again. var/datum/feed_channel/C = src.news_content[src.curr_page] - dat+="[C.channel_name] \[created by: [C.author]\]

    " + dat+="[C.channel_name] \[created by: [C.author]\]

    " if(C.censored) - dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." + dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." else if(isemptylist(C.messages)) dat+="No Feed stories stem from this channel..." @@ -868,9 +868,9 @@ obj/item/newspaper/attack_self(mob/user as mob) i++ dat+="-[MESSAGE.body]
    " if(MESSAGE.img) - to_chat(user, browse_rsc(MESSAGE.img, "tmp_photo[i].png")) + send_rsc(usr, MESSAGE.img, "tmp_photo[i].png") dat+="
    " - dat+="\[[MESSAGE.message_type] by [MESSAGE.author]\]

    " + dat+="\[[MESSAGE.message_type] by [MESSAGE.author]\]

    " dat+="" if(scribble_page==curr_page) dat+="
    There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" @@ -879,12 +879,12 @@ obj/item/newspaper/attack_self(mob/user as mob) for(var/datum/feed_channel/NP in src.news_content) src.pages++ if(src.important_message!=null) - dat+="
    Wanted Issue:


    " - dat+="Criminal name: [important_message.author]
    " + dat+="
    Wanted Issue:


    " + dat+="Criminal name: [important_message.author]
    " dat+="Description: [important_message.body]
    " dat+="Photo:: " if(important_message.img) - to_chat(user, browse_rsc(important_message.img, "tmp_photow.png")) + send_rsc(user, important_message.img, "tmp_photow.png") dat+="
    " else dat+="None" @@ -939,7 +939,7 @@ obj/item/newspaper/Topic(href, href_list) obj/item/newspaper/attackby(obj/item/W as obj, mob/user as mob) if(W.ispen()) if(src.scribble_page == src.curr_page) - to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?") + to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?") else var/s = sanitize(input(user, "Write something", "Newspaper", "")) s = sanitize(s) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 8271ce4d196..1880f1f4919 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -254,7 +254,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() screen = RCS_SENTPASS message_log += "Message sent to [recipient]
    [message]" else - audible_message(text("\icon[src] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4) + audible_message(text("[icon2html(src, viewers(get_turf(src)))] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4) //Handle screen switching if(href_list["setScreen"]) @@ -386,7 +386,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() if(inoperable(MAINT)) return if(screen == RCS_MESSAUTH) var/obj/item/stamp/T = O - msgStamped = text("Stamped with the [T.name]") + msgStamped = text("Stamped with the [T.name]") updateUsrDialog() else if (istype(O, /obj/item/paper_bundle)) if(lid) //More of that restocking business @@ -395,7 +395,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() user.drop_from_inventory(C,get_turf(src)) qdel(C) for (var/mob/U in hearers(4, src.loc)) - U.show_message(text("\icon[src] *The Requests Console beeps: 'Paper added.'")) + U.show_message(text("[icon2html(src, viewers(get_turf(src)))] *The Requests Console beeps: 'Paper added.'")) else to_chat(user, "I should open the lid to add more paper, or try faxing one paper at a time.") else if (istype(O, /obj/item/paper)) @@ -405,7 +405,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() qdel(C) paperstock++ for (var/mob/U in hearers(4, src.loc)) - U.show_message(text("\icon[src] *The Requests Console beeps: 'Paper added.'")) + U.show_message(text("[icon2html(src, viewers(get_turf(src)))] *The Requests Console beeps: 'Paper added.'")) else if(screen == 0) //Faxing them papers var/pass = 0 var/sendto = input("Select department.", "Send Fax", null, null) in allConsoles @@ -453,12 +453,12 @@ var/list/obj/machinery/requests_console/allConsoles = list() P.set_content_unsafe(pname, info) Console.print(P, 0, 'sound/machines/twobeep.ogg') for (var/mob/player in hearers(4, Console.loc)) - player.show_message(text("\icon[Console] *The Requests Console beeps: 'Fax received'")) + player.show_message(text("[icon2html(Console, viewers(get_turf(Console)))] *The Requests Console beeps: 'Fax received'")) Console.paperstock-- if(sent == 1) - user.show_message(text("\icon[src] *The Requests Console beeps: 'Message Sent.'")) + user.show_message(text("[icon2html(src, viewers(get_turf(src)))] *The Requests Console beeps: 'Message Sent.'")) else - user.show_message(text("\icon[src] *The Requests Console beeps: 'NOTICE: No server detected!'")) + user.show_message(text("[icon2html(src, viewers(get_turf(src)))] *The Requests Console beeps: 'NOTICE: No server detected!'")) return diff --git a/code/game/machinery/ringer.dm b/code/game/machinery/ringer.dm index a7fc6e084b1..5437122b70e 100644 --- a/code/game/machinery/ringer.dm +++ b/code/game/machinery/ringer.dm @@ -112,7 +112,7 @@ continue var/message = "Notification from \the [department]!" - pda.new_info(pda.message_silent, pda.ttone, "\icon[pda] [message]") + pda.new_info(pda.message_silent, pda.ttone, "[icon2html(pda, viewers(get_turf(pda)))] [message]") addtimer(CALLBACK(src, .proc/unping), 45 SECONDS) diff --git a/code/game/machinery/suit_cycler.dm b/code/game/machinery/suit_cycler.dm index 5a1bd3e3354..7de8c91835f 100644 --- a/code/game/machinery/suit_cycler.dm +++ b/code/game/machinery/suit_cycler.dm @@ -338,10 +338,10 @@ var/dat = "" if(src.active) - dat += "The [model_text ? "[model_text] " : ""]suit cycler is currently in use. Please wait..." + dat += "The [model_text ? "[model_text] " : ""]suit cycler is currently in use. Please wait..." else if(locked) - dat += "The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator." + dat += "The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator." if(src.allowed(usr)) dat += "
    \[unlock unit\]" else @@ -510,7 +510,7 @@ occupant.apply_effect(radiation_level * 10, IRRADIATE) /obj/machinery/suit_cycler/proc/finished_job() - visible_message("\icon[src] \The [src] pings loudly.") + visible_message("[icon2html(src, viewers(get_turf(src)))] \The [src] pings loudly.") playsound(loc, 'sound/machines/ping.ogg', 50, FALSE) active = FALSE update_icon() diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index fed420bf68c..c2b2e2bd07a 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -114,8 +114,8 @@ dat+= "" dat+= "Maintenance panel controls
    " dat+= "The panel is ridden with controls, button and meters, labeled in strange signs and symbols that
    you cannot understand. Probably the manufactoring world's language.
    Among other things, a few controls catch your eye.

    " - dat+= text("A small dial with a \"Ć«\" symbol embroidded on it. It's pointing towards a gauge that reads [].
    Turn towards []
    ",(src.issuperUV ? "15nm" : "185nm"),src,(src.issuperUV ? "185nm" : "15nm") ) - dat+= text("A thick old-style button, with 2 grimy LED lights next to it. The [] LED is on.
    Press button",(src.safetieson? "GREEN" : "RED"),src) + dat+= text("A small dial with a \"Ć«\" symbol embroidded on it. It's pointing towards a gauge that reads [].
    Turn towards []
    ",(src.issuperUV ? "15nm" : "185nm"),src,(src.issuperUV ? "185nm" : "15nm") ) + dat+= text("A thick old-style button, with 2 grimy LED lights next to it. The [] LED is on.
    Press button",(src.safetieson? "GREEN" : "RED"),src) dat+= text("

    Close panel", user) //user << browse(dat, "window=ssu_m_panel;size=400x500") //onclose(user, "ssu_m_panel") @@ -129,7 +129,7 @@ else if(!src.isbroken) dat+= "" - dat+= "U-Stor-It Suit Storage Unit, model DS1900
    " + dat+= "U-Stor-It Suit Storage Unit, model DS1900
    " dat+= "Welcome to the Unit control panel.

    " dat+= text("Helmet storage compartment: []
    ",(src.HELMET ? HELMET.name : "
    No helmet detected.") ) if(HELMET && src.isopen) @@ -227,7 +227,7 @@ if(!protected) playsound(src.loc, /decl/sound_category/spark_sound, 75, 1, -1) - to_chat(user, "You try to touch the controls but you get zapped. There must be a short circuit somewhere.") + to_chat(user, "You try to touch the controls but you get zapped. There must be a short circuit somewhere.") return*/ else //welp, the guy is protected, we can continue if(src.issuperUV) @@ -253,7 +253,7 @@ if(!protected) playsound(src.loc, /decl/sound_category/spark_sound, 75, 1, -1) - to_chat(user, "You try to touch the controls but you get zapped. There must be a short circuit somewhere.") + to_chat(user, "You try to touch the controls but you get zapped. There must be a short circuit somewhere.") return*/ else to_chat(user, "You push the button. The coloured LED next to it changes.") @@ -305,7 +305,7 @@ /obj/machinery/suit_storage_unit/proc/toggle_open(mob/user as mob) if(src.islocked || src.isUV) - to_chat(user, "Unable to open unit.") + to_chat(user, "Unable to open unit.") return if(src.OCCUPANT) src.eject_occupant(user) @@ -316,7 +316,7 @@ /obj/machinery/suit_storage_unit/proc/toggle_lock(mob/user as mob) if(src.OCCUPANT && src.safetieson) - to_chat(user, "The Unit's safety protocols disallow locking when a biological form is detected inside its compartments.") + to_chat(user, "The Unit's safety protocols disallow locking when a biological form is detected inside its compartments.") return if(src.isopen) return @@ -328,10 +328,10 @@ if(src.isUV || src.isopen) //I'm bored of all these sanity checks return if(src.OCCUPANT && src.safetieson) - to_chat(user, "WARNING: Biological entity detected in the confines of the Unit's storage. Cannot initiate cycle.") + to_chat(user, "WARNING: Biological entity detected in the confines of the Unit's storage. Cannot initiate cycle.") return if(!src.HELMET && !src.MASK && !src.SUIT && !src.OCCUPANT ) //shit's empty yo - to_chat(user, "Unit storage bays empty. Nothing to disinfect -- Aborting.") + to_chat(user, "Unit storage bays empty. Nothing to disinfect -- Aborting.") return to_chat(user, "You start the Unit's cauterisation cycle.") src.cycletime_left = 20 @@ -372,7 +372,7 @@ src.SUIT = null if(src.MASK) src.MASK = null - visible_message("With a loud whining noise, [src]'s door grinds open. Puffs of ashen smoke come out of its chamber.", range = 3) + visible_message("With a loud whining noise, [src]'s door grinds open. Puffs of ashen smoke come out of its chamber.", range = 3) src.isbroken = 1 src.isopen = 1 src.islocked = 0 @@ -396,9 +396,9 @@ if (src.OCCUPANT.client) if(user != OCCUPANT) - to_chat(OCCUPANT, "The machine kicks you out!") + to_chat(OCCUPANT, "The machine kicks you out!") if(user.loc != src.loc) - to_chat(OCCUPANT, "You leave the not-so-cozy confines of the SSU.") + to_chat(OCCUPANT, "You leave the not-so-cozy confines of the SSU.") src.OCCUPANT.client.eye = src.OCCUPANT.client.mob src.OCCUPANT.client.perspective = MOB_PERSPECTIVE @@ -432,13 +432,13 @@ if (usr.stat != 0) return if (!src.isopen) - to_chat(usr, "The unit's doors are shut.") + to_chat(usr, "The unit's doors are shut.") return if (!src.ispowered || src.isbroken) - to_chat(usr, "The unit is not operational.") + to_chat(usr, "The unit is not operational.") return if ( (src.OCCUPANT) || (src.HELMET) || (src.SUIT) ) - to_chat(usr, "It's too cluttered inside for you to fit in!") + to_chat(usr, "It's too cluttered inside for you to fit in!") return usr.visible_message("[usr] starts squeezing into [src]!", "You start squeezing into [src]!", range = 3) if(do_after(usr, 10)) @@ -464,7 +464,7 @@ if(I.isscrewdriver()) src.panelopen = !src.panelopen playsound(src.loc, I.usesound, 100, 1) - to_chat(user, text("You [] the unit's maintenance panel.",(src.panelopen ? "open up" : "close") )) + to_chat(user, text("You [] the unit's maintenance panel.",(src.panelopen ? "open up" : "close") )) update_icon() src.updateUsrDialog() return @@ -473,13 +473,13 @@ if( !(ismob(G.affecting)) ) return if (!src.isopen) - to_chat(usr, "The unit's doors are shut.") + to_chat(usr, "The unit's doors are shut.") return if (!src.ispowered || src.isbroken) - to_chat(usr, "The unit is not operational.") + to_chat(usr, "The unit is not operational.") return if ( (src.OCCUPANT) || (src.HELMET) || (src.SUIT) ) //Unit needs to be absolutely empty - to_chat(user, "The unit's storage area is too cluttered.") + to_chat(user, "The unit's storage area is too cluttered.") return user.visible_message("[user] starts putting [G.affecting] into [src].", "You start putting [G.affecting] into [src].", range = 3) if(do_after(user, 20)) @@ -502,7 +502,7 @@ return var/obj/item/clothing/suit/space/S = I if(src.SUIT) - to_chat(user, "The unit already contains a suit.") + to_chat(user, "The unit already contains a suit.") return to_chat(user, "You load the [S.name] into the storage compartment.") user.drop_from_inventory(S,src) @@ -515,7 +515,7 @@ return var/obj/item/clothing/head/helmet/H = I if(src.HELMET) - to_chat(user, "The unit already contains a helmet.") + to_chat(user, "The unit already contains a helmet.") return to_chat(user, "You load the [H.name] into the storage compartment.") user.drop_from_inventory(H,src) @@ -528,7 +528,7 @@ return var/obj/item/clothing/mask/M = I if(src.MASK) - to_chat(user, "The unit already contains a mask.") + to_chat(user, "The unit already contains a mask.") return to_chat(user, "You load the [M.name] into the storage compartment.") user.drop_from_inventory(M,src) diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index c8e04cedae6..99118a82321 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -232,7 +232,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/list/obj/item/device/radio/radios = list() // --- Gets the accent icon, if there is any --- - var/accent_icon = M.get_accent_icon(speaking) + var/accent_icon = M.get_accent_icon(speaking, M) // --- Broadcast only to intercom devices --- @@ -352,8 +352,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/part_a = "[accent_icon ? accent_icon + " " : ""]\[[freq_text]\][part_b_extra] " // goes in the actual output // --- Some more pre-message formatting --- - var/part_b = " " // Tweaked for security headsets -- TLE - var/part_c = "" + var/part_b = " " // Tweaked for security headsets -- TLE + var/part_c = "" // --- Filter the message; place it in quotes apply a verb --- @@ -411,33 +411,33 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept if (length(heard_masked)) for (var/mob/R in heard_masked) - R.hear_radio(message,verbage, speaking, part_a, part_b, M, 0, name) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 0, name) /* --- Process all the mobs that heard the voice normally (understood) --- */ if (length(heard_normal)) for (var/mob/R in heard_normal) - R.hear_radio(message, verbage, speaking, part_a, part_b, M, 0, realname) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 0, realname) /* --- Process all the mobs that heard the voice normally (did not understand) --- */ if (length(heard_voice)) for (var/mob/R in heard_voice) - R.hear_radio(message,verbage, speaking, part_a, part_b, M,0, vname) + R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M,0, vname) /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ // Displays garbled message (ie "f*c* **u, **i*er!") if (length(heard_garbled)) for (var/mob/R in heard_garbled) - R.hear_radio(message, verbage, speaking, part_a, part_b, M, 1, vname) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 1, vname) /* --- Complete gibberish. Usually happens when there's a compressed message --- */ if (length(heard_gibberish)) for (var/mob/R in heard_gibberish) - R.hear_radio(message, verbage, speaking, part_a, part_b, M, 1) + R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 1) return 1 diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index fe63888a87d..3a7919df9fc 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -343,13 +343,13 @@ // This is not a status display message, since it's something the character // themselves is meant to see BEFORE putting the money in - to_chat(usr, "\icon[cashmoney] That is not enough money.") + to_chat(user, "[icon2html(cashmoney, user)] That is not enough money.") return 0 if(istype(cashmoney, /obj/item/spacecash/bundle)) // Bundles can just have money subtracted, and will work - visible_message("\The [usr] inserts some cash into \the [src].") + visible_message("\The [user] inserts some cash into \the [src].") var/obj/item/spacecash/bundle/cashmoney_bundle = cashmoney cashmoney_bundle.worth -= currently_vending.price @@ -364,9 +364,9 @@ // This is really dirty, but there's no superclass for all bills, so we // just assume that all spacecash that's not something else is a bill - visible_message("\The [usr] inserts a bill into \the [src].") + visible_message("\The [user] inserts a bill into \the [src].") var/left = cashmoney.worth - currently_vending.price - usr.drop_from_inventory(cashmoney,get_turf(src)) + user.drop_from_inventory(cashmoney,get_turf(src)) qdel(cashmoney) if(left) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 006d6d7f5a4..159e3dba572 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -1157,7 +1157,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) // src.client is so that ghosts don't have to listen to rats if(istype(M, /mob/abstract/new_player)) continue - M.show_message("PDA Message - [owner] -> [P.owner]: [t]") + M.show_message("PDA Message - [owner] -> [P.owner]: [t]") if(!conversations.Find("\ref[P]")) conversations.Add("\ref[P]") @@ -1173,7 +1173,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if (!beep_silent) playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) for (var/mob/O in hearers(2, loc)) - O.show_message(text("\icon[src] *[message_tone]*")) + O.show_message(text("[icon2html(src, O)] *[message_tone]*")) //Search for holder of the PDA. var/mob/living/L = null if(loc && isliving(loc)) @@ -1188,7 +1188,7 @@ var/global/list/obj/item/device/pda/PDAs = list() SSnanoui.update_user_uis(L, src) // Update the receiving user's PDA UI so that they can see the new message /obj/item/device/pda/proc/new_news(var/message) - new_info(news_silent, newstone, news_silent ? "" : "\icon[src] [message]") + new_info(news_silent, newstone, news_silent ? "" : "[icon2html(src, viewers(get_turf(src)))] [message]") if(!news_silent) new_news = 1 @@ -1201,7 +1201,7 @@ var/global/list/obj/item/device/pda/PDAs = list() new_message(sending_device, sending_device.owner, sending_device.ownjob, message) /obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message) - var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply)" + var/reception_message = "[icon2html(src, viewers(get_turf(src)))] Message from [sender] ([sender_job]), \"[message]\" (Reply)" new_info(message_silent, ttone, reception_message) log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]",ckey=key_name(usr),ckey_target=key_name(name)) @@ -1213,7 +1213,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(ismob(sending_unit.loc) && isAI(loc)) track = "(Follow)" - var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" + var/reception_message = "[icon2html(src, viewers(get_turf(src)))] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" new_info(message_silent, newstone, reception_message) log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]",ckey=key_name(usr),ckey_target=key_name(name)) @@ -1534,7 +1534,7 @@ var/global/list/obj/item/device/pda/PDAs = list() /obj/item/device/pda/CouldUseTopic(var/mob/user) ..() if(iscarbon(user)) - playsound(src, 'sound/machines/pda_click.ogg', 20) + playsound(loc, 'sound/machines/pda_click.ogg', 20) //Some spare PDAs in a box /obj/item/storage/box/PDAs diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 998b3b8849d..decfc71dc42 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -36,7 +36,7 @@ if(!user || !M) return //sanity M.attack_log += text("\[[time_stamp()]\] Has been flashed (attempt) with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to flash [M.name] ([M.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to flash [M.name] ([M.ckey])") msg_admin_attack("[user.name] ([user.ckey]) Used the [src.name] to flash [M.name] ([M.ckey]) (JMP)",ckey=key_name(user),ckey_target=key_name(M)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) diff --git a/code/game/objects/items/devices/hacktool.dm b/code/game/objects/items/devices/hacktool.dm index f2e201e6972..d917004def6 100644 --- a/code/game/objects/items/devices/hacktool.dm +++ b/code/game/objects/items/devices/hacktool.dm @@ -57,7 +57,7 @@ to_chat(user, SPAN_WARNING("You are already hacking this door!")) return 0 if(!is_type_in_list(target, supported_types)) - to_chat(user, "\icon[src] Unable to hack this target!") + to_chat(user, "[icon2html(src, user)] Unable to hack this target!") return 0 if(istype(target, /obj/machinery/door/airlock)) var/obj/machinery/door/airlock/door = target diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 6ebed0a65ee..8ea33bfff20 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -205,7 +205,7 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/CouldUseTopic(var/mob/user) ..() if(clicksound && iscarbon(user)) - playsound(src, clicksound, clickvol) + playsound(loc, clicksound, clickvol) /obj/item/device/radio/Topic(href, href_list) if(..()) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index c4ffae25ca8..54497109cf4 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -565,14 +565,14 @@ BREATH ANALYZER if(0 to 25) to_chat(user,"Subject oxygen levels nominal.") if(25 to 50) - to_chat(user,"Subject oxygen levels abnormal.") + to_chat(user,"Subject oxygen levels abnormal.") if(50 to INFINITY) - to_chat(user,"Severe oxygen deprivation detected.") + to_chat(user,"Severe oxygen deprivation detected.") var/obj/item/organ/internal/L = H.internal_organs_by_name[BP_LUNGS] if(istype(L)) if(L.is_bruised()) - to_chat(user,"Ruptured lung detected.") + to_chat(user,"Ruptured lung detected.") else if(L.is_damaged()) to_chat(user,"Damaged lung detected.") else @@ -588,11 +588,11 @@ BREATH ANALYZER if(INTOX_MUSCLEIMP to INTOX_VOMIT) additional_string = "\[MODERATELY INTOXICATED\]" if(INTOX_VOMIT to INTOX_BALANCE) - additional_string = "\[HEAVILY INTOXICATED\]" + additional_string = "\[HEAVILY INTOXICATED\]" if(INTOX_BALANCE to INTOX_DEATH) - additional_string = "\[ALCOHOL POISONING LIKELY\]" + additional_string = "\[ALCOHOL POISONING LIKELY\]" if(INTOX_DEATH to INFINITY) - additional_string = "\[DEATH IMMINENT\]" + additional_string = "\[DEATH IMMINENT\]" to_chat(user,"Blood Alcohol Content: [round(bac,0.01)] [additional_string]") if(H.breathing && H.breathing.total_volume) diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 1e58472222a..b0935bfd885 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -35,7 +35,7 @@ effective or pretty fucking useless. to_chat(user, "The mind batterer has been burnt out!") return - user.attack_log += text("\[[time_stamp()]\] Used [src] to knock down people in the area.") + user.attack_log += text("\[[time_stamp()]\] Used [src] to knock down people in the area.") for(var/mob/living/carbon/human/M in orange(10, user)) spawn() diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm index 2b0ba8fffcb..6ec95ba7bd9 100644 --- a/code/game/objects/items/stacks/wrap.dm +++ b/code/game/objects/items/stacks/wrap.dm @@ -68,7 +68,7 @@ H.forceMove(present) H.attack_log += text("\[[time_stamp()]\] Has been wrapped with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to wrap [H.name] ([H.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to wrap [H.name] ([H.ckey])") msg_admin_attack("[key_name_admin(user)] used [src] to wrap [key_name_admin(H)] (JMP)",ckey=key_name(user),ckey_target=key_name(H)) else @@ -101,7 +101,7 @@ if(user in target) //no wrapping closets that you are inside - it's not physically possible return - user.attack_log += text("\[[time_stamp()]\] Has used [src.name] on \ref[target]") + user.attack_log += text("\[[time_stamp()]\] Has used [src.name] on \ref[target]") if (istype(target, /obj/item) && !(istype(target, /obj/item/storage) && !istype(target,/obj/item/storage/box))) diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm index 223ad387b3d..bfbc6d4d444 100644 --- a/code/game/objects/items/weapons/autopsy.dm +++ b/code/game/objects/items/weapons/autopsy.dm @@ -109,13 +109,13 @@ if(0) damage_desc = "Unknown" if(1 to 5) - damage_desc = "negligible" + damage_desc = "negligible" if(5 to 15) - damage_desc = "light" + damage_desc = "light" if(15 to 30) damage_desc = "moderate" if(30 to 1000) - damage_desc = "severe" + damage_desc = "severe" if(!total_score) total_score = D.organs_scanned.len diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index f4d462ef2f1..c88f0ef1589 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -139,10 +139,10 @@ var/const/NO_EMAG_ACT = -50 /obj/item/card/id/proc/prevent_tracking() return 0 -/obj/item/card/id/proc/show(mob/user as mob) +/obj/item/card/id/proc/show(mob/user) if(front && side) - to_chat(user, browse_rsc(front, "front.png")) - to_chat(user, browse_rsc(side, "side.png")) + send_rsc(user, front, "front.png") + send_rsc(user, side, "side.png") var/datum/browser/popup = new(user, "idcard", name, 650, 260) popup.set_content(dat()) popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) @@ -214,8 +214,8 @@ var/const/NO_EMAG_ACT = -50 to_chat(user, "Biometric Imprinting successful!") return - for(var/mob/O in viewers(user, null)) - O.show_message(text("[] shows you: \icon[] []: assignment: []", user, src, src.name, src.assignment), 1) + user.visible_message("[user] shows you: [icon2html(src, viewers(get_turf(src)))] [src.name]. The assignment on the card: [src.assignment]",\ + "You flash your ID card: [icon2html(src, viewers(get_turf(src)))] [src.name]. The assignment on the card: [src.assignment]") src.add_fingerprint(user) return @@ -280,7 +280,7 @@ var/const/NO_EMAG_ACT = -50 set category = "Object" set src in usr - to_chat(usr, text("\icon[] []: The current assignment on the card is [].", src, src.name, src.assignment)) + to_chat(usr, text("[icon2html(src, usr)] []: The current assignment on the card is [].", src.name, src.assignment)) to_chat(usr, "The age on the card is [age].") to_chat(usr, "The citizenship on the card is [citizenship].") to_chat(usr, "The religion on the card is [religion].") diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index c8d08b2e2d5..af11666b7f5 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -138,7 +138,7 @@ injected_with_monkey = " (MONKEY)" M.attack_log += text("\[[time_stamp()]\] Has been injected with [name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [name] to inject [M.name] ([M.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [name] to inject [M.name] ([M.ckey])") log_attack("[user.name] ([user.ckey]) used the [name] to inject [M.name] ([M.ckey])",ckey=key_name(user),ckey_target=key_name(M)) message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with \the [src][injected_with_monkey]") diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index 7669c8d0624..e1ffa736074 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -125,7 +125,7 @@ if(!ptank) to_chat(user, "Attach a phoron tank first!") return - var/dat = text("Flamethrower ([lit ? "Lit" : "Unlit"])
    \n Tank Pressure: [ptank.air_contents.return_pressure()]
    \nAmount to throw: - - - [throw_amount] + + +
    \nRemove phorontank - Close
    ") + var/dat = text("Flamethrower ([lit ? "Lit" : "Unlit"])
    \n Tank Pressure: [ptank.air_contents.return_pressure()]
    \nAmount to throw: - - - [throw_amount] + + +
    \nRemove phorontank - Close
    ") user << browse(dat, "window=flamethrower;size=600x300") onclose(user, "flamethrower") return diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 881cce7ec25..86d4cbc2f5b 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -75,7 +75,7 @@ if(user) H.attack_log += text("\[[time_stamp()]\] Has been handcuffed (attempt) by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Attempted to handcuff [H.name] ([H.ckey])") + user.attack_log += text("\[[time_stamp()]\] Attempted to handcuff [H.name] ([H.ckey])") msg_admin_attack("[key_name_admin(user)] attempted to handcuff [key_name_admin(H)] (JMP)",ckey=key_name(user),ckey_target=key_name(H)) feedback_add_details("handcuffs","H") @@ -118,7 +118,7 @@ var/s = SPAN_WARNING("[H] chews on [H.get_pronoun("his")] [O.name]!") H.visible_message(s, SPAN_WARNING("You chew on your [O.name]!")) message_admins("[key_name_admin(H)] is chewing on [H.get_pronoun("his")] restrained hand - (JMP)") - H.attack_log += text("\[[time_stamp()]\] [s] ([H.ckey])") + H.attack_log += text("\[[time_stamp()]\] [s] ([H.ckey])") log_attack("[s] ([H.ckey])",ckey=key_name(H)) if(O.take_damage(3, 0, damage_flags = DAM_SHARP|DAM_EDGE, used_weapon = "teeth marks")) diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 1f8c6a479cc..4fda369c4b9 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -489,7 +489,7 @@ the implant may become unstable and either pre-maturely inject the subject or si Implant Specifications:
    Name: Cybersun Industries Adrenalin Implant
    Life: Five days.
    -Important Notes: Illegal
    +Important Notes: Illegal

    Implant Details: Subjects injected with implant can activate a massive injection of adrenalin.
    Function: Contains nanobots to stimulate body to mass-produce Adrenalin.
    diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 6ff142c92a9..c7d6b7aa513 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -202,7 +202,7 @@ user.visible_message(SPAN_WARNING("\The [user] tags \the [M] with \the [src]!"), SPAN_NOTICE("You tag \the [M] with \the [src]."), range = 3) M.attack_log += text("\[[time_stamp()]\] Implanted with [src.name] ([src.ipc_tag.name]) by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] ([src.ipc_tag.name]) to implant [M.name] ([M.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] ([src.ipc_tag.name]) to implant [M.name] ([M.ckey])") msg_admin_attack("[key_name_admin(user)] implanted [key_name_admin(M)] with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)",ckey=key_name(user),ckey_target=key_name(M)) ipc_tag.replaced(H, H.organs_by_name[BP_HEAD]) diff --git a/code/game/objects/items/weapons/implants/implantfreedom.dm b/code/game/objects/items/weapons/implants/implantfreedom.dm index d86051b2e3a..5a0360deb7e 100644 --- a/code/game/objects/items/weapons/implants/implantfreedom.dm +++ b/code/game/objects/items/weapons/implants/implantfreedom.dm @@ -58,7 +58,7 @@ Implant Specifications:
    Name: Freedom Beacon
    Life: optimum 5 uses
    -Important Notes: Illegal
    +Important Notes: Illegal

    Implant Details:
    Function: Transmits a specialized cluster of signals to override handcuff locking diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm index b32794072d3..3e934844aed 100644 --- a/code/game/objects/items/weapons/manuals.dm +++ b/code/game/objects/items/weapons/manuals.dm @@ -76,7 +76,7 @@
  • Open the control panel
  • Set the speed to 2
  • Start firing at the singularity generator
  • -
  • When the singularity reaches a large enough size so it starts moving on it's own set the speed down to 0, but don't shut it off
  • +
  • When the singularity reaches a large enough size so it starts moving on it's own set the speed down to 0, but don't shut it off
  • Remember to wear a radiation suit when working with this machine... we did tell you that at the start, right?
  • @@ -238,7 +238,7 @@ A power problem has made the entire station lose power? Could be station-wide wiring problems or syndicate power sinks. In any case follow these steps:
      -
    1. PANIC!
    2. +
    3. PANIC!
    4. Get your ass over to engineering! QUICKLY!!!
    5. Get to the Area Power Controller which controls the power to the emitters.
    6. Swipe it with your ID card - if it doesn't unlock, continue with step 15.
    7. diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 045e3f845b0..e91a53f2768 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -476,7 +476,7 @@ /obj/item/storage/box/mousetraps name = "box of Pest-B-Gon mousetraps" - desc = "WARNING: Keep out of reach of children." + desc = "WARNING: Keep out of reach of children." icon_state = "mousetraps" starts_with = list(/obj/item/device/assembly/mousetrap = 6) diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index 8256fab1306..e0c19e49e07 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -103,7 +103,7 @@ Frequency: src.temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

      Refresh
      " else - src.temp += "Processing Error: Unable to locate orbital position.
      " + src.temp += "Processing Error: Unable to locate orbital position.
      " else if (href_list["freq"]) src.frequency += text2num(href_list["freq"]) diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 69a5f88b4db..b57b1c976f7 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -292,7 +292,7 @@ /obj/item/weldingtool/examine(mob/user) if(..(user, 0)) - to_chat(user, text("\icon[] [] contains []/[] units of fuel!", src, src.name, get_fuel(),src.max_fuel )) + to_chat(user, text("[icon2html(src, user)] [] contains []/[] units of fuel!", src.name, get_fuel(),src.max_fuel )) /obj/item/weldingtool/attackby(obj/item/W, mob/user) if(W.isscrewdriver()) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 0a781515a81..049c303f921 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -197,6 +197,6 @@ attack_verb = list("banned") /obj/item/banhammer/attack(mob/M as mob, mob/user as mob) - to_chat(M, " You have been banned FOR NO REISIN by [user]") - to_chat(user, " You have BANNED [M]") + to_chat(M, " You have been banned FOR NO REISIN by [user]") + to_chat(user, " You have BANNED [M]") playsound(loc, 'sound/effects/adminhelp.ogg', 15) diff --git a/code/game/objects/items/weapons/weldbackpack.dm b/code/game/objects/items/weapons/weldbackpack.dm index 03075033a2d..396136b4f30 100644 --- a/code/game/objects/items/weapons/weldbackpack.dm +++ b/code/game/objects/items/weapons/weldbackpack.dm @@ -50,5 +50,5 @@ /obj/item/weldpack/examine(mob/user) ..(user) - to_chat(user, text("\icon[] [] units of fuel left!", src, src.reagents.total_volume)) + to_chat(user, text("[icon2html(src, user)] [] units of fuel left!", src.reagents.total_volume)) return diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index f090daeef74..a0227dd7c95 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -50,7 +50,7 @@ /obj/CanUseTopic(var/mob/user, var/datum/topic_state/state) if(user.CanUseObjTopic(src)) return ..() - to_chat(user, "\icon[src]Access Denied!") + to_chat(user, "[icon2html(src, user)]Access Denied!") return STATUS_CLOSE /mob/living/silicon/CanUseObjTopic(var/obj/O) @@ -159,13 +159,6 @@ /obj/proc/hear_talk(mob/M as mob, text, verb, datum/language/speaking) if(talking_atom) talking_atom.catchMessage(text, M) -/* - var/mob/mo = locate(/mob) in src - if(mo) - var/rendered = "[M.name]: [text]" - mo.show_message(rendered, 2) - */ - return /obj/proc/see_emote(mob/M as mob, text, var/emote_type) return diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 76db4537804..0806485fc65 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -59,9 +59,9 @@ if(..(user, 1)) if (mybucket) var/contains = mybucket.reagents.total_volume - to_chat(user, "\icon[src] The bucket contains [contains] unit\s of liquid!") + to_chat(user, "[icon2html(src, user)] The bucket contains [contains] unit\s of liquid!") else - to_chat(user, "\icon[src] There is no bucket mounted on it!") + to_chat(user, "[icon2html(src, user)] There is no bucket mounted on it!") //everything else is visible, so doesn't need to be mentioned diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index dda05914649..51ba07a3a22 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -168,7 +168,7 @@ if(pulling) occupant.visible_message("[pulling] has thrusted \the [name] into \the [A], throwing \the [occupant] out of it!") - pulling.attack_log += "\[[time_stamp()]\] Crashed [occupant.name]'s ([occupant.ckey]) [name] into \a [A]" + pulling.attack_log += "\[[time_stamp()]\] Crashed [occupant.name]'s ([occupant.ckey]) [name] into \a [A]" occupant.attack_log += "\[[time_stamp()]\] Thrusted into \a [A] by [pulling.name] ([pulling.ckey]) with \the [name]" msg_admin_attack("[pulling.name] ([pulling.ckey]) has thrusted [occupant.name]'s ([occupant.ckey]) [name] into \a [A] (JMP)",ckey=key_name(pulling),ckey_target=key_name(occupant)) else diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index b6275678211..e08bd7da167 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -58,9 +58,9 @@ else display_name = holder.fakekey if(holder && !holder.fakekey && (holder.rights & R_ADMIN) && config.allow_admin_ooccolor && (src.prefs.ooccolor != initial(src.prefs.ooccolor))) // keeping this for the badmins - to_chat(target, "" + create_text_tag("ooc", "OOC:", target) + " [display_name]: [msg]") + to_chat(target, "" + create_text_tag("OOC", target) + " [display_name]: [msg]") else - to_chat(target, "" + create_text_tag("ooc", "OOC:", target) + " [display_name]: [msg]") + to_chat(target, "" + create_text_tag("OOC", target) + " [display_name]: [msg]") /client/verb/looc(msg as text) set name = "LOOC" @@ -150,7 +150,7 @@ if(target.mob in messagemobs) prefix = "" if((target.mob in messagemobs) || display_remote) - to_chat(target, "" + create_text_tag("looc", "LOOC:", target) + " [prefix][display_name][admin_stuff]: [msg]") + to_chat(target, "" + create_text_tag("LOOC", target) + " [prefix][display_name][admin_stuff]: [msg]") /client/verb/stop_all_sounds() set name = "Stop all sounds" diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index a233d8586c9..ed566e246a5 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -41,7 +41,7 @@ msg += " - [age]" if(is_special_character(C.mob)) - msg += " - Antagonist" + msg += " - Antagonist" msg += " (?)" msg += "
      " total_num++ diff --git a/code/global.dm b/code/global.dm index 7db1a17c1f9..ec92e970fed 100644 --- a/code/global.dm +++ b/code/global.dm @@ -91,8 +91,6 @@ var/datum/moduletypes/mods = new() var/gravity_is_on = 1 -var/datum/server_greeting/server_greeting = null - var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to. // For FTP requests. (i.e. downloading runtime logs.) diff --git a/code/js/byjax.dm b/code/js/byjax.dm index 7189bcb4763..9a7dc651715 100644 --- a/code/js/byjax.dm +++ b/code/js/byjax.dm @@ -45,6 +45,6 @@ proc/send_byjax(receiver, control_id, target_element, new_content=null, callback /* if(callback_args) argums += "&[list2params(callback_args)]" */ - to_chat(receiver, output(argums,"[control_id]:replaceContent")) + send_output(receiver, argums, "[control_id]:replaceContent") return diff --git a/code/modules/admin/DB ban/ban_mirroring.dm b/code/modules/admin/DB ban/ban_mirroring.dm index 53a0d6ac666..41d5adb7a2a 100644 --- a/code/modules/admin/DB ban/ban_mirroring.dm +++ b/code/modules/admin/DB ban/ban_mirroring.dm @@ -342,7 +342,7 @@ data += list(list(C.ckey, C.address, C.computer_id)) var/data_str = json_encode(data) - to_chat(C, output(list2params(list("E-DAT", data_str, 900)), "greeting.browser:setCookie")) + send_output(C, list2params(list("E-DAT", data_str, 900)), "greeting.browser:setCookie") #undef BAD_CID #undef BAD_IP diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index cc3b66f9e3b..b670b18fb5d 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -64,7 +64,7 @@ ip = query.item[3] if(!validckey) if(!banned_mob || (banned_mob && !IsGuestKey(banned_mob.key))) - message_admins("[key_name_admin(usr)] attempted to ban [ckey], but [ckey] has not been seen yet. Please only ban actual players.",1) + message_admins("[key_name_admin(usr)] attempted to ban [ckey], but [ckey] has not been seen yet. Please only ban actual players.",1) return var/a_ckey @@ -507,7 +507,7 @@ var/typedesc ="" switch(bantype) if("PERMABAN") - typedesc = "PERMABAN" + typedesc = "PERMABAN" if("TEMPBAN") typedesc = "TEMPBAN
      ([duration] minutes) [(unbanned || auto) ? "" : "(Edit)"]
      Expires [expiration]
      " if("JOB_PERMABAN") diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index d699988281b..0ede3b88592 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -397,7 +397,7 @@ proc/admin_notice(var/message, var/rights) if(FC.is_admin_channel) dat+="[FC.channel_name]
      " else - dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
      " + dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
      " dat+={"

      Refresh
      Back "} @@ -452,7 +452,7 @@ proc/admin_notice(var/message, var/rights) dat+="[src.admincaster_feed_channel.channel_name]: \[created by: [src.admincaster_feed_channel.author]\]
      " if(src.admincaster_feed_channel.censored) dat+={" - ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
      + ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
      No further feed story additions are allowed while the D-Notice is in effect.

      "} else @@ -464,7 +464,7 @@ proc/admin_notice(var/message, var/rights) i++ dat+="
      [MESSAGE.body] \[Likes: [MESSAGE.likes] Dislikes: [MESSAGE.dislikes]\]
      " if(MESSAGE.img) - to_chat(usr, browse_rsc(MESSAGE.img, "tmp_photo[i].png")) + send_rsc(usr, MESSAGE.img, "tmp_photo[i].png") dat+="

      " dat+="View Comments Add Comment Like Story Dislike Story
      " dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]

      " @@ -484,7 +484,7 @@ proc/admin_notice(var/message, var/rights) else for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) - dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
      " + dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
      " dat+="
      Cancel" if(11) dat+={" @@ -498,7 +498,7 @@ proc/admin_notice(var/message, var/rights) else for(var/channel in SSnews.network_channels) var/datum/feed_channel/FC = SSnews.GetFeedChannel(channel) - dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
      " + dat+="[FC.channel_name] [(FC.censored) ? ("***") : null]
      " dat+="
      Back" if(12) @@ -522,7 +522,7 @@ proc/admin_notice(var/message, var/rights) "} if(src.admincaster_feed_channel.censored) dat+={" - ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
      + ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [current_map.company_name] D-Notice.
      No further feed story additions are allowed while the D-Notice is in effect.

      "} else @@ -580,7 +580,7 @@ proc/admin_notice(var/message, var/rights) Photo:: "} if(SSnews.wanted_issue.img) - to_chat(usr, browse_rsc(SSnews.wanted_issue.img, "tmp_photow.png")) + send_rsc(usr, SSnews.wanted_issue.img, "tmp_photow.png") dat+="
      " else dat+="None" @@ -817,11 +817,11 @@ proc/admin_notice(var/message, var/rights) if(SSticker.current_state == GAME_STATE_PREGAME) SSticker.current_state = GAME_STATE_SETTING_UP log_admin("[usr.key] has started the game.") - message_admins("[usr.key] has started the game.") + message_admins("[usr.key] has started the game.") feedback_add_details("admin_verb","SN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return 1 else - to_chat(usr, "Error: Start Now: Game has already started.") + to_chat(usr, "Error: Start Now: Game has already started.") return 0 /datum/admins/proc/toggleenter() @@ -1363,7 +1363,7 @@ proc/admin_notice(var/message, var/rights) if(check_rights(R_ADMIN|R_MOD)) if (H.paralysis == 0) msg = "has paralyzed [key_name_admin(H)]." - H.visible_message("OOC Information: [H] has been winded by a member of staff! Please freeze all roleplay involving their character until the matter is resolved! Adminhelp if you have further questions.", "You have been winded by a member of staff! Please stand by until they contact you!") + H.visible_message("OOC Information: [H] has been winded by a member of staff! Please freeze all roleplay involving their character until the matter is resolved! Adminhelp if you have further questions.", "You have been winded by a member of staff! Please stand by until they contact you!") H.paralysis = 8000 else if (alert("The player is currently winded. Do you want to unwind him?", "Unwind player?", "Yes", "No") == "No") @@ -1371,7 +1371,7 @@ proc/admin_notice(var/message, var/rights) H.paralysis = 0 msg = "has unparalyzed [key_name_admin(H)]." - H.visible_message("OOC Information: [H] has been unwinded by a member of staff!", "You have been unwinded by a member of staff!") + H.visible_message("OOC Information: [H] has been unwinded by a member of staff!", "You have been unwinded by a member of staff!") log_and_message_admins(msg) feedback_add_details("admin_verb", "WIND") diff --git a/code/modules/admin/admin_attack_log.dm b/code/modules/admin/admin_attack_log.dm index 3c5d560a3cc..1e8b45b29ce 100644 --- a/code/modules/admin/admin_attack_log.dm +++ b/code/modules/admin/admin_attack_log.dm @@ -27,7 +27,7 @@ proc/admin_attack_log(var/mob/attacker, var/mob/victim, var/attacker_message, va victim.attack_log += text("\[[time_stamp()]\] [key_name(attacker)] - [victim_message]") jmp_link = " (JMP)" if(attacker) - attacker.attack_log += text("\[[time_stamp()]\] [key_name(victim)] - [attacker_message]") + attacker.attack_log += text("\[[time_stamp()]\] [key_name(victim)] - [attacker_message]") jmp_link = " (JMP)" msg_admin_attack("[key_name_admin(attacker)] [admin_message] [key_name_admin(victim)] (INTENT: [attacker? uppertext(attacker.a_intent) : "N/A"])[jmp_link]",ckey=key_name(attacker),ckey_target=key_name(victim)) diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 8dc1e9de747..38f12df1257 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -34,7 +34,7 @@ if("singulo", "telesci") //general one-round-only stuff var/F = investigate_subject2file(subject) if(!F) - to_chat(src, "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed.") + to_chat(src, "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed.") return src << browse(F,"window=investigate[subject];size=800x300") @@ -43,8 +43,8 @@ if(href_logfile) src << browse(href_logfile,"window=investigate[subject];size=800x300") else - to_chat(src, "Error: admin_investigate: No href logfile found.") + to_chat(src, "Error: admin_investigate: No href logfile found.") return else - to_chat(src, "Error: admin_investigate: Href Logging is not on.") + to_chat(src, "Error: admin_investigate: Href Logging is not on.") return diff --git a/code/modules/admin/admin_server_greeting.dm b/code/modules/admin/admin_server_greeting.dm deleted file mode 100644 index 0c7ecfcfd13..00000000000 --- a/code/modules/admin/admin_server_greeting.dm +++ /dev/null @@ -1,80 +0,0 @@ -/* - * A file containing the admin commands for interfacing with the server_greeting datum. - */ -/client/proc/admin_edit_motd() - set name = "Edit MotD" - set category = "Server" - - if (!check_rights(R_SERVER)) - return - - var/new_message = input(usr, "Please edit the Message of the Day as necessary.", "Message of the Day", server_greeting.motd) as message - - if (!new_message) - new_message = "
      This is a palceholder. Pester your staff to change it!
      " - - server_greeting.update_value("motd", new_message) - message_admins("[ckey] has edited the message of the day:
      [html_encode(new_message)]") - -/client/proc/admin_memo_control(task in list("write", "delete")) - set name = "Edit Memos" - set category = "Server" - - if (!check_rights(R_ADMIN)) - return - - switch (task) - if ("write") - admin_memo_write() - if ("delete") - admin_memo_delete() - -/client/proc/admin_memo_write() - var/current_memo = "" - if (server_greeting.memo_list.len && server_greeting.memo_list[ckey]) - current_memo = server_greeting.memo_list[ckey] - - var/new_memo = input(usr, "Please write your memo.", "Memo", current_memo) as message - - if (server_greeting.update_value("memo_write", list(ckey, new_memo))) - to_chat(src, "Operation carried out successfully.") - message_admins("[ckey] wrote a new memo:
      [html_encode(new_memo)]") - else - to_chat(src, "Error carrying out desired operation.") - - return - -/client/proc/admin_memo_delete() - if (!server_greeting.memo_list.len) - to_chat(src, "No memos are currently saved.") - return - - if (!check_rights(R_SERVER)) - if (!server_greeting.memo_list[ckey]) - to_chat(src, "You do not have a memo saved. Cancelling.") - - else if (alert("Do you wish to delete your own memo, written on [server_greeting.memo_list[ckey]["date"]]?", "Choices", "Yes", "No") == "Yes") - if (server_greeting.update_value("memo_delete", ckey)) - to_chat(src, "Operation carried out successfully.") - message_admins("[ckey] has deleted their own memo.") - else - to_chat(src, "Error carrying out desired operation.") - - else - to_chat(src, "Cancelled.") - - return - else - var/input = input(usr, "Whose memo shall we delete?", "Remove Memo", null) as null|anything in server_greeting.memo_list - - if (!input) - to_chat(src, "Cancelled.") - return - - if (server_greeting.update_value("memo_delete", input)) - to_chat(src, "Operation carried out successfully.") - message_admins("[ckey] has deleted the memo of [input].") - else - to_chat(src, "Error carrying out desired operation.") - - return diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c012774b9b4..25233ba51a7 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -48,7 +48,6 @@ var/list/admin_verbs_admin = list( /client/proc/rename_silicon, //properly renames silicons, /client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. , /client/proc/check_antagonists, - /client/proc/admin_memo_control, /*admin memo system. show/delete/write. +SERVER needed to delete admin memos of others*/ /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ /client/proc/toggleprayers, /*toggles prayers on/off*/ // /client/proc/toggle_hear_deadcast, /*toggles whether we hear deadchat*/ @@ -172,7 +171,6 @@ var/list/admin_verbs_server = list( /client/proc/toggle_random_events, /client/proc/check_customitem_activity, /client/proc/nanomapgen_DumpImage, - /client/proc/admin_edit_motd, /client/proc/toggle_recursive_explosions, /client/proc/restart_controller, /client/proc/cmd_ss_panic, @@ -273,7 +271,6 @@ var/list/admin_verbs_hideable = list( /client/proc/toggle_antagHUD_use, /client/proc/toggle_antagHUD_restrictions, /client/proc/event_manager_panel, - /client/proc/admin_edit_motd, /client/proc/empty_ai_core_toggle_latejoin, /client/proc/empty_ai_core_toggle_latejoin, /client/proc/cmd_admin_change_custom_event, @@ -301,7 +298,6 @@ var/list/admin_verbs_hideable = list( /client/proc/add_client_color, /datum/admins/proc/force_mode_latespawn, /datum/admins/proc/toggleenter, - /client/proc/admin_memo_control, /datum/admins/proc/toggleguests, /datum/admins/proc/capture_map_part, /client/proc/Set_Holiday, @@ -569,13 +565,13 @@ var/list/admin_verbs_cciaa = list( ghost.reenter_corpse() log_admin("[src] reentered their corpose using aghost.",admin_key=key_name(src)) else - to_chat(ghost, "Error: Aghost: Can't reenter corpse.") + to_chat(ghost, "Error: Aghost: Can't reenter corpse.") return feedback_add_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! else if(istype(mob,/mob/abstract/new_player)) - to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.") + to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.") else //ghostize var/mob/body = mob @@ -728,7 +724,7 @@ var/list/admin_verbs_cciaa = list( C.cure_all_traumas(TRUE, CURE_ADMIN) log_and_message_admins("cured [key_name(C)]'s traumas.") - feedback_add_details("admin_verb","TB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!\ + feedback_add_details("admin_verb","TB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/add_traumas(mob/T as mob in mob_list) set category = "Fun" diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 5bc686eebe1..1bccf6892c6 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -87,13 +87,13 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check return 1 else if(show_msg) - to_chat(user, "Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].") + to_chat(user, "Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].") else if(user.client.holder) return 1 else if(show_msg) - to_chat(user, "Error: You are not an admin.") + to_chat(user, "Error: You are not an admin.") return 0 //probably a bit iffy - will hopefully figure out a better solution @@ -105,7 +105,7 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check if(usr.client.holder.rights != other.holder.rights) if( (usr.client.holder.rights & other.holder.rights) == other.holder.rights ) return 1 //we have all the rights they have and more - to_chat(usr, "Error: Cannot proceed. They have more or equal rights to us.") + to_chat(usr, "Error: Cannot proceed. They have more or equal rights to us.") return 0 /client/proc/deadmin() diff --git a/code/modules/admin/map_capture.dm b/code/modules/admin/map_capture.dm index 206e24cd77b..90420e263d2 100644 --- a/code/modules/admin/map_capture.dm +++ b/code/modules/admin/map_capture.dm @@ -24,7 +24,7 @@ var/cap = generate_image(tx ,ty ,tz ,range, CAPTURE_MODE_PARTIAL, null, ligths, 1) var/file_name = "map_capture_x[tx]_y[ty]_z[tz]_r[range].png" to_chat(usr, "Saved capture in cache as [file_name].") - to_chat(usr, browse_rsc(cap, file_name)) + send_rsc(usr, cap, file_name) else to_chat(usr, "Target coordinates are incorrect.") @@ -33,7 +33,7 @@ var/cap = generate_image(currentx ,currenty ,currentz ,16, CAPTURE_MODE_PARTIAL, null, ligths, 1) var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r16.png" to_chat(usr, "Saved capture in cache as [file_name].") - to_chat(usr, browse_rsc(cap, file_name)) + send_rsc(usr, cap, file_name) currentx = currentx + 16 spawn (6) del(cap) @@ -45,7 +45,7 @@ var/cap = generate_image(currentx ,currenty ,currentz ,16, CAPTURE_MODE_PARTIAL, null, ligths, 1) var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r16.png" to_chat(usr, "Saved capture in cache as [file_name].") - to_chat(usr, browse_rsc(cap, file_name)) + send_rsc(usr, cap, file_name) currentx = currentx + 16 spawn (6) del(cap) diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm index fa7cd9b17cc..9f7c2d2b0d7 100644 --- a/code/modules/admin/player_notes.dm +++ b/code/modules/admin/player_notes.dm @@ -10,7 +10,7 @@ datum/admins/proc/notes_show(var/ckey) datum/admins/proc/notes_gethtml(var/ckey) var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return "Error: Cannot access [NOTESFILE]" + if(!notesfile) return "Error: Cannot access [NOTESFILE]" if(ckey) . = "Notes for [ckey]: \[+\] \[-\]
      " notesfile.cd = "/[ckey]" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 9e0af39d87b..a9b5e68d84a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -827,7 +827,7 @@ //Job + antagonist if(M.mind) - special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]; Has been rev: [(M.mind.has_been_rev)?"Yes":"No"]" + special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]; Has been rev: [(M.mind.has_been_rev)?"Yes":"No"]" else special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing; Has been rev: Mind datum missing;" @@ -838,7 +838,7 @@ switch (M.stat) if (0) status = "Alive" if (1) status = "Unconscious" - if (2) status = "Dead" + if (2) status = "Dead" health_description = "Status: [status]" health_description += "
      Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getBrainLoss()]" else @@ -853,7 +853,7 @@ //GenDer switch(M.gender) if(MALE,FEMALE) gender_description = "[M.gender]" - else gender_description = "[M.gender]" + else gender_description = "[M.gender]" var/dat = "Info about [M.name]:
      " dat += "Mob type: [M.type]
      " diff --git a/code/modules/admin/verbs/access_control.dm b/code/modules/admin/verbs/access_control.dm index 6f1608a473c..65adb902e02 100644 --- a/code/modules/admin/verbs/access_control.dm +++ b/code/modules/admin/verbs/access_control.dm @@ -13,27 +13,27 @@ data += "If you do not know what these do, you shouldn't be touching them!
      " data += "

      Hub Visibility Setting:


      " - data += "Currently [world.visibility ? "VISIBLE" : "HIDDEN"]. Toggle

      " + data += "Currently [world.visibility ? "VISIBLE" : "HIDDEN"]. Toggle

      " data += "

      IP Intel Settings:



      " data += "

      Player Age Settings:



      " data += "

      VM Detection Settings:


      " data += "

      Guest join settings:


      " config_window.set_user(src.mob) diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 017313141f4..d1702a9f13d 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -111,7 +111,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," //Options bar: mob, details ( admin = 2, undibbsed admin = 3, mentor = 4, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so), // highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name) - msg = "HELP: [get_options_bar(mob, 2, 1, 1, 1, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]" + msg = "[create_text_tag("HELP")][get_options_bar(mob, 2, 1, 1, 1, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]" var/admin_number_present = 0 var/admin_number_afk = 0 @@ -128,7 +128,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," to_chat(C, msg) //show it to the person adminhelping too - to_chat(src, "PM to-Staff : [original_msg]") + to_chat(src, "PM to-Staff : [original_msg]") var/admin_number_active = admin_number_present - admin_number_afk log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins.",admin_key=key_name(src)) diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 735cb06c8b8..ef6c9be6feb 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -3,7 +3,7 @@ set category = null set name = "Admin PM Mob" if(!holder) - to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.") + to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.") return if( !ismob(M) || !M.client ) return cmd_admin_pm(M.client,null) @@ -14,7 +14,7 @@ set category = "Admin" set name = "Admin PM" if(!holder) - to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.") + to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.") return var/list/client/targets[0] for(var/p in clients) @@ -41,8 +41,8 @@ /client/proc/cmd_admin_pm(var/client/C, var/msg = null, var/datum/ticket/ticket = null) if(!istype(C, /client)) - if(holder) to_chat(src, "Error: Private-Message: Client not found.") - else to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!") + if(holder) to_chat(src, "Error: Private-Message: Client not found.") + else to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!") return var/receive_pm_type = "Player" @@ -66,9 +66,9 @@ return if(!C) if(holder) - to_chat(src, "Error: Admin-PM: Client not found.") + to_chat(src, "Error: Admin-PM: Client not found.") else - to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!") + to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!") return if(!check_rights(R_SERVER|R_DEBUG|R_DEV, 0)) @@ -125,21 +125,21 @@ adminhelp(reply) //sender has left, adminhelp instead return - var/sender_message = "" + create_text_tag("pm_out_alt", "PM", src) + " to [get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]" + var/sender_message = "" + create_text_tag("PM <-", src) + " to [get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]" if(holder) sender_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" - sender_message += ": [generate_ahelp_key_words(mob, msg)]" + sender_message += ": [generate_ahelp_key_words(mob, msg)]" else - sender_message += ": [msg]" + sender_message += ": [msg]" sender_message += "" to_chat(src, sender_message) - var/receiver_message = "" + create_text_tag("pm_in", "", C) + " \[[receive_pm_type] PM\] [get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]" + var/receiver_message = "" + create_text_tag("PM ->", C) + " \[[receive_pm_type] PM\] [get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]" if(C.holder) receiver_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" - receiver_message += ": [generate_ahelp_key_words(C.mob, msg)]" + receiver_message += ": [generate_ahelp_key_words(C.mob, msg)]" else - receiver_message += ": [msg]" + receiver_message += ": [msg]" receiver_message += "" to_chat(C, receiver_message) @@ -159,11 +159,11 @@ if(X == C || X == src) continue if(X.key != key && X.key != C.key && (X.holder.rights & (R_ADMIN|R_MOD))) - to_chat(X, "" + create_text_tag("pm_other", "PM:", X) + " [key_name(src, X, 0, ticket)] to [key_name(C, X, 0, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]") + to_chat(X, "" + create_text_tag("PM <->", X) + " [key_name(src, X, 0, ticket)] to [key_name(C, X, 0, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]") /client/proc/cmd_admin_discord_pm(sender) if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Private-Message: You are unable to use PM-s (muted).") + to_chat(src, "Error: Private-Message: You are unable to use PM-s (muted).") return var/msg = input(src,"Message:", "Reply private message to [sender] on Discord") as text|null @@ -177,7 +177,7 @@ post_webhook_event(WEBHOOK_ADMIN_PM, list("title"="Help is requested", "message"="PlayerPM to **[discord_escape(sender)]** from **[discord_escape(key_name(src))]**: ```[discord_escape(html_decode(msg))]```")) discord_bot.send_to_admins("PlayerPM to [discord_escape(sender)] from [discord_escape(key_name(src))]: [discord_escape(html_decode(msg))]") - to_chat(src, "" + create_text_tag("pm_out_alt", "", src) + " to Discord-[sender]: [msg]") + to_chat(src, "" + create_text_tag("PM <-", src) + " to Discord-[sender]: [msg]") log_admin("PM: [key_name(src)]->Discord-[sender]: [msg]") for(var/s in staff) @@ -185,4 +185,4 @@ if(C == src) continue if(C.holder.rights & (R_ADMIN|R_MOD)) - to_chat(C, "" + create_text_tag("pm_other", "PM:", C) + " [key_name(src, C, 0)] to Discord-[sender]: [msg]") + to_chat(C, "" + create_text_tag("PM <->", C) + " [key_name(src, C, 0)] to Discord-[sender]: [msg]") diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 177a58187c9..0c4af18b188 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -13,7 +13,7 @@ for(var/s in staff) var/client/C = s if(R_ADMIN & C.holder.rights) - to_chat(C, "" + create_text_tag("admin", "ADMIN:", C) + " [key_name(usr, 1)]([admin_jump_link(mob, src)]): [msg]") + to_chat(C, "" + create_text_tag("ADMIN", C) + " [key_name(usr, 1)]([admin_jump_link(mob, src)]): [msg]") feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -36,7 +36,7 @@ for(var/s in staff) var/client/C = s if ((R_ADMIN|R_MOD) & C.holder.rights) - to_chat(C, "" + create_text_tag("mod", "MOD:", C) + " [sender_name](JMP): [msg]") + to_chat(C, "" + create_text_tag("MOD", C) + " [sender_name](JMP): [msg]") feedback_add_details("admin_verb","MS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -53,7 +53,7 @@ log_admin("DEV: [key_name(src)] : [msg]",admin_key=key_name(src)) if(check_rights(R_DEV,0)) - msg = "DEV: [key_name(usr, 0, 1, 0)]: [msg]" + msg = "[create_text_tag("DEV")] [key_name(usr, 0, 1, 0)]: [msg]" for(var/s in staff) var/client/C = s if(C.holder.rights & (R_ADMIN|R_DEV)) @@ -72,7 +72,7 @@ log_admin("CCIASAY: [key_name(src)] : [msg]",admin_key=key_name(src)) if(check_rights((R_CCIAA|R_ADMIN),0)) - msg = "CCIAAgent: [key_name(usr, 0, 1, 0)]: [msg]" + msg = "CCIAAgent: [key_name(usr, 0, 1, 0)]: [msg]" for(var/s in staff) var/client/C = s if(C.holder.rights & (R_ADMIN|R_CCIAA)) diff --git a/code/modules/admin/verbs/antag-ooc.dm b/code/modules/admin/verbs/antag-ooc.dm index 47565c992be..b736e78cf80 100644 --- a/code/modules/admin/verbs/antag-ooc.dm +++ b/code/modules/admin/verbs/antag-ooc.dm @@ -22,9 +22,9 @@ for(var/mob/M in mob_list) if (check_rights(R_ADMIN|R_MOD|R_CCIAA, 0, M) && M.client.aooc_mute_holder_check() == FALSE) - to_chat(M, "" + create_text_tag("aooc", "Antag-OOC:", M.client) + " [get_options_bar(src, 0, 1, 1)](JMP): [msg]") + to_chat(M, "" + create_text_tag("A-OOC", M.client) + " [get_options_bar(src, 0, 1, 1)](JMP): [msg]") else if (M.mind && M.mind.special_role && M.client) - to_chat(M, "" + create_text_tag("aooc", "Antag-OOC:", M.client) + " [display_name]: [msg]") + to_chat(M, "" + create_text_tag("A-OOC", M.client) + " [display_name]: [msg]") log_ooc("(ANTAG) [key] : [msg]",ckey=key_name(mob)) diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index bbcd9099725..8306d141372 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -27,6 +27,6 @@ if (!msg) return - say_dead_direct("[stafftype]([src.holder.fakekey ? src.holder.fakekey : src.key]) says, \"[msg]\"") + say_dead_direct("[stafftype]([src.holder.fakekey ? src.holder.fakekey : src.key]) says, \"[msg]\"") feedback_add_details("admin_verb","D") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 524759c0920..731fa95b71b 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -24,16 +24,16 @@ set category = null if(!src.holder) - to_chat(src, "Only Admins may use this command.") + to_chat(src, "Only Admins may use this command.") return var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in clients if(!istype(target,/client)) - to_chat(src, "Error: giveruntimelog(): Client not found.") + to_chat(src, "Error: giveruntimelog(): Client not found.") return target.verbs |= /client/proc/getruntimelog - to_chat(target, "You have been granted access to runtime logs. Please use them responsibly or risk being banned.") + to_chat(target, "You have been granted access to runtime logs. Please use them responsibly or risk being banned.") return diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 7d6db5456f6..eb378a4a2b7 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -81,13 +81,13 @@ var/intercom_range_display_status = 0 for(var/obj/machinery/camera/C1 in CL) if(C1.c_tag == null) - output += "
    8. null c_tag for sec camera at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc])
    9. " + output += "
    10. null c_tag for sec camera at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc])
    11. " for(var/obj/machinery/camera/C2 in CL) if(C1 != C2) if(C1.c_tag == C2.c_tag) - output += "
    12. c_tag match for sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) and \[[C2.x], [C2.y], [C2.z]\] ([C2.loc.loc]) - c_tag is [C1.c_tag]
    13. " + output += "
    14. c_tag match for sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) and \[[C2.x], [C2.y], [C2.z]\] ([C2.loc.loc]) - c_tag is [C1.c_tag]
    15. " if(C1.loc == C2.loc && C1.dir == C2.dir && C1.pixel_x == C2.pixel_x && C1.pixel_y == C2.pixel_y) - output += "
    16. FULLY overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
    17. " + output += "
    18. FULLY overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
    19. " if(C1.loc == C2.loc) output += "
    20. overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
    21. " var/turf/T = get_step(C1,turn(C1.dir,180)) diff --git a/code/modules/admin/verbs/massmodvar.dm b/code/modules/admin/verbs/massmodvar.dm index 9b2bb46bb6f..206ce78364a 100644 --- a/code/modules/admin/verbs/massmodvar.dm +++ b/code/modules/admin/verbs/massmodvar.dm @@ -72,7 +72,7 @@ else if(isicon(var_value)) to_chat(usr, "Variable appears to be ICON.") - var_value = "\icon[var_value]" + var_value = "[icon2html(var_value, usr)]" default = "icon" else if(istype(var_value,/atom) || istype(var_value,/datum)) diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index 90af877ed0e..4bae4199a6f 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -239,7 +239,7 @@ var/list/VVdynamic_lock = list( else if(isicon(variable)) to_chat(usr, "Variable appears to be ICON.") - variable = "\icon[variable]" + variable = "[icon2html(variable, usr)]" default = "icon" else if(istype(variable,/atom) || istype(variable,/datum)) @@ -458,7 +458,7 @@ var/list/VVdynamic_lock = list( else if(isicon(var_value)) to_chat(usr, "Variable appears to be ICON.") - var_value = "\icon[var_value]" + var_value = "[icon2html(var_value, usr)]" class = "icon" else if(istype(var_value,/atom) || istype(var_value,/datum)) @@ -520,7 +520,7 @@ var/list/VVdynamic_lock = list( else if(isicon(var_value)) to_chat(usr, "Variable appears to be ICON.") - var_value = "\icon[var_value]" + var_value = "[icon2html(var_value, usr)]" default = "icon" else if(istype(var_value,/atom) || istype(var_value,/datum)) diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 8c3cc49174e..16cff0bd989 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -13,7 +13,7 @@ return var/image/cross = image('icons/obj/storage.dmi',"bible") - msg = "\icon[cross] PRAY: [key_name(src, 1)] (?) (PP) (VV) (SM) ([admin_jump_link(src, src)]) (CA) (SC): [msg]" + msg = "[icon2html(cross, src)] PRAY: [key_name(src, 1)] (?) (PP) (VV) (SM) ([admin_jump_link(src, src)]) (CA) (SC): [msg]" for(var/s in staff) var/client/C = s diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 25f662392e4..546e71c0bc4 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -190,12 +190,12 @@ proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0) if(!usr || !usr.client) return if(!usr.client.holder) - to_chat(usr, "Error: cmd_admin_mute: You don't have permission to do this.") + to_chat(usr, "Error: cmd_admin_mute: You don't have permission to do this.") return if(!M.client) - to_chat(usr, "Error: cmd_admin_mute: This mob doesn't have a client tied to it.") + to_chat(usr, "Error: cmd_admin_mute: This mob doesn't have a client tied to it.") if(M.client.holder) - to_chat(usr, "Error: cmd_admin_mute: You cannot mute an admin/mod.") + to_chat(usr, "Error: cmd_admin_mute: You cannot mute an admin/mod.") if(!M.client) return if(M.client.holder) return @@ -430,7 +430,7 @@ Traitors and the like can also be revived with the previous role mostly intact. break if(!G_found)//If a ghost was not found. - to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.") + to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.") return var/mob/living/carbon/human/new_character = new(pick(latejoin))//The mob being spawned. @@ -629,7 +629,7 @@ Traitors and the like can also be revived with the previous role mostly intact. command_announcement.Announce("[reportbody]", reporttitle, new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1); if("No") to_world("New [current_map.company_name] Update available at all communication consoles.") - to_world(sound('sound/AI/commandreport.ogg')) + sound_to(world, ('sound/AI/commandreport.ogg')) log_admin("[key_name(src)] has created a command report: [reportbody]",admin_key=key_name(usr)) message_admins("[key_name_admin(src)] has created a command report", 1) diff --git a/code/modules/admin/verbs/warning.dm b/code/modules/admin/verbs/warning.dm index ea405565e0b..5343d704415 100644 --- a/code/modules/admin/verbs/warning.dm +++ b/code/modules/admin/verbs/warning.dm @@ -11,7 +11,7 @@ establish_db_connection(dbcon) if (!dbcon.IsConnected()) - to_chat(usr, "Error: warn(): Database Connection failed, reverting to legacy systems.") + to_chat(usr, "Error: warn(): Database Connection failed, reverting to legacy systems.") usr.client.warn_legacy(warned_ckey) return @@ -50,7 +50,7 @@ feedback_add_details("admin_verb", "WARN-DB") if (C) - to_chat(C, "You have been warned by an administrator.
      Click here to review and acknowledge them!
      ") + to_chat(C, "You have been warned by an administrator.
      Click here to review and acknowledge them!
      ") message_admins("[key_name_admin(src)] has warned [warned_ckey] for: [warning_reason].") @@ -63,7 +63,7 @@ /client/proc/warn_legacy(warned_ckey) if (!warned_ckey) - to_chat(usr, "Error: warn_legacy(): No ckey passed!") + to_chat(usr, "Error: warn_legacy(): No ckey passed!") return var/datum/preferences/D @@ -72,14 +72,14 @@ else D = preferences_datums[warned_ckey] if(!D) - to_chat(src, "Error: warn_legacy(): No such ckey found.") + to_chat(src, "Error: warn_legacy(): No such ckey found.") return if(++D.warns >= MAX_WARNS) //uh ohhhh...you'reee iiiiin trouuuubble O:) ban_unban_log_save("[ckey] warned [warned_ckey], resulting in a [AUTOBANTIME] minute autoban.") if(C) message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban.") - to_chat(C, "You have been autobanned due to a warning by [ckey].
      This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.
      ") + to_chat(C, "You have been autobanned due to a warning by [ckey].
      This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.
      ") qdel(C) else message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban.") @@ -87,7 +87,7 @@ feedback_inc("ban_warn",1) else if(C) - to_chat(C, "You have been warned by an administrator.
      Further warnings will result in an autoban.
      ") + to_chat(C, "You have been warned by an administrator.
      Further warnings will result in an autoban.
      ") message_admins("[key_name_admin(src)] has warned [key_name_admin(C)]. They have [MAX_WARNS-D.warns] strikes remaining.") else message_admins("[key_name_admin(src)] has warned [warned_ckey] (DC). They have [MAX_WARNS-D.warns] strikes remaining.") diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 54cb7bf9616..2c859a776c1 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -24,9 +24,9 @@ var/atom/A = D if(A.icon && A.icon_state) sprite = icon(A.icon, A.icon_state) - to_chat(usr, browse_rsc(sprite, "view_vars_sprite.png")) + send_rsc(usr, sprite, "view_vars_sprite.png") - to_chat(usr, browse_rsc('code/js/view_variables.js', "view_variables.js")) + send_rsc(usr, 'code/js/view_variables.js', "view_variables.js") var/html = {" diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index a04acd70ae4..1080fe9e623 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -58,7 +58,7 @@ return /obj/item/device/onetankbomb/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here. - visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + visible_message("[icon2html(src, viewers(get_turf(src)))] *beep* *beep*", "*beep* *beep*") sleep(10) if(!src) return diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index 8e19f97e205..738cdf95127 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -196,7 +196,7 @@ process_activation(var/obj/D, var/normal = 1, var/special = 1) if(!D) return 0 if(!secured) - visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + visible_message("[icon2html(src, viewers(get_turf(src)))] *beep* *beep*", "*beep* *beep*") if((normal) && (a_right) && (a_left)) if(a_right != D) a_right.pulsed(0) diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index cab1b960070..664ab1ce8dc 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -101,7 +101,7 @@ if((!secured)||(!on)||(cooldown > 0)) return 0 pulse(0) if(!holder) - visible_message("\icon[src] *beep* *beep*") + visible_message("[icon2html(src, viewers(get_turf(src)))] *beep* *beep*") cooldown = 2 addtimer(CALLBACK(src, .proc/process_cooldown), 10) return diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 1481edd047b..774484d9ad8 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -52,12 +52,10 @@ sense() var/turf/mainloc = get_turf(src) -// if(scanning && cooldown <= 0) -// mainloc.visible_message("\icon[src] *boop* *boop*", "*boop* *boop*") if((!holder && !secured)||(!scanning)||(cooldown > 0)) return 0 pulse(0) if(!holder) - mainloc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + mainloc.visible_message("[icon2html(src, viewers(get_turf(src)))] *beep* *beep*", "*beep* *beep*") cooldown = 2 addtimer(CALLBACK(src, .proc/process_cooldown), 10) diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index a5e06a62e60..846908be902 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -139,9 +139,9 @@ pulse(1) if(machine) - machine.visible_message("\icon[machine] [capitalize_first_letters(src.name)] beeps, \"Beep beep!\"") + machine.visible_message("[icon2html(machine, viewers(get_turf(machine)))] [capitalize_first_letters(src.name)] beeps, \"Beep beep!\"") else if(!holder) - visible_message("\icon[src] [capitalize_first_letters(src.name)] beeps, \"Beep beep!\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [capitalize_first_letters(src.name)] beeps, \"Beep beep!\"") return diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 13e4d09a178..03fddb5ff8e 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -42,7 +42,7 @@ if(!secured) return 0 pulse(0) if(!holder) - visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + visible_message("[icon2html(src, viewers(get_turf(src)))] *beep* *beep*", "*beep* *beep*") cooldown = 2 addtimer(CALLBACK(src, .proc/process_cooldown), 10) return diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm index 7b1bf582c7c..15104fdfb29 100644 --- a/code/modules/assembly/voice.dm +++ b/code/modules/assembly/voice.dm @@ -22,7 +22,7 @@ recorded = msg listening = FALSE var/turf/T = get_turf(src) //otherwise it won't work in hand - T.visible_message("\icon[src] beeps, \"Activation message is '[recorded]'.\"") + T.visible_message("[icon2html(src, viewers(get_turf(T)))] beeps, \"Activation message is '[recorded]'.\"") else if(findtext(msg, recorded)) pulse(0) @@ -32,7 +32,7 @@ if(!holder) listening = !listening var/turf/T = get_turf(src) - T.visible_message("\icon[src] beeps, \"[listening ? "Now" : "No longer"] recording input.\"") + T.visible_message("[icon2html(src, viewers(get_turf(T)))] beeps, \"[listening ? "Now" : "No longer"] recording input.\"") /obj/item/device/assembly/voice/attack_self(mob/user) diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm index 78f60aaf740..062e6d4f650 100644 --- a/code/modules/awaymissions/bluespaceartillery.dm +++ b/code/modules/awaymissions/bluespaceartillery.dm @@ -48,7 +48,7 @@ if (src.reload < 180) return if ((user.contents.Find(src) || (in_range(src, user) && istype(src.loc, /turf))) || (istype(user, /mob/living/silicon))) command_announcement.Announce("Bluespace artillery fire detected. Brace for impact.") - to_world(sound('sound/effects/yamato_fire.ogg')) + sound_to(world, ('sound/effects/yamato_fire.ogg')) message_admins("[key_name_admin(usr)] has launched an artillery strike.", 1) explosion(t,2,5,11) reload = 0 diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 8a1ef1cebfe..88ae6a4f82a 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -127,6 +127,12 @@ You can set verify to TRUE if you want send() to sleep until the client has the /proc/register_asset(asset_name, asset) SSassets.cache[asset_name] = asset +//Generated names do not include file extention. +//Used mainly for code that deals with assets in a generic way +//The same asset will always lead to the same asset name +/proc/generate_asset_name(file) + return "asset.[md5(fcopy_rsc(file))]" + //These datums are used to populate the asset cache, the proc "register()" does this. //all of our asset datums, used for referring to these later @@ -231,6 +237,16 @@ var/list/asset_datums = list() /datum/asset/chem_master/send(client) send_asset_list(client, assets) +/datum/asset/simple/accents + verify = FALSE + +/datum/asset/simple/accents/register() + for(var/A in subtypesof(/datum/accent)) //yes we have to do this here, SSrecords isn't initialized yet + var/datum/accent/accent = new A + var/name = "[accent.tag_icon].png" + assets[name] = icon('./icons/accent_tags.dmi', accent.tag_icon) + ..() + /datum/asset/simple/faction_icons assets = list( "faction_EPMC.png" = 'icons/misc/factions/ECFlogo.png', @@ -241,3 +257,48 @@ var/list/asset_datums = list() "faction_Hepht.png" = 'icons/misc/factions/Hephaestuslogo.png', "faction_unaffiliated.png" = 'icons/misc/factions/Unaffiliatedlogo.png' ) + +/datum/asset/group + var/list/children + +/datum/asset/group/register() + for(var/type in children) + get_asset_datum(type) + +/datum/asset/group/send(client/C) + for(var/type in children) + var/datum/asset/A = get_asset_datum(type) + A.send(C) + +/datum/asset/group/goonchat + children = list( + /datum/asset/simple/jquery, + /datum/asset/simple/goonchat, + /datum/asset/simple/fontawesome + ) + +/datum/asset/simple/jquery + verify = FALSE + assets = list( + "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js', + ) + +/datum/asset/simple/goonchat + verify = TRUE + assets = list( + "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', + "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', + "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css' + ) + +/datum/asset/simple/fontawesome + verify = FALSE + assets = list( + "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', + "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', + "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot', + "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff', + "font-awesome.css" = 'html/font-awesome/css/all.min.css', + "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css' + ) diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 7c25c5cddf7..52e377e2c9a 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -77,3 +77,8 @@ var/authed = TRUE var/is_initialized = FALSE // Used to track whether the client has been initialized with InitClient. + + preload_rsc = 0 + + ///goonchat chatoutput of the client + var/datum/chatOutput/chatOutput diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 726bd93416a..8cd1240d983 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -42,8 +42,6 @@ if (!info_sent) handle_connection_info(src, href_list["data"]) info_sent = 1 - else - server_greeting.close_window(src, "Your greeting window has malfunctioned and has been shut down.") return @@ -96,6 +94,11 @@ if("usr") hsrc = mob if("prefs") return prefs.process_link(usr,href_list) if("vars") return view_var_Topic(href,href_list,hsrc) + if("chat") return chatOutput.Topic(href, href_list) + + switch(href_list["action"]) + if("openLink") + send_link(src, href_list["link"]) if(href_list["warnacknowledge"]) var/queryid = text2num(href_list["warnacknowledge"]) @@ -143,13 +146,13 @@ query_details["new_status"] = "confirmed" query_details["id"] = request_id - feedback_message = "Account successfully linked!" + feedback_message = "Account successfully linked!" if ("deny") query_contents = "UPDATE ss13_player_linking SET status = :new_status:, deleted_at = NOW() WHERE id = :id:" query_details["new_status"] = "rejected" query_details["id"] = request_id - feedback_message = "Link request rejected!" + feedback_message = "Link request rejected!" else to_chat(src, "Invalid command sent.") return @@ -210,11 +213,6 @@ if ("webint") src.open_webint() - // Forward appropriate topics to the server greeting datum. - if ("greeting") - if (server_greeting) - server_greeting.handle_call(href_list, src) - // Handle the updating of MotD and Memo tabs upon click. if ("updateHashes") var/save = 0 @@ -308,13 +306,13 @@ //This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc. /client/AllowUpload(filename, filelength) if(filelength > UPLOAD_LIMIT) - to_chat(src, "Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.") + to_chat(src, "Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.") return 0 /* //Don't need this at the moment. But it's here if it's needed later. //Helps prevent multiple files being uploaded at once. Or right after eachother. var/time_to_wait = fileaccess_timer - world.time if(time_to_wait > 0) - to_chat(src, "Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.") + to_chat(src, "Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.") return 0 fileaccess_timer = world.time + FTPDELAY */ return 1 @@ -326,6 +324,9 @@ /client/New(TopicData) TopicData = null //Prevent calls to client.Topic from connect + // Load goonchat + chatOutput = new(src) + if(!(connection in list("seeker", "web"))) //Invalid connection type. return null if(byond_version < MIN_CLIENT_VERSION) //Out of date client. @@ -355,6 +356,7 @@ m.client = src src.InitPrefs() //Init some default prefs m.LateLogin() + chatOutput.start() return m //Do auth shit else @@ -362,6 +364,7 @@ src.InitClient() src.InitPrefs() mob.LateLogin() + chatOutput.start() /client/proc/InitPrefs() //preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum) @@ -376,12 +379,6 @@ prefs.last_id = computer_id //these are gonna be used for banning if (byond_version >= 511 && prefs.clientfps) fps = prefs.clientfps - if(SStheming) - SStheming.apply_theme_from_perfs(src) - - // Server greeting shenanigans. - if (server_greeting.find_outdated_info(src, 1) && !info_sent) - server_greeting.display_to_client(src) /client/proc/InitClient() to_chat(src, "If the title screen is black, resources are still downloading. Please be patient until the title screen appears.") @@ -686,15 +683,6 @@ send_link(src, linkURL) return -/client/verb/show_greeting() - set name = "Open Greeting" - set category = "OOC" - - // Update the information just in case. - server_greeting.find_outdated_info(src, 1) - - server_greeting.display_to_client(src) - /client/proc/check_ip_intel() set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep if (config.ipintel_email) @@ -751,4 +739,4 @@ if(istype(gun) && gun.can_autofire()) M.set_dir(get_dir(M, over_object)) gun.Fire(get_turf(over_object), mob, params, (get_dist(over_object, mob) <= 1), FALSE) - CHECK_TICK \ No newline at end of file + CHECK_TICK diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm new file mode 100644 index 00000000000..0b2c074be18 --- /dev/null +++ b/code/modules/client/darkmode.dm @@ -0,0 +1,132 @@ +//Darkmode preference by Kmc2000// + +/* +This lets you switch chat themes by using winset and CSS loading, you must relog to see this change (or rebuild your browseroutput datum) +Things to note: +If you change ANYTHING in interface/skin.dmf you need to change it here: +Format: +winset(src, "window as appears in skin.dmf after elem", "var to change = currentvalue;var to change = desired value") +How this works: +I've added a function to browseroutput.js which registers a cookie for darkmode and swaps the chat accordingly. You can find the button to do this under the "cog" icon next to the ping button (top right of chat) +This then swaps the window theme automatically +Thanks to spacemaniac and mcdonald for help with the JS side of this. +*/ + +/client/proc/force_white_theme() //There's no way round it. We're essentially changing the skin by hand. It's painful but it works, and is the way Lummox suggested. + //Main windows + winset(src, "infowindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "infowindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "rpane", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "rpane", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "info", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "info", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "browseroutput", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "browseroutput", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "outputwindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "rpanewindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "rpanewindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "mainwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = none") + winset(src, "split", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "mainvsplit", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + //Buttons + winset(src, "textb", "background-color = #494949;background-color = none") + winset(src, "textb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "infob", "background-color = #494949;background-color = none") + winset(src, "infob", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "rulesb", "background-color = #494949;background-color = none") + winset(src, "rulesb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "Lore", "background-color = #494949;background-color = none") + winset(src, "Lore", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "wikib", "background-color = #494949;background-color = none") + winset(src, "wikib", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "forumb", "background-color = #494949;background-color = none") + winset(src, "forumb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "changelog", "background-color = #494949;background-color = none") + winset(src, "changelog", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "interfaceb", "background-color = #494949;background-color = none") + winset(src, "interfaceb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "discordb", "background-color = #494949;background-color = none") + winset(src, "discordb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "reportbugb", "background-color = #494949;background-color = none") + winset(src, "reportbugb", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "hotkey_toggle", "background-color = #494949;background-color = none") + winset(src, "hotkey_toggle", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + //Status and verb tabs + winset(src, "output", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "output", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "outputwindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "statwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "statwindow", "text-color = #eaeaea;text-color = #000000") + winset(src, "info", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = #FFFFFF") + winset(src, "info", "tab-background-color = [COLOR_DARKMODE_BACKGROUND];tab-background-color = none") + winset(src, "info", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "info", "tab-text-color = [COLOR_DARKMODE_TEXT];tab-text-color = #000000") + winset(src, "info", "prefix-color = [COLOR_DARKMODE_TEXT];prefix-color = #000000") + winset(src, "info", "suffix-color = [COLOR_DARKMODE_TEXT];suffix-color = #000000") + //Say, OOC, me Buttons etc. + winset(src, "saybutton", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "saybutton", "text-color = [COLOR_DARKMODE_TEXT];text-color = #000000") + winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = none") + +/client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing + //Main windows + winset(src, "infowindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "infowindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "rpane", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "rpane", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "info", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "browseroutput", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "browseroutput", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "outputwindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "outputwindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "rpanewindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "rpanewindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "mainwindow", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "split", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "mainvsplit", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + //Buttons + winset(src, "textb", "background-color = none;background-color = #494949") + winset(src, "textb", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "infob", "background-color = none;background-color = #494949") + winset(src, "infob", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "rulesb", "background-color = none;background-color = #494949") + winset(src, "rulesb", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "Lore", "background-color = none;background-color = #494949") + winset(src, "Lore", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "wikib", "background-color = none;background-color = #494949") + winset(src, "wikib", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "forumb", "background-color = none;background-color = #494949") + winset(src, "forumb", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "changelog", "background-color = none;background-color = #494949") + winset(src, "changelog", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "interfaceb", "background-color = none;background-color = #494949") + winset(src, "interfaceb", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "discordb", "background-color = none;background-color = #494949") + winset(src, "discordb", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "reportbugb", "background-color = none;background-color = #494949") + winset(src, "reportbugb", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "hotkey_toggle", "background-color = none;background-color = #494949") + winset(src, "hotkey_toggle", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + //Status and verb tabs + winset(src, "output", "background-color = none;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "output", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "outputwindow", "background-color = none;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "outputwindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "statwindow", "background-color = none;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "statwindow", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "background-color = #FFFFFF;background-color = [COLOR_DARKMODE_DARKBACKGROUND]") + winset(src, "info", "tab-background-color = none;tab-background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "info", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "tab-text-color = #000000;tab-text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "prefix-color = #000000;prefix-color = [COLOR_DARKMODE_TEXT]") + winset(src, "info", "suffix-color = #000000;suffix-color = [COLOR_DARKMODE_TEXT]") + //Say, OOC, me Buttons etc. + winset(src, "saybutton", "background-color = none;background-color = #494949") + winset(src, "saybutton", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + winset(src, "asset_cache_browser", "background-color = none;background-color = [COLOR_DARKMODE_BACKGROUND]") + winset(src, "asset_cache_browser", "text-color = #000000;text-color = [COLOR_DARKMODE_TEXT]") + diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 463dc5c6a43..f4af2292b35 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -699,7 +699,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O if(current_species.preview_icon) var/icon/preview = icon(current_species.preview_icon, "") preview.Scale(64, 64) // Scale it here to stop it blurring. - to_chat(usr, browse_rsc(icon(icon = preview, icon_state = ""), "species_preview_[current_species.short_name].png")) + send_rsc(usr, icon(icon = preview, icon_state = ""), "species_preview_[current_species.short_name].png") dat += "

      " dat += "Language: [current_species.language]
      " dat += "" @@ -740,9 +740,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O if(restricted) if(restricted == 1) - dat += "You cannot play as this species.
      If you wish to be whitelisted, you can make an application post on the forums.

      " + dat += "You cannot play as this species.
      If you wish to be whitelisted, you can make an application post on the forums.

      " else if(restricted == 2) - dat += "You cannot play as this species.
      This species is not available for play as a station race.

      " + dat += "You cannot play as this species.
      This species is not available for play as a station race.

      " if(!restricted || check_rights(R_ADMIN, 0)) dat += "\[select\]" dat += "" diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/client/preference_setup/global/01_ui.dm index d80aa5e437a..c389942ee72 100644 --- a/code/modules/client/preference_setup/global/01_ui.dm +++ b/code/modules/client/preference_setup/global/01_ui.dm @@ -7,7 +7,6 @@ S["UI_style_color"] >> pref.UI_style_color S["UI_style_alpha"] >> pref.UI_style_alpha S["html_UI_style"] >> pref.html_UI_style - S["skin_theme"] >> pref.skin_theme S["ooccolor"] >> pref.ooccolor S["clientfps"] >> pref.clientfps @@ -16,7 +15,6 @@ S["UI_style_color"] << pref.UI_style_color S["UI_style_alpha"] << pref.UI_style_alpha S["html_UI_style"] << pref.html_UI_style - S["skin_theme"] << pref.skin_theme S["ooccolor"] << pref.ooccolor S["clientfps"] << pref.clientfps @@ -28,7 +26,6 @@ "UI_style_color", "UI_style_alpha", "html_UI_style", - "skin_theme", "ooccolor", "clientfps", "tooltip_style" @@ -47,7 +44,6 @@ "UI_style_color", "UI_style_alpha", "html_UI_style", - "skin_theme", "ooccolor", "clientfps", "tooltip_style", @@ -62,7 +58,6 @@ "UI_style_color" = pref.UI_style_color, "UI_style" = pref.UI_style, "html_UI_style" = pref.html_UI_style, - "skin_theme" = pref.skin_theme, "ooccolor" = pref.ooccolor, "clientfps" = pref.clientfps, "tooltip_style" = pref.tooltip_style @@ -74,7 +69,6 @@ pref.UI_style_alpha = sanitize_integer(text2num(pref.UI_style_alpha), 0, 255, initial(pref.UI_style_alpha)) pref.clientfps = sanitize_integer(text2num(pref.clientfps), 0, 1000, initial(pref.clientfps)) pref.html_UI_style = sanitize_inlist(pref.html_UI_style, SStheming.available_html_themes, initial(pref.html_UI_style)) - pref.skin_theme = sanitize_inlist(pref.skin_theme, SStheming.skin_themes, initial(pref.skin_theme)) pref.ooccolor = sanitize_hexcolor(pref.ooccolor, initial(pref.ooccolor)) /datum/category_item/player_setup_item/player_global/ui/content(mob/user) @@ -86,7 +80,6 @@ dat += "-Alpha(transparency): [pref.UI_style_alpha] - reset
      " dat += "Tooltip Style: [pref.tooltip_style]
      " dat += "HTML UI Style: [pref.html_UI_style]
      " - dat += "Main UI Style: [pref.skin_theme]
      " dat += "-FPS: [pref.clientfps] - reset
      " if(can_select_ooc_color(user)) dat += "OOC Color: " @@ -122,14 +115,6 @@ pref.html_UI_style = html_style_new return TOPIC_REFRESH - else if(href_list["select_skin_theme"]) - var/skin_theme_new = input(user, "Choose HTML UI style.", "Global Preference", pref.skin_theme) as null|anything in SStheming.skin_themes - if(isnull(skin_theme_new) || !CanUseTopic(user)) return TOPIC_NOACTION - pref.skin_theme = skin_theme_new - if(SStheming) - SStheming.apply_theme_from_perfs(user) - return TOPIC_REFRESH - else if(href_list["select_ooc_color"]) var/new_ooccolor = input(user, "Choose OOC color:", "Global Preference") as color|null if(new_ooccolor && can_select_ooc_color(user) && CanUseTopic(user)) diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm index 433b5f5d380..e589e37fa77 100644 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -234,7 +234,7 @@ switch(pref.alternate_option) if(BE_ASSISTANT) - dat += "

      Be assistant if preference unavailable

      " + dat += "

      Be assistant if preference unavailable

      " if(RETURN_TO_LOBBY) dat += "

      Return to lobby if preference unavailable

      " diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 90dfe20752c..afa45cff5a1 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -27,7 +27,6 @@ datum/preferences var/UI_style_color = "#ffffff" var/UI_style_alpha = 255 var/html_UI_style = "Nano" - var/skin_theme = "Light" //Style for popup tooltips var/tooltip_style = "Midnight" var/motd_hash = "" //Hashes for the new server greeting window. diff --git a/code/modules/client/preferences_ambience.dm b/code/modules/client/preferences_ambience.dm index 514524a8f76..e66d78d8253 100644 --- a/code/modules/client/preferences_ambience.dm +++ b/code/modules/client/preferences_ambience.dm @@ -27,7 +27,7 @@ if(prefs.asfx_togs & ASFX_AMBIENCE) to_chat(src, "You will now hear ambient sounds.") else - to_chat(src, "You will no longer hear ambient sounds.") + to_chat(src, "You will no longer hear ambient sounds.") src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1) src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2) feedback_add_details("admin_verb","TSFXAmbi") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -42,7 +42,7 @@ if(prefs.asfx_togs & ASFX_FOOTSTEPS) to_chat(src, "You will now hear footstep sounds.") else - to_chat(src, "You will no longer hear footstep sounds.") + to_chat(src, "You will no longer hear footstep sounds.") feedback_add_details("admin_verb","TSFXFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/Toggle_asfx_vote() @@ -54,7 +54,7 @@ if(prefs.asfx_togs & ASFX_VOTE) to_chat(src, "You will now hear the vote alarm.") else - to_chat(src, "You will no longer hear the vote alarm.") + to_chat(src, "You will no longer hear the vote alarm.") feedback_add_details("admin_verb","TSFXFV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/toggle_vox_voice() @@ -76,7 +76,7 @@ if(prefs.asfx_togs & ASFX_DROPSOUND) to_chat(src, "You will now hear dropping and throwing sounds.") else - to_chat(src, "You will no longer hear dropping and throwing sounds.") + to_chat(src, "You will no longer hear dropping and throwing sounds.") /client/proc/Toggle_arcadesounds() set name = "Toggle Arcade SFX" @@ -88,7 +88,7 @@ if(prefs.asfx_togs & ASFX_ARCADE) to_chat(src, "You will now hear arcade sounds.") else - to_chat(src, "You will no longer hear arcade sounds.") + to_chat(src, "You will no longer hear arcade sounds.") /client/proc/Toggle_radiosounds() set name = "Toggle Radio SFX" @@ -100,7 +100,7 @@ if(prefs.asfx_togs & ASFX_RADIO) to_chat(src, "You will now hear radio sounds.") else - to_chat(src, "You will no longer hear radio sounds.") + to_chat(src, "You will no longer hear radio sounds.") /client/proc/Toggle_instrumentsounds() set name = "Toggle Instrument SFX" @@ -112,4 +112,4 @@ if(prefs.asfx_togs & ASFX_INSTRUMENT) to_chat(src, "You will now hear instrument sounds.") else - to_chat(src, "You will no longer hear instrument sounds.") \ No newline at end of file + to_chat(src, "You will no longer hear instrument sounds.") \ No newline at end of file diff --git a/code/modules/client/preferences_notification.dm b/code/modules/client/preferences_notification.dm index f8b30b51718..32af64c2d0d 100644 --- a/code/modules/client/preferences_notification.dm +++ b/code/modules/client/preferences_notification.dm @@ -205,7 +205,7 @@ if(panel_notification) new_notification("warning","You have [notification_count] unread notifications! Click here to review and acknowledge them!") if(chat_notification) - to_chat(user,"You have unacknowledged notifications.
      Click here to review and acknowledge them!
      ") + to_chat(user,"You have unacknowledged notifications.
      Click here to review and acknowledge them!
      ") /* * Helper proc for getting a count of active CCIA actions against the player's characters. diff --git a/code/modules/clothing/spacesuits/rig/modules/computer.dm b/code/modules/clothing/spacesuits/rig/modules/computer.dm index 89b2084564d..094ab4fd41c 100644 --- a/code/modules/clothing/spacesuits/rig/modules/computer.dm +++ b/code/modules/clothing/spacesuits/rig/modules/computer.dm @@ -215,8 +215,8 @@ else user.drop_from_inventory(ai,src) ai_card = ai - to_chat(ai_mob, "You have been transferred to \the [holder]'s [src].") - to_chat(user, "You load [ai_mob] into \the [holder]'s [src].") + to_chat(ai_mob, "You have been transferred to \the [holder]'s [src].") + to_chat(user, "You load [ai_mob] into \the [holder]'s [src].") integrated_ai = ai_mob diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index f3a03d8121b..5b24377e2ec 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -91,17 +91,17 @@ var/list/species_restricted = list(BODYTYPE_HUMAN,BODYTYPE_TAJARA,BODYTYPE_UNATHI, BODYTYPE_SKRELL, BODYTYPE_IPC, BODYTYPE_IPC_BISHOP, BODYTYPE_IPC_ZENGHU) /obj/item/rig/examine() - to_chat(usr, "This is \icon[src][src.name].") + to_chat(usr, "This is [icon2html(src, usr)][src.name].") to_chat(usr, "[src.desc]") if(wearer) for(var/obj/item/piece in list(helmet,gloves,chest,boots)) if(!piece || piece.loc != wearer) continue - to_chat(usr, "\icon[piece] \The [piece] [piece.gender == PLURAL ? "are" : "is"] deployed.") + to_chat(usr, "[icon2html(piece, usr)] \The [piece] [piece.gender == PLURAL ? "are" : "is"] deployed.") if(src.loc == usr) to_chat(usr, "The maintenance panel is [open ? "open" : "closed"].") - to_chat(usr, "Hardsuit systems are [offline ? "offline" : "online"].") + to_chat(usr, "Hardsuit systems are [offline ? "offline" : "online"].") /obj/item/rig/Initialize() . = ..() @@ -232,7 +232,7 @@ if(!failed_to_seal) if(!instant) - wearer.visible_message("[wearer]'s suit emits a quiet hum as it begins to adjust its seals.","With a quiet hum, the suit begins running checks and adjusting components.") + wearer.visible_message("[wearer]'s suit emits a quiet hum as it begins to adjust its seals.","With a quiet hum, the suit begins running checks and adjusting components.") if(seal_delay && !do_after(wearer, seal_delay, act_target = src)) if(wearer) to_chat(wearer, "You must remain still while the suit is adjusting the components.") playsound(src, 'sound/items/rfd_empty.ogg', 20, FALSE) @@ -266,16 +266,16 @@ piece.item_state = "[initial(icon_state)][!seal_target ? "_sealed" : ""]" switch(msg_type) if("boots") - to_chat(wearer, "\The [piece] [!seal_target ? "seal around your feet" : "relax their grip on your legs"].") + to_chat(wearer, "\The [piece] [!seal_target ? "seal around your feet" : "relax their grip on your legs"].") wearer.update_inv_shoes() if("gloves") - to_chat(wearer, "\The [piece] [!seal_target ? "tighten around your fingers and wrists" : "become loose around your fingers"].") + to_chat(wearer, "\The [piece] [!seal_target ? "tighten around your fingers and wrists" : "become loose around your fingers"].") wearer.update_inv_gloves() if(BP_CHEST) - to_chat(wearer, "\The [piece] [!seal_target ? "cinches tight again your chest" : "releases your chest"].") + to_chat(wearer, "\The [piece] [!seal_target ? "cinches tight again your chest" : "releases your chest"].") wearer.update_inv_wear_suit() if("helmet") - to_chat(wearer, "\The [piece] hisses [!seal_target ? "closed" : "open"].") + to_chat(wearer, "\The [piece] hisses [!seal_target ? "closed" : "open"].") wearer.update_inv_head() if(helmet) helmet.update_light(wearer) @@ -309,17 +309,17 @@ // Success! canremove = seal_target - to_chat(wearer, "Your entire suit [canremove ? "loosens as the components relax" : "tightens around you as the components lock into place"].") + to_chat(wearer, "Your entire suit [canremove ? "loosens as the components relax" : "tightens around you as the components lock into place"].") playsound(src, 'sound/items/rped.ogg', 20, FALSE) if (has_sealed_state) icon_state = canremove ? initial(icon_state) : "[initial(icon_state)]_sealed" if(dnaLock && !offline) if(dnaLock != wearer.dna) - visible_message("\icon[src.icon] [src] announces, \"DNA mismatch. Unauthorized access detected.\"") + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] announces, \"DNA mismatch. Unauthorized access detected.\"") crushing = TRUE if(wearer != initiator) - to_chat(initiator, "Suit adjustment complete. Suit is now [canremove ? "unsealed" : "sealed"].") + to_chat(initiator, "Suit adjustment complete. Suit is now [canremove ? "unsealed" : "sealed"].") if(canremove) for(var/obj/item/rig_module/module in installed_modules) @@ -613,7 +613,7 @@ ..() if(seal_delay > 0 && istype(M) && M.back == src) - M.visible_message("[M] starts putting on \the [src]...", "You start putting on \the [src]...") + M.visible_message("[M] starts putting on \the [src]...", "You start putting on \the [src]...") if(!do_after(M,seal_delay)) if(M && M.back == src) if(!M.unEquip(src)) @@ -622,7 +622,7 @@ return if(istype(M) && M.back == src) - M.visible_message("[M] struggles into \the [src].", "You struggle into \the [src].") + M.visible_message("[M] struggles into \the [src].", "You struggle into \the [src].") wearer = M wearer.wearing_rig = src update_icon() diff --git a/code/modules/clothing/spacesuits/rig/rig_verbs.dm b/code/modules/clothing/spacesuits/rig/rig_verbs.dm index 6f6f7c563e9..bc805048277 100644 --- a/code/modules/clothing/spacesuits/rig/rig_verbs.dm +++ b/code/modules/clothing/spacesuits/rig/rig_verbs.dm @@ -218,11 +218,11 @@ if(!istype(module)) selected_module = null - to_chat(usr, "Primary system is now: deselected.") + to_chat(usr, "Primary system is now: deselected.") return selected_module = module - to_chat(usr, "Primary system is now: [selected_module.interface_name].") + to_chat(usr, "Primary system is now: [selected_module.interface_name].") /obj/item/rig/verb/toggle_module() diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index 82e51fb4b50..9b796246511 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -96,7 +96,7 @@ /obj/item/clothing/suit/bomb_suit/equipped(var/mob/user, var/slot) if (slot == slot_wear_suit) var/mob/living/carbon/human/H = user - H.visible_message("[H] starts putting on \the [src]...", "You start putting on \the [src]...") + H.visible_message("[H] starts putting on \the [src]...", "You start putting on \the [src]...") if(!do_after(H,50)) if(H && H.wear_suit == src) H.wear_suit = null diff --git a/code/modules/detectivework/microscope/dnascanner.dm b/code/modules/detectivework/microscope/dnascanner.dm index 54674dd9629..745fc7b7632 100644 --- a/code/modules/detectivework/microscope/dnascanner.dm +++ b/code/modules/detectivework/microscope/dnascanner.dm @@ -99,7 +99,7 @@ last_process_worldtime = world.time /obj/machinery/dnaforensics/proc/complete_scan() - visible_message("\icon[src] makes an insistent chime.", range = 2) + visible_message("[icon2html(src, viewers(get_turf(src)))] makes an insistent chime.", range = 2) update_icon() if(bloodsamp) var/obj/item/paper/P = new() diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm index 7d19598f6d0..d6e4030b1d4 100644 --- a/code/modules/economy/ATM.dm +++ b/code/modules/economy/ATM.dm @@ -100,14 +100,14 @@ log transactions //display a message to the user var/response = pick("Initiating withdraw. Have a nice day!", "CRITICAL ERROR: Activating cash chamber panic siphon.","PIN Code accepted! Emptying account balance.", "Jackpot!") - to_chat(user, "\icon[src] The [src] beeps: \"[response]\"") + to_chat(user, "[icon2html(src, user)] The [src] beeps: \"[response]\"") return 1 /obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/card)) if(emagged) //prevent inserting id into an emagged ATM - to_chat(user, "\icon[src] CARD READER ERROR. This system has been compromised!") + to_chat(user, "[icon2html(src, user)] CARD READER ERROR. This system has been compromised!") return else if(istype(I,/obj/item/card/emag)) I.resolve_attackby(src, user) @@ -148,7 +148,7 @@ log transactions /obj/machinery/atm/attack_hand(mob/user as mob) if(istype(user, /mob/living/silicon)) - to_chat(user, "\icon[src] Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per system banking regulation #1005.") + to_chat(user, "[icon2html(src, user)] Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per system banking regulation #1005.") return if(get_dist(src,user) <= 1) @@ -259,7 +259,7 @@ log transactions var/target_account_number = text2num(href_list["target_acc_number"]) var/transfer_purpose = href_list["purpose"] if(SSeconomy.charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount)) - to_chat(usr, "\icon[src]Funds transfer successful.") + to_chat(usr, "[icon2html(src, usr)]Funds transfer successful.") authenticated_account.money -= transfer_amount //create an entry in the account transaction log @@ -272,10 +272,10 @@ log transactions T.amount = "([transfer_amount])" SSeconomy.add_transaction_log(authenticated_account,T) else - to_chat(usr, "\icon[src]Funds transfer failed.") + to_chat(usr, "[icon2html(src, usr)]Funds transfer failed.") else - to_chat(usr, "\icon[src]You don't have enough funds to do that!") + to_chat(usr, "[icon2html(src, usr)]You don't have enough funds to do that!") if("view_screen") view_screen = text2num(href_list["view_screen"]) if("change_security_level") @@ -294,7 +294,7 @@ log transactions var/tried_pin = text2num(href_list["account_pin"]) var/datum/money_account/potential_account = SSeconomy.get_account(tried_account_num) if (!potential_account) - to_chat(usr, "\icon[src] Account number not found.") + to_chat(usr, "[icon2html(src, usr)] Account number not found.") number_incorrect_tries++ handle_lockdown() return @@ -311,7 +311,7 @@ log transactions else to_chat(usr, "Account card not found.") if (!authenticated_account) number_incorrect_tries++ - to_chat(usr, "\icon[src] Incorrect pin/account combination entered, [(max_pin_attempts+1) - number_incorrect_tries] attempts remaining.") + to_chat(usr, "[icon2html(src, usr)] Incorrect pin/account combination entered, [(max_pin_attempts+1) - number_incorrect_tries] attempts remaining.") handle_lockdown(tried_account_num) else SSeconomy.bank_log_access(authenticated_account, machine_id) @@ -319,7 +319,7 @@ log transactions playsound(src, 'sound/machines/twobeep.ogg', 50, 1) ticks_left_timeout = 120 view_screen = NO_SCREEN - to_chat(usr, " \icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'") + to_chat(usr, " [icon2html(src, usr)] Access granted. Welcome user '[authenticated_account.owner_name].'") previous_account_number = tried_account_num if("e_withdrawal") @@ -347,7 +347,7 @@ log transactions T.time = worldtime2text() SSeconomy.add_transaction_log(authenticated_account,T) else - to_chat(usr, "\icon[src]You don't have enough funds to do that!") + to_chat(usr, "[icon2html(src, usr)]You don't have enough funds to do that!") if("withdrawal") var/amount = max(text2num(href_list["funds_amount"]),0) amount = round(amount, 0.01) @@ -372,7 +372,7 @@ log transactions T.time = worldtime2text() SSeconomy.add_transaction_log(authenticated_account,T) else - to_chat(usr, "\icon[src]You don't have enough funds to do that!") + to_chat(usr, "[icon2html(src, usr)]You don't have enough funds to do that!") if("balance_statement") if(authenticated_account) var/obj/item/paper/R = new() @@ -452,7 +452,7 @@ log transactions if(!held_card) //this might happen if the user had the browser window open when somebody emagged it if(emagged) - to_chat(usr, "\icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!") + to_chat(usr, "[icon2html(src, usr)] The ATM card reader rejected your ID because this machine has been sabotaged!") else var/obj/item/I = usr.get_active_hand() if (istype(I, /obj/item/card/id)) @@ -480,7 +480,7 @@ log transactions if(I) authenticated_account = SSeconomy.attempt_account_access(I.associated_account_number) if(authenticated_account) - to_chat(human_user, "\icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'") + to_chat(human_user, "[icon2html(src, usr)] Access granted. Welcome user '[authenticated_account.owner_name].'") //create a transaction log entry var/datum/transaction/T = new() diff --git a/code/modules/economy/EFTPOS.dm b/code/modules/economy/EFTPOS.dm index c878eafc3dd..5ab16c09d9d 100644 --- a/code/modules/economy/EFTPOS.dm +++ b/code/modules/economy/EFTPOS.dm @@ -111,7 +111,7 @@ else user << browse(null,"window=eftpos") -/obj/item/device/eftpos/attackby(obj/item/O as obj, user as mob) +/obj/item/device/eftpos/attackby(var/obj/item/O, var/mob/user) var/obj/item/card/id/I = O.GetID() @@ -119,7 +119,7 @@ if(linked_account) scan_card(I, O) else - to_chat(usr, "\icon[src]Unable to connect to linked account.") + to_chat(user, "[icon2html(src, user)]Unable to connect to linked account.") else if (istype(O, /obj/item/spacecash/ewallet)) var/obj/item/spacecash/ewallet/E = O if (linked_account) @@ -127,7 +127,7 @@ if(transaction_locked && !transaction_paid) if(transaction_amount <= E.worth) playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("\icon[src] \The [src] chimes.") + src.visible_message("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes.") transaction_paid = 1 //transfer the money @@ -144,11 +144,11 @@ T.time = worldtime2text() SSeconomy.add_transaction_log(linked_account,T) else - to_chat(usr, "\icon[src]\The [O] doesn't have that much money!") + to_chat(user, "[icon2html(src, user)]\The [O] doesn't have that much money!") else - to_chat(usr, "\icon[src]Connected account has been suspended.") + to_chat(user, "[icon2html(src, user)]Connected account has been suspended.") else - to_chat(usr, "\icon[src]EFTPOS is not connected to an account.") + to_chat(user, "[icon2html(src, user)]EFTPOS is not connected to an account.") else ..() @@ -166,14 +166,14 @@ alert("That is not a valid code!") print_reference() else - to_chat(usr, "\icon[src]Incorrect code entered.") + to_chat(usr, "[icon2html(src, usr)]Incorrect code entered.") if("change_id") var/attempt_code = text2num(input("Re-enter the current EFTPOS access code", "Confirm EFTPOS code")) if(attempt_code == access_code) eftpos_name = sanitize(input("Enter a new terminal ID for this device", "Enter new EFTPOS ID"), MAX_NAME_LEN) + " EFTPOS scanner" print_reference() else - to_chat(usr, "\icon[src]Incorrect code entered.") + to_chat(usr, "[icon2html(src, usr)]Incorrect code entered.") if("link_account") if (!prelocked_account) var/attempt_account_num = input("Enter account number to pay EFTPOS charges into", "New account number") as num @@ -182,9 +182,9 @@ if(linked_account) if(linked_account.suspended) linked_account = null - to_chat(usr, "\icon[src]Account has been suspended.") + to_chat(usr, "[icon2html(src, usr)]Account has been suspended.") else - to_chat(usr, "\icon[src]Account not found.") + to_chat(usr, "[icon2html(src, usr)]Account not found.") if("trans_purpose") var/choice = sanitize(input("Enter reason for EFTPOS transaction", "Transaction purpose")) if(choice) transaction_purpose = choice @@ -207,14 +207,14 @@ else if(linked_account) transaction_locked = 1 else - to_chat(usr, "\icon[src]No account connected to send transactions to.") + to_chat(usr, "[icon2html(src, usr)]No account connected to send transactions to.") if("scan_card") if(linked_account) var/obj/item/I = usr.get_active_hand() if (istype(I, /obj/item/card)) scan_card(I) else - to_chat(usr, "\icon[src]Unable to link accounts.") + to_chat(usr, "[icon2html(src, usr)]Unable to link accounts.") if("reset") //reset the access code - requires HoP/captain access var/obj/item/I = usr.get_active_hand() @@ -222,10 +222,10 @@ var/obj/item/card/id/C = I if((access_cent_captain in C.access) || (access_hop in C.access) || (access_captain in C.access)) access_code = 0 - to_chat(usr, "\icon[src]Access code reset to 0.") + to_chat(usr, "[icon2html(src, usr)]Access code reset to 0.") else if (istype(I, /obj/item/card/emag)) access_code = 0 - to_chat(usr, "\icon[src]Access code reset to 0.") + to_chat(usr, "[icon2html(src, usr)]Access code reset to 0.") src.attack_self(usr) @@ -241,21 +241,21 @@ var/message = SSeconomy.transfer_money(C.associated_account_number, linked_account.account_number, transaction_purpose, machine_id, transaction_amount, null, usr) if(message) - to_chat(usr,"\icon[src][message].") + to_chat(usr,"[icon2html(src, usr)][message].") else playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("\icon[src] \The [src] chimes.") + src.visible_message("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes.") transaction_paid = 1 else - to_chat(usr, "\icon[src]EFTPOS is not connected to an account.") + to_chat(usr, "[icon2html(src, usr)]EFTPOS is not connected to an account.") else if (istype(I, /obj/item/card/emag)) if(transaction_locked) if(transaction_paid) - to_chat(usr, "\icon[src]You stealthily swipe \the [I] through \the [src].") + to_chat(usr, "[icon2html(src, usr)]You stealthily swipe \the [I] through \the [src].") transaction_locked = 0 transaction_paid = 0 else usr.visible_message("\The [usr] swipes a card through \the [src].") playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("\icon[src] \The [src] chimes.") + src.visible_message("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes.") transaction_paid = 1 diff --git a/code/modules/economy/quikpay.dm b/code/modules/economy/quikpay.dm index 565b3219a4b..d2d7780b0f0 100644 --- a/code/modules/economy/quikpay.dm +++ b/code/modules/economy/quikpay.dm @@ -112,10 +112,10 @@ var/transaction = SSeconomy.transfer_money(I.associated_account_number, SSeconomy.get_department_account(destinationact)?.account_number,transaction_purpose,transaction_terminal,transaction_amount,null,usr) if(transaction) - to_chat(usr,"\icon[src][transaction].") + to_chat(user,"[icon2html(src, user)][transaction].") else playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("\icon[src] \The [src] chimes.") + src.visible_message("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes.") print_receipt() sum = 0 receipt = "" diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm index c5962eb125b..1f6f920d5f1 100644 --- a/code/modules/events/money_spam.dm +++ b/code/modules/events/money_spam.dm @@ -177,7 +177,8 @@ if (!P.message_silent) playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1) for (var/mob/O in hearers(3, P.loc)) - if(!P.message_silent) O.show_message(text("\icon[P] *[P.ttone]*")) + if(!P.message_silent) + O.show_message(text("[icon2html(P, O)] *[P.ttone]*")) //Search for holder of the PDA. var/mob/living/L = null if(P.loc && isliving(P.loc)) @@ -187,4 +188,4 @@ L = get(P, /mob/living/silicon) if(L) - to_chat(L, "\icon[P] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)") + to_chat(L, "[icon2html(P, L)] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)") diff --git a/code/modules/examine/examine.dm b/code/modules/examine/examine.dm index 6d542852c41..030a42942c2 100644 --- a/code/modules/examine/examine.dm +++ b/code/modules/examine/examine.dm @@ -53,7 +53,7 @@ description_holders["cult"] = show_cult_info ? A.get_description_cult() : "" description_holders["name"] = "[A.name]" - description_holders["icon"] = "\icon[A]" + description_holders["icon"] = "[icon2html(A, usr)]" description_holders["desc"] = A.desc /client/Stat() diff --git a/code/modules/games/boardgame.dm b/code/modules/games/boardgame.dm index 6bfee62afac..269a028a9bb 100644 --- a/code/modules/games/boardgame.dm +++ b/code/modules/games/boardgame.dm @@ -111,7 +111,7 @@ if(board["[i]"]) var/obj/item/I = board["[i]"] - to_chat(user, browse_rsc(board_icons["[I.icon] [I.icon_state]"],"[I.icon_state].png")) + send_rsc(user, board_icons["[I.icon] [I.icon_state]"],"[I.icon_state].png") dat += " style='background-image:url([I.icon_state].png)'>" else dat+= ">" diff --git a/code/modules/goonchat/_helpers.dm b/code/modules/goonchat/_helpers.dm new file mode 100644 index 00000000000..0cff1928982 --- /dev/null +++ b/code/modules/goonchat/_helpers.dm @@ -0,0 +1,112 @@ +var/regex/is_http_protocol = regex("^https?://") + + +//Converts an icon to base64. Operates by putting the icon in the iconCache savefile, +// exporting it as text, and then parsing the base64 from that. +// (This relies on byond automatically storing icons in savefiles as base64) +/proc/icon2base64(icon/icon, iconKey = "misc") + if (!isicon(icon)) + return FALSE + to_save(iconCache[iconKey], icon) + var/iconData = iconCache.ExportText(iconKey) + var/list/partial = splittext(iconData, "{") + return replacetext(copytext(partial[2], 3, -5), "\n", "") + +/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE, realsize = FALSE, class = null) + if (!thing) + return + + var/key + var/icon/I = thing + if (!target) + return + if (target == world) + target = clients + + var/list/targets + if (!islist(target)) + targets = list(target) + else + targets = target + if (!targets.len) + return + if (!isicon(I)) + if (isfile(thing)) //special snowflake + var/name = "[generate_asset_name(thing)].png" + register_asset(name, thing) + for (var/thing2 in targets) + send_asset(thing2, key, FALSE) + return "" + var/atom/A = thing + if (isnull(dir)) + dir = A.dir + if (isnull(icon_state)) + icon_state = A.icon_state + I = A.icon + if (ishuman(thing)) // Shitty workaround for a BYOND issue. + var/icon/temp = I + I = icon() + I.Insert(temp, dir = SOUTH) + dir = SOUTH + else + if (isnull(dir)) + dir = SOUTH + if (isnull(icon_state)) + icon_state = "" + + I = icon(I, icon_state, dir, frame, moving) + + key = "[generate_asset_name(I)].png" + register_asset(key, I) + for (var/thing2 in targets) + send_asset(thing2, key, FALSE) + + if(realsize) + return "" + + + return "" + +/proc/icon2base64html(thing) + if (!thing) + return + var/static/list/bicon_cache = list() + if (isicon(thing)) + var/icon/I = thing + var/icon_base64 = icon2base64(I) + + if (I.Height() > world.icon_size || I.Width() > world.icon_size) + var/icon_md5 = md5(icon_base64) + icon_base64 = bicon_cache[icon_md5] + if (!icon_base64) // Doesn't exist yet, make it. + bicon_cache[icon_md5] = icon_base64 = icon2base64(I) + + + return "" + + // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. + var/atom/A = thing + var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" + + + if (!bicon_cache[key]) // Doesn't exist, make it. + var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) + if (ishuman(thing)) // Shitty workaround for a BYOND issue. + var/icon/temp = I + I = icon() + I.Insert(temp, dir = SOUTH) + + bicon_cache[key] = icon2base64(I, key) + + return "" + +//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. +/proc/costly_icon2html(thing, target) + if (!thing) + return + + if (isicon(thing)) + return icon2html(thing, target) + + var/icon/I = getFlatIcon(thing) + return icon2html(I, target) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm new file mode 100644 index 00000000000..b654d0d7d7f --- /dev/null +++ b/code/modules/goonchat/browserOutput.dm @@ -0,0 +1,286 @@ +/********************************* +For the main html chat area +*********************************/ + +//Precaching a bunch of shit +var/savefile/iconCache = new("data/tmp/iconCache.sav") //Cache of icons for the browser output + +//Should match the value set in the browser js +#define MAX_COOKIE_LENGTH 5 + +//On client, created on login +/datum/chatOutput + var/client/owner //client ref + // How many times client data has been checked + var/total_checks = 0 + // When to next clear the client data checks counter + var/next_time_to_clear = 0 + var/loaded = FALSE // Has the client loaded the browser output area? + var/list/messageQueue //If they haven't loaded chat, this is where messages will go until they do + var/cookieSent = FALSE // Has the client sent a cookie for analysis + var/broken = FALSE + var/list/connectionHistory //Contains the connection history passed from chat cookie + +/datum/chatOutput/New(client/C) + owner = C + messageQueue = list() + connectionHistory = list() + +/datum/chatOutput/proc/start() + //Check for existing chat + if(!owner) + return FALSE + + if(!winexists(owner, "browseroutput")) // Oh goddamnit. + set waitfor = FALSE + broken = TRUE + message_admins("Couldn't start chat for [key_name_admin(owner)]!") + . = FALSE + alert(owner.mob, "Updated chat window does not exist. If you are using a custom skin file please allow the game to update.") + return + + //It seems if someone disconnects while loading this can runtime, so we have to check for owner again + if(owner && winget(owner, "browseroutput", "is-visible") == "true") //Already setup + doneLoading() + + else //Not setup + load() + + return TRUE + +/datum/chatOutput/proc/load() + set waitfor = FALSE + if(!owner) + return + + var/datum/asset/stuff = get_asset_datum(/datum/asset/group/goonchat) + stuff.send(owner) + + show_browser(owner, file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput") + +/datum/chatOutput/Topic(href, list/href_list) + if(usr.client != owner) + return TRUE + + // Build arguments. + // Arguments are in the form "param[paramname]=thing" + var/list/params = list() + for(var/key in href_list) + if(length(key) > 7 && findtext(key, "param")) // 7 is the amount of characters in the basic param key template. + var/param_name = copytext(key, 7, -1) + var/item = href_list[key] + + params[param_name] = item + + var/data // Data to be sent back to the chat. + switch(href_list["proc"]) + if("doneLoading") + data = doneLoading(arglist(params)) + + if("debug") + data = debug(arglist(params)) + + if("ping") + data = ping(arglist(params)) + + if("analyzeClientData") + data = analyzeClientData(arglist(params)) + + if("swaptodarkmode") + swaptodarkmode() + + if("swaptolightmode") + swaptolightmode() + + if(data) + ehjax_send(data = data) + + +//Called on chat output done-loading by JS. +/datum/chatOutput/proc/doneLoading() + if(loaded) + return + + loaded = TRUE + showChat() + + + for(var/message in messageQueue) + // whitespace has already been handled by the original to_chat + to_chat(owner, message, handle_whitespace=FALSE) + + messageQueue = null + sendClientData() + + syncRegex() + + //do not convert to to_chat() + legacy_chat(owner, "Failed to load fancy chat, reverting to old chat. Certain features won't work.") + +/datum/chatOutput/proc/showChat() + winset(owner, "output", "is-visible=false") + winset(owner, "browseroutput", "is-disabled=false;is-visible=true") + +/proc/syncChatRegexes() + for (var/user in clients) + var/client/C = user + var/datum/chatOutput/Cchat = C.chatOutput + if (Cchat && !Cchat.broken && Cchat.loaded) + Cchat.syncRegex() + +/datum/chatOutput/proc/syncRegex() + var/list/regexes = list() + + if (regexes.len) + ehjax_send(data = list("syncRegex" = regexes)) + +/datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) + if(islist(data)) + data = json_encode(data) + send_output(C, "[data]", "[window]:ehjaxCallback") + +//Sends client connection details to the chat to handle and save +/datum/chatOutput/proc/sendClientData() + //Get dem deets + var/list/deets = list("clientData" = list()) + deets["clientData"]["ckey"] = owner.ckey + deets["clientData"]["ip"] = owner.address + deets["clientData"]["compid"] = owner.computer_id + var/data = json_encode(deets) + ehjax_send(data = data) + +//Called by client, sent data to investigate (cookie history so far) +/datum/chatOutput/proc/analyzeClientData(cookie = "") + //Spam check + if(world.time > next_time_to_clear) + next_time_to_clear = world.time + (3 SECONDS) + total_checks = 0 + + total_checks += 1 + + if(total_checks > SPAM_TRIGGER_AUTOMUTE) + message_admins("[key_name(owner)] kicked for goonchat topic spam") + qdel(owner) + return + + if(!cookie) + return + + if(cookie != "none") + var/list/connData = json_decode(cookie) + if (connData && islist(connData) && connData.len > 0 && connData["connData"]) + connectionHistory = connData["connData"] //lol fuck + var/list/found = new() + + if(connectionHistory.len > MAX_COOKIE_LENGTH) + message_admins("[key_name(src.owner)] was kicked for an invalid ban cookie)") + qdel(owner) + return + + for(var/i in connectionHistory.len to 1 step -1) + if(QDELETED(owner)) + //he got cleaned up before we were done + return + var/list/row = src.connectionHistory[i] + if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object + return + if (world.IsBanned(row["ckey"], row["ip"], row["compid"])) + found = row + break + CHECK_TICK + + //Uh oh this fucker has a history of playing on a banned account!! + if (found.len > 0) + var/msg = "[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])" + //TODO: add a new evasion ban for the CURRENT client details, using the matched row details + message_admins(msg) + log_admin(msg) + + cookieSent = TRUE + +//Called by js client every 60 seconds +/datum/chatOutput/proc/ping() + return "pong" + +//Called by js client on js error +/datum/chatOutput/proc/debug(error) + log_debug("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") + +//Global chat procs +/proc/to_chat_immediate(target, message, handle_whitespace = TRUE, trailing_newline = TRUE) + if(!target || !message) + return + + if(target == world) + target = clients + + var/original_message = message + if(handle_whitespace) + message = replacetext(message, "\n", "
      ") + message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") + + //Replace expanded \icon macro with icon2html + //regex/Replace with a proc won't work here because icon2html takes target as an argument and there is no way to pass it to the replacement proc + //not even hacks with reassigning usr work + var/regex/i = new(@//, "g") + while(i.Find(message)) + message = copytext(message,1,i.index)+icon2html(locate(i.group[1]), target, icon_state=i.group[2])+copytext(message,i.next) + + if(trailing_newline) + message += "
      " + + if(islist(target)) + // Do the double-encoding outside the loop to save nanoseconds + var/twiceEncoded = url_encode(url_encode(message)) + for(var/I in target) + var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible + + if (!C) + continue + + //Send it to the old style output window. + legacy_chat(C, original_message) + + if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. + continue + + if(!C.chatOutput.loaded) + //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + continue + + send_output(C, twiceEncoded, "browseroutput:output") + else + var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible + + if (!C) + return + + //Send it to the old style output window. + legacy_chat(C, original_message) + + if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. + return + + if(!C.chatOutput.loaded) + //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + return + + // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + send_output(C, url_encode(url_encode(message)), "browseroutput:output") + +/proc/to_chat(target, message, handle_whitespace = TRUE, trailing_newline = TRUE) + set waitfor = FALSE + if(Master.initializing || !SSchat) + to_chat_immediate(target, message, handle_whitespace, trailing_newline) + return + SSchat.queue(target, message, handle_whitespace, trailing_newline) + +/datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation) + owner.force_white_theme() + +/datum/chatOutput/proc/swaptodarkmode() + owner.force_dark_theme() + +#undef MAX_COOKIE_LENGTH diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css new file mode 100644 index 00000000000..cbf73d180e9 --- /dev/null +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -0,0 +1,398 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #a4bad6; +} +body { + background: #171717; + font-family: Verdana, sans-serif; + font-size: 13px; + color: #a4bad6; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + scrollbar-face-color:#1A1A1A; + scrollbar-track-color:#171717; + scrollbar-highlight-color:#171717; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 1em; + width: auto; + vertical-align: bottom; +} + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #397ea5;} +a.visited {color: #7c00e6;} +a:visited {color: #7c00e6;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #202020; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #a4bad6; +} +#newMessages:hover {background: #171717;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 135px; + width: 45px; + background: #202020; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #202020; + height: 30px; + padding: 5px 0; + display: block; + color: #a4bad6; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #171717; +} +#userBar .subCell:hover {background: #202020;} +#userBar .toggle { + width: 45px; + background: #202020; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 180px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +.motd {color: #a4bad6; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #a4bad6; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #a4bad6;} + +/* ADD HERE FOR BOLD */ +.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} + +/* ADD HERE FOR ITALIC */ +.italic, .italics, .emote {font-style: italic;} + +/* OUTPUT COLORS */ +.highlight {background: yellow;} + +h1, h2, h3, h4, h5, h6 {color: #a4bad6; font-family: Georgia, Verdana, sans-serif; line-height: 10%;} + +em {font-style: normal; font-weight: bold;} + +/* LOG */ +.log_message {color: #386aff; font-weight: bold;} + +/* CHAT TAGS */ +.tag {color: #fff; border-radius: 15px; font-size: 80%; padding-left: 4px; padding-right: 4px;} +.ooc_tag {background-color: #3c5dc0;} +.looc_tag {color: #000; background-color: #46b2b2;} +.dev_tag {background-color: #2c7731;} +.admin_tag {background-color: #9611d4;} +.mod_tag {background-color: #663a0e;} +.dead_tag {background-color: #9269c7;} +.pmin_tag {background-color: #ff0000;} +.pmout_tag {background-color: #ff0000;} +.pmoutalt_tag {background-color: #b54a4a;} +.pmother_tag {background-color: #498db6;} +.help_tag {background-color: #ff0000;} +.aooc_tag {background-color: #920000;} + +/* OOC */ +.ooc {font-weight: bold;} +.ooc img.text_tag {width: 32px; height: 10px; vertical-align: middle;} + +.ooc .everyone {color: #3c5dc0;} +.ooc .looc {color: #6699CC;} +.ooc .elevated {color: #2e78d9;} +.ooc .moderator {color: #184880;} +.ooc .developer {color: #2c7731;} +.ooc .admin {color: #b82e00;} + +/* Admin: Private Messages */ +.pm .howto {color: #ff0000; font-weight: bold; font-size: 200%;} +.pm .in {color: #ff0000;} +.pm .out {color: #ff0000;} +.pm .other {color: #0000ff;} + +/* Admin: Channels */ +.mod_channel {color: #735638; font-weight: bold;} +.mod_channel .admin {color: #b82e00; font-weight: bold;} +.admin_channel {color: #9611D4; font-weight: bold;} +.cciaasay {color: #22a9b4; font-weight: bold;} +.devsay {color: #2c7731; font-weight: bold;} + +/* Radio: Misc */ +.deadsay {color: #9269c7;} +.radio {color: #00a700;} +.deptradio {color: #ff00ff;} /* when all other department colors fail */ +.newscaster {color: #b43c3c;} + +/* Radio Channels */ +.comradio {color: #5b8deb;} +.syndradio {color: #ac6667;} +.centradio {color: #7272a7;} +.airadio {color: #ec00ec;} +.entradio {color: #d19a46;} + +.secradio {color: #e21111;} +.engradio {color: #cc7b01;} +.medradio {color: #0f7e62;} +.sciradio {color: #c03bc0;} +.supradio {color: #c09141;} +.srvradio {color: #7fc732;} + +/* Miscellaneous */ +.name {font-weight: bold;} +.alert {color: #d82020;} +.vote {color: #9933ff;} +h1.alert, h2.alert {color: #a4bad6;} + +.emote {font-style: italic;} + +/* Game Messages */ +.attack {color: #ff0000;} +.moderate {color: #cc0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.danger {color: #c51e1e; font-weight: bold} +.warning {color: #c51e1e; font-style: italic;} +.boldannounce {color: #c51e1e; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #6685f5;} +.notice {color: #6685f5;} +.alium {color: #00ff00;} +.cult {color: #aa1c1c;} + +/* Languages */ +.alien {color: #ad67ad;} +.tajaran {color: #b15377;} +.tajaran_signlang {color: #cc2c2c;} +.skrell {color: #00CED1;} +.vaurca {color: #b9b943;} +.soghun {color: #2cad2c;} +.solcom {color: #5f5fd4;} +.soghun_alt {color: #1d9b1d;} +.changeling {color: #ad14ad;} +.vox {color: #bb19bb;} +.rough {font-family: "Trebuchet MS", cursive, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.yassa {color: #6323b6;} +.delvahhi {color: #914123; font-weight: bold;} +.siiktau {color: #be3434;} + +.interface {color: #750e75;} + +.good {color: #4f7529; font-weight: bold;} +.bad {color: #ee0000; font-weight: bold;} + +@keyframes hypnocolor { + 0% {color: #202020;} + 25% {color: #4b02ac;} + 50% {color: #9f41f1;} + 75% {color: #541c9c;} + 100% {color: #7adbf3;} +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% {color: #f75a5a;} + 50% {color: #dd0000;} + 100% {color: #f75a5a;} +} + +.icon {height: 1em; width: auto;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: #3d5bc3; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} +.ml-1 {margin-left: 1em;} +.ml-2 {margin-left: 2em;} +.ml-3 {margin-left: 3em;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_white.css b/code/modules/goonchat/browserassets/css/browserOutput_white.css new file mode 100644 index 00000000000..adc8c9e34d0 --- /dev/null +++ b/code/modules/goonchat/browserassets/css/browserOutput_white.css @@ -0,0 +1,395 @@ +/***************************************** +* +* GLOBAL STYLES for white theme normies +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #000000; +} +body { + background: #fff; + font-family: Verdana, sans-serif; + font-size: 13px; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} +img.icon { + height: 1em; + min-height: 1em; + width: auto; + vertical-align: bottom; +} + + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #0000ff;} +a.visited {color: #ff00ff;} +a:visited {color: #ff00ff;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #ddd; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #333; +} +#newMessages:hover {background: #ccc;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 135px; + width: 45px; + background: #ddd; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #ddd; + height: 30px; + padding: 5px 0; + display: block; + color: #333; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #b4b4b4; +} +#userBar .subCell:hover {background: #ccc;} +#userBar .toggle { + width: 45px; + background: #ccc; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 180px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +.motd {color: #638500; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;} + +/* ADD HERE FOR BOLD */ +.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} + +/* ADD HERE FOR ITALIC */ +.italic, .italics, .emote {font-style: italic;} + +/* OUTPUT COLORS */ +.highlight {background: yellow;} + +h1, h2, h3, h4, h5, h6 {color: #0000ff; font-family: Georgia, Verdana, sans-serif; line-height: 10%;} + +em {font-style: normal;font-weight: bold;} + +/* LOG */ +.log_message {color: #386aff;font-weight: bold;} + +/* CHAT TAGS */ +.tag {color: #fff; border-radius: 15px; font-size: 80%; padding-left: 4px; padding-right: 4px;} +.ooc_tag {background-color: #002eb8;} +.looc_tag {color: #000; background-color: #46b2b2;} +.dev_tag {background-color: #2c7731;} +.admin_tag {background-color: #9611d4;} +.mod_tag {background-color: #663a0e;} +.dead_tag {background-color: #530fad;} +.pmin_tag {background-color: #ff0000;} +.pmout_tag {background-color: #ff0000;} +.pmoutalt_tag {background-color: #b54a4a;} +.pmother_tag {background-color: #498db6;} +.help_tag {background-color: #ff0000;} +.aooc_tag {background-color: #920000;} + +/* OOC */ +.ooc {font-weight: bold;} +.ooc img.text_tag {width: 32px; height: 10px; vertical-align: middle;} + +.ooc .everyone {color: #002eb8;} +.ooc .looc {color: #6699CC;} +.ooc .elevated {color: #2e78d9;} +.ooc .moderator {color: #184880;} +.ooc .developer {color: #2c7731;} +.ooc .admin {color: #b82e00;} + +/* Admin: Private Messages */ +.pm .howto {color: #ff0000; font-weight: bold; font-size: 200%;} +.pm .in {color: #ff0000;} +.pm .out {color: #ff0000;} +.pm .other {color: #0000ff;} + +/* Admin: Channels */ +.mod_channel {color: #735638; font-weight: bold;} +.mod_channel .admin {color: #b82e00; font-weight: bold;} +.admin_channel {color: #9611D4; font-weight: bold;} +.cciaasay {color: #22a9b4; font-weight: bold;} +.devsay {color: #2c7731; font-weight: bold;} + +/* Radio: Misc */ +.deadsay {color: #530FAD;} +.radio {color: #008000;} +.deptradio {color: #ff00ff;} /* when all other department colors fail */ +.newscaster {color: #750000;} + +/* Radio Channels */ +.comradio {color: #193A7A;} +.syndradio {color: #6D3F40;} +.centradio {color: #5C5C8A;} +.airadio {color: #FF00FF;} +.entradio {color: #bd893c;} + +.secradio {color: #A30000;} +.engradio {color: #A66300;} +.medradio {color: #0a5c47;} +.sciradio {color: #993399;} +.supradio {color: #5F4519;} +.srvradio {color: #6eaa2c;} + +/* Miscellaneous */ +.name {font-weight: bold;} +.alert {color: #ff0000;} +.vote {color: #6c18c0} +h1.alert, h2.alert {color: #000080;} + +.emote {font-style: italic;} + +/* Game Messages */ +.attack {color: #ff0000;} +.moderate {color: #cc0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.danger {color: #ff0000; font-weight: bold} +.warning {color: #ff0000; font-style: italic;} +.boldannounce {color: #ff0000; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0000CC;} +.notice {color: #000099;} +.alium {color: #00ff00;} +.cult {color: #800080; font-weight: bold; font-style: italic;} + +/* Languages */ +.alien {color: #543354;} +.tajaran {color: #803B56;} +.tajaran_signlang {color: #941C1C;} +.skrell {color: #00CED1;} +.vaurca {color: #9e9e39;} +.soghun {color: #228B22;} +.solcom {color: #22228B;} +.soghun_alt {color: #024402;} +.changeling {color: #800080;} +.vox {color: #AA00AA;} +.rough {font-family: "Trebuchet MS", cursive, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.yassa {color: #400987;} +.delvahhi {color: #5E2612; font-weight: bold;} +.siiktau {color: #A52A2A;} + +.interface {color: #750e75;} + +.good {color: #4f7529; font-weight: bold;} +.bad {color: #ee0000; font-weight: bold;} + +@keyframes hypnocolor { + 0% {color: #0d0d0d;} + 25% {color: #410194;} + 50% {color: #7f17d8;} + 75% {color: #410194;} + 100% {color: #3bb5d3;} +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% {color: #0d0d0d;} + 50% {color: #dd0000;} + 100% {color: #0d0d0d;} +} + +.icon {height: 1em; width: auto;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: blue; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} +.ml-1 {margin-left: 1em;} +.ml-2 {margin-left: 2em;} +.ml-3 {margin-left: 3em;} diff --git a/code/modules/goonchat/browserassets/css/styles_template.css b/code/modules/goonchat/browserassets/css/styles_template.css new file mode 100644 index 00000000000..09938c9bbeb --- /dev/null +++ b/code/modules/goonchat/browserassets/css/styles_template.css @@ -0,0 +1,365 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #a4bad6; +} +body { + background: #171717; + font-family: Verdana, sans-serif; + font-size: 13px; + color: #a4bad6; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + scrollbar-face-color:#1A1A1A; + scrollbar-track-color:#171717; + scrollbar-highlight-color:#171717; +} + +em { + font-style: normal; + font-weight: bold; +} + +img { + margin: 0; + padding: 0; + line-height: 1; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} + +img.icon { + height: 1em; + min-height: 1em; + width: auto; + vertical-align: bottom; +} + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +a {color: #397ea5;} +a.visited {color: #7c00e6;} +a:visited {color: #7c00e6;} +a.popt {text-decoration: none;} + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 13px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #202020; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #a4bad6; +} +#newMessages:hover {background: #171717;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#userBar { + position: fixed; + top: 0; + right: 0; +} +#userBar .subCell { + background: #202020; + height: 30px; + padding: 5px 0; + display: block; + color: #a4bad6; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #171717; +} +#userBar .subCell:hover {background: #202020;} +#userBar .toggle { + width: 45px; + background: #202020; + border-top: 0; + float: right; + text-align: center; +} +#userBar .sub {clear: both; display: none; width: 180px;} +#userBar .sub.scroll {overflow-y: scroll;} +#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#userBar .sub span { + display: block; + line-height: 30px; + float: left; +} +#userBar .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#userBar .sub input { + position: absolute; + padding: 7px 5px; + width: 121px; + line-height: 30px; + float: left; +} +#userBar .topCell {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +.motd {color: #a4bad6; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #a4bad6; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #a4bad6;} + +/* ADD HERE FOR BOLD */ +.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} + +/* ADD HERE FOR ITALIC */ +.italic, .italics, .emote {font-style: italic;} + +/* OUTPUT COLORS */ +.highlight {background: yellow;} + +h1, h2, h3, h4, h5, h6 {color: #a4bad6; font-family: Georgia, Verdana, sans-serif; margin-bottom: 20%;} + +em {font-style: normal; font-weight: bold;} + +/* LOG */ +.log_message {color: #386aff; font-weight: bold;} + +/* OOC */ +.ooc {font-weight: bold;} +.ooc img.text_tag {width: 32px; height: 10px; vertical-align: middle;} + +.ooc .everyone {color: #002eb8;} +.ooc .looc {color: #6699CC;} +.ooc .elevated {color: #2e78d9;} +.ooc .moderator {color: #184880;} +.ooc .developer {color: #1b521f;} +.ooc .admin {color: #b82e00;} + +/* Admin: Private Messages */ +.pm .howto {color: #ff0000; font-weight: bold; font-size: 200%;} +.pm .in {color: #ff0000;} +.pm .out {color: #ff0000;} +.pm .other {color: #0000ff;} + +/* Admin: Channels */ +.mod_channel {color: #735638; font-weight: bold;} +.mod_channel .admin {color: #b82e00; font-weight: bold;} +.admin_channel {color: #9611D4; font-weight: bold;} +.cciaasay {color: #22a9b4; font-weight: bold;} +.devsay {color: #1b521f; font-weight: bold;} + +/* Radio: Misc */ +.deadsay {color: #530FAD;} +.radio {color: #008000;} +.deptradio {color: #ff00ff;} /* when all other department colors fail */ +.newscaster {color: #750000;} + +/* Radio Channels */ +.comradio {color: #193A7A;} +.syndradio {color: #6D3F40;} +.centradio {color: #5C5C8A;} +.airadio {color: #FF00FF;} +.entradio {color: #bd893c;} + +.secradio {color: #A30000;} +.engradio {color: #A66300;} +.medradio {color: #0a5c47;} +.sciradio {color: #993399;} +.supradio {color: #5F4519;} +.srvradio {color: #6eaa2c;} + +/* Miscellaneous */ +.name {font-weight: bold;} +.alert {color: #ff0000;} +h1.alert, h2.alert {color: #000080;} + +.emote {font-style: italic;} + +/* Game Messages */ +.attack {color: #ff0000;} +.moderate {color: #cc0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.danger {color: #ff0000; font-weight: bold;} +.warning {color: #ff0000; font-style: italic;} +.boldannounce {color: #ff0000; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0000cc;} +.notice {color: #000099;} +.alium {color: #00ff00;} +.cult {color: #800080; font-weight: bold; font-style: italic;} + + +/* Languages */ +.alien {color: #543354;} +.tajaran {color: #803B56;} +.tajaran_signlang {color: #941C1C;} +.skrell {color: #00CED1;} +.vaurca {color: #9e9e39;} +.soghun {color: #228B22;} +.solcom {color: #22228B;} +.soghun_alt {color: #024402;} +.changeling {color: #800080;} +.vox {color: #AA00AA;} +.rough {font-family: "Trebuchet MS", cursive, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.yassa {color: #400987;} +.delvahhi {color: #5E2612; font-weight: bold;} +.siiktau {color: #A52A2A;} + +.interface {color: #750e75;} + +.good {color: #4f7529; font-weight: bold;} +.bad {color: #ee0000; font-weight: bold;} + +@keyframes hypnocolor { + 0% {color: #202020;} + 25% {color: #4b02ac;} + 50% {color: #9f41f1;} + 75% {color: #541c9c;} + 100% {color: #7adbf3;} +} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} +@keyframes phobia { + 0% {color: #f75a5a;} + 50% {color: #dd0000;} + 100% {color: #f75a5a;} +} + +.icon {height: 1em; width: auto;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: #3d5bc3; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html new file mode 100644 index 00000000000..11840cc9a78 --- /dev/null +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -0,0 +1,71 @@ + + + + Chat + + + + + + + + + +
      + +
      + Loading...

      + If this takes longer than 30 seconds, it will automatically reload a maximum of 5 times.
      + If it still doesn't work, use the bug report button at the top right of the window. +
      +
      +
      + +
      + + + + diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js new file mode 100644 index 00000000000..1146c8b98d8 --- /dev/null +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -0,0 +1,1038 @@ + +/***************************************** +* +* FUNCTION AND VAR DECLARATIONS +* +******************************************/ + +//DEBUG STUFF +var escaper = encodeURIComponent || escape; +var decoder = decodeURIComponent || unescape; +window.onerror = function(msg, url, line, col, error) { + if (document.location.href.indexOf("proc=debug") <= 0) { + var extra = !col ? '' : ' | column: ' + col; + extra += !error ? '' : ' | error: ' + error; + extra += !navigator.userAgent ? '' : ' | user agent: ' + navigator.userAgent; + var debugLine = 'Error: ' + msg + ' | url: ' + url + ' | line: ' + line + extra; + window.location = '?_src_=chat&proc=debug¶m[error]='+escaper(debugLine); + } + return true; +}; + +//Globals +window.status = 'Output'; +var $messages, $subTheme, $subOptions, $subFont, $selectedSub, $contextMenu, $filterMessages, $last_message; +var opts = { + //General + 'messageCount': 0, //A count...of messages... + 'messageLimit': 2053, //A limit...for the messages... + 'scrollSnapTolerance': 10, //If within x pixels of bottom + 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup + 'imageRetryDelay': 50, //how long between attempts to reload images (in ms) + 'imageRetryLimit': 50, //how many attempts should we make? + 'popups': 0, //Amount of popups opened ever + 'wasd': false, //Is the user in wasd mode? + 'priorChatHeight': 0, //Thing for height-resizing detection + 'restarting': false, //Is the round restarting? + 'iconsize': 12, + + //Options menu + 'selectedSubLoop': null, //Contains the interval loop for closing the selected sub menu + 'suppressSubClose': false, //Whether or not we should be hiding the selected sub menu + 'highlightTerms': [], + 'highlightLimit': 5, + 'highlightColor': '#FFFF00', //The color of the highlighted message + 'pingDisabled': false, //Has the user disabled the ping counter + + //Ping display + 'lastPang': 0, //Timestamp of the last response from the server. + 'pangLimit': 70000, + 'pingTime': 0, //Timestamp of when ping sent + 'pongTime': 0, //Timestamp of when ping received + 'noResponse': false, //Tracks the state of the previous ping request + 'noResponseCount': 0, //How many failed pings? + + //Clicks + 'mouseDownX': null, + 'mouseDownY': null, + 'preventFocus': false, //Prevents switching focus to the game window + + //Client Connection Data + 'clientDataLimit': 5, + 'clientData': [], + + 'font': 'Arial', + 'messageCombining': true, + +}; +var replaceRegexes = {}; + +function clamp(val, min, max) { + return Math.max(min, Math.min(val, max)) +} + +//Polyfill for fucking date now because of course IE8 and below don't support it +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} +//Polyfill for trim() (IE8 and below) +if (typeof String.prototype.trim !== 'function') { + String.prototype.trim = function () { + return this.replace(/^\s+|\s+$/g, ''); + }; +} + +// Linkify the contents of a node, within its parent. +function linkify(parent, insertBefore, text) { + var start = 0; + var match; + var regex = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#\/%?=~_|$!:,.;()]+/ig; + while ((match = regex.exec(text)) !== null) { + // add the unmatched text + parent.insertBefore(document.createTextNode(text.substring(start, match.index)), insertBefore); + + var href = match[0]; + if (!/^https?:\/\//i.test(match[0])) { + href = "http://" + match[0]; + } + + // add the link + var link = document.createElement("a"); + link.href = href; + link.textContent = match[0]; + parent.insertBefore(link, insertBefore); + + start = regex.lastIndex; + } + if (start !== 0) { + // add the remaining text and remove the original text node + parent.insertBefore(document.createTextNode(text.substring(start)), insertBefore); + parent.removeChild(insertBefore); + } +} + +// Recursively linkify the children of a given node. +function linkify_node(node) { + var children = node.childNodes; + // work backwards to avoid the risk of looping forever on our own output + for (var i = children.length - 1; i >= 0; --i) { + var child = children[i]; + if (child.nodeType == Node.TEXT_NODE) { + // text is to be linkified + linkify(node, child, child.textContent); + } else if (child.nodeName != "A" && child.nodeName != "a") { + // do not linkify existing links + linkify_node(child); + } + } +} + +//Shit fucking piece of crap that doesn't work god fuckin damn it +function linkify_fallback(text) { + var rex = /((?:'+$0+''; + } + else { + return $1 ? $0: ''+$0+''; + } + }); +} + +function byondDecode(message) { + // Basically we url_encode twice server side so we can manually read the encoded version and actually do UTF-8. + // The replace for + is because FOR SOME REASON, BYOND replaces spaces with a + instead of %20, and a plus with %2b. + // Marvelous. + message = message.replace(/\+/g, "%20"); + try { + // This is a workaround for the above not always working when BYOND's shitty url encoding breaks. (byond bug id:2399401) + if (decodeURIComponent) { + message = decodeURIComponent(message); + } else { + throw new Error("Easiest way to trigger the fallback") + } + } catch (err) { + message = unescape(message); + } + return message; +} + +function replaceRegex() { + var selectedRegex = replaceRegexes[$(this).attr('replaceRegex')]; + if (selectedRegex) { + var replacedText = $(this).html().replace(selectedRegex[0], selectedRegex[1]); + $(this).html(replacedText); + } + $(this).removeAttr('replaceRegex'); +} + +// Get a highlight markup span +function createHighlightMarkup() { + var extra = ''; + if (opts.highlightColor) { + extra += ' style="background-color: ' + opts.highlightColor + '"'; + } + return ''; +} + +// Get all child text nodes that match a regex pattern +function getTextNodes(elem, pattern) { + var result = $([]); + $(elem).contents().each(function(idx, child) { + if (child.nodeType === 3 && /\S/.test(child.nodeValue) && pattern.test(child.nodeValue)) { + result = result.add(child); + } + else { + result = result.add(getTextNodes(child, pattern)); + } + }); + return result; +} + + +// Highlight all text terms matching the registered regex patterns +function highlightTerms(el) { + var pattern = new RegExp("(" + opts.highlightTerms.join('|') + ")", 'gi'); + var nodes = getTextNodes(el, pattern); + + nodes.each(function (idx, node) { + var content = $(node).text(); + var parent = $(node).parent(); + var pre = $(node.previousSibling); + $(node).remove(); + content.split(pattern).forEach(function (chunk) { + // Get our highlighted span/text node + var toInsert = null; + if (pattern.test(chunk)) { + var tmpElem = $(createHighlightMarkup()); + tmpElem.text(chunk); + toInsert = tmpElem; + } + else { + toInsert = document.createTextNode(chunk); + } + + // Insert back into our element + if (pre.length == 0) { + var result = parent.prepend(toInsert); + pre = $(result[0].firstChild); + } + else { + pre.after(toInsert); + pre = $(pre[0].nextSibling); + } + }); + }); +} + +function iconError(E) { + var that = this; + setTimeout(function() { + var attempts = $(that).data('reload_attempts'); + if (typeof attempts === 'undefined' || !attempts) { + attempts = 1; + } + if (attempts > opts.imageRetryLimit) + return; + var src = that.src; + that.src = null; + that.src = src+'#'+attempts; + $(that).data('reload_attempts', ++attempts); + }, opts.imageRetryDelay); +} + +function updateIconsSize(html) { + $(html).find(".icon").not('.text_tag').css({'height': opts.iconsize, 'width': opts.iconsize}); +} + +//Send a message to the client +function output(message, flag) { + if (typeof message === 'undefined') { + return; + } + if (typeof flag === 'undefined') { + flag = ''; + } + + if (flag !== 'internal') + opts.lastPang = Date.now(); + + message = byondDecode(message).trim(); + + //The behemoth of filter-code (for Admin message filters) + //Note: This is proooobably hella inefficient + var filteredOut = false; + if (opts.hasOwnProperty('showMessagesFilters') && !opts.showMessagesFilters['All'].show) { + //Get this filter type (defined by class on message) + var messageHtml = $.parseHTML(message), + messageClasses; + if (opts.hasOwnProperty('filterHideAll') && opts.filterHideAll) { + var internal = false; + messageClasses = (!!$(messageHtml).attr('class') ? $(messageHtml).attr('class').split(/\s+/) : false); + if (messageClasses) { + for (var i = 0; i < messageClasses.length; i++) { //Every class + if (messageClasses[i] == 'internal') { + internal = true; + break; + } + } + } + if (!internal) { + filteredOut = 'All'; + } + } else { + //If the element or it's child have any classes + if (!!$(messageHtml).attr('class') || !!$(messageHtml).children().attr('class')) { + messageClasses = $(messageHtml).attr('class').split(/\s+/); + if (!!$(messageHtml).children().attr('class')) { + messageClasses = messageClasses.concat($(messageHtml).children().attr('class').split(/\s+/)); + } + var tempCount = 0; + for (var i = 0; i < messageClasses.length; i++) { //Every class + var thisClass = messageClasses[i]; + $.each(opts.showMessagesFilters, function(key, val) { //Every filter + if (key !== 'All' && val.show === false && typeof val.match != 'undefined') { + for (var i = 0; i < val.match.length; i++) { + var matchClass = val.match[i]; + if (matchClass == thisClass) { + filteredOut = key; + break; + } + } + } + if (filteredOut) return false; + }); + if (filteredOut) break; + tempCount++; + } + } else { + if (!opts.showMessagesFilters['Misc'].show) { + filteredOut = 'Misc'; + } + } + } + } + + //Stuff we do along with appending a message + var atBottom = false; + if (!filteredOut) { + var bodyHeight = $('body').height(); + var messagesHeight = $messages.outerHeight(); + var scrollPos = $('body,html').scrollTop(); + + //Should we snap the output to the bottom? + if (bodyHeight + scrollPos >= messagesHeight - opts.scrollSnapTolerance) { + atBottom = true; + if ($('#newMessages').length) { + $('#newMessages').remove(); + } + //If not, put the new messages box in + } else { + if ($('#newMessages').length) { + var messages = $('#newMessages .number').text(); + messages = parseInt(messages); + messages++; + $('#newMessages .number').text(messages); + if (messages == 2) { + $('#newMessages .messageWord').append('s'); + } + } else { + $messages.after('1 new message '); + } + } + } + + opts.messageCount++; + + //Pop the top message off if history limit reached + if (opts.messageCount >= opts.messageLimit) { + $messages.children('div.entry:first-child').remove(); + opts.messageCount--; //I guess the count should only ever equal the limit + } + + // Create the element - if combining is off, we use it, and if it's on, we + // might discard it bug need to check its text content. Some messages vary + // only in HTML markup, have the same text content, and should combine. + var entry = document.createElement('div'); + entry.innerHTML = message; + var trimmed_message = entry.textContent || entry.innerText || ""; + + var handled = false; + if (opts.messageCombining) { + var lastmessages = $messages.children('div.entry:last-child').last(); + if (lastmessages.length && $last_message && $last_message == trimmed_message) { + var badge = lastmessages.children('.r').last(); + if (badge.length) { + badge = badge.detach(); + badge.text(parseInt(badge.text()) + 1); + } else { + badge = $('', {'class': 'r', 'text': 2}); + } + lastmessages.html(message.replace(/\s*$/g,' ')); + lastmessages.find('[replaceRegex]').each(replaceRegex); + lastmessages.append(badge); + badge.animate({ + "font-size": "0.9em" + }, 100, function() { + badge.animate({ + "font-size": "0.7em" + }, 100); + }); + opts.messageCount--; + handled = true; + } + } + + if (!handled) { + //Actually append the message + entry.className = 'entry'; + + if (filteredOut) { + entry.className += ' hidden'; + entry.setAttribute('data-filter', filteredOut); + } + + $(entry).find('[replaceRegex]').each(replaceRegex); + + $last_message = trimmed_message; + $messages[0].appendChild(entry); + + updateIconsSize(entry); + + $(entry).find("img.icon").error(iconError); + + var to_linkify = $(entry).find(".linkify"); + if (typeof Node === 'undefined') { + // Linkify fallback for old IE + for(var i = 0; i < to_linkify.length; ++i) { + to_linkify[i].innerHTML = linkify_fallback(to_linkify[i].innerHTML); + } + } else { + // Linkify for modern IE versions + for(var i = 0; i < to_linkify.length; ++i) { + linkify_node(to_linkify[i]); + } + } + + //Actually do the snap + //Stuff we can do after the message shows can go here, in the interests of responsiveness + if (opts.highlightTerms && opts.highlightTerms.length > 0) { + highlightTerms($(entry)); + } + } + + if (!filteredOut && atBottom) { + $('body,html').scrollTop($messages.outerHeight()); + } +} + +function internalOutput(message, flag) +{ + output(escaper(message), flag) +} + +//Runs a route within byond, client or server side. Consider this "ehjax" for byond. +function runByond(uri) { + window.location = uri; +} + +function setCookie(cname, cvalue, exdays) { + cvalue = escaper(cvalue); + var d = new Date(); + d.setTime(d.getTime() + (exdays*24*60*60*1000)); + var expires = 'expires='+d.toUTCString(); + document.cookie = cname + '=' + cvalue + '; ' + expires + "; path=/"; +} + +function getCookie(cname) { + var name = cname + '='; + var ca = document.cookie.split(';'); + for(var i=0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1); + if (c.indexOf(name) === 0) { + return decoder(c.substring(name.length,c.length)); + } + } + return ''; +} + +function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B);} +function toHex(n) { + n = parseInt(n,10); + if (isNaN(n)) return "00"; + n = Math.max(0,Math.min(n,255)); + return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16); +} + +function setTheme(theme) { + if (theme === 'white') { + document.getElementById("sheetofstyles").href = "browserOutput_white.css"; + runByond('?_src_=chat&proc=swaptolightmode'); + } else if (theme === 'dark') { + document.getElementById("sheetofstyles").href = "browserOutput.css"; + runByond('?_src_=chat&proc=swaptodarkmode'); + } + + setCookie('theme', theme, 365); + internalOutput('Set theme: '+theme+'', 'internal'); +} + +function handleClientData(ckey, ip, compid) { + //byond sends player info to here + var currentData = {'ckey': ckey, 'ip': ip, 'compid': compid}; + if (opts.clientData && !$.isEmptyObject(opts.clientData)) { + runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]='+JSON.stringify({'connData': opts.clientData})); + + for (var i = 0; i < opts.clientData.length; i++) { + var saved = opts.clientData[i]; + if (currentData.ckey == saved.ckey && currentData.ip == saved.ip && currentData.compid == saved.compid) { + return; //Record already exists + } + } + //Lets make sure we obey our limit (can connect from server with higher limit) + while (opts.clientData.length >= opts.clientDataLimit) { + opts.clientData.shift(); + } + } else { + runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]=none'); + } + + //Update the cookie with current details + opts.clientData.push(currentData); + setCookie('connData', JSON.stringify(opts.clientData), 365); +} + +//Server calls this on ehjax response +//Or, y'know, whenever really +function ehjaxCallback(data) { + opts.lastPang = Date.now(); + if (data == 'softPang') { + return; + } else if (data == 'pang') { + opts.pingCounter = 0; //reset + opts.pingTime = Date.now(); + runByond('?_src_=chat&proc=ping'); + + } else if (data == 'pong') { + if (opts.pingDisabled) {return;} + opts.pongTime = Date.now(); + var pingDuration = Math.ceil((opts.pongTime - opts.pingTime) / 2); + $('#pingMs').text(pingDuration+'ms'); + pingDuration = Math.min(pingDuration, 255); + var red = pingDuration; + var green = 255 - pingDuration; + var blue = 0; + var hex = rgbToHex(red, green, blue); + $('#pingDot').css('color', '#'+hex); + + } else if (data == 'roundrestart') { + opts.restarting = true; + internalOutput('
      The connection has been closed because the server is restarting. Please wait while you automatically reconnect.
      ', 'internal'); + } else { + //Oh we're actually being sent data instead of an instruction + var dataJ; + try { + dataJ = $.parseJSON(data); + } catch (e) { + //But...incorrect :sadtrombone: + window.onerror('JSON: '+e+'. '+data, 'browserOutput.html', 327); + return; + } + data = dataJ; + + if (data.clientData) { + if (opts.restarting) { + opts.restarting = false; + $('.connectionClosed.restarting:not(.restored)').addClass('restored').text('The round restarted and you successfully reconnected!'); + } + if (!data.clientData.ckey && !data.clientData.ip && !data.clientData.compid) { + //TODO: Call shutdown perhaps + return; + } else { + handleClientData(data.clientData.ckey, data.clientData.ip, data.clientData.compid); + } + } else if (data.syncRegex) { + for (var i in data.syncRegex) { + + var regexData = data.syncRegex[i]; + var regexName = regexData[0]; + var regexFlags = regexData[1]; + var regexReplaced = regexData[2]; + + replaceRegexes[i] = [new RegExp(regexName, regexFlags), regexReplaced]; + } + } + } +} + +function createPopup(contents, width) { + opts.popups++; + $('body').append(''); + + //Attach close popup event + var $popup = $('#popup'+opts.popups); + var height = $popup.outerHeight(); + $popup.css({'height': height+'px', 'margin': '-'+(height/2)+'px 0 0 -'+(width/2)+'px'}); + + $popup.on('click', '.close', function(e) { + e.preventDefault(); + $popup.remove(); + }); +} + +function toggleWasd(state) { + opts.wasd = (state == 'on' ? true : false); +} + +function subSlideUp() { + $(this).removeClass('scroll'); + $(this).css('height', ''); +} + +function startSubLoop() { + if (opts.selectedSubLoop) { + clearInterval(opts.selectedSubLoop); + } + return setInterval(function() { + if (!opts.suppressSubClose && $selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + clearInterval(opts.selectedSubLoop); + } + }, 5000); //every 5 seconds +} + +function handleToggleClick($sub, $toggle) { + if ($selectedSub !== $sub && $selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + } + $selectedSub = $sub + if ($selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + clearInterval(opts.selectedSubLoop); + } else { + $selectedSub.slideDown('fast', function() { + var windowHeight = $(window).height(); + var toggleHeight = $toggle.outerHeight(); + var priorSubHeight = $selectedSub.outerHeight(); + var newSubHeight = windowHeight - toggleHeight; + $(this).height(newSubHeight); + if (priorSubHeight > (windowHeight - toggleHeight)) { + $(this).addClass('scroll'); + } + }); + opts.selectedSubLoop = startSubLoop(); + } +} + +/***************************************** +* +* DOM READY +* +******************************************/ + +if (typeof $ === 'undefined') { + var div = document.getElementById('loading').childNodes[1]; + div += '

      ERROR: Jquery did not load.'; +} + +$(function() { + $messages = $('#messages'); + $subTheme = $('#subTheme'); + $subOptions = $('#subOptions'); + $subFont = $('#subFont'); + $selectedSub = $subOptions; + + //Hey look it's a controller loop! + setInterval(function() { + if (opts.lastPang + opts.pangLimit < Date.now() && !opts.restarting) { //Every pingLimit + if (!opts.noResponse) { //Only actually append a message if the previous ping didn't also fail (to prevent spam) + opts.noResponse = true; + opts.noResponseCount++; + internalOutput('
      You are either AFK, experiencing lag or the connection has closed.
      ', 'internal'); + } + } else if (opts.noResponse) { //Previous ping attempt failed ohno + $('.connectionClosed[data-count="'+opts.noResponseCount+'"]:not(.restored)').addClass('restored').text('Your connection has been restored (probably)!'); + opts.noResponse = false; + } + }, 2000); //2 seconds + + + /***************************************** + * + * LOAD SAVED CONFIG + * + ******************************************/ + var savedConfig = { + fontsize: getCookie('fontsize'), + iconsize: getCookie('iconsize'), + lineheight: getCookie('lineheight'), + 'spingDisabled': getCookie('pingdisabled'), + 'shighlightTerms': getCookie('highlightterms'), + 'shighlightColor': getCookie('highlightcolor'), + 'sfont': getCookie('font'), + 'smessagecombining': getCookie('messagecombining'), + 'stheme': getCookie('theme'), + }; + + if (savedConfig.fontsize) { + $messages.css('font-size', savedConfig.fontsize); + internalOutput('Loaded font size setting of: '+savedConfig.fontsize+'', 'internal'); + } + if (savedConfig.iconsize) { + opts.iconsize = savedConfig.iconsize; + updateIconsSize($messages); + internalOutput('Loaded icon size setting of: '+savedConfig.iconsize+'', 'internal'); + } + if (savedConfig.lineheight) { + $("body").css('line-height', savedConfig.lineheight); + internalOutput('Loaded line height setting of: '+savedConfig.lineheight+'', 'internal'); + } + if(savedConfig.stheme){ + setTheme(savedConfig.stheme); + } + if (savedConfig.spingDisabled) { + if (savedConfig.spingDisabled == 'true') { + opts.pingDisabled = true; + $('#ping').hide(); + } + internalOutput('Loaded ping display of: '+(opts.pingDisabled ? 'hidden' : 'visible')+'', 'internal'); + } + if (savedConfig.shighlightTerms) { + var savedTerms = $.parseJSON(savedConfig.shighlightTerms).filter(function (entry) { + return entry !== null && /\S/.test(entry); + }); + var actualTerms = savedTerms.length != 0 ? savedTerms.join(', ') : null; + if (actualTerms) { + internalOutput('Loaded highlight strings of: ' + actualTerms+'', 'internal'); + opts.highlightTerms = savedTerms; + } + } + if (savedConfig.shighlightColor) { + opts.highlightColor = savedConfig.shighlightColor; + internalOutput('Loaded highlight color of: '+savedConfig.shighlightColor+'', 'internal'); + } + if (savedConfig.sfont) { + $('body').css({'font-family': savedConfig.sfont}); + internalOutput('Loaded font: '+savedConfig.sfont+'', 'internal'); + } + + if (savedConfig.smessagecombining) { + if (savedConfig.smessagecombining == 'false') { + opts.messageCombining = false; + } else { + opts.messageCombining = true; + } + } + (function() { + var dataCookie = getCookie('connData'); + if (dataCookie) { + var dataJ; + try { + dataJ = $.parseJSON(dataCookie); + } catch (e) { + window.onerror('JSON '+e+'. '+dataCookie, 'browserOutput.html', 434); + return; + } + opts.clientData = dataJ; + } + })(); + + + /***************************************** + * + * BASE CHAT OUTPUT EVENTS + * + ******************************************/ + + $('body').on('click', 'a', function(e) { + e.preventDefault(); + }); + + $('body').on('mousedown', function(e) { + var $target = $(e.target); + + if ($contextMenu && opts.hasOwnProperty('contextMenuTarget') && opts.contextMenuTarget) { + hideContextMenu(); + return false; + } + + if ($target.is('a') || $target.parent('a').length || $target.is('input') || $target.is('textarea')) { + opts.preventFocus = true; + } else { + opts.preventFocus = false; + opts.mouseDownX = e.pageX; + opts.mouseDownY = e.pageY; + } + }); + + $messages.on('mousedown', function(e) { + if ($selectedSub && $selectedSub.is(':visible')) { + $selectedSub.slideUp('fast', subSlideUp); + clearInterval(opts.selectedSubLoop); + } + }); + + $('body').on('mouseup', function(e) { + if (!opts.preventFocus && + (e.pageX >= opts.mouseDownX - opts.clickTolerance && e.pageX <= opts.mouseDownX + opts.clickTolerance) && + (e.pageY >= opts.mouseDownY - opts.clickTolerance && e.pageY <= opts.mouseDownY + opts.clickTolerance) + ) { + opts.mouseDownX = null; + opts.mouseDownY = null; + runByond('byond://winset?mapwindow.map.focus=true'); + } + }); + + $messages.on('click', 'a', function(e) { + var href = $(this).attr('href'); + $(this).addClass('visited'); + if (href[0] == '?' || (href.length >= 8 && href.substring(0,8) == 'byond://')) { + runByond(href); + } else { + href = escaper(href); + runByond('?action=openLink&link='+href); + } + runByond('byond://winset?mapwindow.map.focus=true'); + }); + + //Fuck everything about this event. Will look into alternatives. + $('body').on('keydown', function(e) { + if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') { + return; + } + + if (e.ctrlKey || e.altKey || e.shiftKey) { //Band-aid "fix" for allowing ctrl+c copy paste etc. Needs a proper fix. + return; + } + runByond('byond://winset?mapwindow.map.focus=true'); + }); + + //Mildly hacky fix for scroll issues on mob change (interface gets resized sometimes, messing up snap-scroll) + $(window).on('resize', function(e) { + if ($(this).height() !== opts.priorChatHeight) { + $('body,html').scrollTop($messages.outerHeight()); + opts.priorChatHeight = $(this).height(); + } + }); + + + /***************************************** + * + * OPTIONS INTERFACE EVENTS + * + ******************************************/ + + $('body').on('click', '#newMessages', function(e) { + var messagesHeight = $messages.outerHeight(); + $('body,html').scrollTop(messagesHeight); + $('#newMessages').remove(); + runByond('byond://winset?mapwindow.map.focus=true'); + }); + + $('#toggleOptions').click(function(e) { + handleToggleClick($subOptions, $(this)); + }); + + $('#toggleTheme').click(function(e) { + handleToggleClick($subTheme, $(this)); + }); + + $('#toggleFont').click(function(e) { + handleToggleClick($subFont, $(this)); + }); + + $('.sub, .toggle').mouseenter(function() { + opts.suppressSubClose = true; + }); + + $('.sub, .toggle').mouseleave(function() { + opts.suppressSubClose = false; + }); + + $('#setWhiteTheme').click(function() { + setTheme('white'); + savedConfig.stheme = 'white'; + }) + + $('#setDarkTheme').click(function() { + setTheme('dark'); + savedConfig.stheme = 'dark'; + }) + + $('#decreaseFont').click(function(e) { + savedConfig.fontsize = Math.max(parseInt(savedConfig.fontsize || 13) - 1, 1) + 'px'; + $messages.css({'font-size': savedConfig.fontsize}); + setCookie('fontsize', savedConfig.fontsize, 365); + internalOutput('Font size set to '+savedConfig.fontsize+'', 'internal'); + }); + + $('#increaseFont').click(function(e) { + savedConfig.fontsize = (parseInt(savedConfig.fontsize || 13) + 1) + 'px'; + $messages.css({'font-size': savedConfig.fontsize}); + setCookie('fontsize', savedConfig.fontsize, 365); + internalOutput('Font size set to '+savedConfig.fontsize+'', 'internal'); + }); + + $('#decreaseIcon').click(function(e) { + savedConfig.iconsize = Math.max((parseInt(savedConfig.iconsize) || 12) - 1, 1); + updateIconsSize($messages); + setCookie('iconsize', savedConfig.iconsize, 365); + opts.iconsize = savedConfig.iconsize; + internalOutput('Icon size set to '+savedConfig.iconsize+'', 'internal'); + }) + + $('#increaseIcon').click(function(e) { + savedConfig.iconsize = (parseInt(savedConfig.iconsize || 12) + 1); + updateIconsSize($messages); + setCookie('iconsize', savedConfig.iconsize, 365); + opts.iconsize = savedConfig.iconsize; + internalOutput('Icon size set to '+savedConfig.iconsize+'', 'internal'); + }) + + $('#decreaseLineHeight').click(function(e) { + savedConfig.lineheight = Math.max(parseFloat(savedConfig.lineheight || 1.2) - 0.1, 0.1).toFixed(1); + $("body").css({'line-height': savedConfig.lineheight}); + setCookie('lineheight', savedConfig.lineheight, 365); + internalOutput('Line height set to '+savedConfig.lineheight+'', 'internal'); + }); + + $('#increaseLineHeight').click(function(e) { + savedConfig.lineheight = (parseFloat(savedConfig.lineheight || 1.2) + 0.1).toFixed(1); + $("body").css({'line-height': savedConfig.lineheight}); + setCookie('lineheight', savedConfig.lineheight, 365); + internalOutput('Line height set to '+savedConfig.lineheight+'', 'internal'); + }); + + $('#togglePing').click(function(e) { + if (opts.pingDisabled) { + $('#ping').slideDown('fast'); + opts.pingDisabled = false; + } else { + $('#ping').slideUp('fast'); + opts.pingDisabled = true; + } + setCookie('pingdisabled', (opts.pingDisabled ? 'true' : 'false'), 365); + }); + + $('#saveLog').click(function(e) { + // Requires IE 10+ to issue download commands. Just opening a popup + // window will cause Ctrl+S to save a blank page, ignoring innerHTML. + if (!window.Blob) { + output('This function is only supported on IE 10 and up. Upgrade if possible.', 'internal'); + return; + } + + $.ajax({ + type: 'GET', + url: 'browserOutput_white.css', + success: function(styleData) { + var blob = new Blob(['Chat Log', $messages.html(), '']); + + var fname = 'SS13 Chat Log'; + var date = new Date(), month = date.getMonth(), day = date.getDay(), hours = date.getHours(), mins = date.getMinutes(), secs = date.getSeconds(); + fname += ' ' + date.getFullYear() + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day; + fname += ' ' + (hours < 10 ? '0' : '') + hours + (mins < 10 ? '0' : '') + mins + (secs < 10 ? '0' : '') + secs; + fname += '.html'; + + window.navigator.msSaveBlob(blob, fname); + } + }); + }); + + $('#highlightTerm').click(function(e) { + if ($('.popup .highlightTerm').is(':visible')) {return;} + var termInputs = ''; + for (var i = 0; i < opts.highlightLimit; i++) { + termInputs += '
      '; + } + var popupContent = '
      String Highlighting
      ' + + '
      ' + + '
      Choose up to '+opts.highlightLimit+' strings that will highlight the line when they appear in chat.
      ' + + '
      ' + + termInputs + + '
      ' + + '
      ' + + '
      ' + + '
      '; + createPopup(popupContent, 250); + }); + + $('body').on('keyup', '#highlightColor', function() { + var color = $('#highlightColor').val(); + color = color.trim(); + if (!color || color.charAt(0) != '#') return; + $('#highlightColor').css('background-color', color); + }); + + $('body').on('submit', '#highlightTermForm', function(e) { + e.preventDefault(); + + opts.highlightTerms = []; + for (var count = 0; count < opts.highlightLimit; count++) { + var term = $('#highlightTermInput'+count).val(); + if (term !== null && /\S/.test(term)) { + opts.highlightTerms.push(term.trim().toLowerCase()); + } + } + + var color = $('#highlightColor').val(); + color = color.trim(); + if (color == '' || color.charAt(0) != '#') { + opts.highlightColor = '#FFFF00'; + } else { + opts.highlightColor = color; + } + var $popup = $('#highlightPopup').closest('.popup'); + $popup.remove(); + + setCookie('highlightterms', JSON.stringify(opts.highlightTerms), 365); + setCookie('highlightcolor', opts.highlightColor, 365); + }); + + $('#clearMessages').click(function() { + $messages.empty(); + opts.messageCount = 0; + }); + + $('#fontInputSpan').hover(function() { + $('#fontInput').removeClass('hidden'); + }, function() { + $('#fontInput').addClass('hidden'); + }); + + $('#fontInput').change(function() { + var newFont = $('#fontInput').val() || 'Verdana, sans-serif'; + $('body').css({'font-family': newFont}); + setCookie('font', newFont, 365); + opts.font = newFont; + internalOutput('Font set to: '+newFont+'', 'internal'); + }); + + $('#toggleCombine').click(function(e) { + opts.messageCombining = !opts.messageCombining; + setCookie('messagecombining', (opts.messageCombining ? 'true' : 'false'), 365); + }); + + $('img.icon').error(iconError); + + + + + /***************************************** + * + * KICK EVERYTHING OFF + * + ******************************************/ + + runByond('?_src_=chat&proc=doneLoading'); + if ($('#loading').is(':visible')) { + $('#loading').remove(); + } + $('#userBar').show(); + opts.priorChatHeight = $(window).height(); +}); diff --git a/code/modules/goonchat/browserassets/js/jquery.min.js b/code/modules/goonchat/browserassets/js/jquery.min.js new file mode 100644 index 00000000000..ab28a24729b --- /dev/null +++ b/code/modules/goonchat/browserassets/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
      ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
      a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
      ","
      "],area:[1,"",""],param:[1,"",""],thead:[1,"","
      "],tr:[2,"","
      "],col:[2,"","
      "],td:[3,"","
      "],_default:k.htmlSerialize?[0,"",""]:[1,"X
      ","
      "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("