Greasy Fork is available in English.

ParkourUtilsTemp

Parkour Utilities

// ==UserScript==
// @name         ParkourUtilsTemp
// @namespace    http://tampermonkey.net/
// @version      1.2.1
// @description  Parkour Utilities
// @author       Clarifi
// @license      MIT
// @match        https://bonk.io/gameframe-release.html
// @run-at       document-end
// @grant        none
// ==/UserScript==

window.pkrUtils = {}; // Namespace for encapsulating the UI functions and variables

// Use 'strict' mode for safer code by managing silent errors
'use strict';

pkrUtils.windowConfigs = {
    windowName: "pkrUtils",
    windowId: "pkr_utils_window",
    modVersion: "1.2.1",
    bonkLIBVersion: "1.1.3",
    bonkVersion: "49",
};

pkrUtils.currentData = {};

pkrUtils.positionElement = 0;
pkrUtils.velocityElement = 0;
pkrUtils.specialElement = 0;
pkrUtils.vtolAngle = 0;
pkrUtils.vtolAnglev = 0;
pkrUtils.arrowCharge = 0;
pkrUtils.arrowAngle = 0;

pkrUtils.scale = 1;

pkrUtils.screenWidth = 1;
pkrUtils.gScale = 1;
pkrUtils.goResize = false;

pkrUtils.gCtx = 0;
pkrUtils.markerIndex = 0;
pkrUtils.markers = new Map();

pkrUtils.hasPrecision = false;

pkrUtils.currentMode = -1;

pkrUtils.currentPlayerID = 0;

// Event listener function to change the player selected in the player selector
pkrUtils.select_player = () => {
    let player_selector = document.getElementById("pkrutils_player_selector");
    let player_id = player_selector.options[player_selector.selectedIndex].value;
    pkrUtils.currentPlayerID = player_id;
    //console.log("current Player ID: " + player_id);
};

// Create a new option in the player selector
pkrUtils.create_option = (userID) => {
    //console.log("userID:" + userID);
    let playerName = bonkAPI.getPlayerNameByID(userID);
    let player_selector = document.getElementById("pkrutils_player_selector");
    let newOption = document.createElement("option");
    newOption.innerText = playerName;
    newOption.value = userID;
    newOption.id = "selector_option_" + userID;
    player_selector.appendChild(newOption);
    //console.log("selector_option_" + userID + " added to player_selector");
};

// Remove an option from the player selector
pkrUtils.remove_option = (userID) => {
    let player_selector = document.getElementById("pkrutils_player_selector");
    let option = document.getElementById("selector_option_" + userID);
    player_selector.removeChild(option);
};

// Reset the player selector to the default state
pkrUtils.reset_selector = () => {
    // Remove all options except the default one
    let player_selector = document.getElementById("pkrutils_player_selector");
    Array.from(player_selector.options).forEach((option) => {
        if (option.id !== "pkrutils_selector_option_user") {
            player_selector.removeChild(option);
        }
        // Reset the current player ID
        pkrUtils.currentPlayerID = bonkAPI.getMyID();
        // Set the selector to the first option as default
        player_selector.selectedIndex = bonkAPI.getMyID();
    });
};

// Update the player list in the player selector
pkrUtils.update_players = () => {
    // Get the list of players and the current player ID
    let playerList = bonkAPI.getPlayerList();
    let myID = bonkAPI.getMyID();
    // Reset the player selector
    pkrUtils.reset_selector();
    // Add all player to the player selector
    playerList.forEach((player, id) => {
        if (player && id !== myID) {
            pkrUtils.create_option(id);
        }
    });
};

