KeyTable

Add a customizable key table overlay to the bonk.io game

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         KeyTable
// @version      1.4.2
// @description  Add a customizable key table overlay to the bonk.io game
// @author       BZD + Clarifi
// @namespace    http://tampermonkey.net/
// @license      MIT
// @match        https://bonk.io/gameframe-release.html
// @run-at       document-end
// @grant        none
// ==/UserScript==

// ! Compitable with Bonk Version 49
window.KeyTable = {}; // Namespace for encapsulating the UI functions and variables

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

KeyTable.windowConfigs = {
    windowName: "KeyTable",
    windowId: "keytable_window",
    modVersion: "1.4.2",
    bonkLIBVersion: "1.1.3",
    bonkVersion: "49",
};

// Variable to track the most recent key input by the user
KeyTable.latestInput = 0;
KeyTable.currentPlayerID = 0;
KeyTable.frameCount = [0, 0, 0, 0, 0, 0];
// !could make these arrays but better visibly (specific naming)
KeyTable.keys = {};
KeyTable.keyFilter = {
    'left': 1, 'right': 2, 'up': 4, 'down': 8, 'heavy': 16, 'special': 32
};

// Refresh the styles for all keys on the UI
KeyTable.updateKeyStyles = () => {
    Object.entries(KeyTable.keys).forEach(([dir, element]) => {
        // Change the key's background color if it's currently pressed
        element.style.backgroundColor = KeyTable.latestInput & KeyTable.keyFilter[dir] ? bonkHUD.styleHold.buttonColorHover.color : bonkHUD.styleHold.buttonColor.color;
    });
};

// Reset the background color of all keys to the default state
KeyTable.keyTableReset = () => {
    Object.entries(KeyTable.keys).forEach(([dir, element]) => {
        element.style.backgroundColor = bonkHUD.styleHold.buttonColor.color;
    });
};
 
// Event listener function to change the player selected in the player selector
KeyTable.select_player = () => {
    let player_selector = document.getElementById("player_selector");
    let player_id = player_selector.options[player_selector.selectedIndex].value;
    KeyTable.currentPlayerID = player_id;
    KeyTable.updateKeyStyles();
    //console.log("current Player ID: " + player_id);
};

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

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

