Greasy Fork

MouseHunt HUD Backgroundifier

Change the background of (almost) everything on mousehuntgame.com (But why? What possessed you to seek this out?)

目前为 2021-10-25 提交的版本。查看 最新版本

// ==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
// ==/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();