pkrUtils.generateMarker = (xInput, yInput, rInput) => {
    let markerHold = document.getElementById("pkrutils_marker_hold");

    let markerGraphic = new window.PIXI.Graphics();
    markerGraphic.beginFill(0xffffff);
    markerGraphic.drawCircle((xInput + 365) * pkrUtils.gScale,(yInput + 250) * pkrUtils.gScale, rInput * pkrUtils.gScale);
    markerGraphic.endFill();
    pkrUtils.gCtx.addChild(markerGraphic);

    let resizeFunc = 0;

    let obj = {
        resize: resizeFunc,
        x: xInput,
        y: yInput,
        r: rInput,
    };
    let thisIndex = pkrUtils.markerIndex;
    pkrUtils.markers.set(thisIndex, obj);
    pkrUtils.markerIndex++;

    resizeFunc = function () {
        markerGraphic.clear();
        markerGraphic.beginFill(0xffffff);
        markerGraphic.drawCircle((pkrUtils.markers.get(thisIndex).x + 365) * pkrUtils.gScale, (pkrUtils.markers.get(thisIndex).y + 250) * pkrUtils.gScale, pkrUtils.markers.get(thisIndex).r * pkrUtils.gScale);
        markerGraphic.endFill();
    }
    Object.assign(obj, {resize: resizeFunc})

    pkrUtils.goResize = true;

    let markerDiv = document.createElement("div");
    markerDiv.classList.add("bonkhud-border-color");
    markerDiv.style.height = "3rem";
    markerDiv.style.display = "flex";
    markerDiv.style.borderBottom = "1px solid";
    markerDiv.style.alignItems = "center";
    markerDiv.style.justifyContent = "space-between";
    markerDiv.style.flexWrap = "wrap";
    let nameSpan = document.createElement("span");
    nameSpan.innerText = "(" + xInput + ", " + yInput + ")";
    let markerButton = bonkHUD.generateButton("Delete");
    markerButton.style.width = "3rem";
    markerButton.style.float = "right";

    markerDiv.appendChild(nameSpan);
    markerDiv.appendChild(markerButton);
    markerHold.appendChild(markerDiv);

    markerButton.addEventListener('click', (e) => {
        pkrUtils.markers.delete(thisIndex);
        markerGraphic.destroy();
        markerHold.removeChild(markerDiv);
        pkrUtils.goResize = true;
    });
}

bonkAPI.addEventListener("graphicsReady", (e) => {
    console.log("Readying Graphics");
    pkrUtils.gCtx = new window.PIXI.Container();
    pkrUtils.markers.forEach((val, key, map) => {
        val.resize();
    });
    bonkAPI.pixiCtx.addChild(pkrUtils.gCtx);
    pkrUtils.goResize = true;
});

bonkAPI.addEventListener("modeChange", (e) => {
    currentMode = e.mode;
    let arrowdivs = document.getElementsByClassName("pkrutils-arrows-div");
    let vtoldivs = document.getElementsByClassName("pkrutils-vtol-div");
    if(currentMode == "ar" || currentMode == "ard") {
        for(let i = 0; i < arrowdivs.length; i++) {
            arrowdivs[i].style.display = "block";
        }
        for(let i = 0; i < vtoldivs.length; i++) {
            vtoldivs[i].style.display = "none";
        }
    }
    else if(currentMode == "v") {
        for(let i = 0; i < arrowdivs.length; i++) {
            arrowdivs[i].style.display = "none";
        }
        for(let i = 0; i < vtoldivs.length; i++) {
            vtoldivs[i].style.display = "block";
        }
    }
    else {
        for(let i = 0; i < arrowdivs.length; i++) {
            arrowdivs[i].style.display = "none";
        }
        for(let i = 0; i < vtoldivs.length; i++) {
            vtoldivs[i].style.display = "none";
        }
    }
});

bonkAPI.addEventListener("stepEvent", (e) => {
    if(bonkAPI.isInGame()) {
        let inputState = e.inputState;
        try {
            pkrUtils.currentData = inputState.discs[pkrUtils.currentPlayerID];

            let specialCD = pkrUtils.currentData.a1a;
            let xPos = pkrUtils.currentData.x * pkrUtils.scale - 365;
            let yPos = pkrUtils.currentData.y * pkrUtils.scale - 250;
            let xVel = pkrUtils.currentData.xv * pkrUtils.scale;
            let yVel = pkrUtils.currentData.yv * pkrUtils.scale;
            if(!pkrUtils.hasPrecision) {
                xPos = xPos.toFixed(2);
                yPos = yPos.toFixed(2);
                xVel = xVel.toFixed(2);
                yVel = yVel.toFixed(2);
            }

            pkrUtils.positionElement.textContent = "(" + xPos + ", " + yPos + ")";
            pkrUtils.velocityElement.textContent = "(" + xVel + ", " + yVel + ")";
            pkrUtils.specialElement.textContent = specialCD / 10;
            pkrUtils.vtolAngle.textContent = pkrUtils.currentData.a;
            pkrUtils.vtolAnglev.textContent = pkrUtils.currentData.av;
            pkrUtils.arrowCharge.textContent = pkrUtils.currentData.ds;
            pkrUtils.arrowAngle.textContent = pkrUtils.currentData.da;
        } catch (err) {}
    }
});

