· 10 years ago · Sep 21, 2016, 08:50 PM
1// ==UserScript==
2// @name Overlay + Thèmes
3// @version 2.8.7
4// @description Utilitaire pour Bombparty + Overlay
5// @icon https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/icon.png
6// @icon64 https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/icon64.png
7// @downloadURL https://dl.dropboxusercontent.com/s/lduiww39c6rr5ym/OverlayAvecTheme.user.js
8// @author MrInanimated & Macadelic
9// @match http://bombparty.sparklinlabs.com/play/*
10// @resource twitch_global https://dl.dropboxusercontent.com/s/v3pwhew8apgtf18/global.json
11// @resource twitch_subscriber https://dl.dropboxusercontent.com/s/wdlo8pvpnpv6cmf/subscriber.json
12// @resource ffz_emotes https://dl.dropboxusercontent.com/s/e5bgmf8g12afppe/api.frankerfacez
13// @resource autoScrollOn https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/chatdown.png
14// @resource autoScrollOff https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/chatdownoff.png
15// @resource autoFocusOn https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/focusOn.png
16// @resource autoFocusOff https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/focusOff.png
17// @resource dragOff https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/dragOff.png
18// @resource dragOn https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/dragOn.png
19// @resource hideDeadOn https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/hideDeadOn.png
20// @resource hideDeadOff https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/hideDeadOff.png
21// @resource contextMenuPlugin https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/contextmenu.js
22// @resource contextMenuPluginCSS https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/dist/contextmenu.css
23// @grant GM_getResourceText
24// @grant GM_getResourceURL
25// @grant GM_getValue
26// @grant GM_setValue
27// @grant GM_xmlhttpRequest
28// ==/UserScript==
29
30//@require is not allowed under chrome (according to stackoverflow) and other suggested solutions have yet to work for me
31// a function that loads jQuery and calls a callback function when jQuery has finished loading
32function addJQuery(callback) {
33 var script = document.createElement("script");
34 script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js");
35 script.addEventListener('load', function() {
36 var script = document.createElement("script");
37 script.textContent = "window.jQ=jQuery.noConflict(true);(" + callback.toString() + ")();";
38 document.body.appendChild(script);
39
40 // Load the context menu plugin stuff
41 // This is a pretty simple task to require a whole plugin for, but I want to futureproof for now
42 var script = document.createElement("script");
43 script.textContent = "(function(jQuery){" + GM_getResourceText("contextMenuPlugin") + ";})(jQ);";
44 document.body.appendChild(script);
45
46 var css = document.createElement("style");
47 css.textContent = GM_getResourceText("contextMenuPluginCSS");
48 document.head.appendChild(css);
49 }, false);
50 document.body.appendChild(script);
51}
52
53// load jQuery and execute the main function
54addJQuery(function () {});
55
56// JSON Parser, by Douglas Crockford
57// This is necessary because in this environment I don't have access to the JSON object
58var json_parse=function(){"use strict";var e,t,n={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:" "},r,i=function(t){throw{name:"SyntaxError",message:t,at:e,text:r}},s=function(n){if(n&&n!==t){i("Expected '"+n+"' instead of '"+t+"'")}t=r.charAt(e);e+=1;return t},o=function(){var e,n="";if(t==="-"){n="-";s("-")}while(t>="0"&&t<="9"){n+=t;s()}if(t==="."){n+=".";while(s()&&t>="0"&&t<="9"){n+=t}}if(t==="e"||t==="E"){n+=t;s();if(t==="-"||t==="+"){n+=t;s()}while(t>="0"&&t<="9"){n+=t;s()}}e=+n;if(!isFinite(e)){i("Bad number")}else{return e}},u=function(){var e,r,o="",u;if(t==='"'){while(s()){if(t==='"'){s();return o}if(t==="\\"){s();if(t==="u"){u=0;for(r=0;r<4;r+=1){e=parseInt(s(),16);if(!isFinite(e)){break}u=u*16+e}o+=String.fromCharCode(u)}else if(typeof n[t]==="string"){o+=n[t]}else{break}}else{o+=t}}}i("Bad string")},a=function(){while(t&&t<=" "){s()}},f=function(){switch(t){case"t":s("t");s("r");s("u");s("e");return true;case"f":s("f");s("a");s("l");s("s");s("e");return false;case"n":s("n");s("u");s("l");s("l");return null}i("Unexpected '"+t+"'")},l,c=function(){var e=[];if(t==="["){s("[");a();if(t==="]"){s("]");return e}while(t){e.push(l());a();if(t==="]"){s("]");return e}s(",");a()}}i("Bad array")},h=function(){var e,n={};if(t==="{"){s("{");a();if(t==="}"){s("}");return n}while(t){e=u();a();s(":");if(Object.hasOwnProperty.call(n,e)){i('Duplicate key "'+e+'"')}n[e]=l();a();if(t==="}"){s("}");return n}s(",");a()}}i("Bad object")};l=function(){a();switch(t){case"{":return h();case"[":return c();case'"':return u();case"-":return o();default:return t>="0"&&t<="9"?o():f()}};return function(n,s){var o;r=n;e=0;t=" ";o=l();a();if(t){i("Syntax error")}return typeof s==="function"?function u(e,t){var n,r,i=e[t];if(i&&typeof i==="object"){for(n in i){if(Object.prototype.hasOwnProperty.call(i,n)){r=u(i,n);if(r!==undefined){i[n]=r}else{delete i[n]}}}}return s.call(e,t,i)}({"":o},""):o}}()
59
60var loadJSON = function (resourceName, variableName) {
61 var resource = "undefined";
62 try {
63 resource = GM_getResourceText(resourceName);
64 json_parse(resource);
65 }
66 catch (e) {
67 console.log("Error loading " + resourceName);
68 resource = "undefined";
69 }
70 finally {
71 var script = document.createElement("script");
72 script.setAttribute("type", "application/javascript");
73 script.textContent = "var " + variableName + " = " + resource + ";";
74 document.body.appendChild(script);
75 document.body.removeChild(script);
76 }
77}
78
79loadJSON("twitch_global", "twitch_global");
80loadJSON("twitch_subscriber", "twitch_subscriber");
81loadJSON("ffz_emotes", "ffz_emotes");
82
83var te = document.createElement('script');
84te.setAttribute("type", "application/javascript");
85te.textContent = 'var bpImgUrls = {' +
86 'autoScrollOn : "' + GM_getResourceURL("autoScrollOn") + '",' +
87 'autoScrollOff : "' + GM_getResourceURL("autoScrollOff") + '",' +
88 'autoFocusOn : "' + GM_getResourceURL("autoFocusOn") + '",' +
89 'autoFocusOff : "' + GM_getResourceURL("autoFocusOff") + '",' +
90 'dragOff : "' + GM_getResourceURL("dragOff") + '",' +
91 'dragOn : "' + GM_getResourceURL("dragOn") + '",' +
92 'hideDeadOn : "' + GM_getResourceURL("hideDeadOn") + '",' +
93 'hideDeadOff : "' + GM_getResourceURL("hideDeadOff") + '",' +
94'};';
95document.body.appendChild(te);
96document.body.removeChild(te);
97
98// All the code written within this function RUNS WITHIN THE SCOPE OF THE PAGE.
99// Everything outside it do NOT have access to environment variables.
100var source = function() {
101 // If the window already has a BPOverlay, don't run again
102 if (window.hasOwnProperty('BPOverlayHasRun')) {} else {
103 window.BPOverlayHasRun = true;
104
105 var main = function() {
106
107 // Since this is running via a script loaded on page load, it's difficult ensure the overlay runs after everything has loaded
108 // This piece of code makes sure that all relevant things are loaded before executing the rest of the code
109 // We may need to add more to this long-ass if statement if we add more features in the future
110 if (!(window.hasOwnProperty("channel") && channel.socket && channel.data && channel.appendToChat && channel.socket.listeners("chatMessage").length && channel.socket.listeners("setActivePlayerIndex").length && channel.socket.listeners("winWord").length && channel.socket.listeners("setPlayerLives").length && channel.socket.listeners("setPlayerState").length && channel.socket.listeners("endGame").length && window.hasOwnProperty("JST") && JST["nuclearnode/chatMessage"] && document.getElementById("Sidebar") && document.getElementById("ChatLog") && window.jQ)) {
111 console.log("Everything's not loaded yet, trying again in a second...");
112 setTimeout(main, 1000);
113 return;
114 }
115
116 /*!
117 * Autolinker.js
118 * 0.15.0
119 *
120 * Copyright(c) 2014 Gregory Jacobs <greg@greg-jacobs.com>
121 * MIT Licensed. http://www.opensource.org/licenses/mit-license.php
122 *
123 * https://github.com/gregjacobs/Autolinker.js
124 */
125 !function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.returnExportsGlobal=b()}):"object"==typeof exports?module.exports=b():a.Autolinker=b()}(this,function(){var a=function(b){a.Util.assign(this,b),this.matchValidator=new a.MatchValidator};return a.prototype={constructor:a,urls:!0,email:!0,twitter:!0,newWindow:!0,stripPrefix:!0,className:"",htmlCharacterEntitiesRegex:/( | |<|<|>|>)/gi,matcherRegex:function(){var a=/(^|[^\w])@(\w{1,15})/,b=/(?:[\-;:&=\+\$,\w\.]+@)/,c=/(?:[A-Za-z][-.+A-Za-z0-9]+:(?![A-Za-z][-.+A-Za-z0-9]+:\/\/)(?!\d+\/?)(?:\/\/)?)/,d=/(?:www\.)/,e=/[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/,f=/\.(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/,g=/[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]?!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]]/;return new RegExp(["(",a.source,")","|","(",b.source,e.source,f.source,")","|","(","(?:","(",c.source,e.source,")","|","(?:","(.?//)?",d.source,e.source,")","|","(?:","(.?//)?",e.source,f.source,")",")","(?:"+g.source+")?",")"].join(""),"gi")}(),charBeforeProtocolRelMatchRegex:/^(.)?\/\//,link:function(b){var c=this,d=this.getHtmlParser(),e=this.htmlCharacterEntitiesRegex,f=0,g=[];return d.parse(b,{processHtmlNode:function(a,b,c){"a"===b&&(c?f=Math.max(f-1,0):f++),g.push(a)},processTextNode:function(b){if(0===f)for(var d=a.Util.splitAndCapture(b,e),h=0,i=d.length;i>h;h++){var j=d[h],k=c.processTextNode(j);g.push(k)}else g.push(b)}}),g.join("")},getHtmlParser:function(){var b=this.htmlParser;return b||(b=this.htmlParser=new a.HtmlParser),b},getTagBuilder:function(){var b=this.tagBuilder;return b||(b=this.tagBuilder=new a.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),b},processTextNode:function(a){var b=this;return a.replace(this.matcherRegex,function(a,c,d,e,f,g,h,i,j){var k=b.processCandidateMatch(a,c,d,e,f,g,h,i,j);if(k){var l=b.createMatchReturnVal(k.match,k.matchStr);return k.prefixStr+l+k.suffixStr}return a})},processCandidateMatch:function(b,c,d,e,f,g,h,i,j){var k,l=i||j,m="",n="";if(c&&!this.twitter||f&&!this.email||g&&!this.urls||!this.matchValidator.isValidMatch(g,h,l))return null;if(this.matchHasUnbalancedClosingParen(b)&&(b=b.substr(0,b.length-1),n=")"),f)k=new a.match.Email({matchedText:b,email:f});else if(c)d&&(m=d,b=b.slice(1)),k=new a.match.Twitter({matchedText:b,twitterHandle:e});else{if(l){var o=l.match(this.charBeforeProtocolRelMatchRegex)[1]||"";o&&(m=o,b=b.slice(1))}k=new a.match.Url({matchedText:b,url:b,protocolUrlMatch:!!h,protocolRelativeMatch:!!l,stripPrefix:this.stripPrefix})}return{prefixStr:m,suffixStr:n,matchStr:b,match:k}},matchHasUnbalancedClosingParen:function(a){var b=a.charAt(a.length-1);if(")"===b){var c=a.match(/\(/g),d=a.match(/\)/g),e=c&&c.length||0,f=d&&d.length||0;if(f>e)return!0}return!1},createMatchReturnVal:function(b,c){var d;if(this.replaceFn&&(d=this.replaceFn.call(this,this,b)),"string"==typeof d)return d;if(d===!1)return c;if(d instanceof a.HtmlTag)return d.toString();var e=this.getTagBuilder(),f=e.build(b);return f.toString()}},a.link=function(b,c){var d=new a(c);return d.link(b)},a.match={},a.Util={abstractMethod:function(){throw"abstract"},assign:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},extend:function(b,c){var d=b.prototype,e=function(){};e.prototype=d;var f;f=c.hasOwnProperty("constructor")?c.constructor:function(){d.constructor.apply(this,arguments)};var g=f.prototype=new e;return g.constructor=f,g.superclass=d,delete c.constructor,a.Util.assign(g,c),f},ellipsis:function(a,b,c){return a.length>b&&(c=null==c?"..":c,a=a.substring(0,b-c.length)+c),a},indexOf:function(a,b){if(Array.prototype.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},splitAndCapture:function(a,b){if(!b.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var c,d=[],e=0;c=b.exec(a);)d.push(a.substring(e,c.index)),d.push(c[0]),e=c.index+c[0].length;return d.push(a.substring(e)),d}},a.HtmlParser=a.Util.extend(Object,{htmlRegex:function(){var a=/[0-9a-zA-Z][0-9a-zA-Z:]*/,b=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,c=/(?:".*?"|'.*?'|[^'"=<>`\s]+)/,d=b.source+"(?:\\s*=\\s*"+c.source+")?";return new RegExp(["(?:","<(!DOCTYPE)","(?:","\\s+","(?:",d,"|",c.source+")",")*",">",")","|","(?:","<(/)?","("+a.source+")","(?:","\\s+",d,")*","\\s*/?",">",")"].join(""),"gi")}(),parse:function(a,b){b=b||{};for(var c,d=b.processHtmlNode||function(){},e=b.processTextNode||function(){},f=this.htmlRegex,g=0;null!==(c=f.exec(a));){var h=c[0],i=c[1]||c[3],j=!!c[2],k=a.substring(g,c.index);k&&e(k),d(h,i.toLowerCase(),j),g=c.index+h.length}if(g<a.length){var l=a.substring(g);l&&e(l)}}}),a.HtmlTag=a.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(b){a.Util.assign(this,b),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(a){return this.tagName=a,this},getTagName:function(){return this.tagName||""},setAttr:function(a,b){var c=this.getAttrs();return c[a]=b,this},getAttr:function(a){return this.getAttrs()[a]},setAttrs:function(b){var c=this.getAttrs();return a.Util.assign(c,b),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(a){return this.setAttr("class",a)},addClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);c=h.shift();)-1===f(g,c)&&g.push(c);return this.getAttrs()["class"]=g.join(" "),this},removeClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);g.length&&(c=h.shift());){var i=f(g,c);-1!==i&&g.splice(i,1)}return this.getAttrs()["class"]=g.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(a){return-1!==(" "+this.getClass()+" ").indexOf(" "+a+" ")},setInnerHtml:function(a){return this.innerHtml=a,this},getInnerHtml:function(){return this.innerHtml||""},toString:function(){var a=this.getTagName(),b=this.buildAttrsStr();return b=b?" "+b:"",["<",a,b,">",this.getInnerHtml(),"</",a,">"].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var a=this.getAttrs(),b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c+'="'+a[c]+'"');return b.join(" ")}}),a.MatchValidator=a.Util.extend(Object,{invalidProtocolRelMatchRegex:/^[\w]\/\//,hasFullProtocolRegex:/^[A-Za-z][-.+A-Za-z0-9]+:\/\//,uriSchemeRegex:/^[A-Za-z][-.+A-Za-z0-9]+:/,hasWordCharAfterProtocolRegex:/:[^\s]*?[A-Za-z]/,isValidMatch:function(a,b,c){return b&&!this.isValidUriScheme(b)||this.urlMatchDoesNotHaveProtocolOrDot(a,b)||this.urlMatchDoesNotHaveAtLeastOneWordChar(a,b)||this.isInvalidProtocolRelativeMatch(c)?!1:!0},isValidUriScheme:function(a){var b=a.match(this.uriSchemeRegex)[0];return"javascript:"!==b&&"vbscript:"!==b},urlMatchDoesNotHaveProtocolOrDot:function(a,b){return!(!a||b&&this.hasFullProtocolRegex.test(b)||-1!==a.indexOf("."))},urlMatchDoesNotHaveAtLeastOneWordChar:function(a,b){return a&&b?!this.hasWordCharAfterProtocolRegex.test(a):!1},isInvalidProtocolRelativeMatch:function(a){return!!a&&this.invalidProtocolRelMatchRegex.test(a)}}),a.AnchorTagBuilder=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},build:function(b){var c=new a.HtmlTag({tagName:"a",attrs:this.createAttrs(b.getType(),b.getAnchorHref()),innerHtml:this.processAnchorText(b.getAnchorText())});return c},createAttrs:function(a,b){var c={href:b},d=this.createCssClass(a);return d&&(c["class"]=d),this.newWindow&&(c.target="_blank"),c},createCssClass:function(a){var b=this.className;return b?b+" "+b+"-"+a:""},processAnchorText:function(a){return a=this.doTruncate(a)},doTruncate:function(b){return a.Util.ellipsis(b,this.truncate||Number.POSITIVE_INFINITY)}}),a.match.Match=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},getType:a.Util.abstractMethod,getMatchedText:function(){return this.matchedText},getAnchorHref:a.Util.abstractMethod,getAnchorText:a.Util.abstractMethod}),a.match.Email=a.Util.extend(a.match.Match,{getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),a.match.Twitter=a.Util.extend(a.match.Match,{getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),a.match.Url=a.Util.extend(a.match.Match,{urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,protocolPrepended:!1,getType:function(){return"url"},getUrl:function(){var a=this.url;return this.protocolRelativeMatch||this.protocolUrlMatch||this.protocolPrepended||(a=this.url="http://"+a,this.protocolPrepended=!0),a},getAnchorHref:function(){var a=this.getUrl();return a.replace(/&/g,"&")},getAnchorText:function(){var a=this.getUrl();return this.protocolRelativeMatch&&(a=this.stripProtocolRelativePrefix(a)),this.stripPrefix&&(a=this.stripUrlPrefix(a)),a=this.removeTrailingSlash(a)},stripUrlPrefix:function(a){return a.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(a){return a.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(a){return"/"===a.charAt(a.length-1)&&(a=a.slice(0,-1)),a}}),a});
126
127 // Let's write an additional thing for multi-language text strings!
128 // I kinda wanted to call this i18n, but that's taken
129 var tran = {
130 strings: {
131 fr: {
132 timeText: "Temps Écoulé : ",
133 wordCountText: "Nombre de Mots : ",
134 showHideButtonTitle: "Afficher/Masquer les joueurs morts.",
135 flipsText: "V.R.",
136 flipsTitle: "Vies récupérées en utilisant toutes les lettres bonus",
137 uFlipsText: "V.R.I.",
138 uFlipsTitle: "Vies récupérées inutiles : vies récupérées tandis qu'on en possède trois, ce qui les rend \"inutiles\"",
139 deathsText: "Morts",
140 deathsTitle: "Vies perdues dans cette partie",
141 alphaText: "Alpha",
142 alphaTitle: "La lettre à laquelle ce joueur serait si il jouait en mode alphabet. (Le chiffre entre parenthèses est le nombre de fois où il a complété l'alphabet)",
143 wordsText: "Mots",
144 wordsTitle: "Le nombre total de mots utilsés par ce joueur",
145 playersTitle: "Joueurs :",
146 chatDownButtonTitle: "Forcer le tchat à défiler vers le bas quand il y a un nouveau message.",
147 autoFocusButtonTitle: "Positionner automatiquement le curseur sur le tchat après son tour",
148 dragButtonTitle: "Détacher le tableau des scores.",
149 overlaySettingsButtonTitle: "Paramètres de l'Overlay",
150 overlaySettingsText: "Paramètres",
151 notificationsText: "Notifications",
152 themeH2Text: "Thèmes",
153 easterText: "Easter eggs",
154 chatOpText: "Paramètres du Tchat",
155 playerListText: "Joueurs connectés",
156 creditsText: "Crédits",
157 credits1: "Code Monkey",
158 credits2: "Code Amoeba",
159 credits3: "Traduction",
160 creditsContextMenu: "Menu Contextuel",
161 creditsAutolinker: "Liens automatiques",
162 creditsTwitchEmotes: "Emoticones Twitch",
163 smileyContext: "Liste des smileys",
164 creditsTextText: "2.8.7",
165 containerSizeName: "Taille du tableau",
166 containerSizeOptions: {
167 compact: "Compacte",
168 fitToPlayers: "Ajustée selon les joueurs",
169 },
170 twitchEmotesName: "Emoticones Twitch",
171 twitchEmotesOptions: {
172 on: "Marche",
173 off: "Arrêt",
174 },
175 textAdventureName: "Text Adventure<sup>BETA</sup>",
176 textAdventureName: "Text Adventure<sup>BETA</sup>",
177 textAdventureOptions: {
178 on: "Marche",
179 off: "Arrêt",
180 },
181 hardModesName: "Difficultés supplémentaires",
182 hardModesOptions: {
183 none: "Aucune",
184 rev: "Inversé",
185 jqv: "J/Q/V",
186 az: "Alphabet",
187 xz: "X/Z",
188 kwxyz: "Mode Fils De Pute #NikLalfa",
189 },
190 themeName: "Thème<sup>BETA</sup>",
191 themeOptions: {
192 none: "Aucun",
193 xmas: "Noël",
194 blacktree: "Arbre Noir",
195 purpletree: "Arbre Violet",
196 radio: "Radio (Bleu et noir)",
197 simple: "Simple (Blanc et noir)",
198 sunset: "Couché de soleil",
199 juan: "Thème de Juan",
200 pingu: "Thème de Pingu",
201 loutes: "Thème de Loutestoland",
202 leonarda: "Leonarda",
203 lisa: "Thème de Lisa",
204 caro: "Thème de Caro (Doritos)",
205 custom: "Personnalisé",
206 },
207 customThemeName: "Thème Personnalisé",
208 particlesName: "Particules",
209 particlesOptions: {
210 high: "Elevé",
211 low: "Faible",
212 off: "Désactivé",
213 },
214 notificationsName: "Notifications",
215 notificationVolume: "Volume de Notification",
216 notificationOptions: {
217 on: "Activé",
218 off: "Désactivé",
219 },
220 notificationAlias: "Pseudonymes",
221 notificationAliasTitle: "Noms personnalisés qui déclenchent également une notification.",
222 notificationAliasInputTitle: "Ecrivez vos noms l'un après l'autre, séparés par un point virgule. Par ex. MrInanimated;Inanimated;Animé;Inan",
223 endGameNotification: "Avertit quand une partie se termine",
224 endGameNotificationOptions: {
225 on: "Activé",
226 off: "Désactivé",
227 },
228 alphaRouletteName: "Affichage Mode Alphabet",
229 alphaRouletteOptions: {
230 on: "Activé",
231 off: "Désactivé",
232 },
233 wordCounterName: "Affichage Compteur de Mots",
234 wordCounterOptions: {
235 on: "Activé",
236 off: "Désactivé",
237 },
238 muted: "(muted)",
239 muteUser: "Ignorer",
240 unmuteUser: "Autoriser",
241 areYouSure: "Êtes-vous sûr ?",
242 ignoringText: "Utilisateurs ignorés",
243 ignoringEmpty: "Personne n'est ignoré actuellement.",
244 scoreName: "Score Classement",
245 scoreOption: {
246 on: "Activé",
247 off: "Désactivé",
248 },
249 jqvText: "Ce mot ne contient ni J, ni V, ni Q.",
250 azText: "Au tour de la lettre {l} Kappa !",
251 xzText: "Ce mot ne contient ni X, ni Z !",
252 kwxyzText: "Où tu vois un K, W, X, Y ou un Z ? --'",
253 speechName: "Vocale sur Chrome<sup>BETA</sup>",
254 speechOptions: {
255 on: "Activé",
256 off: "Désactivé",
257 },
258 voiceSelect: "Voix",
259 voiceOptions: {
260 us: "US",
261 ukMale: "GB Homme",
262 ukFem: "GB Femme",
263 fran: "FR",
264 },
265 twitchEmoteError: "Erreur : Les émoticones Twitch n'ont pas été chargées.",
266 updateText: "2.8.7| Nouvelle liste des smileys => https://dl.dropboxusercontent.com/s/l9wk9tad765b9xs/SmileyOverlay.html Snoop Bouncy",
267 },
268 },
269 language: (document.cookie.indexOf("i18next=fr") !== -1 ? "fr" : "en"),
270 fallback: "en",
271 t: function (accessor) {
272 var rStr;
273
274 try {
275 if ((rStr = eval("this.strings." + this.language + "." + accessor)) !== undefined) {
276 return rStr;
277 }
278 }
279 catch (e) {
280 if (!(e instanceof TypeError)) {
281 throw e;
282 }
283 }
284
285 try {
286 if ((rStr = eval("this.strings." + this.fallback + "." + accessor)) !== undefined) {
287 return rStr;
288 }
289 }
290 catch (e) {
291 if (!(e instanceof TypeError)) {
292 throw e;
293 }
294 }
295
296 return accessor;
297 },
298 };
299
300 // Tidy container for storing "global" variables.
301 bpOverlay = {
302 playerNames: {}, // Stores player name by actor index
303 playerScores: Array.apply(null, new Array(20)).map(Number.prototype.valueOf,0), // Stores player's score by actor index
304 playerAuthId: {}, // Stores actor index by authId
305 lostLives: {}, // Stores lost lives by actor index
306 flips: {}, // Stores flips by actor index
307 uFlips: {}, // Stores u-flips by actor index
308 alpha: {}, // Stores progress across the alphabet
309 words: {}, // Stores number of words used per player
310 wordCount: 0, // Stores word count for current round
311 startTime: 0, // Stores (in milliseconds since the epoch) the starting time of the round
312 timeText: "", // Stores the text used to display the time on the overlay
313
314 dragBoxHasBeenCreated: false, //Indicates that the dragbox is 4 real
315 boxHasBeenCreated: false, // True when a DOM object with the id "infoBox" exists
316 firstRun: true, // Set to true every time a game ends. If this is true a new infoBox is created, and this is set to false
317
318 prevPlayerNames: {}, // Stores player name by actor index
319 prevLostLives: {}, // Stores lost lives by actor index
320 prevFlips: {}, // Stores flips by actor index
321 prevUFlips: {}, // Stores u-flips by actor index
322 prevTimeText: "", // Stores the text used to display the time on the overlay
323 prevWordCount: 0, // Stores the word count for the last round
324
325 hideDead: false, // If true, hides dead players' rows on the scoreboard table
326 dragonDrop: false, // If true, indicates that the user has a wish to become or remain a dragon.
327 // dragBoxHasBeenCreated will not replace this
328
329 autoScroll: true, // If true, automatically scrolls that chat down whenever there is a new chat message.
330 autoFocus: true, // If true, automatically switches focus to the chatbox after the user's turn
331
332 focusNext: false, // If true, it is the user's turn (and so we should focus to the chatBox if autoFocus is true after the user's turn)
333
334 twitchOn: true, // If true, twitch emoticons will be displayed.
335
336 markupOn: true, // A dummy, nothing changes this setting just yet
337
338 adventureTextMode: false, //Self explanatory boolean for text adventure toggle
339
340 adventureFirstRun: false,
341 adventureLevels: ["Un putain de noob", "Un débutant", "Un novice", "Flipper", "Flipper expérimenté", "Flipper expert", "Flipper incroyable", "Flipper master", "Sur la voie de l'immortalité", "À demi-immortel", "Un putain d'immortel", "Un pd flipper", "Candidat potentiel au 'hang in there kitty'", "Un incommensurable pd flipper", "Trou de cul", "Une légende immortelle du flip", "Un énorme pd qui tourne plus qu'une toupie", "Pauvre merde, les flips c'est pour les petits", "PD Ultime", "PD Ultime (Élargissement Anal +5", "Si tu continues tu va avoir le trou de cul à ..", "T'es le plus gros fils de pute sur terre", "T'es toujours pas devenu un fils de pute après tout ces flips ?", "Une pute grandeur nature", "Aurélie version humaine", "Jésus jalouse", "Une putain de toupie", "Tu tournes plus que la mère à jordan", "Amateur de la cuisine salée", "Mëme Tsu à pas aimé", "Arrêter le!", "Comment tu fais pour être aussi b(l)b ?", "T'es un bon, t'es bon là ", "Yass sort de ce corps", "T chaud pour faire 7200 mots + alfa + reverse ?", "Plénipotentiaire en herbe", "L'abutyrotomofilogène en chair et en os", "Si tu continues tu va choper le pseudopseudohypoparathyroidisme", "Arrête de flipper fils de pute", "Le disciple de Georges Moustaki", "L'homme au mille et un coeur.. 40 enfaite", "Dieu de BombParty", "Inserer référence Douglas Adam, car 42 coeurs", "Un alpaga, t'es un putain d'alpaga", "Maintenant tu deviens une putain de girafe", "T'es chaud chaud Volcano !!", "omg c un dico '-'"],
342 //o babe jgo mangé pizza je t'aime bon app je t'aime re
343 //The alphabet variables for alphabet hard mode
344 alphabet: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"],
345 alphapos: 0,
346
347 isThemed: false, // Is the game currently themed
348 particleSpawnRate: "high",
349
350 alias: [],
351 notificationSound: new Audio("https://dl.dropboxusercontent.com/s/48mlffyfr0l500m/Iphone_SMS_Tone_Original%20%281%29.wav"),
352 notifications: true,
353
354 endGameNotification: false,
355
356 ignoring: {},
357
358 speechName: "Google UK English Male", //Default voice
359
360 //Letter scores based on the formula ((10 - (pure integer value of percentage))*3). floored at 1. Why this formula? Just because. :D
361 letterScore: { a: 5, b: 25, c: 21, d: 17, e: 1, f: 23, g: 24, h: 12, i: 9, j: 30, k:27, l:18, m:22, n:10, o:7, p:24, q:30, r:12, s:11, t:3, u:22, v:27, w:23, x:30, y:24, z:30},
362 scoreMode: false,
363
364 is_hidden: false,
365 };
366
367 // Store all the game images so they can be changed
368 gameImages = {};
369
370 window.addEventListener("blur", function () { bpOverlay.is_hidden = true; });
371 window.addEventListener("focus", function () { bpOverlay.is_hidden = false; });
372
373 // So, um, the code here is pretty distributed, but I'll explain the "hack" I've found here
374 // Elisee has *kindly* wrapped up all the images he used in a closure
375 // (I totally didn't spend about 3 hours hunting how to do this before finding this hack)
376 // Which means there's normally no way to get at those images and change them
377 // The one point of contact those variables have with the outside environment is the context.drawImage method
378 // So of course that's exploited.
379 // Now, not all the images will be sent to drawImage at once
380 // Hence the need for a missing game images list.
381 var missingGameImgs = [
382 "avatarShadow",
383 "heart",
384 "heartEmpty",
385 "arrow",
386 "bomb",
387 "sparkle",
388 "avatarPlaceHolder",
389 "letter",
390 ]
391
392 // Relacement src's go here
393 var replacementImages = {
394 };
395
396 // Replacement offsets go here
397 var replacementOffsets = {
398 };
399
400 // This is a backup of the original src's of the images
401 // So if ever need to flip back to the default
402 // We use the src's listed here
403 var backupSources = {
404 };
405
406 var canvasContext = document.getElementById("GameCanvas").getContext("2d");
407
408 // Adventure Mode Text formatter!
409 // Use this to have a pool of text messages to randomly choose from.
410
411 // USAGE:
412 // adventureTextFormat.chooseText(textBankName, *arguments)
413 // textBankName: the text bank you want to choose the text from.
414 // *arguments: The arguments you want to fill the empty spaces in your text with.
415 // (It's not tremendously clear what this does, but I'll try to explain it anyway)
416 // You provide it with a string like this:
417 // "The heroic, {0}, faces the mighty {1}."
418 // And then you call adventureTextFormat.chooseText($TextBankWhichTheStringAboveIsIn, "Pingu", "GOS")
419 // It returns "The heroic, Pingu, faces the mighty GOS."
420 // It replaces the numbers inside the braces with the relevant text supplied.
421 // You can have the numbers in any order, so:
422 // "A fierce {1} roars greatly at {0}!" -> "A fierce GOS roars greatly at Pingu!"
423 // You can miss out numbers all together, so:
424 // "{0} takes their stand against the foul beast." -> "Pingu takes their stand against the foul beast."
425
426 var adventureTextFormat = {
427 format: function(format, args) {
428 return format.replace(/{(\d+)}/g, function(match, number) {
429 return typeof args[number] != 'undefined' ? args[number] : match;
430 });
431 },
432
433 chooseText : function (textBankName) {
434 var args = Array.prototype.slice.call(arguments, 1);
435 var textBank = this.textBanks[textBankName];
436 var chosenString = textBank[Math.floor(Math.random() * textBank.length)];
437 return this.format(chosenString, args);
438 },
439
440 // These messages will be randomly selected.
441 // Note: I've never read Shakespeare. If you're a fan of his then you're not of this.
442 // You'd think that someone good with words would be good with sentences but it ain't so
443 textBanks : {
444 newRound : [
445 "Hark, the wheel turns yet again!",
446 "Lo and behold, a new round has cometh!",
447 "The crack of a new bomb, stand ready and begin the new day!",
448 "The whole bomb's a stage, and all the men and women merely nerds!",
449 "Give heed! The wordgrimage is set about, selectees!",
450 "With thine vocable, set forth and slay that which is fragmentary!",
451 "Words are swords, prompts be stomped!",
452 "Sticks and stones will break thy bones / And prompts will surely kill thee!",
453 ],
454 userTurn : [
455 "It is thy turn, squire. You are facing off against {0}. Do thine worst!",
456 "A vile horror seeks thee. What is thine plan for {0}?",
457 "Nay, {0} fixes to tender thine flame. Take action!",
458 "A wild {0} appears!",
459 "Shalt thou stand and accomplish nothing against {0}?",
460 "{0} is about to wound thee. Time for a curt attack!",
461 "Heedeth thou the mighty {0}! Distress or scuffle is forthcoming!",
462 "Art thou harefooted or harebrained! Observe, it is {0}!",
463 ],
464 playerTurn : [
465 "The heroic, {0}, faces the mighty {1}.",
466 "A ferocious roar as {1} corners {0}!",
467 "{0} needeth stand firm or be struck by {1}",
468 "{1} hath hunger who {0} might satisfy, lest!",
469 "{0} faces down the rat that is {1}!",
470 "{0} challenges the verminous {1}!",
471 "Behold the ravenous {1}! Will {0} succeed?",
472 "{0} versus {1}! The trepidation is palpable!",
473
474 ],
475 userLevelUp : [
476 "LEVEL UP: Thou art now {0}",
477 "UPLEVEL : Now thou art {0}",
478 "RISE SIR, AS '{0}'",
479 "YOU FIT A NEW TITLE: {0}",
480 "THOU HAST EVOLVED INTO {0}",
481 "EXPERIENCE MOLDS YOU INTO {0}",
482 "YOU FEEL STRONGER: You become '{0}'",
483 "REJOICE, YOU ARE: {0}",
484 ],
485 levelUp : [
486 "{0} levelled up to {1}",
487 "{0} has become {1}",
488 "{0} is now titled {1}",
489 "{0} has a new name: {1}",
490 "There is now a '{1}' among us",
491 "{0} is levelling up. What's your excuse, faggoth?",
492 "Out of his cocoon, {0} crawls like a majestic buttefly. How can I compare 'levelling up' to a summer's day?",
493 "{0} is evolving! Don't cream your pants, Pokémon faggots!",
494 ],
495 userWinWord : [
496 "Thou hast slain the beast with your {0} and gained {1} EXP!",
497 "The hellion shatters for thine knowledge is vast. A well deserved {1} EXP!",
498 "Smite triumphed over bite! The prompt is no more. You gain {1} EXP!",
499 "Twas foolish of the beast to underestimate you. You gain {1} EXP",
500 "By Jove, the miscreant is rend like a brittle biscuit from your wallop. I say, good show!",
501 "No mercy have thou for these ogres. Let {0} be a lesson. You gain {1} EXP",
502 "Blasted vermin recoil in fear at thine mighty {0}. {1} EXP to thee!",
503 "Idle barking is met with a firm {0}.",
504 ],
505 winWord : [
506 "{0} has killed the beast with the mighty shout {1} and gained {2} EXP!",
507 "{0} fears no ghosts. His guiding {1} has fled them from the shadows!",
508 "{1}, an apt warcry from {0} who gained {2} EXP!",
509 "{0} decimates the hoodlum with {1} and gains {2} EXP",
510 "{1}, and then the dragon is no more! {0} feels stronger by {2} points!",
511 "{0} delivers the final blow to the whale with his {1}!",
512 "{1} was {0}'s weapon of choice and he earns {2} EXP",
513 "{0} shows no mercy and swings his {1}!",
514 ],
515 userLostLife : [
516 "Thine ignorance woundeth and thou hast been hurt",
517 "Incompetent fool, you were lacerated by a mere rodent!",
518 "Thou areth assrapeth so fervently you lose heart!",
519 "If thy stuttereth again, thou shalt surely receive another blow such as this!",
520 "Nay, thou hast been set upon and crushed by that wild thing!",
521 "Is thy fighting as good as thy 'not-being-a-faggot' skill? Thine heart bleeds!",
522 "Thine tongue utters nothing and so thou art skewered like a pig! The agony!",
523 "Thou art badly contused by the assailing prompt. Man up or die, cutter!",
524 ],
525 lostLife : [
526 "Alas... for poor {0} hath been hurt",
527 "{0} has been struck to the ground!",
528 "{0} cries can be heard echoing through these halls!",
529 "{0} receives hefty damage!",
530 "The horror kill and goes forth to claim its next victim",
531 "Sacre bleu. Les monstrosite c'est trop. {0} ne pas victoirement!",
532 "Don't look. {0} was badly mauled!",
533 "Oh lord gawd. {0} got roughed up!",
534 "{0} was generously harmed!",
535 ],
536 userDeath : [
537 "and a grave loss for thou art dead. {0}, may thee rest in peace!",
538 "yet-th, thineth lifeth hateth endeth. Noth. Whyth?",
539 "but this is the end for you. Rest in pieces, sweet prince",
540 "however you face oblivion.",
541 "and thine life flasheth before thine eyes and thou realizes what a dead faggot thou art!",
542 "now you have left the realm of the living and enter the realm of spectators!",
543 "here, you expire like milk and smell like it too! Smelly dead {0}!",
544 "but bonk bonk you conk into the casket. The wonk was too stronk!",
545 ],
546 death : [
547 "and weepeth, thee morn, for {0} hath left yonder mortal coil!",
548 "{0} exits the stage!",
549 "{0} is snuffed like a candle",
550 "{0} is no more, like, jeez, got dun dead good!",
551 "meow meow meow 'COMPLETELY DEAD' meow meow '{0}'",
552 "{0} kicks the bucket, knocks it over and swallows shit!",
553 "{0}, oh, in the prime of his 'not being able to answer prompts like the faggot he is', is deceased!",
554 "{0}, bites the dust, goes the way of all flesh, gives up the ghost, drops off. You know what I mean",
555 ],
556 endRound : [
557 "All things must end and so it does with {0}!",
558 "The ordeal is over!",
559 "{0} was the death of all but one!",
560 "The seemingly unending wave of prompts comes to a halt!",
561 "Now, caged are the dogs of war!",
562 "And on that bombshell, {0}, we have to end!",
563 "Many have fallen! But not all!",
564 "Nothing lasts forever!, Yet...",
565
566 ],
567 winner : [
568 "Rising from the ashes of felled brethren is the victorious {0}!",
569 "A knight in tested armor, still breathing, the glorious {0}!",
570 "Praise be the heroic {0} for that human/otherkin/refridgerator has not be vanquished!",
571 "The surviving faggot was indeed {0}",
572 "Ahoyhoy and a hullo for the indissoluble {0}",
573 "Is it a bird? Is it a plane? Whatever it is, it's {0}",
574 "Doctors hate {0}! The secret doctors don't want you to know is \"don't be a scrub\"!",
575 "{0} the unending, the ceaseless, the permanent, the unfading; the sole survivor!",
576 ],
577 },
578 }
579
580
581 //I'm so proud of this ugly node constructor
582 //I'm certain it's unconventional, but it works so... yippee
583 //It allows for creating images as nodes within an object and
584 //defining attributes at the same time. LALALALALALALAL HAPPY HAPPY THIS
585 //TOOK SO LONG TO FIGURE OUT!!!! AAAAAH. I'M DUMB AND SMART
586
587 //USAGE: x = imNodeConstructor(type, attributes);
588 // 'type' is the type of element on the form document.createElement("whatever");
589 // 'attributes' are a list of attributes on the object form { att1: value1, att2: value2, ... , attN: valueN }
590 // Post: x is of the type "whatever" with the attributes att1, att2, ... , attN
591 var imgNodeConstructor = function(node, attributes) {
592 for (x in attributes) {
593 node[x] = attributes[x];
594 }
595 return node;
596 };
597
598 // Storage of images and their attributes used by the overlay.
599 bpOverlayImgs = {
600
601 //AutoScroll button on state
602 on: imgNodeConstructor(document.createElement("img"), {
603 width: 30,
604 height: 30,
605 src: bpImgUrls.autoScrollOn,
606 }),
607
608 //AutoScroll button off state
609 off: imgNodeConstructor(document.createElement("img"), {
610 width: 30,
611 height: 30,
612 src: bpImgUrls.autoScrollOff,
613 }),
614
615 //AutoFocus button on state
616 autoFocusOn: imgNodeConstructor(document.createElement("img"), {
617 width: 30,
618 height: 30,
619 src: bpImgUrls.autoFocusOn,
620 }),
621
622 //AutoFocus button off state
623 autoFocusOff: imgNodeConstructor(document.createElement("img"), {
624 width: 30,
625 height: 30,
626 src: bpImgUrls.autoFocusOff,
627 }),
628
629 //Dragon button off state
630 dragOff: imgNodeConstructor(document.createElement("img"), {
631 width: 30,
632 height: 30,
633 src: bpImgUrls.dragOff,
634 }),
635
636 //Dragon button on state
637 dragOn: imgNodeConstructor(document.createElement("img"), {
638 width: 30,
639 height: 30,
640 src: bpImgUrls.dragOn,
641 }),
642
643 //These buttons not constructed because they appear solidary and have already been coded with the old method
644 //No changes necessary unless we intend to add more buttons in the players window
645 hideDeadOn: null, // HideDead button on state
646 hideDeadOff: null, // HideDead button off state
647
648 };
649
650
651 //START - A collection of functions for the dragonDrop
652 //The functions basically name themselves and do what they're told
653 //They are then activated by listeneres when a)User starts dragging the 'draggable'
654 // b)User drags over to somewhere (not default behaviour of linkamajigging)
655 // c)User drops the box.
656
657 //window resize meow
658 window.onresize = resize;
659
660 //Called when browser is resized
661 function resize() {
662 //Let's patch this to do nothing if the box hasn't been created.
663 //Hooray for avoiding erors. HOORAY!
664 if(bpOverlay.dragboxHasBeenCreated) {
665 //Let's get the window size
666 var height = window.innerHeight,
667 width = window.innerWidth;
668
669 //Let's get the dragOn size
670 var infoBox = document.getElementById("infoBox");
671 var dragW = infoBox.clientWidth;
672 var dragH = infoBox.clientHeight;
673
674 //Let's get the dragOn... wrawrrr
675 var dragOn = document.getElementById("dragonDrop");
676
677 //... and his coordinates. Nifty. We can use parseInt direclty. directly*
678 var dragX = parseInt(dragOn.style.left);
679 var dragY = parseInt(dragOn.style.top);
680
681 //Resize widthwise
682 if(dragW + dragX > width) {
683 dragOn.style.left = width - dragW + 'px';
684 }
685
686 //Resize heightwise (also pushing it beyond check which isn't needed on the widthwise
687 if(dragY < 0) {
688 dragOn.style.top = "0px";
689 } else if (dragH + dragY > height) {
690 dragOn.style.top = height - dragH + 'px';
691 }
692 }
693 }
694
695 //a: establish the drag and the starting parameters
696 function drag_start(event) {
697 var style = window.getComputedStyle(event.target, null);
698 event.dataTransfer.setData("text/plain", (parseInt(style.getPropertyValue("left"), 10) - event.clientX) + ',' + (parseInt(style.getPropertyValue("top"), 10) - event.clientY));
699 }
700
701 //b: strange shit wont happen because things wont interact
702 // you can however act as if you're dropping the boxonto the ad and it will revert
703 // so this bug is now a feature: "CANNOT ADBLOCK BY DESIGN"
704 function drag_over(event) {
705 event.preventDefault();
706 return false;
707 }
708
709 //c: computes the offset from the drag and adds it to the style.top & style.left
710 function drop(event) {
711 var offset = event.dataTransfer.getData("text/plain").split(',');
712 var dm = document.getElementById('dragonDrop');
713 var addLeft = event.clientX + parseInt(offset[0], 10);
714 var addTop = event.clientY + parseInt(offset[1], 10);
715
716 //Let's see if we can prevent the jigger from flying offscreen by doing something lazy
717 //heigt and width answer "what is the area considered not to be outside of the game?"
718 var height = window.innerHeight,
719 width = window.innerWidth;
720
721 //((Resize friendly, that is, if we want to make this resizable in the future this should hold)).
722 //We seem to need to acquire this through the document.getElementById, it returns 0 otherwise
723 var dragH = document.getElementById("infoBox").clientHeight;
724 var dragW = document.getElementById("infoBox").clientWidth;
725
726
727 //If the drag sends the dragon offscreen, put it to the edge instead
728 //Otherwise let the user do whatever
729 if (addLeft < 0) {
730 dm.style.left = "0px";
731 } else if (addLeft + dragW > width) {
732 dm.style.left = (width - dragW) + 'px';
733 } else {
734 dm.style.left = addLeft + 'px';
735 }
736
737 //Same but for the height
738 if (addTop < 0) {
739 dm.style.top = "0px";
740 } else if (addTop + dragH > height) {
741 dm.style.top = (height - dragH) + 'px';
742 } else {
743 dm.style.top = addTop + 'px';
744 }
745 event.preventDefault();
746 return false;
747 }
748
749
750
751
752 //The body needs to be able to accept the new positions
753 //So naturally the listeners are added to the body
754 //(Imagine how weird this paragraph above would be in a medical paper)
755 document.body.addEventListener('dragover', drag_over, false);
756 document.body.addEventListener('drop', drop, false);
757
758
759 //Configure and style the draggable box, then add to the body
760 var dragAside = document.createElement("whatever");
761 dragAside.id = "dragonDrop";
762 dragAside.draggable = "true";
763 dragAside.style.position = "absolute";
764 dragAside.style.left = "100px"; //starting coordinates
765 dragAside.style.top = "100px"; //eh whatevs, nice round number
766 dragAside.style.width = "300px";
767 dragAside.style.background = "rgb(20, 20, 20)";
768 dragAside.addEventListener('dragstart', drag_start, false);
769 document.body.appendChild(dragAside);
770
771 //BEGIN: Functions for the adventureText thing
772 //////////////////////////////////////////////
773
774 var toggleTextAdventure = function(toggle) {
775
776 if(toggle) {
777
778 bpOverlay.adventureFirstRun = true;
779 bpOverlay.adventureTextMode = true;
780
781 //Hide the old
782 var gameCanvas = document.getElementById("GameCanvas");
783 gameCanvas.parentNode.style.backgroundColor="rgb(20,20,20)";
784 gameCanvas.style.display="none";
785
786 //In with the new
787 var textAdventureDiv = document.createElement("DIV");
788 textAdventureDiv.id="adventure";
789 textAdventureDiv.className="adventureMeow";
790 //textAdventureDiv.style="position: relative; padding: 0.25em; -webkit-box-flex: 1; -moz-box-flex: 1; -o-box-flex: 1; box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; -webkit-box-orient: vertical; -moz-box-orient: vertical; -o-box-orient: vertical; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; text-align: left;";
791 textAdventureDiv.style.backgroundColor="rgb(20,20,20)";
792
793
794
795 //Player info
796 var textAdventurePINFO = document.createElement("P");
797 textAdventurePINFO.id = "adventurePINFO";
798 textAdventurePINFO.className = "adventureMeow";
799 var playerLives=0;
800 var playerLetters=["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v"];
801 //What level? How many letters?
802 var playerIndex = 200; //for undefined
803 for(i=0; i < channel.data.actors.length; i++) {
804 if(channel.data.actors[i].authId === window.app.user.authId) {
805 playerLives = channel.data.actors[i].lives;
806 playerLetters = channel.data.actors[i].lockedLetters;
807 playerIndex = i;
808 }
809 }
810
811 if(playerIndex == 200) {
812 var level = 0;
813 } else if(bpOverlay.flips[playerIndex] >= bpOverlay.adventureLevels.length) {
814 var level = bpOverlay.adventureLevels.length - 1;
815 } else {
816 var level = bpOverlay.flips[playerIndex];
817 }
818
819 textAdventurePINFO.innerHTML = window.app.user.displayName + " : " + bpOverlay.adventureLevels[level];
820 textAdventurePINFO.style.color="rgb(255, 255, 51)";
821
822 var remaining="";
823 //Player remaining letters
824 for(i in playerLetters) {
825 remaining+=playerLetters[i].toUpperCase();
826 }
827
828 var textAdventureEXPINFO = document.createElement("DIV");
829 textAdventureEXPINFO.id="adventureEXPINFO";
830 textAdventureEXPINFO.className = "adventureMeow";
831
832 textAdventureEXPINFO.innerHTML = "Experience requise: " + remaining;
833 textAdventureEXPINFO.style.color="rgb(255,255,255)";
834
835
836 textAdventureDiv.appendChild(textAdventureEXPINFO);
837 textAdventureDiv.appendChild(textAdventurePINFO);
838
839 //Player Container
840 var textAdventurePlayer = document.createElement("DIV");
841 textAdventurePlayer.id = "adventurePlayer";
842 textAdventurePlayer.className="adventureMeow";
843 textAdventurePlayer.style = "position: relative";
844 textAdventureDiv.appendChild(textAdventurePlayer);
845
846 //Player image container
847 var textAdventureAvatar = document.createElement("IMG");
848 textAdventureAvatar.id = "adventureAvatar";
849 textAdventureAvatar.className = "adventureMeow";
850 if(typeof window.app.user.pictureURL === "undefined") {
851 textAdventureAvatar.src = "http://bombparty.sparklinlabs.com/images/AvatarPlaceholder.png";
852 } else {
853 textAdventureAvatar.src = window.app.user.pictureURL;
854 }
855 textAdventureAvatar.style = "position: relative; float: right";
856 textAdventurePlayer.appendChild(textAdventureAvatar);
857
858 //Player bar container
859 var textAdventureBars = document.createElement("DIV");
860 textAdventureBars.id = "adventureBars";
861 textAdventureBars.className = "adventureMeow";
862 textAdventureBars.style="position: relative; float: right;";
863 textAdventurePlayer.appendChild(textAdventureBars);
864
865 //Player health bar
866 var textAdventureHealth = document.createElement("DIV");
867 textAdventureHealth.id = "adventureHealth";
868 textAdventureHealth.className = "adventureMeow";
869 textAdventureHealth.style="position: absolute;";
870 textAdventureHealth.style.width= (10 + playerLives * 70) + "px";
871 textAdventureBars.appendChild(textAdventureHealth);
872
873 //Player exp bar
874 var textAdventureExp = document.createElement("DIV");
875 textAdventureExp.id = "adventureExp";
876 textAdventureExp.className = "adventureMeow";
877 textAdventureExp.style="position: absolute;";
878 textAdventureExp.style.width= (10 + (21 - playerLetters.length) * 10) + "px";
879 textAdventureBars.appendChild(textAdventureExp);
880
881 //Turn container
882 var textAdventureTurns = document.createElement("DIV");
883 textAdventureTurns.id = "adventureTurns";
884 textAdventureTurns.className = "adventureMeow";
885 textAdventureTurns.style = "position: relative; float: right; color: #FFF";
886 textAdventurePlayer.appendChild(textAdventureTurns);
887
888 //Message container
889 var textAdventureMessages = document.createElement("DIV");
890 textAdventureMessages.id = "adventureMessages";
891 textAdventureMessages.className="adventureMeow";
892 textAdventureMessages.align="center";
893 textAdventureMessages.style="position: relative;";
894 textAdventureDiv.appendChild(textAdventureMessages);
895
896 //We need input... and on the project too. Like, comment and subscribe. How? Magic.
897 //Or maybe not. Let's keep this though if we wanna customize more later.
898 //var textAdventureInput = document.createElement("INPUT");
899 //textAdventureInput.id="adventureInput";
900 //textAdventureInput.className="adventureMeow";
901 //textAdventureInput.style.outline="none";
902 //textAdventureInput.style.border="none";
903 //textAdventureInput.style.backgroundColor="rgb(20,20,20)";
904 //textAdventureInput.style.color="rgb(90, 249, 12)";
905 //textAdventureMessages.appendChild(textAdventureInput);
906
907 gameCanvas.parentNode.insertBefore(textAdventureDiv, gameCanvas);
908
909 //I hate CSS. This seems to only work after
910 textAdventureMessages.style.marginLeft="40px";
911 textAdventureMessages.style.marginTop="40px";
912 textAdventureMessages.style.clear="both";
913 textAdventurePlayer.style.marginLeft="40px";
914 textAdventurePlayer.style.marginTop="5px"
915 textAdventurePlayer.style.overflow="hidden";
916 textAdventurePINFO.style.marginLeft="40px";
917 textAdventureEXPINFO.style.marginLeft="40px";
918 textAdventureEXPINFO.style.marginTop="40px";
919 textAdventureAvatar.style.height="76px";
920 textAdventureAvatar.style.width="76px";
921 textAdventureAvatar.style.float="left";
922 textAdventureBars.style.marginLeft="10px";
923 textAdventureBars.style.height="75px";
924 textAdventureBars.style.width="400px";
925 textAdventureBars.style.border="1px solid #141414";
926 textAdventureBars.style.float="left";
927 textAdventureHealth.style.backgroundColor="rgb(255,255,0)";
928 textAdventureHealth.style.border="10px solid red";
929 textAdventureHealth.style.marginTop="8px";
930 textAdventureHealth.style.marginBottom="14px";
931 textAdventureExp.style.backgroundColor="rgb(0,0,204)";
932 textAdventureExp.style.border="10px solid blue";
933 textAdventureExp.style.marginTop="14px";
934 textAdventureExp.style.marginBottom="8px";
935 textAdventureTurns.style.marginLeft="20px";
936 textAdventureTurns.style.float="left";
937
938 } else {
939
940 bpOverlay.adventureTextMode = false;
941 bpOverlay.adventureFirstRun = false; //Probably not needed but I like symmetry
942
943 //Out with the old
944 var old = document.getElementsByClassName("adventureMeow");
945 for(i = 0; i < old.length; i++) {
946 old[i].parentNode.removeChild(old[i]);
947 }
948
949 //In with the previously old, ehhh.... default.
950 //Pretty neat that you can reset this with an empty string. Oh boy.
951 var gameCanvas = document.getElementById("GameCanvas");
952 gameCanvas.parentNode.style.backgroundColor="";
953 gameCanvas.style.display="";
954
955 }
956
957 }
958
959 //msg is the string to be displayed
960 //formatter is a color code on the form "rgb(x,y,z)" where 0<=x,y,z<=255
961 var sendAdventureMessage = function(msg, formatter) {
962 if(bpOverlay.adventureTextMode) {
963 var textAdventureMessages = document.getElementById("adventureMessages");
964 var textAdventureMsg = document.createElement("P");
965 textAdventureMsg.style.color=formatter;
966 textAdventureMsg.innerHTML=msg;
967
968 //We don't want the messages to extend out of the page... now do we?
969 if(textAdventureMessages.children.length > 10) {
970 textAdventureMessages.appendChild(textAdventureMsg);
971 textAdventureMessages.removeChild(textAdventureMessages.firstChild);
972 } else {
973 textAdventureMessages.appendChild(textAdventureMsg);
974 }
975
976
977 }
978 }
979 //////////////////////////////////////////////
980 //END functions for the adventure text thing
981
982 // It's my turn to write a long completely unnecessary feature!
983 //////////////////////////////////////////////
984 var particleEmitters = []; // An array to store the emitters
985 var particleArray = []; // An array for actual particles
986 var particleImgs = []; // An array for particle images
987 var rafID; // For storing the ID for requestAnimationFrame, so we can stop it
988
989 var textColors = { // For converting colours into text specifiers
990 "#cccccc": "statusText",
991 "#ffffff": "promptText",
992 "#a0a0a0": "wordText",
993 "#60aa60": "highlightedText",
994 "#404040": "bonusLetterText",
995 };
996
997 // Bleh, it turns out that browsers haven't completely agreed on a single function for requestAnimationFrame/cancelAnimationFrame
998 var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
999 var cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
1000
1001 // This needs to be exposed because it needs to be called by the GM script
1002 loadCustomTheme = function (themeObj) {
1003 if (themeObj && !bpOverlay.isThemed) {
1004 bpOverlay.isThemed = true;
1005
1006 // Grab the canvas and its context
1007 var canvas = document.getElementById("GameCanvas");
1008 var ctx = canvas.getContext("2d");
1009
1010 // Add and replace images if necessary
1011 if (themeObj.images) {
1012 for (var i in themeObj.images) {
1013 // Validation
1014 if (!themeObj.images[i].src) {
1015 console.log("Error: source is not defined for image " + i + ". Will try to execute anyway");
1016 }
1017
1018 replacementImages[i] = themeObj.images[i].src;
1019
1020 if (themeObj.images[i].xOffset || themeObj.images[i].yOffset) {
1021 var offset = {x: 0, y: 0};
1022 if (themeObj.images[i].xOffset) {
1023 offset.x = themeObj.images[i].xOffset;
1024 }
1025 if (themeObj.images[i].yOffset) {
1026 offset.y = themeObj.images[i].yOffset
1027 }
1028
1029 replacementOffsets[i] = offset;
1030 }
1031
1032 replaceImage(i);
1033 }
1034 }
1035
1036 // Create a style if there is one.
1037 if (themeObj.css) {
1038 if (themeObj.css.text) {
1039 var style = document.createElement('style');
1040 style.id = "customThemeStyle";
1041 style.appendChild(document.createTextNode(themeObj.css.text));
1042 document.getElementsByTagName('head')[0].appendChild(style);
1043 }
1044 else if (themeObj.css.src) {
1045 var style = document.createElement('link');
1046 style.id = "customThemeStyle";
1047 style.rel = "stylesheet";
1048 style.type = "text/css";
1049 style.href = themeObj.css.src;
1050 document.getElementsByTagName('head')[0].appendChild(style);
1051 }
1052 else {
1053 console.log("Error: css field declared but no valid css provided. Will try to execute anyway");
1054 }
1055 }
1056
1057 // If there is particles, then do this whole canvas drawing shebang
1058 if (themeObj.particles) {
1059 // Load up the images
1060 if (themeObj.particles.images && themeObj.particles.images.length) {
1061 for (i = 0; i < themeObj.particles.images.length; i++) {
1062 var img = new Image;
1063 img.src = themeObj.particles.images[i];
1064 particleImgs.push(img);
1065 }
1066 }
1067 else {
1068 console.log("Error: no particle images defined. Will try to execute anyway");
1069 }
1070
1071 var lastTime = (new Date).getTime();
1072
1073 if (themeObj.particles.emitters && themeObj.particles.emitters.length) {
1074 var emitters = themeObj.particles.emitters;
1075 for (i = 0; i < emitters.length; i++) {
1076 var e = emitters[i];
1077 e.spawnParticle = function () {
1078 if (Math.random() < e.spawnRate[bpOverlay.particleSpawnRate]) {
1079 // This bit's quite involved because the data entered into the JSON could take quite a few forms...
1080
1081 var rawSize = Math.random();
1082
1083 // Determine x-position
1084 var pos_x = e.position.x * canvas.width;
1085 if (e.position.width) {
1086 pos_x += Math.random() * e.position.width * canvas.width;
1087 }
1088
1089 // determine y-position
1090 var pos_y = e.position.y * canvas.height;
1091 if (e.position.height) {
1092 pos_y += Math.random() * e.position.height * canvas.height;
1093 }
1094
1095 // Determine x-velocity
1096 var vel_x;
1097 if (typeof(e.velocity.x) === "number") {
1098 vel_x = e.velocity.x;
1099 }
1100 else {
1101 vel_x = e.velocity.x.min + (e.velocity.linkedToSize ? rawSize : Math.random()) * (e.velocity.x.max - e.velocity.x.min);
1102 }
1103
1104 // Determine y-velocity
1105 var vel_y;
1106 if (typeof(e.velocity.y) === "number") {
1107 vel_y = e.velocity.y;
1108 }
1109 else {
1110 vel_y = e.velocity.y.min + (e.velocity.linkedToSize ? rawSize : Math.random()) * (e.velocity.y.max - e.velocity.y.min);
1111 }
1112
1113 // Determine size
1114 var size;
1115 if (typeof(e.size) === "number") {
1116 size = e.size;
1117 }
1118 else {
1119 size = e.size.min + rawSize * (e.size.max - e.size.min);
1120 }
1121
1122 // Determine rotation
1123 var rot;
1124 if (typeof(e.rotation) === "number") {
1125 rot = e.rotation;
1126 }
1127 else {
1128 rot = e.rotation.min + (e.rotation.linkedToSize ? rawSize : Math.random()) * (e.rotation.max - e.rotation.min);
1129 }
1130
1131 // Determine angular velocity
1132 var rotV;
1133 if (typeof(e.angularVelocity) === "number") {
1134 rotV = e.angularVelocity;
1135 }
1136 else {
1137 rotV = e.angularVelocity.min + (e.angularVelocity.linkedToSize ? rawSize : Math.random()) * (e.angularVelocity.max - e.angularVelocity.min);
1138 }
1139
1140 if (e.gravity) {
1141 // Determine x-gravity
1142 var grav_x = e.gravity.x;
1143 // Determine y-gravity
1144 var grav_y = e.gravity.y;
1145 }
1146 else {
1147 var grav_x = 0;
1148 var grav_y = 0;
1149 }
1150
1151 // Put all of this into a particle object
1152 particleArray.push({
1153 imageId: Math.floor(Math.random() * particleImgs.length),
1154 position: {
1155 x: pos_x,
1156 y: pos_y,
1157 },
1158 velocity: {
1159 x: vel_x,
1160 y: vel_y,
1161 },
1162 size: size,
1163 rotation: rot,
1164 angularVelocity: rotV,
1165 gravity: {
1166 x: grav_x,
1167 y: grav_y,
1168 },
1169 alpha: 1,
1170 });
1171
1172 }
1173 }
1174 }
1175 }
1176 else if (themeObj.particles.emitters === [] || !themeObj.particles.emitters) {
1177 console.log("Error: Particles declared but no emitters defined. Will try to execute anyway");
1178 }
1179
1180 // Actual function used for drawing the particles
1181 particleAnimate = function () {
1182 // Run spawning thing on all the emitters
1183 var emitters = themeObj.particles.emitters;
1184 for (i = 0; i < emitters.length; i++) {
1185 emitters[i].spawnParticle();
1186 }
1187
1188 // Time params
1189 var current = (new Date).getTime();
1190 var dt = Math.min((current - lastTime) / 1000, 1);
1191 lastTime = current;
1192
1193 // Euh, reset the scaling
1194 ctx.setTransform(1, 0, 0, 1, 0, 0);
1195
1196 // Loop through all the particles
1197 // We're looping backwards because we want to be able to remove particles
1198 // Without messing up list indices
1199 for (i = particleArray.length - 1; i >= 0; i--) {
1200 var particle = particleArray[i];
1201 var img = particleImgs[particle.imageId];
1202
1203 // Update its parameters
1204 particle.position.x += particle.velocity.x * dt;
1205 particle.position.y += particle.velocity.y * dt;
1206 particle.rotation += particle.angularVelocity * dt;
1207 particle.rotation %= Math.PI * 2;
1208 particle.velocity.x += particle.gravity.x * dt;
1209 particle.velocity.y += particle.gravity.y * dt;
1210
1211 // set the alpha to something lower if it's over the prompt or the locked letters.
1212 if (Math.abs(particle.position.x - canvas.width / 2) < 100 && Math.abs(particle.position.y - canvas.height /2) < 200 ||
1213 particle.position.x + width/2 > canvas.width - Math.min(100, canvas.height / 11 * 2)) {
1214 particle.alpha = Math.max(0.1, particle.alpha - 0.05);
1215 }
1216 else if (particle.alpha < 1) {
1217 particle.alpha = Math.min(1, particle.alpha + 0.05);
1218 }
1219
1220 if (particle.alpha < 1) {
1221 var ga = ctx.globalAlpha;
1222 ctx.globalAlpha = particle.alpha;
1223 }
1224
1225 var width = img.width * particle.size;
1226 var height = img.height * particle.size;
1227
1228 // Draw the particle
1229 // Apparently, to rotate things, you have to transform the entire canvas context
1230 ctx.translate(particle.position.x, particle.position.y);
1231 ctx.rotate(particle.rotation);
1232 ctx.drawImage(img, -width/2, -height/2, width, height);
1233 ctx.rotate(-particle.rotation);
1234 ctx.translate(-particle.position.x, -particle.position.y);
1235
1236 if (particle.alpha < 1) {
1237 ctx.globalAlpha = ga;
1238 }
1239
1240 // Remove the particle if necessary
1241 if (particle.x < -0.2 * canvas.width ||
1242 particle.position.y < -0.2 * canvas.height ||
1243 particle.position.x > 1.2 * canvas.width ||
1244 particle.position.y > 1.2 * canvas.height) {
1245 particleArray.splice(i, 1);
1246 }
1247 }
1248
1249 // Request it again so
1250 rafID = requestAnimationFrame(particleAnimate);
1251 }
1252
1253 particleAnimate();
1254 }
1255
1256 // Do the text styles
1257 if (themeObj.textStyles) {
1258 ctx.fillTextRedux = ctx.fillText;
1259 ctx.fillText = function () {
1260 var tc = ctx.shadowColor;
1261 var tb = ctx.shadowBlur;
1262 var fs = ctx.fillStyle;
1263 var f = ctx.font;
1264
1265 var fontA = f.split("px ");
1266 var fontSize = fontA[0];
1267 var fontFamily = fontA[1];
1268
1269 var thisStyle = themeObj.textStyles[textColors[fs]];
1270 if (thisStyle) {
1271 if (thisStyle.color) {
1272 ctx.fillStyle = thisStyle.color;
1273 }
1274 if (thisStyle.shadow) {
1275 if (typeof thisStyle.shadow === "string")
1276 ctx.shadowColor = thisStyle.shadow;
1277 else
1278 ctx.shadowColor = "#000";
1279
1280 ctx.shadowBlur = 10;
1281 }
1282
1283 var newFont = [fontSize, fontFamily];
1284
1285 if (textColors[fs] === "wordText" || textColors[fs] === "highlightedText") {
1286 if (fontSize === "20") {
1287 if (thisStyle.majorFontSize) {
1288 newFont[0] = thisStyle.majorFontSize;
1289 }
1290 }
1291 else if (fontSize === "14") {
1292 if (thisStyle.minorFontSize) {
1293 newFont[0] = thisStyle.minorFontSize;
1294 }
1295 }
1296 }
1297 else {
1298 if (thisStyle.fontSize) {
1299 newFont[0] = thisStyle.fontSize;
1300 }
1301 }
1302
1303 if (thisStyle.fontFamily) {
1304 newFont[1] = thisStyle.fontFamily;
1305 }
1306
1307 ctx.font = newFont.join("px ");
1308 }
1309
1310 ctx.fillTextRedux.apply(this, arguments);
1311
1312 ctx.font = f;
1313 ctx.fillStyle=fs;
1314 ctx.shadowColor=tc;
1315 ctx.shadowBlur=tb;
1316 };
1317
1318 // Since I'm changing the text size and style sometimes, I need to adjust ctx.measureText
1319 ctx.measureTextRedux = ctx.measureText;
1320 ctx.measureText = function () {
1321 var f = ctx.font;
1322 var fs = ctx.fillStyle;
1323
1324 var fontA = f.split("px ");
1325 var fontSize = fontA[0];
1326 var fontFamily = fontA[1];
1327
1328 var thisStyle = themeObj.textStyles[textColors[fs]];
1329 if (thisStyle) {
1330 var newFont = [fontSize, fontFamily];
1331
1332 // Helpfully, the only time the measureText is actually used
1333 // In Elisee's code is when the words below the players are being drawn
1334 if (textColors[fs] === "wordText" || textColors[fs] === "highlightedText") {
1335 if (fontSize === "20") {
1336 if (thisStyle.majorFontSize) {
1337 newFont[0] = thisStyle.majorFontSize;
1338 }
1339 }
1340 else if (fontSize === "14") {
1341 if (thisStyle.minorFontSize) {
1342 newFont[0] = thisStyle.minorFontSize;
1343 }
1344 }
1345 }
1346
1347 if (thisStyle.fontFamily) {
1348 newFont[1] = thisStyle.fontFamily;
1349 }
1350
1351 ctx.font = newFont.join("px ");
1352 }
1353
1354 var result = ctx.measureTextRedux.apply(this, arguments);
1355
1356 ctx.font = f;
1357
1358 return result;
1359 }
1360
1361 }
1362
1363 for (var i in gameImages) {
1364 replaceImage(i);
1365 }
1366
1367 }
1368 else if (!themeObj && bpOverlay.isThemed) {
1369 bpOverlay.isThemed = false;
1370
1371 // Get rid of the custom style sheet if there is one
1372 if (style = document.getElementById("customThemeStyle")) {
1373 style.parentNode.removeChild(style);
1374 }
1375
1376 // Cancel the particle animation
1377 if (rafID !== undefined) {
1378 cancelAnimationFrame(rafID);
1379 rafID = undefined;
1380 }
1381
1382 var ctx = document.getElementById("GameCanvas").getContext("2d");
1383
1384 if (ctx.fillTextRedux) {
1385 ctx.fillText = ctx.fillTextRedux;
1386 }
1387 if (ctx.measureTextRedux) {
1388 ctx.measureText = ctx.measureTextRedux;
1389 }
1390
1391 for (var i in gameImages) {
1392 unreplaceImage(i);
1393 }
1394
1395 particleImgs = [];
1396 particleArray = [];
1397
1398 // Reset so nothing else gets replaced
1399 replacementImages = {};
1400 replacementOffsets = {};
1401 }
1402 };
1403
1404 // Replace image function
1405 // Call this when a new image is being drawn or when custom theme mode is being activated
1406 var replaceImage = function (imageName) {
1407 if (replacementImages[imageName] && gameImages[imageName]) {
1408 gameImages[imageName].src = replacementImages[imageName];
1409 }
1410 };
1411
1412 // Replace the images back with the originals
1413 // Call when custom theme mode is deactivated
1414 var unreplaceImage = function (imageName) {
1415 if (backupSources[imageName] && gameImages[imageName]) {
1416 gameImages[imageName].src = backupSources[imageName];
1417 }
1418 };
1419
1420 //////////////////////////////////////////////
1421 // END of most of the custom theme code
1422
1423 //Creates a score notifier in ca. the middle of the screen
1424 var scoreNotifier = function(points) {
1425 var scoreDiv = document.createElement("whatever");
1426 scoreDiv.innerHTML="<p style='color: yellow; font-size: 300%'>" + points;
1427 scoreDiv.id = "scoreDiv";
1428 scoreDiv.draggable = "true";
1429 scoreDiv.style.position = "absolute";
1430 scoreDiv.style.left = window.innerWidth / 3 + "px";
1431 scoreDiv.style.top = window.innerHeight / 2 + "px";
1432 scoreDiv.style.width = window.innerWidth / 2 + "px";
1433 scoreDiv.style.background = "rgb(20, 20, 20, 0)";
1434 document.body.appendChild(scoreDiv);
1435
1436 jQ('#scoreDiv').animate({"top":"20px", "opacity":"0"}, 1000, function() {
1437 document.getElementById("scoreDiv").parentNode.removeChild(document.getElementById("scoreDiv"));
1438 });
1439 };
1440
1441 var updateScores = function() {
1442
1443 var stupidSort = [];
1444 for(i=0; i<Object.keys(bpOverlay.playerNames).length; i++) {
1445 var temp = {names: bpOverlay.playerNames[i], score: bpOverlay.playerScores[i]};
1446 stupidSort.push(temp);
1447 }
1448
1449 stupidSort.sort(function(a, b) {
1450 return b.score - a.score;
1451 });
1452
1453 var lTab = document.getElementById("LeaderboardTab");
1454 lTab.innerHTML = "<table>";
1455 var names="";
1456 for(i=0; i<Object.keys(bpOverlay.playerNames).length; i++) {
1457 if(stupidSort[i].names.length > 14) {
1458 names = stupidSort[i].names.substring(0,14);
1459 } else {
1460 names = stupidSort[i].names;
1461 }
1462 lTab.innerHTML += "<br><tr><td>" + names + "</td><td> --- </td><td>" + stupidSort[i].score + "</td></tr>";
1463 }
1464 lTab.innerHTML += "</table>";
1465 };
1466
1467
1468 // This function is called whenever a new round begins.
1469 var generateActorConditions = function() {
1470 // If there is already a box, get rid of it
1471 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
1472 var infoBox = document.getElementById("infoBox");
1473
1474 //remove infoBox from wherever it is
1475 var meow = infoBox.parentNode;
1476 meow.removeChild(infoBox);
1477
1478 //If if then more lines hence both.
1479 bpOverlay.boxHasBeenCreated = false;
1480 bpOverlay.dragBoxHasBeenCreated = false;
1481 }
1482
1483 // Shift current round's variables onto previous round's variables
1484 bpOverlay.prevPlayerNames = bpOverlay.playerNames;
1485 bpOverlay.prevLostLives = bpOverlay.lostLives;
1486 bpOverlay.prevFlips = bpOverlay.flips;
1487 bpOverlay.prevUFlips = bpOverlay.uFlips;
1488 bpOverlay.prevWords = bpOverlay.words;
1489 bpOverlay.prevTimeText = bpOverlay.timeText;
1490 bpOverlay.prevWordCount = bpOverlay.wordCount;
1491
1492 // Reset current round variables
1493 bpOverlay.playerNames = {};
1494 bpOverlay.playerAuthId = {};
1495 bpOverlay.lostLives = {};
1496 bpOverlay.flips = {};
1497 bpOverlay.uFlips = {};
1498 bpOverlay.alpha = {};
1499 bpOverlay.words = {};
1500
1501 actors = channel.data.actors;
1502
1503 // Loop through current round's actors and log data accordingly
1504 for (i = 0; i < actors.length; i++) {
1505 bpOverlay.playerNames[i] = actors[i].displayName;
1506 bpOverlay.playerAuthId[actors[i].authId] = i;
1507 bpOverlay.flips[i] = 0;
1508 bpOverlay.uFlips[i] = 0;
1509 bpOverlay.lostLives[i] = 0;
1510 bpOverlay.alpha[i] = {progress: 0, completed: 0};
1511 bpOverlay.words[i] = 0;
1512 }
1513
1514 // More resetting...
1515 bpOverlay.wordCount = 0;
1516 bpOverlay.timeText = tran.t("timeText") + "0:00";
1517
1518 var d = new Date();
1519 bpOverlay.startTime = d.getTime();
1520
1521 // Create the infoBox.
1522 var infoBox = document.createElement("DIV");
1523 infoBox.id = "infoBox";
1524
1525 // Create the time text display
1526 var timeElement = document.createElement("H2");
1527 timeElement.id = "infoBoxTimer";
1528 timeElement.align = "center"; //Might get overridden if not in drag-mode but who cares :D
1529 timeElement.style.color = "rgb(200,200,200)"; //this as well but that's a good thing
1530 timeElement.textContent = bpOverlay.timeText;
1531 infoBox.appendChild(timeElement);
1532
1533 // Create the word counter display
1534 var wordCounterElement = document.createElement("H2");
1535 wordCounterElement.align = "center";
1536 wordCounterElement.id = "infoWordCounter";
1537 wordCounterElement.style.color = "rgb(200,200,200)";
1538 wordCounterElement.textContent = tran.t("wordCountText") + "0";
1539 infoBox.appendChild(wordCounterElement);
1540
1541 // Oh boy, a horizontal rule! Gee willikers!
1542 var horizontalRule = document.createElement("hr");
1543 infoBox.appendChild(horizontalRule);
1544
1545 // Contain the scoreboard table in a div to allow for scrolling
1546 var infoTableDiv = document.createElement("DIV");
1547 infoTableDiv.className = "infoTableDiv";
1548 infoTableDiv.align = "center"
1549
1550 //Retain choices between rounds from the settings meow
1551 //Ah... this may not exist. Let's patch it.
1552 if(document.getElementById("containerSelect")) {
1553 var cont = document.getElementById("containerSelect");
1554 if(cont.value === "fitToPlayers") {
1555 infoTableDiv.style.maxHeight = "1000px"; //autoflow hinders big meow meow meow yappety yak
1556 } else {
1557 infoTableDiv.style.maxHeight = "100px";
1558 }
1559 }
1560 infoTableDiv.style.overflowY = "auto";
1561
1562 // Make the actual scoreboard table
1563 var infoTable = document.createElement("table");
1564 infoTable.style.tableLayout = "fixed";
1565 infoTable.style.width = "100%";
1566 infoTableDiv.appendChild(infoTable);
1567
1568 // First row is a button and column headers.
1569 var firstRow = document.createElement("tr");
1570
1571 // The first element in the first row is a container for the show/hide button
1572 var showHideContainer = document.createElement("td");
1573
1574 // Make the show_hide button
1575 var showHideButton = document.createElement("BUTTON");
1576 var showHideButtonDiv = document.createElement("DIV");
1577 showHideButtonDiv.className = "headerButtonDiv";
1578 showHideButton.id = "autoFocusButton";
1579 showHideButton.className = "headerButton";
1580 showHideButton.title = tran.t("showHideButtonTitle");
1581
1582 showHideButton.onclick = function() {
1583 // Flip the state of hideDead
1584 bpOverlay.hideDead = !bpOverlay.hideDead;
1585
1586 if (bpOverlay.hideDead) {
1587 // if hideDead is true, remove the off state image and add the on state image
1588 showHideButton.removeChild(bpOverlayImgs.hideDeadOff);
1589 showHideButton.appendChild(bpOverlayImgs.hideDeadOn);
1590
1591 // Hide all the grayed out players
1592 // A bit of a hack, storing information in colours
1593 var rows = document.getElementsByClassName("playerRow");
1594 for (i = 0; i < rows.length; i++) {
1595 if (rows[i].style.color == "rgb(102, 102, 102)") {
1596 rows[i].style.display = "none";
1597 }
1598 }
1599 } else {
1600 // if hideDead is false, remove the on state image and add the off state image
1601 showHideButton.removeChild(bpOverlayImgs.hideDeadOn);
1602 showHideButton.appendChild(bpOverlayImgs.hideDeadOff);
1603
1604 // Since showing the overlay will scroll the chat up, we might want to check if
1605 // the user needs to have the chat scrolled down after expansion
1606 var chatLog = document.getElementById("ChatLog");
1607 var scrollDown = (bpOverlay.autoScroll || chatLog.scrollTop == chatLog.scrollHeight)
1608
1609 // Show all the hidden rows
1610 var rows = document.getElementsByClassName("playerRow");
1611 for (i = 0; i < rows.length; i++) {
1612 if (rows[i].style.display == "none") {
1613 rows[i].style.display = "table-row";
1614 }
1615 }
1616
1617 //Let's add a call to the window.onresize if this is done while the dragon is at the bottom
1618 //This prevents overflow
1619 var funky = window.onresize;
1620 funky();
1621
1622 // If the chat does need scrolling down then scroll it down
1623 if (scrollDown) {
1624 chatLog.scrollTop = chatLog.scrollHeight;
1625 }
1626 }
1627 };
1628
1629 // Add the appropriate image based on the current setting of hideDead
1630 if (bpOverlay.hideDead) {
1631 showHideButton.appendChild(bpOverlayImgs.hideDeadOn);
1632 } else {
1633 showHideButton.appendChild(bpOverlayImgs.hideDeadOff);
1634 }
1635
1636 // ...and append it all into the first row. Phew!
1637 showHideButtonDiv.appendChild(showHideButton);
1638 showHideContainer.appendChild(showHideButtonDiv);
1639 firstRow.appendChild(showHideContainer);
1640
1641 // Make headers for the columns, and append to the first row
1642 var flipColumnHeader = document.createElement("td");
1643 flipColumnHeader.textContent = tran.t("flipsText");;
1644 flipColumnHeader.style.color = "rgb(200,200,200)";
1645 flipColumnHeader.align = "center";
1646 flipColumnHeader.style.padding = "2px";
1647 flipColumnHeader.style.fontSize = "11px";
1648 flipColumnHeader.style.width = "40px";
1649 flipColumnHeader.title = tran.t("flipsTitle");
1650 firstRow.appendChild(flipColumnHeader);
1651 var uFlipColumnHeader = document.createElement("td");
1652 uFlipColumnHeader.textContent = tran.t("uFlipsText");
1653 uFlipColumnHeader.style.color = "rgb(200,200,200)";
1654 uFlipColumnHeader.align = "center";
1655 uFlipColumnHeader.style.padding = "2px";
1656 uFlipColumnHeader.style.fontSize = "11px";
1657 uFlipColumnHeader.style.width = "40px";
1658 uFlipColumnHeader.title = tran.t("uFlipsTitle");
1659 firstRow.appendChild(uFlipColumnHeader);
1660 var lostLivesColumnHeader = document.createElement("td");
1661 lostLivesColumnHeader.textContent = tran.t("deathsText");
1662 lostLivesColumnHeader.style.color = "rgb(200,200,200)";
1663 lostLivesColumnHeader.align = "center";
1664 lostLivesColumnHeader.style.padding = "2px";
1665 lostLivesColumnHeader.style.fontSize = "11px";
1666 lostLivesColumnHeader.style.width = "40px";
1667 lostLivesColumnHeader.title = tran.t("deathsTitle");
1668 firstRow.appendChild(lostLivesColumnHeader);
1669 infoTable.appendChild(firstRow);
1670
1671 // add the alphabet thing
1672 var alphaColumnHeader = document.createElement("td");
1673 alphaColumnHeader.textContent = tran.t("alphaText");
1674 alphaColumnHeader.className = "alphaColumn";
1675 alphaColumnHeader.style.color = "rgb(200,200,200)";
1676 alphaColumnHeader.align = "center";
1677 alphaColumnHeader.style.padding = "2px";
1678 alphaColumnHeader.style.fontSize = "11px";
1679 alphaColumnHeader.style.width = "40px";
1680 alphaColumnHeader.title = tran.t("alphaTitle");
1681 firstRow.appendChild(alphaColumnHeader);
1682
1683 var wordsColumnHeader = document.createElement("td");
1684 wordsColumnHeader.textContent = tran.t("wordsText");
1685 wordsColumnHeader.className = "wordsColumn";
1686 wordsColumnHeader.style.color = "rgb(200,200,200)";
1687 wordsColumnHeader.align = "center";
1688 wordsColumnHeader.style.padding = "2px";
1689 wordsColumnHeader.style.fontSize = "11px";
1690 wordsColumnHeader.style.width = "40px";
1691 wordsColumnHeader.title = tran.t("wordsTitle");
1692 firstRow.appendChild(wordsColumnHeader);
1693
1694 // Loop through the players, making a new row for each one
1695 for (i = 0; i < actors.length; i++) {
1696 var playerRow = document.createElement("tr");
1697 playerRow.id = i + " row"; // Used to reference this row later on
1698 playerRow.className = "playerRow";
1699
1700 if (actors[i].authId === app.user.authId) {
1701 playerRow.style.background = "rgba(255,0,0,0.1)";
1702 }
1703
1704 // If the player this row represents is dead, grey it out
1705 if (actors[i].state == "dead") {
1706 playerRow.style.color = "#666";
1707 if (bpOverlay.hideDead) {
1708 playerRow.style.display = "none";
1709 }
1710 } else {
1711 playerRow.style.color = "rgb(210,210,210)";
1712 }
1713
1714 // Make the cell containing the name
1715 var nameData = document.createElement("td");
1716 var name = bpOverlay.playerNames[i];
1717
1718 nameData.textContent = name;
1719 nameData.align = "center";
1720 nameData.style.whiteSpace = "nowrap";
1721 nameData.style.overflow = "hidden";
1722 nameData.style.textOverflow = "ellipsis";
1723 playerRow.appendChild(nameData)
1724
1725 // Make the cell containing the number of flips
1726 var flipData = document.createElement("td");
1727 flipData.id = i + " flips"; // used to reference this cell later
1728 flipData.textContent = "0";
1729 flipData.align = "center";
1730 playerRow.appendChild(flipData);
1731
1732 // Make the cell containing the # of u-flips
1733 var uFlipData = document.createElement("td");
1734 uFlipData.id = i + " uFlips"; // used to reference this cell later
1735 uFlipData.textContent = "0";
1736 uFlipData.align = "center";
1737 playerRow.appendChild(uFlipData);
1738
1739 // Make the cell containing the # of deaths
1740 var lostLivesData = document.createElement("td");
1741 lostLivesData.id = i + " lives"; // used to reference this cell later
1742 lostLivesData.textContent = "0";
1743 lostLivesData.align = "center";
1744 playerRow.appendChild(lostLivesData);
1745
1746 // Make the alpha thing
1747 var alphaData = document.createElement("td");
1748 alphaData.className = "alphaColumn";
1749 alphaData.id = i + " alpha"; // used to reference this cell later
1750 alphaData.innerHTML = "A (0)";
1751 alphaData.align = "center";
1752 playerRow.appendChild(alphaData);
1753
1754 var wordsData = document.createElement("td");
1755 wordsData.className = "wordsColumn";
1756 wordsData.id = i + " words";
1757 wordsData.innerHTML = "0";
1758 wordsData.align = "center";
1759 playerRow.appendChild(wordsData);
1760
1761 // Append the row to the table
1762 infoTable.appendChild(playerRow);
1763 }
1764
1765 // Append the table to the container...
1766 infoBox.appendChild(infoTableDiv);
1767
1768
1769
1770 //Creates either a docked infoBox or a draggable one
1771 if (bpOverlay.dragonDrop) {
1772 //Created if user wishes dragonDrop
1773 var deDragonDrop = document.getElementById("dragonDrop");
1774 deDragonDrop.appendChild(infoBox);
1775 bpOverlay.dragBoxHasBeenCreated = true;
1776
1777
1778 } else {
1779 //otherwise this is created
1780 var sideBar = document.getElementById("Sidebar");
1781 sideBar.insertBefore(infoBox, sideBar.firstChild);
1782
1783 bpOverlay.boxHasBeenCreated = true;
1784 }
1785
1786 //And yet another check of overflow needed in case the dragon is on the bottom and a new round starts
1787 //with more players than the previous round. This is outside the if(bpOverlay.dragonDrop) because the user might wish
1788 //to switch sides after starting a new round in docked mode. Bugfixes ahoy hoy yay yay
1789 var funky = window.onresize;
1790 funky();
1791
1792 // ..and finally, if autoScrolling is on, scroll the chat back down since this would've caused the chat to scroll up
1793 if (bpOverlay.autoScroll) {
1794 var chatLog = document.getElementById("ChatLog");
1795 chatLog.scrollTop = chatLog.scrollHeight;
1796 }
1797
1798 }
1799
1800 //Usage: generateSettingsElement(itemText, options, selectId, settingsFunction)
1801 //string 'itemText' is the text to the right of the drop down options pane
1802 //object 'options' is an object {value: Text, value2: Text2, ... , valueN: TextN}
1803 // 'value, ..., valueN' are the value we can compare from selectElement.value
1804 // 'Text, ..., TextN' are the strings that the user see when selecting options
1805 //string 'selectId': for your function you probably want to use document.getElementById(selectId)
1806 //function 'settingsFunction' is the function that is called on selectElement.onchange
1807 var generateSettingsElement = function(itemText, options, selectId, locatorId, settingsFunction) {
1808 //Create the text item
1809 //Oh god the horrors of navigating the dom DOM DOOOOM
1810
1811 // Made it so it keeps appending rows to the same table
1812 // As far as I'm aware, I don't think you need a tbody element here
1813 var sTabTable = document.getElementById(locatorId);
1814 var sTabTr = document.createElement("TR");
1815 sTabTable.appendChild(sTabTr);
1816 var sTabTd = document.createElement("TD");
1817 sTabTd.innerHTML = itemText;
1818 sTabTr.appendChild(sTabTd);
1819
1820 //Create the options DOM DOM POMPOM
1821 var sTabOptionsTd = document.createElement("TD");
1822 sTabTr.appendChild(sTabOptionsTd);
1823 var sTabSelect = document.createElement("SELECT");
1824 sTabSelect.id = selectId;
1825 sTabOptionsTd.appendChild(sTabSelect);
1826
1827 //Populate the select field with {Value: text} from options which is an object
1828 for(x in options) {
1829 var op = document.createElement("OPTION");
1830 op.textContent = options[x];
1831 op.value = x;
1832 sTabSelect.appendChild(op);
1833 }
1834
1835 //Add the function to the onchange listener for the newly created select
1836 sTabSelect.onchange = settingsFunction;
1837
1838 //OPTIONAL: Reflect on your lifechoices, such as programming when you should be studying
1839 }
1840
1841 //Usage: function(onSrc, offSrc, buttonId, buttonMessage, defaultState, buttonFunction)
1842 //img onSrc is the image for the on- state
1843 //img offSrc is the image for the off-state
1844 //string buttonId is the id for the created button item in the header
1845 //string buttonMessage is the hovermessage presented by the button
1846 //boolean defaultState: if true, then the button is created with the onSrc image, else the offSrc image
1847 //function buttonFunction is the function that is called when the button is clicked
1848 var makeHeaderButton = function(onSrc, offSrc, buttonId, buttonMessage, defaultState, buttonFunction) {
1849
1850 // Actually make the button, and its container div
1851 var button = document.createElement("BUTTON");
1852 var buttonDiv = document.createElement("DIV");
1853 buttonDiv.className = "headerButtonDiv";
1854
1855 // Insert the button container div into the header
1856 var header = document.getElementsByTagName("header")[0];
1857 var lastChild = header.lastChild;
1858 header.insertBefore(buttonDiv, lastChild);
1859
1860 var onElement = document.createElement("img");
1861 onElement = onSrc;
1862
1863 var offElement = document.createElement("img");
1864 offElement = offSrc;
1865
1866 // General "stylistic touches"
1867 button.id = buttonId;
1868 button.className = "headerButton";
1869 button.title = buttonMessage;
1870
1871 button.onclick = buttonFunction;
1872
1873 //Depending on defaultState, have the button start with the "on" image or the "off"
1874 if (defaultState) {
1875 button.appendChild(onSrc);
1876 button.dataset.state = true; // Turns out, data attributes are pretty useful in storing state
1877 } else {
1878 button.appendChild(offSrc);
1879 button.dataset.state = false;
1880 }
1881
1882 buttonDiv.appendChild(button);
1883 };
1884
1885
1886 // This function is called regularly to update the time text
1887 var updateTime = function() {
1888 // Don't bother doing anything if there's no game or the infoBox hasn't been created
1889 if (channel.data.state === 'playing' && (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated)) {
1890 // Timer code
1891 // Copied directly from Ice's bot
1892 var d = new Date();
1893 var seconds = Math.floor((d.getTime() - bpOverlay.startTime) / 1000);
1894 if ((seconds % 60) < 10) {
1895 var formatter = "0";
1896 } else {
1897 var formatter = "";
1898 }
1899
1900 bpOverlay.timeText = tran.t("timeText") + Math.floor(seconds / 60) + ":" + formatter + "" + (seconds % 60) + "";
1901
1902 // Umm, hmm, this if statement is redundant.
1903 // It looks like it anyway.
1904 // Yus - It most certainly is. I don't know what was going on
1905 //if (bpOverlay.boxHasBeenCreated) {
1906 // Update the infoBox timer text
1907 document.getElementById("infoBoxTimer").textContent = bpOverlay.timeText;
1908 //}
1909 }
1910 }
1911
1912 window.twitch = {
1913 emotes: {},
1914 templates: {},
1915 nonalphabetic: {},
1916 blacklist: {},
1917 };
1918
1919 // Process twitch emotes
1920 try {
1921 var globalEmotes = window.twitch_global;
1922 var subEmotes = window.twitch_subscriber;
1923 var ffzEmotes = window.ffz_emotes;
1924
1925 // TODO: Move this to a resource file somewhere
1926 var specialEmotes = {
1927 "D:": {
1928 src: "//cdn.betterttv.net/emote/55028cd2135896936880fdd7/1x",
1929 titlePrefix: "(bttv) ",
1930 },
1931 "(ditto)": {
1932 src: "//cdn.betterttv.net/emote/554da1a289d53f2d12781907/1x",
1933 titlePrefix: "(bttv) "
1934 },
1935 "FrankerZed": {
1936 src: "//cdn.frankerfacez.com/emoticon/43246/1",
1937 titlePrefix: "(ffz) ",
1938 },
1939 "WooperZ": {
1940 src: "//cdn.frankerfacez.com/emoticon/18150/1",
1941 titlePrefix: "(ffz) ",
1942 },
1943 "KevinSquirtle": {
1944 src: "//cdn.frankerfacez.com/emoticon/18146/1",
1945 titlePrefix: "(ffz) ",
1946 },
1947 "TopPika": {
1948 src: "//cdn.frankerfacez.com/emoticon/18149/1",
1949 titlePrefix: "(ffz) ",
1950 },
1951 "FrenchNerd": {
1952 src: "//cdn.frankerfacez.com/emoticon/83539/1",
1953 titlePrefix: "(ffz) ",
1954 },
1955 "DontBully": {
1956 src: "//cdn.frankerfacez.com/emoticon/34549/1",
1957 titlePrefix: "(ffz) ",
1958 },
1959 "bombb": {
1960 src: "http://iconizer.net/files/Nuvola/orig/clanbomber.png",
1961 titlePrefix: "(ffz) ",
1962 },
1963 "Gucci": {
1964 src: "http://reduction-image.com/gif-anime/temp/487025001462456603_logo.gif",
1965 titlePrefix: "(ffz) ",
1966 },
1967 ":))": {
1968 src: "http://image.jeuxvideo.com/smileys_img/1.gif",
1969 titlePrefix: "(ffz) ",
1970 },
1971 ":-)": {
1972 src: "http://image.jeuxvideo.com/smileys_img/46.gif",
1973 titlePrefix: "(ffz) ",
1974 },
1975 ":hap:": {
1976 src: "http://image.jeuxvideo.com/smileys_img/18.gif",
1977 titlePrefix: "(ffz) ",
1978 },
1979 ":-)))": {
1980 src: "http://image.jeuxvideo.com/smileys_img/23.gif",
1981 titlePrefix: "(ffz) ",
1982 },
1983 ":content:": {
1984 src: "http://image.jeuxvideo.com/smileys_img/37.gif",
1985 titlePrefix: "(ffz) ",
1986 },
1987 ":oui:": {
1988 src: "http://image.jeuxvideo.com/smileys_img/37.gif",
1989 titlePrefix: "(ffz) ",
1990 },
1991 ":cool:": {
1992 src: "http://image.jeuxvideo.com/smileys_img/26.gif",
1993 titlePrefix: "(ffz) ",
1994 },
1995 ":rire:": {
1996 src: "http://image.jeuxvideo.com/smileys_img/39.gif",
1997 titlePrefix: "(ffz) ",
1998 },
1999 ":-D": {
2000 src: "http://image.jeuxvideo.com/smileys_img/40.gif",
2001 titlePrefix: "(ffz) ",
2002 },
2003 ":rire2:": {
2004 src: "http://image.jeuxvideo.com/smileys_img/41.gif",
2005 titlePrefix: "(ffz) ",
2006 },
2007 ":o))": {
2008 src: "http://image.jeuxvideo.com/smileys_img/12.gif",
2009 titlePrefix: "(ffz) ",
2010 },
2011 ":ok:": {
2012 src: "http://image.jeuxvideo.com/smileys_img/36.gif",
2013 titlePrefix: "(ffz) ",
2014 },
2015 ":sournois:": {
2016 src: "http://image.jeuxvideo.com/smileys_img/67.gif",
2017 titlePrefix: "(ffz) ",
2018 },
2019 ":gni:": {
2020 src: "http://image.jeuxvideo.com/smileys_img/62.gif",
2021 titlePrefix: "(ffz) ",
2022 },
2023 ":merci:": {
2024 src: "http://image.jeuxvideo.com/smileys_img/58.gif",
2025 titlePrefix: "(ffz) ",
2026 },
2027 ":rechercher:": {
2028 src: "http://image.jeuxvideo.com/smileys_img/38.gif",
2029 titlePrefix: "(ffz) ",
2030 },
2031 ":gne:": {
2032 src: "http://image.jeuxvideo.com/smileys_img/51.gif",
2033 titlePrefix: "(ffz) ",
2034 },
2035 ":hs:": {
2036 src: "http://image.jeuxvideo.com/smileys_img/64.gif",
2037 titlePrefix: "(ffz) ",
2038 },
2039 ":cimer:": {
2040 src: "http://image.jeuxvideo.com/smileys_img/cimer.gif",
2041 titlePrefix: "(ffz) ",
2042 },
2043 ":siffle:": {
2044 src: "http://image.jeuxvideo.com/smileys_img/siffle.gif",
2045 titlePrefix: "(ffz) ",
2046 },
2047 ":snif:": {
2048 src: "http://image.jeuxvideo.com/smileys_img/20.gif",
2049 titlePrefix: "(ffz) ",
2050 },
2051 ":snif2:": {
2052 src: "http://image.jeuxvideo.com/smileys_img/13.gif",
2053 titlePrefix: "(ffz) ",
2054 },
2055 ":ouch:": {
2056 src: "http://image.jeuxvideo.com/smileys_img/22.gif",
2057 titlePrefix: "(ffz) ",
2058 },
2059 ":ouch2:": {
2060 src: "http://image.jeuxvideo.com/smileys_img/57.gif",
2061 titlePrefix: "(ffz) ",
2062 },
2063 ":p)": {
2064 src: "http://image.jeuxvideo.com/smileys_img/7.gif",
2065 titlePrefix: "(ffz) ",
2066 },
2067 ":((": {
2068 src: "http://image.jeuxvideo.com/smileys_img/45.gif",
2069 titlePrefix: "(ffz) ",
2070 },
2071 ":-(": {
2072 src: "http://image.jeuxvideo.com/smileys_img/14.gif",
2073 titlePrefix: "(ffz) ",
2074 },
2075 ":-((": {
2076 src: "http://image.jeuxvideo.com/smileys_img/15.gif",
2077 titlePrefix: "(ffz) ",
2078 },
2079 ":nonnon:": {
2080 src: "http://image.jeuxvideo.com/smileys_img/25.gif",
2081 titlePrefix: "(ffz) ",
2082 },
2083 ":non2:": {
2084 src: "http://image.jeuxvideo.com/smileys_img/33.gif",
2085 titlePrefix: "(ffz) ",
2086 },
2087 ":nah:": {
2088 src: "http://image.jeuxvideo.com/smileys_img/19.gif",
2089 titlePrefix: "(ffz) ",
2090 },
2091 ":non:": {
2092 src: "http://image.jeuxvideo.com/smileys_img/35.gif",
2093 titlePrefix: "(ffz) ",
2094 },
2095 ":hum:": {
2096 src: "http://image.jeuxvideo.com/smileys_img/68.gif",
2097 titlePrefix: "(ffz) ",
2098 },
2099 ":play:": {
2100 src: "http://image.jeuxvideo.com/smileys_img/play.gif",
2101 titlePrefix: "(ffz) ",
2102 },
2103 ":svp:": {
2104 src: "http://image.jeuxvideo.com/smileys_img/59.gif",
2105 titlePrefix: "(ffz) ",
2106 },
2107 ":help:": {
2108 src: "http://image.jeuxvideo.com/smileys_img/29.gif",
2109 titlePrefix: "(ffz) ",
2110 },
2111 ":lol:": {
2112 src: "http://image.jeuxvideo.com/smileys_img/32.gif",
2113 titlePrefix: "(ffz) ",
2114 },
2115 ":banzai:": {
2116 src: "http://image.jeuxvideo.com/smileys_img/70.gif",
2117 titlePrefix: "(ffz) ",
2118 },
2119 ":ddb:": {
2120 src: "http://image.jeuxvideo.com/smileys_img/ddb.gif",
2121 titlePrefix: "(ffz) ",
2122 },
2123 ":gba:": {
2124 src: "http://image.jeuxvideo.com/smileys_img/17.gif",
2125 titlePrefix: "(ffz) ",
2126 },
2127 ":bravo:": {
2128 src: "http://image.jeuxvideo.com/smileys_img/69.gif",
2129 titlePrefix: "(ffz) ",
2130 },
2131 ":pacg:": {
2132 src: "http://image.jeuxvideo.com/smileys_img/9.gif",
2133 titlePrefix: "(ffz) ",
2134 },
2135 ":pacd:": {
2136 src: "http://image.jeuxvideo.com/smileys_img/10.gif",
2137 titlePrefix: "(ffz) ",
2138 },
2139 "::-p:": {
2140 src: "http://image.jeuxvideo.com/smileys_img/31.gif",
2141 titlePrefix: "(ffz) ",
2142 },
2143 ":peur:": {
2144 src: "http://image.jeuxvideo.com/smileys_img/47.gif",
2145 titlePrefix: "(ffz) ",
2146 },
2147 ":coeur:": {
2148 src: "http://image.jeuxvideo.com/smileys_img/54.gif",
2149 titlePrefix: "(ffz) ",
2150 },
2151 ":coeur": {
2152 src: "http://image.jeuxvideo.com/smileys_img/54.gif",
2153 titlePrefix: "(ffz) ",
2154 },
2155 "coeur:": {
2156 src: "http://image.jeuxvideo.com/smileys_img/54.gif",
2157 titlePrefix: "(ffz) ",
2158 },
2159 ":fou:": {
2160 src: "http://image.jeuxvideo.com/smileys_img/50.gif",
2161 titlePrefix: "(ffz) ",
2162 },
2163 ":fier:": {
2164 src: "http://image.jeuxvideo.com/smileys_img/53.gif",
2165 titlePrefix: "(ffz) ",
2166 },
2167 ":sarcastic:": {
2168 src: "http://image.jeuxvideo.com/smileys_img/43.gif",
2169 titlePrefix: "(ffz) ",
2170 },
2171 ":doute:": {
2172 src: "http://image.jeuxvideo.com/smileys_img/28.gif",
2173 titlePrefix: "(ffz) ",
2174 },
2175 ":malade:": {
2176 src: "http://image.jeuxvideo.com/smileys_img/8.gif",
2177 titlePrefix: "(ffz) ",
2178 },
2179 ":ange:": {
2180 src: "http://image.jeuxvideo.com/smileys_img/60.gif",
2181 titlePrefix: "(ffz) ",
2182 },
2183 ":desole:": {
2184 src: "http://image.jeuxvideo.com/smileys_img/65.gif",
2185 titlePrefix: "(ffz) ",
2186 },
2187 ":sors:": {
2188 src: "http://image.jeuxvideo.com/smileys_img/56.gif",
2189 titlePrefix: "(ffz) ",
2190 },
2191 ":up:": {
2192 src: "http://image.jeuxvideo.com/smileys_img/44.gif",
2193 titlePrefix: "(ffz) ",
2194 },
2195 ":dpdr:": {
2196 src: "http://image.jeuxvideo.com/smileys_img/49.gif",
2197 titlePrefix: "(ffz) ",
2198 },
2199 ":bave:": {
2200 src: "http://image.jeuxvideo.com/smileys_img/71.gif",
2201 titlePrefix: "(ffz) ",
2202 },
2203 ":pave:": {
2204 src: "http://image.jeuxvideo.com/smileys_img/pave.gif",
2205 titlePrefix: "(ffz) ",
2206 },
2207 ":g)": {
2208 src: "http://image.jeuxvideo.com/smileys_img/3.gif",
2209 titlePrefix: "(ffz) ",
2210 },
2211 ":d)": {
2212 src: "http://image.jeuxvideo.com/smileys_img/4.gif",
2213 titlePrefix: "(ffz) ",
2214 },
2215 ":cd:": {
2216 src: "http://image.jeuxvideo.com/smileys_img/5.gif",
2217 titlePrefix: "(ffz) ",
2218 },
2219 ":cute:": {
2220 src: "http://image.jeuxvideo.com/smileys_img/nyu.gif",
2221 titlePrefix: "(ffz) ",
2222 },
2223 ":noel:": {
2224 src: "http://image.jeuxvideo.com/smileys_img/11.gif",
2225 titlePrefix: "(ffz) ",
2226 },
2227 ":question:": {
2228 src: "http://image.jeuxvideo.com/smileys_img/2.gif",
2229 titlePrefix: "(ffz) ",
2230 },
2231 ":mort:": {
2232 src: "http://image.jeuxvideo.com/smileys_img/21.gif",
2233 titlePrefix: "(ffz) ",
2234 },
2235 ":sleep:": {
2236 src: "http://image.jeuxvideo.com/smileys_img/27.gif",
2237 titlePrefix: "(ffz) ",
2238 },
2239 ":honte:": {
2240 src: "http://image.jeuxvideo.com/smileys_img/30.gif",
2241 titlePrefix: "(ffz) ",
2242 },
2243 ":monoeil:": {
2244 src: "http://image.jeuxvideo.com/smileys_img/34.gif",
2245 titlePrefix: "(ffz) ",
2246 },
2247 ":rouge:": {
2248 src: "http://image.jeuxvideo.com/smileys_img/55.gif",
2249 titlePrefix: "(ffz) ",
2250 },
2251 ":fete:": {
2252 src: "http://image.jeuxvideo.com/smileys_img/66.gif",
2253 titlePrefix: "(ffz) ",
2254 },
2255 ":diable:": {
2256 src: "http://image.jeuxvideo.com/smileys_img/61.gif",
2257 titlePrefix: "(ffz) ",
2258 },
2259 ":spoiler:": {
2260 src: "http://image.jeuxvideo.com/smileys_img/63.gif",
2261 titlePrefix: "(ffz) ",
2262 },
2263 ":salut:": {
2264 src: "http://image.jeuxvideo.com/smileys_img/42.gif",
2265 titlePrefix: "(ffz) ",
2266 },
2267 ":bye:": {
2268 src: "http://image.jeuxvideo.com/smileys_img/48.gif",
2269 titlePrefix: "(ffz) ",
2270 },
2271 ":dehors:": {
2272 src: "http://image.jeuxvideo.com/smileys_img/52.gif",
2273 titlePrefix: "(ffz) ",
2274 },
2275 ":pf:": {
2276 src: "http://image.jeuxvideo.com/smileys_img/pf.gif",
2277 titlePrefix: "(ffz) ",
2278 },
2279 ":objection:": {
2280 src: "http://image.jeuxvideo.com/smileys_img/objection.gif",
2281 titlePrefix: "(ffz) ",
2282 },
2283 ":jap:": {
2284 src: "http://image.noelshack.com/fichiers/2016/18/1462553963-mod-article46106704-4fa0eb0128fad.png",
2285 titlePrefix: "(ffz) ",
2286 },
2287 ":macadelic:": {
2288 src: "http://image.noelshack.com/fichiers/2016/18/1462642047-hpsvqdg.png",
2289 titlePrefix: "(ffz) ",
2290 },
2291 ":taka:": {
2292 src: "http://image.noelshack.com/fichiers/2016/18/1462653418-taka.png",
2293 titlePrefix: "(ffz) ",
2294 },
2295
2296 ":taka": {
2297 src: "http://image.noelshack.com/fichiers/2016/18/1462653418-taka.png",
2298 titlePrefix: "(ffz) ",
2299 },
2300
2301 "taka:": {
2302 src: "http://image.noelshack.com/fichiers/2016/18/1462653418-taka.png",
2303 titlePrefix: "(ffz) ",
2304 },
2305
2306 ":takadelic:": {
2307 src: "http://image.noelshack.com/fichiers/2016/18/1462653423-takadelic.png",
2308 titlePrefix: "(ffz) ",
2309 },
2310 "takadelic:": {
2311 src: "http://image.noelshack.com/fichiers/2016/18/1462653423-takadelic.png",
2312 titlePrefix: "(ffz) ",
2313 },
2314 ":takadelic": {
2315 src: "http://image.noelshack.com/fichiers/2016/18/1462653423-takadelic.png",
2316 titlePrefix: "(ffz) ",
2317 },
2318 "boop": {
2319 src: "http://image.noelshack.com/fichiers/2016/21/1464111387-bloggif-57448ca367db1.gif",
2320 titlePrefix: "ffz ",
2321 },
2322 "snugglebunny": {
2323 src: "http://image.noelshack.com/fichiers/2016/21/1464111385-bloggif-5744901211d82.gif",
2324 titlePrefix: "ffz ",
2325 },
2326 "8D": {
2327 src: "http://image.noelshack.com/fichiers/2016/21/1464111384-70986.jpg",
2328 titlePrefix: "ffz ",
2329 },
2330 "macadelic1": {
2331 src: "http://image.noelshack.com/fichiers/2015/01/1420405794-40f74301e597a7c482a7eda10ea18552-1.png",
2332 titlePrefix: "ffz ",
2333 },
2334 "leonarda": {
2335 src: "http://image.noelshack.com/fichiers/2015/01/1420402105-sans-titre-2.png",
2336 titlePrefix: "ffz ",
2337 },
2338 "Ddrake": {
2339 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-drake.png",
2340 titlePrefix: "(ffz) ",
2341 },
2342 "Feujitas": {
2343 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-feujitas.png",
2344 titlePrefix: "(ffz) ",
2345 },
2346 "Joo": {
2347 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-jo.png",
2348 titlePrefix: "(ffz) ",
2349 },
2350 "Jumbo": {
2351 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-jumbo.png",
2352 titlePrefix: "(ffz) ",
2353 },
2354 "Kanye": {
2355 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-kanye.png",
2356 titlePrefix: "(ffz) ",
2357 },
2358 "Kilaz": {
2359 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-kilaz.jpg",
2360 titlePrefix: "(ffz) ",
2361 },
2362 "Liaa": {
2363 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-lia.jpg",
2364 titlePrefix: "(ffz) ",
2365 },
2366 "liaa": {
2367 src: "http://image.noelshack.com/fichiers/2016/19/1463229725-liaa1.png",
2368 titlePrefix: "(ffz) ",
2369 },
2370 "Cage": {
2371 src: "http://image.noelshack.com/fichiers/2016/19/1463230710-cage.png",
2372 titlePrefix: "(ffz) ",
2373 },
2374 "Mrjo": {
2375 src: "http://image.noelshack.com/fichiers/2016/19/1462828194-merjo.png",
2376 titlePrefix: "(ffz) ",
2377 },
2378 "Nouur": {
2379 src: "http://image.noelshack.com/fichiers/2016/21/1464111744-k-ymal-patatesli-borek-buyuk.png",
2380 titlePrefix: "(ffz) ",
2381 },
2382 ":pls:": {
2383 src: "http://image.noelshack.com/fichiers/2016/19/1462828195-pls.png",
2384 titlePrefix: "(ffz) ",
2385 },
2386 "Poutine": {
2387 src: "http://image.noelshack.com/fichiers/2016/19/1462828195-poutine.png",
2388 titlePrefix: "(ffz) ",
2389 },
2390 "Poutine1": {
2391 src: "http://image.noelshack.com/fichiers/2016/19/1462828195-poutine1.png",
2392 titlePrefix: "(ffz) ",
2393 },
2394 "Wsmith": {
2395 src: "http://image.noelshack.com/fichiers/2016/19/1462828195-willsmith.png",
2396 titlePrefix: "(ffz) ",
2397 },
2398 "Juann": {
2399 src: "http://image.noelshack.com/fichiers/2016/19/1463084647-juansmiley.png",
2400 titlePrefix: "(ffz) ",
2401 },
2402 "Moustakii": {
2403 src: "http://image.noelshack.com/fichiers/2016/19/1463314479-moustaki-2.jpg",
2404 titlePrefix: "(ffz) ",
2405 },
2406 "Zebi": {
2407 src: "http://image.noelshack.com/fichiers/2016/20/1463867730-zebi.png",
2408 titlePrefix: "(ffz) ",
2409 },
2410 "Zebi1": {
2411 src: "http://image.noelshack.com/fichiers/2016/20/1463867730-zebi1.png",
2412 titlePrefix: "(ffz) ",
2413 },
2414 "Toz": {
2415 src: "http://image.noelshack.com/fichiers/2016/20/1463867730-toz.png",
2416 titlePrefix: "(ffz) ",
2417 },
2418 "Toz1": {
2419 src: "http://image.noelshack.com/fichiers/2016/20/1463867730-toz1.png",
2420 titlePrefix: "(ffz) ",
2421 },
2422 ":Loutes": {
2423 src: "http://image.noelshack.com/fichiers/2016/20/1463948080-yuno-gasai-by-yuulolita-d4v0627.png",
2424 titlePrefix: "(ffz) ",
2425 },
2426 ":Loutes:": {
2427 src: "http://image.noelshack.com/fichiers/2016/20/1463948080-yuno-gasai-by-yuulolita-d4v0627.png",
2428 titlePrefix: "(ffz) ",
2429 },
2430 "Loutes:": {
2431 src: "http://image.noelshack.com/fichiers/2016/20/1463948080-yuno-gasai-by-yuulolita-d4v0627.png",
2432 titlePrefix: "(ffz) ",
2433 },
2434 "Yuno": {
2435 src: "http://image.noelshack.com/fichiers/2016/20/1463948009-yuno.png",
2436 titlePrefix: "(ffz) ",
2437 },
2438 "Yuno1": {
2439 src: "http://image.noelshack.com/fichiers/2016/20/1463948009-yuno2.png",
2440 titlePrefix: "(ffz) ",
2441 },
2442 "Bblack": {
2443 src: "http://image.noelshack.com/fichiers/2016/21/1464111387-bloggif-57448be1c65a1.gif",
2444 titlePrefix: "(ffz) ",
2445 },
2446 "Kfc": {
2447 src: "http://image.noelshack.com/fichiers/2016/21/1464111386-bloggif-57448cf99fbeb.gif",
2448 titlePrefix: "(ffz) ",
2449 },
2450 "Monkey": {
2451 src: "http://image.noelshack.com/fichiers/2016/21/1464111388-bloggif-57448f5120140.gif",
2452 titlePrefix: "(ffz) ",
2453 },
2454 "Yaroo": {
2455 src: "http://image.noelshack.com/fichiers/2016/21/1464111385-boucher.jpg",
2456 titlePrefix: "(ffz) ",
2457 },
2458 ":Yaroo": {
2459 src: "http://image.noelshack.com/fichiers/2016/21/1464111385-boucher1-copie.png",
2460 titlePrefix: "(ffz) ",
2461 },
2462 ":Yaroo:": {
2463 src: "http://image.noelshack.com/fichiers/2016/21/1464111385-boucher1-copie.png",
2464 titlePrefix: "(ffz) ",
2465 },
2466 "Yaroo:": {
2467 src: "http://image.noelshack.com/fichiers/2016/21/1464111385-boucher1-copie.png",
2468 titlePrefix: "(ffz) ",
2469 },
2470 "KOO": {
2471 src: "http://image.noelshack.com/fichiers/2016/21/1464111391-ko.gif",
2472 titlePrefix: "(ffz) ",
2473 },
2474 "LeoBlack": {
2475 src: "http://image.noelshack.com/fichiers/2016/21/1464111386-leob.png",
2476 titlePrefix: "(ffz) ",
2477 },
2478 "LeoThug": {
2479 src: "http://image.noelshack.com/fichiers/2016/21/1464111386-leothug.png",
2480 titlePrefix: "(ffz) ",
2481 },
2482 "Snoop": {
2483 src: "http://image.noelshack.com/fichiers/2016/21/1464111388-snoop.gif",
2484 titlePrefix: "(ffz) ",
2485 },
2486 "Snoopy": {
2487 src: "http://image.noelshack.com/fichiers/2016/21/1464111388-snoop.gif",
2488 titlePrefix: "(ffz) ",
2489 },
2490 "snoop": {
2491 src: "http://image.noelshack.com/fichiers/2016/21/1464111388-snoop.gif",
2492 titlePrefix: "(ffz) ",
2493 },
2494 "ZbubZbub": {
2495 src: "http://image.noelshack.com/fichiers/2016/21/1464111672-img-23052016-183254.png",
2496 titlePrefix: "(ffz) ",
2497 },
2498 "Bbus": {
2499 src: "http://image.noelshack.com/fichiers/2016/21/1464195638-04e264960511a17a1c71af0e183ef029.gif",
2500 titlePrefix: "(ffz) ",
2501 },
2502 "Ppenis": {
2503 src: "http://image.noelshack.com/fichiers/2016/21/1464195630-aaaaah.gif",
2504 titlePrefix: "(ffz) ",
2505 },
2506 "AsianMoney": {
2507 src: "http://image.noelshack.com/fichiers/2016/21/1464195633-asianmoney.gif",
2508 titlePrefix: "(ffz) ",
2509 },
2510 ":Sarah:": {
2511 src: "http://image.noelshack.com/fichiers/2016/21/1464195615-bbible.jpeg",
2512 titlePrefix: "(ffz) ",
2513 },
2514 ":Sarah": {
2515 src: "http://image.noelshack.com/fichiers/2016/21/1464195615-bbible.jpeg",
2516 titlePrefix: "(ffz) ",
2517 },
2518 "Sarah:": {
2519 src: "http://image.noelshack.com/fichiers/2016/21/1464195615-bbible.jpeg",
2520 titlePrefix: "(ffz) ",
2521 },
2522 "DeadPaul": {
2523 src: "http://image.noelshack.com/fichiers/2016/21/1464195616-deadpaul.jpeg",
2524 titlePrefix: "(ffz) ",
2525 },
2526 "DjKromozom": {
2527 src: "http://image.noelshack.com/fichiers/2016/21/1464195640-djchromozom.gif",
2528 titlePrefix: "(ffz) ",
2529 },
2530 "DjChromozom": {
2531 src: "http://image.noelshack.com/fichiers/2016/21/1464195640-djchromozom.gif",
2532 titlePrefix: "(ffz) ",
2533 },
2534 "DjChromozome": {
2535 src: "http://image.noelshack.com/fichiers/2016/21/1464195640-djchromozom.gif",
2536 titlePrefix: "(ffz) ",
2537 },
2538 "DjChromosome": {
2539 src: "http://image.noelshack.com/fichiers/2016/21/1464195640-djchromozom.gif",
2540 titlePrefix: "(ffz) ",
2541 },
2542 "EbolusRift": {
2543 src: "http://image.noelshack.com/fichiers/2016/21/1464195616-ebolusrift.jpeg",
2544 titlePrefix: "(ffz) ",
2545 },
2546 "Jeezus": {
2547 src: "http://image.noelshack.com/fichiers/2016/21/1464195631-jeezus.gif",
2548 titlePrefix: "(ffz) ",
2549 },
2550 "Equality": {
2551 src: "http://image.noelshack.com/fichiers/2016/21/1464195637-noirzer.gif",
2552 titlePrefix: "(ffz) ",
2553 },
2554 "PokePoke": {
2555 src: "http://image.noelshack.com/fichiers/2016/21/1464195635-pokepoke.gif",
2556 titlePrefix: "(ffz) ",
2557 },
2558 "Alex76": {
2559 src: "http://i.imgur.com/m7wLKbt.png",
2560 titlePrefix: "(ffz) ",
2561 },
2562 "Amandine38": {
2563 src: "http://i.imgur.com/Xg6ap4b.png",
2564 titlePrefix: "(ffz) ",
2565 },
2566
2567 "Atoz": {
2568 src: "http://img.prntscr.com/img?url=http://i.imgur.com/XBEl0BE.png",
2569 titlePrefix: "(ffz) ",
2570 },
2571 "2Legging": {
2572 src: "http://image.noelshack.com/fichiers/2016/21/1464197633-b9aead2849dc4ecc59899e3b312878d6.png",
2573 titlePrefix: "(ffz) ",
2574 },
2575 "German": {
2576 src: "http://image.noelshack.com/fichiers/2016/21/1464198083-german.gif",
2577 titlePrefix: "(ffz) ",
2578 },
2579 "SuicidHelp": {
2580 src: "http://image.noelshack.com/fichiers/2016/21/1464198412-suicidhelp.gif",
2581 titlePrefix: "(ffz) ",
2582 },
2583 "TheRefugees": {
2584 src: "http://image.noelshack.com/fichiers/2016/21/1464198627-therefugees.jpeg",
2585 titlePrefix: "(ffz) ",
2586 },
2587 "LeaEtSesPotesAuParc": {
2588 src: "http://image.noelshack.com/fichiers/2016/21/1464198538-leaetsespotesauparc.gif",
2589 titlePrefix: "(ffz) ",
2590 },
2591 "AngryMittens": {
2592src: "https://emotes.tastycat.org/emotes/cats/AngryMittens.png",
2593titlePrefix: "ffz ",
2594},
2595"Basssss": {
2596src: "https://emotes.tastycat.org/emotes/cats/Basssss.png",
2597titlePrefix: "ffz ",
2598},
2599"BoopBlock": {
2600src: "https://emotes.tastycat.org/emotes/cats/BoopBlock.png",
2601titlePrefix: "ffz ",
2602},
2603"BoopInc": {
2604src: "https://emotes.tastycat.org/emotes/cats/BoopInc.png",
2605titlePrefix: "ffz ",
2606},
2607"Brushy": {
2608src: "https://emotes.tastycat.org/emotes/cats/Brushy.gif",
2609titlePrefix: "ffz ",
2610},
2611"Buggu": {
2612src: "https://emotes.tastycat.org/emotes/cats/Buggu.png",
2613titlePrefix: "ffz ",
2614},
2615"CatWink": {
2616src: "https://emotes.tastycat.org/emotes/cats/CatWink.png",
2617titlePrefix: "ffz ",
2618},
2619"ChillCat": {
2620src: "https://emotes.tastycat.org/emotes/cats/ChillCat.gif",
2621titlePrefix: "ffz ",
2622},
2623"Despair2": {
2624src: "https://emotes.tastycat.org/emotes/cats/Despair2.png",
2625titlePrefix: "ffz ",
2626},
2627"DontEven": {
2628src: "https://emotes.tastycat.org/emotes/cats/DontEven.png",
2629titlePrefix: "ffz ",
2630},
2631"FatCat": {
2632src: "https://emotes.tastycat.org/emotes/cats/FatCat.png",
2633titlePrefix: "ffz ",
2634},
2635"Gasp": {
2636src: "https://emotes.tastycat.org/emotes/cats/Gasp.png",
2637titlePrefix: "ffz ",
2638},
2639"Gasp2": {
2640src: "https://emotes.tastycat.org/emotes/cats/Gasp2.png",
2641titlePrefix: "ffz ",
2642},
2643"Gasp3": {
2644src: "https://emotes.tastycat.org/emotes/cats/Gasp3.png",
2645titlePrefix: "ffz ",
2646},
2647"Gasp420": {
2648src: "https://emotes.tastycat.org/emotes/cats/Gasp420.png",
2649titlePrefix: "ffz ",
2650},
2651"Gasp5": {
2652src: "https://emotes.tastycat.org/emotes/cats/Gasp5.png",
2653titlePrefix: "ffz ",
2654},
2655"Gasp6": {
2656src: "https://emotes.tastycat.org/emotes/cats/Gasp6.png",
2657titlePrefix: "ffz ",
2658},
2659"Gasp7": {
2660src: "https://emotes.tastycat.org/emotes/cats/Gasp7.png",
2661titlePrefix: "ffz ",
2662},
2663"Grumpy": {
2664src: "https://emotes.tastycat.org/emotes/cats/Grumpy.png",
2665titlePrefix: "ffz ",
2666},
2667"HKitty": {
2668src: "https://emotes.tastycat.org/emotes/cats/HKitty.gif",
2669titlePrefix: "ffz ",
2670},
2671"HatersGonnaHate": {
2672src: "https://emotes.tastycat.org/emotes/cats/HatersGonnaHate.gif",
2673titlePrefix: "ffz ",
2674},
2675"HighCat": {
2676src: "https://emotes.tastycat.org/emotes/cats/HighCat.gif",
2677titlePrefix: "ffz ",
2678},
2679"KittyPalm": {
2680src: "https://emotes.tastycat.org/emotes/cats/KittyPalm.png",
2681titlePrefix: "ffz ",
2682},
2683"NyanCat": {
2684src: "https://emotes.tastycat.org/emotes/cats/NyanCat.gif",
2685titlePrefix: "ffz ",
2686},
2687"OMG": {
2688src: "https://emotes.tastycat.org/emotes/cats/OMG.png",
2689titlePrefix: "ffz ",
2690},
2691"Puss": {
2692src: "https://emotes.tastycat.org/emotes/cats/Puss.png",
2693titlePrefix: "ffz ",
2694},
2695"PizzaCat": {
2696src: "https://emotes.tastycat.org/emotes/cats/PizzaCat.png",
2697titlePrefix: "ffz ",
2698},
2699"Sadness": {
2700src: "https://emotes.tastycat.org/emotes/cats/Sadness.png",
2701titlePrefix: "ffz ",
2702},
2703"SayWhat": {
2704src: "https://emotes.tastycat.org/emotes/cats/SayWhat.png",
2705titlePrefix: "ffz ",
2706},
2707"ShadyCat": {
2708src: "https://emotes.tastycat.org/emotes/cats/ShadyCat.png",
2709titlePrefix: "ffz ",
2710},
2711"Skrillbug": {
2712src: "https://emotes.tastycat.org/emotes/cats/Skrillbug.png",
2713titlePrefix: "ffz ",
2714},
2715"SmartCat": {
2716src: "https://emotes.tastycat.org/emotes/cats/SmartCat.png",
2717titlePrefix: "ffz ",
2718},
2719"Smug": {
2720src: "https://emotes.tastycat.org/emotes/cats/Smug.png",
2721titlePrefix: "ffz ",
2722},
2723"SpazCat": {
2724src: "https://emotes.tastycat.org/emotes/cats/SpazCat.gif",
2725titlePrefix: "ffz ",
2726},
2727"Wilson": {
2728src: "https://emotes.tastycat.org/emotes/cats/Wilson.png",
2729titlePrefix: "ffz ",
2730},
2731"Yaaay": {
2732src: "https://emotes.tastycat.org/emotes/cats/Yaaay.gif",
2733titlePrefix: "ffz ",
2734},
2735"3LAU": {
2736src: "https://emotes.tastycat.org/emotes/logos/3LAU.png",
2737titlePrefix: "ffz ",
2738},
2739"7MD": {
2740src: "https://emotes.tastycat.org/emotes/logos/7MD.png",
2741titlePrefix: "ffz ",
2742},
2743"ASOT": {
2744src: "https://emotes.tastycat.org/emotes/logos/ASOT.png",
2745titlePrefix: "ffz ",
2746},
2747"ATB": {
2748src: "https://emotes.tastycat.org/emotes/logos/ATB.png",
2749titlePrefix: "ffz ",
2750},
2751"AVB": {
2752src: "https://emotes.tastycat.org/emotes/logos/AVB.png",
2753titlePrefix: "ffz ",
2754},
2755"AZEDIA": {
2756src: "https://emotes.tastycat.org/emotes/logos/AZEDIA.png",
2757titlePrefix: "ffz ",
2758},
2759"Above&Beyond": {
2760src: "https://emotes.tastycat.org/emotes/logos/Above_and_Beyond.png",
2761titlePrefix: "ffz ",
2762},
2763"Adri": {
2764src: "https://emotes.tastycat.org/emotes/logos/Adri.png",
2765titlePrefix: "ffz ",
2766},
2767"AdventureClub": {
2768src: "https://emotes.tastycat.org/emotes/logos/AdventureClub.png",
2769titlePrefix: "ffz ",
2770},
2771"AeroChord": {
2772src: "https://emotes.tastycat.org/emotes/logos/AeroChord.png",
2773titlePrefix: "ffz ",
2774},
2775"Afrojack": {
2776src: "https://emotes.tastycat.org/emotes/logos/Afrojack.png",
2777titlePrefix: "ffz ",
2778},
2779"ActingDamage": {
2780src: "https://emotes.tastycat.org/emotes/logos/ActingDamage.png",
2781titlePrefix: "ffz ",
2782},
2783"AlexMORPH": {
2784src: "https://emotes.tastycat.org/emotes/logos/AlexMORPH.png",
2785titlePrefix: "ffz ",
2786},
2787"AlexanderPBN": {
2788src: "https://emotes.tastycat.org/emotes/logos/AlexanderPBN.png",
2789titlePrefix: "ffz ",
2790},
2791"AlphaVibez": {
2792src: "https://emotes.tastycat.org/emotes/logos/AlphaVibez.png",
2793titlePrefix: "ffz ",
2794},
2795"Anamanaguchi": {
2796src: "https://emotes.tastycat.org/emotes/logos/Anamanaguchi.png",
2797titlePrefix: "ffz ",
2798},
2799"AndrewRayel": {
2800src: "https://emotes.tastycat.org/emotes/logos/AndrewRayel.png",
2801titlePrefix: "ffz ",
2802},
2803"Anjunabeats": {
2804src: "https://emotes.tastycat.org/emotes/logos/Anjunabeats.png",
2805titlePrefix: "ffz ",
2806},
2807"ApproachingNirvana": {
2808src: "https://emotes.tastycat.org/emotes/logos/ApproachingNirvana.png",
2809titlePrefix: "ffz ",
2810},
2811"Archie": {
2812src: "https://emotes.tastycat.org/emotes/logos/Archie.png",
2813titlePrefix: "ffz ",
2814},
2815"Apashe": {
2816src: "https://emotes.tastycat.org/emotes/logos/Apashe.png",
2817titlePrefix: "ffz ",
2818},
2819"Arion": {
2820src: "https://emotes.tastycat.org/emotes/logos/Arion.png",
2821titlePrefix: "ffz ",
2822},
2823"Armada": {
2824src: "https://emotes.tastycat.org/emotes/logos/Armada.png",
2825titlePrefix: "ffz ",
2826},
2827"Arty": {
2828src: "https://emotes.tastycat.org/emotes/logos/Arty.png",
2829titlePrefix: "ffz ",
2830},
2831"Astronaut": {
2832src: "https://emotes.tastycat.org/emotes/logos/Astronaut.png",
2833titlePrefix: "ffz ",
2834},
2835"Atmozfears": {
2836src: "https://emotes.tastycat.org/emotes/logos/Atmozfears.png",
2837titlePrefix: "ffz ",
2838},
2839"Au5": {
2840src: "https://emotes.tastycat.org/emotes/logos/Au5.png",
2841titlePrefix: "ffz ",
2842},
2843"Audien": {
2844src: "https://emotes.tastycat.org/emotes/logos/Audien.png",
2845titlePrefix: "ffz ",
2846},
2847"Auratic": {
2848src: "https://emotes.tastycat.org/emotes/logos/Auratic.png",
2849titlePrefix: "ffz ",
2850},
2851"Autolaser": {
2852src: "https://emotes.tastycat.org/emotes/logos/Autolaser.png",
2853titlePrefix: "ffz ",
2854},
2855"Auvic": {
2856src: "https://emotes.tastycat.org/emotes/logos/Auvic.png",
2857titlePrefix: "ffz ",
2858},
2859"Avicii": {
2860src: "https://emotes.tastycat.org/emotes/logos/Avicii.png",
2861titlePrefix: "ffz ",
2862},
2863"BMotion": {
2864src: "https://emotes.tastycat.org/emotes/logos/BMotion.png",
2865titlePrefix: "ffz ",
2866},
2867"BT": {
2868src: "https://emotes.tastycat.org/emotes/logos/BT.png",
2869titlePrefix: "ffz ",
2870},
2871"BTSM": {
2872src: "https://emotes.tastycat.org/emotes/logos/BTSM.png",
2873titlePrefix: "ffz ",
2874},
2875"BachelorsOfScience": {
2876src: "https://emotes.tastycat.org/emotes/logos/BachelorsOfScience.png",
2877titlePrefix: "ffz ",
2878},
2879"BarelyAlive": {
2880src: "https://emotes.tastycat.org/emotes/logos/BarelyAlive.png",
2881titlePrefix: "ffz ",
2882},
2883"BasementMusic": {
2884src: "https://emotes.tastycat.org/emotes/logos/BasementMusic.png",
2885titlePrefix: "ffz ",
2886},
2887"BassCity": {
2888src: "https://emotes.tastycat.org/emotes/logos/BassCity.png",
2889titlePrefix: "ffz ",
2890},
2891"BassNation": {
2892src: "https://emotes.tastycat.org/emotes/logos/BassNation.png",
2893titlePrefix: "ffz ",
2894},
2895"Bassnectar": {
2896src: "https://emotes.tastycat.org/emotes/logos/Bassnectar.png",
2897titlePrefix: "ffz ",
2898},
2899"Bcee": {
2900src: "https://emotes.tastycat.org/emotes/logos/Bcee.png",
2901titlePrefix: "ffz ",
2902},
2903"BingoPlayers": {
2904src: "https://emotes.tastycat.org/emotes/logos/BingoPlayers.png",
2905titlePrefix: "ffz ",
2906},
2907"Bitclic": {
2908src: "https://emotes.tastycat.org/emotes/logos/Bitclic.png",
2909titlePrefix: "ffz ",
2910},
2911"BombsAway": {
2912src: "https://emotes.tastycat.org/emotes/logos/BombsAway.png",
2913titlePrefix: "ffz ",
2914},
2915"Borgeous": {
2916src: "https://emotes.tastycat.org/emotes/logos/Borgeous.png",
2917titlePrefix: "ffz ",
2918},
2919"Borgore": {
2920src: "https://emotes.tastycat.org/emotes/logos/Borgore.png",
2921titlePrefix: "ffz ",
2922},
2923"Botnek": {
2924src: "https://emotes.tastycat.org/emotes/logos/Botnek.png",
2925titlePrefix: "ffz ",
2926},
2927"Braken": {
2928src: "https://emotes.tastycat.org/emotes/logos/Braken.png",
2929titlePrefix: "ffz ",
2930},
2931"BrookesBrothers": {
2932src: "https://emotes.tastycat.org/emotes/logos/BrookesBrothers.png",
2933titlePrefix: "ffz ",
2934},
2935"Bustre": {
2936src: "https://emotes.tastycat.org/emotes/logos/Bustre.png",
2937titlePrefix: "ffz ",
2938},
2939"CalvinHarris": {
2940src: "https://emotes.tastycat.org/emotes/logos/CalvinHarris.png",
2941titlePrefix: "ffz ",
2942},
2943"Camo&Krooked": {
2944src: "https://emotes.tastycat.org/emotes/logos/Camo_and_Krooked.png",
2945titlePrefix: "ffz ",
2946},
2947"CarlCox": {
2948src: "https://emotes.tastycat.org/emotes/logos/CarlCox.png",
2949titlePrefix: "ffz ",
2950},
2951"Cartoon": {
2952src: "https://emotes.tastycat.org/emotes/logos/Cartoon.png",
2953titlePrefix: "ffz ",
2954},
2955"Case&Point": {
2956src: "https://emotes.tastycat.org/emotes/logos/Case_and_Point.png",
2957titlePrefix: "ffz ",
2958},
2959"CashCash": {
2960src: "https://emotes.tastycat.org/emotes/logos/CashCash.png",
2961titlePrefix: "ffz ",
2962},
2963"Cazzette": {
2964src: "https://emotes.tastycat.org/emotes/logos/Cazzette.png",
2965titlePrefix: "ffz ",
2966},
2967"Celldweller": {
2968src: "https://emotes.tastycat.org/emotes/logos/Celldweller.png",
2969titlePrefix: "ffz ",
2970},
2971"Chainsmokers": {
2972src: "https://emotes.tastycat.org/emotes/logos/Chainsmokers.png",
2973titlePrefix: "ffz ",
2974},
2975"Champion": {
2976src: "https://emotes.tastycat.org/emotes/logos/Champion.png",
2977titlePrefix: "ffz ",
2978},
2979"Chase&Status": {
2980src: "https://emotes.tastycat.org/emotes/logos/Chase_and_Status.png",
2981titlePrefix: "ffz ",
2982},
2983"ChemicalBrothers": {
2984src: "https://emotes.tastycat.org/emotes/logos/ChemicalBrothers.png",
2985titlePrefix: "ffz ",
2986},
2987"ChillAndTrap": {
2988src: "https://emotes.tastycat.org/emotes/logos/ChillAndTrap.png",
2989titlePrefix: "ffz ",
2990},
2991"ChillCity": {
2992src: "https://emotes.tastycat.org/emotes/logos/ChillCity.png",
2993titlePrefix: "ffz ",
2994},
2995"ChillNation": {
2996src: "https://emotes.tastycat.org/emotes/logos/ChillNation.png",
2997titlePrefix: "ffz ",
2998},
2999"ChrisRamos": {
3000src: "https://emotes.tastycat.org/emotes/logos/ChrisRamos.png",
3001titlePrefix: "ffz ",
3002},
3003"ClosedEyes": {
3004src: "https://emotes.tastycat.org/emotes/logos/ClosedEyes.png",
3005titlePrefix: "ffz ",
3006},
3007"ConcordDawn": {
3008src: "https://emotes.tastycat.org/emotes/logos/ConcordDawn.png",
3009titlePrefix: "ffz ",
3010},
3011"CoyoteKisses": {
3012src: "https://emotes.tastycat.org/emotes/logos/CoyoteKisses.png",
3013titlePrefix: "ffz ",
3014},
3015"Cryptex": {
3016src: "https://emotes.tastycat.org/emotes/logos/Cryptex.png",
3017titlePrefix: "ffz ",
3018},
3019"CyberPixl": {
3020src: "https://emotes.tastycat.org/emotes/logos/CyberPixl.png",
3021titlePrefix: "ffz ",
3022},
3023"DGM": {
3024src: "https://emotes.tastycat.org/emotes/logos/DGM.png",
3025titlePrefix: "ffz ",
3026},
3027"DJFresh": {
3028src: "https://emotes.tastycat.org/emotes/logos/DJFresh.png",
3029titlePrefix: "ffz ",
3030},
3031"DVBBS": {
3032src: "https://emotes.tastycat.org/emotes/logos/DVBBS.png",
3033titlePrefix: "ffz ",
3034},
3035"DaTweekaz": {
3036src: "https://emotes.tastycat.org/emotes/logos/DaTweekaz.png",
3037titlePrefix: "ffz ",
3038},
3039"DadaLife": {
3040src: "https://emotes.tastycat.org/emotes/logos/DadaLife.png",
3041titlePrefix: "ffz ",
3042},
3043"DaftPunk": {
3044src: "https://emotes.tastycat.org/emotes/logos/DaftPunk.png",
3045titlePrefix: "ffz ",
3046},
3047"DaftPunkGuy": {
3048src: "https://emotes.tastycat.org/emotes/logos/DaftPunkGuy.png",
3049titlePrefix: "ffz ",
3050},
3051"DaftPunkThomas": {
3052src: "https://emotes.tastycat.org/emotes/logos/DaftPunkThomas.png",
3053titlePrefix: "ffz ",
3054},
3055"Dannic": {
3056src: "https://emotes.tastycat.org/emotes/logos/Dannic.png",
3057titlePrefix: "ffz ",
3058},
3059"DannyByrd": {
3060src: "https://emotes.tastycat.org/emotes/logos/DannyByrd.png",
3061titlePrefix: "ffz ",
3062},
3063"DarrenStyles": {
3064src: "https://emotes.tastycat.org/emotes/logos/DarrenStyles.png",
3065titlePrefix: "ffz ",
3066},
3067"DashBerlin": {
3068src: "https://emotes.tastycat.org/emotes/logos/DashBerlin.png",
3069titlePrefix: "ffz ",
3070},
3071"Datsik": {
3072src: "https://emotes.tastycat.org/emotes/logos/Datsik.png",
3073titlePrefix: "ffz ",
3074},
3075"DavidQuinn": {
3076src: "https://emotes.tastycat.org/emotes/logos/DavidQuinn.png",
3077titlePrefix: "ffz ",
3078},
3079"DayOne": {
3080src: "https://emotes.tastycat.org/emotes/logos/DayOne.png",
3081titlePrefix: "ffz ",
3082},
3083"Deadmau5": {
3084src: "https://emotes.tastycat.org/emotes/logos/Deadmau5.png",
3085titlePrefix: "ffz ",
3086},
3087"Defqon1": {
3088src: "https://emotes.tastycat.org/emotes/logos/Defqon1.png",
3089titlePrefix: "ffz ",
3090},
3091"DeltaHeavy": {
3092src: "https://emotes.tastycat.org/emotes/logos/DeltaHeavy.png",
3093titlePrefix: "ffz ",
3094},
3095"Deorro": {
3096src: "https://emotes.tastycat.org/emotes/logos/Deorro.png",
3097titlePrefix: "ffz ",
3098},
3099"Deutgen": {
3100src: "https://emotes.tastycat.org/emotes/logos/Deutgen.png",
3101titlePrefix: "ffz ",
3102},
3103"Dexcell": {
3104src: "https://emotes.tastycat.org/emotes/logos/Dexcell.png",
3105titlePrefix: "ffz ",
3106},
3107"DillonFrancis": {
3108src: "https://emotes.tastycat.org/emotes/logos/DillonFrancis.png",
3109titlePrefix: "ffz ",
3110},
3111"DillonFrancisFace": {
3112src: "https://emotes.tastycat.org/emotes/logos/DillonFrancisFace.png",
3113titlePrefix: "ffz ",
3114},
3115"Diplo": {
3116src: "https://emotes.tastycat.org/emotes/logos/Diplo.png",
3117titlePrefix: "ffz ",
3118},
3119"Direct": {
3120src: "https://emotes.tastycat.org/emotes/logos/Direct.png",
3121titlePrefix: "ffz ",
3122},
3123"Dirtyphonics": {
3124src: "https://emotes.tastycat.org/emotes/logos/Dirtyphonics.png",
3125titlePrefix: "ffz ",
3126},
3127"Disclosure": {
3128src: "https://emotes.tastycat.org/emotes/logos/Disclosure.png",
3129titlePrefix: "ffz ",
3130},
3131"Diskord": {
3132src: "https://emotes.tastycat.org/emotes/logos/Diskord.png",
3133titlePrefix: "ffz ",
3134},
3135"DnbPortal": {
3136src: "https://emotes.tastycat.org/emotes/logos/DnbPortal.png",
3137titlePrefix: "ffz ",
3138},
3139"DonDiablo": {
3140src: "https://emotes.tastycat.org/emotes/logos/DonDiablo.png",
3141titlePrefix: "ffz ",
3142},
3143"DonDiablo2": {
3144src: "https://emotes.tastycat.org/emotes/logos/DonDiablo2.png",
3145titlePrefix: "ffz ",
3146},
3147"DotEXE": {
3148src: "https://emotes.tastycat.org/emotes/logos/DotEXE.png",
3149titlePrefix: "ffz ",
3150},
3151"Draper": {
3152src: "https://emotes.tastycat.org/emotes/logos/Draper.png",
3153titlePrefix: "ffz ",
3154},
3155"DropTheBassline": {
3156src: "https://emotes.tastycat.org/emotes/logos/DropTheBassline.png",
3157titlePrefix: "ffz ",
3158},
3159"Droptek": {
3160src: "https://emotes.tastycat.org/emotes/logos/Droptek.png",
3161titlePrefix: "ffz ",
3162},
3163"Dubwoofer": {
3164src: "https://emotes.tastycat.org/emotes/logos/Dubwoofer.png",
3165titlePrefix: "ffz ",
3166},
3167"DukeDumont": {
3168src: "https://emotes.tastycat.org/emotes/logos/DukeDumont.png",
3169titlePrefix: "ffz ",
3170},
3171"Dyro": {
3172src: "https://emotes.tastycat.org/emotes/logos/Dyro.png",
3173titlePrefix: "ffz ",
3174},
3175"EDMCity": {
3176src: "https://emotes.tastycat.org/emotes/logos/EDMCity.png",
3177titlePrefix: "ffz ",
3178},
3179"EDMNetwork": {
3180src: "https://emotes.tastycat.org/emotes/logos/EDMNetwork.png",
3181titlePrefix: "ffz ",
3182},
3183"EH!DE": {
3184src: "https://emotes.tastycat.org/emotes/logos/EH_bang_DE.png",
3185titlePrefix: "ffz ",
3186},
3187"ElectrostepNation": {
3188src: "https://emotes.tastycat.org/emotes/logos/ElectrostepNation.png",
3189titlePrefix: "ffz ",
3190},
3191"ElectrostepNetwork": {
3192src: "https://emotes.tastycat.org/emotes/logos/ElectrostepNetwork.png",
3193titlePrefix: "ffz ",
3194},
3195"Elephante": {
3196src: "https://emotes.tastycat.org/emotes/logos/Elephante.png",
3197titlePrefix: "ffz ",
3198},
3199"ElysianRecords": {
3200src: "https://emotes.tastycat.org/emotes/logos/ElysianRecords.png",
3201titlePrefix: "ffz ",
3202},
3203"Eminence": {
3204src: "https://emotes.tastycat.org/emotes/logos/Eminence.png",
3205titlePrefix: "ffz ",
3206},
3207"Ephixa": {
3208src: "https://emotes.tastycat.org/emotes/logos/Ephixa.png",
3209titlePrefix: "ffz ",
3210},
3211"Eptic": {
3212src: "https://emotes.tastycat.org/emotes/logos/Eptic.png",
3213titlePrefix: "ffz ",
3214},
3215"EpticRobot": {
3216src: "https://emotes.tastycat.org/emotes/logos/EpticRobot.png",
3217titlePrefix: "ffz ",
3218},
3219"EricPrydz": {
3220src: "https://emotes.tastycat.org/emotes/logos/EricPrydz.png",
3221titlePrefix: "ffz ",
3222},
3223"Excision": {
3224src: "https://emotes.tastycat.org/emotes/logos/Excision.png",
3225titlePrefix: "ffz ",
3226},
3227"FOOL": {
3228src: "https://emotes.tastycat.org/emotes/logos/FOOL.png",
3229titlePrefix: "ffz ",
3230},
3231"FarTooLoud": {
3232src: "https://emotes.tastycat.org/emotes/logos/FarTooLoud.png",
3233titlePrefix: "ffz ",
3234},
3235"Favright": {
3236src: "https://emotes.tastycat.org/emotes/logos/Favright.png",
3237titlePrefix: "ffz ",
3238},
3239"FavrightFace": {
3240src: "https://emotes.tastycat.org/emotes/logos/FavrightFace.png",
3241titlePrefix: "ffz ",
3242},
3243"FeedMe": {
3244src: "https://emotes.tastycat.org/emotes/logos/FeedMe.png",
3245titlePrefix: "ffz ",
3246},
3247"Feint": {
3248src: "https://emotes.tastycat.org/emotes/logos/Feint.png",
3249titlePrefix: "ffz ",
3250},
3251"FerryCorsten": {
3252src: "https://emotes.tastycat.org/emotes/logos/FerryCorsten.png",
3253titlePrefix: "ffz ",
3254},
3255"FijiWiji": {
3256src: "https://emotes.tastycat.org/emotes/logos/FijiWiji.png",
3257titlePrefix: "ffz ",
3258},
3259"FijiWijiBag": {
3260src: "https://emotes.tastycat.org/emotes/logos/FijiWijiBag.png",
3261titlePrefix: "ffz ",
3262},
3263"Flite": {
3264src: "https://emotes.tastycat.org/emotes/logos/Flite.png",
3265titlePrefix: "ffz ",
3266},
3267"Fliwo": {
3268src: "https://emotes.tastycat.org/emotes/logos/Fliwo.png",
3269titlePrefix: "ffz ",
3270},
3271"Flume": {
3272src: "https://emotes.tastycat.org/emotes/logos/Flume.png",
3273titlePrefix: "ffz ",
3274},
3275"FluxPavilion": {
3276src: "https://emotes.tastycat.org/emotes/logos/FluxPavilion.png",
3277titlePrefix: "ffz ",
3278},
3279"Fono": {
3280src: "https://emotes.tastycat.org/emotes/logos/Fono.png",
3281titlePrefix: "ffz ",
3282},
3283"FoxStevenson": {
3284src: "https://emotes.tastycat.org/emotes/logos/FoxStevenson.png",
3285titlePrefix: "ffz ",
3286},
3287"FoxStevenson2": {
3288src: "https://emotes.tastycat.org/emotes/logos/FoxStevenson2.png",
3289titlePrefix: "ffz ",
3290},
3291"Foxsky": {
3292src: "https://emotes.tastycat.org/emotes/logos/Foxsky.png",
3293titlePrefix: "ffz ",
3294},
3295"Fractal": {
3296src: "https://emotes.tastycat.org/emotes/logos/Fractal.png",
3297titlePrefix: "ffz ",
3298},
3299"Frantix": {
3300src: "https://emotes.tastycat.org/emotes/logos/Frantix.png",
3301titlePrefix: "ffz ",
3302},
3303"FredV&Grafix": {
3304src: "https://emotes.tastycat.org/emotes/logos/FredV_and_Grafix.png",
3305titlePrefix: "ffz ",
3306},
3307"Frontliner": {
3308src: "https://emotes.tastycat.org/emotes/logos/Frontliner.png",
3309titlePrefix: "ffz ",
3310},
3311"FunkyPanda": {
3312src: "https://emotes.tastycat.org/emotes/logos/FunkyPanda.png",
3313titlePrefix: "ffz ",
3314},
3315"FutureCity": {
3316src: "https://emotes.tastycat.org/emotes/logos/FutureCity.png",
3317titlePrefix: "ffz ",
3318},
3319"GUARD1AN": {
3320src: "https://emotes.tastycat.org/emotes/logos/GUARD1AN.png",
3321titlePrefix: "ffz ",
3322},
3323"Galantis": {
3324src: "https://emotes.tastycat.org/emotes/logos/Galantis.png",
3325titlePrefix: "ffz ",
3326},
3327"GalaxyMusic": {
3328src: "https://emotes.tastycat.org/emotes/logos/GalaxyMusic.png",
3329titlePrefix: "ffz ",
3330},
3331"Gammer": {
3332src: "https://emotes.tastycat.org/emotes/logos/Gammer.png",
3333titlePrefix: "ffz ",
3334},
3335"GarethEmery": {
3336src: "https://emotes.tastycat.org/emotes/logos/GarethEmery.png",
3337titlePrefix: "ffz ",
3338},
3339"Gemini": {
3340src: "https://emotes.tastycat.org/emotes/logos/Gemini.png",
3341titlePrefix: "ffz ",
3342},
3343"GoingQuantum": {
3344src: "https://emotes.tastycat.org/emotes/logos/GoingQuantum.png",
3345titlePrefix: "ffz ",
3346},
3347"Goldfish": {
3348src: "https://emotes.tastycat.org/emotes/logos/Goldfish.png",
3349titlePrefix: "ffz ",
3350},
3351"GoldfishLogo": {
3352src: "https://emotes.tastycat.org/emotes/logos/GoldfishLogo.png",
3353titlePrefix: "ffz ",
3354},
3355"Grabbitz": {
3356src: "https://emotes.tastycat.org/emotes/logos/Grabbitz.png",
3357titlePrefix: "ffz ",
3358},
3359"GrantBowtie": {
3360src: "https://emotes.tastycat.org/emotes/logos/GrantBowtie.png",
3361titlePrefix: "ffz ",
3362},
3363"Griz": {
3364src: "https://emotes.tastycat.org/emotes/logos/Griz.png",
3365titlePrefix: "ffz ",
3366},
3367"Habstrakt": {
3368src: "https://emotes.tastycat.org/emotes/logos/Habstrakt.png",
3369titlePrefix: "ffz ",
3370},
3371"Hardwell": {
3372src: "https://emotes.tastycat.org/emotes/logos/Hardwell.png",
3373titlePrefix: "ffz ",
3374},
3375"Haszan&Overload": {
3376src: "https://emotes.tastycat.org/emotes/logos/Haszan_and_Overload.png",
3377titlePrefix: "ffz ",
3378},
3379"Haywyre": {
3380src: "https://emotes.tastycat.org/emotes/logos/Haywyre.png",
3381titlePrefix: "ffz ",
3382},
3383"Heatbeat": {
3384src: "https://emotes.tastycat.org/emotes/logos/Heatbeat.png",
3385titlePrefix: "ffz ",
3386},
3387"Hellberg": {
3388src: "https://emotes.tastycat.org/emotes/logos/Hellberg.png",
3389titlePrefix: "ffz ",
3390},
3391"Herobust": {
3392src: "https://emotes.tastycat.org/emotes/logos/Herobust.png",
3393titlePrefix: "ffz ",
3394},
3395"HeroicRecordings": {
3396src: "https://emotes.tastycat.org/emotes/logos/HeroicRecordings.png",
3397titlePrefix: "ffz ",
3398},
3399"HexMusique": {
3400src: "https://emotes.tastycat.org/emotes/logos/HexMusique.png",
3401titlePrefix: "ffz ",
3402},
3403"HighContrast": {
3404src: "https://emotes.tastycat.org/emotes/logos/HighContrast.png",
3405titlePrefix: "ffz ",
3406},
3407"HighMaintenance": {
3408src: "https://emotes.tastycat.org/emotes/logos/HighMaintenance.png",
3409titlePrefix: "ffz ",
3410},
3411"Histibe": {
3412src: "https://emotes.tastycat.org/emotes/logos/Histibe.png",
3413titlePrefix: "ffz ",
3414},
3415"HospitalRecords": {
3416src: "https://emotes.tastycat.org/emotes/logos/HospitalRecords.png",
3417titlePrefix: "ffz ",
3418},
3419"HouseCity": {
3420src: "https://emotes.tastycat.org/emotes/logos/HouseCity.png",
3421titlePrefix: "ffz ",
3422},
3423"HouseNation": {
3424src: "https://emotes.tastycat.org/emotes/logos/HouseNation.png",
3425titlePrefix: "ffz ",
3426},
3427"HyperPotions": {
3428src: "https://emotes.tastycat.org/emotes/logos/HyperPotions.png",
3429titlePrefix: "ffz ",
3430},
3431"INNO": {
3432src: "https://emotes.tastycat.org/emotes/logos/INNO.png",
3433titlePrefix: "ffz ",
3434},
3435"INNOSpace": {
3436src: "https://emotes.tastycat.org/emotes/logos/INNOSpace.png",
3437titlePrefix: "ffz ",
3438},
3439"ISeeMonstas": {
3440src: "https://emotes.tastycat.org/emotes/logos/ISeeMonstas.png",
3441titlePrefix: "ffz ",
3442},
3443"IYFFE": {
3444src: "https://emotes.tastycat.org/emotes/logos/IYFFE.png",
3445titlePrefix: "ffz ",
3446},
3447"IlanBluestone": {
3448src: "https://emotes.tastycat.org/emotes/logos/IlanBluestone.png",
3449titlePrefix: "ffz ",
3450},
3451"Imagin8": {
3452src: "https://emotes.tastycat.org/emotes/logos/Imagin8.png",
3453titlePrefix: "ffz ",
3454},
3455"InfectedMushroom": {
3456src: "https://emotes.tastycat.org/emotes/logos/InfectedMushroom.png",
3457titlePrefix: "ffz ",
3458},
3459"Insan3Lik3": {
3460src: "https://emotes.tastycat.org/emotes/logos/Insan3Lik3.png",
3461titlePrefix: "ffz ",
3462},
3463"Inspector": {
3464src: "https://emotes.tastycat.org/emotes/logos/Inspector.png",
3465titlePrefix: "ffz ",
3466},
3467"JackU": {
3468src: "https://emotes.tastycat.org/emotes/logos/JackU.png",
3469titlePrefix: "ffz ",
3470},
3471"JamesEgbert": {
3472src: "https://emotes.tastycat.org/emotes/logos/JamesEgbert.png",
3473titlePrefix: "ffz ",
3474},
3475"JayCosmic": {
3476src: "https://emotes.tastycat.org/emotes/logos/JayCosmic.png",
3477titlePrefix: "ffz ",
3478},
3479"JesseAbiko": {
3480src: "https://emotes.tastycat.org/emotes/logos/JesseAbiko.png",
3481titlePrefix: "ffz ",
3482},
3483"JohnOCallaghan": {
3484src: "https://emotes.tastycat.org/emotes/logos/JohnOCallaghan.png",
3485titlePrefix: "ffz ",
3486},
3487"K-391": {
3488src: "https://emotes.tastycat.org/emotes/logos/K-391.png",
3489titlePrefix: "ffz ",
3490},
3491"K-3912": {
3492src: "https://emotes.tastycat.org/emotes/logos/K-3912.png",
3493titlePrefix: "ffz ",
3494},
3495"KDrew": {
3496src: "https://emotes.tastycat.org/emotes/logos/KDrew.png",
3497titlePrefix: "ffz ",
3498},
3499"Joyryde": {
3500src: "https://emotes.tastycat.org/emotes/logos/Joyryde.png",
3501titlePrefix: "ffz ",
3502},
3503"KTheory": {
3504src: "https://emotes.tastycat.org/emotes/logos/KTheory.png",
3505titlePrefix: "ffz ",
3506},
3507"KaiWachi": {
3508src: "https://emotes.tastycat.org/emotes/logos/KaiWachi.png",
3509titlePrefix: "ffz ",
3510},
3511"KarmaFields": {
3512src: "https://emotes.tastycat.org/emotes/logos/KarmaFields.png",
3513titlePrefix: "ffz ",
3514},
3515"Kasbo": {
3516src: "https://emotes.tastycat.org/emotes/logos/Kasbo.png",
3517titlePrefix: "ffz ",
3518},
3519"Kasger": {
3520src: "https://emotes.tastycat.org/emotes/logos/Kasger.png",
3521titlePrefix: "ffz ",
3522},
3523"Kasum": {
3524src: "https://emotes.tastycat.org/emotes/logos/Kasum.png",
3525titlePrefix: "ffz ",
3526},
3527"KatKrazy": {
3528src: "https://emotes.tastycat.org/emotes/logos/KatKrazy.png",
3529titlePrefix: "ffz ",
3530},
3531"KatKrazyWhite": {
3532src: "https://emotes.tastycat.org/emotes/logos/KatKrazyWhite.png",
3533titlePrefix: "ffz ",
3534},
3535"KevinVillecco": {
3536src: "https://emotes.tastycat.org/emotes/logos/KevinVillecco.png",
3537titlePrefix: "ffz ",
3538},
3539"KeysNKrates": {
3540src: "https://emotes.tastycat.org/emotes/logos/KeysNKrates.png",
3541titlePrefix: "ffz ",
3542},
3543"KickTheHabit": {
3544src: "https://emotes.tastycat.org/emotes/logos/KickTheHabit.png",
3545titlePrefix: "ffz ",
3546},
3547"KillParis": {
3548src: "https://emotes.tastycat.org/emotes/logos/KillParis.png",
3549titlePrefix: "ffz ",
3550},
3551"KillTheNoise": {
3552src: "https://emotes.tastycat.org/emotes/logos/KillTheNoise.png",
3553titlePrefix: "ffz ",
3554},
3555"KlangKarussell": {
3556src: "https://emotes.tastycat.org/emotes/logos/KlangKarussell.png",
3557titlePrefix: "ffz ",
3558},
3559"Klingande": {
3560src: "https://emotes.tastycat.org/emotes/logos/Klingande.png",
3561titlePrefix: "ffz ",
3562},
3563"KnifeParty": {
3564src: "https://emotes.tastycat.org/emotes/logos/KnifeParty.png",
3565titlePrefix: "ffz ",
3566},
3567"KoalaKontrol": {
3568src: "https://emotes.tastycat.org/emotes/logos/KoalaKontrol.png",
3569titlePrefix: "ffz ",
3570},
3571"Kontor": {
3572src: "https://emotes.tastycat.org/emotes/logos/Kontor.png",
3573titlePrefix: "ffz ",
3574},
3575"Keeno": {
3576src: "https://emotes.tastycat.org/emotes/logos/Keeno.png",
3577titlePrefix: "ffz ",
3578},
3579"Kove": {
3580src: "https://emotes.tastycat.org/emotes/logos/Kove.png",
3581titlePrefix: "ffz ",
3582},
3583"Koven": {
3584src: "https://emotes.tastycat.org/emotes/logos/Koven.png",
3585titlePrefix: "ffz ",
3586},
3587"Krewella": {
3588src: "https://emotes.tastycat.org/emotes/logos/Krewella.png",
3589titlePrefix: "ffz ",
3590},
3591"Kygo": {
3592src: "https://emotes.tastycat.org/emotes/logos/Kygo.png",
3593titlePrefix: "ffz ",
3594},
3595"LAOS": {
3596src: "https://emotes.tastycat.org/emotes/logos/LAOS.png",
3597titlePrefix: "ffz ",
3598},
3599"LAXX": {
3600src: "https://emotes.tastycat.org/emotes/logos/LAXX.png",
3601titlePrefix: "ffz ",
3602},
3603"LVTHER": {
3604src: "https://emotes.tastycat.org/emotes/logos/LVTHER.png",
3605titlePrefix: "ffz ",
3606},
3607"Labisch": {
3608src: "https://emotes.tastycat.org/emotes/logos/Labisch.png",
3609titlePrefix: "ffz ",
3610},
3611"Laszlo": {
3612src: "https://emotes.tastycat.org/emotes/logos/Laszlo.png",
3613titlePrefix: "ffz ",
3614},
3615"LektriQue": {
3616src: "https://emotes.tastycat.org/emotes/logos/LektriQue.png",
3617titlePrefix: "ffz ",
3618},
3619"LetsBeFriends": {
3620src: "https://emotes.tastycat.org/emotes/logos/LetsBeFriends.png",
3621titlePrefix: "ffz ",
3622},
3623"Liquicity": {
3624src: "https://emotes.tastycat.org/emotes/logos/Liquicity.png",
3625titlePrefix: "ffz ",
3626},
3627"Loadstar": {
3628src: "https://emotes.tastycat.org/emotes/logos/Loadstar.png",
3629titlePrefix: "ffz ",
3630},
3631"LondonElektricity": {
3632src: "https://emotes.tastycat.org/emotes/logos/LondonElektricity.png",
3633titlePrefix: "ffz ",
3634},
3635"LondonGrammar": {
3636src: "https://emotes.tastycat.org/emotes/logos/LondonGrammar.png",
3637titlePrefix: "ffz ",
3638},
3639"MADnB": {
3640src: "https://emotes.tastycat.org/emotes/logos/MADnB.png",
3641titlePrefix: "ffz ",
3642},
3643"MADubstep": {
3644src: "https://emotes.tastycat.org/emotes/logos/MADubstep.png",
3645titlePrefix: "ffz ",
3646},
3647"MAKJ": {
3648src: "https://emotes.tastycat.org/emotes/logos/MAKJ.png",
3649titlePrefix: "ffz ",
3650},
3651"MANT": {
3652src: "https://emotes.tastycat.org/emotes/logos/MANT.png",
3653titlePrefix: "ffz ",
3654},
3655"MDK": {
3656src: "https://emotes.tastycat.org/emotes/logos/MDK.png",
3657titlePrefix: "ffz ",
3658},
3659"MING": {
3660src: "https://emotes.tastycat.org/emotes/logos/MING.png",
3661titlePrefix: "ffz ",
3662},
3663"Macarize": {
3664src: "https://emotes.tastycat.org/emotes/logos/Macarize.png",
3665titlePrefix: "ffz ",
3666},
3667"Madeon": {
3668src: "https://emotes.tastycat.org/emotes/logos/Madeon.png",
3669titlePrefix: "ffz ",
3670},
3671"Maduk": {
3672src: "https://emotes.tastycat.org/emotes/logos/Maduk.png",
3673titlePrefix: "ffz ",
3674},
3675"MajorLazer": {
3676src: "https://emotes.tastycat.org/emotes/logos/MajorLazer.png",
3677titlePrefix: "ffz ",
3678},
3679"MajorLook": {
3680src: "https://emotes.tastycat.org/emotes/logos/MajorLook.png",
3681titlePrefix: "ffz ",
3682},
3683"MartinGarrix": {
3684src: "https://emotes.tastycat.org/emotes/logos/MartinGarrix.png",
3685titlePrefix: "ffz ",
3686},
3687"MatZo": {
3688src: "https://emotes.tastycat.org/emotes/logos/MatZo.png",
3689titlePrefix: "ffz ",
3690},
3691"Matduke": {
3692src: "https://emotes.tastycat.org/emotes/logos/Matduke.png",
3693titlePrefix: "ffz ",
3694},
3695"Matoma": {
3696src: "https://emotes.tastycat.org/emotes/logos/Matoma.png",
3697titlePrefix: "ffz ",
3698},
3699"Matrix&Futurebound": {
3700src: "https://emotes.tastycat.org/emotes/logos/Matrix_and_Futurebound.png",
3701titlePrefix: "ffz ",
3702},
3703"Mediks": {
3704src: "https://emotes.tastycat.org/emotes/logos/Mediks.png",
3705titlePrefix: "ffz ",
3706},
3707"Melvv": {
3708src: "https://emotes.tastycat.org/emotes/logos/Melvv.png",
3709titlePrefix: "ffz ",
3710},
3711"Metrik": {
3712src: "https://emotes.tastycat.org/emotes/logos/Metrik.png",
3713titlePrefix: "ffz ",
3714},
3715"MichaelHerrera": {
3716src: "https://emotes.tastycat.org/emotes/logos/MichaelHerrera.png",
3717titlePrefix: "ffz ",
3718},
3719"MichaelPBN": {
3720src: "https://emotes.tastycat.org/emotes/logos/MichaelPBN.png",
3721titlePrefix: "ffz ",
3722},
3723"MiddleMilk": {
3724src: "https://emotes.tastycat.org/emotes/logos/MiddleMilk.png",
3725titlePrefix: "ffz ",
3726},
3727"Mikkas": {
3728src: "https://emotes.tastycat.org/emotes/logos/Mikkas.png",
3729titlePrefix: "ffz ",
3730},
3731"MitiS": {
3732src: "https://emotes.tastycat.org/emotes/logos/MitiS.png",
3733titlePrefix: "ffz ",
3734},
3735"Modestep": {
3736src: "https://emotes.tastycat.org/emotes/logos/Modestep.png",
3737titlePrefix: "ffz ",
3738},
3739"MitchellClaxton": {
3740src: "https://emotes.tastycat.org/emotes/logos/MitchellClaxton.png",
3741titlePrefix: "ffz ",
3742},
3743"Monoverse": {
3744src: "https://emotes.tastycat.org/emotes/logos/Monoverse.png",
3745titlePrefix: "ffz ",
3746},
3747"Montee": {
3748src: "https://emotes.tastycat.org/emotes/logos/Montee.png",
3749titlePrefix: "ffz ",
3750},
3751"MordFustang": {
3752src: "https://emotes.tastycat.org/emotes/logos/MordFustang.png",
3753titlePrefix: "ffz ",
3754},
3755"MustDie!": {
3756src: "https://emotes.tastycat.org/emotes/logos/MustDie_bang.png",
3757titlePrefix: "ffz ",
3758},
3759"Muzzy": {
3760src: "https://emotes.tastycat.org/emotes/logos/Muzzy.png",
3761titlePrefix: "ffz ",
3762},
3763"MuzzyNew": {
3764src: "https://emotes.tastycat.org/emotes/logos/MuzzyNew.png",
3765titlePrefix: "ffz ",
3766},
3767"MynuLeng": {
3768src: "https://emotes.tastycat.org/emotes/logos/MynuLeng.png",
3769titlePrefix: "ffz ",
3770},
3771"MuzzyOld": {
3772src: "https://emotes.tastycat.org/emotes/logos/MuzzyOld.png",
3773titlePrefix: "ffz ",
3774},
3775"NCS": {
3776src: "https://emotes.tastycat.org/emotes/logos/NCS.png",
3777titlePrefix: "ffz ",
3778},
3779"NERVO": {
3780src: "https://emotes.tastycat.org/emotes/logos/NERVO.png",
3781titlePrefix: "ffz ",
3782},
3783"NGHTMRE": {
3784src: "https://emotes.tastycat.org/emotes/logos/NGHTMRE.png",
3785titlePrefix: "ffz ",
3786},
3787"Neilio": {
3788src: "https://emotes.tastycat.org/emotes/logos/Neilio.png",
3789titlePrefix: "ffz ",
3790},
3791"Nero": {
3792src: "https://emotes.tastycat.org/emotes/logos/Nero.png",
3793titlePrefix: "ffz ",
3794},
3795"Netsky": {
3796src: "https://emotes.tastycat.org/emotes/logos/Netsky.png",
3797titlePrefix: "ffz ",
3798},
3799"NeverSayDie": {
3800src: "https://emotes.tastycat.org/emotes/logos/NeverSayDie.png",
3801titlePrefix: "ffz ",
3802},
3803"NickyRomero": {
3804src: "https://emotes.tastycat.org/emotes/logos/NickyRomero.png",
3805titlePrefix: "ffz ",
3806},
3807"NikCooper": {
3808src: "https://emotes.tastycat.org/emotes/logos/NikCooper.png",
3809titlePrefix: "ffz ",
3810},
3811"NitroFun": {
3812src: "https://emotes.tastycat.org/emotes/logos/NitroFun.png",
3813titlePrefix: "ffz ",
3814},
3815"Noisestorm": {
3816src: "https://emotes.tastycat.org/emotes/logos/Noisestorm.png",
3817titlePrefix: "ffz ",
3818},
3819"Noisia": {
3820src: "https://emotes.tastycat.org/emotes/logos/Noisia.png",
3821titlePrefix: "ffz ",
3822},
3823"NoisiaLogo": {
3824src: "https://emotes.tastycat.org/emotes/logos/NoisiaLogo.png",
3825titlePrefix: "ffz ",
3826},
3827"Nu:Logic": {
3828src: "https://emotes.tastycat.org/emotes/logos/Nu_col_Logic.png",
3829titlePrefix: "ffz ",
3830},
3831"Nymfo": {
3832src: "https://emotes.tastycat.org/emotes/logos/Nymfo.png",
3833titlePrefix: "ffz ",
3834},
3835"OVERWERK": {
3836src: "https://emotes.tastycat.org/emotes/logos/OVERWERK.png",
3837titlePrefix: "ffz ",
3838},
3839"Obsidia": {
3840src: "https://emotes.tastycat.org/emotes/logos/Obsidia.png",
3841titlePrefix: "ffz ",
3842},
3843"OliverHeldens": {
3844src: "https://emotes.tastycat.org/emotes/logos/OliverHeldens.png",
3845titlePrefix: "ffz ",
3846},
3847"Omnitica": {
3848src: "https://emotes.tastycat.org/emotes/logos/Omnitica.png",
3849titlePrefix: "ffz ",
3850},
3851"OnderKoffer": {
3852src: "https://emotes.tastycat.org/emotes/logos/OnderKoffer.png",
3853titlePrefix: "ffz ",
3854},
3855"PBNHeart": {
3856src: "https://emotes.tastycat.org/emotes/logos/PBNHeart.png",
3857titlePrefix: "ffz ",
3858},
3859"PIXL": {
3860src: "https://emotes.tastycat.org/emotes/logos/PIXL.png",
3861titlePrefix: "ffz ",
3862},
3863"Pandasian": {
3864src: "https://emotes.tastycat.org/emotes/logos/Pandasian.png",
3865titlePrefix: "ffz ",
3866},
3867"Paradoxium": {
3868src: "https://emotes.tastycat.org/emotes/logos/Paradoxium.png",
3869titlePrefix: "ffz ",
3870},
3871"ParisBlohm": {
3872src: "https://emotes.tastycat.org/emotes/logos/ParisBlohm.png",
3873titlePrefix: "ffz ",
3874},
3875"Parry": {
3876src: "https://emotes.tastycat.org/emotes/logos/Parry.png",
3877titlePrefix: "ffz ",
3878},
3879"PartyGhost": {
3880src: "https://emotes.tastycat.org/emotes/logos/PartyGhost.png",
3881titlePrefix: "ffz ",
3882},
3883"PaulKalkbrenner": {
3884src: "https://emotes.tastycat.org/emotes/logos/PaulKalkbrenner.png",
3885titlePrefix: "ffz ",
3886},
3887"PaulvanDyk": {
3888src: "https://emotes.tastycat.org/emotes/logos/PaulvanDyk.png",
3889titlePrefix: "ffz ",
3890},
3891"Pendulum": {
3892src: "https://emotes.tastycat.org/emotes/logos/Pendulum.png",
3893titlePrefix: "ffz ",
3894},
3895"height":7,
3896"PorterRobinson": {
3897src: "https://emotes.tastycat.org/emotes/logos/PorterRobinson.png",
3898titlePrefix: "ffz ",
3899},
3900"PriorityOne": {
3901src: "https://emotes.tastycat.org/emotes/logos/PriorityOne.png",
3902titlePrefix: "ffz ",
3903},
3904"ProdigyAnt": {
3905src: "https://emotes.tastycat.org/emotes/logos/ProdigyAnt.png",
3906titlePrefix: "ffz ",
3907},
3908"Project46": {
3909src: "https://emotes.tastycat.org/emotes/logos/Project46.png",
3910titlePrefix: "ffz ",
3911},
3912"Protostar": {
3913src: "https://emotes.tastycat.org/emotes/logos/Protostar.png",
3914titlePrefix: "ffz ",
3915},
3916"PrototypeRaptor": {
3917src: "https://emotes.tastycat.org/emotes/logos/PrototypeRaptor.png",
3918titlePrefix: "ffz ",
3919},
3920"Proximity": {
3921src: "https://emotes.tastycat.org/emotes/logos/Proximity.png",
3922titlePrefix: "ffz ",
3923},
3924"Puppet": {
3925src: "https://emotes.tastycat.org/emotes/logos/Puppet.png",
3926titlePrefix: "ffz ",
3927},
3928"Pylot": {
3929src: "https://emotes.tastycat.org/emotes/logos/Pylot.png",
3930titlePrefix: "ffz ",
3931},
3932"R3HAB": {
3933src: "https://emotes.tastycat.org/emotes/logos/R3HAB.png",
3934titlePrefix: "ffz ",
3935},
3936"RIOT": {
3937src: "https://emotes.tastycat.org/emotes/logos/RIOT.png",
3938titlePrefix: "ffz ",
3939},
3940"RLGrime": {
3941src: "https://emotes.tastycat.org/emotes/logos/RLGrime.png",
3942titlePrefix: "ffz ",
3943},
3944"RamRecords": {
3945src: "https://emotes.tastycat.org/emotes/logos/RamRecords.png",
3946titlePrefix: "ffz ",
3947},
3948"RamesesB": {
3949src: "https://emotes.tastycat.org/emotes/logos/RamesesB.png",
3950titlePrefix: "ffz ",
3951},
3952"Razihel": {
3953src: "https://emotes.tastycat.org/emotes/logos/Razihel.png",
3954titlePrefix: "ffz ",
3955},
3956"Rezonate": {
3957src: "https://emotes.tastycat.org/emotes/logos/Rezonate.png",
3958titlePrefix: "ffz ",
3959},
3960"RichEdwards": {
3961src: "https://emotes.tastycat.org/emotes/logos/RichEdwards.png",
3962titlePrefix: "ffz ",
3963},
3964"RobGasser": {
3965src: "https://emotes.tastycat.org/emotes/logos/RobGasser.png",
3966titlePrefix: "ffz ",
3967},
3968"Rockwell": {
3969src: "https://emotes.tastycat.org/emotes/logos/Rockwell.png",
3970titlePrefix: "ffz ",
3971},
3972"Rogue": {
3973src: "https://emotes.tastycat.org/emotes/logos/Rogue.png",
3974titlePrefix: "ffz ",
3975},
3976"Rootkit": {
3977src: "https://emotes.tastycat.org/emotes/logos/Rootkit.png",
3978titlePrefix: "ffz ",
3979},
3980"Rudimental": {
3981src: "https://emotes.tastycat.org/emotes/logos/Rudimental.png",
3982titlePrefix: "ffz ",
3983},
3984"S3RL": {
3985src: "https://emotes.tastycat.org/emotes/logos/S3RL.png",
3986titlePrefix: "ffz ",
3987},
3988"SCNDL": {
3989src: "https://emotes.tastycat.org/emotes/logos/SCNDL.png",
3990titlePrefix: "ffz ",
3991},
3992"SanHolo": {
3993src: "https://emotes.tastycat.org/emotes/logos/SanHolo.png",
3994titlePrefix: "ffz ",
3995},
3996"Savant": {
3997src: "https://emotes.tastycat.org/emotes/logos/Savant.png",
3998titlePrefix: "ffz ",
3999},
4000"Seafox": {
4001src: "https://emotes.tastycat.org/emotes/logos/Seafox.png",
4002titlePrefix: "ffz ",
4003},
4004"SevenLions": {
4005src: "https://emotes.tastycat.org/emotes/logos/SevenLions.png",
4006titlePrefix: "ffz ",
4007},
4008"ShawnWasabi": {
4009src: "https://emotes.tastycat.org/emotes/logos/ShawnWasabi.png",
4010titlePrefix: "ffz ",
4011},
4012"Shazzka": {
4013src: "https://emotes.tastycat.org/emotes/logos/Shazzka.png",
4014titlePrefix: "ffz ",
4015},
4016"ShockOne": {
4017src: "https://emotes.tastycat.org/emotes/logos/ShockOne.png",
4018titlePrefix: "ffz ",
4019},
4020"Shogun": {
4021src: "https://emotes.tastycat.org/emotes/logos/Shogun.png",
4022titlePrefix: "ffz ",
4023},
4024"ShogunAudio": {
4025src: "https://emotes.tastycat.org/emotes/logos/ShogunAudio.png",
4026titlePrefix: "ffz ",
4027},
4028"ShogunTaira": {
4029src: "https://emotes.tastycat.org/emotes/logos/ShogunTaira.png",
4030titlePrefix: "ffz ",
4031},
4032"Showtek": {
4033src: "https://emotes.tastycat.org/emotes/logos/Showtek.png",
4034titlePrefix: "ffz ",
4035},
4036"Sian": {
4037src: "https://emotes.tastycat.org/emotes/logos/Sian.png",
4038titlePrefix: "ffz ",
4039},
4040"Sigma": {
4041src: "https://emotes.tastycat.org/emotes/logos/Sigma.png",
4042titlePrefix: "ffz ",
4043},
4044"SirensCeol": {
4045src: "https://emotes.tastycat.org/emotes/logos/SirensCeol.png",
4046titlePrefix: "ffz ",
4047},
4048"Skism": {
4049src: "https://emotes.tastycat.org/emotes/logos/Skism.png",
4050titlePrefix: "ffz ",
4051},
4052"Skrillex": {
4053src: "https://emotes.tastycat.org/emotes/logos/Skrillex.png",
4054titlePrefix: "ffz ",
4055},
4056"Skrux": {
4057src: "https://emotes.tastycat.org/emotes/logos/Skrux.png",
4058titlePrefix: "ffz ",
4059},
4060"Slips&Slurs": {
4061src: "https://emotes.tastycat.org/emotes/logos/Slips_and_Slurs.png",
4062titlePrefix: "ffz ",
4063},
4064"Smooth": {
4065src: "https://emotes.tastycat.org/emotes/logos/Smooth.png",
4066titlePrefix: "ffz ",
4067},
4068"Snails": {
4069src: "https://emotes.tastycat.org/emotes/logos/Snails.png",
4070titlePrefix: "ffz ",
4071},
4072"Snakehips": {
4073src: "https://emotes.tastycat.org/emotes/logos/Snakehips.png",
4074titlePrefix: "ffz ",
4075},
4076"Soulero": {
4077src: "https://emotes.tastycat.org/emotes/logos/Soulero.png",
4078titlePrefix: "ffz ",
4079},
4080"SoundRemedy": {
4081src: "https://emotes.tastycat.org/emotes/logos/SoundRemedy.png",
4082titlePrefix: "ffz ",
4083},
4084"SpagHeddy": {
4085src: "https://emotes.tastycat.org/emotes/logos/SpagHeddy.png",
4086titlePrefix: "ffz ",
4087},
4088"Spinnin": {
4089src: "https://emotes.tastycat.org/emotes/logos/Spinnin.png",
4090titlePrefix: "ffz ",
4091},
4092"SpinninSpinnin": {
4093src: "https://emotes.tastycat.org/emotes/logos/SpinninSpinnin.gif",
4094titlePrefix: "ffz ",
4095},
4096"Splitbreed": {
4097src: "https://emotes.tastycat.org/emotes/logos/Splitbreed.png",
4098titlePrefix: "ffz ",
4099},
4100"StephenWalking": {
4101src: "https://emotes.tastycat.org/emotes/logos/StephenWalking.png",
4102titlePrefix: "ffz ",
4103},
4104"StationEarth": {
4105src: "https://emotes.tastycat.org/emotes/logos/StationEarth.png",
4106titlePrefix: "ffz ",
4107},
4108"Stereotronique": {
4109src: "https://emotes.tastycat.org/emotes/logos/Stereotronique.png",
4110titlePrefix: "ffz ",
4111},
4112"SteveAoki": {
4113src: "https://emotes.tastycat.org/emotes/logos/SteveAoki.png",
4114titlePrefix: "ffz ",
4115},
4116"Stonebank": {
4117src: "https://emotes.tastycat.org/emotes/logos/Stonebank.png",
4118titlePrefix: "ffz ",
4119},
4120"SubFocus": {
4121src: "https://emotes.tastycat.org/emotes/logos/SubFocus.png",
4122titlePrefix: "ffz ",
4123},
4124"Submatik": {
4125src: "https://emotes.tastycat.org/emotes/logos/Submatik.png",
4126titlePrefix: "ffz ",
4127},
4128"SuicideSheep": {
4129src: "https://emotes.tastycat.org/emotes/logos/SuicideSheep.png",
4130titlePrefix: "ffz ",
4131},
4132"SummerWasFun": {
4133src: "https://emotes.tastycat.org/emotes/logos/SummerWasFun.png",
4134titlePrefix: "ffz ",
4135},
4136"Super8&Tab": {
4137src: "https://emotes.tastycat.org/emotes/logos/Super8_and_Tab.png",
4138titlePrefix: "ffz ",
4139},
4140"SwingWhale": {
4141src: "https://emotes.tastycat.org/emotes/logos/SwingWhale.png",
4142titlePrefix: "ffz ",
4143},
4144"SushiKiller": {
4145src: "https://emotes.tastycat.org/emotes/logos/SushiKiller.png",
4146titlePrefix: "ffz ",
4147},
4148"SynCole": {
4149src: "https://emotes.tastycat.org/emotes/logos/SynCole.png",
4150titlePrefix: "ffz ",
4151},
4152"T-Nan": {
4153src: "https://emotes.tastycat.org/emotes/logos/T-Nan.png",
4154titlePrefix: "ffz ",
4155},
4156"TVDS": {
4157src: "https://emotes.tastycat.org/emotes/logos/TVDS.png",
4158titlePrefix: "ffz ",
4159},
4160"Televisor": {
4161src: "https://emotes.tastycat.org/emotes/logos/Televisor.png",
4162titlePrefix: "ffz ",
4163},
4164"Teminite": {
4165src: "https://emotes.tastycat.org/emotes/logos/Teminite.png",
4166titlePrefix: "ffz ",
4167},
4168"Teqq": {
4169src: "https://emotes.tastycat.org/emotes/logos/Teqq.png",
4170titlePrefix: "ffz ",
4171},
4172"TetrixBass": {
4173src: "https://emotes.tastycat.org/emotes/logos/TetrixBass.png",
4174titlePrefix: "ffz ",
4175},
4176"TheDubRebellion": {
4177src: "https://emotes.tastycat.org/emotes/logos/TheDubRebellion.png",
4178titlePrefix: "ffz ",
4179},
4180"TheEdenProject": {
4181src: "https://emotes.tastycat.org/emotes/logos/TheEdenProject.png",
4182titlePrefix: "ffz ",
4183},
4184"TheFatRat": {
4185src: "https://emotes.tastycat.org/emotes/logos/TheFatRat.png",
4186titlePrefix: "ffz ",
4187},
4188"TheProdigy": {
4189src: "https://emotes.tastycat.org/emotes/logos/TheProdigy.png",
4190titlePrefix: "ffz ",
4191},
4192"ThePrototypes": {
4193src: "https://emotes.tastycat.org/emotes/logos/ThePrototypes.png",
4194titlePrefix: "ffz ",
4195},
4196"TheSoundYouNeed": {
4197src: "https://emotes.tastycat.org/emotes/logos/TheSoundYouNeed.png",
4198titlePrefix: "ffz ",
4199},
4200"Throttle": {
4201src: "https://emotes.tastycat.org/emotes/logos/Throttle.png",
4202titlePrefix: "ffz ",
4203},
4204"ThugLife": {
4205src: "https://emotes.tastycat.org/emotes/logos/ThugLife.png",
4206titlePrefix: "ffz ",
4207},
4208"Tiesto": {
4209src: "https://emotes.tastycat.org/emotes/logos/Tiesto.png",
4210titlePrefix: "ffz ",
4211},
4212"Tobu": {
4213src: "https://emotes.tastycat.org/emotes/logos/Tobu.png",
4214titlePrefix: "ffz ",
4215},
4216"Traktion": {
4217src: "https://emotes.tastycat.org/emotes/logos/Traktion.png",
4218titlePrefix: "ffz ",
4219},
4220"TrapBear": {
4221src: "https://emotes.tastycat.org/emotes/logos/TrapBear.png",
4222titlePrefix: "ffz ",
4223},
4224"TrapCity": {
4225src: "https://emotes.tastycat.org/emotes/logos/TrapCity.png",
4226titlePrefix: "ffz ",
4227},
4228"TrapNation": {
4229src: "https://emotes.tastycat.org/emotes/logos/TrapNation.png",
4230titlePrefix: "ffz ",
4231},
4232"Trap&Bass": {
4233src: "https://emotes.tastycat.org/emotes/logos/Trap_and_Bass.png",
4234titlePrefix: "ffz ",
4235},
4236"Tristam": {
4237src: "https://emotes.tastycat.org/emotes/logos/Tristam.png",
4238titlePrefix: "ffz ",
4239},
4240"Tritonal": {
4241src: "https://emotes.tastycat.org/emotes/logos/Tritonal.png",
4242titlePrefix: "ffz ",
4243},
4244"Trivecta": {
4245src: "https://emotes.tastycat.org/emotes/logos/Trivecta.png",
4246titlePrefix: "ffz ",
4247},
4248"TrolleySnatcha": {
4249src: "https://emotes.tastycat.org/emotes/logos/TrolleySnatcha.png",
4250titlePrefix: "ffz ",
4251},
4252"TutTutChild": {
4253src: "https://emotes.tastycat.org/emotes/logos/TutTutChild.png",
4254titlePrefix: "ffz ",
4255},
4256"Twine": {
4257src: "https://emotes.tastycat.org/emotes/logos/Twine.png",
4258titlePrefix: "ffz ",
4259},
4260"TwoThirds": {
4261src: "https://emotes.tastycat.org/emotes/logos/TwoThirds.png",
4262titlePrefix: "ffz ",
4263},
4264"UKF": {
4265src: "https://emotes.tastycat.org/emotes/logos/UKF.png",
4266titlePrefix: "ffz ",
4267},
4268"UKFDnb": {
4269src: "https://emotes.tastycat.org/emotes/logos/UKFDnb.png",
4270titlePrefix: "ffz ",
4271},
4272"UKFDubstep": {
4273src: "https://emotes.tastycat.org/emotes/logos/UKFDubstep.png",
4274titlePrefix: "ffz ",
4275},
4276"UKFMusic": {
4277src: "https://emotes.tastycat.org/emotes/logos/UKFMusic.png",
4278titlePrefix: "ffz ",
4279},
4280"Uppermost": {
4281src: "https://emotes.tastycat.org/emotes/logos/Uppermost.png",
4282titlePrefix: "ffz ",
4283},
4284"VOIA": {
4285src: "https://emotes.tastycat.org/emotes/logos/VOIA.png",
4286titlePrefix: "ffz ",
4287},
4288"VOIAHelmet": {
4289src: "https://emotes.tastycat.org/emotes/logos/VOIAHelmet.png",
4290titlePrefix: "ffz ",
4291},
4292"Vanden": {
4293src: "https://emotes.tastycat.org/emotes/logos/Vanden.png",
4294titlePrefix: "ffz ",
4295},
4296"Vanic": {
4297src: "https://emotes.tastycat.org/emotes/logos/Vanic.png",
4298titlePrefix: "ffz ",
4299},
4300"Varien": {
4301src: "https://emotes.tastycat.org/emotes/logos/Varien.png",
4302titlePrefix: "ffz ",
4303},
4304"Veela": {
4305src: "https://emotes.tastycat.org/emotes/logos/Veela.png",
4306titlePrefix: "ffz ",
4307},
4308"Vexento": {
4309src: "https://emotes.tastycat.org/emotes/logos/Vexento.png",
4310titlePrefix: "ffz ",
4311},
4312"Vice&Virtue": {
4313src: "https://emotes.tastycat.org/emotes/logos/Vice_and_Virtue.png",
4314titlePrefix: "ffz ",
4315},
4316"Vicetone": {
4317src: "https://emotes.tastycat.org/emotes/logos/Vicetone.png",
4318titlePrefix: "ffz ",
4319},
4320"Viper": {
4321src: "https://emotes.tastycat.org/emotes/logos/Viper.png",
4322titlePrefix: "ffz ",
4323},
4324"VirtualRiot": {
4325src: "https://emotes.tastycat.org/emotes/logos/VirtualRiot.png",
4326titlePrefix: "ffz ",
4327},
4328"Volant": {
4329src: "https://emotes.tastycat.org/emotes/logos/Volant.png",
4330titlePrefix: "ffz ",
4331},
4332"Vulpey": {
4333src: "https://emotes.tastycat.org/emotes/logos/Vulpey.png",
4334titlePrefix: "ffz ",
4335},
4336"WRLD": {
4337src: "https://emotes.tastycat.org/emotes/logos/WRLD.png",
4338titlePrefix: "ffz ",
4339},
4340"Wilkinson": {
4341src: "https://emotes.tastycat.org/emotes/logos/Wilkinson.png",
4342titlePrefix: "ffz ",
4343},
4344"Wobblecraft": {
4345src: "https://emotes.tastycat.org/emotes/logos/Wobblecraft.png",
4346titlePrefix: "ffz ",
4347},
4348"WolfBeats": {
4349src: "https://emotes.tastycat.org/emotes/logos/WolfBeats.png",
4350titlePrefix: "ffz ",
4351},
4352"Woody": {
4353src: "https://emotes.tastycat.org/emotes/logos/Woody.png",
4354titlePrefix: "ffz ",
4355},
4356"XYPO": {
4357src: "https://emotes.tastycat.org/emotes/logos/XYPO.png",
4358titlePrefix: "ffz ",
4359},
4360"Xilent": {
4361src: "https://emotes.tastycat.org/emotes/logos/Xilent.png",
4362titlePrefix: "ffz ",
4363},
4364"YellowClaw": {
4365src: "https://emotes.tastycat.org/emotes/logos/YellowClaw.png",
4366titlePrefix: "ffz ",
4367},
4368"Zedd": {
4369src: "https://emotes.tastycat.org/emotes/logos/Zedd.png",
4370titlePrefix: "ffz ",
4371},
4372"ZedsDead": {
4373src: "https://emotes.tastycat.org/emotes/logos/ZedsDead.png",
4374titlePrefix: "ffz ",
4375},
4376"ZomboyFace": {
4377src: "https://emotes.tastycat.org/emotes/logos/ZomboyFace.png",
4378titlePrefix: "ffz ",
4379},
4380"Zyphon": {
4381src: "https://emotes.tastycat.org/emotes/logos/Zyphon.png",
4382titlePrefix: "ffz ",
4383},
4384"marshmello": {
4385src: "https://emotes.tastycat.org/emotes/logos/marshmello.png",
4386titlePrefix: "ffz ",
4387},
4388"nanobii": {
4389src: "https://emotes.tastycat.org/emotes/logos/nanobii.png",
4390titlePrefix: "ffz ",
4391},
4392"nanobiiFace": {
4393src: "https://emotes.tastycat.org/emotes/logos/nanobiiFace.png",
4394titlePrefix: "ffz ",
4395},
4396"plugdj": {
4397src: "https://emotes.tastycat.org/emotes/logos/plugdj.png",
4398titlePrefix: "ffz ",
4399},
4400"xKito": {
4401src: "https://emotes.tastycat.org/emotes/logos/xKito.png",
4402titlePrefix: "ffz ",
4403},
4404"xKore": {
4405src: "https://emotes.tastycat.org/emotes/logos/xKore.png",
4406titlePrefix: "ffz ",
4407},
4408"Zomboy": {
4409src: "https://emotes.tastycat.org/emotes/logos/Zomboy.png",
4410titlePrefix: "ffz ",
4411},
4412"Ackbar": {
4413src: "https://emotes.tastycat.org/emotes/misc/Ackbar.png",
4414titlePrefix: "ffz ",
4415},
4416"Airhorn": {
4417src: "https://emotes.tastycat.org/emotes/misc/Airhorn.png",
4418titlePrefix: "ffz ",
4419},
4420"AwesomeFace": {
4421src: "https://emotes.tastycat.org/emotes/misc/AwesomeFace.png",
4422titlePrefix: "ffz ",
4423},
4424"BGasm": {
4425src: "https://emotes.tastycat.org/emotes/misc/BGasm.png",
4426titlePrefix: "ffz ",
4427},
4428"Babby": {
4429src: "https://emotes.tastycat.org/emotes/misc/Babby.png",
4430titlePrefix: "ffz ",
4431},
4432"Bacon": {
4433src: "https://emotes.tastycat.org/emotes/misc/Bacon.png",
4434titlePrefix: "ffz ",
4435},
4436"BadJoke": {
4437src: "https://emotes.tastycat.org/emotes/misc/BadJoke.png",
4438titlePrefix: "ffz ",
4439},
4440"Bagon": {
4441src: "https://emotes.tastycat.org/emotes/misc/Bagon.png",
4442titlePrefix: "ffz ",
4443},
4444"BanHammer": {
4445src: "https://emotes.tastycat.org/emotes/misc/BanHammer.png",
4446titlePrefix: "ffz ",
4447},
4448"Bazinga": {
4449src: "https://emotes.tastycat.org/emotes/misc/Bazinga.png",
4450titlePrefix: "ffz ",
4451},
4452"Billy": {
4453src: "https://emotes.tastycat.org/emotes/misc/Billy.png",
4454titlePrefix: "ffz ",
4455},
4456"Brother": {
4457src: "https://emotes.tastycat.org/emotes/misc/Brother.png",
4458titlePrefix: "ffz ",
4459},
4460"CanYouNot": {
4461src: "https://emotes.tastycat.org/emotes/misc/CanYouNot.png",
4462titlePrefix: "ffz ",
4463},
4464"Catbug": {
4465src: "https://emotes.tastycat.org/emotes/misc/Catbug.png",
4466titlePrefix: "ffz ",
4467},
4468"Cena": {
4469src: "https://emotes.tastycat.org/emotes/misc/Cena.png",
4470titlePrefix: "ffz ",
4471},
4472"Choooone": {
4473src: "https://emotes.tastycat.org/emotes/misc/Choooone.png",
4474titlePrefix: "ffz ",
4475},
4476"ClapTrap": {
4477src: "https://emotes.tastycat.org/emotes/misc/ClapTrap.png",
4478titlePrefix: "ffz ",
4479},
4480"CrayC": {
4481src: "https://emotes.tastycat.org/emotes/misc/CrayC.png",
4482titlePrefix: "ffz ",
4483},
4484"Carlton": {
4485src: "https://emotes.tastycat.org/emotes/misc/Carlton.png",
4486titlePrefix: "ffz ",
4487},
4488"Dank": {
4489src: "https://emotes.tastycat.org/emotes/misc/Dank.png",
4490titlePrefix: "ffz ",
4491},
4492"Darude": {
4493src: "https://emotes.tastycat.org/emotes/misc/Darude.png",
4494titlePrefix: "ffz ",
4495},
4496"Despair": {
4497src: "https://emotes.tastycat.org/emotes/misc/Despair.png",
4498titlePrefix: "ffz ",
4499},
4500"DickButt": {
4501src: "https://emotes.tastycat.org/emotes/misc/DickButt.png",
4502titlePrefix: "ffz ",
4503},
4504"DoctorKappa": {
4505src: "https://emotes.tastycat.org/emotes/misc/DoctorKappa.png",
4506titlePrefix: "ffz ",
4507},
4508"DogLick": {
4509src: "https://emotes.tastycat.org/emotes/misc/DogLick.png",
4510titlePrefix: "ffz ",
4511},
4512"DogeW": {
4513src: "https://emotes.tastycat.org/emotes/misc/DogeW.png",
4514titlePrefix: "ffz ",
4515},
4516"Dolan": {
4517src: "https://emotes.tastycat.org/emotes/misc/Dolan.png",
4518titlePrefix: "ffz ",
4519},
4520"DonutOwl": {
4521src: "https://emotes.tastycat.org/emotes/misc/DonutOwl.png",
4522titlePrefix: "ffz ",
4523},
4524"DonutPanda": {
4525src: "https://emotes.tastycat.org/emotes/misc/DonutPanda.png",
4526titlePrefix: "ffz ",
4527},
4528"DropThatBray": {
4529src: "https://emotes.tastycat.org/emotes/misc/DropThatBray.png",
4530titlePrefix: "ffz ",
4531},
4532"DropThatEmsi": {
4533src: "https://emotes.tastycat.org/emotes/misc/DropThatEmsi.png",
4534titlePrefix: "ffz ",
4535},
4536"DropThatRaptor": {
4537src: "https://emotes.tastycat.org/emotes/misc/DropThatRaptor.png",
4538titlePrefix: "ffz ",
4539},
4540"DropThatShere": {
4541src: "https://emotes.tastycat.org/emotes/misc/DropThatShere.png",
4542titlePrefix: "ffz ",
4543},
4544"DropThatSoap": {
4545src: "https://emotes.tastycat.org/emotes/misc/DropThatSoap.png",
4546titlePrefix: "ffz ",
4547},
4548"DropTheBass": {
4549src: "https://emotes.tastycat.org/emotes/misc/DropTheBass.png",
4550titlePrefix: "ffz ",
4551},
4552"EphixaCook": {
4553src: "https://emotes.tastycat.org/emotes/misc/EphixaCook.png",
4554titlePrefix: "ffz ",
4555},
4556"FOF": {
4557src: "https://emotes.tastycat.org/emotes/misc/FOF.png",
4558titlePrefix: "ffz ",
4559},
4560"Facepalm": {
4561src: "https://emotes.tastycat.org/emotes/misc/Facepalm.png",
4562titlePrefix: "ffz ",
4563},
4564"Foongus": {
4565src: "https://emotes.tastycat.org/emotes/misc/Foongus.png",
4566titlePrefix: "ffz ",
4567},
4568"GabeN": {
4569src: "https://emotes.tastycat.org/emotes/misc/GabeN.png",
4570titlePrefix: "ffz ",
4571},
4572"Gasp4": {
4573src: "https://emotes.tastycat.org/emotes/misc/Gasp4.png",
4574titlePrefix: "ffz ",
4575},
4576"GayWolverine": {
4577src: "https://emotes.tastycat.org/emotes/misc/GayWolverine.png",
4578titlePrefix: "ffz ",
4579},
4580"Ghostbusters": {
4581src: "https://emotes.tastycat.org/emotes/misc/Ghostbusters.png",
4582titlePrefix: "ffz ",
4583},
4584"Glare": {
4585src: "https://emotes.tastycat.org/emotes/misc/Glare.png",
4586titlePrefix: "ffz ",
4587},
4588"Goose": {
4589src: "https://emotes.tastycat.org/emotes/misc/Goose.png",
4590titlePrefix: "ffz ",
4591},
4592"Grabbed": {
4593src: "https://emotes.tastycat.org/emotes/misc/Grabbed.png",
4594titlePrefix: "ffz ",
4595},
4596"Guinea": {
4597src: "https://emotes.tastycat.org/emotes/misc/Guinea.png",
4598titlePrefix: "ffz ",
4599},
4600"Headshot": {
4601src: "https://emotes.tastycat.org/emotes/misc/Headshot.png",
4602titlePrefix: "ffz ",
4603},
4604"Hodor": {
4605src: "https://emotes.tastycat.org/emotes/misc/Hodor.png",
4606titlePrefix: "ffz ",
4607},
4608"HorseMask": {
4609src: "https://emotes.tastycat.org/emotes/misc/HorseMask.png",
4610titlePrefix: "ffz ",
4611},
4612"Hue": {
4613src: "https://emotes.tastycat.org/emotes/misc/Hue.png",
4614titlePrefix: "ffz ",
4615},
4616"ILoveHaters": {
4617src: "https://emotes.tastycat.org/emotes/misc/ILoveHaters.png",
4618titlePrefix: "ffz ",
4619},
4620"Illuminati": {
4621src: "https://emotes.tastycat.org/emotes/misc/Illuminati.png",
4622titlePrefix: "ffz ",
4623},
4624"Jaraxxus": {
4625src: "https://emotes.tastycat.org/emotes/misc/Jaraxxus.png",
4626titlePrefix: "ffz ",
4627},
4628"Jeff": {
4629src: "https://emotes.tastycat.org/emotes/misc/Jeff.png",
4630titlePrefix: "ffz ",
4631},
4632"Jelly": {
4633src: "https://emotes.tastycat.org/emotes/misc/Jelly.png",
4634titlePrefix: "ffz ",
4635},
4636"JustDoIt": {
4637src: "https://emotes.tastycat.org/emotes/misc/JustDoIt.png",
4638titlePrefix: "ffz ",
4639},
4640"Kappify": {
4641src: "https://emotes.tastycat.org/emotes/misc/Kappify.png",
4642titlePrefix: "ffz ",
4643},
4644"KingKappa": {
4645src: "https://emotes.tastycat.org/emotes/misc/KingKappa.png",
4646titlePrefix: "ffz ",
4647},
4648"KingMonkey": {
4649src: "https://emotes.tastycat.org/emotes/misc/KingMonkey.png",
4650titlePrefix: "ffz ",
4651},
4652"Kirby": {
4653src: "https://emotes.tastycat.org/emotes/misc/Kirby.png",
4654titlePrefix: "ffz ",
4655},
4656"LeftShark": {
4657src: "https://emotes.tastycat.org/emotes/misc/LeftShark.png",
4658titlePrefix: "ffz ",
4659},
4660"Legit": {
4661src: "https://emotes.tastycat.org/emotes/misc/Legit.png",
4662titlePrefix: "ffz ",
4663},
4664"Lenny": {
4665src: "https://emotes.tastycat.org/emotes/misc/Lenny.png",
4666titlePrefix: "ffz ",
4667},
4668"Leviosah": {
4669src: "https://emotes.tastycat.org/emotes/misc/Leviosah.png",
4670titlePrefix: "ffz ",
4671},
4672"Lies": {
4673src: "https://emotes.tastycat.org/emotes/misc/Lies.png",
4674titlePrefix: "ffz ",
4675},
4676"Loki": {
4677src: "https://emotes.tastycat.org/emotes/misc/Loki.png",
4678titlePrefix: "ffz ",
4679},
4680"LondonFace": {
4681src: "https://emotes.tastycat.org/emotes/misc/LondonFace.png",
4682titlePrefix: "ffz ",
4683},
4684"LongCatB": {
4685src: "https://emotes.tastycat.org/emotes/misc/LongCatB.png",
4686titlePrefix: "ffz ",
4687},
4688"LongCatH": {
4689src: "https://emotes.tastycat.org/emotes/misc/LongCatH.png",
4690titlePrefix: "ffz ",
4691},
4692"MoonMoon": {
4693src: "https://emotes.tastycat.org/emotes/misc/MoonMoon.png",
4694titlePrefix: "ffz ",
4695},
4696"ISeeWhat": {
4697src: "https://emotes.tastycat.org/emotes/misc/ISeeWhat.png",
4698titlePrefix: "ffz ",
4699},
4700"NoSkip": {
4701src: "https://emotes.tastycat.org/emotes/misc/NoSkip.png",
4702titlePrefix: "ffz ",
4703},
4704"NotSureIf": {
4705src: "https://emotes.tastycat.org/emotes/misc/NotSureIf.png",
4706titlePrefix: "ffz ",
4707},
4708"NotToday": {
4709src: "https://emotes.tastycat.org/emotes/misc/NotToday.png",
4710titlePrefix: "ffz ",
4711},
4712"Notorious": {
4713src: "https://emotes.tastycat.org/emotes/misc/Notorious.png",
4714titlePrefix: "ffz ",
4715},
4716"NyanPasu": {
4717src: "https://emotes.tastycat.org/emotes/misc/NyanPasu.png",
4718titlePrefix: "ffz ",
4719},
4720"OfficerKappa": {
4721src: "https://emotes.tastycat.org/emotes/misc/OfficerKappa.png",
4722titlePrefix: "ffz ",
4723},
4724"OhYou": {
4725src: "https://emotes.tastycat.org/emotes/misc/OhYou.png",
4726titlePrefix: "ffz ",
4727},
4728"OhYou2": {
4729src: "https://emotes.tastycat.org/emotes/misc/OhYou2.png",
4730titlePrefix: "ffz ",
4731},
4732"Orly": {
4733src: "https://emotes.tastycat.org/emotes/misc/Orly.png",
4734titlePrefix: "ffz ",
4735},
4736"Peace": {
4737src: "https://emotes.tastycat.org/emotes/misc/Peace.png",
4738titlePrefix: "ffz ",
4739},
4740"Pikachu": {
4741src: "https://emotes.tastycat.org/emotes/misc/Pikachu.png",
4742titlePrefix: "ffz ",
4743},
4744"Potato": {
4745src: "https://emotes.tastycat.org/emotes/misc/Potato.png",
4746titlePrefix: "ffz ",
4747},
4748"RageCage": {
4749src: "https://emotes.tastycat.org/emotes/misc/RageCage.png",
4750titlePrefix: "ffz ",
4751},
4752"Raptor": {
4753src: "https://emotes.tastycat.org/emotes/misc/Raptor.png",
4754titlePrefix: "ffz ",
4755},
4756"Raptor2": {
4757src: "https://emotes.tastycat.org/emotes/misc/Raptor2.png",
4758titlePrefix: "ffz ",
4759},
4760"Rigged": {
4761src: "https://emotes.tastycat.org/emotes/misc/Rigged.png",
4762titlePrefix: "ffz ",
4763},
4764"SadMuffin": {
4765src: "https://emotes.tastycat.org/emotes/misc/SadMuffin.png",
4766titlePrefix: "ffz ",
4767},
4768"Sandu": {
4769src: "https://emotes.tastycat.org/emotes/misc/Sandu.png",
4770titlePrefix: "ffz ",
4771},
4772"Rekt": {
4773src: "https://emotes.tastycat.org/emotes/misc/Rekt.png",
4774titlePrefix: "ffz ",
4775},
4776"Sanic": {
4777src: "https://emotes.tastycat.org/emotes/misc/Sanic.png",
4778titlePrefix: "ffz ",
4779},
4780"Scotland": {
4781src: "https://emotes.tastycat.org/emotes/misc/Scotland.png",
4782titlePrefix: "ffz ",
4783},
4784"Scatman": {
4785src: "https://emotes.tastycat.org/emotes/misc/Scatman.png",
4786titlePrefix: "ffz ",
4787},
4788"Serraphix": {
4789src: "https://emotes.tastycat.org/emotes/misc/Serraphix.png",
4790titlePrefix: "ffz ",
4791},
4792"Sherebug": {
4793src: "https://emotes.tastycat.org/emotes/misc/Sherebug.png",
4794titlePrefix: "ffz ",
4795},
4796"Shrek": {
4797src: "https://emotes.tastycat.org/emotes/misc/Shrek.png",
4798titlePrefix: "ffz ",
4799},
4800"Shrek2": {
4801src: "https://emotes.tastycat.org/emotes/misc/Shrek2.png",
4802titlePrefix: "ffz ",
4803},
4804"Sinful": {
4805src: "https://emotes.tastycat.org/emotes/misc/Sinful.png",
4806titlePrefix: "ffz ",
4807},
4808"Skappa": {
4809src: "https://emotes.tastycat.org/emotes/misc/Skappa.png",
4810titlePrefix: "ffz ",
4811},
4812"SlothFace": {
4813src: "https://emotes.tastycat.org/emotes/misc/SlothFace.png",
4814titlePrefix: "ffz ",
4815},
4816"Smash": {
4817src: "https://emotes.tastycat.org/emotes/misc/Smash.png",
4818titlePrefix: "ffz ",
4819},
4820"Smug2": {
4821src: "https://emotes.tastycat.org/emotes/misc/Smug2.png",
4822titlePrefix: "ffz ",
4823},
4824"SmugLiz": {
4825src: "https://emotes.tastycat.org/emotes/misc/SmugLiz.png",
4826titlePrefix: "ffz ",
4827},
4828"SoapChan": {
4829src: "https://emotes.tastycat.org/emotes/misc/SoapChan.png",
4830titlePrefix: "ffz ",
4831},
4832"Spam": {
4833src: "https://emotes.tastycat.org/emotes/misc/Spam.png",
4834titlePrefix: "ffz ",
4835},
4836"Speed": {
4837src: "https://emotes.tastycat.org/emotes/misc/Speed.png",
4838titlePrefix: "ffz ",
4839},
4840"Squappa": {
4841src: "https://emotes.tastycat.org/emotes/misc/Squappa.png",
4842titlePrefix: "ffz ",
4843},
4844"Squid": {
4845src: "https://emotes.tastycat.org/emotes/misc/Squid.png",
4846titlePrefix: "ffz ",
4847},
4848"Steve": {
4849src: "https://emotes.tastycat.org/emotes/misc/Steve.png",
4850titlePrefix: "ffz ",
4851},
4852"SuchDoge": {
4853src: "https://emotes.tastycat.org/emotes/misc/SuchDoge.png",
4854titlePrefix: "ffz ",
4855},
4856"TableFlip": {
4857src: "https://emotes.tastycat.org/emotes/misc/TableFlip.png",
4858titlePrefix: "ffz ",
4859},
4860"TheHoff": {
4861src: "https://emotes.tastycat.org/emotes/misc/TheHoff.png",
4862titlePrefix: "ffz ",
4863},
4864"Toast": {
4865src: "https://emotes.tastycat.org/emotes/misc/Toast.png",
4866titlePrefix: "ffz ",
4867},
4868"WOW": {
4869src: "https://emotes.tastycat.org/emotes/misc/WOW.png",
4870titlePrefix: "ffz ",
4871},
4872"Waffle": {
4873src: "https://emotes.tastycat.org/emotes/misc/Waffle.png",
4874titlePrefix: "ffz ",
4875},
4876"Weegee": {
4877src: "https://emotes.tastycat.org/emotes/misc/Weegee.png",
4878titlePrefix: "ffz ",
4879},
4880"YouDontSay": {
4881src: "https://emotes.tastycat.org/emotes/misc/YouDontSay.png",
4882titlePrefix: "ffz ",
4883},
4884"YouKnowIt": {
4885src: "https://emotes.tastycat.org/emotes/misc/YouKnowIt.png",
4886titlePrefix: "ffz ",
4887},
4888"Zergling": {
4889src: "https://emotes.tastycat.org/emotes/misc/Zergling.png",
4890titlePrefix: "ffz ",
4891},
4892"hhhehehe": {
4893src: "https://emotes.tastycat.org/emotes/misc/hhhehehe.png",
4894titlePrefix: "ffz ",
4895},
4896"really": {
4897src: "https://emotes.tastycat.org/emotes/misc/really.png",
4898titlePrefix: "ffz ",
4899},
4900"sGrin": {
4901src: "https://emotes.tastycat.org/emotes/misc/sGrin.png",
4902titlePrefix: "ffz ",
4903},
4904"shrug": {
4905src: "https://emotes.tastycat.org/emotes/misc/shrug.png",
4906titlePrefix: "ffz ",
4907},
4908"tfw": {
4909src: "https://emotes.tastycat.org/emotes/misc/tfw.png",
4910titlePrefix: "ffz ",
4911},
4912"uwotm8": {
4913src: "https://emotes.tastycat.org/emotes/misc/uwotm8.png",
4914titlePrefix: "ffz ",
4915},
4916"w0t": {
4917src: "https://emotes.tastycat.org/emotes/misc/w0t.png",
4918titlePrefix: "ffz ",
4919},
4920"wat": {
4921src: "https://emotes.tastycat.org/emotes/misc/wat.png",
4922titlePrefix: "ffz ",
4923},
4924"welp": {
4925src: "https://emotes.tastycat.org/emotes/misc/welp.png",
4926titlePrefix: "ffz ",
4927},
4928"welp2": {
4929src: "https://emotes.tastycat.org/emotes/misc/welp2.png",
4930titlePrefix: "ffz ",
4931},
4932"yarly": {
4933src: "https://emotes.tastycat.org/emotes/misc/yarly.png",
4934titlePrefix: "ffz ",
4935},
4936"yee": {
4937src: "https://emotes.tastycat.org/emotes/misc/yee.png",
4938titlePrefix: "ffz ",
4939},
4940"AbbyFace": {
4941src: "https://emotes.tastycat.org/emotes/userfaces/AbbyFace.png",
4942titlePrefix: "ffz ",
4943},
4944"AeroFace": {
4945src: "https://emotes.tastycat.org/emotes/userfaces/AeroFace.png",
4946titlePrefix: "ffz ",
4947},
4948"AngryFungus": {
4949src: "https://emotes.tastycat.org/emotes/userfaces/AngryFungus.png",
4950titlePrefix: "ffz ",
4951},
4952"BananaBoi": {
4953src: "https://emotes.tastycat.org/emotes/userfaces/BananaBoi.png",
4954titlePrefix: "ffz ",
4955},
4956"BasicFace": {
4957src: "https://emotes.tastycat.org/emotes/userfaces/BasicFace.png",
4958titlePrefix: "ffz ",
4959},
4960"BrayFace": {
4961src: "https://emotes.tastycat.org/emotes/userfaces/BrayFace.png",
4962titlePrefix: "ffz ",
4963},
4964"BrayPalm": {
4965src: "https://emotes.tastycat.org/emotes/userfaces/BrayPalm.png",
4966titlePrefix: "ffz ",
4967},
4968"Brayspair": {
4969src: "https://emotes.tastycat.org/emotes/userfaces/Brayspair.png",
4970titlePrefix: "ffz ",
4971},
4972"CeliFace": {
4973src: "https://emotes.tastycat.org/emotes/userfaces/CeliFace.png",
4974titlePrefix: "ffz ",
4975},
4976"CeliGlasses": {
4977src: "https://emotes.tastycat.org/emotes/userfaces/CeliGlasses.png",
4978titlePrefix: "ffz ",
4979},
4980"DNAFace": {
4981src: "https://emotes.tastycat.org/emotes/userfaces/DNAFace.png",
4982titlePrefix: "ffz ",
4983},
4984"Dutto": {
4985src: "https://emotes.tastycat.org/emotes/userfaces/Dutto.png",
4986titlePrefix: "ffz ",
4987},
4988"EmsiFace": {
4989src: "https://emotes.tastycat.org/emotes/userfaces/EmsiFace.png",
4990titlePrefix: "ffz ",
4991},
4992"EmsiPalm": {
4993src: "https://emotes.tastycat.org/emotes/userfaces/EmsiPalm.png",
4994titlePrefix: "ffz ",
4995},
4996"Fatsify": {
4997src: "https://emotes.tastycat.org/emotes/userfaces/Fatsify.png",
4998titlePrefix: "ffz ",
4999},
5000"FlashFace": {
5001src: "https://emotes.tastycat.org/emotes/userfaces/FlashFace.png",
5002titlePrefix: "ffz ",
5003},
5004"FrantixFace": {
5005src: "https://emotes.tastycat.org/emotes/userfaces/FrantixFace.png",
5006titlePrefix: "ffz ",
5007},
5008"FungChamp": {
5009src: "https://emotes.tastycat.org/emotes/userfaces/FungChamp.png",
5010titlePrefix: "ffz ",
5011},
5012"FungFace": {
5013src: "https://emotes.tastycat.org/emotes/userfaces/FungFace.png",
5014titlePrefix: "ffz ",
5015},
5016"HallyFace": {
5017src: "https://emotes.tastycat.org/emotes/userfaces/HallyFace.png",
5018titlePrefix: "ffz ",
5019},
5020"Hekya": {
5021src: "https://emotes.tastycat.org/emotes/userfaces/Hekya.png",
5022titlePrefix: "ffz ",
5023},
5024"HighBray": {
5025src: "https://emotes.tastycat.org/emotes/userfaces/HighBray.gif",
5026titlePrefix: "ffz ",
5027},
5028"HighEmsi": {
5029src: "https://emotes.tastycat.org/emotes/userfaces/HighEmsi.gif",
5030titlePrefix: "ffz ",
5031},
5032"IgorFace": {
5033src: "https://emotes.tastycat.org/emotes/userfaces/IgorFace.png",
5034titlePrefix: "ffz ",
5035},
5036"IlyiaFace": {
5037src: "https://emotes.tastycat.org/emotes/userfaces/IlyiaFace.png",
5038titlePrefix: "ffz ",
5039},
5040"InYoShere": {
5041src: "https://emotes.tastycat.org/emotes/userfaces/InYoShere.gif",
5042titlePrefix: "ffz ",
5043},
5044"KatieFace": {
5045src: "https://emotes.tastycat.org/emotes/userfaces/KatieFace.png",
5046titlePrefix: "ffz ",
5047},
5048"Labitch": {
5049src: "https://emotes.tastycat.org/emotes/userfaces/Labitch.png",
5050titlePrefix: "ffz ",
5051},
5052"MuffinChin": {
5053src: "https://emotes.tastycat.org/emotes/userfaces/MuffinChin.png",
5054titlePrefix: "ffz ",
5055},
5056"MuffinFace": {
5057src: "https://emotes.tastycat.org/emotes/userfaces/MuffinFace.png",
5058titlePrefix: "ffz ",
5059},
5060"MuffinLean": {
5061src: "https://emotes.tastycat.org/emotes/userfaces/MuffinLean.png",
5062titlePrefix: "ffz ",
5063},
5064"MuffinSmile": {
5065src: "https://emotes.tastycat.org/emotes/userfaces/MuffinSmile.png",
5066titlePrefix: "ffz ",
5067},
5068"MuffinWhat": {
5069src: "https://emotes.tastycat.org/emotes/userfaces/MuffinWhat.png",
5070titlePrefix: "ffz ",
5071},
5072"MuzzyFace": {
5073src: "https://emotes.tastycat.org/emotes/userfaces/MuzzyFace.png",
5074titlePrefix: "ffz ",
5075},
5076"NashiFairy": {
5077src: "https://emotes.tastycat.org/emotes/userfaces/NashiFairy.png",
5078titlePrefix: "ffz ",
5079},
5080"NashiTutu": {
5081src: "https://emotes.tastycat.org/emotes/userfaces/NashiTutu.png",
5082titlePrefix: "ffz ",
5083},
5084"OmiFace": {
5085src: "https://emotes.tastycat.org/emotes/userfaces/OmiFace.png",
5086titlePrefix: "ffz ",
5087},
5088"PuhzestFace": {
5089src: "https://emotes.tastycat.org/emotes/userfaces/PuhzestFace.png",
5090titlePrefix: "ffz ",
5091},
5092"PandaFace": {
5093src: "https://emotes.tastycat.org/emotes/userfaces/PandaFace.png",
5094titlePrefix: "ffz ",
5095},
5096"RaptorFace": {
5097src: "https://emotes.tastycat.org/emotes/userfaces/RaptorFace.png",
5098titlePrefix: "ffz ",
5099},
5100"RaptorPalm": {
5101src: "https://emotes.tastycat.org/emotes/userfaces/RaptorPalm.png",
5102titlePrefix: "ffz ",
5103},
5104"Refute": {
5105src: "https://emotes.tastycat.org/emotes/userfaces/Refute.png",
5106titlePrefix: "ffz ",
5107},
5108"RowanFace": {
5109src: "https://emotes.tastycat.org/emotes/userfaces/RowanFace.png",
5110titlePrefix: "ffz ",
5111},
5112"SandyFace": {
5113src: "https://emotes.tastycat.org/emotes/userfaces/SandyFace.png",
5114titlePrefix: "ffz ",
5115},
5116"SchlurbiDwit": {
5117src: "https://emotes.tastycat.org/emotes/userfaces/SchlurbiDwit.png",
5118titlePrefix: "ffz ",
5119},
5120"SchlurbiFace": {
5121src: "https://emotes.tastycat.org/emotes/userfaces/SchlurbiFace.png",
5122titlePrefix: "ffz ",
5123},
5124"SchlurbiHappy": {
5125src: "https://emotes.tastycat.org/emotes/userfaces/SchlurbiHappy.png",
5126titlePrefix: "ffz ",
5127},
5128"SchlurbiTongue": {
5129src: "https://emotes.tastycat.org/emotes/userfaces/SchlurbiTongue.png",
5130titlePrefix: "ffz ",
5131},
5132"ShazzkaFace": {
5133src: "https://emotes.tastycat.org/emotes/userfaces/ShazzkaFace.png",
5134titlePrefix: "ffz ",
5135},
5136"ShereButt": {
5137src: "https://emotes.tastycat.org/emotes/userfaces/ShereButt.png",
5138titlePrefix: "ffz ",
5139},
5140"ShereFace": {
5141src: "https://emotes.tastycat.org/emotes/userfaces/ShereFace.png",
5142titlePrefix: "ffz ",
5143},
5144"ShereShave": {
5145src: "https://emotes.tastycat.org/emotes/userfaces/ShereShave.png",
5146titlePrefix: "ffz ",
5147},
5148"ShereSpin": {
5149src: "https://emotes.tastycat.org/emotes/userfaces/ShereSpin.gif",
5150titlePrefix: "ffz ",
5151},
5152"ShereStache": {
5153src: "https://emotes.tastycat.org/emotes/userfaces/ShereStache.png",
5154titlePrefix: "ffz ",
5155},
5156"Sherebie": {
5157src: "https://emotes.tastycat.org/emotes/userfaces/Sherebie.png",
5158titlePrefix: "ffz ",
5159},
5160"Sheretato": {
5161src: "https://emotes.tastycat.org/emotes/userfaces/Sheretato.png",
5162titlePrefix: "ffz ",
5163},
5164"SloaneFace": {
5165src: "https://emotes.tastycat.org/emotes/userfaces/SloaneFace.png",
5166titlePrefix: "ffz ",
5167},
5168"SloaneSmile": {
5169src: "https://emotes.tastycat.org/emotes/userfaces/SloaneSmile.png",
5170titlePrefix: "ffz ",
5171},
5172"SpekFace": {
5173src: "https://emotes.tastycat.org/emotes/userfaces/SpekFace.png",
5174titlePrefix: "ffz ",
5175},
5176"StanFace": {
5177src: "https://emotes.tastycat.org/emotes/userfaces/StanFace.png",
5178titlePrefix: "ffz ",
5179},
5180"Steven": {
5181src: "https://emotes.tastycat.org/emotes/userfaces/Steven.png",
5182titlePrefix: "ffz ",
5183},
5184"Soul": {
5185src: "https://emotes.tastycat.org/emotes/userfaces/Soul.png",
5186titlePrefix: "ffz ",
5187},
5188"SuperFace": {
5189src: "https://emotes.tastycat.org/emotes/userfaces/SuperFace.png",
5190titlePrefix: "ffz ",
5191},
5192"UpSkirt": {
5193src: "https://emotes.tastycat.org/emotes/userfaces/UpSkirt.png",
5194titlePrefix: "ffz ",
5195},
5196"WTFungus": {
5197src: "https://emotes.tastycat.org/emotes/userfaces/WTFungus.png",
5198titlePrefix: "ffz ",
5199},
5200"BearDance": {
5201src: "https://emotes.tastycat.org/emotes/gifs/BearDance.gif",
5202titlePrefix: "ffz ",
5203},
5204"Bouncy": {
5205src: "https://emotes.tastycat.org/emotes/gifs/Bouncy.gif",
5206titlePrefix: "ffz ",
5207},
5208"CantTouchThis": {
5209src: "https://emotes.tastycat.org/emotes/gifs/CantTouchThis.gif",
5210titlePrefix: "ffz ",
5211},
5212"CarltonDance": {
5213src: "https://emotes.tastycat.org/emotes/gifs/CarltonDance.gif",
5214titlePrefix: "ffz ",
5215},
5216"Chompy": {
5217src: "https://emotes.tastycat.org/emotes/gifs/Chompy.gif",
5218titlePrefix: "ffz ",
5219},
5220"Ditto": {
5221src: "https://emotes.tastycat.org/emotes/gifs/Ditto.gif",
5222titlePrefix: "ffz ",
5223},
5224"Donk": {
5225src: "https://emotes.tastycat.org/emotes/gifs/Donk.gif",
5226titlePrefix: "ffz ",
5227},
5228"EcaFoYnI": {
5229src: "https://emotes.tastycat.org/emotes/gifs/EcaFoYnI.gif",
5230titlePrefix: "ffz ",
5231},
5232"Firework": {
5233src: "https://emotes.tastycat.org/emotes/gifs/Firework.gif",
5234titlePrefix: "ffz ",
5235},
5236"Flappy": {
5237src: "https://emotes.tastycat.org/emotes/gifs/Flappy.gif",
5238titlePrefix: "ffz ",
5239},
5240"HappyIsaac": {
5241src: "https://emotes.tastycat.org/emotes/gifs/HappyIsaac.gif",
5242titlePrefix: "ffz ",
5243},
5244"Headbang": {
5245src: "https://emotes.tastycat.org/emotes/gifs/Headbang.gif",
5246titlePrefix: "ffz ",
5247},
5248"Gir": {
5249src: "https://emotes.tastycat.org/emotes/gifs/Gir.gif",
5250titlePrefix: "ffz ",
5251},
5252"HeartGrab": {
5253src: "https://emotes.tastycat.org/emotes/gifs/HeartGrab.gif",
5254titlePrefix: "ffz ",
5255},
5256"HighRowan": {
5257src: "https://emotes.tastycat.org/emotes/gifs/HighRowan.gif",
5258titlePrefix: "ffz ",
5259},
5260"HighShere": {
5261src: "https://emotes.tastycat.org/emotes/gifs/HighShere.gif",
5262titlePrefix: "ffz ",
5263},
5264"Hypnotoad": {
5265src: "https://emotes.tastycat.org/emotes/gifs/Hypnotoad.gif",
5266titlePrefix: "ffz ",
5267},
5268"InYoFace": {
5269src: "https://emotes.tastycat.org/emotes/gifs/InYoFace.gif",
5270titlePrefix: "ffz ",
5271},
5272"JeffSpin": {
5273src: "https://emotes.tastycat.org/emotes/gifs/JeffSpin.gif",
5274titlePrefix: "ffz ",
5275},
5276"JuanAndOnly": {
5277src: "https://emotes.tastycat.org/emotes/gifs/JuanAndOnly.gif",
5278titlePrefix: "ffz ",
5279},
5280"KappaSpin": {
5281src: "https://emotes.tastycat.org/emotes/gifs/KappaSpin.gif",
5282titlePrefix: "ffz ",
5283},
5284"KirbyHP": {
5285src: "https://emotes.tastycat.org/emotes/gifs/KirbyHP.gif",
5286titlePrefix: "ffz ",
5287},
5288"Kong": {
5289src: "https://emotes.tastycat.org/emotes/gifs/Kong.gif",
5290titlePrefix: "ffz ",
5291},
5292"KarateDance": {
5293src: "https://emotes.tastycat.org/emotes/gifs/KarateDance.gif",
5294titlePrefix: "ffz ",
5295},
5296"Kappai": {
5297src: "https://emotes.tastycat.org/emotes/gifs/Kappai.gif",
5298titlePrefix: "ffz ",
5299},
5300"Kupo": {
5301src: "https://emotes.tastycat.org/emotes/gifs/Kupo.gif",
5302titlePrefix: "ffz ",
5303},
5304"MarioJackson": {
5305src: "https://emotes.tastycat.org/emotes/gifs/MarioJackson.gif",
5306titlePrefix: "ffz ",
5307},
5308"MudkipDance": {
5309src: "https://emotes.tastycat.org/emotes/gifs/MudkipDance.gif",
5310titlePrefix: "ffz ",
5311},
5312"NoBones": {
5313src: "https://emotes.tastycat.org/emotes/gifs/NoBones.gif",
5314titlePrefix: "ffz ",
5315},
5316"PBJTime": {
5317src: "https://emotes.tastycat.org/emotes/gifs/PBJTime.gif",
5318titlePrefix: "ffz ",
5319},
5320"PeanutDance": {
5321src: "https://emotes.tastycat.org/emotes/gifs/PeanutDance.gif",
5322titlePrefix: "ffz ",
5323},
5324"PugLife": {
5325src: "https://emotes.tastycat.org/emotes/gifs/PugLife.gif",
5326titlePrefix: "ffz ",
5327},
5328"Putinonaritz": {
5329src: "https://emotes.tastycat.org/emotes/gifs/Putinonaritz.gif",
5330titlePrefix: "ffz ",
5331},
5332"RaptorDance": {
5333src: "https://emotes.tastycat.org/emotes/gifs/RaptorDance.gif",
5334titlePrefix: "ffz ",
5335},
5336"Ravechu": {
5337src: "https://emotes.tastycat.org/emotes/gifs/Ravechu.gif",
5338titlePrefix: "ffz ",
5339},
5340"RedPanda": {
5341src: "https://emotes.tastycat.org/emotes/gifs/RedPanda.gif",
5342titlePrefix: "ffz ",
5343},
5344"SadBear": {
5345src: "https://emotes.tastycat.org/emotes/gifs/SadBear.gif",
5346titlePrefix: "ffz ",
5347},
5348"Shepard": {
5349src: "https://emotes.tastycat.org/emotes/gifs/Shepard.gif",
5350titlePrefix: "ffz ",
5351},
5352"Snoop": {
5353src: "https://emotes.tastycat.org/emotes/gifs/Snoop.gif",
5354titlePrefix: "ffz ",
5355},
5356"Stitch": {
5357src: "https://emotes.tastycat.org/emotes/gifs/Stitch.gif",
5358titlePrefix: "ffz ",
5359},
5360"Twerk": {
5361src: "https://emotes.tastycat.org/emotes/gifs/Twerk.gif",
5362titlePrefix: "ffz ",
5363},
5364"TwoHearts": {
5365src: "https://emotes.tastycat.org/emotes/gifs/TwoHearts.gif",
5366titlePrefix: "ffz ",
5367},
5368"WarmBeat": {
5369src: "https://emotes.tastycat.org/emotes/gifs/WarmBeat.gif",
5370titlePrefix: "ffz ",
5371},
5372"DanceCat": {
5373src: "https://emotes.tastycat.org/emotes/tastycat/DanceCat.gif",
5374titlePrefix: "ffz ",
5375},
5376"DnbCat": {
5377src: "https://emotes.tastycat.org/emotes/tastycat/DnbCat.png",
5378titlePrefix: "ffz ",
5379},
5380"DrumstepCat": {
5381src: "https://emotes.tastycat.org/emotes/tastycat/DrumstepCat.png",
5382titlePrefix: "ffz ",
5383},
5384"DubstepCat": {
5385src: "https://emotes.tastycat.org/emotes/tastycat/DubstepCat.png",
5386titlePrefix: "ffz ",
5387},
5388"EdmCat": {
5389src: "https://emotes.tastycat.org/emotes/tastycat/EdmCat.png",
5390titlePrefix: "ffz ",
5391},
5392"ElectroCat": {
5393src: "https://emotes.tastycat.org/emotes/tastycat/ElectroCat.png",
5394titlePrefix: "ffz ",
5395},
5396"FutureBassCat": {
5397src: "https://emotes.tastycat.org/emotes/tastycat/FutureBassCat.png",
5398titlePrefix: "ffz ",
5399},
5400"HardDanceCat": {
5401src: "https://emotes.tastycat.org/emotes/tastycat/HardDanceCat.png",
5402titlePrefix: "ffz ",
5403},
5404"GlitchCat": {
5405src: "https://emotes.tastycat.org/emotes/tastycat/GlitchCat.png",
5406titlePrefix: "ffz ",
5407},
5408"HouseCat": {
5409src: "https://emotes.tastycat.org/emotes/tastycat/HouseCat.png",
5410titlePrefix: "ffz ",
5411},
5412"Monsterbutt": {
5413src: "https://emotes.tastycat.org/emotes/tastycat/Monsterbutt.png",
5414titlePrefix: "ffz ",
5415},
5416"Monstercat": {
5417src: "https://emotes.tastycat.org/emotes/tastycat/Monstercat.png",
5418titlePrefix: "ffz ",
5419},
5420"NuDiscoCat": {
5421src: "https://emotes.tastycat.org/emotes/tastycat/NuDiscoCat.png",
5422titlePrefix: "ffz ",
5423},
5424"RainbowCat": {
5425src: "https://emotes.tastycat.org/emotes/tastycat/RainbowCat.gif",
5426titlePrefix: "ffz ",
5427},
5428"RaveCat": {
5429src: "https://emotes.tastycat.org/emotes/tastycat/RaveCat.gif",
5430titlePrefix: "ffz ",
5431},
5432"Tasty": {
5433src: "https://emotes.tastycat.org/emotes/tastycat/Tasty.png",
5434titlePrefix: "ffz ",
5435},
5436"TastyBot": {
5437src: "https://emotes.tastycat.org/emotes/tastycat/TastyBot.png",
5438titlePrefix: "ffz ",
5439},
5440"TastyKitten": {
5441src: "https://emotes.tastycat.org/emotes/tastycat/TastyKitten.png",
5442titlePrefix: "ffz ",
5443},
5444"Tastycat": {
5445src: "https://emotes.tastycat.org/emotes/tastycat/Tastycat.png",
5446titlePrefix: "ffz ",
5447},
5448"TranceCat": {
5449src: "https://emotes.tastycat.org/emotes/tastycat/TranceCat.png",
5450titlePrefix: "ffz ",
5451},
5452"TrapCat": {
5453src: "https://emotes.tastycat.org/emotes/tastycat/TrapCat.png",
5454titlePrefix: "ffz ",
5455},
5456
5457 };
5458
5459 twitch.templates.global = globalEmotes.template;
5460 twitch.templates.subscriber = subEmotes.template;
5461
5462 // Handle twitch based emotes
5463 jQ.each(globalEmotes.emotes, function (code, emote) {
5464 if (!emote.image_id) {
5465 throw "Missing image ID for " + code;
5466 }
5467 twitch.emotes[code] = { image_id: emote.image_id, type: "global" };
5468
5469 if (code.search(/\W/) > -1) {
5470 twitch.nonalphabetic[code] = twitch.emotes[code];
5471 }
5472 });
5473
5474 jQ.each(subEmotes.channels, function (channel, channelObj) {
5475 jQ.each(channelObj.emotes, function (index, emote) {
5476 var code = emote.code;
5477 if (/^([A-Z][a-z]*|[A-Z]+|[a-z]+)$/.test(code)) {
5478 twitch.blacklist[code] = {
5479 image_id: emote.image_id,
5480 channel: channel,
5481 type: "subscriber"
5482 };
5483 }
5484 else {
5485 twitch.emotes[code] = {
5486 image_id: emote.image_id,
5487 channel: channel,
5488 type: "subscriber"
5489 };
5490
5491 if (code.search(/\W/) > -1) {
5492 twitch.nonalphabetic[code] = twitch.emotes[code];
5493 }
5494 }
5495 });
5496 });
5497
5498 // Handle FFZ emotes
5499 jQ.each(ffzEmotes.sets, function (setName, set) {
5500 jQ.each(set.emoticons, function (index, emote) {
5501 var code = emote.name;
5502
5503 if (!emote.urls[1]) {
5504 throw "Missing source url for " + code;
5505 }
5506
5507 twitch.emotes[code] = {
5508 css: emote.css,
5509 margins: emote.margins,
5510 src: emote.urls[1],
5511 type: "ffz",
5512 };
5513
5514 if (code.search(/\W/) > -1) {
5515 twitch.nonalphabetic[code] = twitch.emotes[code];
5516 }
5517 });
5518 });
5519
5520 // Handle special emotes
5521 jQ.each(specialEmotes, function (code, emote) {
5522 twitch.emotes[code] = {
5523 src: emote.src,
5524 titlePrefix: emote.titlePrefix,
5525 type: "special",
5526 };
5527
5528 if (code.search(/\W/) > -1) {
5529 twitch.nonalphabetic[code] = twitch.emotes[code];
5530 }
5531 });
5532 }
5533 catch (e) {
5534 // Emote loading failed
5535 console.error(e);
5536 console.error("Twitch emotes have not loaded. This is likely to be an API error " +
5537 "(check https://dl.dropboxusercontent.com/s/v3pwhew8apgtf18/global.json " +
5538 "https://dl.dropboxusercontent.com/s/wdlo8pvpnpv6cmf/subscriber.json and https://dl.dropboxusercontent.com/s/e5bgmf8g12afppe/api.frankerfacez )");
5539 bpOverlay.emoteError = true;
5540 }
5541// @resource twitch_global https://dl.dropboxusercontent.com/s/v3pwhew8apgtf18/global.json
5542// @resource twitch_subscriber https://dl.dropboxusercontent.com/s/wdlo8pvpnpv6cmf/subscriber.json
5543// @resource ffz_emotes https://dl.dropboxusercontent.com/s/e5bgmf8g12afppe/api.frankerfacez
5544 var twitchify_new = function (message) {
5545 if (!bpOverlay.twitchOn || bpOverlay.emoteError)
5546 return message;
5547
5548 function getEmote(code, emote) {
5549 if (twitch.emotes[code] || emote) {
5550 emote = emote || twitch.emotes[code];
5551
5552 var src;
5553 var title;
5554 switch (emote.type) {
5555 case "ffz":
5556 src = emote.src;
5557 title = "(ffz) " + code;
5558 break;
5559 case "subscriber":
5560 src = twitch.templates.global.small.replace(
5561 "{image_id}", emote.image_id);
5562 title = emote.channel + " > " + code;
5563 break;
5564 case "global":
5565 src = twitch.templates.subscriber.small.replace(
5566 "{image_id}", emote.image_id);
5567 title = code;
5568 break;
5569 case "special":
5570 src = emote.src;
5571 title = emote.titlePrefix + code;
5572 break;
5573 }
5574
5575 var margins = emote.margins;
5576
5577 return '<img src="' + src + '" alt="' + code +
5578 '" title="' + title +
5579 (margins ? '" style="margin:' + margins : "") +
5580 '" class="emoticon"></img>';
5581 }
5582 else {
5583 return code;
5584 }
5585 }
5586
5587 // Deal with nonalphanumeric emotes first
5588 var words = message.split(/(<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>| )/);
5589 for (var i = 0; i < words.length; i++) {
5590 if (twitch.nonalphabetic[words[i]]) {
5591 words[i] = getEmote(words[i]);
5592 }
5593 }
5594 message = words.join("");
5595
5596 words = message.split(/(<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>|\W)/);
5597 for (i = 0; i < words.length; i++) {
5598 words[i] = getEmote(words[i]);
5599 }
5600
5601 message = words.join("");
5602
5603 // Deal with blacklisted emotes
5604 return message.replace(/\[[^\]]+\]/g, function (match) {
5605 var code = match.substring(1, match.length - 1);
5606 if (twitch.blacklist[code]) {
5607 return getEmote(match, twitch.blacklist[code]);
5608 }
5609 return match;
5610 });
5611 };
5612 // It now makes more sense to have the twitch emotes in a separate function
5613 var twitchify = function (message) {
5614 message = twitchify_new(message);
5615 if (bpOverlay.markupOn) {
5616 // Quick and dirty
5617 // Undo the escaping the <b> <i> <s> and <u> tags.
5618 // Not sure if this is completely okay, but whatever for now
5619 message = message.replace(/<(\/?[BISUbisu])>/g, "<$1>");
5620 }
5621 return message;
5622 };
5623
5624 // Inline custom markdown support
5625 var inline = {
5626 escape: /^\\([\\`*{}\[\]()#+\-.!_>~])/,
5627 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
5628 strong: /^\*\*([\s\S]+?)\*\*(?!\*)/,
5629 underline: /^__([\s\S]+?)__(?!_)/,
5630 del: /^~~(?=\S)([\s\S]*?\S)~~/,
5631 em: /^\b_((?:__|[\s\S])+?)_\b|^\*(?=\S)((?:\*\*|\s+[^\*\s]|[^\s\*])*?[^\s\*])\*(?!\*)/,
5632 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
5633 br: /^ {2,}\n(?!\s*$)/,
5634 text: /^[\s\S]+?(?=[\\<!\[_*`~]| {2,}\n|$)/
5635 };
5636
5637 var inlineLex = function (src) {
5638 var out = "";
5639
5640 while (src) {
5641 // escape
5642 if (cap = inline.escape.exec(src)) {
5643 src = src.substring(cap[0].length);
5644 out += cap[1];
5645 continue;
5646 }
5647
5648 // tag
5649 if (cap = inline.tag.exec(src)) {
5650 // Leave it alone
5651 src = src.substring(cap[0].length);
5652 out += cap[0];
5653 continue;
5654 }
5655
5656 // strong
5657 if (cap = inline.strong.exec(src)) {
5658 src = src.substring(cap[0].length);
5659 out += "<strong>" + inlineLex(cap[2] || cap[1]) + "</strong>";
5660 continue;
5661 }
5662
5663 // underline
5664 if (cap = inline.underline.exec(src)) {
5665 src = src.substring(cap[0].length);
5666 // Fuck it, just going to use inline styles
5667 out += "<span style=\"text-decoration: underline\">" + inlineLex(cap[2] || cap[1]) + "</span>";
5668 continue;
5669 }
5670
5671 // em
5672 if (cap = inline.em.exec(src)) {
5673 src = src.substring(cap[0].length);
5674 out += "<em>" + inlineLex(cap[2] || cap[1]) + "</em>";
5675 continue;
5676 }
5677
5678 // del
5679 if (cap = inline.del.exec(src)) {
5680 src = src.substring(cap[0].length);
5681 out += "<del>" + inlineLex(cap[1]) + "</del>";
5682 continue;
5683 }
5684
5685 // code
5686 if (cap = inline.code.exec(src)) {
5687 src = src.substring(cap[0].length);
5688 out += "<code>" + inlineLex(cap[2] || cap[1]) + "</code>";
5689 continue;
5690 }
5691
5692 // br
5693 if (cap = inline.br.exec(src)) {
5694 src = src.substring(cap[0].length);
5695 out += "<br>";
5696 continue;
5697 }
5698
5699 // text
5700 if (cap = inline.text.exec(src)) {
5701 src = src.substring(cap[0].length);
5702 out += cap[0];
5703 continue;
5704 }
5705
5706 if (src) {
5707 throw new Error("Infinite loop starting at: " + src);
5708 }
5709 }
5710
5711 return out;
5712 };
5713
5714 var markdown = function (message) {
5715 try {
5716 return inlineLex(message);
5717 }
5718 catch (e) {
5719 console.log("An error occured whilst parsing markdown:\n" + e.message);
5720 return message;
5721 }
5722 };
5723
5724 // Since a lot of the functions the bot needs to do has to happen before the game updates the state of everything
5725 // We wrap the default game functions to force them to be called after our custom code.
5726 var wrapGameFunctions = function() {
5727
5728 // Context Menus!
5729 jQ(function () {
5730 jQ.contextMenu({
5731 selector: ".User",
5732 items: {
5733 "ban": {
5734 name: i18n.t("nuclearnode:chat.ban"),
5735 className: "contextMenuBanButton",
5736 callback: function () {
5737 var button = jQ(".contextMenuBanButton")[0];
5738 if (button.dataset.state === "1") {
5739 channel.socket.emit("banUser", {displayName: channel.data.usersByAuthId[this[0].dataset.authId].displayName, authId: this[0].dataset.authId});
5740 return true;
5741 }
5742 else {
5743 button.dataset.state = "1";
5744 button.textContent = tran.t("areYouSure");
5745 return false;
5746 }
5747 },
5748 disabled: function (key, opt) {
5749 return !(this[0].dataset.authId && channel.data.usersByAuthId[this[0].dataset.authId] && ["host", "moderator", "hubAdministrator"].indexOf(app.user.role) >= 0)
5750 },
5751 },
5752 "mod": {
5753 name: i18n.t("nuclearnode:chat.mod"),
5754 className: "contextMenuModButton",
5755 callback: function () {
5756 var button = jQ(".contextMenuModButton")[0];
5757 if (button.dataset.state === "1") {
5758 channel.socket.emit("modUser", {displayName: channel.data.usersByAuthId[this[0].dataset.authId].displayName, authId: this[0].dataset.authId});
5759 return true;
5760 }
5761 else {
5762 button.dataset.state = "1";
5763 button.textContent = tran.t("areYouSure");
5764 return false;
5765 }
5766 },
5767 disabled: function (key, opt) {
5768 return !(this[0].dataset.authId && channel.data.usersByAuthId[this[0].dataset.authId] && ["host", "hubAdministrator"].indexOf(app.user.role) >= 0)
5769 },
5770 },
5771 "mute": {
5772 name: "Mute",
5773 callback: function () {
5774 bpOverlay.ignoring[this[0].dataset.authId] = channel.data.usersByAuthId[this[0].dataset.authId].displayName;
5775 var toMute = jQ(".Author-" + this[0].dataset.authId.replace(/:/g, "_"));
5776 for (var i = 0; i < toMute.length; i++) {
5777 toMute[i].style.opacity = .4;
5778 }
5779 updateMuted();
5780 return true;
5781 },
5782 disabled: function (key, opt) {
5783 return !(this[0].dataset.authId && channel.data.usersByAuthId[this[0].dataset.authId])
5784 },
5785 },
5786 }
5787 });
5788
5789 jQ(document.body).on("contextmenu:blur", ".context-menu-item",
5790 function (e) {
5791 var contextMenuItems = jQ(".context-menu-item");
5792 for (var i = 0; i < contextMenuItems.length; i++) {
5793 var item = contextMenuItems[i];
5794 if (item.classList.contains("contextMenuBanButton")) {
5795 item.dataset.state = "0";
5796 item.textContent = i18n.t("nuclearnode:chat.ban");
5797 }
5798 else if (item.classList.contains("contextMenuModButton")) {
5799 item.dataset.state = "0";
5800 item.textContent = i18n.t("nuclearnode:chat.mod");
5801 }
5802 }
5803 }
5804 );
5805 });
5806
5807 // A little wrapper thing to make the canvas fill up the gameImages object
5808 var ctx = canvasContext;
5809 ctx.drawImageRedux = ctx.drawImage; // Do a little wrapping
5810 ctx.drawImage = function () {
5811 for (i = 0; i < missingGameImgs.length; i++) {
5812 if (arguments[0].src.toLowerCase().indexOf("/images/" + missingGameImgs[i].toLowerCase() + ".png") != -1) {
5813 // Fill up gameImages
5814 gameImages[missingGameImgs[i]] = arguments[0];
5815 backupSources[missingGameImgs[i]] = arguments[0].src;
5816 if (bpOverlay.isThemed) {
5817 replaceImage(missingGameImgs[i]);
5818 }
5819
5820 missingGameImgs.splice(i, 1);
5821 break;
5822 }
5823 }
5824
5825 // If there has been an offset specified, apply it
5826 var replaced = false;
5827 for (var i in replacementOffsets) {
5828 if (gameImages[i] && gameImages[i].src === arguments[0].src) {
5829 replaced = replacementOffsets[i];
5830 ctx.translate(replaced.x, replaced.y);
5831 break;
5832 }
5833 }
5834
5835 // Of course, we need to call the actual function first
5836 var val = ctx.drawImageRedux.apply(this, arguments);
5837
5838 // reset the offset
5839 if (replaced) {
5840 ctx.translate(-replaced.x, -replaced.y);
5841 }
5842 return val;
5843 };
5844
5845 // I guess I'm wrapping this as well
5846 channel.socket.listeners("chatMessage").pop();
5847 channel.socket.on("chatMessage", function(e) {
5848 if (!bpOverlay.ignoring[e.userAuthId]) {
5849 var notified = false;
5850 var index;
5851 if (e.text) {
5852 var lowercaseText = e.text.toLowerCase();
5853 if (bpOverlay.notifications) {
5854 if ((index = lowercaseText.indexOf(app.user.displayName.toLowerCase())) !== -1) {
5855 if ((index === 0 || lowercaseText[index-1].search(/\W/) !== -1) &&
5856 (index + app.user.displayName.length >= lowercaseText.length || lowercaseText[index + app.user.displayName.length].search(/\W/) !== -1)) {
5857 if (bpOverlay.is_hidden) {
5858 bpOverlay.notificationSound.play();
5859 }
5860 notified = true;
5861 }
5862 }
5863 else {
5864 var i = 0;
5865 for (; i < bpOverlay.alias.length; i++) {
5866 if ((index = lowercaseText.indexOf(bpOverlay.alias[i])) !== -1) {
5867 if ((index === 0 || lowercaseText[index-1].search(/\W/) !== -1) &&
5868 (index + bpOverlay.alias[i].length >= lowercaseText.length || lowercaseText[index + bpOverlay.alias[i].length].search(/\W/) !== -1)) {
5869 if (bpOverlay.is_hidden) {
5870 bpOverlay.notificationSound.play();
5871 }
5872 notified = true;
5873 break;
5874 }
5875 }
5876 }
5877 }
5878 }
5879 }
5880
5881 null != e.userAuthId ? channel.appendToChat("Message Author-" + e.userAuthId.replace(/:/g, "_") + (notified ? " highlighted" : ""), JST["nuclearnode/chatMessage"]({
5882 text: e.text,
5883 author: JST["nuclearnode/chatUser"]({
5884 user: channel.data.usersByAuthId[e.userAuthId],
5885 i18n: i18n,
5886 app: app
5887 })
5888 })) : channel.appendToChat("msg" + (notified ? " highlighted" : ""), i18n.t("nuclearnode:chat." + e.text))
5889 }
5890 });
5891
5892 // Screw your function for handling chat messages, Elisee
5893 // I'm going to make a better one! With blackjack! And hookers!
5894 JST["nuclearnode/chatMessage"] = function (e) {
5895 var t;
5896 var a = [];
5897 var n = e || {};
5898
5899 return function (e, n) {
5900 a.push(
5901 (null == (t = e) ? "" : t) +
5902 ': <span class="Content">' +
5903 markdown(twitchify(Autolinker.link(jade.escape(null == (t = n) ? "" : t), {
5904 className: "chatMessageLink"
5905 }))) + // This function is literally the exact same as before except for this line
5906 "</span>")
5907 }.call(this, "author" in n ? n.author : "undefined" != typeof author ? author : void 0, "text" in n ? n.text : "undefined" != typeof text ? text : void 0), a.join("")
5908 };
5909
5910 // Get rid of the annoying Ban and Mod buttons next to the chat message.
5911 JST["nuclearnode/chatUser"] = function (e) {
5912 // Again, this is just elisee's code with like just a tiny bit changed
5913 var t, a = [],
5914 n = e || {};
5915 return function (e, n, r) {
5916 var l = [];
5917 (function () {
5918 var t = e.serviceHandles;
5919 if ("number" == typeof t.length)
5920 for (var a = 0, r = t.length; r > a; a++) {
5921 var s = t[a];
5922 null == s && (s = n.t("nuclearnode:serviceHandlePlaceholder")), "guest" != a && l.push(n.t("nuclearnode:userHandleOnService", {
5923 handle: s,
5924 service: n.t("nuclearnode:loginServices." + a)
5925 }))
5926 } else {
5927 var r = 0;
5928 for (var a in t) {
5929 r++;
5930 var s = t[a];
5931 null == s && (s = n.t("nuclearnode:serviceHandlePlaceholder")), "guest" != a && l.push(n.t("nuclearnode:userHandleOnService", {
5932 handle: s,
5933 service: n.t("nuclearnode:loginServices." + a)
5934 }))
5935 }
5936 }
5937 })
5938 .call(this), a.push("<span" + jade.attr("title", l.join(", "), !0, !1) + (e.authId ? jade.attr("data-auth-id", e.authId, !0, !1) : "") + ' class="User">'), "" != e.role && a.push("<span" + jade.attr("title", n.t("nuclearnode:userRoles." + e.role), !0, !1) + jade.cls(["UserRole_" + e.role], [!0]) + "></span> "), a.push(jade.escape(null == (t = e.displayName) ? "" : t)), a.push("</span>")
5939 // Got rid of the Ban and Mod buttons from the line above
5940 }.call(this, "user" in n ? n.user : "undefined" != typeof user ? user : void 0, "i18n" in n ? n.i18n : "undefined" != typeof i18n ? i18n : void 0, "app" in n ? n.app : "undefined" != typeof app ? app : void 0), a.join("")
5941 }
5942 // Those buttons are being rid of so we don't accidentally ban people when trying to chat
5943 // A list of people that you can ban will be provided
5944
5945 // Chat message wrapper
5946 var gameChat = channel.appendToChat;
5947 channel.appendToChat = function(header, message) {
5948 // This stuff's in a try block because I want the default functions to go through even if my custom code fails
5949 try {
5950 // Since Info messages don't go through JST
5951 // This is needed
5952 if (header === "msg" && message.indexOf("class=\"User\"") === -1) {
5953 // Link using the autolinker library any links in the message.
5954 message = Autolinker.link(message, {
5955 className: "chatMessageLink"
5956 });
5957 // That should be fine, because I don't think the Autolinker library disturbs existing tags
5958
5959 message = twitchify(message);
5960
5961 // Pass the message through the markdown thingy
5962 message = markdown(message);
5963 }
5964
5965 // Scroll the chat down.
5966 if (bpOverlay.autoScroll) {
5967 var chatLog = document.getElementById("ChatLog");
5968 chatLog.scrollTop = chatLog.scrollHeight;
5969 }
5970 } finally {
5971 // Do the actual default chat message function
5972 gameChat(header, message);
5973 }
5974 };
5975
5976 // Process previous messages
5977 jQ("#ChatLog > li").each(function (i, el) {
5978 $el = jQ(el);
5979 if ($el.hasClass("msg") && $el.html().indexOf('class="User"') === -1) {
5980 var message = $el.html();
5981 message = Autolinker.link(message, {
5982 className: "chatMessageLink"
5983 });
5984 message = twitchify(message);
5985 message = markdown(message);
5986 $el.html(message);
5987 }
5988 else if ($el.hasClass("msgAccueil") && $el.html().indexOf('class="User"') === -1) {
5989 var message = $el.html();
5990 message = Autolinker.link(message, {
5991 className: "chatMessageLink"
5992 });
5993 message = twitchify(message);
5994 message = markdown(message);
5995 $el.html(message);
5996 }
5997 else if ($el.hasClass("Message")) {
5998 $content = $el.find(".Content");
5999 var message = $content.html();
6000 message = Autolinker.link(message, {
6001 className: "chatMessageLink"
6002 });
6003 message = twitchify(message);
6004 message = markdown(message);
6005 $content.html(message);
6006 }
6007 });
6008
6009 // setActivePlayerIndex wrapper
6010 var gameSetActivePlayerIndex = channel.socket.listeners("setActivePlayerIndex").shift();
6011 channel.socket.on("setActivePlayerIndex", function(actor) {
6012 try {
6013 // Since the first event that fires when a game starts is the setActivePlayerIndex event,
6014 // We create the infoBox and any other first-run procedures here
6015 if (bpOverlay.firstRun) {
6016 generateActorConditions();
6017
6018 //reset the alphabet
6019 bpOverlay.alphapos=0;
6020
6021
6022 // Set firstRun to false so a new box is not created every time there's a turn change
6023 bpOverlay.firstRun = false;
6024
6025 if(bpOverlay.adventureTextMode) {
6026 document.getElementById("adventureMessages").innerHTML="";
6027 sendAdventureMessage(adventureTextFormat.chooseText("newRound"), "rgb(10,200,150)");
6028 }
6029
6030 bpOverlay.adventureFirstRun=true;
6031 }
6032
6033 // Hide the context menu if it is the user's turn
6034 if (channel.data.actors[actor].authId === window.app.user.authId) {
6035 jQ('#context-menu-layer').trigger('mousedown');
6036 }
6037
6038 //invisible break
6039 sendAdventureMessage("break", "rgb(20,20,20");
6040
6041
6042 // Chatbox autofocus code && hijacked for textAdventure
6043 // Which creates a strange conundrum of double checking the bpOverlay.autoFocus, but hey. Smaller code.
6044 // Nested checks ahoy because laziness.
6045 if (bpOverlay.autoFocus || bpOverlay.adventureTextMode) {
6046
6047 if(bpOverlay.adventureTextMode) {
6048 //I'm afraid to have these recalculations elsewhere, they aren't that costly anyhow.
6049 //Player info
6050 var playerLives=0;
6051 var playerLetters=["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v"];
6052 var playerIndex = 200;
6053 //What level? How many letters?
6054 for(i=0; i < channel.data.actors.length; i++) {
6055 if(channel.data.actors[i].authId === window.app.user.authId) {
6056 playerLives = channel.data.actors[i].lives;
6057 playerLetters = channel.data.actors[i].lockedLetters;
6058 playerIndex = i;
6059 }
6060 }
6061
6062 if(playerIndex == 200) {
6063 var level = 0;
6064 } else if(bpOverlay.flips[playerIndex] >= bpOverlay.adventureLevels.length) {
6065 var level = bpOverlay.adventureLevels.length - 1;
6066 } else {
6067 var level = bpOverlay.flips[playerIndex];
6068 }
6069
6070 var textAdventurePINFO = document.getElementById("adventurePINFO");
6071 textAdventurePINFO.innerHTML = window.app.user.displayName + " : " + bpOverlay.adventureLevels[level];
6072
6073 var textAdventureEXPINFO = document.getElementById("adventureEXPINFO");
6074 var remaining="";
6075 //Player remaining letters
6076 for(i in playerLetters) {
6077 remaining+=playerLetters[i].toUpperCase();
6078 }
6079
6080 textAdventureEXPINFO.innerHTML = "Experience needed: " + remaining;
6081
6082
6083
6084
6085 //Player health bar
6086 var textAdventureHealth = document.getElementById("adventureHealth");
6087 textAdventureHealth.style.width = (10 + playerLives * 70) + "px";
6088
6089 //Player exp bar
6090 var textAdventureExp = document.getElementById("adventureExp");
6091 textAdventureExp.style.width= (10 + (21 - playerLetters.length) * 10) + "px";
6092
6093 }
6094
6095
6096 //There is a very very very small chance that this will not work for the "first shift" of the "first round"
6097 //It does work as expected after that though. Almost flawless. People will probably not notice.
6098 //Either that or change the code... but who's unlazy enough? I mean
6099 //This works 90% of the time for the first shift and 100% after that.
6100 if (bpOverlay.focusNext && bpOverlay.autoFocus) {
6101 // If focusNext is true (i.e. it's immediately after the player's turn)
6102 // We set the focus to the chatbox, and reset focusNext.
6103 setTimeout(function() {
6104 // We set focus to the chat only if the user is not the current player
6105 if (channel.data.actors[channel.data.activePlayerIndex].authId !== app.user.authId) {
6106 document.getElementById("ChatInputBox").focus();
6107 }
6108 }, 400);
6109 bpOverlay.focusNext = false;
6110
6111 }
6112 //If first-run, then a small delay is needed to get a correct wordRoot.
6113 if(!bpOverlay.adventureFirstRun) {
6114 if (channel.data.actors[actor].authId === window.app.user.authId) {
6115 // If it's the user's turn, set focusNext to true so the next time
6116 // setActivePlayerIndex fires, we set focus to the chatbox
6117 if(bpOverlay.autoFocus) {
6118 bpOverlay.focusNext = true;
6119 }
6120
6121 sendAdventureMessage(
6122 adventureTextFormat.chooseText("userTurn", channel.data.wordRoot),
6123 "rgb(90, 250, 0)"
6124 );
6125
6126
6127 } else {
6128
6129 sendAdventureMessage(
6130 adventureTextFormat.chooseText("playerTurn", channel.data.actors[actor].displayName, channel.data.wordRoot),
6131 "rgb(255, 165, 0)"
6132 );
6133
6134 }
6135 }
6136
6137 }
6138 } finally {
6139 // Call the actual game function
6140 gameSetActivePlayerIndex(actor);
6141 if(bpOverlay.adventureFirstRun) {
6142 bpOverlay.adventureFirstRun = false;
6143 //The channel.data.wordRoot needs to update in the first run
6144 setTimeout(function() {
6145 if (channel.data.actors[actor].authId === window.app.user.authId) {
6146 // If it's the user's turn, set focusNext to true so the next time
6147 // setActivePlayerIndex fires, we set focus to the chatbox
6148 if(bpOverlay.autoFocus) {
6149 bpOverlay.focusNext = true;
6150 }
6151
6152 sendAdventureMessage(
6153 adventureTextFormat.chooseText("userTurn", channel.data.wordRoot),
6154 "rgb(90, 250, 0)"
6155 );
6156
6157
6158 } else {
6159
6160 sendAdventureMessage(
6161 adventureTextFormat.chooseText("playerTurn", channel.data.actors[actor].displayName, channel.data.wordRoot),
6162 "rgb(255, 165, 0)"
6163 );
6164
6165 }
6166 }, 100);
6167 }
6168 //We need to do this shortly after a shift because the channel needs to be updated first, every time.
6169 if(bpOverlay.adventureTextMode) {
6170 setTimeout(function() {
6171 for(i=0; i < channel.data.actors.length; i++) {
6172
6173 var turns = document.getElementById("adventureTurns");
6174 var index = channel.data.activePlayerIndex;
6175 if( index == i ) {
6176 if(typeof channel.data.actors[index].pictureURL === "undefined") {
6177 var imgSource = "http://bombparty.sparklinlabs.com/images/AvatarPlaceholder.png";
6178 } else {
6179 var imgSource = channel.data.actors[index].pictureURL;
6180 }
6181
6182 var EXP = (21 - channel.data.actors[index].lockedLetters.length);
6183 var hearts="";
6184 for(j=0; j < channel.data.actors[index].lives; j++) {
6185 hearts+="♥";
6186 }
6187 turns.innerHTML="<img src=' "+ imgSource + "' height='70px' width='70px' style='float:left; margin-right: 10px'></img><div style='float:right;'><p style='color: #DFA'>" + channel.data.actors[i].displayName + "<p style='color: orange'>Lives: <span style='color: red'>" + hearts + "</span></p><p style='color: #A746C7'>EXP: <span style='color: #7D8ADB'>" + EXP + "/21</div>";
6188 }
6189 }
6190 },
6191 100);
6192
6193 }
6194 }
6195 });
6196
6197 // winWord wrapper
6198 var gameWinWord = channel.socket.listeners("winWord").shift();
6199 channel.socket.on("winWord", function(actor) {
6200 try {
6201 // We have to manually determine if the user flips, because apparently there's no event
6202 // that fires when a player flips.
6203
6204 // t is the player we're considering.
6205 // Why t? I have no idea.
6206 var t = channel.data.actorsByAuthId[actor.playerAuthId];
6207 var playerNum = bpOverlay.playerAuthId[actor.playerAuthId];
6208 var lockedLetters = t.lockedLetters.slice();
6209 var lastWord = t.lastWord.toLowerCase();
6210 var prevExp = lockedLetters.length;
6211 var scoreSum = 0;
6212 // Remove the letters of the last word that a person used
6213 // from the letters they need to flip
6214 for (i = 0; i < lastWord.length; i++) {
6215 var index;
6216 if ((index = lockedLetters.indexOf(lastWord[i])) != -1) {
6217 lockedLetters.splice(index, 1);
6218 }
6219
6220 if(bpOverlay.scoreMode) {
6221 scoreSum += bpOverlay.letterScore[lastWord[i]];
6222 }
6223
6224
6225 }
6226 var experience = prevExp - lockedLetters.length;
6227
6228 if(bpOverlay.scoreMode) {
6229 scoreNotifier(bpOverlay.playerNames[playerNum] + " " + scoreSum);
6230 bpOverlay.playerScores[playerNum] += scoreSum;
6231 updateScores();
6232 }
6233
6234 // Update the words counter
6235 bpOverlay.words[playerNum]++;
6236 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6237 document.getElementById(playerNum + " words").textContent = bpOverlay.words[playerNum];
6238 }
6239
6240 // Update the alpha thing
6241 if (lastWord.toLowerCase()[0] === bpOverlay.alphabet[bpOverlay.alpha[playerNum].progress]) {
6242 bpOverlay.alpha[playerNum].progress++;
6243 if (bpOverlay.alpha[playerNum].progress >= bpOverlay.alphabet.length) {
6244 bpOverlay.alpha[playerNum].progress = 0;
6245 bpOverlay.alpha[playerNum].completed++;
6246 }
6247
6248 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6249 document.getElementById(playerNum + " alpha").textContent = bpOverlay.alphabet[bpOverlay.alpha[playerNum].progress].toUpperCase() + " (" + bpOverlay.alpha[playerNum].completed + ")";
6250 }
6251 }
6252
6253 // If the lockedLetters is empty after removing all those, letters, the player has flipped
6254 var flipped = (lockedLetters.length === 0);
6255
6256 if (flipped) {
6257 // Append one to the flip counter
6258 bpOverlay.flips[playerNum] += 1;
6259
6260 if(bpOverlay.scoreMode) {
6261 bpOverlay.playerScores[playerNum] += 100;
6262 scoreNotifier(bpOverlay.playerNames[playerNum] + " FLIP BONUS");
6263 }
6264
6265 // If the box is created, update it too
6266 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6267 document.getElementById(playerNum + " flips").textContent = bpOverlay.flips[playerNum];
6268 }
6269
6270 if (t.lives === 3) {
6271 // If the flip happened when the player's lives is already at three, it's an u-flip
6272 // Increment and update
6273 bpOverlay.uFlips[playerNum] += 1;
6274 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6275 document.getElementById(playerNum + " uFlips").textContent = bpOverlay.uFlips[playerNum];
6276 }
6277
6278 }
6279
6280 if(bpOverlay.flips[playerNum] >= bpOverlay.adventureLevels.length) {
6281 var level = bpOverlay.adventureLevels.length - 1;
6282 } else {
6283 var level = bpOverlay.flips[playerNum];
6284 }
6285
6286 if(channel.data.actors[playerNum].displayName === window.app.user.displayName) {
6287 sendAdventureMessage(
6288 adventureTextFormat.chooseText("userLevelUp", bpOverlay.adventureLevels[level]),
6289 "rgb(200, 200, 0"
6290 );
6291 } else {
6292 sendAdventureMessage(
6293 adventureTextFormat.chooseText("levelUp", channel.data.actors[playerNum].displayName, bpOverlay.adventureLevels[level]),
6294 "rgb(200, 200, 0)"
6295 );
6296 }
6297
6298 } else {
6299 if(channel.data.actors[playerNum].displayName === window.app.user.displayName) {
6300 sendAdventureMessage(adventureTextFormat.chooseText("userWinWord", t.lastWord.toUpperCase(), experience),
6301 "rgb(250, 0, 250)"
6302 );
6303
6304 } else {
6305 sendAdventureMessage(adventureTextFormat.chooseText("winWord", t.displayName, t.lastWord.toUpperCase(), experience),
6306 "rgb(250, 0, 250)"
6307 );
6308 }
6309 }
6310
6311 // Add one to the word count, and update the box if it's been created
6312 bpOverlay.wordCount += 1;
6313 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6314 document.getElementById("infoWordCounter").textContent = tran.t("wordCountText") + bpOverlay.wordCount;
6315 }
6316
6317 //Let the player get more alphabets
6318 if(channel.data.actors[playerNum].displayName === window.app.user.displayName) {
6319 if(bpOverlay.alphabet.length <= bpOverlay.alphapos) {
6320 bpOverlay.alphapos = 0;
6321 } else {
6322 bpOverlay.alphapos++;
6323 }
6324 }
6325 } finally {
6326 // Call the actual game function
6327 gameWinWord(actor);
6328 }
6329 });
6330
6331 // setPlayerLives wrapper
6332 var gameSetPlayerLives = channel.socket.listeners("setPlayerLives").shift();
6333 channel.socket.on("setPlayerLives", function(actor) {
6334 try {
6335 // Apparently, setPlayerLives is only used for decreasing a player's lives.
6336 // It unfortunately doesn't fire when a player flips.
6337
6338
6339 if(actor.playerAuthId === window.app.user.authId) {
6340 sendAdventureMessage(adventureTextFormat.chooseText("userLostLife"), "rgb(255,20,10)");
6341 } else {
6342 sendAdventureMessage(adventureTextFormat.chooseText("lostLife", channel.data.actorsByAuthId[actor.playerAuthId].displayName),
6343 "rgb(255,20,10)");
6344 }
6345
6346 var t = channel.data.actorsByAuthId[actor.playerAuthId];
6347 var playerNum = bpOverlay.playerAuthId[actor.playerAuthId];
6348
6349 // if the game data's lives is larger than the updated actor's lives, then the player lost a life
6350 if (t.lives > actor.lives) {
6351 // Increment and update
6352 bpOverlay.lostLives[playerNum] += 1;
6353 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6354 document.getElementById(playerNum + " lives").textContent = bpOverlay.lostLives[playerNum];
6355 }
6356 }
6357 } finally {
6358 // Call the actual game function
6359 gameSetPlayerLives(actor);
6360 }
6361 });
6362
6363 // setPlayerState wrapper
6364 var gameSetPlayerState = channel.socket.listeners("setPlayerState").shift();
6365 channel.socket.on("setPlayerState", function(actor) {
6366 // setPlayerState is really only used to make a player dead.
6367 try {
6368 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6369 if (actor.state == "dead") {
6370 // This code basically just greys out the dead player's row on the scoreboard
6371 var playerNum = bpOverlay.playerAuthId[actor.playerAuthId];
6372 var tableRow = document.getElementById(playerNum + " row");
6373 tableRow.style.color = "#666";
6374
6375 // and if hideDead is true, it hides 'em too
6376 if (bpOverlay.hideDead) {
6377 tableRow.style.display = "none";
6378 }
6379 if(actor.playerAuthId === window.app.user.authId) {
6380 sendAdventureMessage(adventureTextFormat.chooseText("userDeath", channel.data.actorsByAuthId[actor.playerAuthId].displayName)
6381 , "rgb(255,255,255");
6382 } else {
6383 sendAdventureMessage(adventureTextFormat.chooseText("death", channel.data.actorsByAuthId[actor.playerAuthId].displayName),
6384 "rgb(255,255,255");
6385 }
6386 }
6387 }
6388 } finally {
6389 // Call the actual game function
6390 gameSetPlayerState(actor);
6391 }
6392 });
6393
6394 // endGame wrapper
6395 var gameEndGame = channel.socket.listeners("endGame").shift();
6396 channel.socket.on("endGame", function(actorName) {
6397 try {
6398 // Set firstRun to true, because we want the box to be redraw next round
6399 bpOverlay.firstRun = true;
6400
6401 if(bpOverlay.adventureTextMode) {
6402 document.getElementById("adventureMessages").innerHTML="";
6403 document.getElementById("adventureTurns").innerHTML="";
6404 sendAdventureMessage(adventureTextFormat.chooseText("endRound", channel.data.wordRoot.toUpperCase()),
6405 "rgb(204, 255, 204)");
6406 }
6407
6408
6409
6410 // Oh, and set the focus to the chatBox if you need to as well
6411 if (bpOverlay.autoFocus) {
6412 if (bpOverlay.focusNext) {
6413 setTimeout(function() {
6414 document.getElementById("ChatInputBox").focus();
6415 }, 400);
6416 bpOverlay.focusNext = false;
6417 }
6418 }
6419
6420 // Play the notification sound if specified
6421 if (bpOverlay.endGameNotification && bpOverlay.is_hidden) {
6422 bpOverlay.notificationSound.play();
6423 }
6424
6425
6426 // Update the time timer as it might be 1 second behind
6427 updateTime();
6428
6429 //Reset the playerScores
6430 bpOverlay.playerScores = Array.apply(null, new Array(20)).map(Number.prototype.valueOf,0);
6431
6432 } finally {
6433 // Call the actual game function
6434 gameEndGame(actorName);
6435 setTimeout(function() {
6436 sendAdventureMessage(adventureTextFormat.chooseText("winner", channel.data.lastWinner),
6437 "rgb(24, 24, 255)");
6438 }, 100);
6439 }
6440 });
6441
6442 // This function makes the tooltip text that lists all the players in the room
6443 // when you hover over the player count.
6444 // Double function: construct the player list in the leaderboards tab
6445 var changePlayerText = function() {
6446 var playerCount = document.getElementsByClassName("ChannelUsers")[0];
6447 var title = tran.t("playersTitle");
6448 for (var i in channel.data.users) {
6449 title += "\n" + channel.data.users[i].displayName;
6450 }
6451 playerCount.title = title;
6452
6453 // Get the playerListDiv
6454 var playerListDiv = document.getElementById("PlayerList");
6455
6456 // Make the innerHTML
6457 var PDIH = "";
6458 for (var i in channel.data.users) {
6459 // e is our lucky letter today
6460 var e = channel.data.users[i];
6461 var t = e.serviceHandles;
6462 var a = [];
6463 var n = i18n;
6464 var r = app;
6465 var l = [];
6466
6467 // At this point, I kinda said eff it
6468 // So we'll just use Elisee's obfuscated code because it works perfectly well
6469 (function () {
6470 var t = e.serviceHandles;
6471 if ("number" == typeof t.length)
6472 for (var a = 0, r = t.length; r > a; a++) {
6473 var s = t[a];
6474 null == s && (s = n.t("nuclearnode:serviceHandlePlaceholder")), "guest" != a && l.push(n.t("nuclearnode:userHandleOnService", {
6475 handle: s,
6476 service: n.t("nuclearnode:loginServices." + a)
6477 }))
6478 } else {
6479 var r = 0;
6480 for (var a in t) {
6481 r++;
6482 var s = t[a];
6483 null == s && (s = n.t("nuclearnode:serviceHandlePlaceholder")), "guest" != a && l.push(n.t("nuclearnode:userHandleOnService", {
6484 handle: s,
6485 service: n.t("nuclearnode:loginServices." + a)
6486 }))
6487 }
6488 }
6489 })
6490 .call(this), a.push("<span" + jade.attr("title", l.join(", "), !0, !1) + jade.attr("data-auth-id", e.authId, !0, !1) + ' class="BpOS-User User">'), "" != e.role && a.push("<span" + jade.attr("title", n.t("nuclearnode:userRoles." + e.role), !0, !1) + jade.cls(["UserRole_" + e.role], [!0]) + "></span> "), a.push(jade.escape(null == (t = e.displayName) ? "" : t)), a.push('<span class="Actions">'), ("moderator" == r.user.role || "host" == r.user.role || "hubAdministrator" == r.user.role) && (a.push('<button' + jade.attr("data-auth-id", e.authId, !0, !1) + jade.attr("data-display-name", e.displayName, !0, !1) + ' class="BanUser">' + jade.escape(null == (t = n.t("nuclearnode:chat.ban")) ? "" : t) + "</button>"), ("host" == r.user.role || "hubAdministrator" == r.user.role) && a.push("<button" + jade.attr("data-auth-id", e.authId, !0, !1) + jade.attr("data-display-name", e.displayName, !0, !1) + ' class="ModUser">' + jade.escape(null == (t = n.t("nuclearnode:chat.mod")) ? "" : t) + "</button>")), a.push("<button" + jade.attr("data-auth-id", e.authId, !0, !1) + jade.attr("data-display-name", e.displayName, !0, !1) + ' class="MuteUser">' + tran.t("muteUser") + "</button>"), a.push("</span>"), a.push("</span>")
6491
6492 PDIH += a.join("");
6493 PDIH += "<br />";
6494 }
6495
6496 playerListDiv.innerHTML = PDIH;
6497 };
6498
6499 // We want it to fire now, when a user is added, and when a users is removed.
6500 channel.socket.on("addUser", changePlayerText);
6501 channel.socket.on("removeUser", changePlayerText);
6502 channel.socket.on("setUserRole", changePlayerText);
6503 changePlayerText();
6504
6505 // Update the muted player text
6506 var updateMuted = function () {
6507 var ignoringDiv = jQ("#IgnoringListDiv")[0];
6508 var innerHTML = "";
6509 var ignoring_any = false;
6510 for (var i in bpOverlay.ignoring) {
6511 innerHTML += "<span title=\"" + i + "\">" + bpOverlay.ignoring[i] + "<span class=\"Actions\"><button class=\"UnmuteUser\" data-auth-id=\"" + i + "\">" + tran.t("unmuteUser") + "</button></span></span><br />"
6512 ignoring_any = true;
6513 }
6514 if (!ignoring_any) {
6515 innerHTML = tran.t("ignoringEmpty");
6516 }
6517 ignoringDiv.innerHTML = innerHTML;
6518 ignoringDiv.dataset.json = JSON.stringify(bpOverlay.ignoring);
6519 }
6520
6521 // Expose this to the globals so the GM script has access to it
6522 setMuted = function (jsonString) {
6523 bpOverlay.ignoring = JSON.parse(jsonString);
6524 for (var i in bpOverlay.ignoring) {
6525 var toMute = jQ(".Author-" + i.replace(/:/g, "_"));
6526 for (var j = 0; j < toMute.length; i++) {
6527 toMute[j].style.opacity = .4;
6528 }
6529 }
6530 updateMuted();
6531 }
6532
6533 // Click wrapper
6534 // Pls put any document.click actions in here
6535 document.addEventListener("click", function (e) {
6536 if ("BUTTON" === e.target.tagName) {
6537 if (e.target.className === "MuteUser") {
6538 bpOverlay.ignoring[e.target.dataset.authId] = e.target.dataset.displayName;
6539 var toMute = jQ(".Author-" + e.target.dataset.authId.replace(/:/g, "_"));
6540 for (var i = 0; i < toMute.length; i++) {
6541 toMute[i].style.opacity = .4;
6542 }
6543 updateMuted();
6544 return;
6545 }
6546 else if (e.target.className === "UnmuteUser") {
6547 delete bpOverlay.ignoring[e.target.dataset.authId];
6548 updateMuted();
6549 return;
6550 }
6551 }
6552 });
6553 };
6554
6555 // Code that needs to be run when the bot activates.
6556 var firstRunProcs = function() {
6557 // The entire styleshee for the bot is wrapper up in this long string.
6558 // Probably a better way of doing this
6559 // Lol. TFW web-console css is hard
6560 var style = document.createElement('style');
6561 style.appendChild(document.createTextNode('.headerButtonDiv { display: -webkit-box; display: -moz-box; display: -webkit-flex; display: -ms-flexbox; display: box; display: flex; opacity: 0.3; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; filter: alpha(opacity=30);} .headerButtonDiv:hover { opacity: 1; -ms-filter: none; filter: none;} button.headerButton { border: none; background: none; cursor: pointer; opacity: 0.5; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50); display: -webkit-box; display: -moz-box; display: -webkit-flex; display: -ms-flexbox; display: box; display: flex;} button.headerButton:hover { opacity: 0.8; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; filter: alpha(opacity=80);} button.headerButton:active { opacity: 1; -ms-filter: none; filter: none;} .infoTableDiv::-webkit-scrollbar { width: 15px; height: 15px; } .infoTableDiv::-webkit-scrollbar-button { height: 0px; width: 0px; } .infoTableDiv::-webkit-scrollbar-track { background-color: rgba(0,0,0,0.05); } .infoTableDiv::-webkit-scrollbar-thumb { background-color: rgba(255,255,255,0.1); border: 3px solid transparent; -webkit-border-radius: 6px; border-radius: 6px; -webkit-background-clip: content; -moz-background-clip: content; background-clip: content-box; } .infoTableDiv::-webkit-scrollbar-thumb:hover { background-color: rgba(255,255,255,0.15); } .infoTableDiv::-webkit-scrollbar-corner { background-color: rgba(255,255,255,0.1); }#overlaySettingsTab{text-align:left;overflow-y:auto}#overlaySettingsTab h2{padding:.5em .5em 0;opacity:.5;-ms-filter:"alpha(Opacity=50)";filter:alpha(opacity=50)}#overlaySettingsTab h3{padding:.5em .5em 0;opacity:.5;-ms-filter:"alpha(Opacity=50)";filter:alpha(opacity=50)}#overlaySettingsTab table{width:100%;padding:.5em}#overlaySettingsTab table tr td:nth-child(1){width:40%}#overlaySettingsTab table tr td:nth-child(2){width:60%}#overlaySettingsTab table button:not(.UnbanUser),#overlaySettingsTab table input,#overlaySettingsTab table select,#overlaySettingsTab table textarea{width:100%;background:#444;border:none;padding:.25em;color:#fff;font:inherit}#overlaySettingsTab table textarea{resize:vertical;min-height:3em}#overlaySettingsTab table ul{list-style:none}#overlaySettingsTab .BpOS-User .UserRole_hubAdministrator:before{content:\'[★]\';cursor:default;color:#000000}#overlaySettingsTab .BpOS-User .UserRole_host:before{content:\'★\';cursor:default;color:#000000}#overlaySettingsTab .BpOS-User .UserRole_administrator:before{content:\'★\';cursor:default;color:#000000}#overlaySettingsTab .BpOS-User .UserRole_moderator:before{content:\'â—\';cursor:default;color:#FEFEFE}#overlaySettingsTab .Actions button{border:none;background:0 0;cursor:pointer;margin:0 .25em;outline:0;font-weight:400;font-size:smaller;opacity:.8;-ms-filter:"alpha(Opacity=80)";filter:alpha(opacity=80)}#overlaySettingsTab .Actions button.BanUser{color:#a00}#overlaySettingsTab .Actions button.ModUser,#overlaySettingsTab .Actions button.UnmodUser{color:#2a3} .Actions button.MuteUser{color:#ddd} .Actions button.UnmuteUser{color:#eee} #overlaySettingsTab .Actions button:hover{opacity:1;-ms-filter:none;filter:none}#overlaySettingsTab .Actions button:active{background:rgba(255,0,0,.2)}#overlaySettingsTab input{-moz-user-select:text;-webkit-user-select:text;-ms-user-select:text}#ChatLog .highlighted{background: rgba(255, 0, 0, 0.05);}#ChatLog .highlighted:hover {background: rgba(255, 0, 0, 0.1);} input[type=text], textarea { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; } .emoticon { display: inline-block; margin: -5px 0; padding-top: 5px; vertical-align: baseline !important; }'));
6562 document.getElementsByTagName('head')[0].appendChild(style);
6563
6564 // Load the hideDead on/off images
6565 var hideDeadOn = document.createElement("img");
6566 hideDeadOn.width = 15;
6567 hideDeadOn.height = 15;
6568 hideDeadOn.src = bpImgUrls.hideDeadOn;
6569 bpOverlayImgs.hideDeadOn = hideDeadOn;
6570
6571 var hideDeadOff = document.createElement("img");
6572 hideDeadOff.width = 15;
6573 hideDeadOff.height = 15;
6574 hideDeadOff.src = bpImgUrls.hideDeadOff;
6575 bpOverlayImgs.hideDeadOff = hideDeadOff;
6576
6577 //AutoScrollButton made with makeHeaderButton Function
6578 //See usage in the declaration-meow for makeHeaderButton
6579 makeHeaderButton(bpOverlayImgs.on,
6580 bpOverlayImgs.off,
6581 "chatDownButton",
6582 tran.t("chatDownButtonTitle"),
6583 true, //Because we want the onImg displayed at creation
6584 //Then the function within this function
6585 function() {
6586 // Flip the autoScroll property
6587 bpOverlay.autoScroll = !bpOverlay.autoScroll;
6588
6589 if (bpOverlay.autoScroll) {
6590 // if autoScroll is true, remove the off image and add the on image...
6591 document.getElementById("chatDownButton").removeChild(bpOverlayImgs.off);
6592 document.getElementById("chatDownButton").appendChild(bpOverlayImgs.on);
6593 document.getElementById("chatDownButton").dataset.state = true;
6594 } else {
6595 // ...and vice versa if autoScroll is false
6596 document.getElementById("chatDownButton").removeChild(bpOverlayImgs.on);
6597 document.getElementById("chatDownButton").appendChild(bpOverlayImgs.off);
6598 document.getElementById("chatDownButton").dataset.state = false;
6599 }
6600 }
6601 );
6602
6603 //autoFocus button made
6604 makeHeaderButton(bpOverlayImgs.autoFocusOn,
6605 bpOverlayImgs.autoFocusOff,
6606 "autoFocusButton",
6607 tran.t("autoFocusButtonTitle"),
6608 true,
6609 function() {
6610 // Flip the autoFocus property
6611 bpOverlay.autoFocus = !bpOverlay.autoFocus;
6612
6613 if (bpOverlay.autoFocus) {
6614 // You must know the drill by now
6615 document.getElementById("autoFocusButton").removeChild(bpOverlayImgs.autoFocusOff);
6616 document.getElementById("autoFocusButton").appendChild(bpOverlayImgs.autoFocusOn);
6617 document.getElementById("autoFocusButton").dataset.state = true;
6618 } else {
6619 // I'm not even going to bother
6620 document.getElementById("autoFocusButton").removeChild(bpOverlayImgs.autoFocusOn);
6621 document.getElementById("autoFocusButton").appendChild(bpOverlayImgs.autoFocusOff);
6622 document.getElementById("autoFocusButton").dataset.state = false;
6623 }
6624 }
6625 );
6626
6627 //dragOn button made
6628 makeHeaderButton(bpOverlayImgs.dragOn,
6629 bpOverlayImgs.dragOff,
6630 "dragButton",
6631 tran.t("dragButtonTitle"),
6632 false,
6633 function() {
6634 //We don't want the button to react if the neither of the boxes have been created
6635
6636 // Well, because generateActorConditions checks bpOverlay.dragOn, I don't think it matters anymore
6637 // So I'm just going to override it :P (no offense)
6638 // This is in preparation for saving settings across bombparty sessions
6639 // Because if the user was to prefer the drag box, that should be the default
6640 // Which means it bpOverlay.dragOn needs to be true from the get-go
6641 if (bpOverlay.boxHasBeenCreated || bpOverlay.dragBoxHasBeenCreated) {
6642 bpOverlay.dragonDrop = !bpOverlay.dragonDrop; //Flippety flop the boolean be bop
6643
6644 var button = document.getElementById("dragButton");
6645 var sideBar = document.getElementById("Sidebar");
6646 var infoBox = document.getElementById("infoBox");
6647 var dragOnDrop = document.getElementById("dragonDrop");
6648
6649 //In short, this is a switch between docked and dragon mode. Ugly and intuitive
6650 if (bpOverlay.dragonDrop) {
6651
6652 sideBar.removeChild(infoBox);
6653 dragOnDrop.appendChild(infoBox);
6654
6655 button.removeChild(bpOverlayImgs.dragOff);
6656 button.appendChild(bpOverlayImgs.dragOn);
6657 bpOverlay.dragBoxHasBeenCreated = true;
6658 bpOverlay.boxHasBeenCreated = false;
6659 button.dataset.state = true;
6660 } else {
6661
6662 dragOnDrop.removeChild(infoBox);
6663 sideBar.insertBefore(infoBox, sideBar.firstChild);
6664 bpOverlay.dragBoxHasBeenCreated = false;
6665 bpOverlay.boxHasBeenCreated = true;
6666
6667 button.removeChild(bpOverlayImgs.dragOn);
6668 button.appendChild(bpOverlayImgs.dragOff);
6669 button.dataset.state = false;
6670 }
6671 } else {
6672 // The subverting begins
6673 bpOverlay.dragonDrop = !bpOverlay.dragonDrop; //Flippety flop the boolean be bop
6674
6675 var button = document.getElementById("dragButton");
6676
6677 if (bpOverlay.dragonDrop) {
6678
6679 button.removeChild(bpOverlayImgs.dragOff);
6680 button.appendChild(bpOverlayImgs.dragOn);
6681 button.dataset.state = true;
6682
6683 } else {
6684
6685 button.removeChild(bpOverlayImgs.dragOn);
6686 button.appendChild(bpOverlayImgs.dragOff);
6687 button.dataset.state = false;
6688
6689 }
6690
6691 //alert("Didn't find the infoBox.\n\nIf you're running this for the first time and the round hasn't started or if it's the same player's turn from when you started the overlay then this is normal.\n\nYou impatient flap :D");
6692 }
6693 }
6694 );
6695
6696
6697 //Add the fourth button on the settingsTab that hopefully doesn't interfere with the others.
6698 var sideButtons = document.getElementById("SidebarTabButtons");
6699 var sideTabs = document.getElementById("SidebarTabs");
6700
6701 //Make a clone of the settingstab and change it to what we want
6702 var overlaySettingsTab = sideTabs.children[1].cloneNode(true); //clone settings tab
6703 overlaySettingsTab.id="overlaySettingsTab";
6704 overlaySettingsTab.setAttribute("class", "");
6705 overlaySettingsTab.innerHTML=""; //Empty the innerHTML
6706
6707 //Make a clone of a tab button and change it to what we want
6708 var overlaySettingsButton = sideButtons.children[0].cloneNode(true); //clone whatever
6709 overlaySettingsButton.id="overlaySettingsButton";
6710 overlaySettingsButton.setAttribute("class", ""); //We don't want it to start active
6711 overlaySettingsButton.innerHTML="BpOS";
6712 overlaySettingsButton.title=tran.t("overlaySettingsButtonTitle");
6713
6714 //Appendum les shittendum
6715 sideButtons.appendChild(overlaySettingsButton);
6716 sideTabs.appendChild(overlaySettingsTab);
6717
6718 //Define and activate the onclick function for our fourth button
6719 function overlaySettingsFunction() {
6720 for(i=0; i<=2; i++) {
6721 document.getElementById("SidebarTabButtons").children[i].classList.remove("Active"); //Prevent two active classes
6722 }
6723 for(i=0; i<=2; i++) {
6724 document.getElementById("SidebarTabs").children[i].classList.remove("Active"); //Prevent two active classes
6725 }
6726
6727 document.getElementById("overlaySettingsButton").setAttribute("class", "Active");
6728 document.getElementById("overlaySettingsTab").setAttribute("class", "Active");
6729
6730 }
6731 overlaySettingsButton.onclick=overlaySettingsFunction;
6732
6733
6734 //We only want this once (I believe) so this is outside of a function
6735 //Generate the overlay section and append it to the SettingsTab
6736 var bpOverlayH2 = document.createElement("H2");
6737
6738 //We add an id for the jq to recognize the object
6739 bpOverlayH2.id="bpOverlayH2";
6740 bpOverlayH2.onclick=function() {
6741 jQ('#overlaySettingsTableWrapper').slideToggle('slow');
6742 };
6743
6744
6745 //Since we can't require any styles nor anything (cross browser), we're just going to quickly write
6746 //a mouseover and mouseout hacks so that this is nice and responsive
6747 bpOverlayH2.onmouseover=function() {
6748 jQ('#bpOverlayH2').css("text-shadow", "0 0 24px white");
6749 };
6750
6751 bpOverlayH2.onmouseout=function() {
6752 jQ('#bpOverlayH2').css("text-shadow", "0 0 0px black");
6753 };
6754
6755 bpOverlayH2.textContent = tran.t("overlaySettingsText");
6756 var settingsTab = document.getElementById("overlaySettingsTab");
6757 settingsTab.appendChild(bpOverlayH2);
6758
6759 // Moved over the settings tab things to here
6760 // We wrap everything in a div because jquery doesn't handle table smoothly
6761 var sTabTableWrapper = document.createElement("DIV");
6762 // Wrapper starts hidden
6763 sTabTableWrapper.style.display="none";
6764 sTabTableWrapper.id="overlaySettingsTableWrapper";
6765 var sTabTable = document.createElement("TABLE");
6766 sTabTable.id = "overlaySettingsTable";
6767 sTabTableWrapper.appendChild(sTabTable);
6768 settingsTab.appendChild(sTabTableWrapper);
6769
6770 //Notifications h2
6771 var notificationsH2 = document.createElement("H2");
6772 notificationsH2.id = "notificationsH2";
6773 notificationsH2.textContent = tran.t("notificationsText");
6774 notificationsH2.onmouseover=function() {
6775 jQ('#notificationsH2').css("text-shadow", "0 0 24px white");
6776 };
6777
6778 notificationsH2.onmouseout=function() {
6779 jQ('#notificationsH2').css("text-shadow", "0 0 0px black");
6780 };
6781
6782 notificationsH2.onclick=function() {
6783 jQ('#notificationsWrapper').slideToggle('slow');
6784 };
6785
6786 settingsTab.appendChild(notificationsH2);
6787
6788
6789
6790 // Moved over the settings tab things to here
6791 // We wrap everything in a div because jquery doesn't handle table smoothly
6792 var notTabTableWrapper = document.createElement("DIV");
6793 // Wrapper starts hidden
6794 notTabTableWrapper.style.display="none";
6795 notTabTableWrapper.id="notificationsWrapper";
6796 var notTabTable = document.createElement("TABLE");
6797 notTabTable.id = "notificationsTable";
6798 notTabTableWrapper.appendChild(notTabTable);
6799 settingsTab.appendChild(notTabTableWrapper);
6800
6801 //Chat options h2
6802 var chatH2 = document.createElement("H2");
6803 chatH2.id = "chatH2";
6804 chatH2.textContent = tran.t("chatOpText");
6805 chatH2.onmouseover=function() {
6806 jQ('#chatH2').css("text-shadow", "0 0 24px white");
6807 };
6808
6809 chatH2.onmouseout=function() {
6810 jQ('#chatH2').css("text-shadow", "0 0 0px black");
6811 };
6812
6813 chatH2.onclick=function() {
6814 jQ('#chatWrapper').slideToggle('slow');
6815 };
6816
6817 settingsTab.appendChild(chatH2);
6818
6819 // Wrapper starts hidden
6820 var chatTabTableWrapper = document.createElement("DIV");
6821 chatTabTableWrapper.style.display="none";
6822 chatTabTableWrapper.id="chatWrapper";
6823 var chatTabTable = document.createElement("TABLE");
6824 chatTabTable.id = "chatOpTable";
6825 chatTabTableWrapper.appendChild(chatTabTable);
6826 settingsTab.appendChild(chatTabTableWrapper);
6827
6828 //Themes h2
6829 var themeH2 = document.createElement("H2");
6830 themeH2.id = "themeH2";
6831 themeH2.textContent = tran.t("themeH2Text");
6832 themeH2.onmouseover=function() {
6833 jQ('#themeH2').css("text-shadow", "0 0 24px white");
6834 };
6835
6836 themeH2.onmouseout=function() {
6837 jQ('#themeH2').css("text-shadow", "0 0 0px black");
6838 };
6839
6840 themeH2.onclick=function() {
6841 jQ('#themeWrapper').slideToggle('slow');
6842 };
6843
6844 settingsTab.appendChild(themeH2);
6845
6846 // Wrapper starts hidden
6847 var themeTabTableWrapper = document.createElement("DIV");
6848 themeTabTableWrapper.style.display="none";
6849 themeTabTableWrapper.id="themeWrapper";
6850 var themeTabTable = document.createElement("TABLE");
6851 themeTabTable.id = "themeOpTable";
6852 themeTabTableWrapper.appendChild(themeTabTable);
6853 settingsTab.appendChild(themeTabTableWrapper);
6854
6855 //Easter h2
6856 var easterH2 = document.createElement("H2");
6857 easterH2.id = "easterH2";
6858 easterH2.textContent = tran.t("easterText");
6859 easterH2.onmouseover=function() {
6860 jQ('#easterH2').css("text-shadow", "0 0 24px white");
6861 };
6862
6863 easterH2.onmouseout=function() {
6864 jQ('#easterH2').css("text-shadow", "0 0 0px black");
6865 };
6866
6867 easterH2.onclick=function() {
6868 jQ('#easterWrapper').slideToggle('slow');
6869 };
6870
6871 settingsTab.appendChild(easterH2);
6872
6873 // Wrapper starts hidden
6874 var easterTabTableWrapper = document.createElement("DIV");
6875 easterTabTableWrapper.style.display="none";
6876 easterTabTableWrapper.id="easterWrapper";
6877 var easterTabTable = document.createElement("TABLE");
6878 easterTabTable.id = "easterTable";
6879 easterTabTableWrapper.appendChild(easterTabTable);
6880 settingsTab.appendChild(easterTabTableWrapper);
6881
6882
6883
6884
6885 // Might as well have the current players in here
6886 var playerListH2 = document.createElement("H2");
6887 playerListH2.id ="PlayerListH2";
6888 playerListH2.textContent = tran.t("playerListText");
6889 playerListH2.onclick = function() {
6890 jQ('#PlayerListWrapper').slideToggle('slow');
6891 };
6892
6893
6894 playerListH2.onmouseover=function() {
6895 jQ('#PlayerListH2').css("text-shadow", "0 0 24px white");
6896 };
6897
6898 playerListH2.onmouseout=function() {
6899 jQ('#PlayerListH2').css("text-shadow", "0 0 0px black");
6900 };
6901
6902 settingsTab.appendChild(playerListH2);
6903 var playerListWrapper = document.createElement("DIV");
6904 playerListWrapper.id = "PlayerListWrapper";
6905 playerListWrapper.style.display = "none";
6906 playerListWrapper.style.marginLeft = "8px";
6907 settingsTab.appendChild(playerListWrapper)
6908
6909 var playerListDiv = document.createElement("DIV");
6910 playerListDiv.id = "PlayerList";
6911 playerListWrapper.appendChild(playerListDiv);
6912
6913 var ignoringListH3 = document.createElement("H3");
6914 ignoringListH3.id = "IgnoringListH3";
6915 ignoringListH3.textContent = tran.t("ignoringText");
6916 ignoringListH3.onclick = function () {
6917 jQ('#IgnoringListDiv').slideToggle('slow');
6918 };
6919 ignoringListH3.onmouseover=function() {
6920 jQ('#IgnoringListH3').css("text-shadow", "0 0 24px white");
6921 };
6922
6923 ignoringListH3.onmouseout=function() {
6924 jQ('#IgnoringListH3').css("text-shadow", "0 0 0px black");
6925 };
6926 playerListWrapper.appendChild(ignoringListH3);
6927
6928 var ignoringListDiv = document.createElement("DIV");
6929 ignoringListDiv.id = "IgnoringListDiv";
6930 ignoringListDiv.style.display = "none";
6931 ignoringListDiv.marginLeft = "8px";
6932 playerListWrapper.appendChild(ignoringListDiv);
6933 ignoringListDiv.textContent = tran.t("ignoringEmpty");
6934
6935 // A little attribution table
6936 var creditsH2 = document.createElement("H2");
6937 creditsH2.id="creditsH2";
6938 creditsH2.onclick = function() {
6939 jQ('#creditsTableWrapper').slideToggle('slow');
6940 jQ('#creditsTextDiv').slideToggle('slow');
6941 };
6942
6943 creditsH2.onmouseover=function() {
6944 jQ('#creditsH2').css("text-shadow", "0 0 24px white");
6945 };
6946
6947 creditsH2.onmouseout=function() {
6948 jQ('#creditsH2').css("text-shadow", "0 0 0px black");
6949 };
6950 creditsH2.textContent = tran.t("creditsText");
6951 settingsTab.appendChild(creditsH2);
6952
6953 var creditsTable = document.createElement("TABLE");
6954 var creditsTableWrapper = document.createElement("DIV");
6955 creditsTableWrapper.style.display="none";
6956 creditsTableWrapper.id = "creditsTableWrapper";
6957 creditsTable.id = "creditsTable";
6958 creditsTable.innerHTML = "\
6959 <tr><td>" + tran.t("credits1") + "</td><td>MrInanimated</td></tr>\
6960 <tr><td>" + tran.t("credits2") + "</td><td>Skandalabrandur</td></tr>\
6961 <tr><td>" + tran.t("credits3") + "</td><td>Macadelic</td></tr>\
6962 <tr><td>" + tran.t("creditsAutolinker") + "</td><td><a href=\"https://github.com/gregjacobs/Autolinker.js\">Autolinker.js</a></td></tr>\
6963 <tr><td>" + tran.t("creditsTwitchEmotes") + "</td><td><a href=\"http://twitchemotes.com/\">twitchemotes.com</a></td></tr>\
6964 <tr><td>" + tran.t("creditsContextMenu") + "</td><td><a href=\"http://medialize.github.io/jQuery-contextMenu/\">Medialize</a></td></tr>\
6965 <tr><td>" + tran.t("smileyContext") + "</td><td><a href=\"https://dl.dropboxusercontent.com/s/l9wk9tad765b9xs/SmileyOverlay.html/\">Smiley</a></td></tr>";
6966 creditsTableWrapper.appendChild(creditsTable);
6967 settingsTab.appendChild(creditsTableWrapper);
6968
6969 var creditsText = document.createElement("DIV");
6970 creditsText.textContent = tran.t("creditsTextText");
6971 creditsText.style.marginLeft = "8px";
6972 creditsText.id="creditsTextDiv";
6973 creditsText.style.display="none";
6974 settingsTab.appendChild(creditsText);
6975
6976
6977 generateSettingsElement(tran.t("containerSizeName"),
6978 {
6979 compact: tran.t("containerSizeOptions.compact"),
6980 fitToPlayers: tran.t("containerSizeOptions.fitToPlayers")
6981 },
6982 "containerSelect", "overlaySettingsTable",
6983 function () {
6984 //Get the infoTableDiv element and the selector created with the id 'containerSelect'
6985 var infoTableDiv = document.getElementsByClassName("infoTableDiv")[0];
6986 var sTabSelect = document.getElementById("containerSelect");
6987
6988 // Enclosed this in an if in case those were not created
6989 if (infoTableDiv && sTabSelect) {
6990
6991 //Change container.style.maxHeight depending on user choice
6992 if(sTabSelect.value === "compact") {
6993 infoTableDiv.style.maxHeight = "100px";
6994 } else if (sTabSelect.value === "fitToPlayers") {
6995 infoTableDiv.style.maxHeight = "1000px"; //The autoflow whatever takes care of this.
6996
6997 //Prevent flowing out of page
6998 //Let's be lazy and get the window.onresize and run it.
6999 var funky = window.onresize;
7000 funky();
7001 } else {
7002 //Do nothing
7003 }
7004 }
7005
7006 }
7007 );
7008
7009 // Twitch Emote settings
7010 generateSettingsElement(
7011 tran.t("twitchEmotesName"),
7012 {
7013 on: tran.t("twitchEmotesOptions.on"),
7014 off: tran.t("twitchEmotesOptions.off")
7015 },
7016 "twitchEmoteSelect", "chatOpTable",
7017 function () {
7018 var teSelect = document.getElementById("twitchEmoteSelect");
7019
7020 if (teSelect.value === "on") {
7021 bpOverlay.twitchOn = true;
7022 }
7023 else if (teSelect.value === "off") {
7024 bpOverlay.twitchOn = false;
7025 }
7026 else {
7027 }
7028 }
7029 );
7030
7031
7032 //The text adventure setting
7033 generateSettingsElement(
7034 tran.t("textAdventureName"),
7035 {
7036 off: tran.t("textAdventureOptions.off"),
7037 on: tran.t("textAdventureOptions.on")
7038 },
7039 "adventureSetting", "easterTable",
7040 function() {
7041 var sTabSelect = document.getElementById("adventureSetting");
7042 if(sTabSelect.value === "on") {
7043 toggleTextAdventure(true);
7044 } else if(sTabSelect.value === "off") {
7045 toggleTextAdventure(false);
7046 } else {
7047 toggleTextAdventure(false);
7048 }
7049 }
7050 );
7051
7052 //Score setting
7053 generateSettingsElement(
7054 tran.t("scoreName"),
7055 {
7056 off: tran.t("scoreOption.off"),
7057 on: tran.t("scoreOption.on"),
7058 },
7059 "scoreSetting", "easterTable",
7060 function() {
7061 var sTabSelect = document.getElementById("scoreSetting");
7062 if(sTabSelect.value === "on") {
7063 bpOverlay.scoreMode=true;
7064 } else {
7065 bpOverlay.scoreMode=false;
7066 var meowswitch = document.getElementById("LeaderboardTab");
7067 meowswitch.innerHTML=" ";
7068 }
7069 }
7070 );
7071 //Hard modes
7072 generateSettingsElement(
7073 tran.t("hardModesName"),
7074 {
7075 none: tran.t("hardModesOptions.none"),
7076 rev: tran.t("hardModesOptions.rev"),
7077 jqv: tran.t("hardModesOptions.jqv"),
7078 az: tran.t("hardModesOptions.az"),
7079 xz: tran.t("hardModesOptions.xz"),
7080 kwxyz: tran.t("hardModesOptions.kwxyz"),
7081 },
7082 "hardModes", "easterTable",
7083 function() {
7084 var sTabSelect = document.getElementById("hardModes");
7085 if(sTabSelect.value === "rev") {
7086 var wordInputBox = document.getElementById("WordInputBox");
7087
7088 var checkLetter = function() {
7089 document.getElementById("WordInputBox").value = document.getElementById("WordInputBox").value.split("").reverse().join("");
7090 }
7091 wordInputBox.onchange=checkLetter;
7092 } else if (sTabSelect.value === "jqv") {
7093 var wordInputBox = document.getElementById("WordInputBox");
7094
7095 var checkLetter = function() {
7096 var inValue = document.getElementById("WordInputBox").value.toLowerCase();
7097 if(!((inValue.indexOf("q") > -1) || (inValue.indexOf("v") > -1) || (inValue.indexOf("j") > -1))) {
7098 document.getElementById("WordInputBox").value = tran.t("jqvText");
7099 }
7100
7101 }
7102 wordInputBox.onchange=checkLetter;
7103 } else if (sTabSelect.value === "az") {
7104 bpOverlay.alphapos=0;
7105 var wordInputBox = document.getElementById("WordInputBox");
7106
7107 var checkLetter = function() {
7108 var inValue = document.getElementById("WordInputBox").value.toLowerCase();
7109 if(!(inValue[0] === bpOverlay.alphabet[bpOverlay.alphapos])) {
7110 document.getElementById("WordInputBox").value=tran.t("azText").replace("{l}", bpOverlay.alphabet[bpOverlay.alphapos]);
7111 }
7112 }
7113 wordInputBox.onchange=checkLetter;
7114 } else if (sTabSelect.value === "xz") {
7115 var wordInputBox = document.getElementById("WordInputBox");
7116
7117 var checkLetter = function() {
7118 var inValue = document.getElementById("WordInputBox").value.toLowerCase();
7119 if(!((inValue.indexOf("x") > -1) || (inValue.indexOf("z") > -1))) {
7120 document.getElementById("WordInputBox").value = tran.t("xzText");
7121 }
7122
7123 }
7124 wordInputBox.onchange=checkLetter;
7125
7126 } else if (sTabSelect.value === "kwxyz") {
7127 var wordInputBox = document.getElementById("WordInputBox");
7128
7129 var checkLetter = function() {
7130 var inValue = document.getElementById("WordInputBox").value.toLowerCase();
7131 if(!((inValue.indexOf("z") > -1) || (inValue.indexOf("y") > -1) || (inValue.indexOf("x") > -1) || (inValue.indexOf("w") > -1) ||(inValue.indexOf("k") > -1))) {
7132 document.getElementById("WordInputBox").value = tran.t("kwxyzText");
7133 }
7134
7135 }
7136 wordInputBox.onchange=checkLetter;
7137 } else {
7138 document.getElementById("WordInputBox").onchange="";
7139 }
7140 }
7141 );
7142
7143 //Theme element
7144 generateSettingsElement(
7145 tran.t("themeName"),
7146 {
7147 none: tran.t("themeOptions.none"),
7148 "https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/themes/xmas/xmas.json": tran.t("themeOptions.xmas"),
7149 "https://dl.dropboxusercontent.com/s/m245vjl3bukxhrz/black.js":
7150 tran.t("themeOptions.blacktree"),
7151 "https://dl.dropboxusercontent.com/s/c7vu9fn6l3oqzkk/violet.js":
7152 tran.t("themeOptions.purpletree"),
7153 "https://dl.dropboxusercontent.com/s/9q1v3ot6fr25ais/Juan.js":
7154 tran.t("themeOptions.juan"),
7155 "https://raw.githubusercontent.com/MrInanimated/bp-overlay/master/themes/pingu/pingu.json":
7156 tran.t("themeOptions.pingu"),
7157 "http://puu.sh/hL4D1/5bd8ee40e9.json":
7158 tran.t("themeOptions.sunset"),
7159 "http://puu.sh/ki6IT/e9b0178a6f.json":
7160 tran.t("themeOptions.radio"),
7161 "https://puu.sh/nYCFk/a013338974.json":
7162 tran.t("themeOptions.simple"),
7163 "https://dl.dropboxusercontent.com/s/lpff8a77murj6as/jap.js":
7164 tran.t("themeOptions.loutes"),
7165 "https://dl.dropboxusercontent.com/s/qvsjcl150pvkuat/leonarda.js":
7166 tran.t("themeOptions.leonarda"),
7167 "https://dl.dropboxusercontent.com/s/4m51c9xgsg9iwr5/Lisa1.js":
7168 tran.t("themeOptions.lisa"),
7169 "https://raw.githubusercontent.com/EdwardWongHauPepeluTivruskyIV/Bombparty-Doritos-Theme/master/theme.json":
7170 tran.t("themeOptions.caro"),
7171 custom: tran.t("themeOptions.custom"),
7172 },
7173 "themeSelect", "themeOpTable",
7174 function () {
7175 var themeSelect = document.getElementById("themeSelect");
7176 if (themeSelect.value === "none") {
7177 loadCustomTheme(false);
7178 document.getElementById("customThemeRow").style.display = "none";
7179 }
7180 else if (themeSelect.value === "custom") {
7181 document.getElementById("customThemeRow").style.display = "";
7182 }
7183 else {
7184 document.getElementById("customThemeRow").style.display = "none";
7185 }
7186
7187 // Handling the URLs have to be done outside this code
7188 // Because it needs access to GM_xmlhttpRequest
7189
7190 });
7191
7192 // Manual settings creation because it's an input and not a select
7193 // It's wrapped in a anonymous function because
7194 // I can't be bothered to make sure the variable names don't conflict
7195 (function () {
7196 var sTabTable = document.getElementById("themeOpTable");
7197 var sTabTr = document.createElement("TR");
7198 sTabTr.id = "customThemeRow";
7199 sTabTr.style.display = "none";
7200 sTabTable.appendChild(sTabTr);
7201 var sTabTd = document.createElement("TD");
7202 sTabTd.innerHTML = tran.t("customThemeName");
7203 sTabTr.appendChild(sTabTd);
7204 var sTabOptionsTd = document.createElement("TD");
7205 sTabTr.appendChild(sTabOptionsTd);
7206 var sTabInput = document.createElement("INPUT");
7207 sTabInput.id = "customThemeInput";
7208 sTabOptionsTd.appendChild(sTabInput);
7209 })();
7210
7211 //Particle settings
7212 generateSettingsElement(
7213 tran.t("particlesName"),
7214 {
7215 high: tran.t("particlesOptions.high"),
7216 low: tran.t("particlesOptions.low"),
7217 off: tran.t("particlesOptions.off")
7218 },
7219 "particleSelect", "themeOpTable",
7220 function () {
7221 var sTabSelect = document.getElementById("particleSelect");
7222 if(sTabSelect.value === "high") {
7223 bpOverlay.particleSpawnRate = "high";
7224 } else if(sTabSelect.value === "low") {
7225 bpOverlay.particleSpawnRate = "low";
7226 } else {
7227 bpOverlay.particleSpawnRate = "none";
7228 }
7229 }
7230 );
7231
7232 //Notifies
7233 generateSettingsElement(
7234 tran.t("notificationsName"),
7235 {
7236 on: tran.t("notificationOptions.on"),
7237 off: tran.t("notificationOptions.off"),
7238 },
7239 "notificationsSelect", "notificationsTable",
7240 function () {
7241 var sTabSelect = document.getElementById("notificationsSelect");
7242 if (sTabSelect.value == "on") {
7243 bpOverlay.notifications = true;
7244 }
7245 else {
7246 bpOverlay.notifications = false;
7247 }
7248 }
7249 );
7250
7251 // This one's a slider!
7252 (function () {
7253 var sTabTable = document.getElementById("notificationsTable");
7254 var sTabTr = document.createElement("TR");
7255 sTabTable.appendChild(sTabTr);
7256 var sTabTd = document.createElement("TD");
7257 sTabTd.innerHTML = tran.t("notificationVolume");
7258 sTabTr.appendChild(sTabTd);
7259 var sTabOptionsTd = document.createElement("TD");
7260 sTabTr.appendChild(sTabOptionsTd);
7261 var sTabInput = document.createElement("INPUT");
7262 sTabInput.id = "notificationVolumeSlider";
7263 sTabInput.type = "range";
7264 sTabInput.min = 0;
7265 sTabInput.max = 100;
7266 sTabInput.value = 100;
7267 sTabInput.addEventListener("change", function (e) {
7268 bpOverlay.notificationSound.volume = sTabInput.value / 100;
7269 bpOverlay.notificationSound.play();
7270 });
7271 sTabInput.title = tran.t("notificationAliasInputTitle");
7272 sTabOptionsTd.appendChild(sTabInput);
7273 })();
7274
7275 // And another, because this one's an input
7276 (function () {
7277 var sTabTable = document.getElementById("notificationsTable");
7278 var sTabTr = document.createElement("TR");
7279 sTabTr.id = "notificationSettingsRow";
7280 sTabTable.appendChild(sTabTr);
7281 var sTabTd = document.createElement("TD");
7282 sTabTd.innerHTML = tran.t("notificationAlias");
7283 sTabTd.title = tran.t("notificationAliasTitle");
7284 sTabTr.appendChild(sTabTd);
7285 var sTabOptionsTd = document.createElement("TD");
7286 sTabTr.appendChild(sTabOptionsTd);
7287 var sTabInput = document.createElement("INPUT");
7288 sTabInput.id = "notificationAliasInput";
7289 sTabInput.addEventListener("change", function (e) {
7290 var n = sTabInput.value.toLowerCase().split(";");
7291 bpOverlay.alias = [];
7292 var i = 0;
7293 for (; i < n.length; i++) {
7294 if (n[i] !== "") {
7295 bpOverlay.alias.push(n[i]);
7296 }
7297 }
7298 });
7299 sTabInput.title = tran.t("notificationAliasInputTitle");
7300 sTabOptionsTd.appendChild(sTabInput);
7301 })();
7302
7303 //Notification meow
7304 generateSettingsElement(
7305 tran.t("endGameNotification"),
7306 {
7307 on: tran.t("endGameNotificationOptions.on"),
7308 off: tran.t("endGameNotificationOptions.off"),
7309 },
7310 "endGameNotificationSelect", "notificationsTable",
7311 function () {
7312 var sTabSelect = document.getElementById("endGameNotificationSelect");
7313 if (sTabSelect.value == "on") {
7314 bpOverlay.endGameNotification = true;
7315 }
7316 else {
7317 bpOverlay.endGameNotification = false;
7318 }
7319 }
7320 );
7321
7322 document.getElementById("endGameNotificationSelect").value = "off";
7323
7324 var alphaColumnStyle = document.createElement("STYLE");
7325 alphaColumnStyle.textContent = ".alphaColumn{display:none;}";
7326 document.head.appendChild(alphaColumnStyle);
7327
7328 //Alpha display
7329 generateSettingsElement(
7330 tran.t("alphaRouletteName"),
7331 {
7332 on: tran.t("alphaRouletteOptions.on"),
7333 off: tran.t("alphaRouletteOptions.off"),
7334 },
7335 "alphaRouletteSelect", "overlaySettingsTable",
7336 function () {
7337 var sTabSelect = document.getElementById("alphaRouletteSelect");
7338 if (sTabSelect.value == "on") {
7339 alphaColumnStyle.textContent = "";
7340 }
7341 else {
7342 alphaColumnStyle.textContent = ".alphaColumn{display:none;}";
7343 }
7344 }
7345 );
7346
7347 var wordsColumnStyle = document.createElement("STYLE");
7348 wordsColumnStyle.textContent = ".wordsColumn{display:none;}";
7349 document.head.appendChild(wordsColumnStyle);
7350
7351 // Word counter display
7352 generateSettingsElement(
7353 tran.t("wordCounterName"),
7354 {
7355 on: tran.t("wordCounterOptions.on"),
7356 off: tran.t("wordCounterOptions.off"),
7357 },
7358 "wordCounterSelect", "overlaySettingsTable",
7359 function () {
7360 var sTabSelect = document.getElementById("wordCounterSelect");
7361 if (sTabSelect.value == "on") {
7362 wordsColumnStyle.textContent = "";
7363 }
7364 else {
7365 wordsColumnStyle.textContent = ".wordsColumn{display:none;}";
7366 }
7367 }
7368 );
7369
7370 // Only add this if speech synthesis is supported by the browser
7371 if (window.speechSynthesis) {
7372 var speechListener = function (e) {
7373 if (bpOverlay.ignoring[e.userAuthId]) return;
7374
7375 var iterator=0;
7376 for(i=200; i<e.text.length; i+= 200) {
7377 for(j=i; j >= iterator; j -= 1) {
7378 if(e.text[j] === " ") {
7379 barkmeow = new SpeechSynthesisUtterance(e.text.substring(iterator, j));
7380 barkmeow.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == bpOverlay.speechName; })[0];
7381 barkmeow.onstart = function() { startPing() };
7382 barkmeow.onend = function() { pingSuccess(); };
7383 speechSynthesis.speak(barkmeow);
7384 iterator=j;
7385 break;
7386 } else if(j == iterator) {
7387 barkmeow = new SpeechSynthesisUtterance(e.text.substring(iterator, i));
7388 barkmeow.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == bpOverlay.speechName; })[0];
7389 barkmeow.onstart = function() { startPing() };
7390 barkmeow.onend = function() { pingSuccess(); };
7391 iterator=i;
7392 }
7393 }
7394 }
7395 barkmeow = new SpeechSynthesisUtterance(e.text.substring(iterator, e.text.length));
7396 barkmeow.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == bpOverlay.speechName; })[0];
7397 barkmeow.onstart = function() { startPing() };
7398 barkmeow.onend = function() { pingSuccess(); };speechSynthesis.speak(barkmeow);
7399 console.log(barkmeow); //fix for onend not being called at the very end. See stackoverflow. Weird
7400 }
7401
7402 //oh boy. Here we go with the speech element
7403 generateSettingsElement(
7404 tran.t("speechName"),
7405 {
7406 off: tran.t("speechOptions.off"),
7407 on: tran.t("speechOptions.on"),
7408 },
7409 "speechSelect", "chatOpTable",
7410 function() {
7411 var sTabSelect = document.getElementById("speechSelect");
7412 if(sTabSelect.value == "on") {
7413 //The name of the ping function that we will reference
7414 var pingu;
7415
7416 //Starts the ping. If a pingSuccess isn't received within 13 seconds (approx time of 31 w's which break this) after starting a chunk,
7417 //then speechSynthesis.cancel() is called. Dirty workaround.
7418 //it throws out a lot of text if an error occurs, but at least it restarts this whole mess for you
7419 var startPing = function() {
7420 pingu = setTimeout(function(){ speechSynthesis.cancel(); }, 13000);
7421 };
7422
7423 //calling this function signifies that a speecherror has not occurred.
7424 var pingSuccess = function() {
7425 clearTimeout(pingu);
7426 };
7427
7428 //the speecher barkmeow
7429 channel.socket.on("chatMessage", speechListener);
7430 } else {
7431 channel.socket.removeListener("chatMessage", speechListener);
7432 }
7433 }
7434 );
7435
7436 generateSettingsElement(
7437 tran.t("voiceSelect"),
7438 {
7439 us: tran.t("voiceOptions.us"),
7440 ukMale: tran.t("voiceOptions.ukMale"),
7441 ukFem: tran.t("voiceOptions.ukFem"),
7442 fran: tran.t("voiceOptions.fran"),
7443 },
7444 "voiceSelect", "chatOpTable",
7445 function () {
7446 var sTabSelect = document.getElementById("voiceSelect");
7447 if (sTabSelect.value == "us") {
7448 bpOverlay.speechName = "Google US English";
7449 }
7450 else if(sTabSelect.value == "ukMale") {
7451 bpOverlay.speechName = "Google UK English Male";
7452 } else if(sTabSelect.value == "ukFem") {
7453 bpOverlay.speechName = "Google UK English Female";
7454 } else {
7455 bpOverlay.speechName = "Google Français";
7456 }
7457 }
7458
7459 );
7460 }
7461
7462 document.getElementById("alphaRouletteSelect").value = "off";
7463 document.getElementById("wordCounterSelect").value = "off";
7464
7465 // Wrap game functions, make the autoscroll/focus buttons.
7466 wrapGameFunctions();
7467
7468 if (channel.data.state === "playing") {
7469 generateActorConditions();
7470 }
7471 }
7472
7473 firstRunProcs();
7474
7475 // Make updateTime fire every second.
7476 setInterval(updateTime, 1000);
7477
7478 // "Update Text"
7479 channel.appendToChat("msgAccueil", tran.t("updateText"));
7480
7481 if (bpOverlay.emoteError) {
7482 channel.appendToChat("msg", tran.t("twitchEmoteError"));
7483 }
7484 }
7485 main();
7486 }
7487}
7488
7489var s = document.createElement('script');
7490s.setAttribute("type", "application/javascript");
7491s.textContent = '(' + source + ')();';
7492
7493document.body.appendChild(s);
7494document.body.removeChild(s);
7495
7496// Function to validate the theme object
7497// This won't catch everything, but it should prevent future errors
7498// By making sure all the variables are the right type
7499// This is two hundred lines of inefficiency :D
7500var validateThemeObj = function (themeObj) {
7501 var valid = true;
7502
7503 // Validate images
7504 if (typeof(themeObj.images) === "object") {
7505 for (var i in themeObj.images) {
7506 if (typeof(themeObj.images[i]) !== "object") {
7507 console.log("Error: image " + i + " is not an object.");
7508 valid = false;
7509 }
7510 else {
7511 if (typeof(themeObj.images[i].src) !== "string") {
7512 console.log("Error: invalid src provided in image " + i + ".");
7513 valid = false;
7514 }
7515
7516 if (typeof(themeObj.images[i].xOffset) !== "number" && typeof(themeObj.images[i].xOffset) !== "undefined") {
7517 console.log("Error: invalid xOffset in image " + i + ".");
7518 valid = false;
7519 }
7520
7521 if (typeof(themeObj.images[i].yOffset) !== "number" && typeof(themeObj.images[i].yOffset) !== "undefined") {
7522 console.log("Error: invalid yOffset in image " + i + ".");
7523 valid = false;
7524 }
7525 }
7526 }
7527 }
7528 else if (typeof(themeObj.images) !== "undefined") {
7529 console.log("Error: images is not an object.");
7530 valid = false;
7531 }
7532
7533 // Validate css
7534 if (typeof(themeObj.css) === "object") {
7535 if (themeObj.css.text) {
7536 if (typeof(themeObj.css.text) !== "string") {
7537 console.log("Error: invalid css.text provided");
7538 valid = false;
7539 }
7540 }
7541 else if (themeObj.css.src) {
7542 if (typeof(themeObj.css.src) !== "string") {
7543 console.log("Error: invalid css source provided");
7544 valid = false;
7545 }
7546 }
7547 else {
7548 console.log("Error: css field declared, but no css provided");
7549 valid = false;
7550 }
7551 }
7552 else if (typeof(themeObj.css) !== "undefined") {
7553 console.log("Error: css is not an object.");
7554 valid = false;
7555 }
7556
7557 var minMaxOrNumber = function (value) {
7558 if (typeof(value) === "object") {
7559 if (typeof(value.min) !== "number") {
7560 return false;
7561 }
7562 if (typeof(value.max) !== "number") {
7563 return false;
7564 }
7565 }
7566 else if (typeof(value) !== "number") {
7567 return false;
7568 }
7569 return true;
7570 }
7571
7572 // Validate particles
7573 if (typeof(themeObj.particles) === "object") {
7574 if (Object.prototype.toString.call(themeObj.particles.emitters) === "[object Array]") { // Arrays are weird
7575 for (i = 0; i < themeObj.particles.emitters.length; i++) {
7576 var e = themeObj.particles.emitters[i];
7577 // Oh god there's so much to validate aaaaaaaaa
7578
7579 // validate position
7580 if (typeof(e.position) === "object") {
7581 if (typeof(e.position.x) !== "number") {
7582 console.log("Error: particle.emitters[" + i + "].position.x is not a number");
7583 valid = false;
7584 }
7585
7586 if (typeof(e.position.y) !== "number") {
7587 console.log("Error: particle.emitters[" + i + "].position.y is not a number");
7588 valid = false;
7589 }
7590
7591 if (typeof(e.position.width) !== "undefined" && typeof(e.position.width) !== "number") {
7592 console.log("Error: particle.emitters[" + i + "].position.width is not a number");
7593 valid = false;
7594 }
7595
7596 if (typeof(e.position.height) !== "undefined" && typeof(e.position.height) !== "number") {
7597 console.log("Error: particle.emitters[" + i + "].position.height is not a number");
7598 valid = false;
7599 }
7600 }
7601 else {
7602 console.log("Error: particles.emitters[" + i + "].position is not an object");
7603 valid = false;
7604 }
7605
7606 // Validate velocity
7607 if (typeof(e.velocity) === "object") {
7608 if (!minMaxOrNumber(e.velocity.x)) {
7609 console.log("Error: particles.emitters[" + i + "].velocity.x is invalid");
7610 valid = false;
7611 }
7612 if (!minMaxOrNumber(e.velocity.y)) {
7613 console.log("Error: particles.emitters[" + i + "].velocity.y is invalid");
7614 valid = false;
7615 }
7616 }
7617 else {
7618 console.log("Error: particles.emitters[" + i + "].velocity is not an object");
7619 valid = false;
7620 }
7621
7622 // Validate size
7623 if (!minMaxOrNumber(e.size)) {
7624 console.log("Error: particles.emitters[" + i + "].size is invalid");
7625 valid = false;
7626 }
7627
7628 // Validate rotation
7629 if (!minMaxOrNumber(e.rotation)) {
7630 console.log("Error: particles.emitters[" + i + "].rotation is invalid");
7631 valid = false;
7632 }
7633
7634 // Validate angularVelocity
7635 if (!minMaxOrNumber(e.angularVelocity)) {
7636 console.log("Error: particles.emitters[" + i + "].angularVelocity is invalid");
7637 valid = false;
7638 }
7639
7640 // Validate spawnRate
7641 if (typeof(e.spawnRate) === "object") {
7642 if (typeof(e.spawnRate.high) !== "number") {
7643 console.log("Error: particles.emitters[" + i + "].spawnRate.high is invalid");
7644 valid = false;
7645 }
7646 if (typeof(e.spawnRate.low) !== "number") {
7647 console.log("Error: particles.emitters[" + i + "].spawnRate.low is invalid");
7648 valid = false;
7649 }
7650 }
7651 else {
7652 console.log("Error: particle.emitters[" + i + "].spawnRate is not an object");
7653 valid = false;
7654 }
7655
7656 // Validate gravity
7657 if (typeof(e.gravity) === "object") {
7658 if (!minMaxOrNumber(e.gravity.x)) {
7659 console.log("Error: particles.emitters[" + i + "].gravity.x is invalid");
7660 valid = false;
7661 }
7662 if (!minMaxOrNumber(e.gravity.y)) {
7663 console.log("Error: particles.emitters[" + i + "].gravity.y is invalid");
7664 valid = false;
7665 }
7666 }
7667 else {
7668 console.log("Error: particles.emitters[" + i + "].gravity is not an object");
7669 valid = false;
7670 }
7671
7672 // Effing hell!
7673 }
7674 }
7675 else {
7676 console.log("Error: particles.emitters is not an array");
7677 valid = false;
7678 }
7679
7680 if (Object.prototype.toString.call(themeObj.particles.images) === "[object Array]") {
7681 for (i = 0; i < themeObj.particles.images.length; i++) {
7682 if (typeof(themeObj.particles.images[i]) !== "string") {
7683 console.log("Error: particles.images[" + i + "] is not a string");
7684 valid = false;
7685 }
7686 }
7687 }
7688 }
7689 else if (typeof(themeObj.particles) !== "undefined") {
7690 console.log("Error: particles is not an object");
7691 valid = false;
7692 }
7693
7694 var validateTextStyle = function (textStyle) {
7695 if (textStyle === undefined) {
7696 return true;
7697 }
7698 if (typeof(textStyle) === "object") {
7699 if (typeof(textStyle.color) !== "undefined") {
7700 if (typeof(textStyle.color) !== "string") {
7701 return false;
7702 }
7703 }
7704
7705 if (typeof(textStyle.fontFamily) !== "undefined") {
7706 if (typeof(textStyle.fontFamily) !== "string") {
7707 return false;
7708 }
7709 }
7710
7711 if (typeof(textStyle.fontSize) !== "undefined") {
7712 if (typeof(textStyle.fontSize) !== "number") {
7713 return false;
7714 }
7715 }
7716
7717 if (typeof(textStyle.majorFontSize) !== "undefined") {
7718 if (typeof(textStyle.majorFontSize) !== "number") {
7719 return false;
7720 }
7721 }
7722
7723 if (typeof(textStyle.minorFontSize) !== "undefined") {
7724 if (typeof(textStyle.minorFontSize) !== "number") {
7725 return false;
7726 }
7727 }
7728 }
7729 else if (typeof(textStyle !== "undefined")) {
7730 return false;
7731 }
7732 return true;
7733 }
7734
7735 var ts = ["statusText", "promptText", "wordText", "highlightedText", "bonusLetterText"];
7736
7737 // Validate textStyles
7738 if (typeof(themeObj.textStyles) === "object") {
7739 for (i = 0; i < ts.length; i++) {
7740 if (!validateTextStyle(themeObj.textStyles[ts[i]])) {
7741 console.log("Error: textStyles." + ts[i] + " is invalid or has some invalid parameters.");
7742 valid = false;
7743 }
7744 }
7745 }
7746 else if (typeof(themeObj.textStyles) !== "undefined") {
7747 console.log("Error: textStyles is not an object.");
7748 valid = false;
7749 }
7750
7751 return valid;
7752};
7753
7754var loadAndApplyTheme = function (url) {
7755 GM_xmlhttpRequest({
7756 method: "GET",
7757 url: url,
7758 onload: function (resp) {
7759 try {
7760 var themeObj = json_parse(resp.responseText);
7761 }
7762 catch (e) {
7763 alert("Invalid JSON.");
7764 console.log(e);
7765 return;
7766 }
7767
7768 if (validateThemeObj(themeObj)) {
7769 var s = document.createElement('script');
7770 s.setAttribute("type", "application/javascript");
7771 s.textContent = "loadCustomTheme(false); loadCustomTheme(" + resp.responseText + ")";
7772
7773 document.body.appendChild(s);
7774 document.body.removeChild(s);
7775 }
7776 else {
7777 alert("Invalid theme specified. Check the console for what is invalid.");
7778 }
7779 },
7780 onerror: function (resp) {
7781 alert("Error loading " + url);
7782 },
7783 });
7784};
7785// This code attaches listeners to relevant settings objects to make them persistent
7786// Process to attach to things in the DOM from the sandboxed environment
7787// This needs to happen in this environment because I need access to the GM functions
7788var attachToSettings = function () {
7789 if (!(document.getElementById("containerSelect") &&
7790 document.getElementById("twitchEmoteSelect") &&
7791 document.getElementById("adventureSetting") &&
7792 document.getElementById("themeSelect") &&
7793 document.getElementById("customThemeInput") &&
7794 document.getElementById("notificationsSelect") &&
7795 document.getElementById("notificationVolumeSlider") &&
7796 document.getElementById("notificationAliasInput") &&
7797 document.getElementById("endGameNotificationSelect") &&
7798 document.getElementById("particleSelect") &&
7799 document.getElementById("chatDownButton") &&
7800 document.getElementById("autoFocusButton") &&
7801 document.getElementById("dragButton") &&
7802 document.getElementById("alphaRouletteSelect"))) {
7803 console.log("Cannot attach, trying again in a second");
7804 setTimeout(attachToSettings, 1000);
7805 }
7806 else {
7807 // Whoo look at them variables
7808 var cs = document.getElementById("containerSelect");
7809 var tes = document.getElementById("twitchEmoteSelect");
7810 var as = document.getElementById("adventureSetting");
7811 var ts = document.getElementById("themeSelect");
7812 var cti = document.getElementById("customThemeInput");
7813 var ns = document.getElementById("notificationsSelect");
7814 var nai = document.getElementById("notificationAliasInput");
7815 var nvs = document.getElementById("notificationVolumeSlider");
7816 var egns = document.getElementById("endGameNotificationSelect");
7817 var ps = document.getElementById("particleSelect");
7818 var cdb = document.getElementById("chatDownButton");
7819 var afb = document.getElementById("autoFocusButton");
7820 var db = document.getElementById("dragButton");
7821 var ars = document.getElementById("alphaRouletteSelect");
7822 var wcs = document.getElementById("wordCounterSelect");
7823
7824 var loadAndChangeSelect = function (element, valueName, defaultValue) {
7825 if (GM_getValue(valueName, defaultValue) !== element.value) {
7826 element.value = GM_getValue(valueName, defaultValue);
7827 var event = new Event("change");
7828 element.dispatchEvent(event);
7829 }
7830 }
7831
7832 var loadAndChangeButton = function (element, valueName, defaultValue) {
7833 if (GM_getValue(valueName, defaultValue) !== element.dataset.state) {
7834 var event = new MouseEvent("click");
7835 element.dispatchEvent(event);
7836 }
7837 }
7838
7839 loadAndChangeSelect(cs, "containerState", "compact");
7840 loadAndChangeSelect(tes, "twitchEmoteState", "on");
7841 loadAndChangeSelect(as, "adventureState", "off");
7842 loadAndChangeSelect(ns, "notificationsState", "on");
7843 loadAndChangeSelect(nai, "notificationAlias", ""); // Yay duck typing
7844 loadAndChangeSelect(egns, "endGameNotificationSetting", "off");
7845 loadAndChangeSelect(ars, "alphaRouletteState", "off");
7846 loadAndChangeSelect(wcs, "wordCounterState", "off");
7847 loadAndChangeSelect(ps, "particleState", "high");
7848 loadAndChangeButton(cdb, "chatDownState", "true"); // String booleans because of the way data attributes work in HTML :(
7849 // Trust me, I don't like being stringly typed either
7850 loadAndChangeButton(afb, "autoFocusState", "true");
7851 loadAndChangeButton(db, "dragState", "false");
7852
7853 // Have to handle this one slightly differently
7854 if (GM_getValue("notificationVolume", 100) !== nvs.value) {
7855 nvs.value = GM_getValue("notificationVolume", 100);
7856 var s = document.createElement("script");
7857 s.textContent = "bpOverlay.notificationSound.volume=" + (nvs.value / 100);
7858 document.body.appendChild(s);
7859 document.body.removeChild(s);
7860 };
7861
7862 cs.addEventListener("change", function () {
7863 setTimeout(function () {
7864 GM_setValue("containerState", cs.value);
7865 }, 100);
7866 });
7867
7868 tes.addEventListener("change", function () {
7869 setTimeout(function () {
7870 GM_setValue("twitchEmoteState", tes.value);
7871 }, 100);
7872 });
7873
7874 as.addEventListener("change", function () {
7875 setTimeout(function () {
7876 GM_setValue("adventureState", as.value);
7877 }, 100);
7878 });
7879
7880 ns.addEventListener("change", function () {
7881 setTimeout(function () {
7882 GM_setValue("notificationsState", ns.value);
7883 }, 100);
7884 });
7885
7886 nai.addEventListener("change", function () {
7887 setTimeout(function () {
7888 GM_setValue("notificationAlias", nai.value);
7889 }, 100);
7890 });
7891
7892 nvs.addEventListener("change", function () {
7893 setTimeout(function () {
7894 GM_setValue("notificationVolume", nvs.value);
7895 }, 100);
7896 });
7897
7898 egns.addEventListener("change", function () {
7899 setTimeout(function () {
7900 GM_setValue("endGameNotificationSetting", egns.value);
7901 }, 100);
7902 });
7903
7904 ps.addEventListener("change", function () {
7905 setTimeout(function () {
7906 GM_setValue("particleState", ps.value);
7907 }, 100);
7908 });
7909
7910 ars.addEventListener("change", function () {
7911 setTimeout(function () {
7912 GM_setValue("alphaRouletteState", ars.value);
7913 }, 100);
7914 });
7915
7916 wcs.addEventListener("change", function () {
7917 setTimeout(function () {
7918 GM_setValue("wordCounterState", wcs.value);
7919 }, 100);
7920 });
7921
7922 cdb.addEventListener("click", function () {
7923 setTimeout(function () {
7924 GM_setValue("chatDownState", cdb.dataset.state);
7925 }, 100);
7926 });
7927
7928 afb.addEventListener("click", function () {
7929 setTimeout(function () {
7930 GM_setValue("autoFocusState", afb.dataset.state);
7931 }, 100);
7932 });
7933
7934 db.addEventListener("click", function () {
7935 setTimeout(function () {
7936 GM_setValue("dragState", db.dataset.state);
7937 }, 100);
7938 });
7939
7940 // These ones are special!
7941 ts.addEventListener("change", function () {
7942 if (ts.value !== "none" && ts.value !== "custom") {
7943 loadAndApplyTheme(ts.value);
7944 GM_setValue("theme", ts.value);
7945 GM_setValue("customTheme", "none");
7946 cti.value = "";
7947 }
7948 else if (ts.value === "none") {
7949 GM_setValue("theme", "none");
7950 GM_setValue("customTheme", "none");
7951 }
7952 });
7953
7954 cti.addEventListener("keypress", function (e) {
7955 if (e.keyCode === 13) {
7956 loadAndApplyTheme(cti.value);
7957 GM_setValue("theme", "custom");
7958 GM_setValue("customTheme", cti.value);
7959 }
7960 });
7961
7962 loadAndChangeSelect(ts, "theme", "none");
7963
7964 if (GM_getValue("customTheme", "none") !== "none") {
7965 GM_setValue("theme", "custom");
7966 cti.value = GM_getValue("customTheme", "none");
7967 loadAndApplyTheme(cti.value);
7968 }
7969
7970 }
7971}
7972
7973attachToSettings();