// Reset the player selector to the default state
KeyTable.reset_selector = () => {
    // Remove all options except the default one
    let player_selector = document.getElementById("player_selector");
    Array.from(player_selector.options).forEach((option) => {
        if (option.id !== "selector_option_user") {
            player_selector.removeChild(option);
        }
        // Reset the current player ID
        KeyTable.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
KeyTable.update_players = () => {
    // Get the list of players and the current player ID
    let playerList = bonkAPI.getPlayerList();
    let myID = bonkAPI.getMyID();
    // Reset the player selector
    KeyTable.reset_selector();
    // Add all player to the player selector
    playerList.forEach((player, id) => {
        if (player && id !== myID) {
            KeyTable.create_option(id);
        }
    });
};

// Process input data and invoke style updates
bonkAPI.addEventListener("gameInputs", (e) => {
    // console.log("gameInputs event received", e);
    if (e.userID == KeyTable.currentPlayerID) {
        // console.log("Updating latestInput for player", readingPlayerID, "with input", e.rawInput);
        KeyTable.latestInput = e.rawInput;
        KeyTable.updateKeyStyles();
    }
});

/*bonkAPI.addEventListener("stepEvent", (e) => {
    for(int i = 0; i < KeyTable.keys) {

    }
});*/

// 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
    KeyTable.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("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) {
        KeyTable.currentPlayerID = bonkAPI.getMyID();
        // Set the selector to the first option as default
        player_selector.selectedIndex = 0;
    }

    KeyTable.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("selector_option_user");
    let playerName = bonkAPI.getPlayerNameByID(e.userID);
    option.textContent = playerName;
    option.value = e.userID;
    KeyTable.currentPlayerID = e.userID;
    // Reset the player selector to the default state
    KeyTable.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("selector_option_user");
    let playerName = bonkAPI.getPlayerNameByID(bonkAPI.getMyID());
    option.textContent = playerName;
    option.value = bonkAPI.getMyID();
    KeyTable.currentPlayerID = bonkAPI.getMyID();
    // Update the player list in the player selector
    KeyTable.update_players();
});

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

    let keyHold = document.createElement("table");
    keyHold.style.flex = "1 1 auto";

    let tableBody = document.createElement("tbody");
    let topRow = document.createElement("tr");
    KeyTable.keys["special"] = document.createElement("td");
    KeyTable.keys["special"].classList.add("bonkhud-button-color");
    KeyTable.keys["special"].classList.add("bonkhud-text-color");
    KeyTable.keys["special"].style.width = "34%";
    KeyTable.keys["special"].style.textAlign = "center";
    KeyTable.keys["special"].textContent = "Special";

    KeyTable.keys["up"] = document.createElement("td");
    KeyTable.keys["up"].classList.add("bonkhud-button-color");
    KeyTable.keys["up"].classList.add("bonkhud-text-color");
    KeyTable.keys["up"].style.width = "34%";
    KeyTable.keys["up"].style.textAlign = "center";
    KeyTable.keys["up"].textContent = "↑";

    KeyTable.keys["heavy"] = document.createElement("td");
    KeyTable.keys["heavy"].classList.add("bonkhud-button-color");
    KeyTable.keys["heavy"].classList.add("bonkhud-text-color");
    KeyTable.keys["heavy"].style.width = "34%";
    KeyTable.keys["heavy"].style.textAlign = "center";
    KeyTable.keys["heavy"].textContent = "Heavy";

    let botRow = document.createElement("tr");
    KeyTable.keys["left"] = document.createElement("td");
    KeyTable.keys["left"].classList.add("bonkhud-button-color");
    KeyTable.keys["left"].classList.add("bonkhud-text-color");
    KeyTable.keys["left"].style.width = "34%";
    KeyTable.keys["left"].style.textAlign = "center";
    KeyTable.keys["left"].textContent = "←";

    KeyTable.keys["down"] = document.createElement("td");
    KeyTable.keys["down"].classList.add("bonkhud-button-color");
    KeyTable.keys["down"].classList.add("bonkhud-text-color");
    KeyTable.keys["down"].style.width = "34%";
    KeyTable.keys["down"].style.textAlign = "center";
    KeyTable.keys["down"].textContent = "↓";

    KeyTable.keys["right"] = document.createElement("td");
    KeyTable.keys["right"].classList.add("bonkhud-button-color");
    KeyTable.keys["right"].classList.add("bonkhud-text-color");
    KeyTable.keys["right"].style.width = "34%";
    KeyTable.keys["right"].style.textAlign = "center";
    KeyTable.keys["right"].textContent = "→";

    let pSelectorHold = document.createElement("div");
    pSelectorHold.style.flex = "0 1 auto";
    pSelectorHold.style.padding = "10px";

    let pSelector = document.createElement("select");
    pSelector.id = "player_selector";

    let pOption = document.createElement("option");
    pOption.id = "selector_option_user";
    pOption.textContent = "......";

    topRow.appendChild(KeyTable.keys["special"]);
    topRow.appendChild(KeyTable.keys["up"]);
    topRow.appendChild(KeyTable.keys["heavy"]);

    botRow.appendChild(KeyTable.keys["left"]);
    botRow.appendChild(KeyTable.keys["down"]);
    botRow.appendChild(KeyTable.keys["right"]);

    tableBody.appendChild(topRow);
    tableBody.appendChild(botRow);

    pSelector.appendChild(pOption);

    pSelectorHold.appendChild(pSelector);

    keyHold.appendChild(tableBody);

    keyTable.appendChild(keyHold);
    keyTable.appendChild(pSelectorHold);

    let keyTableSettings = document.createElement('div');
    keyTableSettings.style.margin = "10px";

    let inputTopRow = document.createElement('div');
    inputTopRow.style.display = "flex";

    let heavyInput = document.createElement('input');
    heavyInput.setAttribute("type", "text");
    heavyInput.value = "Heavy";
    heavyInput.style.minWidth = "0";

    let upInput = document.createElement('input');
    upInput.setAttribute("type", "text");
    upInput.value = "↑";
    upInput.style.minWidth = "0";

    let specialInput = document.createElement('input');
    specialInput.setAttribute("type", "text");
    specialInput.value = "Special";
    specialInput.style.minWidth = "0";

    let inputBottomRow = document.createElement('div');
    inputBottomRow.style.display = "flex";

    let leftInput = document.createElement('input');
    leftInput.setAttribute("type", "text");
    leftInput.value = "←";
    leftInput.style.minWidth = "0";

    let downInput = document.createElement('input');
    downInput.setAttribute("type", "text");
    downInput.value = "↓";
    downInput.style.minWidth = "0";

    let rightInput = document.createElement('input');
    rightInput.setAttribute("type", "text");
    rightInput.value = "→";
    rightInput.style.minWidth = "0";

    inputTopRow.appendChild(specialInput);
    inputTopRow.appendChild(upInput);
    inputTopRow.appendChild(heavyInput);

    inputBottomRow.appendChild(leftInput);
    inputBottomRow.appendChild(downInput);
    inputBottomRow.appendChild(rightInput);

    keyTableSettings.appendChild(inputTopRow);
    keyTableSettings.appendChild(inputBottomRow);

    KeyTable.windowConfigs.settingsContent = keyTableSettings;

    let keytable_index = bonkHUD.createWindow(
        KeyTable.windowConfigs.windowName,
        keyTable,
        KeyTable.windowConfigs
    );
    let keytable_window = bonkHUD.getElementByIndex(keytable_index);
    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";

    bonkHUD.loadUISetting(keytable_index);

    let recoveredSetting = bonkHUD.getModSetting(keytable_index);
    if(recoveredSetting) {
        KeyTable.keys["heavy"].textContent = recoveredSetting["heavy"];
        KeyTable.keys["up"].textContent = recoveredSetting["up"];
        KeyTable.keys["special"].textContent = recoveredSetting["special"];
        KeyTable.keys["left"].textContent = recoveredSetting["left"];
        KeyTable.keys["down"].textContent = recoveredSetting["down"];
        KeyTable.keys["right"].textContent = recoveredSetting["right"];

        heavyInput.value = recoveredSetting["heavy"];
        upInput.value = recoveredSetting["up"];
        specialInput.value = recoveredSetting["special"];
        leftInput.value = recoveredSetting["left"];
        downInput.value = recoveredSetting["down"];
        rightInput.value = recoveredSetting["right"];
    }

    let saveFunction = function() {
        let setting = {
            "heavy": heavyInput.value,
            "up": upInput.value,
            "special": specialInput.value,
            "left": leftInput.value,
            "down": downInput.value,
            "right": rightInput.value,
        };
        bonkHUD.saveModSetting(keytable_index, setting);

        KeyTable.keys["heavy"].textContent = heavyInput.value;
        KeyTable.keys["up"].textContent = upInput.value;
        KeyTable.keys["special"].textContent = specialInput.value;
        KeyTable.keys["left"].textContent = leftInput.value;
        KeyTable.keys["down"].textContent = downInput.value;
        KeyTable.keys["right"].textContent = rightInput.value;
        KeyTable.updateKeyStyles();
    }

    heavyInput.onchange = saveFunction;
    upInput.onchange = saveFunction;
    specialInput.onchange = saveFunction;
    leftInput.onchange = saveFunction;
    downInput.onchange = saveFunction;
    rightInput.onchange = saveFunction;

    // Initialize the key styles
    KeyTable.updateKeyStyles();
};

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

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