bonkAPI.addEventListener('gameStart', (e) => {
    try {
        pkrUtils.scale = e.mapData.physics.ppm;
        pkrUtils.goResize = true;
    } catch(er) {console.log(er)}
});

bonkAPI.addEventListener("graphicsUpdate", (e) => {
    //console.log("g");
    if(pkrUtils.screenWidth != e.width || pkrUtils.goResize) {
        pkrUtils.screenWidth = e.width;
        pkrUtils.gScale = e.width / 730;
        pkrUtils.markers.forEach((val, key, map) => {
            val.resize();
        });
        pkrUtils.goResize = false;
    }
});

// Event listener for when a user joins the game
bonkAPI.addEventListener("userJoin", (e) => {
    //console.log("User join event received", e);
    //console.log("User ID", e.userID);
    // Add the player to the player selector
    pkrUtils.create_option(e.userID);
});

// Event listener for when a user leaves the game
bonkAPI.addEventListener("userLeave", (e) => {
    //console.log("User Leave event received", e);
    //console.log("User ID", e.userID);
    // Remove the player from the player selector
    let playerName = bonkAPI.getPlayerNameByID(e.userID);
    let player_selector = document.getElementById("pkrutils_player_selector");
    // If the player is the current player, set the current player to 0 and reset the selector
    if (player_selector.options[player_selector.selectedIndex].value === playerName) {
        pkrUtils.currentPlayerID = bonkAPI.getMyID();
        // Set the selector to the first option as default
        player_selector.selectedIndex = 0;
    }

    pkrUtils.remove_option(e.userID);
});

// Event listener for when user(mod user) creates a room
bonkAPI.addEventListener("createRoom", (e) => {
    //console.log("create Room event received", e);
    //console.log("User ID", e);
    // Set the player name in the player selector to the current user
    let option = document.getElementById("pkrutils_selector_option_user");
    let playerName = bonkAPI.getPlayerNameByID(e.userID);
    option.innerText = playerName;
    option.value = e.userID;
    pkrUtils.currentPlayerID = e.userID;
    // Reset the player selector to the default state
    pkrUtils.reset_selector();
});

// Event listener for when user(mod user) joins a room
bonkAPI.addEventListener("joinRoom", (e) => {
    //console.log("on Join event received", e);
    //console.log("User ID", e.userID);
    // Set the player name in the player selector to the current user
    let option = document.getElementById("pkrutils_selector_option_user");
    let playerName = bonkAPI.getPlayerNameByID(bonkAPI.getMyID());
    option.innerText = playerName;
    option.value = bonkAPI.getMyID();
    pkrUtils.currentPlayerID = bonkAPI.getMyID();
    // Update the player list in the player selector
    pkrUtils.update_players();
});

