Greasy Fork is available in English.

Arras.io Gamepad support

Allows you to use your Gamepad to play arras.io! Press F1 to toggle between active and disabled. Controls: Right thumb stick to move your tank, Left thumb stick to aim, RT to shoot, LT for right click, A for autofire, B for autospin, X for override and Y for taking control of other tanks. Setup "commandKeys" in the script to match your keybindings ingame.

  1. // ==UserScript==
  2. // @name Arras.io Gamepad support
  3. // @namespace Violentmonkey Scripts
  4. // @match *://arras.io/*
  5. // @grant none
  6. // @version 1.2
  7. // @author alexandra
  8. // @description Allows you to use your Gamepad to play arras.io! Press F1 to toggle between active and disabled. Controls: Right thumb stick to move your tank, Left thumb stick to aim, RT to shoot, LT for right click, A for autofire, B for autospin, X for override and Y for taking control of other tanks. Setup "commandKeys" in the script to match your keybindings ingame.
  9. // @run-at document-start
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. let commandKeys = { // change this if you want
  14. autofire: "KeyE",
  15. autospin: "KeyC",
  16. override: "KeyR",
  17. takeControl: "KeyF"
  18. }
  19.  
  20. let enabled = false
  21.  
  22. window.addEventListener("keydown", (e) => {
  23. if (e.code === "F1") {
  24. e.preventDefault()
  25. enabled = !enabled
  26. }
  27. })
  28.  
  29. let windowListener = window.addEventListener
  30. window.addEventListener = function(...args) {
  31. let type = args[0]
  32. if (type === "keydown" || type === "keyup") {
  33. let callback = args[1]
  34.  
  35. args[1] = function(event) {
  36. return callback.call(this, {
  37. isTrusted: true,
  38. key: event.key,
  39. code: event.code,
  40. preventDefault: function(){}
  41. })
  42. }
  43. }
  44. return windowListener.apply(this, args)
  45. }
  46.  
  47. let cnvsElementListener = HTMLDivElement.prototype.addEventListener
  48. HTMLDivElement.prototype.addEventListener = function(...args) {
  49. let type = args[0]
  50. if (type === "mousedown" || type === "mouseup" || type === "mousemove") {
  51. let callback = args[1]
  52.  
  53. args[1] = function(event) {
  54. return callback.call(this, {
  55. isTrusted: true,
  56. clientX: event.clientX,
  57. clientY: event.clientY,
  58. button: event.button,
  59. preventDefault: function(){}
  60. })
  61. }
  62. }
  63. return cnvsElementListener.apply(this, args)
  64. }
  65.  
  66. function keyEvent(key, type) {
  67. window.dispatchEvent(new KeyboardEvent(type ? "keydown" : "keyup", {
  68. code: key
  69. }))
  70. }
  71.  
  72. function mouseEvent(x, y, button, type) {
  73. let event = new MouseEvent(type, {
  74. clientX: x,
  75. clientY: y,
  76. button: button,
  77. })
  78. document.querySelector("#canvas").dispatchEvent(event)
  79. }
  80.  
  81. function eightDirMoveTo(cx, cy, ex, ey) {
  82. if (ex > cx) {
  83. keyEvent("ArrowLeft", false)
  84. keyEvent("ArrowRight", true)
  85. } else if (ex < cx) {
  86. keyEvent("ArrowLeft", true)
  87. keyEvent("ArrowRight", false)
  88. } else {
  89. keyEvent("ArrowLeft", false)
  90. keyEvent("ArrowRight", false)
  91. }
  92.  
  93. if (ey > cy) {
  94. keyEvent("ArrowUp", false)
  95. keyEvent("ArrowDown", true)
  96. } else if (ey < cy) {
  97. keyEvent("ArrowUp", true)
  98. keyEvent("ArrowDown", false)
  99. } else {
  100. keyEvent("ArrowUp", false)
  101. keyEvent("ArrowDown", false)
  102. }
  103. }
  104.  
  105. let stsText = document.createElement("div")
  106. stsText.style.position = "absolute"
  107. stsText.style.margin = "15px"
  108. stsText.style.color = "white"
  109. stsText.style.fontSize = "20px"
  110. stsText.style.fontWeight = "bold"
  111. stsText.style.fontFamily = "Ubuntu"
  112. stsText.textContent = "No Gamepad connected!"
  113. stsText.style.textShadow = "-1px 0 black, 0 1px black, 1px 0 black, 0 -1px black"
  114. stsText.style.pointerEvents = "none"
  115.  
  116. let enText = document.createElement("div")
  117. enText.style.position = "absolute"
  118. enText.style.margin = "15px"
  119. enText.style.color = "white"
  120. enText.style.fontSize = "15px"
  121. enText.style.fontWeight = "bold"
  122. enText.style.fontFamily = "Ubuntu"
  123. enText.textContent = "Disabled!"
  124. enText.style.textShadow = "-1px 0 black, 0 1px black, 1px 0 black, 0 -1px black"
  125. enText.style.top = "20px"
  126. enText.style.pointerEvents = "none"
  127.  
  128. let crosshair = document.createElement("img")
  129. crosshair.style.position = "absolute"
  130. crosshair.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACjSURBVEhL1Y5BDsUgCEQ9SJe9/816Bqs2kAHFIrGLvmSSysD7Py2QIdvJ13H+S05ClFPCsKRKdbAvWUJI8W11JS74mL4XZq9YBzgn2nswHzJb9sx1J5gtmvIao2ORXuoS6J5id1iOgaJLoBPoJUT8I6DNjE4wW/TMdddhLY/k7W386BB9wHHMXPAhHuvviJjoRBjsS8KwZKdUg/LtfCuHOEjpBh0tTqQ2XaPuAAAAAElFTkSuQmCC"
  131. crosshair.style.pointerEvents = "none"
  132. crosshair.style.visibility = "hidden"
  133. crosshair.style.margin = 0
  134.  
  135. let movArrow = document.createElement("img")
  136. movArrow.style.position = "absolute"
  137. movArrow.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAlCAYAAAAA7LqSAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEaSURBVFhH1ZYJCgMhEAQ1//+zYUQXSTxanWsLFiEIWvaMJiiQyidKLKMUPQGRNSVFZimwr2slUmFb/1NGK9h6xzqRlqu9WCfScpWOqkhKy70ey9Q42Wp1RhWJEaqirVKjySoSxG8igBAsY9ojYKlBB23e7IAMsZzk4tYiGTCdId0eAU9JhNOLwNM7kjlNx51IBZR5JrkVIcASz5Pc9ciIVe+4TqRldbivEXl9IiSA/JVxLbLzprgVQVIoX8adCFpKZXygH1TuWuRKPxGoqIkQI5mdXhhhXlocEoSpCFhKW6aqfcKVQsvW5E3+DodEbhp6hqoIwPF+PL0jV4fqIRGWPVgnwnaQVomwryspQvRkRNaUFiFaGaH1QvgCHmRUMUA6MH0AAAAASUVORK5CYII="
  138. movArrow.style.pointerEvents = "none"
  139. movArrow.style.visibility = "hidden"
  140. movArrow.style.margin = 0
  141. movArrow.style.padding = 0
  142. movArrow.style.transformOrigin = "center center"
  143. movArrow.width = 40
  144.  
  145. document.addEventListener("DOMContentLoaded", () => {
  146. document.body.appendChild(movArrow)
  147. document.body.appendChild(crosshair)
  148. document.body.appendChild(stsText)
  149. document.body.appendChild(enText)
  150. })
  151.  
  152. let gamepadControls = {
  153. A: 0,
  154. B: 0,
  155. X: 0,
  156. Y: 0
  157. }
  158.  
  159. let gamepadRangeX = window.innerWidth
  160. let gamepadRangeY = window.innerHeight
  161.  
  162. // buttons[0] A
  163. // buttons[1] B
  164. // buttons[2] X
  165. // buttons[3] Y
  166. // buttons[4] LB
  167. // buttons[5] RB
  168. // buttons[6] LT
  169. // buttons[7] RT
  170.  
  171. let gamepad
  172. setInterval(() => {
  173. let gamepads = navigator.getGamepads().find((x) => x !== null)
  174. if (gamepads) {
  175. gamepad = gamepads
  176. stsText.textContent = "Gamepad connected!"
  177. } else {
  178. gamepad = undefined
  179. stsText.textContent = "No Gamepad connected!"
  180. }
  181.  
  182. if (enabled) {
  183. enText.textContent = "Enabled!"
  184. if (gamepad) {
  185. crosshair.style.visibility = "visible"
  186. movArrow.style.visibility = "visible"
  187. let target = gamepad.axes.slice(0, 2).map((x) => Math.round(x))
  188. let cursorPos = gamepad.axes.slice(2, 4).map((x) => x + 1)
  189.  
  190. cursorPos[0] *= gamepadRangeX
  191. cursorPos[1] *= gamepadRangeY
  192.  
  193. cursorPos[0] -= gamepadRangeX / 2
  194. cursorPos[1] -= gamepadRangeY / 2
  195.  
  196. if (cursorPos[0] > window.innerWidth) cursorPos[0] = window.innerWidth
  197. if (cursorPos[0] < 0) cursorPos[0] = 0
  198. if (cursorPos[1] > window.innerHeight) cursorPos[1] = window.innerHeight
  199. if (cursorPos[1] < 0) cursorPos[1] = 0
  200.  
  201. if (gamepad.buttons[6].pressed) {
  202. keyEvent("ShiftLeft", true)
  203. } else {
  204. keyEvent("ShiftLeft", false)
  205. }
  206.  
  207. if (gamepad.buttons[0].pressed) {
  208. gamepadControls.A++
  209. } else {
  210. gamepadControls.A = 0
  211. }
  212. if (gamepad.buttons[1].pressed) {
  213. gamepadControls.B++
  214. } else {
  215. gamepadControls.B = 0
  216. }
  217. if (gamepad.buttons[2].pressed) {
  218. gamepadControls.X++
  219. } else {
  220. gamepadControls.X = 0
  221. }
  222. if (gamepad.buttons[3].pressed) {
  223. gamepadControls.Y++
  224. } else {
  225. gamepadControls.Y = 0
  226. }
  227.  
  228. if (gamepadControls.A === 1) {
  229. keyEvent(commandKeys.autofire, true)
  230. keyEvent(commandKeys.autofire, false)
  231. }
  232.  
  233. if (gamepadControls.B === 1) {
  234. keyEvent(commandKeys.autospin, true)
  235. keyEvent(commandKeys.autospin, false)
  236. }
  237.  
  238. if (gamepadControls.X === 1) {
  239. keyEvent(commandKeys.override, true)
  240. keyEvent(commandKeys.override, false)
  241. }
  242.  
  243. if (gamepadControls.Y === 1) {
  244. keyEvent(commandKeys.takeControl, true)
  245. keyEvent(commandKeys.takeControl, false)
  246. }
  247.  
  248. crosshair.style.left = cursorPos[0] - 11.5 + "px"
  249. crosshair.style.top = cursorPos[1] - 11.5 + "px"
  250.  
  251. if (target[0] || target[1]) {
  252. let dir = Math.atan2(target[1], target[0])
  253. movArrow.style.transform = `rotate(${dir}rad)`
  254. movArrow.style.left = ((window.innerWidth / 2) + Math.cos(dir) * 75) - 20 + "px"
  255. movArrow.style.top = ((window.innerHeight / 2) + Math.sin(dir) * 75) - 15 + "px"
  256. } else {
  257. movArrow.style.visibility = "hidden"
  258. }
  259.  
  260. eightDirMoveTo(0, 0, target[0], target[1])
  261. mouseEvent(
  262. cursorPos[0],
  263. cursorPos[1],
  264. 0,
  265. gamepad.buttons[7].pressed ? "mousedown" : "mouseup"
  266. )
  267. } else {
  268. crosshair.style.visibility = "hidden"
  269. movArrow.style.visibility = "hidden"
  270. }
  271. } else {
  272. enText.textContent = "Disabled!"
  273. crosshair.style.visibility = "hidden"
  274. movArrow.style.visibility = "hidden"
  275. }
  276. })
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295. // empty space wooo