From f512ed5e1da29a26912692a4f43b109301f2152d Mon Sep 17 00:00:00 2001 From: Lzimann Date: Thu, 16 Mar 2017 11:12:21 -0300 Subject: [PATCH 01/47] Adds goonchat --- code/__HELPERS/unsorted.dm | 5 +- code/modules/client/client_defines.dm | 4 +- code/modules/client/client_procs.dm | 9 + goon/browserassets/css/browserOutput.css | 362 ++++++++ goon/browserassets/css/font-awesome.css | 788 ++++++++++++++++++ goon/browserassets/html/browserOutput.html | 44 + goon/browserassets/js/browserOutput.js | 908 +++++++++++++++++++++ goon/browserassets/js/json2.min.js | 1 + goon/code/datums/browserOutput.dm | 291 +++++++ interface/skin.dmf | 23 +- tgstation.dme | 2 +- 11 files changed, 2421 insertions(+), 16 deletions(-) create mode 100644 goon/browserassets/css/browserOutput.css create mode 100644 goon/browserassets/css/font-awesome.css create mode 100644 goon/browserassets/html/browserOutput.html create mode 100644 goon/browserassets/js/browserOutput.js create mode 100644 goon/browserassets/js/json2.min.js create mode 100644 goon/code/datums/browserOutput.dm diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index e3a5a7e295d..ac2a2d7245d 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1422,6 +1422,7 @@ var/valid_HTTPSGet = FALSE fdel(temp_file) #define UNTIL(X) while(!(X)) stoplag() - +/* /proc/to_chat(target, message) - target << message \ No newline at end of file + target << message + */ \ No newline at end of file diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 9b9adff580b..16e1a648d3c 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -62,4 +62,6 @@ var/connection_timeofday //world.timeofday they connected var/inprefs = FALSE - var/list/topiclimiter \ No newline at end of file + var/list/topiclimiter + + var/datum/chatOutput/chatOutput \ No newline at end of file diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 0e59e5c924b..0b597d95bd1 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -95,6 +95,12 @@ return if("vars") return view_var_Topic(href,href_list,hsrc) + if("chat") + return chatOutput.Topic(href, href_list) + + switch(href_list["action"]) + if("openLink") + src << link(href_list["link"]) ..() //redirect to hsrc.Topic() @@ -145,6 +151,7 @@ var/next_external_rsc = 0 /client/New(TopicData) var/tdata = TopicData //save this for later use + chatOutput = new /datum/chatOutput(src) TopicData = null //Prevent calls to client.Topic from connect if(connection != "seeker" && connection != "web")//Invalid connection type. @@ -196,6 +203,8 @@ var/next_external_rsc = 0 . = ..() //calls mob.Login() + chatOutput.start() + connection_time = world.time connection_realtime = world.realtime connection_timeofday = world.timeofday diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css new file mode 100644 index 00000000000..182210d7656 --- /dev/null +++ b/goon/browserassets/css/browserOutput.css @@ -0,0 +1,362 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #000000; +} +body { + background: #fff; + font-family: Verdana, sans-serif; + font-size: 9pt; + line-height: 1.4; + 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; +} +img.icon { + width: 16px; + height: 16px; +} + +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: 14px; + 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: 40px; + 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; +} +#options { + position: fixed; + top: 0; + right: 0; +} +#options a { + background: #ddd; + height: 30px; + padding: 5px 0; + display: block; + color: #333; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #b4b4b4; +} +#options a:hover {background: #ccc;} +#options .toggle { + width: 40px; + background: #ccc; + border-top: 0; + float: right; + text-align: center; +} +#options .sub {clear: both; display: none; width: 160px;} +#options .sub.scroll {overflow-y: scroll;} +#options .sub a {padding: 5px 0 5px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#options .sub span { + display: block; + line-height: 30px; + float: left; +} +#options .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#options .decreaseFont {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;} +h1.alert, h2.alert {color: #000000;} + +em {font-style: normal; font-weight: bold;} + +.adminobserverooc {color: #0099cc; font-weight: bold;} +.adminooc {color: #b82e00; font-weight: bold;} +.adminobserver {color: #996600; font-weight: bold;} +.admin {color: #386aff; font-weight: bold;} +/* SAY CLASSES */ +.say {} +.deadsay {color: #5c00e6;} +.siliconsay {font-family: 'Courier New', Courier, monospace;} +/* RADIO CLASSES */ +.radio {color: #008000;} + +.syndradio {color: #6d3f40;} +.centradio {color: #686868;} + +.aiprivradio {color: #ff00ff;} +.comradio {color: #948f02;} + +.secradio {color: #a30000;} +.engradio {color: #fb5613;} +.medradio {color: #337296;} +.sciradio {color: #993399;} +.supradio {color: #a8732b;} +.servadio {color: #6eaa2c;} + +.attack {color: #ff0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.selecteddna {color: #ffffff; background-color: #001B1B} +.alert {color: #ff0000;} +.userdanger {color: #ff0000; font-weight: bold; font-size: 3;} +.danger {color: #ff0000;} +.warning {color: #ff0000; font-style: italic;} +.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} +.announce {color: #228b22; font-weight: bold;} +.boldannounce {color: #ff0000; font-weight: bold;} +.greenannounce {color: #00ff00; font-weight: bold;} +.rose {color: #ff5050;} +.info {color: #0000CC;} +.notice {color: #000099;} +.boldnotice {color: #000099; font-weight: bold;} +.adminnotice {color: #0000ff;} +.unconscious {color: #0000ff; font-weight: bold;} +.suicide {color: #ff5050; font-style: italic;} +.green {color: #03ff39;} +.shadowling {color: #3b2769;} +.cult {color: #960000;} +.cultitalic {color: #960000; font-style: italic;} +.cultlarge {color: #960000; font-weight: bold; font-size: 3;} +.narsie {color: #960000; font-weight: bold; font-size: 125px;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 6;} +.colossus {color: #7F282A; font-size: 5;} +.hierophant {color: #660099; font-weight: bold; font-style: italic;} +.hierophant_warning {color: #660099; font-style: italic;} +.purple {color: #5e2d79;} +.holoparasite {color: #35333a;} +.holoparasitebold {color: #35333a; font-weight: bold;} + +.revennotice {color: #1d2953;} +.revenboldnotice {color: #1d2953; font-weight: bold;} +.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;} +.revenminor {color: #823abb} +.revenwarning {color: #760fbb; font-style: italic;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 3;} +.umbra {color: #5000A0;} +.umbra_bold {color: #5000A0; font-weight: bold;} +.umbra_italics {color: #5000A0; font-style: italic;} +.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} +.umbra_large {color: #5000A0; font-size: 3;} + +.brass {color: #BE8700;} +.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;} +.large_brass {color: #BE8700; font-size: 3;} +.big_brass {color: #BE8700; font-size: 3; font-weight: bold; font-style: italic;} +.ratvar {color: #BE8700; font-size: 6; font-weight: bold; font-style: italic;} +.alloy {color: #42474D;} +.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;} +.large_alloy {color: #42474D; font-size: 3;} +.nezbere_large {color: #42474D; font-size: 3; font-weight: bold; font-style: italic;} +.nezbere {color: #42474D; font-weight: bold; font-style: italic;} +.nezbere_small {color: #42474D;} +.sevtug_large {color: #AF0AAF; font-size: 3; font-weight: bold; font-style: italic;} +.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;} +.sevtug_small {color: #AF0AAF;} +.inathneq_large {color: #1E8CE1; font-size: 3; font-weight: bold; font-style: italic;} +.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;} +.inathneq_small {color: #1E8CE1;} +.nzcrentr_large {color: #DAAA18; font-size: 3; font-weight: bold; font-style: italic;} +.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;} +.nzcrentr_small {color: #DAAA18;} +.neovgre_large {color: #6E001A; font-size: 3; font-weight: bold; font-style: italic;} +.neovgre {color: #6E001A; font-weight: bold; font-style: italic;} +.neovgre_small {color: #6E001A;} + +.newscaster {color: #800000;} +.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} + +.alien {color: #543354;} +.noticealien {color: #00c000;} +.alertalien {color: #00c000; font-weight: bold;} +.borer {color: #543354; font-style: italic;} +.changeling {color: #800080; font-style: italic;} + +.interface {color: #330033;} + +.sans {font-family: "Comic Sans MS", cursive, sans-serif;} +.papyrus {font-family: "Papyrus", cursive, sans-serif;} +.robot {font-family: "Courier New", cursive, sans-serif;} + +.command_headset {font-weight: bold; font-size: 3;} +.big {font-size: 3;} +.reallybig {font-size: 4;} +.greentext {color: #00FF00; font-size: 3;} +.redtext {color: #FF0000; font-size: 3;} +.clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} + +big img.icon {width: 32px; height: 32px;} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 2;} +.abductor {color: #800080; font-style: italic;} + +.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;} \ No newline at end of file diff --git a/goon/browserassets/css/font-awesome.css b/goon/browserassets/css/font-awesome.css new file mode 100644 index 00000000000..cc99d7b3374 --- /dev/null +++ b/goon/browserassets/css/font-awesome.css @@ -0,0 +1,788 @@ +@font-face{font-family:'FontAwesome';src:url('fontawesome-webfont.eot');src:url('fontawesome-webfont.eot') format('embedded-opentype'),url('fontawesome-webfont.woff') format('woff'),url('fontawesome-webfont.ttf') format('truetype'),url('fontawesome-webfont.svg') format('svg');font-weight:normal;font-style:normal;}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;} +[class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none;} +.icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em;} +a [class^="icon-"],a [class*=" icon-"]{display:inline;} +[class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:0.2857142857142857em;}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em;} +.icons-ul{margin-left:2.142857142857143em;list-style-type:none;}.icons-ul>li{position:relative;} +.icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit;} +[class^="icon-"].hide,[class*=" icon-"].hide{display:none;} +.icon-muted{color:#eeeeee;} +.icon-light{color:#ffffff;} +.icon-dark{color:#333333;} +.icon-border{border:solid 1px #eeeeee;padding:.2em .25em .15em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.icon-2x{font-size:2em;}.icon-2x.icon-border{border-width:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.icon-3x{font-size:3em;}.icon-3x.icon-border{border-width:3px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.icon-4x{font-size:4em;}.icon-4x.icon-border{border-width:4px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.icon-5x{font-size:5em;}.icon-5x.icon-border{border-width:5px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px;} +.pull-right{float:right;} +.pull-left{float:left;} +[class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em;} +[class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em;} +[class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;} +.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none;} +.btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em;} +.btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block;} +.nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em;} +.btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em;} +.btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em;} +.btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em;} +.btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0;}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em;} +.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em;} +.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em;} +.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit;} +.icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%;}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em;} +.icon-stack .icon-stack-base{font-size:2em;*line-height:1em;} +.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear;} +a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none;} +@-moz-keyframes spin{0%{-moz-transform:rotate(0deg);} 100%{-moz-transform:rotate(359deg);}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);} 100%{-webkit-transform:rotate(359deg);}}@-o-keyframes spin{0%{-o-transform:rotate(0deg);} 100%{-o-transform:rotate(359deg);}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg);} 100%{-ms-transform:rotate(359deg);}}@keyframes spin{0%{transform:rotate(0deg);} 100%{transform:rotate(359deg);}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);} +.icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);} +.icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);} +.icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1);} +.icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1);} +a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block;} +.icon-glass:before{content:"\f000";} +.icon-music:before{content:"\f001";} +.icon-search:before{content:"\f002";} +.icon-envelope-alt:before{content:"\f003";} +.icon-heart:before{content:"\f004";} +.icon-star:before{content:"\f005";} +.icon-star-empty:before{content:"\f006";} +.icon-user:before{content:"\f007";} +.icon-film:before{content:"\f008";} +.icon-th-large:before{content:"\f009";} +.icon-th:before{content:"\f00a";} +.icon-th-list:before{content:"\f00b";} +.icon-ok:before{content:"\f00c";} +.icon-remove:before{content:"\f00d";} +.icon-zoom-in:before{content:"\f00e";} +.icon-zoom-out:before{content:"\f010";} +.icon-power-off:before,.icon-off:before{content:"\f011";} +.icon-signal:before{content:"\f012";} +.icon-gear:before,.icon-cog:before{content:"\f013";} +.icon-trash:before{content:"\f014";} +.icon-home:before{content:"\f015";} +.icon-file-alt:before{content:"\f016";} +.icon-time:before{content:"\f017";} +.icon-road:before{content:"\f018";} +.icon-download-alt:before{content:"\f019";} +.icon-download:before{content:"\f01a";} +.icon-upload:before{content:"\f01b";} +.icon-inbox:before{content:"\f01c";} +.icon-play-circle:before{content:"\f01d";} +.icon-rotate-right:before,.icon-repeat:before{content:"\f01e";} +.icon-refresh:before{content:"\f021";} +.icon-list-alt:before{content:"\f022";} +.icon-lock:before{content:"\f023";} +.icon-flag:before{content:"\f024";} +.icon-headphones:before{content:"\f025";} +.icon-volume-off:before{content:"\f026";} +.icon-volume-down:before{content:"\f027";} +.icon-volume-up:before{content:"\f028";} +.icon-qrcode:before{content:"\f029";} +.icon-barcode:before{content:"\f02a";} +.icon-tag:before{content:"\f02b";} +.icon-tags:before{content:"\f02c";} +.icon-book:before{content:"\f02d";} +.icon-bookmark:before{content:"\f02e";} +.icon-print:before{content:"\f02f";} +.icon-camera:before{content:"\f030";} +.icon-font:before{content:"\f031";} +.icon-bold:before{content:"\f032";} +.icon-italic:before{content:"\f033";} +.icon-text-height:before{content:"\f034";} +.icon-text-width:before{content:"\f035";} +.icon-align-left:before{content:"\f036";} +.icon-align-center:before{content:"\f037";} +.icon-align-right:before{content:"\f038";} +.icon-align-justify:before{content:"\f039";} +.icon-list:before{content:"\f03a";} +.icon-indent-left:before{content:"\f03b";} +.icon-indent-right:before{content:"\f03c";} +.icon-facetime-video:before{content:"\f03d";} +.icon-picture:before{content:"\f03e";} +.icon-pencil:before{content:"\f040";} +.icon-map-marker:before{content:"\f041";} +.icon-adjust:before{content:"\f042";} +.icon-tint:before{content:"\f043";} +.icon-edit:before{content:"\f044";} +.icon-share:before{content:"\f045";} +.icon-check:before{content:"\f046";} +.icon-move:before{content:"\f047";} +.icon-step-backward:before{content:"\f048";} +.icon-fast-backward:before{content:"\f049";} +.icon-backward:before{content:"\f04a";} +.icon-play:before{content:"\f04b";} +.icon-pause:before{content:"\f04c";} +.icon-stop:before{content:"\f04d";} +.icon-forward:before{content:"\f04e";} +.icon-fast-forward:before{content:"\f050";} +.icon-step-forward:before{content:"\f051";} +.icon-eject:before{content:"\f052";} +.icon-chevron-left:before{content:"\f053";} +.icon-chevron-right:before{content:"\f054";} +.icon-plus-sign:before{content:"\f055";} +.icon-minus-sign:before{content:"\f056";} +.icon-remove-sign:before{content:"\f057";} +.icon-ok-sign:before{content:"\f058";} +.icon-question-sign:before{content:"\f059";} +.icon-info-sign:before{content:"\f05a";} +.icon-screenshot:before{content:"\f05b";} +.icon-remove-circle:before{content:"\f05c";} +.icon-ok-circle:before{content:"\f05d";} +.icon-ban-circle:before{content:"\f05e";} +.icon-arrow-left:before{content:"\f060";} +.icon-arrow-right:before{content:"\f061";} +.icon-arrow-up:before{content:"\f062";} +.icon-arrow-down:before{content:"\f063";} +.icon-mail-forward:before,.icon-share-alt:before{content:"\f064";} +.icon-resize-full:before{content:"\f065";} +.icon-resize-small:before{content:"\f066";} +.icon-plus:before{content:"\f067";} +.icon-minus:before{content:"\f068";} +.icon-asterisk:before{content:"\f069";} +.icon-exclamation-sign:before{content:"\f06a";} +.icon-gift:before{content:"\f06b";} +.icon-leaf:before{content:"\f06c";} +.icon-fire:before{content:"\f06d";} +.icon-eye-open:before{content:"\f06e";} +.icon-eye-close:before{content:"\f070";} +.icon-warning-sign:before{content:"\f071";} +.icon-plane:before{content:"\f072";} +.icon-calendar:before{content:"\f073";} +.icon-random:before{content:"\f074";} +.icon-comment:before{content:"\f075";} +.icon-magnet:before{content:"\f076";} +.icon-chevron-up:before{content:"\f077";} +.icon-chevron-down:before{content:"\f078";} +.icon-retweet:before{content:"\f079";} +.icon-shopping-cart:before{content:"\f07a";} +.icon-folder-close:before{content:"\f07b";} +.icon-folder-open:before{content:"\f07c";} +.icon-resize-vertical:before{content:"\f07d";} +.icon-resize-horizontal:before{content:"\f07e";} +.icon-bar-chart:before{content:"\f080";} +.icon-twitter-sign:before{content:"\f081";} +.icon-facebook-sign:before{content:"\f082";} +.icon-camera-retro:before{content:"\f083";} +.icon-key:before{content:"\f084";} +.icon-gears:before,.icon-cogs:before{content:"\f085";} +.icon-comments:before{content:"\f086";} +.icon-thumbs-up-alt:before{content:"\f087";} +.icon-thumbs-down-alt:before{content:"\f088";} +.icon-star-half:before{content:"\f089";} +.icon-heart-empty:before{content:"\f08a";} +.icon-signout:before{content:"\f08b";} +.icon-linkedin-sign:before{content:"\f08c";} +.icon-pushpin:before{content:"\f08d";} +.icon-external-link:before{content:"\f08e";} +.icon-signin:before{content:"\f090";} +.icon-trophy:before{content:"\f091";} +.icon-github-sign:before{content:"\f092";} +.icon-upload-alt:before{content:"\f093";} +.icon-lemon:before{content:"\f094";} +.icon-phone:before{content:"\f095";} +.icon-unchecked:before,.icon-check-empty:before{content:"\f096";} +.icon-bookmark-empty:before{content:"\f097";} +.icon-phone-sign:before{content:"\f098";} +.icon-twitter:before{content:"\f099";} +.icon-facebook:before{content:"\f09a";} +.icon-github:before{content:"\f09b";} +.icon-unlock:before{content:"\f09c";} +.icon-credit-card:before{content:"\f09d";} +.icon-rss:before{content:"\f09e";} +.icon-hdd:before{content:"\f0a0";} +.icon-bullhorn:before{content:"\f0a1";} +.icon-bell:before{content:"\f0a2";} +.icon-certificate:before{content:"\f0a3";} +.icon-hand-right:before{content:"\f0a4";} +.icon-hand-left:before{content:"\f0a5";} +.icon-hand-up:before{content:"\f0a6";} +.icon-hand-down:before{content:"\f0a7";} +.icon-circle-arrow-left:before{content:"\f0a8";} +.icon-circle-arrow-right:before{content:"\f0a9";} +.icon-circle-arrow-up:before{content:"\f0aa";} +.icon-circle-arrow-down:before{content:"\f0ab";} +.icon-globe:before{content:"\f0ac";} +.icon-wrench:before{content:"\f0ad";} +.icon-tasks:before{content:"\f0ae";} +.icon-filter:before{content:"\f0b0";} +.icon-briefcase:before{content:"\f0b1";} +.icon-fullscreen:before{content:"\f0b2";} +.icon-group:before{content:"\f0c0";} +.icon-link:before{content:"\f0c1";} +.icon-cloud:before{content:"\f0c2";} +.icon-beaker:before{content:"\f0c3";} +.icon-cut:before{content:"\f0c4";} +.icon-copy:before{content:"\f0c5";} +.icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6";} +.icon-save:before{content:"\f0c7";} +.icon-sign-blank:before{content:"\f0c8";} +.icon-reorder:before{content:"\f0c9";} +.icon-list-ul:before{content:"\f0ca";} +.icon-list-ol:before{content:"\f0cb";} +.icon-strikethrough:before{content:"\f0cc";} +.icon-underline:before{content:"\f0cd";} +.icon-table:before{content:"\f0ce";} +.icon-magic:before{content:"\f0d0";} +.icon-truck:before{content:"\f0d1";} +.icon-pinterest:before{content:"\f0d2";} +.icon-pinterest-sign:before{content:"\f0d3";} +.icon-google-plus-sign:before{content:"\f0d4";} +.icon-google-plus:before{content:"\f0d5";} +.icon-money:before{content:"\f0d6";} +.icon-caret-down:before{content:"\f0d7";} +.icon-caret-up:before{content:"\f0d8";} +.icon-caret-left:before{content:"\f0d9";} +.icon-caret-right:before{content:"\f0da";} +.icon-columns:before{content:"\f0db";} +.icon-sort:before{content:"\f0dc";} +.icon-sort-down:before{content:"\f0dd";} +.icon-sort-up:before{content:"\f0de";} +.icon-envelope:before{content:"\f0e0";} +.icon-linkedin:before{content:"\f0e1";} +.icon-rotate-left:before,.icon-undo:before{content:"\f0e2";} +.icon-legal:before{content:"\f0e3";} +.icon-dashboard:before{content:"\f0e4";} +.icon-comment-alt:before{content:"\f0e5";} +.icon-comments-alt:before{content:"\f0e6";} +.icon-bolt:before{content:"\f0e7";} +.icon-sitemap:before{content:"\f0e8";} +.icon-umbrella:before{content:"\f0e9";} +.icon-paste:before{content:"\f0ea";} +.icon-lightbulb:before{content:"\f0eb";} +.icon-exchange:before{content:"\f0ec";} +.icon-cloud-download:before{content:"\f0ed";} +.icon-cloud-upload:before{content:"\f0ee";} +.icon-user-md:before{content:"\f0f0";} +.icon-stethoscope:before{content:"\f0f1";} +.icon-suitcase:before{content:"\f0f2";} +.icon-bell-alt:before{content:"\f0f3";} +.icon-coffee:before{content:"\f0f4";} +.icon-food:before{content:"\f0f5";} +.icon-file-text-alt:before{content:"\f0f6";} +.icon-building:before{content:"\f0f7";} +.icon-hospital:before{content:"\f0f8";} +.icon-ambulance:before{content:"\f0f9";} +.icon-medkit:before{content:"\f0fa";} +.icon-fighter-jet:before{content:"\f0fb";} +.icon-beer:before{content:"\f0fc";} +.icon-h-sign:before{content:"\f0fd";} +.icon-plus-sign-alt:before{content:"\f0fe";} +.icon-double-angle-left:before{content:"\f100";} +.icon-double-angle-right:before{content:"\f101";} +.icon-double-angle-up:before{content:"\f102";} +.icon-double-angle-down:before{content:"\f103";} +.icon-angle-left:before{content:"\f104";} +.icon-angle-right:before{content:"\f105";} +.icon-angle-up:before{content:"\f106";} +.icon-angle-down:before{content:"\f107";} +.icon-desktop:before{content:"\f108";} +.icon-laptop:before{content:"\f109";} +.icon-tablet:before{content:"\f10a";} +.icon-mobile-phone:before{content:"\f10b";} +.icon-circle-blank:before{content:"\f10c";} +.icon-quote-left:before{content:"\f10d";} +.icon-quote-right:before{content:"\f10e";} +.icon-spinner:before{content:"\f110";} +.icon-circle:before{content:"\f111";} +.icon-mail-reply:before,.icon-reply:before{content:"\f112";} +.icon-github-alt:before{content:"\f113";} +.icon-folder-close-alt:before{content:"\f114";} +.icon-folder-open-alt:before{content:"\f115";} +.icon-expand-alt:before{content:"\f116";} +.icon-collapse-alt:before{content:"\f117";} +.icon-smile:before{content:"\f118";} +.icon-frown:before{content:"\f119";} +.icon-meh:before{content:"\f11a";} +.icon-gamepad:before{content:"\f11b";} +.icon-keyboard:before{content:"\f11c";} +.icon-flag-alt:before{content:"\f11d";} +.icon-flag-checkered:before{content:"\f11e";} +.icon-terminal:before{content:"\f120";} +.icon-code:before{content:"\f121";} +.icon-reply-all:before{content:"\f122";} +.icon-mail-reply-all:before{content:"\f122";} +.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123";} +.icon-location-arrow:before{content:"\f124";} +.icon-crop:before{content:"\f125";} +.icon-code-fork:before{content:"\f126";} +.icon-unlink:before{content:"\f127";} +.icon-question:before{content:"\f128";} +.icon-info:before{content:"\f129";} +.icon-exclamation:before{content:"\f12a";} +.icon-superscript:before{content:"\f12b";} +.icon-subscript:before{content:"\f12c";} +.icon-eraser:before{content:"\f12d";} +.icon-puzzle-piece:before{content:"\f12e";} +.icon-microphone:before{content:"\f130";} +.icon-microphone-off:before{content:"\f131";} +.icon-shield:before{content:"\f132";} +.icon-calendar-empty:before{content:"\f133";} +.icon-fire-extinguisher:before{content:"\f134";} +.icon-rocket:before{content:"\f135";} +.icon-maxcdn:before{content:"\f136";} +.icon-chevron-sign-left:before{content:"\f137";} +.icon-chevron-sign-right:before{content:"\f138";} +.icon-chevron-sign-up:before{content:"\f139";} +.icon-chevron-sign-down:before{content:"\f13a";} +.icon-html5:before{content:"\f13b";} +.icon-css3:before{content:"\f13c";} +.icon-anchor:before{content:"\f13d";} +.icon-unlock-alt:before{content:"\f13e";} +.icon-bullseye:before{content:"\f140";} +.icon-ellipsis-horizontal:before{content:"\f141";} +.icon-ellipsis-vertical:before{content:"\f142";} +.icon-rss-sign:before{content:"\f143";} +.icon-play-sign:before{content:"\f144";} +.icon-ticket:before{content:"\f145";} +.icon-minus-sign-alt:before{content:"\f146";} +.icon-check-minus:before{content:"\f147";} +.icon-level-up:before{content:"\f148";} +.icon-level-down:before{content:"\f149";} +.icon-check-sign:before{content:"\f14a";} +.icon-edit-sign:before{content:"\f14b";} +.icon-external-link-sign:before{content:"\f14c";} +.icon-share-sign:before{content:"\f14d";} +.icon-compass:before{content:"\f14e";} +.icon-collapse:before{content:"\f150";} +.icon-collapse-top:before{content:"\f151";} +.icon-expand:before{content:"\f152";} +.icon-euro:before,.icon-eur:before{content:"\f153";} +.icon-gbp:before{content:"\f154";} +.icon-dollar:before,.icon-usd:before{content:"\f155";} +.icon-rupee:before,.icon-inr:before{content:"\f156";} +.icon-yen:before,.icon-jpy:before{content:"\f157";} +.icon-renminbi:before,.icon-cny:before{content:"\f158";} +.icon-won:before,.icon-krw:before{content:"\f159";} +.icon-bitcoin:before,.icon-btc:before{content:"\f15a";} +.icon-file:before{content:"\f15b";} +.icon-file-text:before{content:"\f15c";} +.icon-sort-by-alphabet:before{content:"\f15d";} +.icon-sort-by-alphabet-alt:before{content:"\f15e";} +.icon-sort-by-attributes:before{content:"\f160";} +.icon-sort-by-attributes-alt:before{content:"\f161";} +.icon-sort-by-order:before{content:"\f162";} +.icon-sort-by-order-alt:before{content:"\f163";} +.icon-thumbs-up:before{content:"\f164";} +.icon-thumbs-down:before{content:"\f165";} +.icon-youtube-sign:before{content:"\f166";} +.icon-youtube:before{content:"\f167";} +.icon-xing:before{content:"\f168";} +.icon-xing-sign:before{content:"\f169";} +.icon-youtube-play:before{content:"\f16a";} +.icon-dropbox:before{content:"\f16b";} +.icon-stackexchange:before{content:"\f16c";} +.icon-instagram:before{content:"\f16d";} +.icon-flickr:before{content:"\f16e";} +.icon-adn:before{content:"\f170";} +.icon-bitbucket:before{content:"\f171";} +.icon-bitbucket-sign:before{content:"\f172";} +.icon-tumblr:before{content:"\f173";} +.icon-tumblr-sign:before{content:"\f174";} +.icon-long-arrow-down:before{content:"\f175";} +.icon-long-arrow-up:before{content:"\f176";} +.icon-long-arrow-left:before{content:"\f177";} +.icon-long-arrow-right:before{content:"\f178";} +.icon-apple:before{content:"\f179";} +.icon-windows:before{content:"\f17a";} +.icon-android:before{content:"\f17b";} +.icon-linux:before{content:"\f17c";} +.icon-dribbble:before{content:"\f17d";} +.icon-skype:before{content:"\f17e";} +.icon-foursquare:before{content:"\f180";} +.icon-trello:before{content:"\f181";} +.icon-female:before{content:"\f182";} +.icon-male:before{content:"\f183";} +.icon-gittip:before{content:"\f184";} +.icon-sun:before{content:"\f185";} +.icon-moon:before{content:"\f186";} +.icon-archive:before{content:"\f187";} +.icon-bug:before{content:"\f188";} +.icon-vk:before{content:"\f189";} +.icon-weibo:before{content:"\f18a";} +.icon-renren:before{content:"\f18b";} + +.icon-large{font-size:1.3333333333333333em;margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px;vertical-align:middle;} +.nav [class^="icon-"],.nav [class*=" icon-"]{vertical-align:inherit;margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px;}.nav [class^="icon-"].icon-large,.nav [class*=" icon-"].icon-large{vertical-align:-25%;} +.nav-pills [class^="icon-"].icon-large,.nav-tabs [class^="icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large{line-height:.75em;margin-top:-7px;padding-top:5px;margin-bottom:-5px;padding-bottom:4px;} +.btn [class^="icon-"].pull-left,.btn [class*=" icon-"].pull-left,.btn [class^="icon-"].pull-right,.btn [class*=" icon-"].pull-right{vertical-align:inherit;} +.btn [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large{margin-top:-0.5em;} +a [class^="icon-"],a [class*=" icon-"]{cursor:pointer;} +.icon-glass{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-music{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-search{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-envelope-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-heart{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-user{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-film{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-th-large{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-th{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-th-list{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ok{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-remove{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-zoom-in{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-zoom-out{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-power-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-signal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cog{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gear{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-trash{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-home{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-time{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-road{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-download-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-download{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-upload{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-inbox{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-play-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-repeat{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rotate-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-refresh{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-lock{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flag{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-headphones{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-volume-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-volume-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-volume-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-qrcode{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-barcode{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tag{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tags{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-book{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bookmark{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-print{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-camera{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-font{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bold{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-italic{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-text-height{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-text-width{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-center{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-align-justify{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-indent-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-indent-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-facetime-video{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-picture{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pencil{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-map-marker{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-adjust{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tint{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-edit{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-share{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-move{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-step-backward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fast-backward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-backward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-play{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pause{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-stop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fast-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-step-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eject{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plus-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-minus-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-remove-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ok-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-question-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-info-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-screenshot{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-remove-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ok-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ban-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-arrow-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-share-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mail-forward{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-full{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-small{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-minus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-asterisk{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-exclamation-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gift{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-leaf{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fire{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eye-open{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eye-close{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-warning-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plane{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-calendar{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-random{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comment{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-magnet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-retweet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-shopping-cart{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-close{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-open{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-vertical{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-resize-horizontal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bar-chart{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-twitter-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-facebook-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-camera-retro{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-key{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cogs{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gears{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comments{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-up-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-down-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-half{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-heart-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-signout{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-linkedin-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pushpin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-external-link{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-signin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-trophy{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-github-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-upload-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-lemon{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-phone{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unchecked{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bookmark-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-phone-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-twitter{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-facebook{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-github{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unlock{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-credit-card{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rss{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hdd{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bullhorn{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bell{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-certificate{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hand-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-arrow-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-globe{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-wrench{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tasks{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-filter{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-briefcase{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fullscreen{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-group{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-link{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cloud{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-beaker{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cut{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-copy{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-paper-clip{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-paperclip{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-save{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sign-blank{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-reorder{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list-ul{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-list-ol{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-strikethrough{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-underline{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-table{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-magic{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-truck{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pinterest{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-pinterest-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-google-plus-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-google-plus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-money{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-caret-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-columns{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-envelope{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-linkedin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-undo{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rotate-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-legal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dashboard{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comment-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-comments-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bolt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sitemap{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-umbrella{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-paste{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-lightbulb{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-exchange{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cloud-download{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cloud-upload{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-user-md{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-stethoscope{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-suitcase{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bell-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-coffee{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-food{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file-text-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-building{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-hospital{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ambulance{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-medkit{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fighter-jet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-beer{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-h-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-plus-sign-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-double-angle-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-angle-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-desktop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-laptop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tablet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mobile-phone{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle-blank{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-quote-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-quote-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-spinner{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-circle{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-reply{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mail-reply{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-github-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-close-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-folder-open-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-expand-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-collapse-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-smile{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-frown{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-meh{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gamepad{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-keyboard{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flag-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flag-checkered{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-terminal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-code{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-reply-all{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-mail-reply-all{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-half-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-star-half-full{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-location-arrow{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-crop{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-code-fork{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unlink{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-question{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-info{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-exclamation{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-superscript{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-subscript{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eraser{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-puzzle-piece{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-microphone{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-microphone-off{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-shield{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-calendar-empty{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-fire-extinguisher{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rocket{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-maxcdn{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-chevron-sign-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-html5{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-css3{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-anchor{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-unlock-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bullseye{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ellipsis-horizontal{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ellipsis-vertical{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rss-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-play-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-ticket{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-minus-sign-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check-minus{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-level-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-level-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-check-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-edit-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-external-link-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-share-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-compass{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-collapse{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-collapse-top{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-expand{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-eur{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-euro{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gbp{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-usd{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dollar{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-inr{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-rupee{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-jpy{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-yen{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-cny{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-renminbi{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-krw{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-won{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-btc{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bitcoin{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-file-text{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-alphabet{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-alphabet-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-attributes{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-attributes-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-order{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sort-by-order-alt{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-thumbs-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-youtube-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-youtube{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-xing{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-xing-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-youtube-play{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dropbox{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-stackexchange{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-instagram{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-flickr{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-adn{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bitbucket{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bitbucket-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tumblr{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-tumblr-sign{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-down{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-up{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-left{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-long-arrow-right{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-apple{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-windows{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-android{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-linux{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-dribbble{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-skype{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-foursquare{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-trello{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-female{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-male{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-gittip{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-sun{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-moon{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-archive{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-bug{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-vk{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-weibo{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} +.icon-renren{*zoom:expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '');} \ No newline at end of file diff --git a/goon/browserassets/html/browserOutput.html b/goon/browserassets/html/browserOutput.html new file mode 100644 index 00000000000..74212fd8156 --- /dev/null +++ b/goon/browserassets/html/browserOutput.html @@ -0,0 +1,44 @@ + + + + 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. +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js new file mode 100644 index 00000000000..0fb7386dd86 --- /dev/null +++ b/goon/browserassets/js/browserOutput.js @@ -0,0 +1,908 @@ +/***************************************** +* +* 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, $subOptions, $contextMenu, $filterMessages; +var opts = { + //General + 'messageCount': 0, //A count...of messages... + 'messageLimit': 2053, //A limit...for the messages... + 'scrollSnapTolerance': 5, //If within x pixels of bottom + 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup + 'popups': 0, //Amount of popups opened ever + 'wasd': false, //Is the user in wasd mode? + 'chatMode': 'default', //The mode the chat is in + 'priorChatHeight': 0, //Thing for height-resizing detection + 'restarting': false, //Is the round restarting? + + //Options menu + 'subOptionsLoop': null, //Contains the interval loop for closing the options menu + 'suppressOptionsClose': false, //Whether or not we should be hiding the suboptions 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': 35000, + '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': [], + +}; + +function outerHTML(el) { + var wrap = document.createElement('div'); + wrap.appendChild(el.cloneNode(true)); + return wrap.innerHTML; +} + +//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, ''); + }; +} + +//Shit fucking piece of crap that doesn't work god fuckin damn it +function linkify(text) { + var rex = /((?:'+$0+''; + } + else { + return $1 ? $0: ''+$0+''; + } + }); +} + +//Actually turns the highlight term match into appropriate html +function addHighlightMarkup(match) { + var extra = ''; + if (opts.highlightColor) { + extra += ' style="background-color: '+opts.highlightColor+'"'; + } + return ''+match+''; +} + +//Highlights words based on user settings +function highlightTerms(el) { + if (el.children.length > 0) { + for(var h = 0; h < el.children.length; h++){ + highlightTerms(el.children[h]); + } + } + + var hasTextNode = false; + for (var node = 0; node < el.childNodes.length; node++) + { + if (el.childNodes[node].nodeType === 3) + { + hasTextNode = true; + break; + } + } + + if (hasTextNode) { //If element actually has text + var newText = ''; + for (var c = 0; c < el.childNodes.length; c++) { //Each child element + if (el.childNodes[c].nodeType === 3) { //Is it text only? + var words = el.childNodes[c].data.split(' '); + for (var w = 0; w < words.length; w++) { //Each word in the text + var newWord = null; + for (var i = 0; i < opts.highlightTerms.length; i++) { //Each highlight term + if (opts.highlightTerms[i] && words[w].toLowerCase().indexOf(opts.highlightTerms[i].toLowerCase()) > -1) { //If a match is found + newWord = words[w].replace("<", "<").replace(new RegExp(opts.highlightTerms[i], 'gi'), addHighlightMarkup); + break; + } + console.log(newWord) + } + newText += newWord || words[w].replace("<", "<"); + newText += w >= words.length ? '' : ' '; + } + } else { //Every other type of element + newText += outerHTML(el.childNodes[c]); + } + } + el.innerHTML = newText; + } +} +//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(); + + // 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") + message = decoder(message) + + //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 '); + } + } + } + + //Url stuff + if (message.length && flag != 'preventLink') { + message = linkify(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 + } + + //Actually append the message + var entry = document.createElement('div'); + entry.className = 'entry'; + + if (filteredOut) { + entry.className += ' hidden'; + entry.setAttribute('data-filter', filteredOut); + } + + entry.innerHTML = message.trim(); + $messages[0].appendChild(entry); + + //Actually do the snap + if (!filteredOut && atBottom) { + $('body,html').scrollTop($messages.outerHeight()); + } + + //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); + } +} + +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; +} + +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 changeMode(mode) { + switch (mode) { + case 'geocities': + //switch in stylesheet + opts.chatMode = mode; + break; + case 'console': + + opts.chatMode = mode; + break; + case 'default': + default: + //remove loaded stylesheet/s + opts.chatMode = 'default'; + } +} + +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 + } + } + + if (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 if (data == 'stopaudio') { + $('.dectalk').remove(); + } 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.modeChange) { + changeMode(data.modeChange); + } else if (data.firebug) { + if (data.trigger) { + internalOutput('Loading firebug console, triggered by '+data.trigger+'...', 'internal'); + } else { + internalOutput('Loading firebug console...', 'internal'); + } + var firebugEl = document.createElement('script'); + firebugEl.src = 'https://getfirebug.com/firebug-lite-debug.js'; + document.body.appendChild(firebugEl); + } else if (data.dectalk) { + var message = ''; + if (data.decTalkTrigger) { + message = ' '+ + 'You hear a strange robotic voice...' + message; + } + internalOutput(message, 'preventLink'); + } + } +} + +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); +} + +/***************************************** +* +* DOM READY +* +******************************************/ + +if (typeof $ === 'undefined') { + var div = document.getElementById('loading').childNodes[1]; + div += '

