Ahab / ctzoom

// ==UserScript==
// @name         ctzoom
// @version      0.1
// @author       Ahab [1735214]
// @include      *torn.com/christmas_town*
// @run-at       document-start
// @grant        none
// @updateURL    https://openuserjs.org/meta/Ahab/ctzoom.meta.js
// @downloadURL  https://openuserjs.org/install/Ahab/ctzoom.user.js
// @license      MIT
// ==/UserScript==

const code = `
window.moveSpeed = parseFloat(localStorage.getItem('ctSpeed')) || parseFloat(localStorage.getItem('ctOrgMovement'));

window.changeSpeed = function(newSpeed) {
    localStorage.setItem('ctSpeed', newSpeed);
    window.moveSpeed = newSpeed;
    location.reload();
};
const originalFetch = window.fetch;
window.fetch = async function(...args) {
    const response = await originalFetch(...args);
    if ((args[0] && args[0].includes && args[0].includes('init')) || (args[0] && args[0].includes && args[0].includes('move'))) {
        return response.clone().text().then(text => {
            try {
                const newResponse = JSON.parse(text);
                if (!newResponse.error) {
                    $(".text-wrapper").css("visibility", "visible");
                    localStorage.setItem('ctOrgMovement', newResponse.mapData.movement.modifier);
                    newResponse.mapData.movement.modifier = window.moveSpeed;
                    return new Response(JSON.stringify(newResponse), {
                        status: response.status,
                        statusText: response.statusText,
                        headers: response.headers
                    });
                } else {
                    let errorMsg = $(".text-wrapper .paragraph").first();
                    $(".text-wrapper").css("visibility", "hidden");
                    errorMsg.text("You can not move so often");
                    errorMsg.css("visibility", "visible");
                    return response;
                }
            } catch (e) {
                return response;
            }
        });
    } else {
        return response;
    }
};
`

var observer = new MutationObserver(function(mutations, obs) {
    var target = document.querySelector(".ct-wrap");
    if (target) {
        target.insertAdjacentHTML('beforeBegin', '<input id="ctSetspeed" type="number" placeholder="'+parseFloat(localStorage.getItem("ctOrgMovement"))+'" value="'+parseFloat(localStorage.getItem("ctSpeed"))+'" style="margin: 0 0 5px 15px; width: 7ch" max="5" step="0.001"></input><button id="saveSpeed" style="margin: 0 0 5px 5px; cursor: pointer; border-radius: 4px; border: 1px solid #444; background: #333; color: #fff; font-weight: bold;">Save</button>')
        obs.disconnect();
    }
})
observer.observe(document.documentElement, {
    childList: true,
    subtree: true
});

document.addEventListener('input', function(e) {
    if (e.target.id === 'ctSetspeed') {
        const max = 5.0;
        const min = 0.01;
        let val = parseFloat(e.target.value);
        if (val > max) {
            e.target.value = max;
        } else if (val < min) {
            e.target.value = min;
        }
    }
});

document.addEventListener('click', function(e) {
    if (e.target.id === 'saveSpeed') {
        const input = document.getElementById('ctSetspeed');
        let newSpeed = parseFloat(input.value);
        if (newSpeed > 1.298) {
            alert(`Movement modifier of ${newSpeed} will trigger rate limit. "Safe" maximum is 1.298`);
        }
        if (isNaN(newSpeed)) {
            newSpeed = parseFloat(localStorage.getItem("ctOrgMovement"));
        }
        e.target.innerText = "Saving...";
        window.changeSpeed(newSpeed);
    }
});

const script = document.createElement('script');
script.textContent = code;
document.documentElement.appendChild(script);
script.remove();