A cheat client for bonk.io, includes a GrappleBot and HeavyBot that is almost perfect
// ==UserScript==
// @name Bonk Cheat Client
// @version 6.1.0
// @description A cheat client for bonk.io, includes a GrappleBot and HeavyBot that is almost perfect
// @author Steairy
// @match https://bonk.io/gameframe-release.html
// @run-at document-end
// @grant none
// @license MIT
// @namespace https://greasyfork.org/users/1612566
// ==/UserScript==
window.heavyBotEnabled = false;
window.grappleBotEnabled = false;
window.autoGrappleHotkey = "KeyG";
window.isAutoGrapplePressed = false;
window.isHeavyPressed = false;
window.addEventListener("keydown", (e) => {
if(e.code === window.autoGrappleHotkey){
window.isAutoGrapplePressed = true;
}
if(e.code == "KeyX"){
window.isHeavyPressed = true;
}
}, true);
window.addEventListener("keyup", (e) => {
if(e.code === window.autoGrappleHotkey) {
window.isAutoGrapplePressed = false;
}
if(e.code == "KeyX"){
window.isHeavyPressed = false;
}
}, true);
(function(){
// Makes the HUD
function initHUD() {
let windowHTML = document.createElement("div");
let sectionDiv = bonkHUD.generateSection();
sectionDiv.style.padding = "12px";
sectionDiv.style.display = "flex";
sectionDiv.style.flexDirection = "column";
sectionDiv.style.gap = "10px";
function createRow(labelText, appendElement) {
let row = document.createElement("div");
row.style.display = "flex";
row.style.alignItems = "center";
row.style.justifyContent = "space-between";
row.style.width = "100%";
let label = document.createElement("label");
label.classList.add("bonkhud-text-color", "bonkhud-settings-label");
label.style.fontSize = "13px";
label.textContent = labelText;
row.appendChild(label);
row.appendChild(appendElement);
return row;
}
let heavyCheckbox = document.createElement("input");
heavyCheckbox.type = "checkbox";
heavyCheckbox.checked = window.heavyBotEnabled;
heavyCheckbox.style.cursor = "pointer";
heavyCheckbox.onchange = (e) => {
window.heavyBotEnabled = e.target.checked;
};
let grappleCheckbox = document.createElement("input");
grappleCheckbox.type = "checkbox";
grappleCheckbox.checked = window.grappleBotEnabled;
grappleCheckbox.style.cursor = "pointer";
grappleCheckbox.onchange = (e) => {
window.grappleBotEnabled = e.target.checked;
};
let bindBtn = document.createElement("button");
bindBtn.textContent = window.autoGrappleHotkey.replace("Key", "").toUpperCase();
bindBtn.style.backgroundColor = "#2e2e2e";
bindBtn.style.color = "#ffffff";
bindBtn.style.border = "1px solid #4a4a4a";
bindBtn.style.borderRadius = "4px";
bindBtn.style.padding = "3px 10px";
bindBtn.style.minWidth = "75px";
bindBtn.style.textAlign = "center";
bindBtn.style.cursor = "pointer";
bindBtn.style.fontSize = "11px";
bindBtn.style.fontWeight = "bold";
bindBtn.style.transition = "background-color 0.15s, border-color 0.15s";
bindBtn.onmouseenter = () => { bindBtn.style.backgroundColor = "#3d3d3d"; bindBtn.style.borderColor = "#666"; };
bindBtn.onmouseleave = () => { bindBtn.style.backgroundColor = "#2e2e2e"; bindBtn.style.borderColor = "#4a4a4a"; };
let isBinding = false;
bindBtn.onclick = () => {
if (isBinding) return;
isBinding = true;
bindBtn.textContent = "...";
bindBtn.style.backgroundColor = "#522";
bindBtn.style.borderColor = "#844";
const listenForCall = (e) => {
e.preventDefault();
e.stopPropagation();
window.autoGrappleHotkey = e.code;
bindBtn.textContent = e.code.replace("Key", "").toUpperCase();
bindBtn.style.backgroundColor = "#2e2e2e";
bindBtn.style.borderColor = "#4a4a4a";
window.removeEventListener("keydown", listenForCall, true);
isBinding = false;
};
window.addEventListener("keydown", listenForCall, true);
};
sectionDiv.appendChild(createRow("Enable HeavyBot", heavyCheckbox));
sectionDiv.appendChild(createRow("Enable GrappleBot", grappleCheckbox));
sectionDiv.appendChild(createRow("AutoGrapple Hotkey", bindBtn));
windowHTML.appendChild(sectionDiv);
const botHUDConfig = {
windowName: "Bot Control",
windowId: "bot_control_window",
windowContent: windowHTML,
};
const modIndex = bonkHUD.createMod(botHUDConfig.windowName, botHUDConfig);
let botWindow = bonkHUD.getElementByIndex(modIndex);
if (botWindow) {
botWindow.style.padding = "0";
botWindow.style.width = "100%";
botWindow.style.height = "100%";
}
bonkHUD.loadUISetting(modIndex);
}
function getGameState(data){
const gameState = data.gameState;
const activePlayers = [];
const playerIDs = bonkAPI.getPlayersInLobbyID();
const discsContainer = gameState.discs || gameState.p || null;
const myID = bonkAPI.getMyID();
if (!discsContainer) return;
playerIDs.forEach((id) => {
const lobbyInfo = bonkAPI.getPlayerByID(id);
const disc = discsContainer[id];
if(!lobbyInfo || !disc) return;
const x = disc.x ?? 0;
const y = disc.y ?? 0;
const xv = disc.xv ?? (disc.lv && disc.lv[0] !== undefined ? disc.lv[0] : 0);
const yv = disc.yv ?? (disc.lv && disc.lv[1] !== undefined ? disc.lv[1] : 0);
const isHeavy = disc.a1 === true;
const cooldown = disc.a1a ?? 0;
const angle = disc.a ?? 0;
activePlayers.push({
id: id,
isMe: (id === myID),
userName: lobbyInfo.userName,
team: lobbyInfo.team,
level: lobbyInfo.level,
physics: {
x: x,
y: y,
xv: xv,
yv: yv,
angle: angle,
heavy: isHeavy,
cooldown: cooldown
}
});
});
return activePlayers;
}
const BonkController = {
_triggerKeyEvent: function(type, keyCode, key, code) {
const event = new KeyboardEvent(type, {
bubbles: true, cancelable: true,
keyCode: keyCode, key: key, code: code, which: keyCode
});
document.dispatchEvent(event);
},
heavy: (press) => BonkController._triggerKeyEvent(press ? 'keydown' : 'keyup', 32, ' ', 'Space'),
grapple: (press) => BonkController._triggerKeyEvent(press ? 'keydown' : 'keyup', 90, 'z', 'KeyZ'),
};
const triggerRadius = 2.0;
const TPS = 30;
var motionHistory = new Map();
function botLoop(state){
if(!state || state.length === 0){
return;
}
const me = state.find(p => p.isMe);
var willCollide = false;
if(!me) return;
if(!motionHistory.has(me.id)) motionHistory.set(me.id, { xv: me.physics.xv, yv: me.physics.yv });
const myHistory = motionHistory.get(me.id);
const myDvx = me.physics.xv - myHistory.xv;
const myDvy = me.physics.yv - myHistory.yv;
for(var i = 0; i < state.length; i++){
const player = state[i];
if(player === me) continue;
if(!motionHistory.has(player.id)) motionHistory.set(player.id, {xv: player.physics.xv, yv: player.physics.yv});
const enemyHistory = motionHistory.get(player.id);
const enemyDvx = player.physics.xv - enemyHistory.xv;
const enemyDvy = player.physics.yv - enemyHistory.yv;
const currentDist = Math.hypot(me.physics.x - player.physics.x, me.physics.y - player.physics.y);
if(currentDist <= triggerRadius){
willCollide = true;
}
else{
// Assuming constant velocity
const myNextX1 = me.physics.x + (me.physics.xv / TPS);
const myNextY1 = me.physics.y + (me.physics.yv / TPS);
const enemyNextX1 = player.physics.x + (player.physics.xv / TPS);
const enemyNextY1 = player.physics.y + (player.physics.yv / TPS);
const distInertial = Math.hypot(myNextX1 - enemyNextX1, myNextY1 - enemyNextY1);
// Assuming constant acceleration
const myNextX2 = me.physics.x + ((me.physics.xv + myDvx) / TPS);
const myNextY2 = me.physics.y + ((me.physics.yv + myDvy) / TPS);
const enemyNextX2 = player.physics.x + ((player.physics.xv + enemyDvx) / TPS);
const enemyNextY2 = player.physics.y + ((player.physics.yv + enemyDvy) / TPS);
const distAccelerated = Math.hypot(myNextX2 - enemyNextX2, myNextY2 - enemyNextY2);
if(distInertial <= triggerRadius || distAccelerated <= triggerRadius){
willCollide = true;
}
}
motionHistory.set(player.id, {xv: player.physics.xv, yv: player.physics.yv});
}
motionHistory.set(me.id, {xv: me.physics.xv, yv: me.physics.yv});
if(window.heavyBotEnabled && !window.isHeavyPressed) BonkController.heavy(willCollide);
if(window.grappleBotEnabled) BonkController.grapple(!willCollide && window.isAutoGrapplePressed);
}
// Main loop
initHUD();
bonkAPI.addEventListener("stepEvent", function(data){
if(!data || !data.gameState) return;
const state = getGameState(data);
botLoop(state);
})
})();