// Main function to construct and add the key table UI to the DOM
const addPkrDiv = () => {
    // Create the key table
    let pkrDiv = document.createElement("div");

    pkrDiv.innerHTML = `
        <div class="bonkhud-settings-row">
            <div>
                <span class="bonkhud-settings-label">Position: </span>
                <span id="pkrutils_position"></span>
            </div>
            <div>
                <span class="bonkhud-settings-label">Velocity: </span>
                <span id="pkrutils_velocity"></span>
            </div>
            <div>
                <span class="bonkhud-settings-label">Special: </span>
                <span id="pkrutils_special"></span>
            </div>
            <div class="pkrutils-vtol-div" style="display:none">
                <span class="bonkhud-settings-label">Angle: </span>
                <span id="pkrutils_a"></span>
            </div>
            <div class="pkrutils-vtol-div" style="display:none">
                <span class="bonkhud-settings-label">Angle 2: </span>
                <span id="pkrutils_av"></span>
            </div>
            <div class="pkrutils-arrows-div" style="display:none">
                <span class="bonkhud-settings-label">Charge: </span>
                <span id="pkrutils_ds"></span>
            </div>
            <div class="pkrutils-arrows-div" style="display:none">
                <span class="bonkhud-settings-label">Angle: </span>
                <span id="pkrutils_da"></span>
            </div>
        </div>
        <div class="bonkhud-settings-row">
            <select id="pkrutils_player_selector">
                <option id="pkrutils_selector_option_user">......</option>
            </select>
            <div>
                <span class="bonkhud-settings-label" style="margin-right:5px;vertical-align:middle;">Precision</span>
                <input type="checkbox" id="pkrutils_precision_toggle">
            </div>
        </div>
        <div id="pkrutils_marker_maker" class="bonkhud-settings-row">
            <div>
                <span class="bonkhud-settings-label">x </span>
                <input id="pkrutils_x_marker" type="number" value="0" style="width:100%">
            </div>
            <div>
                <span class="bonkhud-settings-label">y </span>
                <input id="pkrutils_y_marker" type="number" value="0" style="width:100%">
            </div>
            <div style="margin-bottom: 5px;">
                <span class="bonkhud-settings-label">Radius </span>
                <input id="pkrutils_r_marker" type="number" min="1" value="1" style="width:100%">
            </div>
        </div>
        <div id="pkrutils_marker_hold" style="padding:10px"></div>`;

    let pkrIndex = bonkHUD.createWindow(
        pkrUtils.windowConfigs.windowName,
        pkrDiv,
        pkrUtils.windowConfigs);
    /*let keytable_window = document.getElementById("keytable_window");
    keytable_window.style.width = "100%";
    keytable_window.style.height = "calc(100% - 32px)";
    keytable_window.style.padding = "0";
    keytable_window.style.display = "flex";
    keytable_window.style.flexFlow = "column";*/

    let precisionCheck = document.getElementById("pkrutils_precision_toggle");
    precisionCheck.checked = false;
    precisionCheck.oninput = function () {
        pkrUtils.hasPrecision = precisionCheck.checked;
    };

    let markerMaker = document.getElementById("pkrutils_marker_maker");
    let markerGenerator = bonkHUD.generateButton("Create Marker");
    markerGenerator.style.marginBottom = "5px";
    markerGenerator.addEventListener('click', (e) => {
        pkrUtils.generateMarker(parseInt(document.getElementById("pkrutils_x_marker").value), parseInt(document.getElementById("pkrutils_y_marker").value), parseInt(document.getElementById("pkrutils_r_marker").value));
    });

    let markerGenerator2 = bonkHUD.generateButton("Marker At Position");
    markerGenerator2.style.marginBottom = "5px";
    markerGenerator2.addEventListener('click', (e) => {
        try {
            pkrUtils.generateMarker(Math.trunc(pkrUtils.currentData.x * pkrUtils.scale - 365), Math.trunc(pkrUtils.currentData.y * pkrUtils.scale - 250), parseInt(document.getElementById("pkrutils_r_marker").value));
        } catch(er) {
            console.log("Unable to create marker");
        }
    });

    markerMaker.appendChild(markerGenerator);
    markerMaker.appendChild(markerGenerator2);

    pkrUtils.positionElement = document.getElementById("pkrutils_position");
    pkrUtils.velocityElement = document.getElementById("pkrutils_velocity");
    pkrUtils.specialElement = document.getElementById("pkrutils_special");
    pkrUtils.vtolAngle = document.getElementById("pkrutils_a");
    pkrUtils.vtolAnglev = document.getElementById("pkrutils_av");
    pkrUtils.arrowCharge = document.getElementById("pkrutils_ds");
    pkrUtils.arrowAngle = document.getElementById("pkrutils_da");

    bonkHUD.loadUISetting(pkrIndex);
};

// Initialization logic to set up the UI once the document is ready
const init = () => {
    addPkrDiv();
    let playerSelector = document.getElementById("pkrutils_player_selector");
    if (playerSelector) {
        playerSelector.addEventListener("change", pkrUtils.select_player);
    } else {
        console.error("pkrutils_player_selector element not found!");
    }
};

if (document.readyState === "complete" || document.readyState === "interactive") {
    init();
} else {
    document.addEventListener("DOMContentLoaded", init);
}