ERROR: Jquery did not load.'; +} + +$(function() { + $messages = $('#messages'); + $subOptions = $('#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 = { + 'sfontSize': getCookie('fontsize'), + 'sfontType': getCookie('fonttype'), + 'spingDisabled': getCookie('pingdisabled'), + 'shighlightTerms': getCookie('highlightterms'), + 'shighlightColor': getCookie('highlightcolor'), + }; + + if (savedConfig.sfontSize) { + $messages.css('font-size', savedConfig.sfontSize); + internalOutput('Loaded font size setting of: '+savedConfig.sfontSize+'', 'internal'); + } + if (savedConfig.sfontType) { + $messages.css('font-family', savedConfig.sfontType); + internalOutput('Loaded font type setting of: '+savedConfig.sfontType+'', 'internal'); + } + 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); + var actualTerms = ''; + for (var i = 0; i < savedTerms.length; i++) { + if (savedTerms[i]) { + actualTerms += savedTerms[i] + ', '; + } + } + if (actualTerms) { + actualTerms = actualTerms.substring(0, actualTerms.length - 2); + 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'); + } + + (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 ($subOptions && $subOptions.is(':visible')) { + $subOptions.slideUp('fast', function() { + $(this).removeClass('scroll'); + $(this).css('height', ''); + }); + clearInterval(opts.subOptionsLoop); + } + }); + + $('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); + } + }); + + //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; + } + + e.preventDefault() + + var k = e.which; + var command; // Command to execute through winset. + + // Hardcoded because else there would be no feedback message. + if (k == 113) { // F2 + runByond('byond://winset?screenshot=auto'); + internalOutput('Screenshot taken', 'internal'); + } + + var c = ""; + switch (k) { + case 8: + c = 'BACK'; + case 9: + c = 'TAB'; + case 13: + c = 'ENTER'; + case 19: + c = 'PAUSE'; + case 27: + c = 'ESCAPE'; + case 33: // Page up + c = 'NORTHEAST'; + case 34: // Page down + c = 'SOUTHEAST'; + case 35: // End + c = 'SOUTHWEST'; + case 36: // Home + c = 'NORTHWEST'; + case 37: + c = 'WEST'; + case 38: + c = 'NORTH'; + case 39: + c = 'EAST'; + case 40: + c = 'SOUTH'; + case 45: + c = 'INSERT'; + case 46: + c = 'DELETE'; + case 93: // That weird thing to the right of alt gr. + c = 'APPS'; + + default: + c = String.fromCharCode(k); + } + +// if(opts.macros.hasOwnProperty(c.toUpperCase())) + // command = opts.macros[c]; + + if (command) { + runByond('byond://winset?mapwindow.map.focus=true;command='+command); + return false; + } + else if (c.length == 0) { + if (!e.shiftKey) { + c = c.toLowerCase(); + } + runByond('byond://winset?mapwindow.map.focus=true;mainwindow.input.text='+c); + return false; + } else { + runByond('byond://winset?mapwindow.map.focus=true'); + return false; + } + }); + + //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(); + } + }); + + //Audio sound prevention + $messages.on('click', '.stopAudio', function() { + var $audio = $(this).parent().children('audio'); + if ($audio) { + $audio.remove(); + } + }); + + + /***************************************** + * + * 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) { + if ($subOptions.is(':visible')) { + $subOptions.slideUp('fast', function() { + $(this).removeClass('scroll'); + $(this).css('height', ''); + }); + clearInterval(opts.subOptionsLoop); + } else { + $subOptions.slideDown('fast', function() { + var windowHeight = $(window).height(); + var toggleHeight = $('#toggleOptions').outerHeight(); + var priorSubHeight = $subOptions.outerHeight(); + var newSubHeight = windowHeight - toggleHeight; + $(this).height(newSubHeight); + if (priorSubHeight > (windowHeight - toggleHeight)) { + $(this).addClass('scroll'); + } + }); + opts.subOptionsLoop = setInterval(function() { + if (!opts.suppressOptionsClose && $('#subOptions').is(':visible')) { + $subOptions.slideUp('fast', function() { + $(this).removeClass('scroll'); + $(this).css('height', ''); + }); + clearInterval(opts.subOptionsLoop); + } + }, 5000); //Every 5 seconds + } + }); + + $('#subOptions, #toggleOptions').mouseenter(function() { + opts.suppressOptionsClose = true; + }); + + $('#subOptions, #toggleOptions').mouseleave(function() { + opts.suppressOptionsClose = false; + }); + + $('#decreaseFont').click(function(e) { + var fontSize = parseInt($messages.css('font-size')); + fontSize = fontSize - 1 + 'px'; + $messages.css({'font-size': fontSize}); + setCookie('fontsize', fontSize, 365); + internalOutput('Font size set to '+fontSize+'', 'internal'); + }); + + $('#increaseFont').click(function(e) { + var fontSize = parseInt($messages.css('font-size')); + fontSize = fontSize + 1 + 'px'; + $messages.css({'font-size': fontSize}); + setCookie('fontsize', fontSize, 365); + internalOutput('Font size set to '+fontSize+'', 'internal'); + }); + + $('#chooseFont').click(function(e) { + if ($('.popup .changeFont').is(':visible')) {return;} + var popupContent = '
Change Font
' + + ''; + createPopup(popupContent, 200); + }); + + $('body').on('click', '#changeFont a', function(e) { + var font = $(this).attr('data-font'); + $messages.css('font-family', font); + setCookie('fonttype', font, 365); + }); + + $('#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) { + var saved = ''; + + if (window.XMLHtpRequest) { + xmlHttp = new XMLHttpRequest(); + } else { + xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); + } + xmlHttp.open('GET', 'browserOutput.css', false); + xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xmlHttp.send(); + saved += ''; + + saved += $messages.html(); + saved = saved.replace(/&/g, '&'); + saved = saved.replace(/'; + } + 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(); + + var count = 0; + while (count < opts.highlightLimit) { + var term = $('#highlightTermInput'+count).val(); + if (term) { + term = term.trim(); + if (term === '') { + opts.highlightTerms[count] = null; + } else { + opts.highlightTerms[count] = term.toLowerCase(); + } + } else { + opts.highlightTerms[count] = null; + } + count++; + } + + 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; + }); + + + /***************************************** + * + * KICK EVERYTHING OFF + * + ******************************************/ + + runByond('?_src_=chat&proc=doneLoading'); + if ($('#loading').is(':visible')) { + $('#loading').remove(); + } + $('#userBar').show(); + opts.priorChatHeight = $(window).height(); +}); \ No newline at end of file diff --git a/goon/browserassets/js/json2.min.js b/goon/browserassets/js/json2.min.js new file mode 100644 index 00000000000..d867407f265 --- /dev/null +++ b/goon/browserassets/js/json2.min.js @@ -0,0 +1 @@ +"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;u>r;r+=1)f[r]=str(r,i)||"null";return o=0===f.length?"[]":gap?"[\n"+gap+f.join(",\n"+gap)+"\n"+a+"]":"["+f.join(",")+"]",gap=a,o}if(rep&&"object"==typeof rep)for(u=rep.length,r=0;u>r;r+=1)"string"==typeof rep[r]&&(n=rep[r],o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));else for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));return o=0===f.length?"{}":gap?"{\n"+gap+f.join(",\n"+gap)+"\n"+a+"}":"{"+f.join(",")+"}",gap=a,o}}var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,r){var n;if(gap="",indent="","number"==typeof r)for(n=0;r>n;n+=1)indent+=" ";else"string"==typeof r&&(indent=r);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(t,e){var r,n,o=t[e];if(o&&"object"==typeof o)for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(n=walk(o,r),void 0!==n?o[r]=n:delete o[r]);return reviver.call(t,e,o)}var j;if(text=String(text),rx_dangerous.lastIndex=0,rx_dangerous.test(text)&&(text=text.replace(rx_dangerous,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),rx_one.test(text.replace(rx_two,"@").replace(rx_three,"]").replace(rx_four,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(); \ No newline at end of file diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm new file mode 100644 index 00000000000..5aabde155cd --- /dev/null +++ b/goon/code/datums/browserOutput.dm @@ -0,0 +1,291 @@ +/********************************* +For the main html chat area +*********************************/ + +/var/list/chatResources = list( + "code/modules/html_interface/jquery.min.js", + "goon/browserassets/js/json2.min.js", + "goon/browserassets/js/browserOutput.js", + "tgui/assets/fonts/fontawesome-webfont.eot", + "tgui/assets/fonts/fontawesome-webfont.svg", + "tgui/assets/fonts/fontawesome-webfont.ttf", + "tgui/assets/fonts/fontawesome-webfont.woff", + "goon/browserassets/css/font-awesome.css", + "goon/browserassets/css/browserOutput.css" +) + +//Precaching a bunch of shit +var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons for the browser output + +//On client, created on login +/datum/chatOutput + var/client/owner = null //client ref + var/loaded = 0 // Has the client loaded the browser output area? + var/list/messageQueue = list() //If they haven't loaded chat, this is where messages will go until they do + var/cookieSent = 0 // Has the client sent a cookie for analysis + var/list/connectionHistory = list() //Contains the connection history passed from chat cookie + var/broken = FALSE + +/datum/chatOutput/New(client/C) + . = ..() + + owner = C + // to_chat(world.log, "chatOutput: New()") + +/datum/chatOutput/proc/start() + //Check for existing chat + if(!owner) + return FALSE + + if(!winexists(owner, "browseroutput")) // Oh goddamnit. + alert(owner.mob, "Updated chat window does not exist. If you are using a custom skin file please allow the game to update.") + broken = TRUE + return FALSE + + if(winget(owner, "browseroutput", "is-disabled") == "false") //Already setup + doneLoading() + + else //Not setup + load() + + return TRUE + +/datum/chatOutput/proc/load() + set waitfor = FALSE + if(!owner) + return + + // to_chat(world.log, "chatOutput: load()") + + for(var/attempts in 1 to 5) + for(var/asset in global.chatResources) // No asset cache, just get this fucking shit SENT. + owner << browse_rsc(file(asset)) + + //log_world("Sending main chat window to client [owner.ckey]") + owner << browse(file("goon/browserassets/html/browserOutput.html"), "window=browseroutput") + sleep(14 + (chatResources.len * 7)) + if(!owner || loaded) + break + + // log_world("chatOutput: [owner.ckey] load() completed") + +/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(data) + ehjax_send(data = data) + +//Called on chat output done-loading by JS. +/datum/chatOutput/proc/doneLoading() + if(loaded) + return + + loaded = TRUE + winset(owner, "browseroutput", "is-disabled=false") + for(var/message in messageQueue) + to_chat(owner, message) + + messageQueue = null + sendClientData() + + pingLoop() + +/datum/chatOutput/proc/pingLoop() + set waitfor = FALSE + + while (owner) + ehjax_send(data = owner.is_afk(29) ? "softPang" : "pang") // SoftPang isn't handled anywhere but it'll always reset the opts.lastPang. + sleep(30) + +/datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) + if(islist(data)) + data = json_encode(data) + C << output("[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 = "") + if(!cookie) + return + + if(cookie != "none") + var/list/connData = json_decode(cookie) + if (connData && islist(connData) && connData.len > 0 && connData["connData"]) + src.connectionHistory = connData["connData"] //lol fuck + var/list/found = new() + for(var/i in connectionHistory.len to 1 step -1) + 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["compid"], row["ip"])) + found = row + break + + //Uh oh this fucker has a history of playing on a banned account!! + if (found.len > 0) + //TODO: add a new evasion ban for the CURRENT client details, using the matched row details + message_admins("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") + log_admin("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") + + 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_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") + +#ifdef TESTING +/client/verb/debug_chat() + set hidden = 1 + chatOutput.ehjax_send(data = list("firebug" = 1)) +#endif +//Global chat procs + +/var/list/bicon_cache = list() + +//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 + iconCache[iconKey] << icon + var/iconData = iconCache.ExportText(iconKey) + var/list/partial = splittext(iconData, "{") + return replacetext(copytext(partial[2], 3, -5), "\n", "") + +/proc/bicon(obj) + if (!obj) + return + + if (isicon(obj)) + //Icons get pooled constantly, references are no good here. + /*if (!bicon_cache["\ref[obj]"]) // Doesn't exist yet, make it. + bicon_cache["\ref[obj]"] = icon2base64(obj) + return ""*/ + return "" + + // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. + var/atom/A = obj + 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(obj)) // Shitty workaround for a BYOND issue. + var/icon/temp = I + I = icon() + I.Insert(temp, dir = SOUTH) + bicon_cache[key] = icon2base64(I, key) + + return "" + +//Aliases for bicon +/proc/bi(obj) + bicon(obj) + +//Costlier version of bicon() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. +/proc/costly_bicon(obj) + if (!obj) + return + + if (isicon(obj)) + return bicon(obj) + + var/icon/I = getFlatIcon(obj) + return bicon(I) + +/proc/to_chat(target, message) + if(isnull(target)) + return + //Ok so I did my best but I accept that some calls to this will be for shit like sound and images + //It stands that we PROBABLY don't want to output those to the browser output so just handle them here + if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || islist(target) || istype(target, /client) || istype(target, /datum/log) || target == world)) + target << message + if (!istype(target, /atom)) // Really easy to mix these up, and not having to make sure things are mobs makes the code cleaner. + CRASH("DEBUG: Boutput called with invalid message") + return + + //Otherwise, we're good to throw it at the user + else if (istext(message)) + if (istext(target)) + return + + //Some macros remain in the string even after parsing and fuck up the eventual output + if (findtext(message, "\improper")) + message = replacetext(message, "\improper", "") + if (findtext(message, "\proper")) + message = replacetext(message, "\proper", "") + + //Grab us a client if possible + var/client/C = grab_client(target) + + if (C && C.chatOutput) + if(C.chatOutput.broken) // A player who hasn't updated his skin file. + to_chat(C, message) + return 1 + if(!C.chatOutput.loaded && C.chatOutput.messageQueue && islist(C.chatOutput.messageQueue)) + //Client sucks at loading things, put their messages in a queue + C.chatOutput.messageQueue.Add(message) + return + + if(istype(target, /datum/log)) + var/datum/log/L = target + L.log += (message + "\n") + return + + message = replacetext(message, "\n", "
") + message = replacetext(message, "\t", "    ") + + // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + target << output(url_encode(url_encode(message)), "browseroutput:output") + +/proc/grab_client(target) + if(istype(target, /client)) + return target + else if(istype(target, /mob)) + var/mob/M = target + if(M.client) + return M.client + else if(istype(target, /datum/mind)) + var/datum/mind/M = target + if(M.current && M.current.client) + return M.current.client + +/datum/log //exists purely to capture to_chat() output + var/log = "" \ No newline at end of file diff --git a/interface/skin.dmf b/interface/skin.dmf index 16acfc33f2f..0c69e8d9e2c 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1659,8 +1659,8 @@ window "outputwindow" macro = "" menu = "" on-close = "" - elem "output" - type = OUTPUT + elem "browseroutput" + type = BROWSER pos = 0,0 size = 640x480 anchor1 = 0,0 @@ -1671,20 +1671,20 @@ window "outputwindow" text-color = #000000 background-color = #ffffff is-visible = true - is-disabled = false + is-disabled = true is-transparent = false - is-default = true + is-default = false border = none drop-zone = false right-click = false - saved-params = "max-lines" + saved-params = "" on-size = "" - link-color = #0000ff - visited-color = #ff00ff - style = "" - enable-http-images = false - max-lines = 1000 - image = "" + show-history = false + show-url = false + auto-format = false + use-title = false + on_show = "" + on_hide = "" window "statwindow" elem "statwindow" @@ -1759,4 +1759,3 @@ window "statwindow" on-tab = "" prefix-color = none suffix-color = none - diff --git a/tgstation.dme b/tgstation.dme index 92b318371da..b2894190e8d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2061,7 +2061,7 @@ #include "code\orphaned_procs\dbcore.dm" #include "code\orphaned_procs\priority_announce.dm" #include "code\orphaned_procs\statistics.dm" +#include "goon\code\datums\browserOutput.dm" #include "interface\interface.dm" -#include "interface\stylesheet.dm" #include "interface\skin.dmf" // END_INCLUDE From 2082a248d9aad972d68914d2f1f6730767051921 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Mon, 24 Apr 2017 22:12:01 -0300 Subject: [PATCH 02/47] Bicon conversion --- code/__HELPERS/icons.dm | 2 +- code/__HELPERS/unsorted.dm | 4 +- code/datums/wires/mulebot.dm | 10 ++-- code/datums/wires/particle_accelerator.dm | 2 +- code/datums/wires/syndicatebomb.dm | 24 ++++---- code/game/atoms.dm | 2 +- code/game/gamemodes/clock_cult/clock_mobs.dm | 2 +- .../gamemodes/devil/true_devil/_true_devil.dm | 6 +- code/game/gamemodes/gang/gang_datum.dm | 2 +- code/game/gamemodes/gang/gang_pen.dm | 2 +- code/game/gamemodes/gang/recaller.dm | 18 +++--- code/game/machinery/computer/message.dm | 8 +-- code/game/machinery/machinery.dm | 2 +- code/game/machinery/overview.dm | 8 +-- code/game/machinery/syndicatebomb.dm | 10 ++-- code/game/machinery/telecomms/broadcasting.dm | 2 +- code/game/mecha/equipment/mecha_equipment.dm | 2 +- code/game/mecha/mecha.dm | 6 +- .../effects/decals/Cleanable/humans.dm | 2 +- code/game/objects/effects/mines.dm | 2 +- code/game/objects/items/devices/PDA/PDA.dm | 4 +- .../objects/items/devices/geiger_counter.dm | 14 ++--- code/game/objects/items/toys.dm | 4 +- code/game/objects/items/weapons/AI_modules.dm | 2 +- code/game/objects/items/weapons/cards_ids.dm | 2 +- code/modules/admin/verbs/pray.dm | 2 +- code/modules/assembly/bomb.dm | 2 +- code/modules/assembly/health.dm | 2 +- code/modules/assembly/infrared.dm | 2 +- code/modules/assembly/proximity.dm | 2 +- code/modules/assembly/signaler.dm | 2 +- code/modules/assembly/timer.dm | 2 +- .../modules/clothing/spacesuits/flightsuit.dm | 14 ++--- code/modules/clothing/spacesuits/hardsuit.dm | 2 +- code/modules/emoji/emoji_parse.dm | 2 +- .../kitchen_machinery/icecream_vat.dm | 2 +- code/modules/food_and_drinks/pizzabox.dm | 2 +- code/modules/mob/living/carbon/examine.dm | 16 ++--- .../mob/living/carbon/human/examine.dm | 58 +++++++++---------- .../mob/living/carbon/human/human_defense.dm | 4 +- code/modules/mob/living/silicon/ai/examine.dm | 2 +- .../mob/living/silicon/pai/software.dm | 2 +- .../mob/living/silicon/robot/examine.dm | 4 +- .../mob/living/simple_animal/bot/bot.dm | 6 +- .../mob/living/simple_animal/bot/mulebot.dm | 2 +- .../mob/living/simple_animal/constructs.dm | 2 +- .../simple_animal/friendly/drone/_drone.dm | 14 ++--- .../living/simple_animal/friendly/mouse.dm | 2 +- .../simple_animal/guardian/types/dextrous.dm | 10 ++-- .../mob/living/simple_animal/slime/slime.dm | 2 +- code/modules/reagents/chemistry/holder.dm | 4 +- code/modules/recycling/conveyor2.dm | 2 +- code/modules/uplink/uplink_item.dm | 6 +- 53 files changed, 157 insertions(+), 157 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 69349bcc982..f971aecf5d1 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -167,7 +167,7 @@ mob Output_Icon() set name = "2. Output Icon" - to_chat(src, "Icon is: \icon[getFlatIcon(src)]") + to_chat(src, "Icon is: [bicon(getFlatIcon(src))]") Label_Icon() set name = "3. Label Icon" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index ac2a2d7245d..c7402ee8660 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -832,11 +832,11 @@ var/list/WALLITEMS_INVERSE = typecacheof(list( /obj/proc/atmosanalyzer_scan(datum/gas_mixture/air_contents, mob/user, obj/target = src) var/obj/icon = target - user.visible_message("[user] has used the analyzer on \icon[icon] [target].", "You use the analyzer on \icon[icon] [target].") + user.visible_message("[user] has used the analyzer on [bicon(icon)] [target].", "You use the analyzer on [bicon(icon)] [target].") var/pressure = air_contents.return_pressure() var/total_moles = air_contents.total_moles() - to_chat(user, "Results of analysis of \icon[icon] [target].") + to_chat(user, "Results of analysis of [bicon(icon)] [target].") if(total_moles>0) to_chat(user, "Pressure: [round(pressure,0.1)] kPa") diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm index bec3a5d73c8..00b2dd10b89 100644 --- a/code/datums/wires/mulebot.dm +++ b/code/datums/wires/mulebot.dm @@ -20,12 +20,12 @@ var/mob/living/simple_animal/bot/mulebot/M = holder switch(wire) if(WIRE_POWER1, WIRE_POWER2) - holder.visible_message("\icon[M] The charge light flickers.") + holder.visible_message("[bicon(M)] The charge light flickers.") if(WIRE_AVOIDANCE) - holder.visible_message("\icon[M] The external warning lights flash briefly.") + holder.visible_message("[bicon(M)] The external warning lights flash briefly.") if(WIRE_LOADCHECK) - holder.visible_message("\icon[M] The load platform clunks.") + holder.visible_message("[bicon(M)] The load platform clunks.") if(WIRE_MOTOR1, WIRE_MOTOR2) - holder.visible_message("\icon[M] The drive motor whines briefly.") + holder.visible_message("[bicon(M)] The drive motor whines briefly.") else - holder.visible_message("\icon[M] You hear a radio crackle.") \ No newline at end of file + holder.visible_message("[bicon(M)] You hear a radio crackle.") \ No newline at end of file diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm index 6c69742f9b1..436b8be3ecd 100644 --- a/code/datums/wires/particle_accelerator.dm +++ b/code/datums/wires/particle_accelerator.dm @@ -25,7 +25,7 @@ if(WIRE_INTERFACE) C.interface_control = !C.interface_control if(WIRE_LIMIT) - C.visible_message("\icon[C][C] makes a large whirring noise.") + C.visible_message("[bicon(C)][C] makes a large whirring noise.") /datum/wires/particle_accelerator/control_box/on_cut(wire, mend) var/obj/machinery/particle_accelerator/control_box/C = holder diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm index 80b5a9d6518..78acc42eb04 100644 --- a/code/datums/wires/syndicatebomb.dm +++ b/code/datums/wires/syndicatebomb.dm @@ -19,21 +19,21 @@ switch(wire) if(WIRE_BOOM) if(B.active) - holder.visible_message("\icon[B] An alarm sounds! It's go-") + holder.visible_message("[bicon(B)] An alarm sounds! It's go-") B.explode_now = TRUE tell_admins(B) if(WIRE_UNBOLT) - holder.visible_message("\icon[B] The bolts spin in place for a moment.") + holder.visible_message("[bicon(B)] The bolts spin in place for a moment.") if(WIRE_DELAY) if(B.delayedbig) - holder.visible_message("\icon[B] The bomb has already been delayed.") + holder.visible_message("[bicon(B)] The bomb has already been delayed.") else - holder.visible_message("\icon[B] The bomb chirps.") + holder.visible_message("[bicon(B)] The bomb chirps.") playsound(B, 'sound/machines/chime.ogg', 30, 1) B.detonation_timer += 300 B.delayedbig = TRUE if(WIRE_PROCEED) - holder.visible_message("\icon[B] The bomb buzzes ominously!") + holder.visible_message("[bicon(B)] The bomb buzzes ominously!") playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1) var/seconds = B.seconds_remaining() if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them. @@ -44,13 +44,13 @@ B.detonation_timer = world.time + 100 if(WIRE_ACTIVATE) if(!B.active && !B.defused) - holder.visible_message("\icon[B] You hear the bomb start ticking!") + holder.visible_message("[bicon(B)] You hear the bomb start ticking!") B.activate() B.update_icon() else if(B.delayedlittle) - holder.visible_message("\icon[B] Nothing happens.") + holder.visible_message("[bicon(B)] Nothing happens.") else - holder.visible_message("\icon[B] The bomb seems to hesitate for a moment.") + holder.visible_message("[bicon(B)] The bomb seems to hesitate for a moment.") B.detonation_timer += 100 B.delayedlittle = TRUE @@ -62,24 +62,24 @@ B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage. else if(B.active) - holder.visible_message("\icon[B] An alarm sounds! It's go-") + holder.visible_message("[bicon(B)] An alarm sounds! It's go-") B.explode_now = TRUE tell_admins(B) else B.defused = TRUE if(WIRE_UNBOLT) if(!mend && B.anchored) - holder.visible_message("\icon[B] The bolts lift out of the ground!") + holder.visible_message("[bicon(B)] The bolts lift out of the ground!") playsound(B, 'sound/effects/stealthoff.ogg', 30, 1) B.anchored = FALSE if(WIRE_PROCEED) if(!mend && B.active) - holder.visible_message("\icon[B] An alarm sounds! It's go-") + holder.visible_message("[bicon(B)] An alarm sounds! It's go-") B.explode_now = TRUE tell_admins(B) if(WIRE_ACTIVATE) if(!mend && B.active) - holder.visible_message("\icon[B] The timer stops! The bomb has been defused!") + holder.visible_message("[bicon(B)] The timer stops! The bomb has been defused!") B.active = FALSE B.defused = TRUE B.update_icon() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 8f47ae1656f..c60641cc272 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -235,7 +235,7 @@ f_name = "a " f_name += "blood-stained [name]!" - to_chat(user, "\icon[src] That's [f_name]") + to_chat(user, "[bicon(src)] That's [f_name]") if(desc) to_chat(user, desc) diff --git a/code/game/gamemodes/clock_cult/clock_mobs.dm b/code/game/gamemodes/clock_cult/clock_mobs.dm index 3538a8a557c..1a90ce07070 100644 --- a/code/game/gamemodes/clock_cult/clock_mobs.dm +++ b/code/game/gamemodes/clock_cult/clock_mobs.dm @@ -38,7 +38,7 @@ /mob/living/simple_animal/hostile/clockwork/examine(mob/user) var/t_He = p_they(TRUE) var/t_s = p_s() - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" msg += "[desc]\n" if(health < maxHealth) msg += "" diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm index c7af40414b5..3d35b5551c6 100644 --- a/code/game/gamemodes/devil/true_devil/_true_devil.dm +++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm @@ -65,15 +65,15 @@ /mob/living/carbon/true_devil/examine(mob/user) - var/msg = "*---------*\nThis is \icon[src] [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] [src]!\n" //Left hand items for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "It is holding \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "It is holding [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "It is holding \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "It is holding [bicon(I)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" //Braindead if(!client && stat != DEAD) diff --git a/code/game/gamemodes/gang/gang_datum.dm b/code/game/gamemodes/gang/gang_datum.dm index 78d75c957f4..e4d932da217 100644 --- a/code/game/gamemodes/gang/gang_datum.dm +++ b/code/game/gamemodes/gang/gang_datum.dm @@ -159,7 +159,7 @@ var/mob/living/mob = get(tool.loc,/mob/living) if(mob && mob.mind && mob.stat == CONSCIOUS) if(mob.mind.gang_datum == src) - to_chat(mob, "\icon[tool] [message]") + to_chat(mob, "[bicon(tool)] [message]") return diff --git a/code/game/gamemodes/gang/gang_pen.dm b/code/game/gamemodes/gang/gang_pen.dm index fb7dbf52581..b4bc4f912d3 100644 --- a/code/game/gamemodes/gang/gang_pen.dm +++ b/code/game/gamemodes/gang/gang_pen.dm @@ -56,4 +56,4 @@ cooldown = 0 icon_state = "pen" var/mob/M = get(src, /mob) - to_chat(M, "\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.") + to_chat(M, "[bicon(src)] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.") diff --git a/code/game/gamemodes/gang/recaller.dm b/code/game/gamemodes/gang/recaller.dm index 423380c8095..903d2a5aef8 100644 --- a/code/game/gamemodes/gang/recaller.dm +++ b/code/game/gamemodes/gang/recaller.dm @@ -108,7 +108,7 @@ if(!message || !can_use(user)) return if(user.z > 2) - to_chat(user, "\icon[src]Error: Station out of range.") + to_chat(user, "[bicon(src)]Error: Station out of range.") return var/list/members = list() members += gang.gangsters @@ -170,35 +170,35 @@ gang.message_gangtools("[usr] is attempting to recall the emergency shuttle.") recalling = 1 - to_chat(loc, "\icon[src]Generating shuttle recall order with codes retrieved from last call signal...") + to_chat(loc, "[bicon(src)]Generating shuttle recall order with codes retrieved from last call signal...") sleep(rand(100,300)) if(SSshuttle.emergency.mode != SHUTTLE_CALL) //Shuttle can only be recalled when it's moving to the station - to_chat(user, "\icon[src]Emergency shuttle cannot be recalled at this time.") + to_chat(user, "[bicon(src)]Emergency shuttle cannot be recalled at this time.") recalling = 0 return 0 - to_chat(loc, "\icon[src]Shuttle recall order generated. Accessing station long-range communication arrays...") + to_chat(loc, "[bicon(src)]Shuttle recall order generated. Accessing station long-range communication arrays...") sleep(rand(100,300)) if(!gang.dom_attempts) - to_chat(user, "\icon[src]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.") + to_chat(user, "[bicon(src)]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.") recalling = 0 return 0 var/turf/userturf = get_turf(user) if(userturf.z != 1) //Shuttle can only be recalled while on station - to_chat(user, "\icon[src]Error: Device out of range of station communication arrays.") + to_chat(user, "[bicon(src)]Error: Device out of range of station communication arrays.") recalling = 0 return 0 var/datum/station_state/end_state = new /datum/station_state() end_state.count() if((100 * start_state.score(end_state)) < 80) //Shuttle cannot be recalled if the station is too damaged - to_chat(user, "\icon[src]Error: Station communication systems compromised. Unable to establish connection.") + to_chat(user, "[bicon(src)]Error: Station communication systems compromised. Unable to establish connection.") recalling = 0 return 0 - to_chat(loc, "\icon[src]Comm arrays accessed. Broadcasting recall signal...") + to_chat(loc, "[bicon(src)]Comm arrays accessed. Broadcasting recall signal...") sleep(rand(100,300)) @@ -210,7 +210,7 @@ if(SSshuttle.cancelEvac(user)) return 1 - to_chat(loc, "\icon[src]No response recieved. Emergency shuttle cannot be recalled at this time.") + to_chat(loc, "[bicon(src)]No response recieved. Emergency shuttle cannot be recalled at this time.") return 0 /obj/item/device/gangtool/proc/can_use(mob/living/carbon/human/user) diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index 17cb756cf16..ed843dfd076 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -413,10 +413,10 @@ customrecepient.tnote += "← From [customsender] ([customjob]):
[custommessage]
" if (!customrecepient.silent) playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1) - customrecepient.audible_message("\icon[customrecepient] *[customrecepient.ttone]*", null, 3) + customrecepient.audible_message("[bicon(customrecepient)] *[customrecepient.ttone]*", null, 3) if( customrecepient.loc && ishuman(customrecepient.loc) ) var/mob/living/carbon/human/H = customrecepient.loc - to_chat(H, "\icon[customrecepient] Message from [customsender] ([customjob]), \"[custommessage]\" (Reply)") + to_chat(H, "[bicon(customrecepient)] Message from [customsender] ([customjob]), \"[custommessage]\" (Reply)") log_pda("[usr]/([usr.ckey]) (PDA: [customsender]) sent \"[custommessage]\" to [customrecepient.owner]") customrecepient.cut_overlays() customrecepient.add_overlay(image('icons/obj/pda.dmi', "pda-r")) @@ -426,10 +426,10 @@ customrecepient.tnote += "← From [PDARec.owner] ([customjob]):
[custommessage]
" if (!customrecepient.silent) playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1) - customrecepient.audible_message("\icon[customrecepient] *[customrecepient.ttone]*", null, 3) + customrecepient.audible_message("[bicon(customrecepient)] *[customrecepient.ttone]*", null, 3) if( customrecepient.loc && ishuman(customrecepient.loc) ) var/mob/living/carbon/human/H = customrecepient.loc - to_chat(H, "\icon[customrecepient] Message from [PDARec.owner] ([customjob]), \"[custommessage]\" (Reply)") + to_chat(H, "[bicon(customrecepient)] Message from [PDARec.owner] ([customjob]), \"[custommessage]\" (Reply)") log_pda("[usr]/([usr.ckey]) (PDA: [PDARec.owner]) sent \"[custommessage]\" to [customrecepient.owner]") customrecepient.cut_overlays() customrecepient.add_overlay(image('icons/obj/pda.dmi', "pda-r")) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 7a0945e7f55..9a97dd47dc8 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -426,7 +426,7 @@ Class Procs: /obj/machinery/proc/display_parts(mob/user) to_chat(user, "Following parts detected in the machine:") for(var/obj/item/C in component_parts) - to_chat(user, "\icon[C] [C.name]") + to_chat(user, "[bicon(C)] [C.name]") /obj/machinery/examine(mob/user) ..() diff --git a/code/game/machinery/overview.dm b/code/game/machinery/overview.dm index 9dfb77ab669..18a5dd70903 100644 --- a/code/game/machinery/overview.dm +++ b/code/game/machinery/overview.dm @@ -146,7 +146,7 @@ var/icon/I2 = imap[2+(ix + icx*iy)*2] - //to_chat(world, "icon: \icon[I]") + //to_chat(world, "icon: [bicon(I)]") I.DrawBox(colour, rx, ry, rx+1, ry+1) @@ -163,7 +163,7 @@ H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]" - //to_chat(world, "\icon[I] at [H.screen_loc]") + //to_chat(world, "[bicon(I)] at [H.screen_loc]") H.name = (i==0)?"maprefresh":"map" @@ -274,7 +274,7 @@ var/icon/I = imap[1+(ix + icx*iy)] - //to_chat(world, "icon: \icon[I]") + //to_chat(world, "icon: [bicon(I)]") I.DrawBox(colour, rx, ry, rx, ry) @@ -289,7 +289,7 @@ H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]" - //to_chat(world, "\icon[I] at [H.screen_loc]") + //to_chat(world, "[bicon(I)] at [H.screen_loc]") H.name = (i==0)?"maprefresh":"map" diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index e11d0ad6011..74dcb61a950 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -210,14 +210,14 @@ var/new_timer = input(user, "Please set the timer.", "Timer", "[timer_set]") as num if(in_range(src, user) && isliving(user)) //No running off and setting bombs from across the station timer_set = Clamp(new_timer, minimum_timer, maximum_timer) - src.loc.visible_message("\icon[src] timer set for [timer_set] seconds.") + src.loc.visible_message("[bicon(src)] timer set for [timer_set] seconds.") if(alert(user,"Would you like to start the countdown now?",,"Yes","No") == "Yes" && in_range(src, user) && isliving(user)) if(defused || active) if(defused) - src.loc.visible_message("\icon[src] Device error: User intervention required.") + src.loc.visible_message("[bicon(src)] Device error: User intervention required.") return else - src.loc.visible_message("\icon[src] [timer_set] seconds until detonation, please clear the area.") + src.loc.visible_message("[bicon(src)] [timer_set] seconds until detonation, please clear the area.") activate() update_icon() add_fingerprint(user) @@ -324,7 +324,7 @@ var/obj/machinery/syndicatebomb/holder = loc if(istype(holder)) attempts++ - holder.loc.visible_message("\icon[holder] Alert: Bomb has detonated. Your score is now [defusals] for [attempts]. Resetting wires...") + holder.loc.visible_message("[bicon(holder)] Alert: Bomb has detonated. Your score is now [defusals] for [attempts]. Resetting wires...") reset() else qdel(src) @@ -334,7 +334,7 @@ if(istype(holder)) attempts++ defusals++ - holder.loc.visible_message("\icon[holder] Alert: Bomb has been defused. Your score is now [defusals] for [attempts]! Resetting wires in 5 seconds...") + holder.loc.visible_message("[bicon(holder)] Alert: Bomb has been defused. Your score is now [defusals] for [attempts]! Resetting wires in 5 seconds...") sleep(50) //Just in case someone is trying to remove the bomb core this gives them a little window to crowbar it out if(istype(holder)) reset() diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm index 7227a393dfc..7bc9f9fe3cc 100644 --- a/code/game/machinery/telecomms/broadcasting.dm +++ b/code/game/machinery/telecomms/broadcasting.dm @@ -316,7 +316,7 @@ // Create a radio headset for the sole purpose of using its icon var/obj/item/device/radio/headset/radio = new - var/part_b = "
\icon[radio]\[[freq_text]\][part_b_extra] " + var/part_b = " [bicon(radio)]\[[freq_text]\][part_b_extra] " var/part_c = "
" if (display_freq==SYND_FREQ) diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 60bd42bf231..84d4b0bcfa6 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -140,7 +140,7 @@ /obj/item/mecha_parts/mecha_equipment/proc/occupant_message(message) if(chassis) - chassis.occupant_message("\icon[src] [message]") + chassis.occupant_message("[bicon(src)] [message]") return /obj/item/mecha_parts/mecha_equipment/proc/log_message(message) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 84010473806..9eae889926d 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -263,7 +263,7 @@ if(equipment && equipment.len) to_chat(user, "It's equipped with:") for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) - to_chat(user, "\icon[ME] [ME]") + to_chat(user, "[bicon(ME)] [ME]") //processing internal damage, temperature, air regulation, alert updates, lights power use. /obj/mecha/process() @@ -639,7 +639,7 @@ var/can_control_mech = 0 for(var/obj/item/mecha_parts/mecha_tracking/ai_control/A in trackers) can_control_mech = 1 - to_chat(user, "\icon[src] Status of [name]:\n[A.get_mecha_info()]") + to_chat(user, "[bicon(src)] Status of [name]:\n[A.get_mecha_info()]") break if(!can_control_mech) to_chat(user, "You cannot control exosuits without AI control beacons installed.") @@ -1000,7 +1000,7 @@ /obj/mecha/proc/occupant_message(message as text) if(message) if(occupant && occupant.client) - to_chat(occupant, "\icon[src] [message]") + to_chat(occupant, "[bicon(src)] [message]") return /obj/mecha/proc/log_message(message as text,red=null) diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index ab4c6e858be..561305f4af9 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -168,7 +168,7 @@ . += "You recognise the footprints as belonging to:\n" for(var/shoe in shoe_types) var/obj/item/clothing/shoes/S = shoe - . += "some [initial(S.name)] \icon[S]\n" + . += "some [initial(S.name)] [bicon(S)]\n" to_chat(user, .) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index e8ea608e2e5..06d116cc932 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -22,7 +22,7 @@ /obj/effect/mine/proc/triggermine(mob/victim) if(triggered) return - visible_message("[victim] sets off \icon[src] [src]!") + visible_message("[victim] sets off [bicon(src)] [src]!") var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(3, 1, src) s.start() diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 732206e93ce..0cc796e52f9 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -620,7 +620,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if (!silent) playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) - audible_message("\icon[src] *[ttone]*", null, 3) + audible_message("[bicon(src)] *[ttone]*", null, 3) //Search for holder of the PDA. var/mob/living/L = null if(loc && isliving(loc)) @@ -630,7 +630,7 @@ var/global/list/obj/item/device/pda/PDAs = list() L = get(src, /mob/living/silicon) if(L && L.stat != UNCONSCIOUS) - to_chat(L, "\icon[src] Message from [source.owner] ([source.ownjob]), \"[msg.message]\"[msg.get_photo_ref()] (Reply)") + to_chat(L, "[bicon(src)] Message from [source.owner] ([source.ownjob]), \"[msg.message]\"[msg.get_photo_ref()] (Reply)") update_icon() add_overlay(image(icon, icon_alert)) diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index a7afbd0a21c..0aa6a55c035 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -86,27 +86,27 @@ if(isliving(loc)) var/mob/living/M = loc if(!emagged) - to_chat(M, "\icon[src] RADIATION PULSE DETECTED.") - to_chat(M, "\icon[src] Severity: [amount]") + to_chat(M, "[bicon(src)] RADIATION PULSE DETECTED.") + to_chat(M, "[bicon(src)] Severity: [amount]") else - to_chat(M, "\icon[src] !@%$AT!(N P!LS! D/TEC?ED.") - to_chat(M, "\icon[src] &!F2rity: <=[amount]#1") + to_chat(M, "[bicon(src)] !@%$AT!(N P!LS! D/TEC?ED.") + to_chat(M, "[bicon(src)] &!F2rity: <=[amount]#1") update_icon() /obj/item/device/geiger_counter/attack_self(mob/user) scanning = !scanning update_icon() - to_chat(user, "\icon[src] You switch [scanning ? "on" : "off"] [src].") + to_chat(user, "[bicon(src)] You switch [scanning ? "on" : "off"] [src].") /obj/item/device/geiger_counter/attack(mob/living/M, mob/user) if(user.a_intent == INTENT_HELP) if(!emagged) user.visible_message("[user] scans [M] with [src].", "You scan [M]'s radiation levels with [src]...") if(!M.radiation) - to_chat(user, "\icon[src] Radiation levels within normal boundaries.") + to_chat(user, "[bicon(src)] Radiation levels within normal boundaries.") return 1 else - to_chat(user, "\icon[src] Subject is irradiated. Radiation levels: [M.radiation].") + to_chat(user, "[bicon(src)] Subject is irradiated. Radiation levels: [M.radiation].") return 1 else user.visible_message("[user] scans [M] with [src].", "You project [src]'s stored radiation into [M]'s body!") diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 8f5cbf5e75e..59ed100d13e 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -499,7 +499,7 @@ return list(pick(messages)) /obj/item/toy/talking/proc/toy_talk(mob/user, message) - user.loc.visible_message("\icon[src] [message]") + user.loc.visible_message("[bicon(src)] [message]") if(chattering) chatter(message, phomeme, user) @@ -1130,7 +1130,7 @@ user.visible_message("[user] pulls back the string on [src].") icon_state = "[initial(icon_state)]_used" sleep(5) - audible_message("\icon[src] Hiss!") + audible_message("[bicon(src)] Hiss!") var/list/possible_sounds = list('sound/voice/hiss1.ogg', 'sound/voice/hiss2.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss4.ogg') var/chosen_sound = pick(possible_sounds) playsound(get_turf(src), chosen_sound, 50, 1) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 3fb99d53853..914ebf73fda 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -523,7 +523,7 @@ AI MODULES laws[1] = generate_ion_law() to_chat(user, "You press the button on [src].") playsound(user, 'sound/machines/click.ogg', 20, 1) - src.loc.visible_message("\icon[src] [laws[1]]") + src.loc.visible_message("[bicon(src)] [laws[1]]") /******************** Mother Drone ******************/ diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index c3e813f5a80..650a685f08b 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -86,7 +86,7 @@ var/dorm = 0 // determines if this ID has claimed a dorm already /obj/item/weapon/card/id/attack_self(mob/user) - user.visible_message("[user] shows you: \icon[src] [src.name].", \ + user.visible_message("[user] shows you: [bicon(src)] [src.name].", \ "You show \the [src.name].") src.add_fingerprint(user) return diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index bb35726331e..69964326c8d 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -33,7 +33,7 @@ prayer_type = "CULTIST PRAYER" deity = "Nar-Sie" - msg = "\icon[cross][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)] [ADMIN_SMITE(src)]: [msg]" + msg = "[bicon(cross)][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)] [ADMIN_SMITE(src)]: [msg]" for(var/client/C in admins) if(C.prefs.chat_toggles & CHAT_PRAYER) diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index 481e692a5d7..2630c5b4ed5 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -61,7 +61,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("[bicon(src)] *beep* *beep*", "*beep* *beep*") sleep(10) if(!src) return diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm index 07b05ef565b..99cd72834f4 100644 --- a/code/modules/assembly/health.dm +++ b/code/modules/assembly/health.dm @@ -57,7 +57,7 @@ health_scan = M.health if(health_scan <= alarm_health) pulse() - audible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + audible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*") toggle_scan() return return diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 23de148130f..38e624e0184 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -99,7 +99,7 @@ if(!secured || !on || next_activate > world.time) return FALSE pulse(0) - audible_message("\icon[src] *beep* *beep*", null, 3) + audible_message("[bicon(src)] *beep* *beep*", null, 3) next_activate = world.time + 30 /obj/item/device/assembly/infra/interact(mob/user)//TODO: change this this to the wire control panel diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 081a9661358..5779c8d88d9 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -62,7 +62,7 @@ if(!secured || next_activate > world.time) return 0 pulse(0) - audible_message("\icon[src] *beep* *beep*", null, 3) + audible_message("[bicon(src)] *beep* *beep*", null, 3) next_activate = world.time + 30 diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index cf00655c3a3..0db0d0cce56 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -142,7 +142,7 @@ Code: if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 pulse(1) - audible_message("\icon[src] *beep* *beep*", null, 1) + audible_message("[bicon(src)] *beep* *beep*", null, 1) return diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 12f8f464dc5..1ad41185efa 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -45,7 +45,7 @@ if(!secured || next_activate > world.time) return FALSE pulse(0) - audible_message("\icon[src] *beep* *beep*", null, 3) + audible_message("[bicon(src)] *beep* *beep*", null, 3) if(loop) timing = 1 update_icon() diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm index c036927b38b..150c3e19a82 100644 --- a/code/modules/clothing/spacesuits/flightsuit.dm +++ b/code/modules/clothing/spacesuits/flightsuit.dm @@ -796,13 +796,13 @@ /obj/item/device/flightpack/proc/usermessage(message, urgency = 0) if(urgency == 0) - to_chat(wearer, "\icon[src]|[message]") + to_chat(wearer, "[bicon(src)]|[message]") if(urgency == 1) - to_chat(wearer, "\icon[src]|[message]") + to_chat(wearer, "[bicon(src)]|[message]") if(urgency == 2) - to_chat(wearer, "\icon[src]|[message]") + to_chat(wearer, "[bicon(src)]|[message]") if(urgency == 3) - to_chat(wearer, "\icon[src]|[message]") + to_chat(wearer, "[bicon(src)]|[message]") /obj/item/device/flightpack/attackby(obj/item/I, mob/user, params) if(ishuman(user) && !ishuman(src.loc)) @@ -949,11 +949,11 @@ /obj/item/clothing/suit/space/hardsuit/flightsuit/proc/usermessage(message, urgency = 0) if(!urgency) - to_chat(user, "\icon[src]|[message]") + to_chat(user, "[bicon(src)]|[message]") else if(urgency == 1) - to_chat(user, "\icon[src]|[message]") + to_chat(user, "[bicon(src)]|[message]") else if(urgency == 2) - to_chat(user, "\icon[src]|[message]") + to_chat(user, "[bicon(src)]|[message]") /obj/item/clothing/suit/space/hardsuit/flightsuit/examine(mob/user) ..() diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index b9c4a117cb8..0605dfffe08 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -48,7 +48,7 @@ /obj/item/clothing/head/helmet/space/hardsuit/proc/display_visor_message(var/msg) var/mob/wearer = loc if(msg && ishuman(wearer)) - wearer.show_message("\icon[src][msg]", 1) + wearer.show_message("[bicon(src)][msg]", 1) /obj/item/clothing/head/helmet/space/hardsuit/rad_act(severity) ..() diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 364a17e95a6..24d32a10dd9 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -19,7 +19,7 @@ var/list/emojis if(search) emoji = lowertext(copytext(text, pos+1, search)) if(emoji in emojis) - parsed += " " + parsed += " [bicon(image('icons/emoji.dmi', iconstate="[emoji]"))]" pos = search + 1 else parsed += copytext(text, pos, search) diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm index 43be7ad7479..647c1bc5ba0 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm @@ -98,7 +98,7 @@ var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = O if(!I.ice_creamed) if(product_types[dispense_flavour] > 0) - src.visible_message("\icon[src] [user] scoops delicious [flavour_name] ice cream into [I].") + src.visible_message("[bicon(src)] [user] scoops delicious [flavour_name] ice cream into [I].") product_types[dispense_flavour] -= 1 I.add_ice_cream(flavour_name) // if(beaker) diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index 7e7f049c767..21d52813bb6 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -80,7 +80,7 @@ return open = !open if(open && !bomb_defused) - audible_message("\icon[src] *beep*") + audible_message("[bicon(src)] *beep*") bomb_active = TRUE START_PROCESSING(SSobj, src) update_icon() diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 2fe0a7f7bdd..ebc349cefc4 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -6,26 +6,26 @@ var/t_has = p_have() var/t_is = p_are() - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" if (handcuffed) - msg += "[t_He] [t_is] \icon[src.handcuffed] handcuffed!\n" + msg += "[t_He] [t_is] [bicon(handcuffed)] handcuffed!\n" if (head) - msg += "[t_He] [t_is] wearing \icon[src.head] \a [src.head] on [t_his] head. \n" + msg += "[t_He] [t_is] wearing [bicon(head)] \a [src.head] on [t_his] head. \n" if (wear_mask) - msg += "[t_He] [t_is] wearing \icon[src.wear_mask] \a [src.wear_mask] on [t_his] face.\n" + msg += "[t_He] [t_is] wearing [bicon(wear_mask)] \a [src.wear_mask] on [t_his] face.\n" if (wear_neck) - msg += "[t_He] [t_is] wearing \icon[src.wear_neck] \a [src.wear_neck] around [t_his] neck.\n" + msg += "[t_He] [t_is] wearing [bicon(wear_neck)] \a [src.wear_neck] around [t_his] neck.\n" for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "[t_He] [t_is] holding \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "[t_He] [t_is] holding [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "[t_He] [t_is] holding \icon[I] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "[t_He] [t_is] holding [bicon(I)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" if (back) - msg += "[t_He] [t_has] \icon[src.back] \a [src.back] on [t_his] back.\n" + msg += "[t_He] [t_has] [bicon(back)] \a [src.back] on [t_his] back.\n" var/appears_dead = 0 if (stat == DEAD) appears_dead = 1 diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 25ec62df457..5a957aad40c 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -19,55 +19,55 @@ if(istype(w_uniform,/obj/item/clothing/under)) var/obj/item/clothing/under/U = w_uniform if(U.hastie) - tie_msg += " with \icon[U.hastie] \a [U.hastie]" + tie_msg += " with [bicon(U.hastie)] \a [U.hastie]" if(w_uniform.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][tie_msg]!\n" + msg += "[t_He] [t_is] wearing [bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][tie_msg]!\n" else - msg += "[t_He] [t_is] wearing \icon[w_uniform] \a [w_uniform][tie_msg].\n" + msg += "[t_He] [t_is] wearing [bicon(w_uniform)] \a [w_uniform][tie_msg].\n" //head if(head) if(head.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[head] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on [t_his] head!\n" + msg += "[t_He] [t_is] wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on [t_his] head!\n" else - msg += "[t_He] [t_is] wearing \icon[head] \a [head] on [t_his] head.\n" + msg += "[t_He] [t_is] wearing [bicon(head)] \a [head] on [t_his] head.\n" //suit/armor if(wear_suit) if(wear_suit.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[wear_suit] [wear_suit.gender==PLURAL?"some":"a"] blood-stained [wear_suit.name]!\n" + msg += "[t_He] [t_is] wearing [bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] blood-stained [wear_suit.name]!\n" else - msg += "[t_He] [t_is] wearing \icon[wear_suit] \a [wear_suit].\n" + msg += "[t_He] [t_is] wearing [bicon(wear_suit)] \a [wear_suit].\n" //suit/armor storage if(s_store) if(s_store.blood_DNA) - msg += "[t_He] [t_is] carrying \icon[s_store] [s_store.gender==PLURAL?"some":"a"] blood-stained [s_store.name] on [t_his] [wear_suit.name]!\n" + msg += "[t_He] [t_is] carrying [bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] blood-stained [s_store.name] on [t_his] [wear_suit.name]!\n" else - msg += "[t_He] [t_is] carrying \icon[s_store] \a [s_store] on [t_his] [wear_suit.name].\n" + msg += "[t_He] [t_is] carrying [bicon(s_store)] \a [s_store] on [t_his] [wear_suit.name].\n" //back if(back) if(back.blood_DNA) - msg += "[t_He] [t_has] \icon[back] [back.gender==PLURAL?"some":"a"] blood-stained [back] on [t_his] back.\n" + msg += "[t_He] [t_has] [bicon(back)] [back.gender==PLURAL?"some":"a"] blood-stained [back] on [t_his] back.\n" else - msg += "[t_He] [t_has] \icon[back] \a [back] on [t_his] back.\n" + msg += "[t_He] [t_has] [bicon(back)] \a [back] on [t_his] back.\n" //Hands for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "[t_He] [t_is] holding \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "[t_He] [t_is] holding [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "[t_He] [t_is] holding \icon[I] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "[t_He] [t_is] holding [bicon(I)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" //gloves if(gloves && !(slot_gloves in obscured)) if(gloves.blood_DNA) - msg += "[t_He] [t_has] \icon[gloves] [gloves.gender==PLURAL?"some":"a"] blood-stained [gloves.name] on [t_his] hands!\n" + msg += "[t_He] [t_has] [bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] blood-stained [gloves.name] on [t_his] hands!\n" else - msg += "[t_He] [t_has] \icon[gloves] \a [gloves] on [t_his] hands.\n" + msg += "[t_He] [t_has] [bicon(gloves)] \a [gloves] on [t_his] hands.\n" else if(blood_DNA) var/hand_number = get_num_arms() if(hand_number) @@ -78,48 +78,48 @@ //handcuffed? if(handcuffed) if(istype(handcuffed, /obj/item/weapon/restraints/handcuffs/cable)) - msg += "[t_He] [t_is] \icon[handcuffed] restrained with cable!\n" + msg += "[t_He] [t_is] [bicon(handcuffed)] restrained with cable!\n" else - msg += "[t_He] [t_is] \icon[handcuffed] handcuffed!\n" + msg += "[t_He] [t_is] [bicon(handcuffed)] handcuffed!\n" //belt if(belt) if(belt.blood_DNA) - msg += "[t_He] [t_has] \icon[belt] [belt.gender==PLURAL?"some":"a"] blood-stained [belt.name] about [t_his] waist!\n" + msg += "[t_He] [t_has] [bicon(belt)] [belt.gender==PLURAL?"some":"a"] blood-stained [belt.name] about [t_his] waist!\n" else - msg += "[t_He] [t_has] \icon[belt] \a [belt] about [t_his] waist.\n" + msg += "[t_He] [t_has] [bicon(belt)] \a [belt] about [t_his] waist.\n" //shoes if(shoes && !(slot_shoes in obscured)) if(shoes.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[shoes] [shoes.gender==PLURAL?"some":"a"] blood-stained [shoes.name] on [t_his] feet!\n" + msg += "[t_He] [t_is] wearing [bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] blood-stained [shoes.name] on [t_his] feet!\n" else - msg += "[t_He] [t_is] wearing \icon[shoes] \a [shoes] on [t_his] feet.\n" + msg += "[t_He] [t_is] wearing [bicon(shoes)] \a [shoes] on [t_his] feet.\n" //mask if(wear_mask && !(slot_wear_mask in obscured)) if(wear_mask.blood_DNA) - msg += "[t_He] [t_has] \icon[wear_mask] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] on [t_his] face!\n" + msg += "[t_He] [t_has] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] on [t_his] face!\n" else - msg += "[t_He] [t_has] \icon[wear_mask] \a [wear_mask] on [t_his] face.\n" + msg += "[t_He] [t_has] [bicon(wear_mask)] \a [wear_mask] on [t_his] face.\n" if (wear_neck && !(slot_neck in obscured)) - msg += "[t_He] [t_is] wearing \icon[src.wear_neck] \a [src.wear_neck] around [t_his] neck.\n" + msg += "[t_He] [t_is] wearing [bicon(wear_neck)] \a [src.wear_neck] around [t_his] neck.\n" //eyes if(glasses && !(slot_glasses in obscured)) if(glasses.blood_DNA) - msg += "[t_He] [t_has] \icon[glasses] [glasses.gender==PLURAL?"some":"a"] blood-stained [glasses] covering [t_his] eyes!\n" + msg += "[t_He] [t_has] [bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] blood-stained [glasses] covering [t_his] eyes!\n" else - msg += "[t_He] [t_has] \icon[glasses] \a [glasses] covering [t_his] eyes.\n" + msg += "[t_He] [t_has] [bicon(glasses)] \a [glasses] covering [t_his] eyes.\n" //ears if(ears && !(slot_ears in obscured)) - msg += "[t_He] [t_has] \icon[ears] \a [ears] on [t_his] ears.\n" + msg += "[t_He] [t_has] [bicon(ears)] \a [ears] on [t_his] ears.\n" //ID if(wear_id) - msg += "[t_He] [t_is] wearing \icon[wear_id] \a [wear_id].\n" + msg += "[t_He] [t_is] wearing [bicon(wear_id)] \a [wear_id].\n" //Jitters switch(jitteriness) @@ -163,7 +163,7 @@ var/obj/item/bodypart/BP = X missing -= BP.body_zone for(var/obj/item/I in BP.embedded_objects) - msg += "[t_He] [t_has] \a \icon[I] [I] embedded in [t_his] [BP.name]!\n" + msg += "[t_He] [t_has] \a [bicon(I)] [I] embedded in [t_his] [BP.name]!\n" //stores missing limbs var/l_limbs_missing = 0 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 4054803b278..7071c52d576 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -681,10 +681,10 @@ status += "numb" if(status == "") status = "OK" - to_chat(src, "\t [status == "OK" ? "\blue" : "\red"] Your [LB.name] is [status].") + to_chat(src, "\t Your [LB.name] is [status].") for(var/obj/item/I in LB.embedded_objects) - to_chat(src, "\t \red There is \a [I] embedded in your [LB.name]!") + to_chat(src, "\t There is \a [I] embedded in your [LB.name]!") for(var/t in missing) to_chat(src, "Your [parse_zone(t)] is missing!") diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index e0b3cf38f18..c7f70277ea0 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -1,5 +1,5 @@ /mob/living/silicon/ai/examine(mob/user) - var/msg = "*---------*\nThis is \icon[src] [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] [src]!\n" if (src.stat == DEAD) msg += "It appears to be powered-down.\n" else diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 5ea2dc2491e..9433f40d68e 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -173,7 +173,7 @@ if(href_list["send"]) sradio.send_signal("ACTIVATE") - audible_message("\icon[src] *beep* *beep*") + audible_message("[bicon(src)] *beep* *beep*") if(href_list["freq"]) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 804113fb24a..4515ea0383a 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,11 +1,11 @@ /mob/living/silicon/robot/examine(mob/user) - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" if(desc) msg += "[desc]\n" var/obj/act_module = get_active_held_item() if(act_module) - msg += "It is holding \icon[act_module] \a [act_module].\n" + msg += "It is holding [bicon(act_module)] \a [act_module].\n" msg += "" if (src.getBruteLoss()) if (src.getBruteLoss() < maxHealth*0.5) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 9f746c0f5b5..0196b2a4e00 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -473,7 +473,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/area/end_area = get_area(waypoint) if(client) //Player bots instead get a location command from the AI - to_chat(src, "Priority waypoint set by \icon[caller] [caller]. Proceed to [end_area.name]<\b>.") + to_chat(src, "Priority waypoint set by [bicon(caller)] [caller]. Proceed to [end_area.name]<\b>.") //For giving the bot temporary all-access. var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id @@ -489,7 +489,7 @@ Pass a positive integer as an argument to override a bot's default speed. turn_on() //Saves the AI the hassle of having to activate a bot manually. access_card = all_access //Give the bot all-access while under the AI's command. if(message) - to_chat(calling_ai, "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination.") + to_chat(calling_ai, "[bicon(src)] [name] called to [end_area.name]. [path.len-1] meters to destination.") pathset = 1 mode = BOT_RESPONDING tries = 0 @@ -504,7 +504,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/success = bot_move(ai_waypoint, 3) if(!success) if(calling_ai) - to_chat(calling_ai, "\icon[src] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]") + to_chat(calling_ai, "[bicon(src)] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]") calling_ai = null bot_reset() diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 50fe9bc4102..b31c6f4e223 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -598,7 +598,7 @@ var/global/mulebot_count = 0 if(pathset) //The AI called us here, so notify it of our arrival. loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing". if(calling_ai) - to_chat(calling_ai, "\icon[src] [src] wirelessly plays a chiming sound!") + to_chat(calling_ai, "[bicon(src)] [src] wirelessly plays a chiming sound!") playsound(calling_ai, 'sound/machines/chime.ogg',40, 0) calling_ai = null radio_channel = "AI Private" //Report on AI Private instead if the AI is controlling us. diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 886c7db33e7..71c104579a7 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -44,7 +44,7 @@ /mob/living/simple_animal/hostile/construct/examine(mob/user) var/t_He = p_they(TRUE) var/t_s = p_s() - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" msg += "[desc]\n" if(health < maxHealth) msg += "" diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 6d23f54150a..f70daf2a3d0 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -158,29 +158,29 @@ /mob/living/simple_animal/drone/examine(mob/user) - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" //Hands for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "It has \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "It has [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "It has \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "It has [bicon(I)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" //Internal storage if(internal_storage && !(internal_storage.flags&ABSTRACT)) if(internal_storage.blood_DNA) - msg += "It is holding \icon[internal_storage] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" + msg += "It is holding [bicon(internal_storage)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" else - msg += "It is holding \icon[internal_storage] \a [internal_storage] in its internal storage.\n" + msg += "It is holding [bicon(internal_storage)] \a [internal_storage] in its internal storage.\n" //Cosmetic hat - provides no function other than looks if(head && !(head.flags&ABSTRACT)) if(head.blood_DNA) - msg += "It is wearing \icon[head] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on its head!\n" + msg += "It is wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on its head!\n" else - msg += "It is wearing \icon[head] \a [head] on its head.\n" + msg += "It is wearing [bicon(head)] \a [head] on its head.\n" //Braindead if(!client && stat != DEAD) diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 1189273adbe..9629cacc4f3 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -56,7 +56,7 @@ if( ishuman(AM) ) if(!stat) var/mob/M = AM - to_chat(M, "\icon[src] Squeek!") + to_chat(M, "[bicon(src)] Squeek!") playsound(src, 'sound/effects/mousesqueek.ogg', 100, 1) ..() diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm index 84bb6031f45..5fe0ccaadef 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -26,21 +26,21 @@ /mob/living/simple_animal/hostile/guardian/dextrous/examine(mob/user) if(dextrous) - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" msg += "[desc]\n" for(var/obj/item/I in held_items) if(!(I.flags & ABSTRACT)) if(I.blood_DNA) - msg += "It has \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + msg += "It has [bicon(I)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" else - msg += "It has \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + msg += "It has [bicon(I)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" if(internal_storage && !(internal_storage.flags&ABSTRACT)) if(internal_storage.blood_DNA) - msg += "It is holding \icon[internal_storage] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" + msg += "It is holding [bicon(internal_storage)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" else - msg += "It is holding \icon[internal_storage] \a [internal_storage] in its internal storage.\n" + msg += "It is holding [bicon(internal_storage)] \a [internal_storage] in its internal storage.\n" msg += "*---------*" to_chat(user, msg) else diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 023aea68da3..bc18a564090 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -348,7 +348,7 @@ var/list/slime_colours = list("rainbow", "grey", "purple", "metal", "orange", /mob/living/simple_animal/slime/examine(mob/user) - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + var/msg = "*---------*\nThis is [bicon(src)] \a [src]!\n" if (src.stat == DEAD) msg += "It is limp and unresponsive.\n" else diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index bb6f9f7b909..03f2911cb63 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -400,14 +400,14 @@ var/const/INJECT = 5 //injection if(C.mix_sound) playsound(get_turf(cached_my_atom), C.mix_sound, 80, 1) for(var/mob/M in seen) - to_chat(M, "\icon[my_atom] [C.mix_message]") + to_chat(M, "[bicon(my_atom)] [C.mix_message]") if(istype(cached_my_atom, /obj/item/slime_extract)) var/obj/item/slime_extract/ME2 = my_atom ME2.Uses-- if(ME2.Uses <= 0) // give the notification that the slime core is dead for(var/mob/M in seen) - to_chat(M, "\icon[my_atom] \The [my_atom]'s power is consumed in the reaction.") + to_chat(M, "[bicon(my_atom)] \The [my_atom]'s power is consumed in the reaction.") ME2.name = "used slime extract" ME2.desc = "This extract has been used up." diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 2ef0842a04d..f5c3c954a0c 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -341,7 +341,7 @@ found = 1 break if(!found) - to_chat(user, "\icon[src]The conveyor switch did not detect any linked conveyor belts in range.") + to_chat(user, "[bicon(src)]The conveyor switch did not detect any linked conveyor belts in range.") return var/obj/machinery/conveyor_switch/NC = new/obj/machinery/conveyor_switch(A, id) transfer_fingerprints_to(NC) diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm index 67fc9ea1b53..e4bff932775 100644 --- a/code/modules/uplink/uplink_item.dm +++ b/code/modules/uplink/uplink_item.dm @@ -101,10 +101,10 @@ var/list/uplink_items = list() // Global list so we only initialize this once. var/obj/item/weapon/storage/box/B = A if(istype(B) && B.contents.len > 0) for(var/obj/item/I in B) - U.purchase_log += "\icon[I]" + U.purchase_log += "[bicon(I)]" else if(purchase_log_vis) - U.purchase_log += "\icon[A]" + U.purchase_log += "[bicon(A)]" if(limited_stock > 0) limited_stock -= 1 @@ -1312,7 +1312,7 @@ var/list/uplink_items = list() // Global list so we only initialize this once. continue crate_value -= I.cost new I.item(C) - U.purchase_log += "\icon[I.item]" + U.purchase_log += "[bicon(I.item)]" return C From c6185ec9945cdad2a2a3a5fa4cbc71119f287c28 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Fri, 28 Apr 2017 08:24:17 -0300 Subject: [PATCH 03/47] Changes the chat to use asset caches instead of directly sending it in a way to prevent assets not being sent in some conditions. Fixes byond donor icon in ooc. Fixes emojis not working and removes animated emojis. --- code/modules/client/asset_cache.dm | 13 +++++++++++++ code/modules/client/verbs/ooc.dm | 2 +- code/modules/emoji/emoji_parse.dm | 2 +- goon/code/datums/browserOutput.dm | 27 +++++---------------------- icons/emoji.dmi | Bin 26504 -> 25068 bytes 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 6d8ffa64381..2e55c494005 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -267,6 +267,19 @@ GLOBAL_LIST_EMPTY(asset_datums) "jquery-1.10.2.min.js" = 'html/IRV/jquery-1.10.2.min.js' ) +/datum/asset/simple/chat + assets = list( + "jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js', + "json2.min.js" = 'goon/browserassets/js/json2.min.js', + "browserOutput.js" = 'goon/browserassets/js/browserOutput.js', + "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', + "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', + "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf', + "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', + "font-awesome.css" = 'goon/browserassets/css/font-awesome.css', + "browserOutput.css" = 'goon/browserassets/css/browserOutput.css' + ) + //Registers HTML Interface assets. /datum/asset/HTML_interface/register() for(var/path in typesof(/datum/html_interface)) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 79b21dccee2..61452d8a351 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -57,7 +57,7 @@ var/keyname = key if(prefs.unlock_content) if(prefs.toggles & MEMBER_PUBLIC) - keyname = "[keyname]" + keyname = "[bicon(icon('icons/member_content.dmi', "blag"))][keyname]" for(var/client/C in GLOB.clients) if(C.prefs.chat_toggles & CHAT_OOC) diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 87c1e0ad10e..5ecadbe09c7 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -16,7 +16,7 @@ if(search) emoji = lowertext(copytext(text, pos+1, search)) if(emoji in emojis) - parsed += " [bicon(image('icons/emoji.dmi', iconstate="[emoji]"))]" + parsed += bicon(icon('icons/emoji.dmi', emoji)) pos = search + 1 else parsed += copytext(text, pos, search) diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm index 5aabde155cd..a708b2094d8 100644 --- a/goon/code/datums/browserOutput.dm +++ b/goon/code/datums/browserOutput.dm @@ -2,18 +2,6 @@ For the main html chat area *********************************/ -/var/list/chatResources = list( - "code/modules/html_interface/jquery.min.js", - "goon/browserassets/js/json2.min.js", - "goon/browserassets/js/browserOutput.js", - "tgui/assets/fonts/fontawesome-webfont.eot", - "tgui/assets/fonts/fontawesome-webfont.svg", - "tgui/assets/fonts/fontawesome-webfont.ttf", - "tgui/assets/fonts/fontawesome-webfont.woff", - "goon/browserassets/css/font-awesome.css", - "goon/browserassets/css/browserOutput.css" -) - //Precaching a bunch of shit var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons for the browser output @@ -30,7 +18,7 @@ var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons fo . = ..() owner = C - // to_chat(world.log, "chatOutput: New()") + // log_world("chatOutput: New()") /datum/chatOutput/proc/start() //Check for existing chat @@ -57,15 +45,10 @@ var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons fo // to_chat(world.log, "chatOutput: load()") - for(var/attempts in 1 to 5) - for(var/asset in global.chatResources) // No asset cache, just get this fucking shit SENT. - owner << browse_rsc(file(asset)) - - //log_world("Sending main chat window to client [owner.ckey]") - owner << browse(file("goon/browserassets/html/browserOutput.html"), "window=browseroutput") - sleep(14 + (chatResources.len * 7)) - if(!owner || loaded) - break + var/datum/asset/chat = get_asset_datum(/datum/asset/simple/chat) + chat.send(owner) + //log_world("Sending main chat window to client [owner.ckey]") + owner << browse(file("goon/browserassets/html/browserOutput.html"), "window=browseroutput") // log_world("chatOutput: [owner.ckey] load() completed") diff --git a/icons/emoji.dmi b/icons/emoji.dmi index df89c12c948030f6317609c2596649c06cd61fdc..eb60e1c53a727427ef822b0f12a17b16f29da50a 100644 GIT binary patch literal 25068 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 N002ovPDHLkV1kqN6wm+w literal 26504 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 From 3ba0e151986e98922f4d6da826961769f4f0ef44 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Fri, 28 Apr 2017 16:06:19 -0300 Subject: [PATCH 04/47] Asset cache did not work --- code/modules/client/asset_cache.dm | 13 ------------ goon/browserassets/css/browserOutput.css | 2 +- goon/code/datums/browserOutput.dm | 26 ++++++++++++++++++++---- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 6199274798d..a29c3179b21 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -279,19 +279,6 @@ GLOBAL_LIST_EMPTY(asset_datums) "changelog.css" = 'html/changelog.css' ) -/datum/asset/simple/chat - assets = list( - "jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js', - "json2.min.js" = 'goon/browserassets/js/json2.min.js', - "browserOutput.js" = 'goon/browserassets/js/browserOutput.js', - "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', - "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', - "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf', - "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', - "font-awesome.css" = 'goon/browserassets/css/font-awesome.css', - "browserOutput.css" = 'goon/browserassets/css/browserOutput.css' - ) - //Registers HTML Interface assets. /datum/asset/HTML_interface/register() for(var/path in typesof(/datum/html_interface)) diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index 182210d7656..820537e32b1 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -117,7 +117,7 @@ a.popt {text-decoration: none;} } #options .sub {clear: both; display: none; width: 160px;} #options .sub.scroll {overflow-y: scroll;} -#options .sub a {padding: 5px 0 5px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#options .sub a {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} #options .sub span { display: block; line-height: 30px; diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm index a708b2094d8..54b6f28d463 100644 --- a/goon/code/datums/browserOutput.dm +++ b/goon/code/datums/browserOutput.dm @@ -4,6 +4,17 @@ For the main html chat area //Precaching a bunch of shit var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons for the browser output +var/list/chatResources = list( + "code/modules/html_interface/js/jquery.min.js", + "goon/browserassets/js/json2.min.js", + "goon/browserassets/js/browserOutput.js", + "tgui/assets/fonts/fontawesome-webfont.eot", + "tgui/assets/fonts/fontawesome-webfont.svg", + "tgui/assets/fonts/fontawesome-webfont.ttf", + "tgui/assets/fonts/fontawesome-webfont.woff", + "goon/browserassets/css/font-awesome.css", + "goon/browserassets/css/browserOutput.css" + ) //On client, created on login /datum/chatOutput @@ -44,11 +55,18 @@ var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons fo return // to_chat(world.log, "chatOutput: load()") + for(var/attempts in 1 to 5) + for(var/asset in chatResources) + owner << browse_rsc(file(asset)) - var/datum/asset/chat = get_asset_datum(/datum/asset/simple/chat) - chat.send(owner) - //log_world("Sending main chat window to client [owner.ckey]") - owner << browse(file("goon/browserassets/html/browserOutput.html"), "window=browseroutput") + //log_world("Sending main chat window to client [owner.ckey]") + owner << browse(file("goon/browserassets/html/browserOutput.html"), "window=browseroutput") + sleep(14 + (chatResources.len * 7)) + if(!owner || loaded) + break + + if(!loaded) + stack_trace("[owner] failed to load chat.") // log_world("chatOutput: [owner.ckey] load() completed") From ce5edaa8eebd3e41bcaaa87aa5895f61e08fb221 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Mon, 1 May 2017 12:46:32 -0300 Subject: [PATCH 05/47] Glob --- goon/code/datums/browserOutput.dm | 69 +++++++++++++++---------------- tgstation.dme | 8 ++-- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm index 54b6f28d463..d9283977283 100644 --- a/goon/code/datums/browserOutput.dm +++ b/goon/code/datums/browserOutput.dm @@ -3,32 +3,21 @@ For the main html chat area *********************************/ //Precaching a bunch of shit -var/savefile/iconCache = new /savefile("data/iconCache.sav") //Cache of icons for the browser output -var/list/chatResources = list( - "code/modules/html_interface/js/jquery.min.js", - "goon/browserassets/js/json2.min.js", - "goon/browserassets/js/browserOutput.js", - "tgui/assets/fonts/fontawesome-webfont.eot", - "tgui/assets/fonts/fontawesome-webfont.svg", - "tgui/assets/fonts/fontawesome-webfont.ttf", - "tgui/assets/fonts/fontawesome-webfont.woff", - "goon/browserassets/css/font-awesome.css", - "goon/browserassets/css/browserOutput.css" - ) +GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of icons for the browser output //On client, created on login /datum/chatOutput - var/client/owner = null //client ref - var/loaded = 0 // Has the client loaded the browser output area? - var/list/messageQueue = list() //If they haven't loaded chat, this is where messages will go until they do - var/cookieSent = 0 // Has the client sent a cookie for analysis - var/list/connectionHistory = list() //Contains the connection history passed from chat cookie + var/client/owner //client ref + 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/list/connectionHistory //Contains the connection history passed from chat cookie var/broken = FALSE /datum/chatOutput/New(client/C) - . = ..() - owner = C + messageQueue = list() + connectionHistory = list() // log_world("chatOutput: New()") /datum/chatOutput/proc/start() @@ -54,6 +43,18 @@ var/list/chatResources = list( if(!owner) return + var/static/list/chatResources = list( + "code/modules/html_interface/js/jquery.min.js", + "goon/browserassets/js/json2.min.js", + "goon/browserassets/js/browserOutput.js", + "tgui/assets/fonts/fontawesome-webfont.eot", + "tgui/assets/fonts/fontawesome-webfont.svg", + "tgui/assets/fonts/fontawesome-webfont.ttf", + "tgui/assets/fonts/fontawesome-webfont.woff", + "goon/browserassets/css/font-awesome.css", + "goon/browserassets/css/browserOutput.css" + ) + // to_chat(world.log, "chatOutput: load()") for(var/attempts in 1 to 5) for(var/asset in chatResources) @@ -65,9 +66,9 @@ var/list/chatResources = list( if(!owner || loaded) break - if(!loaded) - stack_trace("[owner] failed to load chat.") - + if(owner && !loaded) + doneLoading() // try doing this manually + CRASH("[owner] failed to load chat. Attempting doneLoading() manually") // log_world("chatOutput: [owner.ckey] load() completed") /datum/chatOutput/Topic(href, list/href_list) @@ -146,7 +147,7 @@ var/list/chatResources = list( if(cookie != "none") var/list/connData = json_decode(cookie) if (connData && islist(connData) && connData.len > 0 && connData["connData"]) - src.connectionHistory = connData["connData"] //lol fuck + connectionHistory = connData["connData"] //lol fuck var/list/found = new() for(var/i in connectionHistory.len to 1 step -1) var/list/row = src.connectionHistory[i] @@ -174,12 +175,12 @@ var/list/chatResources = list( #ifdef TESTING /client/verb/debug_chat() - set hidden = 1 - chatOutput.ehjax_send(data = list("firebug" = 1)) + set hidden = TRUE + chatOutput.ehjax_send(data = list("firebug" = TRUE)) #endif //Global chat procs -/var/list/bicon_cache = list() +GLOBAL_LIST_EMPTY(bicon_cache) //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. @@ -187,8 +188,8 @@ var/list/chatResources = list( /proc/icon2base64(icon/icon, iconKey = "misc") if (!isicon(icon)) return FALSE - iconCache[iconKey] << icon - var/iconData = iconCache.ExportText(iconKey) + GLOB.iconCache[iconKey] << icon + var/iconData = GLOB.iconCache.ExportText(iconKey) var/list/partial = splittext(iconData, "{") return replacetext(copytext(partial[2], 3, -5), "\n", "") @@ -206,19 +207,15 @@ var/list/chatResources = list( // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. var/atom/A = obj var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" - if (!bicon_cache[key]) // Doesn't exist, make it. + if (!GLOB.bicon_cache[key]) // Doesn't exist, make it. var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) if (ishuman(obj)) // Shitty workaround for a BYOND issue. var/icon/temp = I I = icon() I.Insert(temp, dir = SOUTH) - bicon_cache[key] = icon2base64(I, key) + GLOB.bicon_cache[key] = icon2base64(I, key) - return "" - -//Aliases for bicon -/proc/bi(obj) - bicon(obj) + return "" //Costlier version of bicon() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. /proc/costly_bicon(obj) @@ -259,7 +256,7 @@ var/list/chatResources = list( if (C && C.chatOutput) if(C.chatOutput.broken) // A player who hasn't updated his skin file. to_chat(C, message) - return 1 + return TRUE if(!C.chatOutput.loaded && C.chatOutput.messageQueue && islist(C.chatOutput.messageQueue)) //Client sucks at loading things, put their messages in a queue C.chatOutput.messageQueue.Add(message) diff --git a/tgstation.dme b/tgstation.dme index 11f25b99116..bde9789c549 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -672,10 +672,10 @@ #include "code\game\objects\effects\decals\decal.dm" #include "code\game\objects\effects\decals\misc.dm" #include "code\game\objects\effects\decals\remains.dm" -#include "code\game\objects\effects\decals\Cleanable\aliens.dm" -#include "code\game\objects\effects\decals\Cleanable\humans.dm" -#include "code\game\objects\effects\decals\Cleanable\misc.dm" -#include "code\game\objects\effects\decals\Cleanable\robots.dm" +#include "code\game\objects\effects\decals\cleanable\aliens.dm" +#include "code\game\objects\effects\decals\cleanable\humans.dm" +#include "code\game\objects\effects\decals\cleanable\misc.dm" +#include "code\game\objects\effects\decals\cleanable\robots.dm" #include "code\game\objects\effects\effect_system\effect_system.dm" #include "code\game\objects\effects\effect_system\effects_explosion.dm" #include "code\game\objects\effects\effect_system\effects_foam.dm" From 5dc30c19849d7ec13c5e4cea10cb9836803e4113 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Mon, 1 May 2017 14:19:22 -0300 Subject: [PATCH 06/47] Changes the directory to code/modules/goonchat --- .../datums => code/modules/goonchat}/browserOutput.dm | 10 +++++----- .../goonchat}/browserassets/css/browserOutput.css | 0 .../goonchat}/browserassets/css/font-awesome.css | 0 .../goonchat}/browserassets/html/browserOutput.html | 0 .../goonchat}/browserassets/js/browserOutput.js | 0 .../modules/goonchat}/browserassets/js/json2.min.js | 0 tgstation.dme | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename {goon/code/datums => code/modules/goonchat}/browserOutput.dm (96%) rename {goon => code/modules/goonchat}/browserassets/css/browserOutput.css (100%) rename {goon => code/modules/goonchat}/browserassets/css/font-awesome.css (100%) rename {goon => code/modules/goonchat}/browserassets/html/browserOutput.html (100%) rename {goon => code/modules/goonchat}/browserassets/js/browserOutput.js (100%) rename {goon => code/modules/goonchat}/browserassets/js/json2.min.js (100%) diff --git a/goon/code/datums/browserOutput.dm b/code/modules/goonchat/browserOutput.dm similarity index 96% rename from goon/code/datums/browserOutput.dm rename to code/modules/goonchat/browserOutput.dm index d9283977283..2baaaaa47ef 100644 --- a/goon/code/datums/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -45,14 +45,14 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic var/static/list/chatResources = list( "code/modules/html_interface/js/jquery.min.js", - "goon/browserassets/js/json2.min.js", - "goon/browserassets/js/browserOutput.js", + "code/modules/goonchat/browserassets/js/json2.min.js", + "code/modules/goonchat/browserassets/js/browserOutput.js", "tgui/assets/fonts/fontawesome-webfont.eot", "tgui/assets/fonts/fontawesome-webfont.svg", "tgui/assets/fonts/fontawesome-webfont.ttf", "tgui/assets/fonts/fontawesome-webfont.woff", - "goon/browserassets/css/font-awesome.css", - "goon/browserassets/css/browserOutput.css" + "code/modules/goonchat/browserassets/css/font-awesome.css", + "code/modules/goonchat/browserassets/css/browserOutput.css" ) // to_chat(world.log, "chatOutput: load()") @@ -61,7 +61,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic owner << browse_rsc(file(asset)) //log_world("Sending main chat window to client [owner.ckey]") - owner << browse(file("goon/browserassets/html/browserOutput.html"), "window=browseroutput") + owner << browse(file("code/modules/goonchat/browserassets/html/browserOutput.html"), "window=browseroutput") sleep(14 + (chatResources.len * 7)) if(!owner || loaded) break diff --git a/goon/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css similarity index 100% rename from goon/browserassets/css/browserOutput.css rename to code/modules/goonchat/browserassets/css/browserOutput.css diff --git a/goon/browserassets/css/font-awesome.css b/code/modules/goonchat/browserassets/css/font-awesome.css similarity index 100% rename from goon/browserassets/css/font-awesome.css rename to code/modules/goonchat/browserassets/css/font-awesome.css diff --git a/goon/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html similarity index 100% rename from goon/browserassets/html/browserOutput.html rename to code/modules/goonchat/browserassets/html/browserOutput.html diff --git a/goon/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js similarity index 100% rename from goon/browserassets/js/browserOutput.js rename to code/modules/goonchat/browserassets/js/browserOutput.js diff --git a/goon/browserassets/js/json2.min.js b/code/modules/goonchat/browserassets/js/json2.min.js similarity index 100% rename from goon/browserassets/js/json2.min.js rename to code/modules/goonchat/browserassets/js/json2.min.js diff --git a/tgstation.dme b/tgstation.dme index bde9789c549..0dcead96ded 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1098,6 +1098,7 @@ #include "code\modules\awaymissions\mission_code\spacebattle.dm" #include "code\modules\awaymissions\mission_code\stationCollision.dm" #include "code\modules\awaymissions\mission_code\wildwest.dm" +#include "code\modules\browserOutput\browserOutput.dm" #include "code\modules\cargo\console.dm" #include "code\modules\cargo\export_scanner.dm" #include "code\modules\cargo\exports.dm" @@ -2090,7 +2091,6 @@ #include "code\modules\VR\vr_sleeper.dm" #include "code\modules\zombie\items.dm" #include "code\modules\zombie\organs.dm" -#include "goon\code\datums\browserOutput.dm" #include "interface\interface.dm" #include "interface\stylesheet.dm" #include "interface\skin.dmf" From d3163419134490e0f595cb215098303f0c53800b Mon Sep 17 00:00:00 2001 From: Lzimann Date: Mon, 1 May 2017 14:22:57 -0300 Subject: [PATCH 07/47] Updates tgstation.dme --- tgstation.dme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgstation.dme b/tgstation.dme index 0dcead96ded..a042dc9e7ec 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1098,7 +1098,6 @@ #include "code\modules\awaymissions\mission_code\spacebattle.dm" #include "code\modules\awaymissions\mission_code\stationCollision.dm" #include "code\modules\awaymissions\mission_code\wildwest.dm" -#include "code\modules\browserOutput\browserOutput.dm" #include "code\modules\cargo\console.dm" #include "code\modules\cargo\export_scanner.dm" #include "code\modules\cargo\exports.dm" @@ -1307,6 +1306,7 @@ #include "code\modules\food_and_drinks\recipes\tablecraft\recipes_spaghetti.dm" #include "code\modules\games\cards.dm" #include "code\modules\games\cas.dm" +#include "code\modules\goonchat\browserOutput.dm" #include "code\modules\holiday\easter.dm" #include "code\modules\holiday\holidays.dm" #include "code\modules\holodeck\area_copy.dm" From 4ee094c93b7c1cb4c96a739ec43e08bdbeedec40 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Wed, 3 May 2017 12:14:29 -0300 Subject: [PATCH 08/47] A different approach for testing --- code/modules/goonchat/browserOutput.dm | 38 +++++++++---------- .../browserassets/js/browserOutput.js | 2 +- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 2baaaaa47ef..f5a626b03f7 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -44,32 +44,28 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic return var/static/list/chatResources = list( - "code/modules/html_interface/js/jquery.min.js", - "code/modules/goonchat/browserassets/js/json2.min.js", - "code/modules/goonchat/browserassets/js/browserOutput.js", - "tgui/assets/fonts/fontawesome-webfont.eot", - "tgui/assets/fonts/fontawesome-webfont.svg", - "tgui/assets/fonts/fontawesome-webfont.ttf", - "tgui/assets/fonts/fontawesome-webfont.woff", - "code/modules/goonchat/browserassets/css/font-awesome.css", - "code/modules/goonchat/browserassets/css/browserOutput.css" + "jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js', + "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', + "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', + "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', + "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', + "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf', + "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', + "font-awesome.css" = 'code/modules/goonchat/browserassets/css/font-awesome.css', + "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + "browserOutput.html" = 'code/modules/goonchat/browserassets/html/browserOutput.html' ) // to_chat(world.log, "chatOutput: load()") - for(var/attempts in 1 to 5) - for(var/asset in chatResources) - owner << browse_rsc(file(asset)) +// for(var/attempts in 1 to 5) + for(var/asset in chatResources) + owner << browse_rsc(file(chatResources[asset]), asset) //log_world("Sending main chat window to client [owner.ckey]") - owner << browse(file("code/modules/goonchat/browserassets/html/browserOutput.html"), "window=browseroutput") - sleep(14 + (chatResources.len * 7)) - if(!owner || loaded) - break - - if(owner && !loaded) - doneLoading() // try doing this manually - CRASH("[owner] failed to load chat. Attempting doneLoading() manually") - // log_world("chatOutput: [owner.ckey] load() completed") + owner << browse(file("code/modules/goonchat/browserassets/html/browserOutput.html"), "window=browseroutput") + //sleep(14 + (chatResources.len * 7)) + if(loaded) + log_world("chatOutput: [owner.ckey] load() completed") /datum/chatOutput/Topic(href, list/href_list) if(usr.client != owner) diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index 0fb7386dd86..b47c22ecfc1 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -803,7 +803,7 @@ $(function() { $('#saveLog').click(function(e) { var saved = ''; - if (window.XMLHtpRequest) { + if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } else { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); From 4c32447c53c54a2e6fa6d73e6bc1a3df257f55c9 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Wed, 3 May 2017 12:39:21 -0300 Subject: [PATCH 09/47] Never pull with the dme open --- tgstation.dme | 1 + 1 file changed, 1 insertion(+) diff --git a/tgstation.dme b/tgstation.dme index a042dc9e7ec..62f88688c05 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -215,6 +215,7 @@ #include "code\datums\dog_fashion.dm" #include "code\datums\emotes.dm" #include "code\datums\forced_movement.dm" +#include "code\datums\holocall.dm" #include "code\datums\hud.dm" #include "code\datums\map_config.dm" #include "code\datums\martial.dm" From 4c1ad2c91dd2bfc7112476115738524702f497a0 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Wed, 3 May 2017 13:50:15 -0300 Subject: [PATCH 10/47] Sweet javascript error handler --- code/modules/goonchat/browserOutput.dm | 1 + code/modules/goonchat/browserassets/html/browserOutput.html | 1 + code/modules/goonchat/browserassets/js/browserOutput.js | 2 ++ tgstation.dme | 1 + 4 files changed, 5 insertions(+) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index f5a626b03f7..a92d64b048a 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -46,6 +46,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic var/static/list/chatResources = list( "jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js', "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', + "errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js', "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html index 74212fd8156..ea32f79da11 100644 --- a/code/modules/goonchat/browserassets/html/browserOutput.html +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -6,6 +6,7 @@ + diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index b47c22ecfc1..a89a4039db6 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -1,3 +1,4 @@ + /***************************************** * * FUNCTION AND VAR DECLARATIONS @@ -5,6 +6,7 @@ ******************************************/ //DEBUG STUFF +var triggerError = attachErrorHandler('chatDebug', true); var escaper = encodeURIComponent || escape; var decoder = decodeURIComponent || unescape; window.onerror = function(msg, url, line, col, error) { diff --git a/tgstation.dme b/tgstation.dme index 62f88688c05..726b46f5663 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1308,6 +1308,7 @@ #include "code\modules\games\cards.dm" #include "code\modules\games\cas.dm" #include "code\modules\goonchat\browserOutput.dm" +#include "code\modules\goonchat\jsErrorHandler.dm" #include "code\modules\holiday\easter.dm" #include "code\modules\holiday\holidays.dm" #include "code\modules\holodeck\area_copy.dm" From 13da512ea096a0160b1e31c0bdb74b808b117c81 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Wed, 3 May 2017 14:06:34 -0300 Subject: [PATCH 11/47] Actually adds the files --- .../goonchat/browserassets/js/errorHandler.js | 34 +++++++ code/modules/goonchat/jsErrorHandler.dm | 97 +++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 code/modules/goonchat/browserassets/js/errorHandler.js create mode 100644 code/modules/goonchat/jsErrorHandler.dm diff --git a/code/modules/goonchat/browserassets/js/errorHandler.js b/code/modules/goonchat/browserassets/js/errorHandler.js new file mode 100644 index 00000000000..ebe7e324112 --- /dev/null +++ b/code/modules/goonchat/browserassets/js/errorHandler.js @@ -0,0 +1,34 @@ +(function(window, navigator) { + + var escaper = encodeURIComponent || escape; + + var triggerError = function(msg, url, line, col, error) { + window.onerror(msg, url, line, col, error); + }; + + /** + * Directs JS errors to a byond proc for logging + * + * @param string file Name of the logfile to dump errors in, do not prepend with data/ + * @param boolean overrideDefault True to prevent default JS errors (an big honking error prompt thing) + * @return boolean + */ + var attach = function(file, overrideDefault) { + overrideDefault = typeof overrideDefault === 'undefined' ? false : overrideDefault; + file = escaper(file); + + window.onerror = function(msg, url, line, col, error) { + 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 = '?action=debugFileOutput&file=' + file + '&message=' + escaper(debugLine); + return overrideDefault; + }; + + return triggerError; + }; + + window.attachErrorHandler = attach; + +}(window, window.navigator)); \ No newline at end of file diff --git a/code/modules/goonchat/jsErrorHandler.dm b/code/modules/goonchat/jsErrorHandler.dm new file mode 100644 index 00000000000..1038ff46add --- /dev/null +++ b/code/modules/goonchat/jsErrorHandler.dm @@ -0,0 +1,97 @@ +/** +* This is a generic handler for logging your dumb JS errors generated by html popups +* +* 1. Add your logfile to the validFiles list +* 2. Include the "browserassets/js/errorHandler.js" file in your html file (if using chui, skip this step) (look at browserOutput.html for an example) +* 3. Call attachErrorHandler('yourLogFile'); at the top of your JS (again see browserOutput.js for an example) +*/ + +/datum/debugFileOutput + var/directory = "data/popupErrors" //where to shove all the logfiles + var/ext = "log" //file extension + var/logFileLimit = 52428800 //50mb, so yeah pretty permissive + + //Add your dumb file here. This is so some schmuck can't just shit out a bunch of spam logfiles and use all the diskspace. Relative to src.directory + var/list/validFiles = list( + "chatDebug", + "tooltipDebug", + "chemDispenser", + "banPanel", + "stationNamer" + ) + +/datum/debugFileOutput/proc/error(fileName, message, client/C) + if (!fileName || !message) return 0 + + if (!(fileName in src.validFiles)) + throw EXCEPTION("Debug log file '[fileName].[src.ext]' is not a valid path.") + + var/logFile = file("[src.directory]/[fileName].[src.ext]") + var/fileSize = length(logFile) + if (fileSize >= src.logFileLimit) + CRASH("Debug Error Handling encountered an error! This is highly ironic! File: '[fileName]' has exceeded the filesize limit of: [src.logFileLimit] bytes") + + message = "\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: \[[C && C.key ? C.key : "Unknown Client"]\] triggered: [message]" + logFile << message + return 1 + +/datum/debugFileOutput/proc/clear(fileName) + if (!fileName) return 0 + + if (!fexists("[src.directory]/[fileName].[src.ext]")) + throw EXCEPTION("Debug log file '[fileName].[src.ext]' does not exist.") + + if (!(fileName in src.validFiles)) + throw EXCEPTION("Debug log file '[fileName].[src.ext]' is not a valid path.") + + fdel("[src.directory]/[fileName].[src.ext]") + return 1 + +/datum/debugFileOutput/proc/clearAll() + var/list/deleted = new() + for (var/fileName in src.validFiles) + if (fexists("[src.directory]/[fileName].[src.ext]")) + fdel("[src.directory]/[fileName].[src.ext]") + deleted += fileName + + return deleted + + +var/global/datum/debugFileOutput/debugFileOutput = new() + +/client/Topic(href, href_list) + ..() + + if (href_list["action"] && href_list["action"] == "debugFileOutput" && href_list["file"] && href_list["message"]) + var/file = href_list["file"] + var/message = href_list["message"] + debugFileOutput.error(file, message, src) + +/client/proc/deleteJsLogFile(fileName as text) + set category = "Debug" + set name = "Delete JS Logfile" + set desc = "Delete a logfile for JS error reporting. Be sure you want to do this!" + set popup_menu = 0 + if(!holder) + return + if (!fileName) + return + + debugFileOutput.clear(fileName) + + log_admin("[key_name(usr)] deleted the '[fileName]' JS logfile") + message_admins("[key_name_admin(usr)] deleted the '[fileName]' JS logfile") + +/client/proc/deleteAllJsLogFiles() + set category = null + set name = "Delete All JS Logfiles" + set desc = "Delete all logfiles for JS error reporting. Be extra sure you want to do this!" + + if (alert("Are you really sure you want to delete every single JS logfile?", "No", "Yes") == "No") + return + + var/list/summary = debugFileOutput.clearAll() + var/friendlySummary = summary.Join(", ") + + log_admin("[key_name(usr)] deleted every JS logfile! ([friendlySummary])") + message_admins("[key_name_admin(usr)] deleted every JS logfile! ([friendlySummary])") \ No newline at end of file From 3c13e1747f6bcce315779fb91e54fcbef3291a72 Mon Sep 17 00:00:00 2001 From: Lzimann Date: Wed, 3 May 2017 15:02:36 -0300 Subject: [PATCH 12/47] Glob for the glob god --- code/modules/goonchat/jsErrorHandler.dm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/code/modules/goonchat/jsErrorHandler.dm b/code/modules/goonchat/jsErrorHandler.dm index 1038ff46add..67ea5faca38 100644 --- a/code/modules/goonchat/jsErrorHandler.dm +++ b/code/modules/goonchat/jsErrorHandler.dm @@ -57,7 +57,7 @@ return deleted -var/global/datum/debugFileOutput/debugFileOutput = new() +GLOBAL_DATUM_INIT(debugFileOutput, /datum/debugFileOutput, new) /client/Topic(href, href_list) ..() @@ -65,7 +65,7 @@ var/global/datum/debugFileOutput/debugFileOutput = new() if (href_list["action"] && href_list["action"] == "debugFileOutput" && href_list["file"] && href_list["message"]) var/file = href_list["file"] var/message = href_list["message"] - debugFileOutput.error(file, message, src) + GLOB.debugFileOutput.error(file, message, src) /client/proc/deleteJsLogFile(fileName as text) set category = "Debug" @@ -77,7 +77,7 @@ var/global/datum/debugFileOutput/debugFileOutput = new() if (!fileName) return - debugFileOutput.clear(fileName) + GLOB.debugFileOutput.clear(fileName) log_admin("[key_name(usr)] deleted the '[fileName]' JS logfile") message_admins("[key_name_admin(usr)] deleted the '[fileName]' JS logfile") @@ -87,10 +87,13 @@ var/global/datum/debugFileOutput/debugFileOutput = new() set name = "Delete All JS Logfiles" set desc = "Delete all logfiles for JS error reporting. Be extra sure you want to do this!" + if(!holder) + return + if (alert("Are you really sure you want to delete every single JS logfile?", "No", "Yes") == "No") return - var/list/summary = debugFileOutput.clearAll() + var/list/summary = GLOB.debugFileOutput.clearAll() var/friendlySummary = summary.Join(", ") log_admin("[key_name(usr)] deleted every JS logfile! ([friendlySummary])") From 92ab7e1d811ce46cb4269d77fab66d2e4d31e5a9 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 5 May 2017 19:15:12 -0400 Subject: [PATCH 13/47] Adds debugging procs --- code/modules/goonchat/browserOutput.dm | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index a92d64b048a..f123989120b 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -13,8 +13,12 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic var/cookieSent = FALSE // Has the client sent a cookie for analysis var/list/connectionHistory //Contains the connection history passed from chat cookie var/broken = FALSE + var/static/debug_log /datum/chatOutput/New(client/C) + if(!debug_log) + debug_log = file("[GLOB.log_directory]/goonchat.log") + owner = C messageQueue = list() connectionHistory = list() @@ -72,6 +76,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if(usr.client != owner) return TRUE + debug_log << "[owner.ckey] >> [href]" + // Build arguments. // Arguments are in the form "param[paramname]=thing" var/list/params = list() @@ -124,6 +130,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic /datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) if(islist(data)) data = json_encode(data) + debug_log << "[C.ckey] << [data]" C << output("[data]", "[window]:ehjaxCallback") //Sends client connection details to the chat to handle and save @@ -170,11 +177,16 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic /datum/chatOutput/proc/debug(error) log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") -#ifdef TESTING +/datum/chatOutput/proc/Broke() + debug_log << "THE CHAT BROKE FOR [usr.client.ckey]" + /client/verb/debug_chat() set hidden = TRUE chatOutput.ehjax_send(data = list("firebug" = TRUE)) -#endif + +/client/verb/chat_broke() + chatOutput.Broke() + //Global chat procs GLOBAL_LIST_EMPTY(bicon_cache) From a1b5ce06b0836c89c3501a1bf7ffc6011b76ad32 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:13:33 -0400 Subject: [PATCH 14/47] Less spam --- code/modules/goonchat/browserOutput.dm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index f123989120b..8a511879fb8 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -76,8 +76,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if(usr.client != owner) return TRUE - debug_log << "[owner.ckey] >> [href]" - + var/doLog = TRUE // Build arguments. // Arguments are in the form "param[paramname]=thing" var/list/params = list() @@ -98,13 +97,18 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if("ping") data = ping(arglist(params)) + doLog = FALSE if("analyzeClientData") data = analyzeClientData(arglist(params)) + if(doLog) + debug_log << "[owner.ckey] >> [href]" + if(data) ehjax_send(data = data) + //Called on chat output done-loading by JS. /datum/chatOutput/proc/doneLoading() if(loaded) From ff273f31259c54c6858448dd535d534931bc1129 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:22:39 -0400 Subject: [PATCH 15/47] Even less spammy --- code/modules/goonchat/browserOutput.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 8a511879fb8..0e450666281 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -188,7 +188,12 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic set hidden = TRUE chatOutput.ehjax_send(data = list("firebug" = TRUE)) +GLOBAL_LIST_EMPTY(broken_ckeys) /client/verb/chat_broke() + if(broken_ckeys[ckey]) + return + broken_ckeys[ckey] = TRUE + message_admins("The chat broke for [ckey]!") chatOutput.Broke() //Global chat procs From d76eb9644c37acb0d594fb7bf878adeac4849a81 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:25:42 -0400 Subject: [PATCH 16/47] Even better --- code/modules/goonchat/browserOutput.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 0e450666281..63ea95f1f00 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -190,8 +190,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic GLOBAL_LIST_EMPTY(broken_ckeys) /client/verb/chat_broke() + set category = "OOC" if(broken_ckeys[ckey]) return + if(alert(usr, "HEY LISTEN! We are debugging the new chat system and you can only use this command once! HAS YOUR CHAT BOX ACTUALLY BROKEN?",, "Yes", "No") != "Yes") + return broken_ckeys[ckey] = TRUE message_admins("The chat broke for [ckey]!") chatOutput.Broke() From 04a483d48bc4c43204adf71c62eb4d02bd8b23a4 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:26:08 -0400 Subject: [PATCH 17/47] Ree --- code/modules/goonchat/browserOutput.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 63ea95f1f00..26d96f64db3 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -191,11 +191,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic GLOBAL_LIST_EMPTY(broken_ckeys) /client/verb/chat_broke() set category = "OOC" - if(broken_ckeys[ckey]) + if(GLOB.broken_ckeys[ckey]) return if(alert(usr, "HEY LISTEN! We are debugging the new chat system and you can only use this command once! HAS YOUR CHAT BOX ACTUALLY BROKEN?",, "Yes", "No") != "Yes") return - broken_ckeys[ckey] = TRUE + GLOB.broken_ckeys[ckey] = TRUE message_admins("The chat broke for [ckey]!") chatOutput.Broke() From 97676ce920ec58d307d4fd147811fdb422b1a5be Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:27:22 -0400 Subject: [PATCH 18/47] Stuff --- code/modules/goonchat/browserOutput.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 26d96f64db3..d196bc8e8cd 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -191,6 +191,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic GLOBAL_LIST_EMPTY(broken_ckeys) /client/verb/chat_broke() set category = "OOC" + set name = "CHAT BROKE" if(GLOB.broken_ckeys[ckey]) return if(alert(usr, "HEY LISTEN! We are debugging the new chat system and you can only use this command once! HAS YOUR CHAT BOX ACTUALLY BROKEN?",, "Yes", "No") != "Yes") From afad85f7d62098d8b01b2c4704bca0b61e15482f Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:29:25 -0400 Subject: [PATCH 19/47] So much spam --- code/modules/goonchat/browserOutput.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index d196bc8e8cd..265f912fdba 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -99,6 +99,9 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic data = ping(arglist(params)) doLog = FALSE + if("pong" || "pang") + doLog = FALSE + if("analyzeClientData") data = analyzeClientData(arglist(params)) @@ -191,7 +194,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic GLOBAL_LIST_EMPTY(broken_ckeys) /client/verb/chat_broke() set category = "OOC" - set name = "CHAT BROKE" + set name = "MY CHAT BROKE!" if(GLOB.broken_ckeys[ckey]) return if(alert(usr, "HEY LISTEN! We are debugging the new chat system and you can only use this command once! HAS YOUR CHAT BOX ACTUALLY BROKEN?",, "Yes", "No") != "Yes") From 0d59f922d6fe033b0c79803ca62308bc17eabebc Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:31:29 -0400 Subject: [PATCH 20/47] So much spam! --- code/modules/goonchat/browserOutput.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 265f912fdba..e6de1a8bf9e 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -99,13 +99,10 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic data = ping(arglist(params)) doLog = FALSE - if("pong" || "pang") - doLog = FALSE - if("analyzeClientData") data = analyzeClientData(arglist(params)) - if(doLog) + if(doLog && href != "pong" && href != "pang") debug_log << "[owner.ckey] >> [href]" if(data) From fd805a7f879a0091d47a49a9dac46ace08f83910 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sat, 6 May 2017 11:35:01 -0400 Subject: [PATCH 21/47] Wew --- code/modules/goonchat/browserOutput.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index e6de1a8bf9e..f323c8fc47a 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -102,7 +102,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if("analyzeClientData") data = analyzeClientData(arglist(params)) - if(doLog && href != "pong" && href != "pang") + if(doLog) debug_log << "[owner.ckey] >> [href]" if(data) @@ -134,7 +134,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic /datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) if(islist(data)) data = json_encode(data) - debug_log << "[C.ckey] << [data]" + if(data != "pong" && data != "pang" && data != "softPang") + debug_log << "[C.ckey] << [data]" C << output("[data]", "[window]:ehjaxCallback") //Sends client connection details to the chat to handle and save From 4ad986bde853b6851b13d52bfeee23da672ce2e4 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 8 May 2017 09:28:34 -0400 Subject: [PATCH 22/47] @SpaiR's recommendation for log saving --- .../browserassets/js/browserOutput.js | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index a89a4039db6..d8c8d5b8afe 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -803,31 +803,25 @@ $(function() { }); $('#saveLog').click(function(e) { - var saved = ''; + $.ajax({ + type: 'GET', + url: 'browserOutput.css', + success: function(styleData) { + var win; - if (window.XMLHttpRequest) { - xmlHttp = new XMLHttpRequest(); - } else { - xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); - } - xmlHttp.open('GET', 'browserOutput.css', false); - xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xmlHttp.send(); - saved += ''; + try { + win = window.open('', 'Chat Log', 'toolbar=no, location=no, directories=no, status=no, menubar=yes, scrollbars=yes, resizable=yes, width=780, height=600, top=' + (screen.height/2 - 635/2) + ', left=' + (screen.width/2 - 780/2)); + } catch (e) { + return; + } - saved += $messages.html(); - saved = saved.replace(/&/g, '&'); - saved = saved.replace(/Chat Log'; + win.document.head.innerHTML += ''; + win.document.body.innerHTML = $messages.html(); + } + } + }); }); $('#highlightTerm').click(function(e) { From d7326821a6ab68d5fa644216f626b9b8495719b3 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 8 May 2017 10:29:13 -0400 Subject: [PATCH 23/47] Fixes rogue html and <<'s --- code/game/gamemodes/cult/cult_comms.dm | 2 +- code/game/gamemodes/cult/ritual.dm | 2 +- code/modules/stock_market/computer.dm | 2 +- code/world.dm | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm index ffaaf46b802..d01d5603654 100644 --- a/code/game/gamemodes/cult/cult_comms.dm +++ b/code/game/gamemodes/cult/cult_comms.dm @@ -171,7 +171,7 @@ return 0 if(cooldown > world.time) if(!CM.active) - owner << "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can mark another target!" + to_chat(owner, "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can mark another target!") return 0 return ..() diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 069a4224800..a83e83cdbd5 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -70,7 +70,7 @@ This file contains the arcane tome files. /obj/item/weapon/tome/proc/read_tome(mob/user) var/text = "" text += "
Archives of the Dark One



