paper2hack

Modding utility/menu for paper.io

  1. // ==UserScript==
  2. // @name paper2hack
  3. // @description Modding utility/menu for paper.io
  4. // @version 0.1.22
  5. // @author Pablo Gracia
  6. // @match https://paper-io.com
  7. // @match https://paper-io.com/teams/
  8. // @match https://paperio.site
  9. // @match https://paper-io.com/battleroyale/
  10. // @match https://paperanimals.io
  11. // @match https://amogus.io
  12. // @require https://cdn.jsdelivr.net/npm/tweakpane@3.1.4/dist/tweakpane.min.js
  13. // @license GPL-3.0-only
  14. // @icon https://paper-io.com/favicon.ico
  15. // @grant none
  16. // @namespace https://gf.qytechs.cn/users/1204224
  17. // ==/UserScript==
  18. adblock = () => false //this detects if adblock is on, we make it always return false so that the impostor skin loads
  19. window.addEventListener('load', function () {
  20. "use strict";
  21. const VERSION = "beta 0.1.21"
  22. let newApi
  23. let finish = false; // Start booting
  24. // New api loads too slow!!
  25. // Maybe plan in only supporting the old api? just an opinion
  26. (async() => {
  27. console.log("[paper2hack] Waiting for api");
  28. while(!window.hasOwnProperty("paperio2api")) // paperio2api was first defined!
  29. if (window.hasOwnProperty("paper2")) {newApi = false;return;} // paper2 was first defined!
  30. await new Promise(resolve => setTimeout(resolve, 1000)); // Wait!!
  31. console.log("[paper2hack] api defined!");
  32. })();
  33. window.api = {
  34. /**
  35. * Gets the configuration
  36. * @returns the configuration
  37. */
  38. config: function () {
  39. if (newApi) {
  40. return paperio2api.config;
  41. } else {
  42. return paper2.currentConfig;
  43. }
  44. },
  45. /**
  46. * Gets the game
  47. * @returns the game
  48. */
  49. game: function () {
  50. if (newApi) {
  51. return paperio2api.game
  52. } else {
  53. return paper2.game
  54. }
  55. },
  56. /**
  57. * Gets the player
  58. * @returns the player
  59. */
  60. player: function () {
  61. return this.game().player;
  62. },
  63. /**
  64. * Search an unit by the name
  65. * If no unit is found, it will return `null`
  66. * If an unit is found, it will return that unit
  67. * If multiple names are used
  68. * The first one will be returned
  69. * @param {*} name The name to be searched for
  70. * @returns The unit if found, null if not
  71. */
  72. searchForUnit: function (name) {
  73. for (let i = 0; i < this.game().units.length; i++) {
  74. if (this.game().units[i].name.toLowerCase() == name.toLowerCase()) {return this.game().units[i];}
  75. }
  76. return null;
  77. },
  78. /**
  79. * Create a message, that will appear above the specified unit.
  80. * @param {*} unit The unit
  81. * @param {*} text The text
  82. * @param {*} hexColor The color, in hex, for example : `#FF00FF`
  83. */
  84. addMessage: function (unit, text, hexColor) {
  85. unit.addLabel({
  86. "unit": undefined, // Assign to the unit
  87. "text": text,
  88. "color": hexColor
  89. })
  90. },
  91. /**
  92. * Kills the unit, by the other unit
  93. * @param {*} unitToKill The unit that will be killed
  94. * @param {*} unitToGetKill The unit that'll get the kill stat for
  95. */
  96. kill: function (unitToKill, unitToGetKill) {
  97. if (unitToGetKill == undefined) {unitToGetKill = this.player()}
  98. this.game().kill(unitToKill, unitToGetKill)
  99. },
  100. /**
  101. * Returns the resource located at the resource array (`a0_0x344c`)
  102. * This is only intended for reverse engineering
  103. * @param {number} res the resource, starting at `196`
  104. * @returns the resource, as a `string` can also be undefined
  105. */
  106. getResource: function (res) {
  107. return a0_0x2cc6(res);
  108. }
  109. }
  110. let ETC = {
  111. "newMessage":function (message) {
  112. let newMessage = document.createElement("p");
  113. document.querySelectorAll("#message")[1].appendChild(newMessage);
  114. newMessage.innerText = message;
  115. // Return the new message, if you need it
  116. return newMessage;
  117. },
  118. "reset": function () { alert("Cannot be done with tweakpane!\nTry clearing site data.") },
  119. "zoomScroll": false,
  120. "debugging": false,
  121. "map": false,
  122. "despawnK": false,
  123. "speed": api.config().unitSpeed,
  124. "skin": "",
  125. "skinUnlock": () => {
  126. try {
  127. shop.btnsData.forEach(item => {
  128. if (item.codeName) {
  129. unlockSkin(item.codeName)
  130. }
  131. })
  132. console.log("[paper2hack] skins unlocked!")
  133. } catch (e) {
  134. console.log("[paper2hack] Error unlocking skins!", e)
  135. }
  136. },
  137. "_skins": [],
  138. "pause": function () {
  139. if (!newApi) {
  140. // Toggle between paused and unpaused
  141. // This is not possible in the new api (I believe)
  142. api.game().paused = !paper2.game.paused;
  143. if (api.game().paused) {
  144. console.log("[paper2hack] Paused");
  145. } else {
  146. console.log("[paper2hack] Unpaused");
  147. }
  148. // Return so the unit speed doesn't change
  149. return;
  150. }
  151. if (api.config().unitSpeed !== 0) {
  152. api.config().unitSpeed = 0
  153. console.log("[paper2hack] Paused")
  154. } else {
  155. api.config().unitSpeed = 90
  156. console.log("[paper2hack] Unpaused")
  157. }
  158. return;
  159. },
  160. "despawnOthers": function () {
  161. // Array where we store the units to kill
  162. let unitkills = [];
  163. for (let i = 0; i < api.game().units.length; i++) {
  164. if (api.game().units[i].isPlayer) {continue;} // Ignore if we get the player unit
  165. unitkills.push(api.game().units[i]);
  166. }
  167. // Iterate through the units that we're going to kill
  168. unitkills.forEach((obj) => {
  169. api.kill(obj, obj);
  170. })
  171. },
  172. "help": function () {
  173. alert(`
  174. paper2hack ${VERSION} written by stretch07 and contributors.\n\n
  175. https://github.com/stretch07/paper2hack \n
  176. Issues? https://github.com/stretch07/paper2hack/issues
  177.  
  178. If you encounter any issues with paper2hack, refresh the page, hit the 'Reset' button, or uninstall/reinstall the mod. As a last resort, try clearing site data.
  179. `)
  180. },
  181. "keysList": function () {
  182. alert(`Keyboard shortcuts:\n- Space: Pause/play\n- K: Despawn all other players`)
  183. },
  184. "openGithub": function () {
  185. window.open("https://github.com/stretch07/paper2hack", '_blank').focus();
  186. }
  187. }
  188. function scrollE(e) {
  189. if (e.deltaY > 0) {
  190. if (api.config().maxScale > 0.45) {
  191. api.config().maxScale -= 0.2
  192. }
  193. } else if (e.deltaY < 0) {
  194. if (api.config().maxScale < 4.5) {
  195. api.config().maxScale += 0.2
  196. }
  197. }
  198. }
  199.  
  200. let pane = new Tweakpane.Pane({ title: "paper2hack"})
  201. let mods = pane.addFolder({ title: "Mods" })
  202. mods.addInput(ETC, "speed", { min: 5, max: 500, count: 5 }).on("change", ev => {
  203. api.config().unitSpeed = ev.value;
  204. })
  205. mods.addInput(ETC, "skin", {
  206. label: "Skin",
  207. // Yeah unreadable i know
  208. // Got this with a simple js trick ;)
  209. options: {"No skin":"skin_00","Orange":"skin_20","Burger":"skin_19","Matrix":"skin_49","Green Goblin":"skin_48","Squid Game":"skin_47","Venom":"skin_46","Money Heist":"skin_45","Doge":"skin_44","Baby Yoda":"skin_43","Chess Queen":"skin_42","Impostor":"skin_41","Cyber Punk":"skin_40","Stay safe":"skin_39","Sanitizer":"skin_38","Doctor":"skin_37","COVID-19":"skin_36","Geralt":"skin_35","Batman":"skin_30","Joker":"skin_29","Pennywise":"skin_28","Reaper":"skin_27","Captain America":"skin_26","Thanos":"skin_25","Cupid":"skin_24","Snowman":"skin_23","Present":"skin_22","Christmas":"skin_21","Ladybug":"skin_18","Tank":"skin_17","Duck":"skin_16","Cake":"skin_15","Cash":"skin_14","Sushi":"skin_13","Bat":"skin_12","Heart":"skin_11","Rainbow":"skin_10","Nyan cat":"skin_01","Watermelon":"skin_02","Ghost":"skin_03","Pizza":"skin_04","Minion":"skin_05","Freddy":"skin_06","Spiderman":"skin_07","Teletubby":"skin_08","Unicorn":"skin_09","Eye":"eye", "Frankenstein":"Frank", "Santa":"santa", "Rudolph":"rudolf"}
  210. }).on("change", ev => {
  211. if (newApi && finish) {window.alert("Cannot do this in this version!");}
  212. // Oh boy! No player No skin!
  213. if (!api.game() || !api.player()) {return;}
  214. let id = ev.value;
  215. // The skin manager uses the codeName to get the skin itself
  216. let codeName;
  217. let secret = true;
  218. shop.btnsData.forEach(s => {
  219. if (s.useId == id) {
  220. codeName = s.codeName;
  221. // There is no skins with the same code name, so we can return!
  222. return;
  223. }
  224. })
  225. // Edge cases since these skins don't have use ids
  226. if (id == "eye") {codeName = id;}
  227. else if (id == "Frank") {codeName = id;}
  228. else if (id == "santa") {codeName = id;}
  229. else if (id == "rudolf") {codeName = id;}
  230. else { secret = false; }
  231. // The skin manager treats the default skin as undefined
  232. // if we don't do this it will create an error and will not change the skin
  233. if (codeName == "default") {codeName = undefined;}
  234. // Get the skin from the code name
  235. let skin = api.game().skinManager.getPlayerSkin(codeName);
  236. // And set it to the player!
  237. api.player().setSkin(skin);
  238. if (secret) {return;}
  239. shop.chosenSkin = id;
  240. Cookies.set('skin', id);
  241. })
  242. mods.addInput(ETC, "debugging", { label: "Debug" }).on("change", ev => {
  243. api.game().debug = ev.value
  244. api.game().debugGraph = ev.value
  245. })
  246. mods.addInput(ETC, "map", { label: "Map"}).on("change", ev => {
  247. api.game().debugView = ev.value;
  248. })
  249. mods.addButton({ title: "Pause/Play" }).on("click", ETC.pause)
  250. if (!newApi) {
  251. mods.addButton({ title: "Unlock skins", }).on("click", ETC.skinUnlock)
  252. }
  253. mods.addButton({ title: "I give up" }).on("click",() => {
  254. api.kill(api.player());
  255. })
  256. mods.addButton({ title: "Despawn others" }).on("click", ETC.despawnOthers)
  257. mods.addInput(ETC, "despawnK", { label: "Despawn Others on K" })
  258.  
  259. // keyboard shortcuts
  260. // pause: Spacebar
  261. // kill everyone: K
  262. document.addEventListener("keydown", ev => {
  263. if (!api.player()) {return;} //If not in game, return
  264. if (event.key === 'k') {
  265. if (!ETC.despawnK) return;
  266. ETC.despawnOthers()
  267. }
  268. if (event.key === " ") {
  269. ETC.pause()
  270. }
  271. })
  272. mods.addInput(ETC, "zoomScroll", { label: "Scroll to Zoom" }).on("change", ev => {
  273. if (ev.value === true) {
  274. window.addEventListener("wheel", scrollE)
  275. } else {
  276. window.removeEventListener("wheel", scrollE)
  277. }
  278. })
  279. mods.addButton({ title: "Reset" }).on('click', ETC.reset);
  280. let about = pane.addFolder({ title: "About", expanded: false });
  281. about.addButton({ title: "Help" }).on("click", ETC.help);
  282. about.addButton({ title: "Keyboard Shortcuts" }).on("click", ETC.keysList);
  283. about.addButton({ title: "GitHub" }).on("click", ETC.openGithub);
  284. /*Last things*/
  285. if (!localStorage.getItem('paper2hack')) {
  286. this.localStorage.setItem('paper2hack', JSON.stringify({}))
  287. }
  288. pane.importPreset(JSON.parse(localStorage.getItem("paper2hack")))
  289. pane.on("change", e => {
  290. localStorage.setItem("paper2hack", JSON.stringify(pane.exportPreset()))
  291. })
  292. document.querySelector(".tp-dfwv").style.zIndex = "50"; //Make sure the menu shows up over some GUI
  293. finish = true; // Ended booting
  294. let messages = this.document.querySelectorAll("#message p");
  295. messages.forEach((msg)=>{msg.remove();}) //Remove all messages
  296. ETC.newMessage(`paper2hack ${VERSION}`);
  297. let checkinstallmessage = ETC.newMessage('');
  298. checkinstallmessage.innerHTML = `<a style="color: white" href="https://github.com/stretch07/paper2hack">check/install update</a>`;
  299. ETC.newMessage(`have fun hacking!`);
  300. }, false);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址