Roll20 Fixes

Some silly fixes and 'improvements' to Roll20 because I'm impatient and a psycho

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name			Roll20 Fixes
// @namespace		http://statonions.com/
// @version			0.3.21
// @description		Some silly fixes and 'improvements' to Roll20 because I'm impatient and a psycho
// @author			Justice Noon
// @match			https://app.roll20.net/editor/
// @grant			GM_setValue
// @grant			GM_getValue
// ==/UserScript==
// Changelog: Fix disabled zoom slider

(function() {
    'use strict';

//Features
var TMp = {
	clickShow: true,
	macroHide: true,
	fullButt: true,
	fixPing: "1",
	css: {
		player:	false,
		zoom: false,
		sidebar: false,
		quick: false,
		turns: false,
        error: false,
		macroTok: true,
		bigQuery: true
	},
	pfCustomAttr: true,
	splitTokName: "3",
	toolbarButt: true,
	scaleToks: false,
	statusHQ: false,
	scrollPages: '2',
    perfMode: false,
	noPopouts: false
};
try {
	GM_info;
	var stored = GM_getValue('TMp', 'nah');
	if (stored == 'nah')
		GM_setValue('TMp', JSON.stringify(TMp));
	else {
		var checkVals = function(d, s) {
			for (var k in d) {
				if (typeof d[k] !== typeof s[k])
					s[k] = d[k];
				if (typeof d[k] == 'object')
					s[k] = checkVals(d[k], s[k]);
			};
			return s;
		};
		TMp = checkVals(TMp, JSON.parse(stored));
		GM_setValue('TMp', JSON.stringify(TMp));
	}
	checkLoaded();
}
catch(err) {
	checkLoaded();
}

function checkLoaded(tried) {
    if (!tried) tried = 1;
    try {
            if (Campaign && Campaign.activePage().thegraphics && Campaign.activePage().thegraphics.models[0] && Campaign.activePage().thegraphics.models[0].view && Campaign.activePage().thegraphics.models[0].view.graphic) {
                tried = 69;
				showtime();
			}
            else
                setTimeout(checkLoaded, 1000, tried);
    }
    catch(err) {
        if (++tried < 69)
            setTimeout(checkLoaded, 1000, tried);
        else {
            console.log(err);
			console.log("Couldn't load userscript. Aborting.");
		}
    }
};

function showtime() {
//For *my* players specifically. Activates all css tweaks. I'm too lazy to maintain separate code (in-person touchpad view)
////_.each(TMp.css, (c,i,l) => l[i] = true);TMp.perfMode = true;
	//Create greasemonkey preferences menu
	try {
		GM_info;
		var prefLi = document.createElement('li');
		prefLi.id = 'showfixes';
		var prefSpan = document.createElement('span');
		prefSpan.setAttribute('class', 'pictos');
		prefSpan.appendChild(document.createTextNode('x'));
		prefLi.appendChild(prefSpan);
		prefLi.appendChild(document.createTextNode("\r\n        'Fixes' Preferences\r\n"));
		document.getElementById('helpsite').childNodes[3].childNodes[1].appendChild(prefLi);
		prefLi.addEventListener('click', promptPrefs);
        $("#helpsite").off();

		function promptPrefs(e) {
			e.stopPropagation();
			var finished = false, response, responseVal, responseMod = '', ref = TMp, counter, changeKey;
			while (!finished) {
				counter = 1;
				response = prompt(_.reduce(ref, (memo, v, k) => memo + '\n' + counter++ + ':' + k + '  ::  ' + (_.isObject(v) ? '[' + _.keys(v).length + ' properties]' : v), 'Enter a number:\n0:Back'), 'Enter a number to swap value.');
				responseVal = parseInt(response.replace(/\+/g,'').replace(/-/g,''));
				responseMod = (response.indexOf('+') != -1 ? '+' : (response.indexOf('-') != -1 ? '-' : ''));
				if (/[^0-9+-]+/.test(response) || responseVal == 0 || responseVal > counter) {
					if (ref === TMp) {
						GM_setValue('TMp', JSON.stringify(TMp));
						finished = true;
						alert('Reload to see changes');
					}
					else
						ref = TMp;
				}
				else {
					changeKey = _.keys(ref)[responseVal-1];
					if (_.isObject(ref[changeKey])) {
						if (responseMod == '!')
							_.each(ref[changeKey], (e,i) => {if (typeof e == 'boolean') ref[changeKey][i] = !e});
						else if (responseMod == '+')
							_.each(ref[changeKey], (e,i) => {if (typeof e == 'boolean') ref[changeKey][i] = true});
						else if (responseMod == '-')
							_.each(ref[changeKey], (e,i) => {if (typeof e == 'boolean') ref[changeKey][i] = false});
						else
							ref = ref[changeKey];
					}
					else if (_.isBoolean(ref[changeKey]))
						ref[changeKey] = !ref[changeKey];
					else
						ref[changeKey] = prompt('Enter a new value for ' + changeKey);
				}
			}
		}
	}
	catch (err) {
		console.log('No GM. No need for preferences.');
	}

	window.myLower = Campaign.activePage().thegraphics.models[0].view.graphic.canvas.lowerCanvasEl;
	window.myUpper = Campaign.activePage().thegraphics.models[0].view.graphic.canvas.upperCanvasEl;
	window.myMain = document.getElementById('finalcanvas');

	//Display tokenname on select
	if (TMp.clickShow) {
		var toks = [];
		var muteCallback = function(mutationsList) {
			if (currentcontexttarget) {
				for(var mutation of mutationsList) {
					if (!_.isEmpty(mutation.addedNodes)) {
						let cct = currentcontexttarget.canvas;
						let cctIt = cct.lastRenderedObjectWithControlsAboveOverlay.model.attributes;
						if (!cctIt.showname) {
							cctIt.showname = true;
							toks.push([cctIt.page_id, cctIt.id]);
						}
						cct._objects.push(cct._objects.splice(cct._objects.indexOf(cct.lastRenderedObjectWithControlsAboveOverlay), 1)[0]);
						currentcontexttarget.canvas.renderAll && currentcontexttarget.canvas.renderAll();
					}
					else if (!_.isEmpty(mutation.removedNodes)) {
						_.each(toks, tok => {if (tok[0] == Campaign.activePage().id) _.find(Campaign.activePage().thegraphics.models, tokk => tokk.attributes.id == tok[1]).attributes.showname = false});
						toks = [];
						currentcontexttarget.canvas.renderAll && currentcontexttarget.canvas.renderAll();
						Campaign.activePage().reorderByZ();
					}
				}
			}
		};
		var observer = new MutationObserver(muteCallback);
		observer.observe(document.getElementById('editor-wrapper'), {childList: true});
	}

	if (TMp.css.macroTok) {
		var macroTokCallback = function(mutationsList) {
			for (var mutation of mutationsList) {
                _.delay((mutation) => {
                    let cctIt = currentcontexttarget.canvas.lastRenderedObjectWithControlsAboveOverlay.model.attributes;
                    if (mutation.target.style.display == 'block' && cctIt.gmnotes != 'blank' && cctIt.gmnotes != '%3Cp%3Eblank%3C/p%3E')
                        _.each(document.getElementsByClassName('tokenactions')[0].firstElementChild.children, ob => ob.setAttribute('data-blank', 'false'));
                }, (typeof currentcontexttarget == 'undefined' ? 1000 : 0), mutation);
			}
		};
		var macroObserver = new MutationObserver(macroTokCallback);
		macroObserver.observe(document.querySelector('.mode.tokenactions'), {attributeFilter: ['style']});
	}

	//Allow Macros to be hidden
	if (TMp.macroHide) {
		var toggleMacro = document.createElement('div');
		toggleMacro.setAttribute('class', 'macrobox');
		var toggleButton = document.createElement('button');
		toggleButton.setAttribute('class', 'btn');
		toggleButton.appendChild(document.createTextNode('Show/Hide'));
		toggleButton.id = 'toggleMacros';
		toggleMacro.appendChild(toggleButton)
		//macrobar is defined by default
		macrobar.appendChild(toggleMacro);
		document.getElementById('toggleMacros').addEventListener('click', () => macrobar.style.left = (macrobar.style.left == '' ? (macrobar.offsetWidth * -1 + 100) + 'px' : ''));
	}

	//Create fullscreen button
	if (TMp.fullButt) {
		var fullScreenLi = document.createElement('li');
		fullScreenLi.setAttribute('tip', 'Toggle Fullscreen');
		fullScreenLi.id = 'fullscreener';
		var fullScreenSpan = document.createElement('span');
		fullScreenSpan.setAttribute('class', 'pictos');
		fullScreenSpan.appendChild(document.createTextNode('`'));
		fullScreenLi.appendChild(fullScreenSpan);
		floatingtoolbar.childNodes[1].appendChild(fullScreenLi);
		fullScreenLi.addEventListener('click', toggleFullScreen);

		function toggleFullScreen() {
			var doc = window.document;
			var docEl = doc.documentElement;

			var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
			var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;

			if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
			requestFullScreen.call(docEl);
			}
			else {
			cancelFullScreen.call(doc);
			}
		}
	}
	//Create Floating Toolbar button
	if (TMp.toolbarButt) {
		var ToolBar = _.filter(Campaign.players.get(d20_player_id).macros.models, m => m.attributes.name.indexOf('ToolBar') > -1);
		if (_.isUndefined(ToolBar))
			ToolBar = _.filter(_.union(..._.map(Campaign.players.models, m => m.macros.models)), m => {return m.visibleToCurrentPlayer() && m.attributes.name.indexOf('ToolBar') > -1});
		_.each(ToolBar, tb => {
			var actions = tb.attributes.action.split('\n');
			var toolBarLi = document.createElement('li');
			toolBarLi.setAttribute('tip', 'Additional Macros');
			toolBarLi.id = 'ToolBar' + (tb.attributes.name == ToolBar ? tb.id : tb.attributes.name.replace('ToolBar',''));
			toolBarLi.setAttribute('style', 'display: flex; justify-content: center; align-items: center;');
			for (var k = 0, thisAction, thisSpan, thisLi, thisA, thisODiv; k < actions.length; k++) {
				thisAction = actions[k].split('||');
				thisSpan = document.createElement('span');
				thisSpan.setAttribute('class', 'pictos');
                thisSpan.setAttribute('style', 'left: -11rem;');
				//Make sure character is supported and won't unclip out of side
				var canvas = document.createElement('canvas').getContext('2d');
				canvas.font = '22px Pictos';
				var width = canvas.measureText(thisAction[0]);
				if (width.width > 31)
					thisAction[0] = _.compact([...thisAction[0].replace(/[\u200B-\u200D\uFEFF]/g, '')]).join(' ');
				thisSpan.appendChild(document.createTextNode(thisAction[0]));
				if (k == 0) {
					toolBarLi.appendChild(thisSpan);
					var thisDiv = document.createElement('div');
					thisDiv.setAttribute('class', 'submenu');
					var thisUl = document.createElement('ul');
				}
				else {
					thisLi = document.createElement('li');
					thisA = document.createElement('a');
                    if (thisAction[2].indexOf('j:') > -1) {
                     thisA.setAttribute('href', '!');
                     thisA.onclick = eval('() => {' + thisAction[2].substr(2) + '}');
                    }
                    else
                        thisA.setAttribute('href', thisAction[2]);
					thisA.appendChild(thisSpan);
					thisODiv = document.createElement('div');
					thisODiv.appendChild(document.createTextNode(thisAction[1]));
					thisA.appendChild(thisODiv);
					thisLi.appendChild(thisA);
					thisUl.appendChild(thisLi);
				}
			}
			thisDiv.appendChild(thisUl);
			thisDiv.setAttribute('style', 'top: -' + k*20 + 'px !important;');
			toolBarLi.appendChild(thisDiv);
			floatingtoolbar.childNodes[1].appendChild(toolBarLi);
		});
	}

	//Fix Pings
	if (TMp.fixPing != "0") {
		JSON.parse2 = JSON.parse;
		JSON.parse = function(e) {
			var intercept = JSON.parse2(e), api = false;
			if (intercept.type == 'mapping') {
				if (_.isUndefined(intercept.currentLayer))
                    api = true;
                if (TMp.fixPing == "2" && intercept.player == "api") {
                    if (is_gm)
                        spoofPing(intercept);
                    Object.assign(intercept, {scrollto: false, left: -100, top: -100});
                }
                intercept.currentLayer = 'objects';
                if (intercept.pageid != Campaign.activePage().id || (api && intercept.player != "api" && intercept.player != d20_player_id))
                    Object.assign(intercept, {scrollto: false, left: -100, top: -100});
			}
			return intercept;
		};
		function spoofPing(old) {
			var paddingOffset = [], currentCanvasOffset = [];
			var canvasZoom = Math.round(document.getElementById('finalcanvas').getContext('2d').getTransform().a * 10) / 10;
			var canvasWidth = document.getElementById('finalcanvas').clientWidth, canvasHeight = document.getElementById('finalcanvas').clientHeight;
			var scaledTop = document.getElementById('editor-wrapper').scrollTop / canvasZoom, scaledLeft = document.getElementById('editor-wrapper').scrollLeft / canvasZoom;
			var pageWidth = Campaign.activePage().attributes.width * 70, pageHeight = Campaign.activePage().attributes.height * 70;
			var padding = 125;
			if (scaledLeft < padding)
				(paddingOffset[0] = padding - scaledLeft, currentCanvasOffset[0] = 0);
			else {
				if (pageWidth / canvasZoom - scaledLeft - canvasWidth / canvasZoom + padding < 0)
					(paddingOffset[0] = pageWidth / canvasZoom - scaledLeft - canvasWidth / canvasZoom + padding, currentCanvasOffset[0] = scaledLeft - padding + paddingOffset[0]);
				else
					(paddingOffset[0] = 0, currentCanvasOffset[0] = scaledLeft - padding);
			}
			if (scaledTop < padding)
				(paddingOffset[1] = padding - scaledTop, currentCanvasOffset[1] = 0);
			else {
				if (pageHeight / canvasZoom - scaledTop - canvasHeight / canvasZoom + padding < 0)
					(paddingOffset[1] = pageHeight / canvasZoom - scaledTop - canvasHeight / canvasZoom + padding, currentCanvasOffset[1] = scaledTop - padding + paddingOffset[1]);
				else
					(paddingOffset[1] = 0, currentCanvasOffset[1] = scaledTop - padding);
			}
			//var m = {left: old.left, top: old.top};
            var pos = {left: canvasZoom * (old.left - currentCanvasOffset[0]) + paddingOffset[0], top: canvasZoom * (old.top - currentCanvasOffset[1]) + paddingOffset[1]};
			var evt = new MouseEvent('mousedown', {bubbles: true, cancelable: true, composed: true, buttons: 1, shiftKey: true, clientX: pos.left, clientY: pos.top});
            var maskedArr = [];
           _.each(Campaign.activePage().thegraphics.models, m => {
               if (m.attributes.layer == 'objects' && Math.abs(m.attributes.top - old.top) <= m.attributes.height / 2 && Math.abs(m.attributes.left - old.left) <= m.attributes.width / 2) {
                   //debugger;
                   maskedArr.push([m.id, m.view.graphic.selectable]);
                   m.view.graphic.selectable = false;
               }
           });
            _.delay((e, mask) => {window.myUpper.dispatchEvent(e); _.each(mask, m => Campaign.activePage().thegraphics._byId[m[0]].view.graphic.selectable = m[1]);}, 1000, new MouseEvent('mouseup', {bubbles: true, cancelable: true, composed: true, buttons: 1, clientX: 1, clientY: 1}), maskedArr);
            return !(window.myUpper.dispatchEvent(evt));
		}
	}

	//CSS override block
	if (_.contains(TMp.css, true) || TMp.toolbarButt || TMp.statusHQ) {
		var style = document.createElement('style');
		style.type = 'text/css';
		style.innerHTML = '';
		//Remove player names/ icons
		if (TMp.css.player)
			style.innerHTML += '.player.ui-droppable {display: none;} ';
		//Remove Zoom Slider
		if (TMp.css.zoom)
			style.innerHTML += '#zoomclick {display:none;} ';
		//Remove sidebar show/ hide button
		if (TMp.css.sidebar)
			style.innerHTML += '#sidebarcontrol {display: none;} ';
		//Increase quickmenu sizes
		if (TMp.css.quick)
			style.innerHTML += '.sheet-roll-cell a{padding:.5em !important;} ';
		//Permanently hide turn order
		if (TMp.css.turns)
			style.innerHTML += 'div.ui-dialog[style*="width: 160px;"] {display: none !important;} ';
        //Hides the connection error box
		if (TMp.css.error)
			style.innerHTML += '#connectionerror {display: none !important;} ';
		//Query window input box should size to the box size
		if (TMp.css.bigQuery)
			style.innerHTML += '.ui-dialog-content.ui-widget-content > p > strong + input {width: 100% !important; width: -moz-available !important; width: -webkit-fill-available !important; width: fill-available !important;} ';
		//Hide macroTokens by default
		if (TMp.css.macroTok)
			style.innerHTML += 'button[data-type="macro"]:not([data-blank="false"]) {display: none !important;} ';
		if (TMp.statusHQ)
			style.innerHTML += '#radial-menu .markermenu .markericon {background-image: url(https://files.catbox.moe/08tmts.svg) !important;} ';
		//Fills Toolbar buttons to their spaces
			style.innerHTML += '.submenu > ul > li > a {display: inline-block; width: 100%; height: 100%; color: grey; text-align: center;} .submenu > ul > li > a:hover {text-decoration: none;} .submenu > ul > li > a > .pictos {position: relative; left: -6rem; top: .1rem;} .submenu > ul > li > a > div {position: absolute; left: 3rem; top: .5rem;}';
		document.getElementsByTagName('head')[0].appendChild(style);
	}

	//Popouts and/ or dialogs create browser-behavior tabs instead of forced popups. 1 for just characters, 2 for everything.
	if (TMp.noPopouts) {
		unsafeWindow._open = unsafeWindow.open;
		if (TMp.noPopouts == 1)
			unsafeWindow.open = function(a,b,c) {if (a == "/editor/popout") return unsafeWindow._open(a, b); else return unsafeWindow._open(a,b,c);};
		else
			unsafeWindow.open = function(a,b,c) {return unsafeWindow._open(a, b);};
	}

	//Character sheets display custom attributes as name
	if (TMp.pfCustomAttr) {
		function cssInjection(charId) {
			var list = [1,2,3,10,11,12];
			var head = 'div.dialog.characterdialog[data-characterid=' + charId + '] {', foot = '';
			_.each(list, function(cK) {
				cK = 'customa' + cK;
				let val = {};
				if (!_.isUndefined(val = _.find(Campaign.characters._byId[charId].attribs.models, at => at.attributes.name == cK + '-name')))
					head += `--${cK}: "${val.attributes.current}"; `
				foot += `input[title="@{buff_${cK}-total}"] + span {visibility: hidden; top: -1.2rem;} input[title="@{buff_${cK}-total}"] + span::after {content: var(--${cK}, "${cK}"); visibility: visible; display: block;} `
			});
			return [head + '} ', foot];
		}
		function newShow(that) {
			var customOver;
			var modCss = cssInjection(that.model.attributes.id);
			if (_.isNull(document.getElementById('customOver'))) {
				customOver = document.createElement('style');
				customOver.type = 'text/css';
				customOver.id = 'customOver';
				customOver.innerHTML = modCss[1];
			}
			else {
				customOver = document.getElementById('customOver');
			}
			customOver.innerHTML += (modCss[0].indexOf('{}') > -1 ? '' : modCss[0]);
			if (that.childWindow) {
				_.delay(function() {customOver.innerHTML = modCss.join(' '); that.childWindow.document.getElementsByTagName('head')[0].appendChild(customOver)}, 4000);
			}
			else
				document.getElementsByTagName('head')[0].appendChild(customOver);
		};

		_.each(Campaign.characters.models, ch => {ch.view.showDialog2 = ch.view.showDialog; ch.view.showDialog = function(e, t) {this.showDialog2(e, t); newShow(this)}});
		_.each(Campaign.characters.models, ch => {ch.view.showPopout2 = ch.view.showPopout; ch.view.showPopout = function(e, t) {this.showPopout2(e, t); newShow(this)}});
		//Bookmarklet check then process active child windows
		if (typeof unsafeWindow == 'undefined')
			_.each(window.allChildWindows, win => {newShow(Campaign.characters._byId[win.document.getElementsByClassName('dialog characterdialog')[0].getAttribute('data-characterid')].view)});
	}

	//Tokens auto split their name to multiple lines
	if (TMp.splitTokName != "0") {
        var newFill = function(x, y, w, h) {
            if (this.font != 'bold 14px Arial' || this.fillStyle.replace(/ /g,'').indexOf('rgba(255,255,255,0.5') == -1)
                this.fillRect2(x, y, w, h);
            else if (this.fillText != this.newText)
                this.fillText = this.newText;
            //Note to self: Find where they're resetting this and stop it. A lot of wasted cycles for this.
        };
        var newText = function(t, x, y, m) {
            if (this.font != 'bold 14px Arial' || this.fillStyle != '#000000')
                this.fillText2(t, x, y, m);
            else if (this.canvas == window.myUpper)
                return;
            else {
                var g = 14, r = y - 22, n = m, max = parseInt(TMp.splitTokName), forced, tmpFix = 3;
                var texes = t.toString().split(' ');
                for (var k = 0; k < texes.length; k++) {
                    while ((this.measureText(texes[k] + ' ' + texes[k+1]).width < r*2 || k >= max - 1) && k+1 < texes.length ) {
                        texes[k] += ' ' + texes[k+1];
                        texes.splice(k+1, 1);
                    }
                    if (texes[k].indexOf('\\n') > -1) {
                        forced = texes[k].split('\\n');
                        texes[k] = forced.shift();
                        texes.splice(k+1, 0, ...forced);
                    }
                    texes[k] = texes[k].replace(/_/g, ' ');
                    n = this.measureText(texes[k]).width;
                    this.fillStyle = 'rgba(255, 255, 255, 0.50)';
                    this.fillRect2(-1 * Math.floor((n + 6) / 2), r + 8 + (g+6)*k, n + 6, g + 6);
                    this.fillStyle = 'rgb(0,0,0)';
                    this.fillText2(texes[k], x, y + tmpFix + (g+6)*k, n);
                }
            }
		};
        _.each([window.myMain, window.myUpper, window.myLower], function(c) {
            let can = c.getContext('2d');
            can.fillRect2 = can.fillRect;
            can.fillRect = newFill;
            can.newFill = newFill;
            can.fillText2 = can.fillText;
            can.fillText = newText;
            can.newText = newText;
        });
	}

	if (false && (TMp.scaleToks || TMp.statusHQ)) {
		var newRect = function(x, y, w, h) {
			var rgba = /rgba\( ?(\d*) ?, ?(\d*) ?, ?(\d*) ?, ?((?:\d|\.)*) ?\)/.exec(this.fillStyle), fillStr, offset = 24;
			if (rgba && parseFloat(rgba[4]).toFixed(2) == "0.75" && (Campaign.tokendisplay.bar3_rgb + '' == (fillStr = rgba[1] + ',' + rgba[2] + ',' + rgba[3]) || (Campaign.tokendisplay.bar2_rgb + '' == fillStr && _.isNumber(offset -= 12)) || (Campaign.tokendisplay.bar1_rgb + '' == fillStr && _.isNumber(offset -= 24)))) {
				var scale = (x - 3) * -1 / 35;
				if (scale != 1) {
					h = scale * 8;
					y = (y - offset + 20) + ((offset - 20) * scale);
					x = (x - 3) + (3 * scale);
					this.lineWidth = scale;
					w = Math.floor((70 * scale - 6 * scale) * (w / (70 * scale - 6)));
				}
			}
			this.rect2(x, y, w, h);
		};
		var newImage = function() {
			if (arguments[7] && arguments[7] == 21 && (arguments[0].src == 'https://files.catbox.moe/08tmts.svg' || arguments[0].src == 'https://app.roll20.net/images/statussheet.png' || arguments[0].src == 'https://app.roll20.net/images/statussheet_small.png')) {
				if (TMp.statusHQ) {
					if (arguments[0].src != 'https://files.catbox.moe/08tmts.svg')
						arguments[0].src = 'https://files.catbox.moe/08tmts.svg';
					arguments[3] = 24;
					arguments[4] = 24;
				}
				if (false) {
					var scaleO, scaleR, scaleH, scaleD, it, scale, k, j, pairs;
					switch(Campaign.get('markers_position')) {
						case 'bottom':
							scaleO = arguments[5];
							scaleR = arguments[6] + 19;
							it = (scaleR - scaleO);
							scale = scaleR / 35;
							for (k = 0; k <= it / 16; k++) for (j = 0; j <= it / 22; j++) if (k * 16 + j * 22 == it) pairs = [k,j];
							scaleD = scaleR - 10 * scale;
							scaleH = scaleO + 16 * pairs[0] * scale + 22 * pairs[1] * scale;
							break;
						case 'left':
							scaleO = -(arguments[5]);
							scaleR = -(arguments[6] + 19);
							it = (scaleO - scaleR);
							scale = scaleO / 35;
							for (k = 0; k <= it / 16; k++) for (j = 0; j <= it / 22; j++) if (k * 16 + j * 22 == it) pairs = [k,j];
							scaleD = -scaleR - 10 * scale + 16 * pairs * scale[0] + 22 * pairs[1] * scale;
							scaleH = -scaleO + 16 * pairs[0] * scale + 22 * pairs[1] * scale;
							break;
						case 'right':
							scaleO = arguments[5] + 18;
							scaleR = -(arguments[6] + 19);
							it = (scaleO - scaleR);
							scale = scaleO / 35;
							for (k = 0; k <= it / 16; k++) for (j = 0; j <= it / 22; j++) if (k * 16 + j * 22 == it) pairs = [k,j];
							scaleD = -scaleR - 10 * scale + 16 * pairs[0] * scale + 22 * pairs[1] * scale;
							scaleH = scaleO - 18 * scale;
							break;
						default:
							debugger;
							scaleO = arguments[5];
							scaleR = -(arguments[6] - 1);
							it = (scaleR - scaleO);
							scale = scaleR / 35;
							for (k = 0; k <= it / 16; k++) for (j = 0; j <= it / 22; j++) if (k * 16 + j * 22 == it) pairs = [k,j];
							scaleD = 10 * scale - scaleR;
							scaleH = scaleO + 16 * pairs[0] + 22 * pairs[1] - 16 * pairs[0] * scale - 22 * pairs[1] * scale;
					}
					arguments[5] = scaleH;
					arguments[6] = scaleD - 9 * scale;
					arguments[7] = 21 * scale;
					arguments[8] = 21 * scale;
				}
			}
			this.drawImage2(...arguments);
		}
		_.each([window.myMain, window.myUpper, window.myLower], function(c) {
			let can = c.getContext('2d');
			if (TMp.scaleToks) {
				can.rect2 = can.rect;
				can.rect = newRect;
			}
			can.drawImage2 = can.drawImage;
			can.drawImage = newImage;
		});

	}

	//Makes mousewheel scroll page listing at top and adds custom speed to it
	if (TMp.scrollPages != '0' && is_gm) {
		var scrollHorizontally = function(e) {
			e = window.event || e;
			document.getElementById('page-toolbar').children[1].scrollLeft -= (Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))) * (parseFloat(TMp.scrollPages) * 40));
			e.preventDefault();
		}
        document.getElementById('page-toolbar').children[1].addEventListener("wheel", scrollHorizontally, false);
	}

	//Disables anti-aliasing on canvas if you need the performance
    if (TMp.perfMode) {
		_.each([window.myMain, window.myUpper, window.myLower], function(c) {
			c.getContext('2d').imageSmoothingEnabled = false;
		});
    }
}

})();