Mobile Mode - Bonk.io

Allows you to use bonk.io on mobile devices

  1. // ==UserScript==
  2. // @name Mobile Mode - Bonk.io
  3. // @namespace left paren
  4. // @match https://bonk.io/gameframe-release.html
  5. // @grant none
  6. // @version 1.0
  7. // @author left paren
  8. // @license The Unlicense
  9. // @description Allows you to use bonk.io on mobile devices
  10.  
  11. // ==/UserScript==
  12. window.top.document.head.innerHTML += '<meta name="viewport" content="width=1200px, maximum-scale=0.5">'
  13. function kill(el) {
  14. el.style.top = el.style.left = el.style.width = el.style.height = "0px"
  15. }
  16.  
  17. kill(window.top.document.getElementById("adboxverticalCurse"))
  18. kill(window.top.document.getElementById("adboxverticalleftCurse"))
  19.  
  20. window.top.document.body.style.width = "1420px"
  21. window.top.document.body.style.height = 1420*(window.screen.availHeight / window.screen.availWidth) + "px"
  22. window.top.document.body.style.transformOrigin = "top left"
  23. window.top.document.body.style.overflow = "hidden"
  24.  
  25. /**
  26. * Simulate a key event.
  27. * @param {Number} keyCode The keyCode of the key to simulate
  28. * @param {String} type (optional) The type of event : down, up or press. The default is down
  29. * @param {Object} modifiers (optional) An object which contains modifiers keys { ctrlKey: true, altKey: false, ...}
  30. */
  31. function simulateKey (keyCode, type, modifiers) {
  32. var evtName = (typeof(type) === "string") ? "key" + type : "keydown";
  33. var modifier = (typeof(modifiers) === "object") ? modifier : {};
  34.  
  35. var event = document.createEvent("HTMLEvents");
  36. event.initEvent(evtName, true, false);
  37. event.keyCode = keyCode;
  38.  
  39. for (var i in modifiers) {
  40. event[i] = modifiers[i];
  41. }
  42.  
  43. document.dispatchEvent(event);
  44. }
  45.  
  46. var up = 38
  47. var down = 40
  48. var left = 37
  49. var right = 39
  50. var heavy = 88
  51. var special = 17
  52. var enter = 13
  53.  
  54. function addButton(key, x, y, text) {
  55. var button = document.createElement("div")
  56. button.innerText = text
  57. if (typeof key == "number") {
  58. button.addEventListener("touchstart", ()=>{simulateKey(key, "down")})
  59. button.addEventListener("touchend", ()=>{simulateKey(key, "up")})
  60. } else {
  61. button.addEventListener("click", key)
  62. }
  63. button.style.position = "fixed"
  64. button.style.bottom = y
  65. button.style.left = x
  66. button.style.lineHeight = "100px"
  67. button.style.fontSize = "50px"
  68. button.classList = "brownButton brownButton_classic buttonShadow"
  69. button.style.width = button.style.height = "100px"
  70. document.body.append(button)
  71. return button
  72. }
  73.  
  74. function clamp(x, min, max) {
  75. if (x < min) return min
  76. if (x > max) return max
  77. return x
  78. }
  79.  
  80. joystick = {
  81. currentKeys: {
  82. up: false,
  83. down: false,
  84. left: false,
  85. right: false
  86. },
  87. applyKeys: function() {
  88. simulateKey(up, joystick.currentKeys.up?"down":"up")
  89. simulateKey(down, joystick.currentKeys.down?"down":"up")
  90. simulateKey(left, joystick.currentKeys.left?"down":"up")
  91. simulateKey(right, joystick.currentKeys.right?"down":"up")
  92. },
  93. /**
  94. *
  95. * @param {TouchEvent} e
  96. */
  97. move: function(e) {
  98. var touch = e.touches.item(0)
  99. var elBox = joystick.el.getBoundingClientRect()
  100. var relative = {
  101. x: (touch.clientX - elBox.left) / (elBox.width / 2) - 1,
  102. y: (touch.clientY - elBox.top) / (elBox.height / 2) - 1,
  103. }
  104. joystick.handleAtVector(relative.x, relative.y)
  105. },
  106. end: function(e) {
  107. joystick.handleAtVector(0, 0)
  108. },
  109. handleAtVector(x, y) {
  110. console.log([x, y])
  111. joystick.el.style.transform = `perspective(1000px) rotate3d(${clamp(-y, -1, 1)}, ${clamp(x, -1, 1)}, 0, 15deg)`
  112. joystick.currentKeys.up = y<-0.6
  113. joystick.currentKeys.down = y>0.6
  114. joystick.currentKeys.left = x<-0.6
  115. joystick.currentKeys.right = x>0.6
  116. joystick.applyKeys()
  117. },
  118. /** @type {HTMLDivElement} */
  119. el: undefined
  120. }
  121.  
  122.  
  123. joystick.el = document.createElement("div")
  124. joystick.el.addEventListener("touchstart", joystick.move)
  125. joystick.el.addEventListener("touchmove", joystick.move)
  126. joystick.el.addEventListener("touchend", joystick.end)
  127. joystick.el.style.position = "fixed"
  128. joystick.el.style.bottom = "10px"
  129. joystick.el.style.right = "10px"
  130. joystick.el.style.opacity = "30%"
  131. joystick.el.style.transformOrigin = "center"
  132. joystick.el.style.backgroundBlendMode = "multiply"
  133. joystick.el.style.backgroundSize = "cover"
  134. joystick.el.style.backgroundImage = "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAABHNCSVQICAgIfAhkiAAACfRJREFUeF7t1sFtHEEMAEHbUFgb/kahZGw/7AgIEMdG6b+YYXHUuJ+///798PfRAu/7fvT9Kpd7nqcySnaOX9nJDEaAQE5AsHIrNRCBroBgdXdrMgI5AcHKrdRABLoCgtXdrckI5AQEK7dSAxHoCghWd7cmI5ATEKzcSg1EoCsgWN3dmoxATkCwcis1EIGugGB1d2syAjkBwcqt1EAEugKC1d2tyQjkBAQrt1IDEegKCFZ3tyYjkBMQrNxKDUSgKyBY3d2ajEBOQLByKzUQga6AYHV3azICOQHByq3UQAS6AoLV3a3JCOQEBCu3UgMR6AoIVne3JiOQExCs3EoNRKArIFjd3ZqMQE5AsHIrNRCBroBgdXdrMgI5AcHKrdRABLoCgtXdrckI5AQEK7dSAxHoCghWd7cmI5ATEKzcSg1EoCsgWN3dmoxATkCwcis1EIGugGB1d2syAjkBwcqt1EAEugKC1d2tyQjkBAQrt1IDEegKCFZ3tyYjkBMQrNxKDUSgKyBY3d2ajEBOQLByKzUQga6AYHV3azICOQHByq3UQAS6AoLV3a3JCOQEBCu3UgMR6AoIVne3JiOQExCs3EoNRKArIFjd3ZqMQE5AsHIrNRCBroBgdXdrMgI5AcHKrdRABLoCgtXdrckI5AQEK7dSAxHoCghWd7cmI5ATEKzcSg1EoCsgWN3dmoxATkCwcis1EIGugGB1d2syAjkBwcqt1EAEugKC1d2tyQjkBAQrt1IDEegKCFZ3tyYjkBMQrNxKDUSgKyBY3d2ajEBOQLByKzUQga6AYHV3azICOQHByq3UQAS6AoLV3a3JCOQEBCu3UgMR6AoIVne3JiOQExCs3EoNRKArIFjd3ZqMQE5AsHIrNRCBroBgdXdrMgI5AcHKrdRABLoCgtXdrckI5AQEK7dSAxHoCghWd7cmI5ATEKzcSg1EoCsgWN3dmoxATkCwcis1EIGugGB1d2syAjkBwcqt1EAEugKC1d2tyQjkBAQrt1IDEegKCFZ3tyYjkBMQrNxKDUSgKyBY3d2ajEBOQLByKzUQga6AYHV3azICOQHByq3UQAS6AoLV3a3JCOQEBCu3UgMR6AoIVne3JiOQExCs3EoNRKArIFjd3ZqMQE5AsHIrNRCBroBgdXdrMgI5AcHKrdRABLoCgtXdrckI5AQEK7dSAxHoCghWd7cmI5ATEKzcSg1EoCvw9b5vd7rIZN/f35FJjEFgJuAX1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAoI1iK2owgQmAkI1szP1wQILAp8Pc+zeJyjCHyugP+Fz93N/5v5hfX5O3JDAgT+CQiWp0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAoJ1ZlUuSoCAYHkDBAicERCsM6tyUQIEBMsbIEDgjIBgnVmVixIgIFjeAAECZwQE68yqXJQAAcHyBggQOCMgWGdW5aIECAiWN0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAoJ1ZlUuSoCAYHkDBAicERCsM6tyUQIEBMsbIEDgjIBgnVmVixIgIFjeAAECZwQE68yqXJQAAcHyBggQOCMgWGdW5aIECAiWN0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAoJ1ZlUuSoCAYHkDBAicERCsM6tyUQIEBMsbIEDgjIBgnVmVixIgIFjeAAECZwQE68yqXJQAAcHyBggQOCMgWGdW5aIECAiWN0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAoJ1ZlUuSoCAYHkDBAicERCsM6tyUQIEBMsbIEDgjIBgnVmVixIgIFjeAAECZwQE68yqXJQAAcHyBggQOCMgWGdW5aIECAiWN0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAoJ1ZlUuSoCAYHkDBAicERCsM6tyUQIEBMsbIEDgjIBgnVmVixIgIFjeAAECZwQE68yqXJQAAcHyBggQOCMgWGdW5aIECAiWN0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAoJ1ZlUuSoCAYHkDBAicERCsM6tyUQIEBMsbIEDgjIBgnVmVixIgIFjeAAECZwQE68yqXJQAAcHyBggQOCMgWGdW5aIECAiWN0CAwBkBwTqzKhclQECwvAECBM4ICNaZVbkoAQKC5Q0QIHBGQLDOrMpFCRAQLG+AAIEzAn8ARK4Pmm9m298AAAAASUVORK5CYII=)"
  135. joystick.el.classList = "brownButton brownButton_classic buttonShadow"
  136. joystick.el.style.width = joystick.el.style.height = "380px"
  137. document.body.append(joystick.el)
  138.  
  139. fullscreenButton = document.createElement("div")
  140. fullscreenButton.innerText = "⛶"
  141. fullscreenButton.addEventListener("click", ()=>{window.top.document.documentElement.requestFullscreen()})
  142. fullscreenButton.style.position = "fixed"
  143. fullscreenButton.style.top =
  144. fullscreenButton.style.right = "10px"
  145. fullscreenButton.style.lineHeight = "100px"
  146. fullscreenButton.style.fontSize = "50px"
  147. fullscreenButton.classList = "brownButton brownButton_classic buttonShadow"
  148. fullscreenButton.style.width = fullscreenButton.style.height = "100px"
  149. document.body.append(fullscreenButton)
  150.  
  151. joystick.special = addButton(special, "10px", "10px", "Z")
  152. joystick.heavy = addButton(heavy, "120px", "10px", "X")
  153. addButton(()=>{}, "10px", "120px", "💬").addEventListener("touchend", ()=>{
  154. setTimeout(()=>{
  155. var ingame = document.getElementById("gamerenderer").style.visibility == "inherit"
  156. if (ingame) {
  157. document.getElementById("gamerenderer").focus()
  158. simulateKey(enter, "down")
  159. } else {
  160. document.getElementById("newbonklobby_chat_input").focus()
  161. document.getElementById("newbonklobby_chat_lowerinstruction").style.visibility = "hidden"
  162. }
  163. }, 100)
  164. })
  165. function handleAnimFrame() {
  166. requestAnimationFrame(handleAnimFrame);
  167.  
  168. //joystick
  169. var ingame = document.getElementById("gamerenderer").style.visibility == "inherit"
  170. joystick.el.style.display =
  171. joystick.special.style.display =
  172. joystick.heavy.style.display = ingame ? "block" : "none"
  173. if (ingame) joystick.applyKeys()
  174.  
  175. // gamepad support
  176. var gamepads = navigator.getGamepads()
  177. gamepads.forEach(g=>{
  178. if (!g) return
  179. simulateKey(up, g.axes[1]<-0.3?"down":"up")
  180. simulateKey(down, g.axes[1]>0.3?"down":"up")
  181. simulateKey(left, g.axes[0]<-0.3?"down":"up")
  182. simulateKey(right, g.axes[0]>0.3?"down":"up")
  183. simulateKey(heavy, g.buttons[2].pressed?"down":"up")
  184. simulateKey(special, g.buttons[1].pressed<-0.3?"down":"up")
  185. })
  186.  
  187. // scale viewport
  188. if (window.top.document.fullscreenElement) {
  189. fullscreenButton.style.display = "none"
  190. var html = window.top.document.fullscreenElement
  191. var body = window.top.document.body
  192. var scale = Math.min(
  193. window.screen.availWidth / body.clientWidth,
  194. window.screen.availHeight / body.clientHeight,
  195. )
  196. scale *= 100
  197. body.style.transform = `scale(${scale}%, ${scale}%)`
  198. } else {
  199. fullscreenButton.style.display = "block"
  200. }
  201. }
  202.  
  203. requestAnimationFrame(handleAnimFrame)
  204.  
  205. window.addEventListener('load', () => {
  206. document.getElementById("newbonklobby_chat_input").type = "search"
  207. document.getElementById("newbonklobby_chat_input").autocomplete = "off"
  208. });