" - text += "A rune's name and effects can be revealed by examining the rune.<

" + text += "A rune's name and effects can be revealed by examining the rune.

" text += "Create Talisman
This rune is one of the most important runes the cult has, being the only way to create new talismans. A blank sheet of paper must be on top of the rune. After \ invoking it and choosing which talisman you desire, the paper will be converted, after some delay into a talisman.

" diff --git a/code/modules/stock_market/computer.dm b/code/modules/stock_market/computer.dm index 5299debf24f..9cef9b30483 100644 --- a/code/modules/stock_market/computer.dm +++ b/code/modules/stock_market/computer.dm @@ -235,7 +235,7 @@ a.updated { if (!amt) return if (!S.buyShares(logged_in, amt)) - to_chat(user, "<Could not complete transaction.") + to_chat(user, "Could not complete transaction.") return var/total = amt * S.current_value diff --git a/code/world.dm b/code/world.dm index 353d8198183..87815b8e959 100644 --- a/code/world.dm +++ b/code/world.dm @@ -198,7 +198,7 @@ #define CHAT_PULLR 64 //defined in preferences.dm, but not available here at compilation time for(var/client/C in GLOB.clients) if(C.prefs && (C.prefs.chat_toggles & CHAT_PULLR)) - C << "PR: [announcement]" + to_chat(C, "PR: [announcement]") #undef CHAT_PULLR #define WORLD_REBOOT(X) log_world("World rebooted at [time_stamp()]"); ..(X); return; From 41d0f0aa74845bb81b0d73c7abfe4bc7f75ca086 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 8 May 2017 10:31:15 -0400 Subject: [PATCH 24/47] And this --- code/modules/mob/living/silicon/robot/robot_defense.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 01c700768f1..a160818ed4a 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -152,7 +152,7 @@ sleep(5) to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") sleep(10) - to_chat(src, "> N") + to_chat(src, " N") sleep(20) to_chat(src, "ERRORERRORERROR") to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and their commands.") From 87c47c6c6359afe5075c898529182dd0bbb09876 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 8 May 2017 11:44:56 -0400 Subject: [PATCH 25/47] Revert "And this" This reverts commit 41d0f0aa74845bb81b0d73c7abfe4bc7f75ca086. --- code/modules/mob/living/silicon/robot/robot_defense.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index a160818ed4a..01c700768f1 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -152,7 +152,7 @@ sleep(5) to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") sleep(10) - to_chat(src, " N") + to_chat(src, "> N") sleep(20) to_chat(src, "ERRORERRORERROR") to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and their commands.") From a79187962f91077cbe4bd6328af76617212c59b3 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 15:35:57 -0400 Subject: [PATCH 26/47] Fix new bicons --- code/game/gamemodes/gang/gang_datum.dm | 2 +- code/game/machinery/computer/apc_control.dm | 8 ++++---- code/game/objects/items/weapons/pneumaticCannon.dm | 4 ++-- code/game/objects/items/weapons/powerfist.dm | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/game/gamemodes/gang/gang_datum.dm b/code/game/gamemodes/gang/gang_datum.dm index 664938d60ba..315ed48ab1c 100644 --- a/code/game/gamemodes/gang/gang_datum.dm +++ b/code/game/gamemodes/gang/gang_datum.dm @@ -286,7 +286,7 @@ G.points += points_newer pmessage += "Your influential choice of clothing has further increased your influence by [points_newer] points.
" pmessage += "You now have [G.points] influence.
" - to_chat(ganger, "\icon[G] [pmessage]") + to_chat(ganger, "[bicon(G)] [pmessage]") //Multiverse diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index 0c1b870771b..0c624688ce6 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -116,24 +116,24 @@ authenticated = FALSE auth_id = "\[NULL\]" if(href_list["restore_logging"]) - to_chat(usr, "\icon[src] Logging functionality restored from backup data.") + to_chat(usr, "[bicon(src)] Logging functionality restored from backup data.") emagged = FALSE LAZYADD(logs, "-=- Logging restored to full functionality at this point -=-") if(href_list["access_apc"]) playsound(src, "terminal_type", 50, 0) var/obj/machinery/power/apc/APC = locate(href_list["access_apc"]) in GLOB.apcs_list if(!APC || APC.aidisabled || APC.panel_open || QDELETED(APC)) - to_chat(usr, "\icon[src] APC does not return interface request. Remote access may be disabled.") + to_chat(usr, "[bicon(src)] APC does not return interface request. Remote access may be disabled.") return if(active_apc) - to_chat(usr, "\icon[src] Disconnected from [active_apc].") + to_chat(usr, "[bicon(src)] Disconnected from [active_apc].") active_apc.say("Remote access canceled. Interface locked.") playsound(active_apc, 'sound/machines/BoltsDown.ogg', 25, 0) playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0) active_apc.locked = TRUE active_apc.update_icon() active_apc = null - to_chat(usr, "\icon[src] Connected to APC in [get_area(APC)]. Interface request sent.") + to_chat(usr, "[bicon(src)] Connected to APC in [get_area(APC)]. Interface request sent.") log_activity("remotely accessed APC in [get_area(APC)]") APC.interact(usr, GLOB.not_incapacitated_state) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) diff --git a/code/game/objects/items/weapons/pneumaticCannon.dm b/code/game/objects/items/weapons/pneumaticCannon.dm index bc26417b0ca..8af789bfcf3 100644 --- a/code/game/objects/items/weapons/pneumaticCannon.dm +++ b/code/game/objects/items/weapons/pneumaticCannon.dm @@ -36,9 +36,9 @@ to_chat(user, "You'll need to get closer to see any more.") return for(var/obj/item/I in loadedItems) - to_chat(user, "\icon [I] It has \the [I] loaded.") + to_chat(user, "[bicon(I)] It has \the [I] loaded.") if(tank) - to_chat(user, "\icon [tank] It has \the [tank] mounted onto it.") + to_chat(user, "[bicon(tank)] It has \the [tank] mounted onto it.") /obj/item/weapon/pneumatic_cannon/attackby(obj/item/weapon/W, mob/user, params) diff --git a/code/game/objects/items/weapons/powerfist.dm b/code/game/objects/items/weapons/powerfist.dm index 7b26c58a5df..d3a940090dd 100644 --- a/code/game/objects/items/weapons/powerfist.dm +++ b/code/game/objects/items/weapons/powerfist.dm @@ -24,7 +24,7 @@ to_chat(user, "You'll need to get closer to see any more.") return if(tank) - to_chat(user, "\icon [tank] It has \the [tank] mounted onto it.") + to_chat(user, "[bicon(tank)] It has \the [tank] mounted onto it.") /obj/item/weapon/melee/powerfist/attackby(obj/item/weapon/W, mob/user, params) From 71a72f8c9642ceef8b5c29f1860bcddb4ddac434 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 15:38:00 -0400 Subject: [PATCH 27/47] Makes bicon param less stupidly named --- code/modules/goonchat/browserOutput.dm | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index f323c8fc47a..b413a3d251f 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -216,23 +216,23 @@ GLOBAL_LIST_EMPTY(bicon_cache) var/list/partial = splittext(iconData, "{") return replacetext(copytext(partial[2], 3, -5), "\n", "") -/proc/bicon(obj) - if (!obj) +/proc/bicon(thing) + if (QDELETED(thing)) return - if (isicon(obj)) + if (isicon(thing)) //Icons get pooled constantly, references are no good here. /*if (!bicon_cache["\ref[obj]"]) // Doesn't exist yet, make it. bicon_cache["\ref[obj]"] = icon2base64(obj) return ""*/ - return "" + return "" // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. - var/atom/A = obj + var/atom/A = thing var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" if (!GLOB.bicon_cache[key]) // Doesn't exist, make it. var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) - if (ishuman(obj)) // Shitty workaround for a BYOND issue. + if (ishuman(thing)) // Shitty workaround for a BYOND issue. var/icon/temp = I I = icon() I.Insert(temp, dir = SOUTH) @@ -241,14 +241,14 @@ GLOBAL_LIST_EMPTY(bicon_cache) return "" //Costlier version of bicon() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. -/proc/costly_bicon(obj) - if (!obj) +/proc/costly_bicon(thing) + if (!thing) return - if (isicon(obj)) - return bicon(obj) + if (isicon(thing)) + return bicon(thing) - var/icon/I = getFlatIcon(obj) + var/icon/I = getFlatIcon(thing) return bicon(I) /proc/to_chat(target, message) From 705beac0da02ffb349aa37b0fd7c6c7c2897c6e3 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 15:46:31 -0400 Subject: [PATCH 28/47] Make bicon_cache static --- code/modules/goonchat/browserOutput.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index b413a3d251f..a1056ce79ae 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -203,8 +203,6 @@ GLOBAL_LIST_EMPTY(broken_ckeys) //Global chat procs -GLOBAL_LIST_EMPTY(bicon_cache) - //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) @@ -230,15 +228,17 @@ GLOBAL_LIST_EMPTY(bicon_cache) // 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 (!GLOB.bicon_cache[key]) // Doesn't exist, make it. + + var/static/list/bicon_cache = list() + 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) - GLOB.bicon_cache[key] = icon2base64(I, key) + bicon_cache[key] = icon2base64(I, key) - return "" + return "" //Costlier version of bicon() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. /proc/costly_bicon(thing) From 2addb941eb7b7ca4f945501fb9a6da72b1e0519f Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 15:53:14 -0400 Subject: [PATCH 29/47] Cleans up to_chat --- code/modules/goonchat/browserOutput.dm | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index a1056ce79ae..88b55a2b6fd 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -252,14 +252,25 @@ GLOBAL_LIST_EMPTY(broken_ckeys) return bicon(I) /proc/to_chat(target, message) - if(isnull(target)) + if(!target) return + + if(target == world) + to_chat(GLOB.clients, message) + return + + if(islist(target)) + for(var/I in target) + to_chat(target, message) + return + //Ok so I did my best but I accept that some calls to this will be for shit like sound and images //It stands that we PROBABLY don't want to output those to the browser output so just handle them here - if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || islist(target) || istype(target, /client) || istype(target, /datum/log) || target == world)) + if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || istype(target, /datum/log))) target << message + stack_trace("to_chat called with invalid target! [target]") if (!istype(target, /atom)) // Really easy to mix these up, and not having to make sure things are mobs makes the code cleaner. - CRASH("DEBUG: Boutput called with invalid message") + CRASH("to_chat called with invalid message") return //Otherwise, we're good to throw it at the user From e3495fa03494d3b1b3e749fc96ad313d0ebd2d5b Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 16:05:36 -0400 Subject: [PATCH 30/47] Remove debug code fix bugs --- code/modules/goonchat/browserOutput.dm | 44 ++++---------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 88b55a2b6fd..a70257976a0 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -12,17 +12,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic 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/list/connectionHistory //Contains the connection history passed from chat cookie - var/broken = FALSE - var/static/debug_log /datum/chatOutput/New(client/C) - if(!debug_log) - debug_log = file("[GLOB.log_directory]/goonchat.log") - owner = C messageQueue = list() connectionHistory = list() - // log_world("chatOutput: New()") /datum/chatOutput/proc/start() //Check for existing chat @@ -30,9 +24,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic return FALSE if(!winexists(owner, "browseroutput")) // Oh goddamnit. + set waitfor = FALSE + 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.") - broken = TRUE - return FALSE + return if(winget(owner, "browseroutput", "is-disabled") == "false") //Already setup doneLoading() @@ -61,16 +57,10 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic "browserOutput.html" = 'code/modules/goonchat/browserassets/html/browserOutput.html' ) - // to_chat(world.log, "chatOutput: load()") -// for(var/attempts in 1 to 5) for(var/asset in chatResources) owner << browse_rsc(file(chatResources[asset]), asset) - //log_world("Sending main chat window to client [owner.ckey]") owner << browse(file("code/modules/goonchat/browserassets/html/browserOutput.html"), "window=browseroutput") - //sleep(14 + (chatResources.len * 7)) - if(loaded) - log_world("chatOutput: [owner.ckey] load() completed") /datum/chatOutput/Topic(href, list/href_list) if(usr.client != owner) @@ -114,6 +104,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if(loaded) return + testing("Chat loaded for [owner.ckey]") loaded = TRUE winset(owner, "browseroutput", "is-disabled=false") for(var/message in messageQueue) @@ -134,8 +125,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic /datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) if(islist(data)) data = json_encode(data) - if(data != "pong" && data != "pang" && data != "softPang") - debug_log << "[C.ckey] << [data]" C << output("[data]", "[window]:ehjaxCallback") //Sends client connection details to the chat to handle and save @@ -182,25 +171,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic /datum/chatOutput/proc/debug(error) log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") -/datum/chatOutput/proc/Broke() - debug_log << "THE CHAT BROKE FOR [usr.client.ckey]" - -/client/verb/debug_chat() - set hidden = TRUE - chatOutput.ehjax_send(data = list("firebug" = TRUE)) - -GLOBAL_LIST_EMPTY(broken_ckeys) -/client/verb/chat_broke() - set category = "OOC" - set name = "MY CHAT BROKE!" - if(GLOB.broken_ckeys[ckey]) - return - if(alert(usr, "HEY LISTEN! We are debugging the new chat system and you can only use this command once! HAS YOUR CHAT BOX ACTUALLY BROKEN?",, "Yes", "No") != "Yes") - return - GLOB.broken_ckeys[ckey] = TRUE - message_admins("The chat broke for [ckey]!") - chatOutput.Broke() - //Global chat procs //Converts an icon to base64. Operates by putting the icon in the iconCache savefile, @@ -215,7 +185,7 @@ GLOBAL_LIST_EMPTY(broken_ckeys) return replacetext(copytext(partial[2], 3, -5), "\n", "") /proc/bicon(thing) - if (QDELETED(thing)) + if (!thing) return if (isicon(thing)) @@ -289,7 +259,7 @@ GLOBAL_LIST_EMPTY(broken_ckeys) if (C && C.chatOutput) if(C.chatOutput.broken) // A player who hasn't updated his skin file. - to_chat(C, message) + C << message return TRUE if(!C.chatOutput.loaded && C.chatOutput.messageQueue && islist(C.chatOutput.messageQueue)) //Client sucks at loading things, put their messages in a queue From 09e63f633cffb245c8dd270d70241b5fedba312e Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 16:08:47 -0400 Subject: [PATCH 31/47] Another fix --- code/modules/goonchat/browserOutput.dm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index a70257976a0..06685ee8a4d 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -11,6 +11,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic 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) @@ -25,6 +26,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic 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.") @@ -66,7 +68,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if(usr.client != owner) return TRUE - var/doLog = TRUE // Build arguments. // Arguments are in the form "param[paramname]=thing" var/list/params = list() @@ -87,14 +88,10 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if("ping") data = ping(arglist(params)) - doLog = FALSE if("analyzeClientData") data = analyzeClientData(arglist(params)) - if(doLog) - debug_log << "[owner.ckey] >> [href]" - if(data) ehjax_send(data = data) From 42be7a34f94b264fb668a3c4cc6e5562ccbf5a54 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 26 May 2017 16:16:41 -0400 Subject: [PATCH 32/47] Fix dept stylesheet --- code/modules/goonchat/browserassets/css/browserOutput.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index 820537e32b1..94ab5fe4d93 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -252,8 +252,8 @@ em {font-style: normal; font-weight: bold;} .engradio {color: #fb5613;} .medradio {color: #337296;} .sciradio {color: #993399;} -.supradio {color: #a8732b;} -.servadio {color: #6eaa2c;} +.suppradio {color: #a8732b;} +.servradio {color: #6eaa2c;} .attack {color: #ff0000;} .disarm {color: #990000;} From caeb8b53496dd95fdebd98f036d2e96fa211b455 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sun, 28 May 2017 12:38:30 -0400 Subject: [PATCH 33/47] Fixes default font size --- code/modules/goonchat/browserassets/css/browserOutput.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index 94ab5fe4d93..383b9b58ca6 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -56,7 +56,7 @@ a.popt {text-decoration: none;} #loading i {display: block; padding-bottom: 3px;} #messages { - font-size: 14px; + font-size: 13px; padding: 3px; margin: 0; word-wrap: break-word; From dee794122d207fc45b397833755e226ce9a4fbf6 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sun, 28 May 2017 12:38:37 -0400 Subject: [PATCH 34/47] Fix client targets --- code/modules/goonchat/browserOutput.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 06685ee8a4d..5c541c430ca 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -233,7 +233,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic //Ok so I did my best but I accept that some calls to this will be for shit like sound and images //It stands that we PROBABLY don't want to output those to the browser output so just handle them here - if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || istype(target, /datum/log))) + if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || !istype(target, /client) || istype(target, /datum/log))) target << message stack_trace("to_chat called with invalid target! [target]") if (!istype(target, /atom)) // Really easy to mix these up, and not having to make sure things are mobs makes the code cleaner. From 2d816ba454d32d74e8bdb6aa8a1e55c6cfff39ea Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sun, 28 May 2017 12:40:32 -0400 Subject: [PATCH 35/47] Fix it harder --- code/modules/goonchat/browserOutput.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 5c541c430ca..eabfbdedfc6 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -233,7 +233,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic //Ok so I did my best but I accept that some calls to this will be for shit like sound and images //It stands that we PROBABLY don't want to output those to the browser output so just handle them here - if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || !istype(target, /client) || istype(target, /datum/log))) + if (istype(message, /image) || istype(message, /sound) || istype(target, /savefile) || !(ismob(target) || istype(target, /client) || istype(target, /datum/log))) target << message stack_trace("to_chat called with invalid target! [target]") if (!istype(target, /atom)) // Really easy to mix these up, and not having to make sure things are mobs makes the code cleaner. From 1fecdd2fe4e2e599919a474cc50fb12f95945ccb Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Wed, 7 Jun 2017 10:59:56 -0400 Subject: [PATCH 36/47] Make it use rsc html --- code/modules/goonchat/browserOutput.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index eabfbdedfc6..a52c20bd151 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -62,7 +62,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic for(var/asset in chatResources) owner << browse_rsc(file(chatResources[asset]), asset) - owner << browse(file("code/modules/goonchat/browserassets/html/browserOutput.html"), "window=browseroutput") + owner << browse(file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput") /datum/chatOutput/Topic(href, list/href_list) if(usr.client != owner) From 45aa3f8a3e6e5f82d5315a74205e08c693eedb9f Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Wed, 7 Jun 2017 11:00:16 -0400 Subject: [PATCH 37/47] Make it use asset cache --- code/modules/client/asset_cache.dm | 15 +++++++++++++++ code/modules/goonchat/browserOutput.dm | 19 +++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index a29c3179b21..811f6ee8f19 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -279,6 +279,21 @@ GLOBAL_LIST_EMPTY(asset_datums) "changelog.css" = 'html/changelog.css' ) +/datum/asset/simple/goonchat + verify = TRUE + assets = list( + "jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js', + "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', + "errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js', + "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', + "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', + "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', + "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf', + "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', + "font-awesome.css" = 'code/modules/goonchat/browserassets/css/font-awesome.css', + "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + ) + //Registers HTML Interface assets. /datum/asset/HTML_interface/register() for(var/path in typesof(/datum/html_interface)) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index a52c20bd151..09d44d4e911 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -45,22 +45,9 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if(!owner) return - var/static/list/chatResources = list( - "jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js', - "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', - "errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js', - "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', - "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot', - "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg', - "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf', - "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff', - "font-awesome.css" = 'code/modules/goonchat/browserassets/css/font-awesome.css', - "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', - "browserOutput.html" = 'code/modules/goonchat/browserassets/html/browserOutput.html' - ) - - for(var/asset in chatResources) - owner << browse_rsc(file(chatResources[asset]), asset) + var/datum/asset/stuff = get_asset_datum(/datum/asset/simple/goonchat) + stuff.register() + stuff.send(owner) owner << browse(file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput") From 5a6053db57c38b91aa31ed0bdae3324555cb682f Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Wed, 7 Jun 2017 11:11:01 -0400 Subject: [PATCH 38/47] Fixes to_chat with lists --- code/modules/goonchat/browserOutput.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 09d44d4e911..636ce5baf23 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -215,7 +215,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic if(islist(target)) for(var/I in target) - to_chat(target, message) + to_chat(I, message) return //Ok so I did my best but I accept that some calls to this will be for shit like sound and images From 535dc67a3dd0a84afc61c77c90f84162a3373b37 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 8 Jun 2017 09:25:35 -0400 Subject: [PATCH 39/47] Fixes badass syndie --- code/game/gamemodes/traitor/traitor.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 58c1c2fc6d6..fe45b583660 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -123,7 +123,8 @@ if(uplink_true) text += " (used [TC_uses] TC) [purchases]" if(TC_uses==0 && traitorwin) - text += "" + var/static/icon/badass = icon('icons/BadAss.dmi', "badass") + text += "[bicon(badass)]" text += objectives From d5ed64f0051b120ef0f6feb2fb81dc7c4c6737b8 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 8 Jun 2017 12:11:01 -0400 Subject: [PATCH 40/47] Fixes the bug!!!! --- code/datums/browser.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 62a005b5d96..17b1060e7bc 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -111,7 +111,10 @@ break /datum/browser/proc/close() - user << browse(null, "window=[window_id]") + if(!isnull(window_id)) //null check because this can potentially nuke goonchat + user << browse(null, "window=[window_id]") + else + WARNING("Browser [title] tried to close with a null ID") /datum/browser/alert var/selectedbutton = 0 From ad4e8d5cebca98a0c7866f0db192277c54bcb5da Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 8 Jun 2017 12:17:18 -0400 Subject: [PATCH 41/47] Sanity check open --- code/datums/browser.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 17b1060e7bc..686757077c2 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -92,6 +92,10 @@ "} /datum/browser/proc/open(use_onclose = 1) + if(isnull(window_id)) //null check because this can potentially nuke goonchat + WARNING("Browser [title] tried to open with a null ID") + to_chat(user, "The [title] browser you tried to open failed a sanity check! Please report this on github!" + return var/window_size = "" if (width && height) window_size = "size=[width]x[height];" From b6538c50e25c8c01eedff97d13292ed9c5830cf3 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 8 Jun 2017 12:52:25 -0400 Subject: [PATCH 42/47] Fixes, css, removes changefont --- code/datums/browser.dm | 4 +- .../browserassets/css/browserOutput.css | 84 +++++++++++-------- .../browserassets/html/browserOutput.html | 1 - interface/stylesheet.dm | 8 ++ 4 files changed, 59 insertions(+), 38 deletions(-) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 686757077c2..c854d20f18f 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -94,7 +94,7 @@ /datum/browser/proc/open(use_onclose = 1) if(isnull(window_id)) //null check because this can potentially nuke goonchat WARNING("Browser [title] tried to open with a null ID") - to_chat(user, "The [title] browser you tried to open failed a sanity check! Please report this on github!" + to_chat(user, "The [title] browser you tried to open failed a sanity check! Please report this on github!") return var/window_size = "" if (width && height) @@ -115,7 +115,7 @@ break /datum/browser/proc/close() - if(!isnull(window_id)) //null check because this can potentially nuke goonchat + if(!isnull(window_id))//null check because this can potentially nuke goonchat user << browse(null, "window=[window_id]") else WARNING("Browser [title] tried to close with a null ID") diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index 383b9b58ca6..ffd81b6a5d6 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -231,37 +231,44 @@ h1.alert, h2.alert {color: #000000;} em {font-style: normal; font-weight: bold;} +'.ooc { font-weight: bold;} .adminobserverooc {color: #0099cc; font-weight: bold;} -.adminooc {color: #b82e00; font-weight: bold;} +.adminooc {color: #700038; font-weight: bold;} + .adminobserver {color: #996600; font-weight: bold;} .admin {color: #386aff; font-weight: bold;} -/* SAY CLASSES */ + +.name { font-weight: bold;} + .say {} .deadsay {color: #5c00e6;} -.siliconsay {font-family: 'Courier New', Courier, monospace;} -/* RADIO CLASSES */ .radio {color: #008000;} - -.syndradio {color: #6d3f40;} -.centradio {color: #686868;} - -.aiprivradio {color: #ff00ff;} -.comradio {color: #948f02;} - -.secradio {color: #a30000;} -.engradio {color: #fb5613;} -.medradio {color: #337296;} .sciradio {color: #993399;} +.comradio {color: #948f02;} +.secradio {color: #a30000;} +.medradio {color: #337296;} +.engradio {color: #fb5613;} .suppradio {color: #a8732b;} .servradio {color: #6eaa2c;} +.syndradio {color: #6d3f40;} +.centcomradio {color: #686868;} +.aiprivradio {color: #ff00ff;} +.redteamradio {color: #ff0000;} +.blueteamradio {color: #0000ff;} + +.yell { font-weight: bold;} + +.alert {color: #ff0000;} +h1.alert, h2.alert {color: #000000;} + +.emote { font-style: italic;} +.selecteddna {color: #ffffff; background-color: #001B1B} .attack {color: #ff0000;} .disarm {color: #990000;} .passive {color: #660000;} -.selecteddna {color: #ffffff; background-color: #001B1B} -.alert {color: #ff0000;} -.userdanger {color: #ff0000; font-weight: bold; font-size: 3;} +.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;} .danger {color: #ff0000;} .warning {color: #ff0000; font-style: italic;} .boldwarning {color: #ff0000; font-style: italic; font-weight: bold} @@ -273,16 +280,17 @@ em {font-style: normal; font-weight: bold;} .notice {color: #000099;} .boldnotice {color: #000099; font-weight: bold;} .adminnotice {color: #0000ff;} +.adminhelp {color: #ff0000; font-weight: bold;} .unconscious {color: #0000ff; font-weight: bold;} .suicide {color: #ff5050; font-style: italic;} .green {color: #03ff39;} .shadowling {color: #3b2769;} .cult {color: #960000;} .cultitalic {color: #960000; font-style: italic;} -.cultlarge {color: #960000; font-weight: bold; font-size: 3;} -.narsie {color: #960000; font-weight: bold; font-size: 125px;} -.narsiesmall {color: #960000; font-weight: bold; font-size: 6;} -.colossus {color: #7F282A; font-size: 5;} +.cultlarge {color: #960000; font-weight: bold; font-size: 24px;} +.narsie {color: #960000; font-weight: bold; font-size: 120px;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;} +.colossus {color: #7F282A; font-size: 40px;} .hierophant {color: #660099; font-weight: bold; font-style: italic;} .hierophant_warning {color: #660099; font-style: italic;} .purple {color: #5e2d79;} @@ -291,37 +299,37 @@ em {font-style: normal; font-weight: bold;} .revennotice {color: #1d2953;} .revenboldnotice {color: #1d2953; font-weight: bold;} -.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;} +.revenbignotice {color: #1d2953; font-weight: bold; font-size: 24px;} .revenminor {color: #823abb} .revenwarning {color: #760fbb; font-style: italic;} -.revendanger {color: #760fbb; font-weight: bold; font-size: 3;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;} .umbra {color: #5000A0;} .umbra_bold {color: #5000A0; font-weight: bold;} .umbra_italics {color: #5000A0; font-style: italic;} .umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} -.umbra_large {color: #5000A0; font-size: 3;} +.umbra_large {color: #5000A0; font-size: 24px;} .brass {color: #BE8700;} .heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;} -.large_brass {color: #BE8700; font-size: 3;} -.big_brass {color: #BE8700; font-size: 3; font-weight: bold; font-style: italic;} -.ratvar {color: #BE8700; font-size: 6; font-weight: bold; font-style: italic;} +.large_brass {color: #BE8700; font-size: 24px;} +.big_brass {color: #BE8700; font-size: 24px; font-weight: bold; font-style: italic;} +.ratvar {color: #BE8700; font-size: 48px; font-weight: bold; font-style: italic;} .alloy {color: #42474D;} .heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;} -.large_alloy {color: #42474D; font-size: 3;} -.nezbere_large {color: #42474D; font-size: 3; font-weight: bold; font-style: italic;} +.large_alloy {color: #42474D; font-size: 24px;} +.nezbere_large {color: #42474D; font-size: 24px; font-weight: bold; font-style: italic;} .nezbere {color: #42474D; font-weight: bold; font-style: italic;} .nezbere_small {color: #42474D;} -.sevtug_large {color: #AF0AAF; font-size: 3; font-weight: bold; font-style: italic;} +.sevtug_large {color: #AF0AAF; font-size: 24px; font-weight: bold; font-style: italic;} .sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;} .sevtug_small {color: #AF0AAF;} -.inathneq_large {color: #1E8CE1; font-size: 3; font-weight: bold; font-style: italic;} +.inathneq_large {color: #1E8CE1; font-size: 24px; font-weight: bold; font-style: italic;} .inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;} .inathneq_small {color: #1E8CE1;} -.nzcrentr_large {color: #DAAA18; font-size: 3; font-weight: bold; font-style: italic;} +.nzcrentr_large {color: #DAAA18; font-size: 24px; font-weight: bold; font-style: italic;} .nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;} .nzcrentr_small {color: #DAAA18;} -.neovgre_large {color: #6E001A; font-size: 3; font-weight: bold; font-style: italic;} +.neovgre_large {color: #6E001A; font-size: 24px; font-weight: bold; font-style: italic;} .neovgre {color: #6E001A; font-weight: bold; font-style: italic;} .neovgre_small {color: #6E001A;} @@ -340,18 +348,24 @@ em {font-style: normal; font-weight: bold;} .papyrus {font-family: "Papyrus", cursive, sans-serif;} .robot {font-family: "Courier New", cursive, sans-serif;} -.command_headset {font-weight: bold; font-size: 3;} +.command_headset {font-weight: bold; font-size: 24px;} .big {font-size: 3;} .reallybig {font-size: 4;} .greentext {color: #00FF00; font-size: 3;} .redtext {color: #FF0000; font-size: 3;} .clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} +.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} -big img.icon {width: 32px; height: 32px;} +BIG IMG.icon {width: 32px; height: 32px;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 2;} .abductor {color: #800080; font-style: italic;} +.slime {color: #00CED1;} +.drone {color: #848482;} +.monkey {color: #975032;} +.swarmer {color: #2C75FF;} +.resonate {color: #298F85;} .connectionClosed, .fatalError {background: red; color: white; padding: 5px;} .connectionClosed.restored {background: green;} diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html index ea32f79da11..f55e69ecd17 100644 --- a/code/modules/goonchat/browserassets/html/browserOutput.html +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -32,7 +32,6 @@
Decrease font size - Increase font size + - Change font Toggle ping display Highlight string Save chat log diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index 10c39a2eb82..2022db1586b 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -1,3 +1,11 @@ +/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +/// !!!!!!!!!!HEY LISTEN!!!!!!!!!!!!!!!!!!!!!!!! +/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// If you modify this file you ALSO need to modify code/modules/goonchat/browserAssets/browserOutput.css +// BUT you have to use PX font sizes with are on a x8 scale of these font sizes +// Sample font-size: DM: 8 CSS: 64px + /client/script = {"