[Updated] Hordes Auto Loot

Auto Loot + Anti Afk + Item Uniting (Made By 0vC4, Updated By xFuRiOuS)

当前为 2022-04-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name [Updated] Hordes Auto Loot
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.7
  5. // @description Auto Loot + Anti Afk + Item Uniting (Made By 0vC4, Updated By xFuRiOuS)
  6. // @author xFuRiOuS#9356
  7. // @match https://hordes.io/play
  8. // @icon https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://hordes.io&size=32
  9. // @grant none
  10. // @namespace https://greasyfork.org/users/857980
  11. // @license MIT
  12. // @run-at document-start
  13. // ==/UserScript==
  14.  
  15.  
  16. // My Discord Tag : xFuRiOuS#9356
  17. // Feel Free To Contact Me If Your Interested In More Stuff Like This !
  18.  
  19.  
  20. document.write();
  21.  
  22.  
  23. fetch('https://hordes.io/play')
  24. .then(d=>d.text())
  25. .then(async html => {
  26. const element = html.match(/<script.*?client\.js.*?><\/script>/)[0]
  27. const url = element.match(/src="(.*?)"/)[1]
  28. html = html.replace(element,`<script>let _t=origin;delete origin;eval(_t)</script>`)
  29.  
  30. let origin = await (fetch(url).then(d=>d.text()))
  31.  
  32. const name = 'ha';
  33. const pickedMarker = 'inProcessPick';
  34.  
  35. const getRandom = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
  36.  
  37. const vr = {
  38. intersReady: {
  39. antiAfk: true,
  40. looting: true,
  41. uiextra: true,
  42. },
  43.  
  44. antiAfk: () => (vr.intersReady.antiAfk=!vr.intersReady.antiAfk),
  45. looting: () => (vr.intersReady.looting=!vr.intersReady.looting),
  46. uiextra: () => (vr.intersReady.uiextra=!vr.intersReady.uiextra),
  47.  
  48. rules: {
  49. fixedDelay: 0,
  50. randomDelay: 0,
  51.  
  52. gold: true,
  53. rune: true,
  54. misc: false,
  55.  
  56. book1: false,
  57. book2: false,
  58. book3: true,
  59. book4: true,
  60. book5: true,
  61.  
  62. loot1: false,
  63. loot2: false,
  64. loot3: true,
  65. loot4: true,
  66. quality: 70
  67. },
  68.  
  69. command (name, str) { vr.send(vr.coder.clientCommand.packData({command: name, string: str+''})) },
  70. drop (slotID) {vr.command("itemdrop", slotID); },
  71. pick (item) {if(item[pickedMarker])return; item[pickedMarker]=true; vr.send(vr.coder.clientPlayerChangeTarget.encode({_header:1,target:item.id}))},
  72. invFull () {
  73. if (!(vr.me && vr.me.inventory && vr.me.inventory.slots)) return true;
  74. return [...vr.me.inventory.slots.keys()].filter(i=>i<101).length === vr.me.inventory.size;
  75. },
  76. concatItems () {
  77. if (!(vr.me && vr.me.inventory && vr.me.inventory.slots)) return;
  78.  
  79. const inventoryItems = [...vr.me.inventory.slots].filter(a=>a[0]<101);
  80. const stackable = (item, item2) => item.type==item2.type&&item.tier==item2.tier&&item.stacks>0&&item.stacks<50;
  81.  
  82. inventoryItems.map(item => {
  83. const withItem = inventoryItems.find(item2 => item[0] > item2[0] && stackable(item[1], item2[1]) )
  84. if (withItem) vr.command('itemmove', item[0]+' '+withItem[0])
  85. });
  86. },
  87.  
  88.  
  89. inters: {
  90. antiAfk: setInterval(() => vr.intersReady.antiAfk&&vr.world&&vr.world.tick(Math.random()/1e3), 1e3/60),
  91. uiextra: setInterval(() => {
  92. if (!vr.intersReady.uiextra) return;
  93.  
  94. if (getChoiceByTitle('Yes, show me the items for sale.')) getChoiceByTitle('Yes, show me the items for sale.').click()
  95. if (getChoiceByTitle('Yes, open my Stash.')) getChoiceByTitle('Yes, open my Stash.').click()
  96. if (getChoiceByTitle('Show me your wares.')) getChoiceByTitle('Show me your wares.').click()
  97. if (getChoiceByTitle('Yes, I have some items.')) getChoiceByTitle('Yes, I have some items.').click()
  98. }),
  99. looting: (function lootingLoop() { setTimeout(() => {
  100. if (vr.intersReady.looting && vr.me && vr.world.entities.type[3].length) {
  101.  
  102. const full = vr.invFull();
  103.  
  104. const inventoryItems = [...vr.me.inventory.slots].filter(a=>a[0]<101).map(a=>a[1]);
  105. const stackable = item => inventoryItems.find(i=>i.type==item.droptype&&i.tier==item.tier&&i.stacks>0&&i.stacks<50)
  106.  
  107. const loot = vr.world.entities.type[3]
  108. .map(i=>((i[pickedMarker]=false),i))
  109. .filter(i => {
  110. if (i.droptype == 'gold') return vr.me.stats.alive && vr.rules.gold;
  111. if (stackable(i)) return true;
  112. if (full) return false;
  113.  
  114. if (i.droptype == 'book') {
  115. return vr.rules.book1 && i.name.endsWith('Lv. 1') ||
  116. vr.rules.book2 && i.name.endsWith('Lv. 2') ||
  117. vr.rules.book3 && i.name.endsWith('Lv. 3') ||
  118. vr.rules.book4 && i.name.endsWith('Lv. 4') ||
  119. vr.rules.book5 && i.name.endsWith('Lv. 5')
  120. } else if (i.droptype == 'misc') {
  121. return vr.rules.misc;
  122. } else if (i.droptype == 'rune') {
  123. return vr.rules.rune;
  124. } else {
  125. return (vr.rules.loot1 && i.color == 'common' ||
  126. vr.rules.loot2 && i.color == 'uncommon' ||
  127. vr.rules.loot3 && i.color == 'rare' ||
  128. vr.rules.loot4 && i.color == 'epic') &&
  129. vr.rules.quality <= i.quality
  130. }
  131. return false;
  132. })
  133. .filter(i => i.canBePickedUpBy(vr.me));
  134.  
  135. (vr.rules.fixedDelay || vr.rules.randomDelay) && loot.length ? vr.pick(loot.shift()) : loot.map(vr.pick)
  136. }
  137.  
  138. lootingLoop();
  139. }, (window[name]?.rules.fixedDelay || 0) + (window[name]?.rules.randomDelay || 0)) })(),
  140. }
  141. };
  142.  
  143. window[name] = vr;
  144.  
  145. let world = origin.match(/([_a-zA-Z0-9]*?)\.entities\.array\.length;/)[1]
  146. let coder = origin.match(/\,([_a-zA-Z0-9]*?)=\{clientPlayerInput:\{/)[1]
  147. let ws = origin.match(/\(([_a-zA-Z0-9]*?)=new WebSocket/)[1]
  148. let send = origin.match(/([_a-zA-Z0-9]*?)=[_a-zA-Z0-9]*?=>\{void 0!==[_a-zA-Z0-9]*?&&1===[_a-zA-Z0-9]*?&&[_a-zA-Z0-9]*?\.send\(.*?\)\}/)[1]
  149.  
  150. origin = origin.replace('this.player=t', 'Object.assign(window.'+name+
  151. ',{world:'+world+
  152. ',me:t'+
  153. ',coder:'+coder+
  154. ',ws:'+ws+
  155. ',send:'+send+
  156. '}),this.player=t')
  157.  
  158. window.origin = origin
  159. document.open().write(html)
  160. document.close()
  161.  
  162.  
  163. const getChoiceByTitle = title => [...document.getElementsByClassName('choice')].find(c=>c.textContent.includes(title))
  164.  
  165.  
  166. // hotkeys
  167. document.addEventListener('keydown', e => e.code == 'ShiftRight' && vr.looting());
  168. document.addEventListener('keydown', e => e.code == 'ControlRight' && vr.concatItems());
  169.  
  170.  
  171. let autoLootUI = false;
  172. document.addEventListener('keydown', e => e.shiftKey && e.code == 'KeyL' && toggleAutoLootSettings());
  173.  
  174. function toggleAutoLootSettings() {
  175. if (!autoLootUI) {
  176. document.querySelector(".l-ui.layout > .container:first-child").insertAdjacentHTML('afterend',
  177. `<style>
  178. .grid-content {
  179. display: grid;
  180. grid-template-columns: 2fr 1fr;
  181. grid-gap: 8px;
  182. align-items: center;
  183. }
  184.  
  185. .container.auto-loot-ui {
  186. min-width: 350px;
  187. max-width: 600px;
  188. width: 90%;
  189. height: 60%;
  190. min-height: 350px;
  191. max-height: 600px;
  192. z-index: 9;
  193. }
  194.  
  195. .window.auto-loot-window {
  196. padding: 5px;
  197. height: 100%;
  198. display: grid;
  199. grid-template-rows: 30px 1fr;
  200. grid-gap: 4px;
  201. transform-origin: inherit;
  202. min-width: fit-content;
  203. }
  204.  
  205. .titleframe.auto-loot-titleframe {
  206. line-height: 1em;
  207. display: flex;
  208. align-items: center;
  209. position: relative;
  210. letter-spacing: 0.5px;
  211. }
  212.  
  213. .titleicon.auto-loot-titleicon {
  214. margin: 3px;
  215. }
  216.  
  217. .title.auto-loot-title {
  218. width: 100%;
  219. padding-left: 4px;
  220. font-weight: bold;
  221. }
  222.  
  223. .slot.auto-loot-slot {
  224. min-height: 0;
  225. }
  226. </style>
  227. <div class="absCentered container auto-loot-ui">
  228. <div class="window panel-black auto-loot-window">
  229. <div class="titleframe auto-loot-titleframe">
  230. <img src="/assets/ui/icons/bag.svg?v=5305285" class="titleicon svgicon auto-loot-titleicon">
  231. <div class="textprimary title auto-loot-title">
  232. <div name="title">Auto Loot</div>
  233. </div>
  234. <img src="/assets/ui/icons/cross.svg?v=5284585" class="btn black svgicon close-ui">
  235. </div>
  236. <div class="slot scrollbar auto-loot-slot">
  237. <div class="panel-black">
  238. <h3 class="textprimary"></h3>
  239. <div class="grid-content scripts">
  240. <div>Automatic Looting</div>
  241. <div class="btn checkbox" name="looting"></div>
  242. <div>Anti AFK</div>
  243. <div class="btn checkbox" name="antiAfk"></div>
  244. <div>Concatenate Inventory Items</div>
  245. <div class="">ControlRight</div>
  246. </div>
  247. <h3 class="textprimary">Coins Meter</h3>
  248. <div class="grid-content coins-meter">
  249. <div>Session Time</div>
  250. <div class="coins-meter-time"></div>
  251. <div>Coins Earned</div>
  252. <div class="coins-meter-earned"></div>
  253. <div>Coins / Minute</div>
  254. <div class="coins-meter-earned-minute"></div>
  255. <div>Coins / Hour</div>
  256. <div class="coins-meter-earned-hour"></div>
  257. <div></div>
  258. <div class="btn grey coins-meter-reset">Reset</div>
  259. </div>
  260. <h3 class="textprimary">Delay</h3>
  261. <div class="grid-content delay">
  262. <div>Fixed Delay<br><small class="textgrey fixed-delay-indicator">ms</small></div>
  263. <input type="range" class="fixed-delay" name="delay" min="0" max="1000">
  264. <div>With Randomness<br><small class="textgrey random-delay-indicator">ms</small></div>
  265. <input type="range" class="random-delay" name="random-delay" min="0" max="1000">
  266. </div>
  267. <h3 class="textprimary">Main</h3>
  268. <div class="grid-content main">
  269. <div>Gold</div>
  270. <div class="btn checkbox" name="gold"></div>
  271. <div>Rune</div>
  272. <div class="btn checkbox" name="rune"></div>
  273. <div>Misc</div>
  274. <div class="btn checkbox" name="misc"></div>
  275. </div>
  276. <h3 class="textprimary">Books</h3>
  277. <div class="grid-content books">
  278. <div>Lv. 1</div>
  279. <div class="btn checkbox" name="book1"></div>
  280. <div>Lv. 2</div>
  281. <div class="btn checkbox" name="book2"></div>
  282. <div>Lv. 3</div>
  283. <div class="btn checkbox" name="book3"></div>
  284. <div>Lv. 4</div>
  285. <div class="btn checkbox" name="book4"></div>
  286. <div>Lv. 5</div>
  287. <div class="btn checkbox" name="book5"></div>
  288. </div>
  289. <h3 class="textprimary">Items</h3>
  290. <div class="grid-content items">
  291. <div class="textgrey">Common (0% - 49%)</div>
  292. <div class="btn checkbox" name="loot1"></div>
  293. <div class="textgreen">Uncommon (50% - 69%)</div>
  294. <div class="btn checkbox" name="loot2"></div>
  295. <div class="textblue">Rare (70% - 89%)</div>
  296. <div class="btn checkbox" name="loot3"></div>
  297. <div class="textpurp">Epic (90% - 100%)</div>
  298. <div class="btn checkbox" name="loot4"></div>
  299. <div>Item Quality% Minimum<br><small class="textgrey quality-range-indicator">%</small></div>
  300. <input type="range" class="quality-range" name="quality" min="0" max="100">
  301. </div>
  302. <h3 class="textprimary"></h3>
  303. </div>
  304. </div>
  305. </div>
  306. </div>`
  307. );
  308.  
  309. document.querySelector('.close-ui').addEventListener('click', e => toggleAutoLootSettings());
  310.  
  311. document.querySelectorAll('.auto-loot-ui .scripts .btn.checkbox').forEach((el) => {
  312. if (vr.intersReady[el.getAttribute("name")]) el.classList.add("active")
  313. el.addEventListener('click', e => {
  314. e.target.classList.contains("active") ? e.target.classList.remove("active") : e.target.classList.add("active");
  315. vr.intersReady[e.target.getAttribute("name")] ^= 1;
  316. })
  317. })
  318.  
  319. document.querySelectorAll('.auto-loot-ui .main .btn.checkbox, .auto-loot-ui .books .btn.checkbox, .auto-loot-ui .items .btn.checkbox').forEach((el) => {
  320. if (vr.rules[el.getAttribute("name")]) el.classList.add("active")
  321. el.addEventListener('click', e => {
  322. e.target.classList.contains("active") ? e.target.classList.remove("active") : e.target.classList.add("active");
  323. vr.rules[e.target.getAttribute("name")] ^= 1;
  324. })
  325. });
  326.  
  327. document.querySelector('.auto-loot-ui .delay .fixed-delay').value = vr.rules.fixedDelay;
  328. document.querySelector('.auto-loot-ui .delay .fixed-delay-indicator').innerHTML = vr.rules.fixedDelay + " ms";
  329. document.querySelector('.auto-loot-ui .delay .fixed-delay').addEventListener('input', e => {
  330. vr.rules.fixedDelay = parseInt(e.target.value);
  331. document.querySelector('.auto-loot-ui .delay .fixed-delay-indicator').innerHTML = e.target.value + " ms";
  332. });
  333.  
  334. document.querySelector('.auto-loot-ui .delay .random-delay').value = vr.rules.randomDelay;
  335. document.querySelector('.auto-loot-ui .delay .random-delay-indicator').innerHTML = "0 - " + vr.rules.randomDelay + " ms";
  336. document.querySelector('.auto-loot-ui .delay .random-delay').addEventListener('input', e => {
  337. vr.rules.randomDelay = parseInt(e.target.value);
  338. document.querySelector('.auto-loot-ui .delay .random-delay-indicator').innerHTML = "0 - " + e.target.value + " ms";
  339. });
  340.  
  341. document.querySelector('.auto-loot-ui .items .quality-range').value = vr.rules.quality;
  342. document.querySelector('.auto-loot-ui .items .quality-range-indicator').innerHTML = vr.rules.quality + "%";
  343. document.querySelector('.auto-loot-ui .items .quality-range').addEventListener('input', e => {
  344. vr.rules.quality = parseInt(e.target.value);
  345. document.querySelector('.auto-loot-ui .items .quality-range-indicator').innerHTML = e.target.value + "%";
  346. });
  347.  
  348. document.querySelector('.coins-meter-reset').addEventListener('click', e => resetCoinsMeter());
  349. }
  350. else {
  351. document.querySelector('.auto-loot-ui').remove();
  352. }
  353.  
  354. autoLootUI ^= 1;
  355. }
  356.  
  357.  
  358. // Gold Meter
  359. const pad = value => value < 10 ? `0${value}` : value;
  360.  
  361. function msToString(ms) {
  362. const hours = pad(Math.floor(ms / (1000 * 60 * 60) % 60));
  363. const minutes = pad(Math.floor(ms / (1000 * 60) % 60));
  364. const seconds = pad(Math.floor(ms / 1000 % 60));
  365. return `${hours}:${minutes}:${seconds}`;
  366. }
  367.  
  368. function formatStringCoins(coins) {
  369. const gold = Math.floor(coins / 10000)
  370. const silver = pad(Math.floor((coins % 10000) / 100))
  371. const copper = pad(Math.floor((coins % 10000) % 100))
  372. return `<span>
  373. <span class="textgold">${gold}</span> <img class="texticon" src="/assets/ui/currency/gold.webp">
  374. <span class="textsilver">${silver}</span> <img class="texticon" src="/assets/ui/currency/silver.webp">
  375. <span class="textcopper">${copper}</span> <img class="texticon" src="/assets/ui/currency/copper.webp">
  376. </span>`;
  377. }
  378.  
  379. let startTime = new Date().getTime();
  380.  
  381. let currentCoins = 0;
  382. let coinsEarned = 0;
  383.  
  384. function resetCoinsMeter() {
  385. startTime = new Date().getTime();
  386. currentCoins = vr.me.inventory.gold;
  387. coinsEarned = 0;
  388. }
  389.  
  390. setInterval(() => {
  391. if (!vr.me) return;
  392.  
  393. coinsEarned += Math.max(vr.me.inventory.gold - currentCoins, 0);
  394. currentCoins = vr.me.inventory.gold;
  395. })
  396.  
  397. setInterval(() => {
  398. if (!autoLootUI) return;
  399.  
  400. let midTime = new Date().getTime() - startTime;
  401.  
  402. document.querySelector('.coins-meter-time').innerHTML = msToString(midTime);
  403. document.querySelector('.coins-meter-earned').innerHTML = formatStringCoins(coinsEarned);
  404. document.querySelector('.coins-meter-earned-minute').innerHTML = formatStringCoins(coinsEarned * 60 / (midTime / 1000));
  405. document.querySelector('.coins-meter-earned-hour').innerHTML = formatStringCoins(coinsEarned * 60 * 60 / (midTime / 1000));
  406. })
  407. });