r!PsAw Multibox public

optimised multibox (no precise aim & move to mouse for now)

  1. // ==UserScript==
  2. // @name r!PsAw Multibox public
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.5
  5. // @description optimised multibox (no precise aim & move to mouse for now)
  6. // @author r!PsAw
  7. // @match https://diep.io/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=diep.io
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. /*
  14. TODO-List:
  15. - finish importing world coordinates
  16. -> rework bot following other bots
  17. - add Player detection tracers
  18. - maybe add Tank upgrades option to auto upgrade to main tank
  19.  
  20. */
  21. //I do not recommend changing the code unless you understand it, since it might break
  22. //In this code player is the tank that is running this code and clone usually is the main tab
  23.  
  24. //let other scripts know that this one is active
  25. window.ripsaw_multibox = true;
  26. const ctx = canvas.getContext('2d');
  27. let you, him, inGame = false,
  28. connected = false;
  29.  
  30. function windowScaling() {
  31. const a = canvas.height / 1080;
  32. const b = canvas.width / 1920;
  33. return b < a ? a : b;
  34. }
  35.  
  36. function window_2_canvas(a) {
  37. let b = a * (canvas.width / window.innerWidth);
  38. return b;
  39. }
  40.  
  41. //options
  42. let key_option = ["WASD", "Arrows"];
  43. let mouse_modes = ["Copy", "Reversed"];
  44. let movement_modes = ["Clump", "Copy"];
  45. let repel_modes = ["long 50/50", "infinite 70/30", "infinity", "Necromancer"];
  46.  
  47. let config = {
  48. move_keys: key_option[0],
  49. copy_keys: false,
  50. copy_build: false,
  51. copy_mouse: false,
  52. movement_mode: movement_modes[0],
  53. mouse_mode: mouse_modes[0],
  54. afk: false,
  55. drone_repel: false,
  56. drone_repel_mode: repel_modes[0],
  57. };
  58.  
  59. //GUI logic (visual menu)
  60. function n2id(string) {
  61. return string.toLowerCase().replace(/ /g, "-");
  62. }
  63.  
  64. class El {
  65. constructor(
  66. name,
  67. type,
  68. el_color,
  69. width,
  70. height,
  71. opacity = "1",
  72. zindex = "100"
  73. ) {
  74. this.el = document.createElement(type);
  75. this.el.style.backgroundColor = el_color;
  76. this.el.style.width = width;
  77. this.el.style.height = height;
  78. this.el.style.opacity = opacity;
  79. this.el.style.zIndex = zindex;
  80. this.el.id = n2id(name);
  81. }
  82. setPosition(position, display, top, left, translate) {
  83. this.el.style.position = position;
  84. this.el.style.display = display;
  85. this.el.style.top = top;
  86. this.el.style.left = left;
  87. this.el.style.transform = "translate(" + translate + ")";
  88. this.display = display; //store last display
  89. }
  90. margin(top, left, right, bottom) {
  91. this.el.style.marginTop = top;
  92. this.el.style.marginLeft = left;
  93. this.el.style.marginRight = right;
  94. this.el.style.marginBottom = bottom;
  95. }
  96. setText(text, txt_color, font, fontsize, stroke, align) {
  97. this.el.innerHTML = text;
  98. this.el.style.color = txt_color;
  99. this.el.style.fontFamily = font;
  100. this.el.style.fontSize = fontsize;
  101. this.el.style.textShadow = stroke;
  102. this.el.style.textAlign = align;
  103. }
  104. add(parent) {
  105. parent.appendChild(this.el);
  106. }
  107. remove() {
  108. if (this.el.parentElement) {
  109. this.el.parentElement.removeChild(this.el);
  110. console.log("Element removed successfully.");
  111. } else {
  112. console.warn("Attempted to remove element, but it's not in the DOM.");
  113. }
  114. }
  115.  
  116. toggle(showOrHide) {
  117. switch (showOrHide) {
  118. case "hide":
  119. this.el.display = "none";
  120. break;
  121. case "show":
  122. this.el.display = this.display;
  123. break;
  124. }
  125. }
  126. }
  127.  
  128. class Setting {
  129. constructor(name, text, type, configsett, cycleArray = []) {
  130. this.sett = new El(name, "button", "Indigo", "100px", "60px", "0.75");
  131. this.sett.setPosition("relative", "block");
  132. this.sett.margin("20px", "10px", "10px", "20px");
  133. this.sett.setText(
  134. text,
  135. "white",
  136. "Lucida Console, Courier New, monospace",
  137. "15px",
  138. "0 0 2px gray",
  139. "center"
  140. );
  141. const element = this.sett.el; // Reference the DOM element
  142. element.onclick = () => {
  143. switch (type) {
  144. case "boolean":
  145. config[configsett] = !config[configsett];
  146. element.style.backgroundColor = config[configsett] ?
  147. "Navy" :
  148. "Indigo";
  149. break;
  150.  
  151. case "cycle": {
  152. const currentIndex = cycleArray.indexOf(config[configsett]);
  153. const nextIndex = (currentIndex + 1) % cycleArray.length;
  154. config[configsett] = cycleArray[nextIndex];
  155. element.innerHTML = `${text.split(":")[0]}: ${config[configsett]}`;
  156. }
  157. break;
  158.  
  159. default:
  160. console.error("Invalid setting type:", type);
  161. break;
  162. }
  163. };
  164. }
  165. add(parent) {
  166. this.sett.add(parent);
  167. }
  168. remove() {
  169. this.sett.remove();
  170. }
  171. toggle(showOrHide) {
  172. this.sett.toggle(showOrHide);
  173. }
  174. }
  175.  
  176. let gui_loaded = false;
  177. let hidden = false;
  178.  
  179. function load_GUI() {
  180. //define everything
  181. if (!gui_loaded) {
  182. let sett_classes = [];
  183.  
  184. let cont = new El("Mb Container", "div", "purple", "350px", "675x", "0.75");
  185. cont.setPosition("absolute", "block", "50%", "100%", "-50%, -50%");
  186.  
  187. let credit = new El(
  188. "credit Element",
  189. "div",
  190. "transparent",
  191. "150px",
  192. "25px",
  193. "0.75"
  194. );
  195. credit.setText(
  196. "Multibox by r!PsAw",
  197. "white",
  198. "Lucida Console, Courier New, monospace",
  199. "20px",
  200. "0 0 2px red",
  201. "center"
  202. );
  203. credit.setPosition("relative", "block");
  204.  
  205. let mk_setting = new Setting(
  206. "Move Keys",
  207. `Move Keys: ${config.move_keys}`,
  208. "cycle",
  209. "move_keys",
  210. key_option
  211. );
  212. sett_classes.push(mk_setting);
  213.  
  214. let ck_setting = new Setting(
  215. "Copy Keys",
  216. "Copy Keys",
  217. "boolean",
  218. "copy_keys"
  219. );
  220. sett_classes.push(ck_setting);
  221.  
  222. let cb_setting = new Setting(
  223. "Copy Build",
  224. "Copy Build",
  225. "boolean",
  226. "copy_build"
  227. );
  228. sett_classes.push(cb_setting);
  229.  
  230. let cm_setting = new Setting(
  231. "Copy Mouse",
  232. "Copy Mouse",
  233. "boolean",
  234. "copy_mouse"
  235. );
  236. sett_classes.push(cm_setting);
  237.  
  238.  
  239. let mvm_setting = new Setting(
  240. "Movement Mode",
  241. `Movement: ${config.movement_mode}`,
  242. "cycle",
  243. "movement_mode",
  244. movement_modes
  245. );
  246. sett_classes.push(mvm_setting);
  247.  
  248.  
  249. let mm_setting = new Setting(
  250. "Mouse Mode",
  251. `Mouse Mode: ${config.mouse_mode}`,
  252. "cycle",
  253. "mouse_mode",
  254. mouse_modes
  255. );
  256. sett_classes.push(mm_setting);
  257.  
  258. let afk_setting = new Setting("Afk", "Afk", "boolean", "afk");
  259. sett_classes.push(afk_setting);
  260.  
  261. let dr_setting = new Setting(
  262. "Drone Repel",
  263. "Repel Drones",
  264. "boolean",
  265. "drone_repel"
  266. );
  267. sett_classes.push(dr_setting);
  268.  
  269. let dm_setting = new Setting(
  270. "Drone Repel Modes",
  271. `Repel Mode: ${config.drone_repel_mode}`,
  272. "cycle",
  273. "drone_repel_mode",
  274. repel_modes
  275. );
  276. sett_classes.push(dm_setting);
  277. //load elements if unloaded
  278. cont.add(document.body);
  279. credit.add(cont.el);
  280. let l = sett_classes.length;
  281. for (let i = 0; i < l; i++) {
  282. sett_classes[i].add(cont.el);
  283. }
  284. gui_loaded = true;
  285. }
  286. }
  287.  
  288. //mouse
  289. function click_at(x, y, delay1 = 150) {
  290. input.onTouchStart(-1, x, y);
  291. setTimeout(() => {
  292. input.onTouchEnd(-1, x, y);
  293. }, delay1);
  294. }
  295.  
  296. function ghost_click_at(x, y, delay1 = 150) {
  297. input.onTouchStart(0, x, y);
  298. setTimeout(() => {
  299. input.onTouchEnd(0, x, y);
  300. }, delay1);
  301. }
  302.  
  303. function mouse_move(x, y) {
  304. input.onTouchMove(-1, x, y);
  305. }
  306.  
  307. //define keys
  308. const RAW_MAPPING = [
  309. "KeyA",
  310. "KeyB",
  311. "KeyC",
  312. "KeyD",
  313. "KeyE",
  314. "KeyF",
  315. "KeyG",
  316. "KeyH",
  317. "KeyI",
  318. "KeyJ",
  319. "KeyK",
  320. "KeyL",
  321. "KeyM",
  322. "KeyN",
  323. "KeyO",
  324. "KeyP",
  325. "KeyQ",
  326. "KeyR",
  327. "KeyS",
  328. "KeyT",
  329. "KeyU",
  330. "KeyV",
  331. "KeyW",
  332. "KeyX",
  333. "KeyY",
  334. "KeyZ",
  335. "ArrowUp",
  336. "ArrowLeft",
  337. "ArrowDown",
  338. "ArrowRight",
  339. "Tab",
  340. "Enter",
  341. "NumpadEnter",
  342. "ShiftLeft",
  343. "ShiftRight",
  344. "Space",
  345. "Numpad0",
  346. "Numpad1",
  347. "Numpad2",
  348. "Numpad3",
  349. "Numpad4",
  350. "Numpad5",
  351. "Numpad6",
  352. "Numpad7",
  353. "Numpad8",
  354. "Numpad9",
  355. "Digit0",
  356. "Digit1",
  357. "Digit2",
  358. "Digit3",
  359. "Digit4",
  360. "Digit5",
  361. "Digit6",
  362. "Digit7",
  363. "Digit8",
  364. "Digit9",
  365. "F2",
  366. "End",
  367. "Home",
  368. "Semicolon",
  369. "Comma",
  370. "NumpadComma",
  371. "Period",
  372. "Backslash",
  373. ]
  374.  
  375. function key_down(keyString) {
  376. const index = RAW_MAPPING.indexOf(keyString);
  377. if (index === -1) {
  378. console.error(`Invalid key string: ${keyString}`);
  379. return;
  380. }
  381. const result = index + 1; // Add 1 to the index as per your requirement
  382. input.onKeyDown(result);
  383. }
  384.  
  385. function key_up(keyString) {
  386. const index = RAW_MAPPING.indexOf(keyString);
  387. if (index === -1) {
  388. console.error(`Invalid key string: ${keyString}`);
  389. return;
  390. }
  391. const result = index + 1; // Add 1 to the index as per your requirement
  392. input.onKeyUp(result);
  393. }
  394.  
  395. function key_press(keyString, delay = 100) {
  396. key_down(keyString);
  397. setTimeout(() => {
  398. key_up(keyString)
  399. }, delay);
  400. }
  401.  
  402. //those are updating player.keys when the script executes them
  403. /*
  404. function script_key_down(keyString, player) {
  405. const index = RAW_MAPPING.indexOf(keyString);
  406. player.keys[index] = 1;
  407. //console.log(`index ${index} player.keys[index] ${player.keys[index]} keyString ${keyString}`);
  408. key_down(keyString);
  409. }
  410.  
  411. function script_key_up(keyString, player) {
  412. const index = RAW_MAPPING.indexOf(keyString);
  413. player.keys[index] = 0;
  414. //console.log(`index ${index} player.keys[index] ${player.keys[index]} keyString ${keyString}`);
  415. key_up(keyString);
  416. }
  417. */
  418.  
  419. //credits to mi300
  420. const ARENA_WIDTH = 26000;
  421. const ARENA_HEIGHT = 26000;
  422. let minimapArrow = [0, 0];
  423. let square_pos = [0, 0]
  424. let leaderArrow = [0, 0];
  425. let minimapPos = [0, 0];
  426. let minimapDim = [0, 0];
  427. let calls = 0;
  428. let points = [];
  429.  
  430. function hook(target, callback) {
  431.  
  432. function check() {
  433. window.requestAnimationFrame(check);
  434. if (window.arrows) {
  435. minimapArrow[0] = window.arrows[0][0];
  436. minimapArrow[1] = window.arrows[0][0];
  437. minimapPos[0] = window.arrows[2][0];
  438. minimapPos[1] = window.arrows[2][1];
  439. minimapDim[0] = window.arrows[3][0];
  440. minimapDim[1] = window.arrows[3][1];
  441. //console.warn("[r!PsAw] canceled!");
  442. //console.log(minimapArrow);
  443. return;
  444. }
  445. const func = CanvasRenderingContext2D.prototype[target]
  446.  
  447. if (func.toString().includes(target)) {
  448.  
  449. CanvasRenderingContext2D.prototype[target] = new Proxy(func, {
  450. apply(method, thisArg, args) {
  451. callback(thisArg, args)
  452.  
  453. return Reflect.apply(method, thisArg, args)
  454. }
  455. });
  456. }
  457. }
  458. window.requestAnimationFrame(check)
  459. }
  460.  
  461. hook('beginPath', function(thisArg, args) {
  462. calls = 1;
  463. points = [];
  464. });
  465. hook('moveTo', function(thisArg, args) {
  466. if (calls == 1) {
  467. calls += 1;
  468. points.push(args)
  469. } else {
  470. calls = 0;
  471. }
  472. });
  473. hook('lineTo', function(thisArg, args) {
  474. if (calls >= 2 && calls <= 6) {
  475. calls += 1;
  476. points.push(args)
  477. } else {
  478. calls = 0;
  479. }
  480. });
  481.  
  482.  
  483. function getCentre(vertices) {
  484. let centre = [0, 0];
  485. vertices.forEach(vertex => {
  486. centre[0] += vertex[0]
  487. centre[1] += vertex[1]
  488. });
  489. centre[0] /= vertices.length;
  490. centre[1] /= vertices.length;
  491. return centre;
  492. }
  493.  
  494. hook('fill', function(thisArg, args) {
  495. if (calls >= 4 && calls <= 6) {
  496. if (!window.M_X && thisArg.fillStyle === "#000000" && thisArg.globalAlpha > 0.9) {
  497. minimapArrow = getCentre(points);
  498. return;
  499. }
  500. } else {
  501. calls = 0;
  502. }
  503. });
  504.  
  505. hook('strokeRect', function(thisArg, args) {
  506. const t = thisArg.getTransform();
  507. minimapPos = [t.e, t.f];
  508. minimapDim = [t.a, t.d];
  509. });
  510.  
  511. //detect if focused
  512. let is_main = document.hasFocus();
  513.  
  514. function setFocusState(isFocused) {
  515. is_main = isFocused;
  516. }
  517. window.addEventListener('focus', () => setFocusState(true));
  518. window.addEventListener('blur', () => setFocusState(false));
  519.  
  520. //status(0) = is in game? status(1) = is connected? everything else returns null
  521. function status(type) {
  522. let s;
  523. switch (type) {
  524. case 0:
  525. s = extern.doesHaveTank() > 0;
  526. break
  527. case 1:
  528. s = !!window.lobby_ip;
  529. break
  530. }
  531. return s;
  532. }
  533.  
  534. //create ingame Notifications
  535. function rgbToNumber(r, g, b) {
  536. return (r << 16) | (g << 8) | b;
  537. }
  538. const notification_rbgs = {
  539. require: [255, 165, 0], //orange
  540. warning: [255, 0, 0], //red
  541. normal: [0, 0, 128] //blue
  542. }
  543.  
  544. let notifications = [];
  545.  
  546. function new_notification(text, color, duration) {
  547. input.inGameNotification(text, color, duration);
  548. }
  549.  
  550. function one_time_notification(text, color, duration){
  551. if(notifications.includes(text)){
  552. return;
  553. }
  554. if(!inGame){
  555. notifications = [];
  556. }else{
  557. new_notification(text, color, duration);
  558. notifications.push(text);
  559. }
  560. }
  561.  
  562. //FOV finder
  563. let FOV = 0.55;
  564. let fov_factors = [0.699, 0.8, 0.85, 0.899];
  565. let fov_tanks = {
  566. 0.699: ["Ranger"],
  567. 0.8: ["Assassin", "Stalker"],
  568. 0.85: ["Predator", "Streamliner", "Hunter"],
  569. 0.899: ["Sniper", "Overseer", "Overlord", "Necromancer", "Manager", "Trapper", "Gunner Trapper", "Overtrapper", "Mega Trapper", "Tri-Trapper", "Smasher", "Landmine", "Streamliner", "Auto Trapper", "Battleship", "Auto Smasher", "Spike", "Factory", "Skimmer", "Glider", "Rocketeer"]
  570. };
  571.  
  572. function find_fieldFactor(tank) {
  573. let fieldFactor = 1;
  574. let l = fov_factors.length;
  575. for (let i = 0; i < l; i++) {
  576. if (fov_tanks[fov_factors[i]].includes(tank)) {
  577. fieldFactor = fov_factors[i];
  578. }
  579. }
  580. return fieldFactor;
  581. }
  582.  
  583. function calculateFOV(Fv, l) {
  584. const numerator = 0.55 * Fv;
  585. const denominator = Math.pow(1.01, (l - 1) / 2);
  586. return (numerator / denominator);
  587. }
  588.  
  589. const crx = CanvasRenderingContext2D.prototype;
  590. let diepFont = "20"; //I'm just assigning some value to it here, so it's not null or undefined
  591. let sf = {
  592. autoFire: false,
  593. autoSpin: false
  594. };
  595.  
  596. //this function is for both main and slave tab
  597. function update_sf(state, f_or_s) {
  598. switch (state) {
  599. case " ON":
  600. sf[f_or_s] = true;
  601. break
  602. case " OFF":
  603. sf[f_or_s] = false;
  604. break
  605. }
  606. }
  607.  
  608.  
  609.  
  610. crx.fillText = new Proxy(crx.fillText, {
  611. apply: function(f, _this, args) {
  612. //detect Auto Spin & Auto Fire
  613. if (args[0] === "diep.io") {
  614. diepFont = _this.font.split("px")[0];
  615. }
  616. if (args[0].includes("Auto Fire: ") && _this.font.split("px")[0] === diepFont) {
  617. update_sf(args[0].split(':')[1], "autoFire");
  618. }
  619. if (args[0].includes("Auto Spin: ") && _this.font.split("px")[0] === diepFont) {
  620. update_sf(args[0].split(':')[1], "autoSpin");
  621. }
  622. //detect data for FOV
  623. if (args[0].startsWith("Lvl ") && inGame) {
  624. let words = args[0].split(" ");
  625. let level = words[1];
  626. let tank = words.slice(2).join(" ").trim();
  627. let fieldFactor = find_fieldFactor(tank);
  628. FOV = calculateFOV(fieldFactor, level);
  629. you.fov = FOV;
  630. console.log(`
  631. %c[r!PsAw Multibox] FOV value was changed, look :0
  632.  
  633. tank: ${tank}
  634. level: ${level}
  635. fieldFactor: ${fieldFactor}
  636. FOV: ${you.fov}
  637. `, "color: purple");
  638. }
  639.  
  640. f.apply(_this, args);
  641. }
  642. });
  643.  
  644. //share & recieve information across tabs
  645. /*
  646. keys index explanation:
  647. 0: 0 = undefined, 1 = wasd, 2 = arrow keys
  648. value 0 for unpressed and 1 for pressed:
  649. 1: rest_keys[0]
  650. 2: rest_keys[1]
  651. 3: rest_keys[2]
  652. 4: rest_keys[3]
  653. 5: Shift (Triggered by ShiftLeft, ShiftRight or Right Mouse click
  654. 6: Space (Triggered by Space and Left Mouse Click)
  655. 7: Backslash (since sandbox arena is unusual, it breaks the world coords system, so it won't be used for now)
  656. auto Fire & Auto Spin (0 for off and 1 for on):
  657. 8: Auto Fire
  658. 9: Auto Spin
  659.  
  660. This setup reduces number of transfered values from 64 to 10
  661. Because the build is stored in a different array
  662. */
  663. class Player {
  664. constructor() {
  665. this.pos_xy = new Uint16Array(2); //remake in world coords
  666. this.afk_xy = new Uint16Array(2); //remake in world coords
  667. this.mouse_xy = new Uint16Array(4); //last 2 should be world coords
  668. this.keys = new Uint8Array(10);
  669. this.build = new Uint8Array(33);
  670. this.windowSizes = new Uint16Array(2);
  671. this.minimapScale = new Uint16Array(4);
  672. this.fov = FOV;
  673. }
  674. }
  675.  
  676. function update_move_keys(player){
  677. let bool = 0;
  678. if(key_option.includes(config.move_keys)){
  679. bool = key_option.indexOf(config.move_keys)+1;
  680. }
  681. player.keys[0] = bool;
  682. //console.log(player.keys[0]);
  683. }
  684.  
  685. function update_build(player) {
  686. player.build.fill(0);
  687. let raw = extern.get_convar("game_stats_build");
  688. let temp_arr = [...raw];
  689. let l = temp_arr.length;
  690. for (let i = 0; i < l; i++) {
  691. player.build[i] = temp_arr[i];
  692. }
  693. }
  694.  
  695. /* OLD VERSION (with converter to 1/2/3/4/5/6/7/8)
  696. function update_build(player) {
  697. player.build.fill(0);
  698. let raw = extern.get_convar("game_stats_build");
  699. let temp_arr = [...raw];
  700. let l = temp_arr.length;
  701. for (let i = 0; i < l; i++) {
  702. let increase_index = parseFloat(temp_arr[i]);
  703. player.build[increase_index - 1]++;
  704. }
  705. }
  706. */
  707.  
  708. function update_pos(player) {
  709. player.pos_xy[0] = Math.floor(minimapArrow[0]);
  710. player.pos_xy[1] = Math.floor(minimapArrow[1]);
  711. //console.log(player.pos_xy);
  712. }
  713.  
  714. function update_minimap_Scale(player) {
  715. player.minimapScale[0] = minimapPos[0];
  716. player.minimapScale[1] = minimapPos[1];
  717. player.minimapScale[2] = minimapDim[0];
  718. player.minimapScale[3] = minimapDim[1];
  719. }
  720.  
  721. function update_window_sizes(player) {
  722. player.windowSizes[0] = window.innerWidth;
  723. player.windowSizes[1] = window.innerHeight;
  724. }
  725.  
  726. function save_sf(player){
  727. player.keys[8] = sf.autoFire?1:0;
  728. player.keys[9] = sf.autoSpin?1:0;
  729. //console.log(player.keys);
  730. }
  731.  
  732. function save_info(player) {
  733. localStorage.setItem("Multibox Player", JSON.stringify(player));
  734. }
  735.  
  736. function get_info() {
  737. return JSON.parse(localStorage.getItem("Multibox Player"));
  738. }
  739.  
  740. //define some values
  741. let wasd = ["KeyW", "KeyA", "KeyS", "KeyD"];
  742. let arrows = ["ArrowUp", "ArrowLeft", "ArrowDown", "ArrowRight"];
  743. let build_keys = [
  744. "KeyU",
  745. "KeyM",
  746. "Numpad1",
  747. "Numpad2",
  748. "Numpad3",
  749. "Numpad4",
  750. "Numpad5",
  751. "Numpad6",
  752. "Numpad7",
  753. "Numpad8",
  754. "Digit1",
  755. "Digit2",
  756. "Digit3",
  757. "Digit4",
  758. "Digit5",
  759. "Digit6",
  760. "Digit7",
  761. "Digit8", ];
  762.  
  763. function move_keys() {
  764. switch (config.move_keys) {
  765. case "WASD":
  766. return wasd;
  767. break
  768. case "Arrows":
  769. return arrows;
  770. break
  771. }
  772. }
  773.  
  774. function rest_keys() { //opposite to move_keys
  775. switch(config.move_keys){
  776. case "WASD":
  777. return arrows;
  778. break
  779. case "Arrows":
  780. return wasd;
  781. break
  782. }
  783. }
  784.  
  785. //copy clone values
  786.  
  787. function copy_key_inputs(player) {
  788. //OLD
  789. /*
  790. for (let i = 0; i < RAW_MAPPING.length; i++) {
  791. const keyString = RAW_MAPPING[i];
  792. if (!keyString) {
  793. console.error(`Invalid keyString at index ${i}`);
  794. continue;
  795. }
  796.  
  797. switch (player.keys[i]) {
  798. case 0:
  799. if (!rest_keys().includes(keyString) && !build_keys.includes(keyString)) { //DO NOT copy wasd/arrow keys OR build keys
  800. key_up(keyString);
  801. }
  802. break;
  803. case 1:
  804. if (!rest_keys().includes(keyString) && !build_keys.includes(keyString)) { //DO NOT copy wasd/arrow keys OR build keys
  805. key_down(keyString);
  806. //console.log(keyString);
  807. }
  808. break;
  809. default:
  810. console.error(`Unexpected value for player.keys[${i}]: ${player.keys[i]}`);
  811. }
  812. }
  813. */
  814. //NEW
  815. for(let i = 1; i < 8; i++){
  816. copy_key_sub_func(i, player);
  817. }
  818. }
  819.  
  820. function copy_key_sub_func(index, player){
  821. if(index < 5 && config.movement_mode != "Copy"){
  822. return;
  823. }
  824. let mk = move_keys();
  825. let allowed_keys = [mk[0], mk[1], mk[2], mk[3], "ShiftLeft", "Space", "Backslash"];
  826. let key = allowed_keys[index-1];
  827. if(player.keys[index] === 0){
  828. key_up(key);
  829. }else{
  830. key_down(key);
  831. }
  832. }
  833.  
  834. //scaling from window to window
  835. function scaleCoordinates(sourceX, sourceY, sourceWidth, sourceHeight, targetWidth, targetHeight) {
  836. // Scale factors for width and height
  837. const scaleX = targetWidth / sourceWidth;
  838. const scaleY = targetHeight / sourceHeight;
  839.  
  840. // Scale the coordinates
  841. const scale = Math.min(scaleX, scaleY);
  842. const targetX = sourceX * scale;
  843. const targetY = sourceY * scale;
  844.  
  845.  
  846. return {
  847. x: targetX,
  848. y: targetY
  849. };
  850. }
  851.  
  852. //copy mouse coords
  853. function get_invert_mouse_coords(x, y, width, height) {
  854. let center = {
  855. x: width / 2,
  856. y: height / 2
  857. };
  858. let d = {
  859. x: x - center.x,
  860. y: y - center.y
  861. };
  862. let inverted_coords = {
  863. x: center.x - d.x,
  864. y: center.y - d.y
  865. };
  866. return inverted_coords;
  867. }
  868.  
  869. function copy_mouse_inputs(player, clone) {
  870. console.log("copying inputs");
  871. switch (config.mouse_mode) {
  872. case "Copy": {
  873. console.log("Copy");
  874. let final = scaleCoordinates(clone.mouse_xy[0], clone.mouse_xy[1], clone.windowSizes[0], clone.windowSizes[1], player.windowSizes[0], player.windowSizes[1]);
  875. console.log(final);
  876. mouse_move(final.x, final.y);
  877. }
  878. break
  879. case "Reversed": { //haven't tested yet
  880. let modified = get_invert_mouse_coords(clone.mouse_xy[0], clone.mouse_xy[1], clone.windowSizes[0], clone.windowSizes[1]);
  881. let final = scaleCoordinates(modified.x, modified.y, clone.windowSizes[0], clone.windowSizes[1], player.windowSizes[0], player.windowSizes[1]);
  882. mouse_move(final.x, final.y);
  883. }
  884. break
  885. }
  886. }
  887.  
  888. //update your values
  889. //const KEY_MAP = new Map(RAW_MAPPING.map((key, index) => [key, index]));
  890. window.addEventListener('keydown', function(e) {
  891. //OLD
  892. /*
  893. if (connected && inGame && is_main) {
  894. if (move_keys().includes(e.code) || build_keys.includes(e.code)) {
  895. return; //don't copy wasd/arrows or build keys
  896. }
  897. if (e.code === "KeyQ") {
  898. hidden = !hidden;
  899. toggle_GUI(hidden);
  900. }
  901. let index = KEY_MAP.get(e.code);
  902. if (index !== undefined) {
  903. you.keys[index] = 1;
  904. //console.log(`pressed ${e.code} status ${you.keys[index]} index ${index}`);
  905. }
  906. }
  907. */
  908. //NEW
  909. if (connected && is_main) {
  910. if (e.code === "KeyQ") {
  911. hidden = !hidden;
  912. toggle_GUI(hidden);
  913. }
  914. if(inGame){
  915. if(move_keys().includes(e.code)){
  916. let index = move_keys().indexOf(e.code);
  917. you.keys[index+1] = 1;
  918. //console.log(you.keys);
  919. }
  920. if(rest_keys().includes(e.code)){
  921. let rest_move = ["W, A, S, D", "Arrow Keys"];
  922. if(rest_keys()[0] === "KeyW"){
  923. new_notification(`Warning, you are using ${rest_move[0]}, use ${rest_move[1]} instead OR change your move keys to ${rest_move[0]}`, rgbToNumber(243, 185, 26), 5000);
  924. }else{
  925. new_notification(`Warning, you are using ${rest_move[1]}, use ${rest_move[0]} instead OR change your move keys to ${rest_move[1]}`, rgbToNumber(243, 185, 26), 5000);
  926. }
  927. }
  928. if(e.code === "Space"){
  929. you.keys[6] = 1;
  930. //console.log(you.keys);
  931. }
  932. if(e.code === "ShiftLeft" || e.code === "ShiftRight"){
  933. you.keys[5] = 1;
  934. //console.log(you.keys);
  935. }
  936. if(e.code === "Backslash"){
  937. you.keys[7] = 1;
  938. //console.log(you.keys);
  939. }
  940. }
  941. }
  942. });
  943.  
  944. window.addEventListener('keyup', function(e) {
  945. //OLD
  946. /*
  947. if (connected && inGame && is_main) {
  948. let index = KEY_MAP.get(e.code);
  949. if (index !== undefined) {
  950. you.keys[index] = 0;
  951. //console.log(`unpressed ${e.code} status ${you.keys[index]} index ${index}`);
  952. }
  953. }
  954. */
  955. //NEW
  956. if (connected && inGame && is_main) {
  957. if(move_keys().includes(e.code)){
  958. let index = move_keys().indexOf(e.code);
  959. you.keys[index+1] = 0;
  960. //console.log(you.keys);
  961. }
  962. if(e.code === "Space"){
  963. you.keys[6] = 0;
  964. //console.log(you.keys);
  965. }
  966. if(e.code === "ShiftLeft" || e.code === "ShiftRight"){
  967. you.keys[5] = 0;
  968. //console.log(you.keys);
  969. }
  970. if(e.code === "Backslash"){
  971. you.keys[7] = 0;
  972. //console.log(you.keys);
  973. }
  974. }
  975. });
  976.  
  977. window.addEventListener('mousemove', function(e) {
  978. if (connected && inGame && is_main) {
  979. you.mouse_xy[0] = e.clientX;
  980. you.mouse_xy[1] = e.clientY;
  981. //console.log(you.mouse_xy);
  982. }
  983. });
  984.  
  985. window.addEventListener("mousedown", function(e) {
  986. if (connected && inGame && is_main) {
  987. if (e.button === 0){
  988. you.keys[6] = 1;
  989. //console.log(you.keys);
  990. }
  991. if (e.button === 2) {
  992. you.keys[5] = 1;
  993. //console.log(you.keys);
  994. }
  995. }
  996. });
  997.  
  998. window.addEventListener("mouseup", function(e) {
  999. if (connected && inGame && is_main) {
  1000. if (e.button === 0){
  1001. you.keys[6] = 0;
  1002. //console.log(you.keys);
  1003. }
  1004. if (e.button === 2) {
  1005. you.keys[5] = 0;
  1006. //console.log(you.keys);
  1007. }
  1008. }
  1009. });
  1010.  
  1011. //copy build
  1012. function read_build(player) {
  1013. let buildStr = "";
  1014. for (let i = 0; i < 33; i++) {
  1015. if (player.build[i] === 0) {
  1016. break
  1017. }
  1018. buildStr += player.build[i];
  1019. }
  1020. return buildStr;
  1021. }
  1022.  
  1023. function copy_build(string) {
  1024. extern.execute(`game_stats_build ${string}`);
  1025. }
  1026.  
  1027. //AFK logic
  1028. let moving = false;
  1029. let goal = {
  1030. x: 0,
  1031. y: 0
  1032. };
  1033.  
  1034. function set_goal(x, y) {
  1035. goal.x = x;
  1036. goal.y = y;
  1037. }
  1038.  
  1039. function move_to_goal(player) {
  1040. if (config.afk) {
  1041. if (player.pos_xy[0] > goal.x) {
  1042. key_up(rest_keys()[3]);
  1043. key_down(rest_keys()[1]);
  1044. } else {
  1045. key_up(rest_keys()[1]);
  1046. key_down(rest_keys()[3]);
  1047. }
  1048. if (player.pos_xy[1] > goal.y) {
  1049. key_up(rest_keys()[2]);
  1050. key_down(rest_keys()[0]);
  1051. } else {
  1052. key_up(rest_keys()[0]);
  1053. key_down(rest_keys()[2]);
  1054. }
  1055. moving = true;
  1056. } else {
  1057. if (moving) {
  1058. for (let i = 0; i < rest_keys().length; i++) {
  1059. key_up(rest_keys()[i]);
  1060. }
  1061. moving = false;
  1062. }
  1063. set_goal(player.pos_xy[0], player.pos_xy[1]);
  1064. }
  1065. }
  1066.  
  1067. //Tank Clump (enabled when copy keys enabled)
  1068. let debug = [
  1069. 0,
  1070. 0,
  1071. 0,
  1072. 0
  1073. ];
  1074.  
  1075. function scale_minimap(PlayerInfo, CloneInfo) {
  1076. //NOTE: This is only possible, because minimap is a square
  1077.  
  1078. //player
  1079. let pos1 = {
  1080. x: PlayerInfo[0],
  1081. y: PlayerInfo[1]
  1082. };
  1083. let m_pos1 = {
  1084. x: PlayerInfo[2],
  1085. y: PlayerInfo[3]
  1086. };
  1087. let m_dim1 = {
  1088. w: PlayerInfo[4],
  1089. h: PlayerInfo[5]
  1090. };
  1091. console.log("PlayerInfo");
  1092. console.log(PlayerInfo);
  1093.  
  1094. //clone
  1095. let pos2 = {
  1096. x: CloneInfo[0],
  1097. y: CloneInfo[1]
  1098. };
  1099. let m_pos2 = {
  1100. x: CloneInfo[2],
  1101. y: CloneInfo[3]
  1102. };
  1103. let m_dim2 = {
  1104. w: CloneInfo[4],
  1105. h: CloneInfo[5]
  1106. };
  1107. console.log("CloneInfo");
  1108. console.log(CloneInfo);
  1109.  
  1110. //translate clone coords into player coords
  1111. let distance_2_mpos = {
  1112. x: pos2.x - m_pos2.x,
  1113. y: pos2.y - m_pos2.y
  1114. };
  1115. let calc_percentage = {
  1116. x: (distance_2_mpos.x / m_dim2.w) * 100,
  1117. y: (distance_2_mpos.y / m_dim2.h) * 100
  1118. };
  1119.  
  1120. //use % from clone and transfer to player
  1121. let scaled_clone = {
  1122. x: m_pos1.x + (m_dim1.w / 100 * calc_percentage.x),
  1123. y: m_pos1.y + (m_dim1.h / 100 * calc_percentage.y)
  1124. }
  1125. debug[0] = window_2_canvas(pos1.x);
  1126. debug[1] = window_2_canvas(pos1.y);
  1127. debug[2] = window_2_canvas(scaled_clone.x);
  1128. debug[3] = window_2_canvas(scaled_clone.y);
  1129. return scaled_clone;
  1130. }
  1131.  
  1132. function clump(player, clone) {
  1133. if (config.copy_keys && config.movement_mode === "Clump") {
  1134. if(config.afk){
  1135. one_time_notification("Disabled Clump since you have afk on :)", rgbToNumber(243, 185, 26), 5000);
  1136. if (moving) {
  1137. for (let i = 0; i < move_keys().length; i++) {
  1138. script_key_up(move_keys()[i], player);
  1139. }
  1140. moving = false;
  1141. }
  1142. return;
  1143. }
  1144.  
  1145. let scaled_clone = scale_minimap([
  1146. player.pos_xy[0], player.pos_xy[1],
  1147. player.minimapScale[0], player.minimapScale[1],
  1148. player.minimapScale[2], player.minimapScale[3]
  1149. ], [
  1150. clone.pos_xy[0], clone.pos_xy[1],
  1151. clone.minimapScale[0], clone.minimapScale[1],
  1152. clone.minimapScale[2], clone.minimapScale[3]
  1153. ]);
  1154. console.log(`
  1155. you ${player.pos_xy}
  1156. clone ${scaled_clone.x} ${scaled_clone.y}
  1157. 1st cond ${player.pos_xy[0] > scaled_clone.x}
  1158. 2nd cond ${player.pos_xy[1] > scaled_clone.y}
  1159. `);
  1160.  
  1161. if (player.pos_xy[0] > scaled_clone.x) {
  1162. key_up(rest_keys()[3]);
  1163. key_down(rest_keys()[1]);
  1164. } else {
  1165. key_up(rest_keys()[1]);
  1166. key_down(rest_keys()[3]);
  1167. }
  1168. if (player.pos_xy[1] > scaled_clone.y) {
  1169. key_up(rest_keys()[2]);
  1170. key_down(rest_keys()[0]);
  1171. } else {
  1172. key_up(rest_keys()[0]);
  1173. key_down(rest_keys()[2]);
  1174. }
  1175. moving = true;
  1176. } else {
  1177. if (moving) {
  1178. for (let i = 0; i < move_keys().length; i++) {
  1179. key_up(move_keys()[i]);
  1180. }
  1181. moving = false;
  1182. }
  1183. set_goal(player.pos_xy[0], player.pos_xy[1]);
  1184. }
  1185. }
  1186.  
  1187. //toggle GUI
  1188. function toggle_GUI(state) {
  1189. let cont = document.getElementById("mb-container");
  1190. if (state) {
  1191. cont.style.display = "none";
  1192. } else {
  1193. cont.style.display = "block";
  1194. }
  1195. }
  1196.  
  1197. //Drone Repel
  1198. let timings = { //long 50/50 by default
  1199. main: 50000,
  1200. inside: 25000
  1201. }
  1202.  
  1203. let reset_finished = false;
  1204.  
  1205. function repel_loop() {
  1206. if (inGame && config.drone_repel) {
  1207. reset_finished = false;
  1208. key_down("ShiftLeft");
  1209. setTimeout(() => {
  1210. key_up("ShiftLeft");
  1211. }, timings.inside);
  1212. } else {
  1213. if (!reset_finished) {
  1214. key_up("ShiftLeft");
  1215. reset_finished = true;
  1216. }
  1217. }
  1218. }
  1219. setInterval(repel_loop, timings.main);
  1220.  
  1221. function update_timings() {
  1222. switch (config.drone_repel_mode) {
  1223. case "long 50/50":
  1224. timings.main = 50000;
  1225. timings.inside = 25000;
  1226. break
  1227. case "infinite 70/30":
  1228. timings.main = 10000;
  1229. timings.inside = 7000;
  1230. break
  1231. case "infinity":
  1232. timings.main = 100000;
  1233. timings.inside = 99999;
  1234. break
  1235. case "Necromancer":
  1236. timings.main = 50000;
  1237. timings.inside = 20000;
  1238. break
  1239. }
  1240. }
  1241.  
  1242. //replace move keys of every clone to your main move keys
  1243. function new_move_keys(player, clone){
  1244. if(player.keys[0] != clone.keys[0]){
  1245. let btn = document.getElementById("move-keys");
  1246. let index = clone.keys[0]-1;
  1247. config.move_keys = key_option[index];
  1248. btn.innerHTML = `Move Keys: ${key_option[index]}`;
  1249. }
  1250. }
  1251.  
  1252. //this loop will handle your auto fire + auto spin, separately from init
  1253. function handle_sf(){
  1254. if(connected && inGame && config.copy_keys){
  1255. if(!is_main){
  1256. if(you.keys[8] != him.keys[8]){
  1257. key_press("KeyE");
  1258. you.keys[8] = him.keys[8];
  1259. }
  1260. if(you.keys[9] != him.keys[9]){
  1261. key_press("KeyC");
  1262. you.keys[9] = him.keys[9];
  1263. }
  1264. }
  1265. }
  1266. }
  1267.  
  1268. setInterval(handle_sf, 2500);
  1269.  
  1270. //initialise (I luv this shit)
  1271. function init() {
  1272. window.requestAnimationFrame(init);
  1273. inGame = status(0);
  1274. connected = status(1);
  1275. if (connected) {
  1276. if (!you) {
  1277. you = new Player();
  1278. console.log("%c[r!PsAw] Player found, reading info for multibox... ^w^", "color: green");
  1279. }
  1280. load_GUI();
  1281. if (inGame) {
  1282. update_move_keys(you);
  1283. update_build(you);
  1284. update_window_sizes(you);
  1285. update_minimap_Scale(you);
  1286. update_pos(you);
  1287. move_to_goal(you);
  1288. update_timings();
  1289. if (is_main) {
  1290. save_sf(you);
  1291. save_info(you);
  1292. } else {
  1293. him = get_info();
  1294. if (config.copy_keys) {
  1295. copy_key_inputs(him);
  1296. clump(you, him);
  1297. }
  1298. new_move_keys(you, him);
  1299. config.copy_build ? copy_build(read_build(him)) : null;
  1300. config.copy_mouse ? copy_mouse_inputs(you, him) : null;
  1301. }
  1302. }else{
  1303. update_sf(" OFF", "autoFire");
  1304. update_sf(" OFF", "autoSpin");
  1305. }
  1306. }
  1307. }
  1308. window.requestAnimationFrame(init);
  1309.  
  1310. //canvas debug
  1311.  
  1312. setTimeout(() => {
  1313. let gui = () => {
  1314. if (!is_main) {
  1315. ctx.beginPath();
  1316. ctx.moveTo(debug[0], debug[1]);
  1317. ctx.lineTo(debug[2], debug[3]);
  1318. ctx.strokeStyle = "black";
  1319. ctx.stroke();
  1320. }
  1321. window.requestAnimationFrame(gui);
  1322. };
  1323. gui();
  1324. setTimeout(() => {
  1325. gui();
  1326. }, 5000);
  1327. }, 1000);