Bonk.io script to draws out an arrow's full trajectory when aiming
// ==UserScript==
// @name Bonk.io Arrow Trajectory
// @version 2.3
// @description Bonk.io script to draws out an arrow's full trajectory when aiming
// @author Triton
// @icon https://bonk.io/graphics/tt/favicon-32x32.png
// @match https://bonk.io/*
// @match https://bonk.io/gameframe-release.html
// @run-at document-end
// @grant none
// @namespace https://greasyfork.org/users/1015072
// ==/UserScript==
(function () {
'use strict';
function injector(func) {
if (window.location.hostname === "bonk.io" && window.location.pathname !== "/gameframe-release.html") {
const waitForFrame = setInterval(() => {
const frame = document.getElementById("maingameframe");
if (frame && frame.contentWindow && frame.contentDocument) {
const script = document.createElement("script");
script.textContent = `(${func.toString()})();`;
frame.contentDocument.head.appendChild(script);
clearInterval(waitForFrame);
}
}, 500);
} else {
func();
}
}
injector(function () {
const scope = window;
if (!scope.PIXI || !scope.PIXI.Graphics) return;
//Constants
const BASE_RADIUS_PPM = 19.709589041095892;
const PHYSICS = {
GRAVITY: 197,
VEL_MULT: 592,
VEL_BASE: 301
};
const CONFIG = {
MAX_CHARGE: 1.5,
KEY: "KeyZ",
COLOR: 0xD3D3D3, //Sets trajectory color
THICKNESS: 2,
ALPHA: 0.1, //Sets trajectory transparency
POINTS: 50,
SIM_TIME: 5.0 //Set higher to show longer trajectory
};
let myUserName = null;
let myPlayerContainer = null;
let myPlayerID = -1;
let aimerChild = null;
let arcGraphics = null;
let chargeStartTime = 0;
let isCharging = false;
let isHoldingKey = false;
let currentPPM = BASE_RADIUS_PPM;
let pixiObjectId = 0;
//Websocket hook
const originalSend = scope.WebSocket.prototype.send;
scope.WebSocket.prototype.send = function (args) {
if (typeof args === "string" && args.startsWith('42[12,')) {
try {
const json = JSON.parse(args.substring(2));
myUserName = json[1].userName;
} catch (e) { }
}
return originalSend.apply(this, arguments);
};
//PIXI hook
const originalDrawCircle = scope.PIXI.Graphics.prototype.drawCircle;
scope.PIXI.Graphics.prototype.drawCircle = function (...args) {
const radius = args[2];
const parent = this.parent;
setTimeout(() => {
if (parent && parent.visible) {
if (parent._bonkId === undefined) parent._bonkId = pixiObjectId++;
let foundName = null;
if (parent.children) {
for (let i = 0; i < parent.children.length; i++) {
const c = parent.children[i];
if (c && c._text) { foundName = c._text; break; }
}
}
if (foundName) {
if (!myUserName) {
try {
const topBar = window.parent.document.getElementById("maingameframe").contentWindow.document.getElementById("pretty_top_name");
if (topBar) myUserName = topBar.textContent.trim();
} catch (e) {
console.error(`Username Error: ${e}`);
}
}
if (myUserName && foundName.trim() === myUserName.trim()) {
myPlayerContainer = parent;
myPlayerID = parent._bonkId;
if (radius > 5 && radius < 60) currentPPM = radius;
}
}
}
}, 0);
return originalDrawCircle.apply(this, args);
};
function getGlobalTransform(obj) {
if (!obj || !obj.transform) return { x: 0, y: 0, rot: 0 };
obj.updateTransform();
const wt = obj.transform.worldTransform;
const globalPos = obj.getGlobalPosition();
return {
x: globalPos.x,
y: globalPos.y,
rot: Math.atan2(wt.b, wt.a)
};
}
document.addEventListener("keydown", (e) => {
if (e.code === CONFIG.KEY) isHoldingKey = true;
});
document.addEventListener("keyup", (e) => {
if (e.code === CONFIG.KEY) isHoldingKey = false;
});
const originalRAF = scope.requestAnimationFrame;
scope.requestAnimationFrame = function (callback) {
if (!arcGraphics && scope.PIXI) {
arcGraphics = new scope.PIXI.Graphics();
}
if (myPlayerContainer && myPlayerContainer.visible && myPlayerContainer.transform && arcGraphics) {
let currentAimer = null;
for (let i = 0; i < myPlayerContainer.children.length; i++) {
const c = myPlayerContainer.children[i];
if (c.constructor.name === 'e' || c.constructor.name === 'h') {
currentAimer = c;
break;
}
}
aimerChild = currentAimer;
const arrowActive = aimerChild && aimerChild.visible && aimerChild.alpha > 0.1;
if (isHoldingKey && arrowActive) {
if (!isCharging) {
isCharging = true;
chargeStartTime = Date.now();
}
const world = myPlayerContainer.parent;
if (world && arcGraphics.parent !== world) world.addChild(arcGraphics);
arcGraphics.clear();
arcGraphics.lineStyle(CONFIG.THICKNESS, CONFIG.COLOR, CONFIG.ALPHA);
const scale = currentPPM / BASE_RADIUS_PPM;
const G_term = PHYSICS.GRAVITY * scale;
const h = Math.min(((Date.now() - chargeStartTime) / 1000.0), CONFIG.MAX_CHARGE);
const V_total = (PHYSICS.VEL_MULT * h + PHYSICS.VEL_BASE) * scale;
const tf = getGlobalTransform(aimerChild);
const n = -tf.rot;
const cos_n = Math.cos(n);
const sin_n = Math.sin(n);
const startLocal = world.toLocal({ x: tf.x, y: tf.y });
arcGraphics.moveTo(startLocal.x, startLocal.y);
const dt = CONFIG.SIM_TIME / CONFIG.POINTS;
for (let i = 1; i <= CONFIG.POINTS; i++) {
const t = i * dt;
const dx = V_total * cos_n * t;
const dy = (V_total * sin_n * t) - (G_term * Math.pow(t, 2));
const pLoc = world.toLocal({
x: tf.x + dx,
y: tf.y - dy
});
arcGraphics.lineTo(pLoc.x, pLoc.y);
}
} else {
isCharging = false;
chargeStartTime = 0;
if (arcGraphics) arcGraphics.clear();
}
}
return originalRAF.call(scope, callback);
};
});
})();