paper2hack

Modding utility/menu for paper.io

当前为 2024-01-07 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         paper2hack
// @description  Modding utility/menu for paper.io
// @version      0.1.21
// @author       its-pablo
// @match        https://paper-io.com
// @match        https://paper-io.com/teams/
// @match        https://paper-io.com/battleroyale/
// @match        https://paperanimals.io
// @match        https://amogus.io
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/tweakpane.min.js
// @license      GPL-3.0-only
// @icon         https://paper-io.com/favicon.ico
// @grant        none
// @namespace https://greasyfork.org/users/1204224
// ==/UserScript==
adblock = () => false //this detects if adblock is on, we make it always return false so that the impostor skin loads
window.addEventListener('load', function () {
    "use strict";
    const VERSION = "beta 0.1.21"
    let newApi
    let finish = false; // Start booting
    // New api loads too slow!!
    // Maybe plan in only supporting the old api? just an opinion
    (async() => {
        console.log("[paper2hack] Waiting for api");
        while(!window.hasOwnProperty("paperio2api")) // paperio2api was first defined!
            if (window.hasOwnProperty("paper2")) {newApi = false;return;} // paper2 was first defined!
            await new Promise(resolve => setTimeout(resolve, 1000)); // Wait!!
        console.log("[paper2hack] api defined!");
    })();
    window.api = {
        /**
         * Gets the configuration
         * @returns the configuration
         */
        config: function () {
            if (newApi) {
                return paperio2api.config;
            } else {
                return paper2.currentConfig;
            }
        },
        /**
         * Gets the game
         * @returns the game
         */
        game: function () {
            if (newApi) {
                return paperio2api.game
            } else {
                return paper2.game
            }
        },
        /**
         * Gets the player
         * @returns the player
         */
        player: function () {
            return this.game().player;   
        },
        /**
         * Search an unit by the name
         * If no unit is found, it will return `null`
         * If an unit is found, it will return that unit
         * If multiple names are used
         * The first one will be returned
         * @param {*} name The name to be searched for
         * @returns The unit if found, null if not
         */
        searchForUnit: function (name) {
            for (let i = 0; i < this.game().units.length; i++) {
                if (this.game().units[i].name.toLowerCase() == name.toLowerCase()) {return this.game().units[i];}
            }
            return null;
        },
        /**
         * Create a message, that will appear above the specified unit.
         * @param {*} unit The unit 
         * @param {*} text The text
         * @param {*} hexColor The color, in hex, for example : `#FF00FF`
         */
        addMessage: function (unit, text, hexColor) {
            unit.addLabel({
                "unit": undefined, // Assign to the unit
                "text": text,
                "color": hexColor
            })
        },
        /**
         * Kills the unit, by the other unit
         * @param {*} unitToKill The unit that will be killed
         * @param {*} unitToGetKill The unit that'll get the kill stat for
         */
        kill: function (unitToKill, unitToGetKill) {
            if (unitToGetKill == undefined) {unitToGetKill = this.player()}
            this.game().kill(unitToKill, unitToGetKill)
        },
        /**
         * Returns the resource located at the resource array (`a0_0x344c`)
         * This is only intended for reverse engineering
         * @param {number} res the resource, starting at `196`
         * @returns the resource, as a `string` can also be undefined
         */
        getResource: function (res) {
            return a0_0x2cc6(res);
        }
    }
    let ETC = {
        "newMessage":function (message) {
            let newMessage = document.createElement("p");
            document.querySelectorAll("#message")[1].appendChild(newMessage);
            newMessage.innerText = message;
            // Return the new message, if you need it
            return newMessage;
        },
        "reset": function () { alert("Cannot be done with tweakpane!\nTry clearing site data.") },
        "zoomScroll": false,
        "debugging": false,
        "map": false,
        "despawnK": false,
        "speed": api.config().unitSpeed,
        "skin": "",
        "skinUnlock": () => {
            try {
                shop.btnsData.forEach(item => {
                    if (item.codeName) {
                        unlockSkin(item.codeName)
                    }
                })
                console.log("[paper2hack] skins unlocked!")
            } catch (e) {
                console.log("[paper2hack] Error unlocking skins!", e)
            }
        },
        "_skins": [],
        "pause": function () {
            if (!newApi) {
                // Toggle between paused and unpaused
                // This is not possible in the new api (I believe)
                api.game().paused = !paper2.game.paused;
                if (api.game().paused) {
                    console.log("[paper2hack] Paused");
                } else {
                    console.log("[paper2hack] Unpaused");
                }
                // Return so the unit speed doesn't change
                return;
            }
            if (api.config().unitSpeed !== 0) {
                api.config().unitSpeed = 0
                console.log("[paper2hack] Paused")
            } else {
                api.config().unitSpeed = 90
                console.log("[paper2hack] Unpaused")
            }
            return;
        },
        "despawnOthers": function () {
            // Array where we store the units to kill
            let unitkills = [];
            for (let i = 0; i < api.game().units.length; i++) {
                if (api.game().units[i].isPlayer) {continue;} // Ignore if we get the player unit
                unitkills.push(api.game().units[i]);
            }
            // Iterate through the units that we're going to kill
            unitkills.forEach((obj) => {
                api.kill(obj, obj);
            })
        },
        "help": function () {
            alert(`
            paper2hack ${VERSION} written by stretch07 and contributors.\n\n
            https://github.com/stretch07/paper2hack \n
            Issues? https://github.com/stretch07/paper2hack/issues

            If you encounter any issues with paper2hack, refresh the page, hit the 'Reset' button, or uninstall/reinstall the mod. As a last resort, try clearing site data.
        `)
        },
        "keysList": function () {
            alert(`Keyboard shortcuts:\n- Space: Pause/play\n- K: Despawn all other players`)
        },
        "openGithub": function () {
            window.open("https://github.com/stretch07/paper2hack", '_blank').focus();
        }
    }
    function scrollE(e) {
        if (e.deltaY > 0) {
            if (api.config().maxScale > 0.45) {
                api.config().maxScale -= 0.2
            }
        } else if (e.deltaY < 0) {
            if (api.config().maxScale < 4.5) {
                api.config().maxScale += 0.2
            }
        }
    }

    let pane = new Tweakpane.Pane({ title: "paper2hack"})
    let mods = pane.addFolder({ title: "Mods" })
    mods.addInput(ETC, "speed", { min: 5, max: 500, count: 5 }).on("change", ev => {
        api.config().unitSpeed = ev.value;
    })
    mods.addInput(ETC, "skin", {
        label: "Skin",
        // Yeah unreadable i know
        // Got this with a simple js trick ;)
        options: {"No skin":"skin_00","Orange":"skin_20","Burger":"skin_19","Matrix":"skin_49","Green Goblin":"skin_48","Squid Game":"skin_47","Venom":"skin_46","Money Heist":"skin_45","Doge":"skin_44","Baby Yoda":"skin_43","Chess Queen":"skin_42","Impostor":"skin_41","Cyber Punk":"skin_40","Stay safe":"skin_39","Sanitizer":"skin_38","Doctor":"skin_37","COVID-19":"skin_36","Geralt":"skin_35","Batman":"skin_30","Joker":"skin_29","Pennywise":"skin_28","Reaper":"skin_27","Captain America":"skin_26","Thanos":"skin_25","Cupid":"skin_24","Snowman":"skin_23","Present":"skin_22","Christmas":"skin_21","Ladybug":"skin_18","Tank":"skin_17","Duck":"skin_16","Cake":"skin_15","Cash":"skin_14","Sushi":"skin_13","Bat":"skin_12","Heart":"skin_11","Rainbow":"skin_10","Nyan cat":"skin_01","Watermelon":"skin_02","Ghost":"skin_03","Pizza":"skin_04","Minion":"skin_05","Freddy":"skin_06","Spiderman":"skin_07","Teletubby":"skin_08","Unicorn":"skin_09","Eye":"eye", "Frankenstein":"Frank", "Santa":"santa", "Rudolph":"rudolf"}
    }).on("change", ev => {
        if (newApi && finish) {window.alert("Cannot do this in this version!");}
        // Oh boy! No player No skin!
        if (!api.game() || !api.player()) {return;}
        let id = ev.value;
        // The skin manager uses the codeName to get the skin itself
        let codeName;
	let secret = true;
        shop.btnsData.forEach(s => {
            if (s.useId == id) {
                codeName = s.codeName;
                // There is no skins with the same code name, so we can return!
                return;
            }
        })
        // Edge cases since these skins don't have use ids
        if (id == "eye")    {codeName = id;}
	else if (id == "Frank")  {codeName = id;}
	else if (id == "santa")  {codeName = id;}
	else if (id == "rudolf") {codeName = id;}
	else { secret = false; }
	// The skin manager treats the default skin as undefined
        // if we don't do this it will create an error and will not change the skin
        if (codeName == "default") {codeName = undefined;}
        // Get the skin from the code name
        let skin = api.game().skinManager.getPlayerSkin(codeName);
        // And set it to the player!
        api.player().setSkin(skin);
	if (secret) {return;}
        shop.chosenSkin = id;
        Cookies.set('skin', id);
    })
    mods.addInput(ETC, "debugging", { label: "Debug" }).on("change", ev => {
        api.game().debug = ev.value
        api.game().debugGraph = ev.value
    })
    mods.addInput(ETC, "map", { label: "Map"}).on("change", ev => {
        api.game().debugView = ev.value;
    })
    mods.addButton({ title: "Pause/Play" }).on("click", ETC.pause)
    if (!newApi) {
        mods.addButton({ title: "Unlock skins", }).on("click", ETC.skinUnlock)
    }
    mods.addButton({ title: "I give up" }).on("click",() => {
        api.kill(api.player());
    })
    mods.addButton({ title: "Despawn others" }).on("click", ETC.despawnOthers)
    mods.addInput(ETC, "despawnK", { label: "Despawn Others on K" })

    // keyboard shortcuts
    // pause: Spacebar
    // kill everyone: K
    document.addEventListener("keydown", ev => {
	if (!api.player()) {return;} //If not in game, return
        if (event.key === 'k') {
            if (!ETC.despawnK) return;
            ETC.despawnOthers()
        }
        if (event.key === " ") {
            ETC.pause()
        }
    })
    mods.addInput(ETC, "zoomScroll", { label: "Scroll to Zoom" }).on("change", ev => {
        if (ev.value === true) {
            window.addEventListener("wheel", scrollE)
        } else {
            window.removeEventListener("wheel", scrollE)
        }
    })
    mods.addButton({ title: "Reset" }).on('click', ETC.reset);
    let about = pane.addFolder({ title: "About", expanded: false });
    about.addButton({ title: "Help" }).on("click", ETC.help);
    about.addButton({ title: "Keyboard Shortcuts" }).on("click", ETC.keysList);
    about.addButton({ title: "GitHub" }).on("click", ETC.openGithub);
    /*Last things*/
    if (!localStorage.getItem('paper2hack')) {
        this.localStorage.setItem('paper2hack', JSON.stringify({}))
    }
    pane.importPreset(JSON.parse(localStorage.getItem("paper2hack")))
    pane.on("change", e => {
        localStorage.setItem("paper2hack", JSON.stringify(pane.exportPreset()))
    })
    document.querySelector(".tp-dfwv").style.zIndex = "50"; //Make sure the menu shows up over some GUI
    finish = true; // Ended booting
    let messages = this.document.querySelectorAll("#message p");
    messages.forEach((msg)=>{msg.remove();}) //Remove all messages
    ETC.newMessage(`paper2hack ${VERSION}`);
    let checkinstallmessage = ETC.newMessage('');
    checkinstallmessage.innerHTML = `<a style="color: white" href="https://github.com/stretch07/paper2hack">check/install update</a>`;
    ETC.newMessage(`have fun hacking!`);
}, false);