// ==UserScript== // @name MouseHunt HUD Backgroundifier // @author LethalVision // @version 0.3 // @description Change the background of (almost) everything on mousehuntgame.com (But why? What possessed you to seek this out?) // @include http://mousehuntgame.com/* // @include https://mousehuntgame.com/* // @include http://www.mousehuntgame.com/* // @include https://www.mousehuntgame.com/* // @grant none // @namespace https://greasyfork.org/en/users/683695-lethalvision // @downloadURL none // ==/UserScript== const TAG = "HUD_BCKGRNDFR" var preferences = { hudUrl: "", backUrl: "", leftUrl: "", rightUrl: "", statOpacity: 1, hudOpacity: 1, statShadow: false }; function init() { var loadedPref = window.localStorage.getItem(TAG); if (loadedPref){ try{ loadedPref = JSON.parse(loadedPref); preferences.hudUrl = loadedPref.hudUrl; preferences.backUrl = loadedPref.backUrl; preferences.leftUrl = loadedPref.leftUrl; preferences.rightUrl = loadedPref.rightUrl; preferences.statOpacity = loadedPref.statOpacity; preferences.hudOpacity = loadedPref.hudOpacity; preferences.statShadow = loadedPref.statShadow; console.log("Backgroundifier preferences loaded"); } catch (err) { console.log('Preference parse error: ' + err); } } addListener(); addButton(); setTimeout(function(){ updateAll(); }, 500); } // stuff preferences into the localStorage function savePreferences() { var jsonString = JSON.stringify(preferences); window.localStorage.setItem(TAG, jsonString); } function addListener() { const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function() { this.addEventListener("load", function() { if ( this.responseURL === "https://www.mousehuntgame.com/managers/ajax/pages/page.php" || this.responseURL === "https://www.mousehuntgame.com/managers/ajax/pages/preferences.php") { addButton(); updateAll(); } }); originalOpen.apply(this, arguments); }; } // === SMOKE AND MIRRORS HERE === // add button to bring up the settings function addButton() { if (document.getElementById("hudBtn")) { // if button already exists return; } const div = document.createElement("div"); div.className = "hudBtn-container"; div.style.position = "absolute"; div.style.bottom = "5px"; div.style.right = "7px" const hudBtn = document.createElement("button"); hudBtn.id = "hudBtn"; hudBtn.textContent = "!"; hudBtn.style.width = "20px" hudBtn.style.height = "20px" hudBtn.style.opacity = "0.5" hudBtn.onclick = function(){renderBox();} div.appendChild(hudBtn); const hudContainer = document.getElementsByClassName("headsUpDisplayView"); if (!hudContainer || hudContainer.length != 1) { // hudContainer can't be found or the length is unexpected return; } hudContainer[0].insertAdjacentElement("afterend",div); } // render the almighty Tsitu's Floating Box function renderBox(){return new Promise((resolve, reject) => { // clear all open boxes document .querySelectorAll("#hud-options") .forEach(el=> el.remove()) const div = document.createElement("div"); div.id = "hud-options"; div.style.backgroundColor = "#F5F5F5"; div.style.position = "fixed"; div.style.zIndex = "9999"; div.style.left = "35vw"; div.style.top = "55vh"; div.style.border = "solid 3px #696969"; div.style.borderRadius = "20px"; div.style.padding = "10px"; div.style.textAlign = "left"; div.style.minWidth = "207px"; const buttonDiv = document.createElement("div"); buttonDiv.style.float= "right"; buttonDiv.style.textAlign = "right"; const closeButton = document.createElement("button", { id: "close-button" }); closeButton.textContent = "x"; closeButton.onclick = function () { document.body.removeChild(div); }; closeButton.style.marginRight = "5px" const titleDiv = document.createElement("div") titleDiv.id = "hud-optionsheader"; titleDiv.textContent = "HUD Backgroundifier"; titleDiv.style.width = "75%"; titleDiv.style.float= "left"; titleDiv.style.textAlign = "left"; titleDiv.style.fontSize = "12px" titleDiv.style.fontWeight = "bold"; titleDiv.style.marginLeft = "5px"; const urlDiv = document.createElement("div") urlDiv.className = "clear" urlDiv.textContent = "Image URLs"; urlDiv.style.fontWeight = "bold"; urlDiv.style.textAlign = "left"; urlDiv.style.marginTop = "5px"; urlDiv.style.marginLeft = "5px"; var urlTable = document.createElement('table'); urlTable.style.textAlign = "left"; urlTable.style.borderSpacing = "1em 0"; urlTable.style.paddingTop = "5px" var topRow = urlTable.insertRow(); topRow.style.height = "24px"; var topDesc = topRow.insertCell(0); topDesc.appendChild(document.createTextNode("HUD background:")); // set width once and the rest should follow topDesc.style.width = "35%" var urlInput = document.createElement('input'); urlInput.id = "urlInput"; urlInput.style.width = "95%"; urlInput.value = preferences.hudUrl; urlInput.onchange = function(){ checkAndLoadImage("hud", urlInput.value); } topRow.insertCell(1).appendChild(urlInput); var backRow = urlTable.insertRow(); backRow.style.height = "24px"; var backDesc = backRow.insertCell(0); backDesc.appendChild(document.createTextNode("Camp background:")); var backInput = document.createElement('input'); backInput.id = "backInput"; backInput.style.width = "95%"; backInput.value = preferences.backUrl; backInput.onchange = function(){ checkAndLoadImage("back", backInput.value); } backRow.insertCell(1).appendChild(backInput); var leftRow = urlTable.insertRow(); leftRow.style.height = "24px"; var leftDesc = leftRow.insertCell(0); leftDesc.appendChild(document.createTextNode("Left screen background:")); var leftInput = document.createElement('input'); leftInput.id = "leftInput"; leftInput.style.width = "95%"; leftInput.value = preferences.leftUrl; leftInput.onchange = function(){ checkAndLoadImage("left", leftInput.value); } leftRow.insertCell(1).appendChild(leftInput); var rightRow = urlTable.insertRow(); rightRow.style.height = "24px"; var rightDesc = rightRow.insertCell(0); rightDesc.appendChild(document.createTextNode("Right screen background:")); var rightInput = document.createElement('input'); rightInput.id = "rightInput"; rightInput.style.width = "95%"; rightInput.value = preferences.rightUrl; rightInput.onchange = function(){ checkAndLoadImage("right", rightInput.value); } rightRow.insertCell(1).appendChild(rightInput); const opDiv = document.createElement("div") opDiv.textContent = "Transparency Settings"; opDiv.style.fontWeight = "bold"; opDiv.style.textAlign = "left"; opDiv.style.marginTop = "5px"; opDiv.style.marginLeft = "5px"; var opTable = document.createElement('table'); opTable.style.textAlign = "left"; opTable.style.borderSpacing = "1em 0"; opTable.style.paddingTop = "5px" var statOpRow = opTable.insertRow(); statOpRow.style.height = "24px"; var statDesc = statOpRow.insertCell(0); statDesc.appendChild(document.createTextNode("Hunter Stats:")); // set width once and the rest should follow statDesc.style.width = "20%" var statSlider = document.createElement('input'); statSlider.id = "statSlider"; statSlider.type = "range" statSlider.style.width = "95%"; statSlider.style.verticalAlign = "middle"; // this is where I should use some fancy function to handle the conversion for each slider instead of just copy/pasting it twice // but it's 3AM and I'm in physical pain statSlider.value = preferences.statOpacity*100; statSlider.onchange = function(){ preferences.statOpacity = statSlider.value/100.0; updateOpacity() } statOpRow.insertCell(1).appendChild(statSlider); var hudOpRow = opTable.insertRow(); hudOpRow.style.height = "24px"; var hudDesc = hudOpRow.insertCell(0); hudDesc.appendChild(document.createTextNode("Location HUD:")); // set width once and the rest should follow hudDesc.style.width = "20%" var hudSlider = document.createElement('input'); hudSlider.id = "hudSlider"; hudSlider.type = "range" hudSlider.style.width = "95%"; hudSlider.style.verticalAlign = "middle"; hudSlider.value = preferences.hudOpacity*100; hudSlider.onchange = function(){ preferences.hudOpacity = hudSlider.value/100.0; updateOpacity() } hudOpRow.insertCell(1).appendChild(hudSlider); const miscDiv = document.createElement("div") miscDiv.textContent = "Misc Settings"; miscDiv.style.fontWeight = "bold"; miscDiv.style.textAlign = "Left"; miscDiv.style.marginTop = "5px"; miscDiv.style.marginLeft = "5px"; var shadowLabel = document.createElement("label"); shadowLabel.textContent = "Toggle shadow for hunter stats"; shadowLabel.style.textAlign = "left"; shadowLabel.style.marginLeft = "10px"; var shadowCheckbox = document.createElement('input'); shadowCheckbox.id = "shadowCheckbox"; shadowCheckbox.style.height = "24px"; shadowCheckbox.style.verticalAlign = "middle"; shadowCheckbox.type = "checkbox" shadowCheckbox.checked = preferences.statShadow; shadowCheckbox.onchange = function(){ preferences.statShadow = shadowCheckbox.checked; updateShadow(); } shadowLabel.appendChild(shadowCheckbox); buttonDiv.appendChild(closeButton); div.appendChild(titleDiv); div.appendChild(buttonDiv) div.appendChild(urlDiv); div.appendChild(urlTable); div.appendChild(opDiv); div.appendChild(opTable); div.appendChild(miscDiv); div.appendChild(shadowLabel); document.body.appendChild(div); // why does this exist dragElement(div); resolve(); })} // === Tsitu's drag magic functions === // no seriously this should be a library or something function dragElement(elmnt) { var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; if (document.getElementById(elmnt.id + "header")) { // if present, the header is where you move the DIV from: document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown; } else { // otherwise, move the DIV from anywhere inside the DIV: elmnt.onmousedown = dragMouseDown; } function dragMouseDown(e) { e = e || window.event; e.preventDefault(); // get the mouse cursor position at startup: pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; // call a function whenever the cursor moves: document.onmousemove = elementDrag; } function elementDrag(e) { e = e || window.event; e.preventDefault(); // calculate the new cursor position: pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; // set the element's new position: elmnt.style.top = (elmnt.offsetTop - pos2) + "px"; elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; } function closeDragElement() { // stop moving when mouse button is released: document.onmouseup = null; document.onmousemove = null; } } // === Main logic === async function checkAndLoadImage(portion, url) { var imgUrl; if (url){ // check if url is a valid image let imgPromise = new Promise(function(resolve) { try{ var img = new Image(); img.onload = function(){ resolve(this.width != 0 && this.height != 0) }; img.src = url; } catch (error) { console.error(error.stack); resolve(false); } }); var validImage = await imgPromise; imgUrl = validImage ? url : ""; } else { imgUrl = ""; } switch(portion) { case "hud": preferences.hudUrl = imgUrl; break; case "back": preferences.backUrl = imgUrl; break; case "left": preferences.leftUrl = imgUrl; break; case "right": preferences.rightUrl = imgUrl; break; default: console.log("checkAndLoadImage(): invalid portion"); } savePreferences(); updateImg(portion); } // Update HUD background function updateImg(portion) { var target; var bgString; var url; // set the variables // YEAH HARDCODING switch(portion) { case "hud": target = document.getElementsByClassName("mousehuntHud-marbleDrawer"); bgString = `url(https://www.mousehuntgame.com/images/ui/hud/mousehuntHudPedestal.gif?asset_cache_version=2) -37px 0 no-repeat, url(https://www.mousehuntgame.com/images/ui/hud/mousehuntHudPedestal.gif?asset_cache_version=2) 723px 0 no-repeat, url(${preferences.hudUrl}) bottom center / 100%`; url = preferences.hudUrl; break; case "back": target = document.getElementById("mousehuntContainer"); bgString = `url(${preferences.backUrl}) repeat-y center / 100%`; // special handling for journal back - it should only be applied on the camp page. if (window.location.href.includes("camp.php")) { url = preferences.backUrl; } else { url = ""; } break; case "left": target = document.getElementsByClassName("pageFrameView-column left"); bgString = `url(${preferences.leftUrl})`; url = preferences.leftUrl; break; case "right": target = document.getElementsByClassName("pageFrameView-column right"); bgString = `url(${preferences.rightUrl})`; url = preferences.rightUrl; break; default: updateImg("hud"); updateImg("back"); updateImg("left"); updateImg("right"); return; } // actually replace stuff replaceBackground(target, url, bgString); } function replaceBackground(element, url, bgString) { // streamline getElementByClass/getElementById var replaceElem; if (element.length == 1) { replaceElem = element[0]; } else{ replaceElem = element; } // only update if a url is specified if (url){ replaceElem.style.background = bgString; } else { // this should reset the background replaceElem.style.background = ""; } } // update transparency function updateOpacity() { savePreferences(); const statsElem = document.getElementsByClassName("headsUpDisplayView-stats")[0]; const hudElem = document.getElementsByClassName("hudLocationContent")[0]; statsElem.style.opacity = preferences.statOpacity; hudElem.style.opacity = preferences.hudOpacity; } // update stat shading function updateShadow() { savePreferences(); const statsElem = document.getElementsByClassName("headsUpDisplayView-stats")[0]; if (preferences.statShadow) { // set background to black with 0.3 opacity statsElem.style.backgroundColor = "rgba(0, 0, 0, 0.30)"; } else { statsElem.style.backgroundColor = "transparent"; } } function updateAll() { updateImg(); updateOpacity(); updateShadow(); } // start the script init();