KeyTable

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

  1. // ==UserScript==
  2. // @name KeyTable
  3. // @version 1.4.2
  4. // @description Add a customizable key table overlay to the bonk.io game
  5. // @author BZD + Clarifi
  6. // @namespace http://tampermonkey.net/
  7. // @license MIT
  8. // @match https://bonk.io/gameframe-release.html
  9. // @run-at document-end
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. // ! Compitable with Bonk Version 49
  14. window.KeyTable = {}; // Namespace for encapsulating the UI functions and variables
  15.  
  16. // Use 'strict' mode for safer code by managing silent errors
  17. 'use strict';
  18.  
  19. KeyTable.windowConfigs = {
  20. windowName: "KeyTable",
  21. windowId: "keytable_window",
  22. modVersion: "1.4.2",
  23. bonkLIBVersion: "1.1.3",
  24. bonkVersion: "49",
  25. };
  26.  
  27. // Variable to track the most recent key input by the user
  28. KeyTable.latestInput = 0;
  29. KeyTable.currentPlayerID = 0;
  30. KeyTable.frameCount = [0, 0, 0, 0, 0, 0];
  31. // !could make these arrays but better visibly (specific naming)
  32. KeyTable.keys = {};
  33. KeyTable.keyFilter = {
  34. 'left': 1, 'right': 2, 'up': 4, 'down': 8, 'heavy': 16, 'special': 32
  35. };
  36.  
  37. // Refresh the styles for all keys on the UI
  38. KeyTable.updateKeyStyles = () => {
  39. Object.entries(KeyTable.keys).forEach(([dir, element]) => {
  40. // Change the key's background color if it's currently pressed
  41. element.style.backgroundColor = KeyTable.latestInput & KeyTable.keyFilter[dir] ? bonkHUD.styleHold.buttonColorHover.color : bonkHUD.styleHold.buttonColor.color;
  42. });
  43. };
  44.  
  45. // Reset the background color of all keys to the default state
  46. KeyTable.keyTableReset = () => {
  47. Object.entries(KeyTable.keys).forEach(([dir, element]) => {
  48. element.style.backgroundColor = bonkHUD.styleHold.buttonColor.color;
  49. });
  50. };
  51. // Event listener function to change the player selected in the player selector
  52. KeyTable.select_player = () => {
  53. let player_selector = document.getElementById("player_selector");
  54. let player_id = player_selector.options[player_selector.selectedIndex].value;
  55. KeyTable.currentPlayerID = player_id;
  56. KeyTable.updateKeyStyles();
  57. //console.log("current Player ID: " + player_id);
  58. };
  59.  
  60. // Create a new option in the player selector
  61. KeyTable.create_option = (userID) => {
  62. //console.log("userID:" + userID);
  63. let playerName = bonkAPI.getPlayerNameByID(userID);
  64. let player_selector = document.getElementById("player_selector");
  65. let newOption = document.createElement("option");
  66. newOption.textContent = playerName;
  67. newOption.value = userID;
  68. newOption.id = "selector_option_" + userID;
  69. player_selector.appendChild(newOption);
  70. KeyTable.updateKeyStyles();
  71. //console.log("selector_option_" + userID + " added to player_selector");
  72. };
  73.  
  74. // Remove an option from the player selector
  75. KeyTable.remove_option = (userID) => {
  76. let player_selector = document.getElementById("player_selector");
  77. let option = document.getElementById("selector_option_" + userID);
  78. player_selector.removeChild(option);
  79. };
  80.  
  81. // Reset the player selector to the default state
  82. KeyTable.reset_selector = () => {
  83. // Remove all options except the default one
  84. let player_selector = document.getElementById("player_selector");
  85. Array.from(player_selector.options).forEach((option) => {
  86. if (option.id !== "selector_option_user") {
  87. player_selector.removeChild(option);
  88. }
  89. // Reset the current player ID
  90. KeyTable.currentPlayerID = bonkAPI.getMyID();
  91. // Set the selector to the first option as default
  92. player_selector.selectedIndex = bonkAPI.getMyID();
  93. });
  94. };
  95.  
  96. // Update the player list in the player selector
  97. KeyTable.update_players = () => {
  98. // Get the list of players and the current player ID
  99. let playerList = bonkAPI.getPlayerList();
  100. let myID = bonkAPI.getMyID();
  101. // Reset the player selector
  102. KeyTable.reset_selector();
  103. // Add all player to the player selector
  104. playerList.forEach((player, id) => {
  105. if (player && id !== myID) {
  106. KeyTable.create_option(id);
  107. }
  108. });
  109. };
  110.  
  111. // Process input data and invoke style updates
  112. bonkAPI.addEventListener("gameInputs", (e) => {
  113. // console.log("gameInputs event received", e);
  114. if (e.userID == KeyTable.currentPlayerID) {
  115. // console.log("Updating latestInput for player", readingPlayerID, "with input", e.rawInput);
  116. KeyTable.latestInput = e.rawInput;
  117. KeyTable.updateKeyStyles();
  118. }
  119. });
  120.  
  121. /*bonkAPI.addEventListener("stepEvent", (e) => {
  122. for(int i = 0; i < KeyTable.keys) {
  123.  
  124. }
  125. });*/
  126.  
  127. // Event listener for when a user joins the game
  128. bonkAPI.addEventListener("userJoin", (e) => {
  129. //console.log("User join event received", e);
  130. //console.log("User ID", e.userID);
  131. // Add the player to the player selector
  132. KeyTable.create_option(e.userID);
  133. });
  134.  
  135. // Event listener for when a user leaves the game
  136. bonkAPI.addEventListener("userLeave", (e) => {
  137. //console.log("User Leave event received", e);
  138. //console.log("User ID", e.userID);
  139. // Remove the player from the player selector
  140. let playerName = bonkAPI.getPlayerNameByID(e.userID);
  141. let player_selector = document.getElementById("player_selector");
  142. // If the player is the current player, set the current player to 0 and reset the selector
  143. if (player_selector.options[player_selector.selectedIndex].value === playerName) {
  144. KeyTable.currentPlayerID = bonkAPI.getMyID();
  145. // Set the selector to the first option as default
  146. player_selector.selectedIndex = 0;
  147. }
  148.  
  149. KeyTable.remove_option(e.userID);
  150. });
  151.  
  152. // Event listener for when user(mod user) creates a room
  153. bonkAPI.addEventListener("createRoom", (e) => {
  154. //console.log("create Room event received", e);
  155. //console.log("User ID", e);
  156. // Set the player name in the player selector to the current user
  157. let option = document.getElementById("selector_option_user");
  158. let playerName = bonkAPI.getPlayerNameByID(e.userID);
  159. option.textContent = playerName;
  160. option.value = e.userID;
  161. KeyTable.currentPlayerID = e.userID;
  162. // Reset the player selector to the default state
  163. KeyTable.reset_selector();
  164. });
  165.  
  166. // Event listener for when user(mod user) joins a room
  167. bonkAPI.addEventListener("joinRoom", (e) => {
  168. //console.log("on Join event received", e);
  169. //console.log("User ID", e.userID);
  170. // Set the player name in the player selector to the current user
  171. let option = document.getElementById("selector_option_user");
  172. let playerName = bonkAPI.getPlayerNameByID(bonkAPI.getMyID());
  173. option.textContent = playerName;
  174. option.value = bonkAPI.getMyID();
  175. KeyTable.currentPlayerID = bonkAPI.getMyID();
  176. // Update the player list in the player selector
  177. KeyTable.update_players();
  178. });
  179.  
  180. // Main function to construct and add the key table UI to the DOM
  181. const addKeyTable = () => {
  182. // Create the key table
  183. let keyTable = document.createElement("div");
  184.  
  185. let keyHold = document.createElement("table");
  186. keyHold.style.flex = "1 1 auto";
  187.  
  188. let tableBody = document.createElement("tbody");
  189. let topRow = document.createElement("tr");
  190. KeyTable.keys["special"] = document.createElement("td");
  191. KeyTable.keys["special"].classList.add("bonkhud-button-color");
  192. KeyTable.keys["special"].classList.add("bonkhud-text-color");
  193. KeyTable.keys["special"].style.width = "34%";
  194. KeyTable.keys["special"].style.textAlign = "center";
  195. KeyTable.keys["special"].textContent = "Special";
  196.  
  197. KeyTable.keys["up"] = document.createElement("td");
  198. KeyTable.keys["up"].classList.add("bonkhud-button-color");
  199. KeyTable.keys["up"].classList.add("bonkhud-text-color");
  200. KeyTable.keys["up"].style.width = "34%";
  201. KeyTable.keys["up"].style.textAlign = "center";
  202. KeyTable.keys["up"].textContent = "↑";
  203.  
  204. KeyTable.keys["heavy"] = document.createElement("td");
  205. KeyTable.keys["heavy"].classList.add("bonkhud-button-color");
  206. KeyTable.keys["heavy"].classList.add("bonkhud-text-color");
  207. KeyTable.keys["heavy"].style.width = "34%";
  208. KeyTable.keys["heavy"].style.textAlign = "center";
  209. KeyTable.keys["heavy"].textContent = "Heavy";
  210.  
  211. let botRow = document.createElement("tr");
  212. KeyTable.keys["left"] = document.createElement("td");
  213. KeyTable.keys["left"].classList.add("bonkhud-button-color");
  214. KeyTable.keys["left"].classList.add("bonkhud-text-color");
  215. KeyTable.keys["left"].style.width = "34%";
  216. KeyTable.keys["left"].style.textAlign = "center";
  217. KeyTable.keys["left"].textContent = "←";
  218.  
  219. KeyTable.keys["down"] = document.createElement("td");
  220. KeyTable.keys["down"].classList.add("bonkhud-button-color");
  221. KeyTable.keys["down"].classList.add("bonkhud-text-color");
  222. KeyTable.keys["down"].style.width = "34%";
  223. KeyTable.keys["down"].style.textAlign = "center";
  224. KeyTable.keys["down"].textContent = "↓";
  225.  
  226. KeyTable.keys["right"] = document.createElement("td");
  227. KeyTable.keys["right"].classList.add("bonkhud-button-color");
  228. KeyTable.keys["right"].classList.add("bonkhud-text-color");
  229. KeyTable.keys["right"].style.width = "34%";
  230. KeyTable.keys["right"].style.textAlign = "center";
  231. KeyTable.keys["right"].textContent = "→";
  232.  
  233. let pSelectorHold = document.createElement("div");
  234. pSelectorHold.style.flex = "0 1 auto";
  235. pSelectorHold.style.padding = "10px";
  236.  
  237. let pSelector = document.createElement("select");
  238. pSelector.id = "player_selector";
  239.  
  240. let pOption = document.createElement("option");
  241. pOption.id = "selector_option_user";
  242. pOption.textContent = "......";
  243.  
  244. topRow.appendChild(KeyTable.keys["special"]);
  245. topRow.appendChild(KeyTable.keys["up"]);
  246. topRow.appendChild(KeyTable.keys["heavy"]);
  247.  
  248. botRow.appendChild(KeyTable.keys["left"]);
  249. botRow.appendChild(KeyTable.keys["down"]);
  250. botRow.appendChild(KeyTable.keys["right"]);
  251.  
  252. tableBody.appendChild(topRow);
  253. tableBody.appendChild(botRow);
  254.  
  255. pSelector.appendChild(pOption);
  256.  
  257. pSelectorHold.appendChild(pSelector);
  258.  
  259. keyHold.appendChild(tableBody);
  260.  
  261. keyTable.appendChild(keyHold);
  262. keyTable.appendChild(pSelectorHold);
  263.  
  264. let keyTableSettings = document.createElement('div');
  265. keyTableSettings.style.margin = "10px";
  266.  
  267. let inputTopRow = document.createElement('div');
  268. inputTopRow.style.display = "flex";
  269.  
  270. let heavyInput = document.createElement('input');
  271. heavyInput.setAttribute("type", "text");
  272. heavyInput.value = "Heavy";
  273. heavyInput.style.minWidth = "0";
  274.  
  275. let upInput = document.createElement('input');
  276. upInput.setAttribute("type", "text");
  277. upInput.value = "↑";
  278. upInput.style.minWidth = "0";
  279.  
  280. let specialInput = document.createElement('input');
  281. specialInput.setAttribute("type", "text");
  282. specialInput.value = "Special";
  283. specialInput.style.minWidth = "0";
  284.  
  285. let inputBottomRow = document.createElement('div');
  286. inputBottomRow.style.display = "flex";
  287.  
  288. let leftInput = document.createElement('input');
  289. leftInput.setAttribute("type", "text");
  290. leftInput.value = "←";
  291. leftInput.style.minWidth = "0";
  292.  
  293. let downInput = document.createElement('input');
  294. downInput.setAttribute("type", "text");
  295. downInput.value = "↓";
  296. downInput.style.minWidth = "0";
  297.  
  298. let rightInput = document.createElement('input');
  299. rightInput.setAttribute("type", "text");
  300. rightInput.value = "→";
  301. rightInput.style.minWidth = "0";
  302.  
  303. inputTopRow.appendChild(specialInput);
  304. inputTopRow.appendChild(upInput);
  305. inputTopRow.appendChild(heavyInput);
  306.  
  307. inputBottomRow.appendChild(leftInput);
  308. inputBottomRow.appendChild(downInput);
  309. inputBottomRow.appendChild(rightInput);
  310.  
  311. keyTableSettings.appendChild(inputTopRow);
  312. keyTableSettings.appendChild(inputBottomRow);
  313.  
  314. KeyTable.windowConfigs.settingsContent = keyTableSettings;
  315.  
  316. let keytable_index = bonkHUD.createWindow(
  317. KeyTable.windowConfigs.windowName,
  318. keyTable,
  319. KeyTable.windowConfigs
  320. );
  321. let keytable_window = bonkHUD.getElementByIndex(keytable_index);
  322. keytable_window.style.width = "100%";
  323. keytable_window.style.height = "calc(100% - 32px)";
  324. keytable_window.style.padding = "0";
  325. keytable_window.style.display = "flex";
  326. keytable_window.style.flexFlow = "column";
  327.  
  328. bonkHUD.loadUISetting(keytable_index);
  329.  
  330. let recoveredSetting = bonkHUD.getModSetting(keytable_index);
  331. if(recoveredSetting) {
  332. KeyTable.keys["heavy"].textContent = recoveredSetting["heavy"];
  333. KeyTable.keys["up"].textContent = recoveredSetting["up"];
  334. KeyTable.keys["special"].textContent = recoveredSetting["special"];
  335. KeyTable.keys["left"].textContent = recoveredSetting["left"];
  336. KeyTable.keys["down"].textContent = recoveredSetting["down"];
  337. KeyTable.keys["right"].textContent = recoveredSetting["right"];
  338.  
  339. heavyInput.value = recoveredSetting["heavy"];
  340. upInput.value = recoveredSetting["up"];
  341. specialInput.value = recoveredSetting["special"];
  342. leftInput.value = recoveredSetting["left"];
  343. downInput.value = recoveredSetting["down"];
  344. rightInput.value = recoveredSetting["right"];
  345. }
  346.  
  347. let saveFunction = function() {
  348. let setting = {
  349. "heavy": heavyInput.value,
  350. "up": upInput.value,
  351. "special": specialInput.value,
  352. "left": leftInput.value,
  353. "down": downInput.value,
  354. "right": rightInput.value,
  355. };
  356. bonkHUD.saveModSetting(keytable_index, setting);
  357.  
  358. KeyTable.keys["heavy"].textContent = heavyInput.value;
  359. KeyTable.keys["up"].textContent = upInput.value;
  360. KeyTable.keys["special"].textContent = specialInput.value;
  361. KeyTable.keys["left"].textContent = leftInput.value;
  362. KeyTable.keys["down"].textContent = downInput.value;
  363. KeyTable.keys["right"].textContent = rightInput.value;
  364. KeyTable.updateKeyStyles();
  365. }
  366.  
  367. heavyInput.onchange = saveFunction;
  368. upInput.onchange = saveFunction;
  369. specialInput.onchange = saveFunction;
  370. leftInput.onchange = saveFunction;
  371. downInput.onchange = saveFunction;
  372. rightInput.onchange = saveFunction;
  373.  
  374. // Initialize the key styles
  375. KeyTable.updateKeyStyles();
  376. };
  377.  
  378. // Initialization logic to set up the UI once the document is ready
  379. const init = () => {
  380. addKeyTable();
  381. let playerSelector = document.getElementById("player_selector");
  382. if (playerSelector) {
  383. playerSelector.addEventListener("change", KeyTable.select_player);
  384. } else {
  385. console.error("player_selector element not found!");
  386. }
  387. };
  388.  
  389. if (document.readyState === "complete" || document.readyState === "interactive") {
  390. init();
  391. } else {
  392. document.addEventListener("DOMContentLoaded", init);
  393. }