AlterAle - zombs.io

weeb mod de-weeb'd

  1. // ==UserScript==
  2. // @name AlterAle - zombs.io
  3. // @namespace http://tampermonkey.net/
  4. // @version -.5.1
  5. // @description weeb mod de-weeb'd
  6. // @author rdm / AyuBloom
  7. // @match zombs.io
  8. // @icon https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/AlterAle%20Arcaea.webp?v=1717835928442
  9. // @grant none
  10. // @license GNU GPLv3
  11. // ==/UserScript==
  12.  
  13. /* @Dependencies */
  14. /*
  15. bytebuffer.js (c) 2015 Daniel Wirtz <dcode@dcode.io>
  16. Backing buffer: ArrayBuffer, Accessor: Uint8Array
  17. Released under the Apache License, Version 2.0
  18. see: https://github.com/dcodeIO/bytebuffer.js for details
  19. */
  20. (function (h, l) {
  21. if ("function" === typeof define && define.amd) define(["long"], l);
  22. else if ("function" === typeof require && "object" === typeof module && module && module.exports) {
  23. h = module;
  24. try {
  25. var t = require("long");
  26. } catch (v) {}
  27. l = l(t);
  28. h.exports = l;
  29. } else (h.dcodeIO = h.dcodeIO || {}).ByteBuffer = l(h.dcodeIO.Long);
  30. })(this, function (h) {
  31. function l(a) {
  32. var b = 0;
  33. return function () {
  34. return b < a.length ? a.charCodeAt(b++) : null;
  35. };
  36. }
  37. function t() {
  38. var a = [],
  39. b = [];
  40. return function () {
  41. if (0 === arguments.length) return b.join("") + x.apply(String, a);
  42. 1024 < a.length + arguments.length && (b.push(x.apply(String, a)), (a.length = 0));
  43. Array.prototype.push.apply(a, arguments);
  44. };
  45. }
  46. function v(a, b, c, e, k) {
  47. var f = 8 * k - e - 1;
  48. var d = (1 << f) - 1,
  49. g = d >> 1,
  50. n = -7;
  51. k = c ? k - 1 : 0;
  52. var h = c ? -1 : 1,
  53. q = a[b + k];
  54. k += h;
  55. c = q & ((1 << -n) - 1);
  56. q >>= -n;
  57. for (n += f; 0 < n; c = 256 * c + a[b + k], k += h, n -= 8);
  58. f = c & ((1 << -n) - 1);
  59. c >>= -n;
  60. for (n += e; 0 < n; f = 256 * f + a[b + k], k += h, n -= 8);
  61. if (0 === c) c = 1 - g;
  62. else {
  63. if (c === d) return f ? NaN : Infinity * (q ? -1 : 1);
  64. f += Math.pow(2, e);
  65. c -= g;
  66. }
  67. return (q ? -1 : 1) * f * Math.pow(2, c - e);
  68. }
  69. function y(a, b, c, e, k, f) {
  70. var d,
  71. g = 8 * f - k - 1,
  72. n = (1 << g) - 1,
  73. h = n >> 1,
  74. q = 23 === k ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
  75. f = e ? 0 : f - 1;
  76. var l = e ? 1 : -1,
  77. m = 0 > b || (0 === b && 0 > 1 / b) ? 1 : 0;
  78. b = Math.abs(b);
  79. isNaN(b) || Infinity === b
  80. ? ((b = isNaN(b) ? 1 : 0), (e = n))
  81. : ((e = Math.floor(Math.log(b) / Math.LN2)),
  82. 1 > b * (d = Math.pow(2, -e)) && (e--, (d *= 2)),
  83. (b = 1 <= e + h ? b + q / d : b + q * Math.pow(2, 1 - h)),
  84. 2 <= b * d && (e++, (d /= 2)),
  85. e + h >= n ? ((b = 0), (e = n)) : 1 <= e + h ? ((b = (b * d - 1) * Math.pow(2, k)), (e += h)) : ((b = b * Math.pow(2, h - 1) * Math.pow(2, k)), (e = 0)));
  86. for (; 8 <= k; a[c + f] = b & 255, f += l, b /= 256, k -= 8);
  87. e = (e << k) | b;
  88. for (g += k; 0 < g; a[c + f] = e & 255, f += l, e /= 256, g -= 8);
  89. a[c + f - l] |= 128 * m;
  90. }
  91. var g = function (a, b, c) {
  92. "undefined" === typeof a && (a = g.DEFAULT_CAPACITY);
  93. "undefined" === typeof b && (b = g.DEFAULT_ENDIAN);
  94. "undefined" === typeof c && (c = g.DEFAULT_NOASSERT);
  95. if (!c) {
  96. a |= 0;
  97. if (0 > a) throw RangeError("Illegal capacity");
  98. b = !!b;
  99. c = !!c;
  100. }
  101. this.buffer = 0 === a ? w : new ArrayBuffer(a);
  102. this.view = 0 === a ? null : new Uint8Array(this.buffer);
  103. this.offset = 0;
  104. this.markedOffset = -1;
  105. this.limit = a;
  106. this.littleEndian = b;
  107. this.noAssert = c;
  108. };
  109. g.VERSION = "5.0.1";
  110. g.LITTLE_ENDIAN = !0;
  111. g.BIG_ENDIAN = !1;
  112. g.DEFAULT_CAPACITY = 16;
  113. g.DEFAULT_ENDIAN = g.BIG_ENDIAN;
  114. g.DEFAULT_NOASSERT = !1;
  115. g.Long = h || null;
  116. var d = g.prototype;
  117. Object.defineProperty(d, "__isByteBuffer__", { value: !0, enumerable: !1, configurable: !1 });
  118. var w = new ArrayBuffer(0),
  119. x = String.fromCharCode;
  120. g.accessor = function () {
  121. return Uint8Array;
  122. };
  123. g.allocate = function (a, b, c) {
  124. return new g(a, b, c);
  125. };
  126. g.concat = function (a, b, c, e) {
  127. if ("boolean" === typeof b || "string" !== typeof b) (e = c), (c = b), (b = void 0);
  128. for (var k = 0, f = 0, d = a.length, u; f < d; ++f) g.isByteBuffer(a[f]) || (a[f] = g.wrap(a[f], b)), (u = a[f].limit - a[f].offset), 0 < u && (k += u);
  129. if (0 === k) return new g(0, c, e);
  130. b = new g(k, c, e);
  131. for (f = 0; f < d; ) (c = a[f++]), (u = c.limit - c.offset), 0 >= u || (b.view.set(c.view.subarray(c.offset, c.limit), b.offset), (b.offset += u));
  132. b.limit = b.offset;
  133. b.offset = 0;
  134. return b;
  135. };
  136. g.isByteBuffer = function (a) {
  137. return !0 === (a && a.__isByteBuffer__);
  138. };
  139. g.type = function () {
  140. return ArrayBuffer;
  141. };
  142. g.wrap = function (a, b, c, e) {
  143. "string" !== typeof b && ((e = c), (c = b), (b = void 0));
  144. if ("string" === typeof a)
  145. switch (("undefined" === typeof b && (b = "utf8"), b)) {
  146. case "base64":
  147. return g.fromBase64(a, c);
  148. case "hex":
  149. return g.fromHex(a, c);
  150. case "binary":
  151. return g.fromBinary(a, c);
  152. case "utf8":
  153. return g.fromUTF8(a, c);
  154. case "debug":
  155. return g.fromDebug(a, c);
  156. default:
  157. throw Error("Unsupported encoding: " + b);
  158. }
  159. if (null === a || "object" !== typeof a) throw TypeError("Illegal buffer");
  160. if (g.isByteBuffer(a)) return (b = d.clone.call(a)), (b.markedOffset = -1), b;
  161. if (a instanceof Uint8Array) (b = new g(0, c, e)), 0 < a.length && ((b.buffer = a.buffer), (b.offset = a.byteOffset), (b.limit = a.byteOffset + a.byteLength), (b.view = new Uint8Array(a.buffer)));
  162. else if (a instanceof ArrayBuffer) (b = new g(0, c, e)), 0 < a.byteLength && ((b.buffer = a), (b.offset = 0), (b.limit = a.byteLength), (b.view = 0 < a.byteLength ? new Uint8Array(a) : null));
  163. else if ("[object Array]" === Object.prototype.toString.call(a)) for (b = new g(a.length, c, e), b.limit = a.length, c = 0; c < a.length; ++c) b.view[c] = a[c];
  164. else throw TypeError("Illegal buffer");
  165. return b;
  166. };
  167. d.writeBitSet = function (a, b) {
  168. var c = "undefined" === typeof b;
  169. c && (b = this.offset);
  170. if (!this.noAssert) {
  171. if (!(a instanceof Array)) throw TypeError("Illegal BitSet: Not an array");
  172. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  173. b >>>= 0;
  174. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  175. }
  176. var e = b,
  177. k = a.length,
  178. f = k >> 3,
  179. d = 0;
  180. for (b += this.writeVarint32(k, b); f--; ) {
  181. var g = (!!a[d++] & 1) | ((!!a[d++] & 1) << 1) | ((!!a[d++] & 1) << 2) | ((!!a[d++] & 1) << 3) | ((!!a[d++] & 1) << 4) | ((!!a[d++] & 1) << 5) | ((!!a[d++] & 1) << 6) | ((!!a[d++] & 1) << 7);
  182. this.writeByte(g, b++);
  183. }
  184. if (d < k) {
  185. for (g = f = 0; d < k; ) g |= (!!a[d++] & 1) << f++;
  186. this.writeByte(g, b++);
  187. }
  188. return c ? ((this.offset = b), this) : b - e;
  189. };
  190. d.readBitSet = function (a) {
  191. var b = "undefined" === typeof a;
  192. b && (a = this.offset);
  193. var c = this.readVarint32(a),
  194. e = c.value,
  195. k = e >> 3,
  196. f = 0,
  197. d = [];
  198. for (a += c.length; k--; )
  199. (c = this.readByte(a++)), (d[f++] = !!(c & 1)), (d[f++] = !!(c & 2)), (d[f++] = !!(c & 4)), (d[f++] = !!(c & 8)), (d[f++] = !!(c & 16)), (d[f++] = !!(c & 32)), (d[f++] = !!(c & 64)), (d[f++] = !!(c & 128));
  200. if (f < e) for (k = 0, c = this.readByte(a++); f < e; ) d[f++] = !!((c >> k++) & 1);
  201. b && (this.offset = a);
  202. return d;
  203. };
  204. d.readBytes = function (a, b) {
  205. var c = "undefined" === typeof b;
  206. c && (b = this.offset);
  207. if (!this.noAssert) {
  208. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  209. b >>>= 0;
  210. if (0 > b || b + a > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+" + a + ") <= " + this.buffer.byteLength);
  211. }
  212. b = this.slice(b, b + a);
  213. c && (this.offset += a);
  214. return b;
  215. };
  216. d.writeInt8 = function (a, b) {
  217. var c = "undefined" === typeof b;
  218. c && (b = this.offset);
  219. if (!this.noAssert) {
  220. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  221. a |= 0;
  222. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  223. b >>>= 0;
  224. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  225. }
  226. b += 1;
  227. var e = this.buffer.byteLength;
  228. b > e && this.resize((e *= 2) > b ? e : b);
  229. this.view[b - 1] = a;
  230. c && (this.offset += 1);
  231. return this;
  232. };
  233. d.writeByte = d.writeInt8;
  234. d.readInt8 = function (a) {
  235. var b = "undefined" === typeof a;
  236. b && (a = this.offset);
  237. if (!this.noAssert) {
  238. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  239. a >>>= 0;
  240. if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
  241. }
  242. a = this.view[a];
  243. 128 === (a & 128) && (a = -(255 - a + 1));
  244. b && (this.offset += 1);
  245. return a;
  246. };
  247. d.readByte = d.readInt8;
  248. d.writeUint8 = function (a, b) {
  249. var c = "undefined" === typeof b;
  250. c && (b = this.offset);
  251. if (!this.noAssert) {
  252. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  253. a >>>= 0;
  254. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  255. b >>>= 0;
  256. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  257. }
  258. b += 1;
  259. var e = this.buffer.byteLength;
  260. b > e && this.resize((e *= 2) > b ? e : b);
  261. this.view[b - 1] = a;
  262. c && (this.offset += 1);
  263. return this;
  264. };
  265. d.writeUInt8 = d.writeUint8;
  266. d.readUint8 = function (a) {
  267. var b = "undefined" === typeof a;
  268. b && (a = this.offset);
  269. if (!this.noAssert) {
  270. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  271. a >>>= 0;
  272. if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
  273. }
  274. a = this.view[a];
  275. b && (this.offset += 1);
  276. return a;
  277. };
  278. d.readUInt8 = d.readUint8;
  279. d.writeInt16 = function (a, b) {
  280. var c = "undefined" === typeof b;
  281. c && (b = this.offset);
  282. if (!this.noAssert) {
  283. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  284. a |= 0;
  285. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  286. b >>>= 0;
  287. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  288. }
  289. b += 2;
  290. var e = this.buffer.byteLength;
  291. b > e && this.resize((e *= 2) > b ? e : b);
  292. b -= 2;
  293. this.littleEndian ? ((this.view[b + 1] = (a & 65280) >>> 8), (this.view[b] = a & 255)) : ((this.view[b] = (a & 65280) >>> 8), (this.view[b + 1] = a & 255));
  294. c && (this.offset += 2);
  295. return this;
  296. };
  297. d.writeShort = d.writeInt16;
  298. d.readInt16 = function (a) {
  299. var b = "undefined" === typeof a;
  300. b && (a = this.offset);
  301. if (!this.noAssert) {
  302. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  303. a >>>= 0;
  304. if (0 > a || a + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+2) <= " + this.buffer.byteLength);
  305. }
  306. if (this.littleEndian) {
  307. var c = this.view[a];
  308. c |= this.view[a + 1] << 8;
  309. } else (c = this.view[a] << 8), (c |= this.view[a + 1]);
  310. 32768 === (c & 32768) && (c = -(65535 - c + 1));
  311. b && (this.offset += 2);
  312. return c;
  313. };
  314. d.readShort = d.readInt16;
  315. d.writeUint16 = function (a, b) {
  316. var c = "undefined" === typeof b;
  317. c && (b = this.offset);
  318. if (!this.noAssert) {
  319. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  320. a >>>= 0;
  321. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  322. b >>>= 0;
  323. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  324. }
  325. b += 2;
  326. var e = this.buffer.byteLength;
  327. b > e && this.resize((e *= 2) > b ? e : b);
  328. b -= 2;
  329. this.littleEndian ? ((this.view[b + 1] = (a & 65280) >>> 8), (this.view[b] = a & 255)) : ((this.view[b] = (a & 65280) >>> 8), (this.view[b + 1] = a & 255));
  330. c && (this.offset += 2);
  331. return this;
  332. };
  333. d.writeUInt16 = d.writeUint16;
  334. d.readUint16 = function (a) {
  335. var b = "undefined" === typeof a;
  336. b && (a = this.offset);
  337. if (!this.noAssert) {
  338. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  339. a >>>= 0;
  340. if (0 > a || a + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+2) <= " + this.buffer.byteLength);
  341. }
  342. if (this.littleEndian) {
  343. var c = this.view[a];
  344. c |= this.view[a + 1] << 8;
  345. } else (c = this.view[a] << 8), (c |= this.view[a + 1]);
  346. b && (this.offset += 2);
  347. return c;
  348. };
  349. d.readUInt16 = d.readUint16;
  350. d.writeInt32 = function (a, b) {
  351. var c = "undefined" === typeof b;
  352. c && (b = this.offset);
  353. if (!this.noAssert) {
  354. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  355. a |= 0;
  356. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  357. b >>>= 0;
  358. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  359. }
  360. b += 4;
  361. var e = this.buffer.byteLength;
  362. b > e && this.resize((e *= 2) > b ? e : b);
  363. b -= 4;
  364. this.littleEndian
  365. ? ((this.view[b + 3] = (a >>> 24) & 255), (this.view[b + 2] = (a >>> 16) & 255), (this.view[b + 1] = (a >>> 8) & 255), (this.view[b] = a & 255))
  366. : ((this.view[b] = (a >>> 24) & 255), (this.view[b + 1] = (a >>> 16) & 255), (this.view[b + 2] = (a >>> 8) & 255), (this.view[b + 3] = a & 255));
  367. c && (this.offset += 4);
  368. return this;
  369. };
  370. d.writeInt = d.writeInt32;
  371. d.readInt32 = function (a) {
  372. var b = "undefined" === typeof a;
  373. b && (a = this.offset);
  374. if (!this.noAssert) {
  375. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  376. a >>>= 0;
  377. if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
  378. }
  379. if (this.littleEndian) {
  380. var c = this.view[a + 2] << 16;
  381. c |= this.view[a + 1] << 8;
  382. c |= this.view[a];
  383. c += (this.view[a + 3] << 24) >>> 0;
  384. } else (c = this.view[a + 1] << 16), (c |= this.view[a + 2] << 8), (c |= this.view[a + 3]), (c += (this.view[a] << 24) >>> 0);
  385. b && (this.offset += 4);
  386. return c | 0;
  387. };
  388. d.readInt = d.readInt32;
  389. d.writeUint32 = function (a, b) {
  390. var c = "undefined" === typeof b;
  391. c && (b = this.offset);
  392. if (!this.noAssert) {
  393. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  394. a >>>= 0;
  395. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  396. b >>>= 0;
  397. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  398. }
  399. b += 4;
  400. var e = this.buffer.byteLength;
  401. b > e && this.resize((e *= 2) > b ? e : b);
  402. b -= 4;
  403. this.littleEndian
  404. ? ((this.view[b + 3] = (a >>> 24) & 255), (this.view[b + 2] = (a >>> 16) & 255), (this.view[b + 1] = (a >>> 8) & 255), (this.view[b] = a & 255))
  405. : ((this.view[b] = (a >>> 24) & 255), (this.view[b + 1] = (a >>> 16) & 255), (this.view[b + 2] = (a >>> 8) & 255), (this.view[b + 3] = a & 255));
  406. c && (this.offset += 4);
  407. return this;
  408. };
  409. d.writeUInt32 = d.writeUint32;
  410. d.readUint32 = function (a) {
  411. var b = "undefined" === typeof a;
  412. b && (a = this.offset);
  413. if (!this.noAssert) {
  414. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  415. a >>>= 0;
  416. if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
  417. }
  418. if (this.littleEndian) {
  419. var c = this.view[a + 2] << 16;
  420. c |= this.view[a + 1] << 8;
  421. c |= this.view[a];
  422. c += (this.view[a + 3] << 24) >>> 0;
  423. } else (c = this.view[a + 1] << 16), (c |= this.view[a + 2] << 8), (c |= this.view[a + 3]), (c += (this.view[a] << 24) >>> 0);
  424. b && (this.offset += 4);
  425. return c;
  426. };
  427. d.readUInt32 = d.readUint32;
  428. h &&
  429. ((d.writeInt64 = function (a, b) {
  430. var c = "undefined" === typeof b;
  431. c && (b = this.offset);
  432. if (!this.noAssert) {
  433. if ("number" === typeof a) a = h.fromNumber(a);
  434. else if ("string" === typeof a) a = h.fromString(a);
  435. else if (!(a && a instanceof h)) throw TypeError("Illegal value: " + a + " (not an integer or Long)");
  436. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  437. b >>>= 0;
  438. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  439. }
  440. "number" === typeof a ? (a = h.fromNumber(a)) : "string" === typeof a && (a = h.fromString(a));
  441. b += 8;
  442. var e = this.buffer.byteLength;
  443. b > e && this.resize((e *= 2) > b ? e : b);
  444. b -= 8;
  445. e = a.low;
  446. a = a.high;
  447. this.littleEndian
  448. ? ((this.view[b + 3] = (e >>> 24) & 255),
  449. (this.view[b + 2] = (e >>> 16) & 255),
  450. (this.view[b + 1] = (e >>> 8) & 255),
  451. (this.view[b] = e & 255),
  452. (b += 4),
  453. (this.view[b + 3] = (a >>> 24) & 255),
  454. (this.view[b + 2] = (a >>> 16) & 255),
  455. (this.view[b + 1] = (a >>> 8) & 255),
  456. (this.view[b] = a & 255))
  457. : ((this.view[b] = (a >>> 24) & 255),
  458. (this.view[b + 1] = (a >>> 16) & 255),
  459. (this.view[b + 2] = (a >>> 8) & 255),
  460. (this.view[b + 3] = a & 255),
  461. (b += 4),
  462. (this.view[b] = (e >>> 24) & 255),
  463. (this.view[b + 1] = (e >>> 16) & 255),
  464. (this.view[b + 2] = (e >>> 8) & 255),
  465. (this.view[b + 3] = e & 255));
  466. c && (this.offset += 8);
  467. return this;
  468. }),
  469. (d.writeLong = d.writeInt64),
  470. (d.readInt64 = function (a) {
  471. var b = "undefined" === typeof a;
  472. b && (a = this.offset);
  473. if (!this.noAssert) {
  474. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  475. a >>>= 0;
  476. if (0 > a || a + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+8) <= " + this.buffer.byteLength);
  477. }
  478. if (this.littleEndian) {
  479. var c = this.view[a + 2] << 16;
  480. c |= this.view[a + 1] << 8;
  481. c |= this.view[a];
  482. c += (this.view[a + 3] << 24) >>> 0;
  483. a += 4;
  484. var e = this.view[a + 2] << 16;
  485. e |= this.view[a + 1] << 8;
  486. e |= this.view[a];
  487. e += (this.view[a + 3] << 24) >>> 0;
  488. } else
  489. (e = this.view[a + 1] << 16),
  490. (e |= this.view[a + 2] << 8),
  491. (e |= this.view[a + 3]),
  492. (e += (this.view[a] << 24) >>> 0),
  493. (a += 4),
  494. (c = this.view[a + 1] << 16),
  495. (c |= this.view[a + 2] << 8),
  496. (c |= this.view[a + 3]),
  497. (c += (this.view[a] << 24) >>> 0);
  498. a = new h(c, e, !1);
  499. b && (this.offset += 8);
  500. return a;
  501. }),
  502. (d.readLong = d.readInt64),
  503. (d.writeUint64 = function (a, b) {
  504. var c = "undefined" === typeof b;
  505. c && (b = this.offset);
  506. if (!this.noAssert) {
  507. if ("number" === typeof a) a = h.fromNumber(a);
  508. else if ("string" === typeof a) a = h.fromString(a);
  509. else if (!(a && a instanceof h)) throw TypeError("Illegal value: " + a + " (not an integer or Long)");
  510. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  511. b >>>= 0;
  512. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  513. }
  514. "number" === typeof a ? (a = h.fromNumber(a)) : "string" === typeof a && (a = h.fromString(a));
  515. b += 8;
  516. var e = this.buffer.byteLength;
  517. b > e && this.resize((e *= 2) > b ? e : b);
  518. b -= 8;
  519. e = a.low;
  520. a = a.high;
  521. this.littleEndian
  522. ? ((this.view[b + 3] = (e >>> 24) & 255),
  523. (this.view[b + 2] = (e >>> 16) & 255),
  524. (this.view[b + 1] = (e >>> 8) & 255),
  525. (this.view[b] = e & 255),
  526. (b += 4),
  527. (this.view[b + 3] = (a >>> 24) & 255),
  528. (this.view[b + 2] = (a >>> 16) & 255),
  529. (this.view[b + 1] = (a >>> 8) & 255),
  530. (this.view[b] = a & 255))
  531. : ((this.view[b] = (a >>> 24) & 255),
  532. (this.view[b + 1] = (a >>> 16) & 255),
  533. (this.view[b + 2] = (a >>> 8) & 255),
  534. (this.view[b + 3] = a & 255),
  535. (b += 4),
  536. (this.view[b] = (e >>> 24) & 255),
  537. (this.view[b + 1] = (e >>> 16) & 255),
  538. (this.view[b + 2] = (e >>> 8) & 255),
  539. (this.view[b + 3] = e & 255));
  540. c && (this.offset += 8);
  541. return this;
  542. }),
  543. (d.writeUInt64 = d.writeUint64),
  544. (d.readUint64 = function (a) {
  545. var b = "undefined" === typeof a;
  546. b && (a = this.offset);
  547. if (!this.noAssert) {
  548. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  549. a >>>= 0;
  550. if (0 > a || a + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+8) <= " + this.buffer.byteLength);
  551. }
  552. if (this.littleEndian) {
  553. var c = this.view[a + 2] << 16;
  554. c |= this.view[a + 1] << 8;
  555. c |= this.view[a];
  556. c += (this.view[a + 3] << 24) >>> 0;
  557. a += 4;
  558. var e = this.view[a + 2] << 16;
  559. e |= this.view[a + 1] << 8;
  560. e |= this.view[a];
  561. e += (this.view[a + 3] << 24) >>> 0;
  562. } else
  563. (e = this.view[a + 1] << 16),
  564. (e |= this.view[a + 2] << 8),
  565. (e |= this.view[a + 3]),
  566. (e += (this.view[a] << 24) >>> 0),
  567. (a += 4),
  568. (c = this.view[a + 1] << 16),
  569. (c |= this.view[a + 2] << 8),
  570. (c |= this.view[a + 3]),
  571. (c += (this.view[a] << 24) >>> 0);
  572. a = new h(c, e, !0);
  573. b && (this.offset += 8);
  574. return a;
  575. }),
  576. (d.readUInt64 = d.readUint64));
  577. d.writeFloat32 = function (a, b) {
  578. var c = "undefined" === typeof b;
  579. c && (b = this.offset);
  580. if (!this.noAssert) {
  581. if ("number" !== typeof a) throw TypeError("Illegal value: " + a + " (not a number)");
  582. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  583. b >>>= 0;
  584. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  585. }
  586. b += 4;
  587. var e = this.buffer.byteLength;
  588. b > e && this.resize((e *= 2) > b ? e : b);
  589. y(this.view, a, b - 4, this.littleEndian, 23, 4);
  590. c && (this.offset += 4);
  591. return this;
  592. };
  593. d.writeFloat = d.writeFloat32;
  594. d.readFloat32 = function (a) {
  595. var b = "undefined" === typeof a;
  596. b && (a = this.offset);
  597. if (!this.noAssert) {
  598. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  599. a >>>= 0;
  600. if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
  601. }
  602. a = v(this.view, a, this.littleEndian, 23, 4);
  603. b && (this.offset += 4);
  604. return a;
  605. };
  606. d.readFloat = d.readFloat32;
  607. d.writeFloat64 = function (a, b) {
  608. var c = "undefined" === typeof b;
  609. c && (b = this.offset);
  610. if (!this.noAssert) {
  611. if ("number" !== typeof a) throw TypeError("Illegal value: " + a + " (not a number)");
  612. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  613. b >>>= 0;
  614. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  615. }
  616. b += 8;
  617. var e = this.buffer.byteLength;
  618. b > e && this.resize((e *= 2) > b ? e : b);
  619. y(this.view, a, b - 8, this.littleEndian, 52, 8);
  620. c && (this.offset += 8);
  621. return this;
  622. };
  623. d.writeDouble = d.writeFloat64;
  624. d.readFloat64 = function (a) {
  625. var b = "undefined" === typeof a;
  626. b && (a = this.offset);
  627. if (!this.noAssert) {
  628. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  629. a >>>= 0;
  630. if (0 > a || a + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+8) <= " + this.buffer.byteLength);
  631. }
  632. a = v(this.view, a, this.littleEndian, 52, 8);
  633. b && (this.offset += 8);
  634. return a;
  635. };
  636. d.readDouble = d.readFloat64;
  637. g.MAX_VARINT32_BYTES = 5;
  638. g.calculateVarint32 = function (a) {
  639. a >>>= 0;
  640. return 128 > a ? 1 : 16384 > a ? 2 : 2097152 > a ? 3 : 268435456 > a ? 4 : 5;
  641. };
  642. g.zigZagEncode32 = function (a) {
  643. return (((a |= 0) << 1) ^ (a >> 31)) >>> 0;
  644. };
  645. g.zigZagDecode32 = function (a) {
  646. return ((a >>> 1) ^ -(a & 1)) | 0;
  647. };
  648. d.writeVarint32 = function (a, b) {
  649. var c = "undefined" === typeof b;
  650. c && (b = this.offset);
  651. if (!this.noAssert) {
  652. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  653. a |= 0;
  654. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  655. b >>>= 0;
  656. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  657. }
  658. var e = g.calculateVarint32(a);
  659. b += e;
  660. var k = this.buffer.byteLength;
  661. b > k && this.resize((k *= 2) > b ? k : b);
  662. b -= e;
  663. for (a >>>= 0; 128 <= a; ) (k = (a & 127) | 128), (this.view[b++] = k), (a >>>= 7);
  664. this.view[b++] = a;
  665. return c ? ((this.offset = b), this) : e;
  666. };
  667. d.writeVarint32ZigZag = function (a, b) {
  668. return this.writeVarint32(g.zigZagEncode32(a), b);
  669. };
  670. d.readVarint32 = function (a) {
  671. var b = "undefined" === typeof a;
  672. b && (a = this.offset);
  673. if (!this.noAssert) {
  674. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  675. a >>>= 0;
  676. if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
  677. }
  678. var c = 0,
  679. e = 0;
  680. do {
  681. if (!this.noAssert && a > this.limit) throw ((a = Error("Truncated")), (a.truncated = !0), a);
  682. var k = this.view[a++];
  683. 5 > c && (e |= (k & 127) << (7 * c));
  684. ++c;
  685. } while (0 !== (k & 128));
  686. e |= 0;
  687. return b ? ((this.offset = a), e) : { value: e, length: c };
  688. };
  689. d.readVarint32ZigZag = function (a) {
  690. a = this.readVarint32(a);
  691. "object" === typeof a ? (a.value = g.zigZagDecode32(a.value)) : (a = g.zigZagDecode32(a));
  692. return a;
  693. };
  694. h &&
  695. ((g.MAX_VARINT64_BYTES = 10),
  696. (g.calculateVarint64 = function (a) {
  697. "number" === typeof a ? (a = h.fromNumber(a)) : "string" === typeof a && (a = h.fromString(a));
  698. var b = a.toInt() >>> 0,
  699. c = a.shiftRightUnsigned(28).toInt() >>> 0;
  700. a = a.shiftRightUnsigned(56).toInt() >>> 0;
  701. return 0 == a ? (0 == c ? (16384 > b ? (128 > b ? 1 : 2) : 2097152 > b ? 3 : 4) : 16384 > c ? (128 > c ? 5 : 6) : 2097152 > c ? 7 : 8) : 128 > a ? 9 : 10;
  702. }),
  703. (g.zigZagEncode64 = function (a) {
  704. "number" === typeof a ? (a = h.fromNumber(a, !1)) : "string" === typeof a ? (a = h.fromString(a, !1)) : !1 !== a.unsigned && (a = a.toSigned());
  705. return a.shiftLeft(1).xor(a.shiftRight(63)).toUnsigned();
  706. }),
  707. (g.zigZagDecode64 = function (a) {
  708. "number" === typeof a ? (a = h.fromNumber(a, !1)) : "string" === typeof a ? (a = h.fromString(a, !1)) : !1 !== a.unsigned && (a = a.toSigned());
  709. return a.shiftRightUnsigned(1).xor(a.and(h.ONE).toSigned().negate()).toSigned();
  710. }),
  711. (d.writeVarint64 = function (a, b) {
  712. var c = "undefined" === typeof b;
  713. c && (b = this.offset);
  714. if (!this.noAssert) {
  715. if ("number" === typeof a) a = h.fromNumber(a);
  716. else if ("string" === typeof a) a = h.fromString(a);
  717. else if (!(a && a instanceof h)) throw TypeError("Illegal value: " + a + " (not an integer or Long)");
  718. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  719. b >>>= 0;
  720. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  721. }
  722. "number" === typeof a ? (a = h.fromNumber(a, !1)) : "string" === typeof a ? (a = h.fromString(a, !1)) : !1 !== a.unsigned && (a = a.toSigned());
  723. var e = g.calculateVarint64(a),
  724. k = a.toInt() >>> 0,
  725. f = a.shiftRightUnsigned(28).toInt() >>> 0;
  726. a = a.shiftRightUnsigned(56).toInt() >>> 0;
  727. b += e;
  728. var d = this.buffer.byteLength;
  729. b > d && this.resize((d *= 2) > b ? d : b);
  730. b -= e;
  731. switch (e) {
  732. case 10:
  733. this.view[b + 9] = (a >>> 7) & 1;
  734. case 9:
  735. this.view[b + 8] = 9 !== e ? a | 128 : a & 127;
  736. case 8:
  737. this.view[b + 7] = 8 !== e ? (f >>> 21) | 128 : (f >>> 21) & 127;
  738. case 7:
  739. this.view[b + 6] = 7 !== e ? (f >>> 14) | 128 : (f >>> 14) & 127;
  740. case 6:
  741. this.view[b + 5] = 6 !== e ? (f >>> 7) | 128 : (f >>> 7) & 127;
  742. case 5:
  743. this.view[b + 4] = 5 !== e ? f | 128 : f & 127;
  744. case 4:
  745. this.view[b + 3] = 4 !== e ? (k >>> 21) | 128 : (k >>> 21) & 127;
  746. case 3:
  747. this.view[b + 2] = 3 !== e ? (k >>> 14) | 128 : (k >>> 14) & 127;
  748. case 2:
  749. this.view[b + 1] = 2 !== e ? (k >>> 7) | 128 : (k >>> 7) & 127;
  750. case 1:
  751. this.view[b] = 1 !== e ? k | 128 : k & 127;
  752. }
  753. return c ? ((this.offset += e), this) : e;
  754. }),
  755. (d.writeVarint64ZigZag = function (a, b) {
  756. return this.writeVarint64(g.zigZagEncode64(a), b);
  757. }),
  758. (d.readVarint64 = function (a) {
  759. var b = "undefined" === typeof a;
  760. b && (a = this.offset);
  761. if (!this.noAssert) {
  762. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  763. a >>>= 0;
  764. if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
  765. }
  766. var c = a,
  767. e = 0,
  768. k = 0;
  769. var d = this.view[a++];
  770. var g = d & 127;
  771. if (
  772. d & 128 &&
  773. ((d = this.view[a++]), (g |= (d & 127) << 7), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  774. ((d = this.view[a++]), (g |= (d & 127) << 14), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  775. ((d = this.view[a++]), (g |= (d & 127) << 21), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  776. ((d = this.view[a++]), (e = d & 127), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  777. ((d = this.view[a++]), (e |= (d & 127) << 7), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  778. ((d = this.view[a++]), (e |= (d & 127) << 14), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  779. ((d = this.view[a++]), (e |= (d & 127) << 21), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  780. ((d = this.view[a++]), (k = d & 127), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
  781. ((d = this.view[a++]), (k |= (d & 127) << 7), d & 128 || (this.noAssert && "undefined" === typeof d))
  782. )
  783. throw Error("Buffer overrun");
  784. g = h.fromBits(g | (e << 28), (e >>> 4) | (k << 24), !1);
  785. return b ? ((this.offset = a), g) : { value: g, length: a - c };
  786. }),
  787. (d.readVarint64ZigZag = function (a) {
  788. (a = this.readVarint64(a)) && a.value instanceof h ? (a.value = g.zigZagDecode64(a.value)) : (a = g.zigZagDecode64(a));
  789. return a;
  790. }));
  791. d.writeCString = function (a, b) {
  792. var c = "undefined" === typeof b;
  793. c && (b = this.offset);
  794. var e,
  795. d = a.length;
  796. if (!this.noAssert) {
  797. if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
  798. for (e = 0; e < d; ++e) if (0 === a.charCodeAt(e)) throw RangeError("Illegal str: Contains NULL-characters");
  799. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  800. b >>>= 0;
  801. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  802. }
  803. d = m.calculateUTF16asUTF8(l(a))[1];
  804. b += d + 1;
  805. e = this.buffer.byteLength;
  806. b > e && this.resize((e *= 2) > b ? e : b);
  807. b -= d + 1;
  808. m.encodeUTF16toUTF8(
  809. l(a),
  810. function (a) {
  811. this.view[b++] = a;
  812. }.bind(this)
  813. );
  814. this.view[b++] = 0;
  815. return c ? ((this.offset = b), this) : d;
  816. };
  817. d.readCString = function (a) {
  818. var b = "undefined" === typeof a;
  819. b && (a = this.offset);
  820. if (!this.noAssert) {
  821. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  822. a >>>= 0;
  823. if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
  824. }
  825. var c = a,
  826. e,
  827. d = -1;
  828. m.decodeUTF8toUTF16(
  829. function () {
  830. if (0 === d) return null;
  831. if (a >= this.limit) throw RangeError("Illegal range: Truncated data, " + a + " < " + this.limit);
  832. d = this.view[a++];
  833. return 0 === d ? null : d;
  834. }.bind(this),
  835. (e = t()),
  836. !0
  837. );
  838. return b ? ((this.offset = a), e()) : { string: e(), length: a - c };
  839. };
  840. d.writeIString = function (a, b) {
  841. var c = "undefined" === typeof b;
  842. c && (b = this.offset);
  843. if (!this.noAssert) {
  844. if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
  845. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  846. b >>>= 0;
  847. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  848. }
  849. var e = b;
  850. var d = m.calculateUTF16asUTF8(l(a), this.noAssert)[1];
  851. b += 4 + d;
  852. var f = this.buffer.byteLength;
  853. b > f && this.resize((f *= 2) > b ? f : b);
  854. b -= 4 + d;
  855. this.littleEndian
  856. ? ((this.view[b + 3] = (d >>> 24) & 255), (this.view[b + 2] = (d >>> 16) & 255), (this.view[b + 1] = (d >>> 8) & 255), (this.view[b] = d & 255))
  857. : ((this.view[b] = (d >>> 24) & 255), (this.view[b + 1] = (d >>> 16) & 255), (this.view[b + 2] = (d >>> 8) & 255), (this.view[b + 3] = d & 255));
  858. b += 4;
  859. m.encodeUTF16toUTF8(
  860. l(a),
  861. function (a) {
  862. this.view[b++] = a;
  863. }.bind(this)
  864. );
  865. if (b !== e + 4 + d) throw RangeError("Illegal range: Truncated data, " + b + " == " + (b + 4 + d));
  866. return c ? ((this.offset = b), this) : b - e;
  867. };
  868. d.readIString = function (a) {
  869. var b = "undefined" === typeof a;
  870. b && (a = this.offset);
  871. if (!this.noAssert) {
  872. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  873. a >>>= 0;
  874. if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
  875. }
  876. var c = a,
  877. e = this.readUint32(a);
  878. e = this.readUTF8String(e, g.METRICS_BYTES, (a += 4));
  879. a += e.length;
  880. return b ? ((this.offset = a), e.string) : { string: e.string, length: a - c };
  881. };
  882. g.METRICS_CHARS = "c";
  883. g.METRICS_BYTES = "b";
  884. d.writeUTF8String = function (a, b) {
  885. var c = "undefined" === typeof b;
  886. c && (b = this.offset);
  887. if (!this.noAssert) {
  888. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  889. b >>>= 0;
  890. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  891. }
  892. var e = b;
  893. var d = m.calculateUTF16asUTF8(l(a))[1];
  894. b += d;
  895. var f = this.buffer.byteLength;
  896. b > f && this.resize((f *= 2) > b ? f : b);
  897. b -= d;
  898. m.encodeUTF16toUTF8(
  899. l(a),
  900. function (a) {
  901. this.view[b++] = a;
  902. }.bind(this)
  903. );
  904. return c ? ((this.offset = b), this) : b - e;
  905. };
  906. d.writeString = d.writeUTF8String;
  907. g.calculateUTF8Chars = function (a) {
  908. return m.calculateUTF16asUTF8(l(a))[0];
  909. };
  910. g.calculateUTF8Bytes = function (a) {
  911. return m.calculateUTF16asUTF8(l(a))[1];
  912. };
  913. g.calculateString = g.calculateUTF8Bytes;
  914. d.readUTF8String = function (a, b, c) {
  915. "number" === typeof b && ((c = b), (b = void 0));
  916. var e = "undefined" === typeof c;
  917. e && (c = this.offset);
  918. "undefined" === typeof b && (b = g.METRICS_CHARS);
  919. if (!this.noAssert) {
  920. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal length: " + a + " (not an integer)");
  921. a |= 0;
  922. if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
  923. c >>>= 0;
  924. if (0 > c || c + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+0) <= " + this.buffer.byteLength);
  925. }
  926. var d = 0,
  927. f = c;
  928. if (b === g.METRICS_CHARS) {
  929. var p = t();
  930. m.decodeUTF8(
  931. function () {
  932. return d < a && c < this.limit ? this.view[c++] : null;
  933. }.bind(this),
  934. function (a) {
  935. ++d;
  936. m.UTF8toUTF16(a, p);
  937. }
  938. );
  939. if (d !== a) throw RangeError("Illegal range: Truncated data, " + d + " == " + a);
  940. return e ? ((this.offset = c), p()) : { string: p(), length: c - f };
  941. }
  942. if (b === g.METRICS_BYTES) {
  943. if (!this.noAssert) {
  944. if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
  945. c >>>= 0;
  946. if (0 > c || c + a > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+" + a + ") <= " + this.buffer.byteLength);
  947. }
  948. var h = c + a;
  949. m.decodeUTF8toUTF16(
  950. function () {
  951. return c < h ? this.view[c++] : null;
  952. }.bind(this),
  953. (p = t()),
  954. this.noAssert
  955. );
  956. if (c !== h) throw RangeError("Illegal range: Truncated data, " + c + " == " + h);
  957. return e ? ((this.offset = c), p()) : { string: p(), length: c - f };
  958. }
  959. throw TypeError("Unsupported metrics: " + b);
  960. };
  961. d.readString = d.readUTF8String;
  962. d.writeVString = function (a, b) {
  963. var c = "undefined" === typeof b;
  964. c && (b = this.offset);
  965. if (!this.noAssert) {
  966. if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
  967. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
  968. b >>>= 0;
  969. if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
  970. }
  971. var e = b;
  972. var d = m.calculateUTF16asUTF8(l(a), this.noAssert)[1];
  973. var f = g.calculateVarint32(d);
  974. b += f + d;
  975. var p = this.buffer.byteLength;
  976. b > p && this.resize((p *= 2) > b ? p : b);
  977. b -= f + d;
  978. b += this.writeVarint32(d, b);
  979. m.encodeUTF16toUTF8(
  980. l(a),
  981. function (a) {
  982. this.view[b++] = a;
  983. }.bind(this)
  984. );
  985. if (b !== e + d + f) throw RangeError("Illegal range: Truncated data, " + b + " == " + (b + d + f));
  986. return c ? ((this.offset = b), this) : b - e;
  987. };
  988. d.readVString = function (a) {
  989. var b = "undefined" === typeof a;
  990. b && (a = this.offset);
  991. if (!this.noAssert) {
  992. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  993. a >>>= 0;
  994. if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
  995. }
  996. var c = a,
  997. e = this.readVarint32(a);
  998. e = this.readUTF8String(e.value, g.METRICS_BYTES, (a += e.length));
  999. a += e.length;
  1000. return b ? ((this.offset = a), e.string) : { string: e.string, length: a - c };
  1001. };
  1002. d.append = function (a, b, c) {
  1003. if ("number" === typeof b || "string" !== typeof b) (c = b), (b = void 0);
  1004. var e = "undefined" === typeof c;
  1005. e && (c = this.offset);
  1006. if (!this.noAssert) {
  1007. if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
  1008. c >>>= 0;
  1009. if (0 > c || c + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+0) <= " + this.buffer.byteLength);
  1010. }
  1011. a instanceof g || (a = g.wrap(a, b));
  1012. b = a.limit - a.offset;
  1013. if (0 >= b) return this;
  1014. c += b;
  1015. var d = this.buffer.byteLength;
  1016. c > d && this.resize((d *= 2) > c ? d : c);
  1017. c -= b;
  1018. this.view.set(a.view.subarray(a.offset, a.limit), c);
  1019. a.offset += b;
  1020. e && (this.offset += b);
  1021. return this;
  1022. };
  1023. d.appendTo = function (a, b) {
  1024. a.append(this, b);
  1025. return this;
  1026. };
  1027. d.writeBytes = d.append;
  1028. d.assert = function (a) {
  1029. this.noAssert = !a;
  1030. return this;
  1031. };
  1032. d.capacity = function () {
  1033. return this.buffer.byteLength;
  1034. };
  1035. d.clear = function () {
  1036. this.offset = 0;
  1037. this.limit = this.buffer.byteLength;
  1038. this.markedOffset = -1;
  1039. return this;
  1040. };
  1041. d.clone = function (a) {
  1042. var b = new g(0, this.littleEndian, this.noAssert);
  1043. a ? ((b.buffer = new ArrayBuffer(this.buffer.byteLength)), (b.view = new Uint8Array(b.buffer))) : ((b.buffer = this.buffer), (b.view = this.view));
  1044. b.offset = this.offset;
  1045. b.markedOffset = this.markedOffset;
  1046. b.limit = this.limit;
  1047. return b;
  1048. };
  1049. d.compact = function (a, b) {
  1050. "undefined" === typeof a && (a = this.offset);
  1051. "undefined" === typeof b && (b = this.limit);
  1052. if (!this.noAssert) {
  1053. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
  1054. a >>>= 0;
  1055. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
  1056. b >>>= 0;
  1057. if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
  1058. }
  1059. if (0 === a && b === this.buffer.byteLength) return this;
  1060. var c = b - a;
  1061. if (0 === c) return (this.buffer = w), (this.view = null), 0 <= this.markedOffset && (this.markedOffset -= a), (this.limit = this.offset = 0), this;
  1062. var e = new ArrayBuffer(c),
  1063. d = new Uint8Array(e);
  1064. d.set(this.view.subarray(a, b));
  1065. this.buffer = e;
  1066. this.view = d;
  1067. 0 <= this.markedOffset && (this.markedOffset -= a);
  1068. this.offset = 0;
  1069. this.limit = c;
  1070. return this;
  1071. };
  1072. d.copy = function (a, b) {
  1073. "undefined" === typeof a && (a = this.offset);
  1074. "undefined" === typeof b && (b = this.limit);
  1075. if (!this.noAssert) {
  1076. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
  1077. a >>>= 0;
  1078. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
  1079. b >>>= 0;
  1080. if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
  1081. }
  1082. if (a === b) return new g(0, this.littleEndian, this.noAssert);
  1083. var c = b - a,
  1084. e = new g(c, this.littleEndian, this.noAssert);
  1085. e.offset = 0;
  1086. e.limit = c;
  1087. 0 <= e.markedOffset && (e.markedOffset -= a);
  1088. this.copyTo(e, 0, a, b);
  1089. return e;
  1090. };
  1091. d.copyTo = function (a, b, c, e) {
  1092. var d, f;
  1093. if (!this.noAssert && !g.isByteBuffer(a)) throw TypeError("Illegal target: Not a ByteBuffer");
  1094. b = (f = "undefined" === typeof b) ? a.offset : b | 0;
  1095. c = (d = "undefined" === typeof c) ? this.offset : c | 0;
  1096. e = "undefined" === typeof e ? this.limit : e | 0;
  1097. if (0 > b || b > a.buffer.byteLength) throw RangeError("Illegal target range: 0 <= " + b + " <= " + a.buffer.byteLength);
  1098. if (0 > c || e > this.buffer.byteLength) throw RangeError("Illegal source range: 0 <= " + c + " <= " + this.buffer.byteLength);
  1099. var p = e - c;
  1100. if (0 === p) return a;
  1101. a.ensureCapacity(b + p);
  1102. a.view.set(this.view.subarray(c, e), b);
  1103. d && (this.offset += p);
  1104. f && (a.offset += p);
  1105. return this;
  1106. };
  1107. d.ensureCapacity = function (a) {
  1108. var b = this.buffer.byteLength;
  1109. return b < a ? this.resize((b *= 2) > a ? b : a) : this;
  1110. };
  1111. d.fill = function (a, b, c) {
  1112. var e = "undefined" === typeof b;
  1113. e && (b = this.offset);
  1114. "string" === typeof a && 0 < a.length && (a = a.charCodeAt(0));
  1115. "undefined" === typeof b && (b = this.offset);
  1116. "undefined" === typeof c && (c = this.limit);
  1117. if (!this.noAssert) {
  1118. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
  1119. a |= 0;
  1120. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal begin: Not an integer");
  1121. b >>>= 0;
  1122. if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal end: Not an integer");
  1123. c >>>= 0;
  1124. if (0 > b || b > c || c > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + b + " <= " + c + " <= " + this.buffer.byteLength);
  1125. }
  1126. if (b >= c) return this;
  1127. for (; b < c; ) this.view[b++] = a;
  1128. e && (this.offset = b);
  1129. return this;
  1130. };
  1131. d.flip = function () {
  1132. this.limit = this.offset;
  1133. this.offset = 0;
  1134. return this;
  1135. };
  1136. d.mark = function (a) {
  1137. a = "undefined" === typeof a ? this.offset : a;
  1138. if (!this.noAssert) {
  1139. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
  1140. a >>>= 0;
  1141. if (0 > a || a + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+0) <= " + this.buffer.byteLength);
  1142. }
  1143. this.markedOffset = a;
  1144. return this;
  1145. };
  1146. d.order = function (a) {
  1147. if (!this.noAssert && "boolean" !== typeof a) throw TypeError("Illegal littleEndian: Not a boolean");
  1148. this.littleEndian = !!a;
  1149. return this;
  1150. };
  1151. d.LE = function (a) {
  1152. this.littleEndian = "undefined" !== typeof a ? !!a : !0;
  1153. return this;
  1154. };
  1155. d.BE = function (a) {
  1156. this.littleEndian = "undefined" !== typeof a ? !a : !1;
  1157. return this;
  1158. };
  1159. d.prepend = function (a, b, c) {
  1160. if ("number" === typeof b || "string" !== typeof b) (c = b), (b = void 0);
  1161. var e = "undefined" === typeof c;
  1162. e && (c = this.offset);
  1163. if (!this.noAssert) {
  1164. if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
  1165. c >>>= 0;
  1166. if (0 > c || c + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+0) <= " + this.buffer.byteLength);
  1167. }
  1168. a instanceof g || (a = g.wrap(a, b));
  1169. b = a.limit - a.offset;
  1170. if (0 >= b) return this;
  1171. var d = b - c;
  1172. if (0 < d) {
  1173. var f = new ArrayBuffer(this.buffer.byteLength + d),
  1174. p = new Uint8Array(f);
  1175. p.set(this.view.subarray(c, this.buffer.byteLength), b);
  1176. this.buffer = f;
  1177. this.view = p;
  1178. this.offset += d;
  1179. 0 <= this.markedOffset && (this.markedOffset += d);
  1180. this.limit += d;
  1181. c += d;
  1182. } else new Uint8Array(this.buffer);
  1183. this.view.set(a.view.subarray(a.offset, a.limit), c - b);
  1184. a.offset = a.limit;
  1185. e && (this.offset -= b);
  1186. return this;
  1187. };
  1188. d.prependTo = function (a, b) {
  1189. a.prepend(this, b);
  1190. return this;
  1191. };
  1192. d.printDebug = function (a) {
  1193. "function" !== typeof a && (a = console.log.bind(console));
  1194. a(this.toString() + "\n-------------------------------------------------------------------\n" + this.toDebug(!0));
  1195. };
  1196. d.remaining = function () {
  1197. return this.limit - this.offset;
  1198. };
  1199. d.reset = function () {
  1200. 0 <= this.markedOffset ? ((this.offset = this.markedOffset), (this.markedOffset = -1)) : (this.offset = 0);
  1201. return this;
  1202. };
  1203. d.resize = function (a) {
  1204. if (!this.noAssert) {
  1205. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal capacity: " + a + " (not an integer)");
  1206. a |= 0;
  1207. if (0 > a) throw RangeError("Illegal capacity: 0 <= " + a);
  1208. }
  1209. if (this.buffer.byteLength < a) {
  1210. a = new ArrayBuffer(a);
  1211. var b = new Uint8Array(a);
  1212. b.set(this.view);
  1213. this.buffer = a;
  1214. this.view = b;
  1215. }
  1216. return this;
  1217. };
  1218. d.reverse = function (a, b) {
  1219. "undefined" === typeof a && (a = this.offset);
  1220. "undefined" === typeof b && (b = this.limit);
  1221. if (!this.noAssert) {
  1222. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
  1223. a >>>= 0;
  1224. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
  1225. b >>>= 0;
  1226. if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
  1227. }
  1228. if (a === b) return this;
  1229. Array.prototype.reverse.call(this.view.subarray(a, b));
  1230. return this;
  1231. };
  1232. d.skip = function (a) {
  1233. if (!this.noAssert) {
  1234. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal length: " + a + " (not an integer)");
  1235. a |= 0;
  1236. }
  1237. var b = this.offset + a;
  1238. if (!this.noAssert && (0 > b || b > this.buffer.byteLength)) throw RangeError("Illegal length: 0 <= " + this.offset + " + " + a + " <= " + this.buffer.byteLength);
  1239. this.offset = b;
  1240. return this;
  1241. };
  1242. d.slice = function (a, b) {
  1243. "undefined" === typeof a && (a = this.offset);
  1244. "undefined" === typeof b && (b = this.limit);
  1245. if (!this.noAssert) {
  1246. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
  1247. a >>>= 0;
  1248. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
  1249. b >>>= 0;
  1250. if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
  1251. }
  1252. var c = this.clone();
  1253. c.offset = a;
  1254. c.limit = b;
  1255. return c;
  1256. };
  1257. d.toBuffer = function (a) {
  1258. var b = this.offset,
  1259. c = this.limit;
  1260. if (!this.noAssert) {
  1261. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: Not an integer");
  1262. b >>>= 0;
  1263. if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal limit: Not an integer");
  1264. c >>>= 0;
  1265. if (0 > b || b > c || c > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + b + " <= " + c + " <= " + this.buffer.byteLength);
  1266. }
  1267. if (!a && 0 === b && c === this.buffer.byteLength) return this.buffer;
  1268. if (b === c) return w;
  1269. a = new ArrayBuffer(c - b);
  1270. new Uint8Array(a).set(new Uint8Array(this.buffer).subarray(b, c), 0);
  1271. return a;
  1272. };
  1273. d.toArrayBuffer = d.toBuffer;
  1274. d.toString = function (a, b, c) {
  1275. if ("undefined" === typeof a) return "ByteBufferAB(offset=" + this.offset + ",markedOffset=" + this.markedOffset + ",limit=" + this.limit + ",capacity=" + this.capacity() + ")";
  1276. "number" === typeof a && (c = b = a = "utf8");
  1277. switch (a) {
  1278. case "utf8":
  1279. return this.toUTF8(b, c);
  1280. case "base64":
  1281. return this.toBase64(b, c);
  1282. case "hex":
  1283. return this.toHex(b, c);
  1284. case "binary":
  1285. return this.toBinary(b, c);
  1286. case "debug":
  1287. return this.toDebug();
  1288. case "columns":
  1289. return this.toColumns();
  1290. default:
  1291. throw Error("Unsupported encoding: " + a);
  1292. }
  1293. };
  1294. var z = (function () {
  1295. for (
  1296. var a = {},
  1297. b = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99,
  1298. 100,
  1299. 101,
  1300. 102,
  1301. 103,
  1302. 104,
  1303. 105,
  1304. 106,
  1305. 107,
  1306. 108,
  1307. 109,
  1308. 110,
  1309. 111,
  1310. 112,
  1311. 113,
  1312. 114,
  1313. 115,
  1314. 116,
  1315. 117,
  1316. 118,
  1317. 119,
  1318. 120,
  1319. 121,
  1320. 122,
  1321. 48,
  1322. 49,
  1323. 50,
  1324. 51,
  1325. 52,
  1326. 53,
  1327. 54,
  1328. 55,
  1329. 56,
  1330. 57,
  1331. 43,
  1332. 47,
  1333. ],
  1334. c = [],
  1335. e = 0,
  1336. d = b.length;
  1337. e < d;
  1338. ++e
  1339. )
  1340. c[b[e]] = e;
  1341. a.encode = function (a, c) {
  1342. for (var e, d; null !== (e = a()); )
  1343. c(b[(e >> 2) & 63]),
  1344. (d = (e & 3) << 4),
  1345. null !== (e = a())
  1346. ? ((d |= (e >> 4) & 15), c(b[(d | ((e >> 4) & 15)) & 63]), (d = (e & 15) << 2), null !== (e = a()) ? (c(b[(d | ((e >> 6) & 3)) & 63]), c(b[e & 63])) : (c(b[d & 63]), c(61)))
  1347. : (c(b[d & 63]), c(61), c(61));
  1348. };
  1349. a.decode = function (a, b) {
  1350. function e(a) {
  1351. throw Error("Illegal character code: " + a);
  1352. }
  1353. for (var d, k, f; null !== (d = a()); )
  1354. if (((k = c[d]), "undefined" === typeof k && e(d), null !== (d = a()) && ((f = c[d]), "undefined" === typeof f && e(d), b(((k << 2) >>> 0) | ((f & 48) >> 4)), null !== (d = a())))) {
  1355. k = c[d];
  1356. if ("undefined" === typeof k)
  1357. if (61 === d) break;
  1358. else e(d);
  1359. b((((f & 15) << 4) >>> 0) | ((k & 60) >> 2));
  1360. if (null !== (d = a())) {
  1361. f = c[d];
  1362. if ("undefined" === typeof f)
  1363. if (61 === d) break;
  1364. else e(d);
  1365. b((((k & 3) << 6) >>> 0) | f);
  1366. }
  1367. }
  1368. };
  1369. a.test = function (a) {
  1370. return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(a);
  1371. };
  1372. return a;
  1373. })();
  1374. d.toBase64 = function (a, b) {
  1375. "undefined" === typeof a && (a = this.offset);
  1376. "undefined" === typeof b && (b = this.limit);
  1377. a |= 0;
  1378. b |= 0;
  1379. if (0 > a || b > this.capacity || a > b) throw RangeError("begin, end");
  1380. var c;
  1381. z.encode(
  1382. function () {
  1383. return a < b ? this.view[a++] : null;
  1384. }.bind(this),
  1385. (c = t())
  1386. );
  1387. return c();
  1388. };
  1389. g.fromBase64 = function (a, b) {
  1390. if ("string" !== typeof a) throw TypeError("str");
  1391. var c = new g((a.length / 4) * 3, b),
  1392. e = 0;
  1393. z.decode(l(a), function (a) {
  1394. c.view[e++] = a;
  1395. });
  1396. c.limit = e;
  1397. return c;
  1398. };
  1399. g.btoa = function (a) {
  1400. return g.fromBinary(a).toBase64();
  1401. };
  1402. g.atob = function (a) {
  1403. return g.fromBase64(a).toBinary();
  1404. };
  1405. d.toBinary = function (a, b) {
  1406. "undefined" === typeof a && (a = this.offset);
  1407. "undefined" === typeof b && (b = this.limit);
  1408. a |= 0;
  1409. b |= 0;
  1410. if (0 > a || b > this.capacity() || a > b) throw RangeError("begin, end");
  1411. if (a === b) return "";
  1412. for (var c = [], e = []; a < b; ) c.push(this.view[a++]), 1024 <= c.length && (e.push(String.fromCharCode.apply(String, c)), (c = []));
  1413. return e.join("") + String.fromCharCode.apply(String, c);
  1414. };
  1415. g.fromBinary = function (a, b) {
  1416. if ("string" !== typeof a) throw TypeError("str");
  1417. for (var c = 0, e = a.length, d = new g(e, b); c < e; ) {
  1418. b = a.charCodeAt(c);
  1419. if (255 < b) throw RangeError("illegal char code: " + b);
  1420. d.view[c++] = b;
  1421. }
  1422. d.limit = e;
  1423. return d;
  1424. };
  1425. d.toDebug = function (a) {
  1426. for (var b = -1, c = this.buffer.byteLength, e, d = "", f = "", g = ""; b < c; ) {
  1427. -1 !== b && ((e = this.view[b]), (d = 16 > e ? d + ("0" + e.toString(16).toUpperCase()) : d + e.toString(16).toUpperCase()), a && (f += 32 < e && 127 > e ? String.fromCharCode(e) : "."));
  1428. ++b;
  1429. if (a && 0 < b && 0 === b % 16 && b !== c) {
  1430. for (; 51 > d.length; ) d += " ";
  1431. g += d + f + "\n";
  1432. d = f = "";
  1433. }
  1434. d =
  1435. b === this.offset && b === this.limit
  1436. ? d + (b === this.markedOffset ? "!" : "|")
  1437. : b === this.offset
  1438. ? d + (b === this.markedOffset ? "[" : "<")
  1439. : b === this.limit
  1440. ? d + (b === this.markedOffset ? "]" : ">")
  1441. : d + (b === this.markedOffset ? "'" : a || (0 !== b && b !== c) ? " " : "");
  1442. }
  1443. if (a && " " !== d) {
  1444. for (; 51 > d.length; ) d += " ";
  1445. g += d + f + "\n";
  1446. }
  1447. return a ? g : d;
  1448. };
  1449. g.fromDebug = function (a, b, c) {
  1450. var e = a.length;
  1451. b = new g(((e + 1) / 3) | 0, b, c);
  1452. for (var d = 0, f = 0, h, l = !1, n = !1, m = !1, q = !1, r = !1; d < e; ) {
  1453. switch ((h = a.charAt(d++))) {
  1454. case "!":
  1455. if (!c) {
  1456. if (n || m || q) {
  1457. r = !0;
  1458. break;
  1459. }
  1460. n = m = q = !0;
  1461. }
  1462. b.offset = b.markedOffset = b.limit = f;
  1463. l = !1;
  1464. break;
  1465. case "|":
  1466. if (!c) {
  1467. if (n || q) {
  1468. r = !0;
  1469. break;
  1470. }
  1471. n = q = !0;
  1472. }
  1473. b.offset = b.limit = f;
  1474. l = !1;
  1475. break;
  1476. case "[":
  1477. if (!c) {
  1478. if (n || m) {
  1479. r = !0;
  1480. break;
  1481. }
  1482. n = m = !0;
  1483. }
  1484. b.offset = b.markedOffset = f;
  1485. l = !1;
  1486. break;
  1487. case "<":
  1488. if (!c) {
  1489. if (n) {
  1490. r = !0;
  1491. break;
  1492. }
  1493. n = !0;
  1494. }
  1495. b.offset = f;
  1496. l = !1;
  1497. break;
  1498. case "]":
  1499. if (!c) {
  1500. if (q || m) {
  1501. r = !0;
  1502. break;
  1503. }
  1504. q = m = !0;
  1505. }
  1506. b.limit = b.markedOffset = f;
  1507. l = !1;
  1508. break;
  1509. case ">":
  1510. if (!c) {
  1511. if (q) {
  1512. r = !0;
  1513. break;
  1514. }
  1515. q = !0;
  1516. }
  1517. b.limit = f;
  1518. l = !1;
  1519. break;
  1520. case "'":
  1521. if (!c) {
  1522. if (m) {
  1523. r = !0;
  1524. break;
  1525. }
  1526. m = !0;
  1527. }
  1528. b.markedOffset = f;
  1529. l = !1;
  1530. break;
  1531. case " ":
  1532. l = !1;
  1533. break;
  1534. default:
  1535. if (!c && l) r = !0;
  1536. else {
  1537. h = parseInt(h + a.charAt(d++), 16);
  1538. if (!c && (isNaN(h) || 0 > h || 255 < h)) throw TypeError("Illegal str: Not a debug encoded string");
  1539. b.view[f++] = h;
  1540. l = !0;
  1541. }
  1542. }
  1543. if (r) throw TypeError("Illegal str: Invalid symbol at " + d);
  1544. }
  1545. if (!c) {
  1546. if (!n || !q) throw TypeError("Illegal str: Missing offset or limit");
  1547. if (f < b.buffer.byteLength) throw TypeError("Illegal str: Not a debug encoded string (is it hex?) " + f + " < " + e);
  1548. }
  1549. return b;
  1550. };
  1551. d.toHex = function (a, b) {
  1552. a = "undefined" === typeof a ? this.offset : a;
  1553. b = "undefined" === typeof b ? this.limit : b;
  1554. if (!this.noAssert) {
  1555. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
  1556. a >>>= 0;
  1557. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
  1558. b >>>= 0;
  1559. if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
  1560. }
  1561. for (var c = Array(b - a), e; a < b; ) (e = this.view[a++]), 16 > e ? c.push("0", e.toString(16)) : c.push(e.toString(16));
  1562. return c.join("");
  1563. };
  1564. g.fromHex = function (a, b, c) {
  1565. if (!c) {
  1566. if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
  1567. if (0 !== a.length % 2) throw TypeError("Illegal str: Length not a multiple of 2");
  1568. }
  1569. var e = a.length;
  1570. b = new g((e / 2) | 0, b);
  1571. for (var d, f = 0, h = 0; f < e; f += 2) {
  1572. d = parseInt(a.substring(f, f + 2), 16);
  1573. if (!c && (!isFinite(d) || 0 > d || 255 < d)) throw TypeError("Illegal str: Contains non-hex characters");
  1574. b.view[h++] = d;
  1575. }
  1576. b.limit = h;
  1577. return b;
  1578. };
  1579. var m = (function () {
  1580. var a = {
  1581. MAX_CODEPOINT: 1114111,
  1582. encodeUTF8: function (a, c) {
  1583. var b = null;
  1584. "number" === typeof a &&
  1585. ((b = a),
  1586. (a = function () {
  1587. return null;
  1588. }));
  1589. for (; null !== b || null !== (b = a()); )
  1590. 128 > b
  1591. ? c(b & 127)
  1592. : (2048 > b ? c(((b >> 6) & 31) | 192) : 65536 > b ? (c(((b >> 12) & 15) | 224), c(((b >> 6) & 63) | 128)) : (c(((b >> 18) & 7) | 240), c(((b >> 12) & 63) | 128), c(((b >> 6) & 63) | 128)), c((b & 63) | 128)),
  1593. (b = null);
  1594. },
  1595. decodeUTF8: function (a, c) {
  1596. for (
  1597. var b,
  1598. d,
  1599. f,
  1600. g,
  1601. h = function (a) {
  1602. a = a.slice(0, a.indexOf(null));
  1603. var b = Error(a.toString());
  1604. b.name = "TruncatedError";
  1605. b.bytes = a;
  1606. throw b;
  1607. };
  1608. null !== (b = a());
  1609.  
  1610. )
  1611. if (0 === (b & 128)) c(b);
  1612. else if (192 === (b & 224)) null === (d = a()) && h([b, d]), c(((b & 31) << 6) | (d & 63));
  1613. else if (224 === (b & 240)) (null !== (d = a()) && null !== (f = a())) || h([b, d, f]), c(((b & 15) << 12) | ((d & 63) << 6) | (f & 63));
  1614. else if (240 === (b & 248)) (null !== (d = a()) && null !== (f = a()) && null !== (g = a())) || h([b, d, f, g]), c(((b & 7) << 18) | ((d & 63) << 12) | ((f & 63) << 6) | (g & 63));
  1615. else throw RangeError("Illegal starting byte: " + b);
  1616. },
  1617. UTF16toUTF8: function (a, c) {
  1618. for (var b, d = null; null !== (b = null !== d ? d : a()); ) 55296 <= b && 57343 >= b && null !== (d = a()) && 56320 <= d && 57343 >= d ? (c(1024 * (b - 55296) + d - 56320 + 65536), (d = null)) : c(b);
  1619. null !== d && c(d);
  1620. },
  1621. UTF8toUTF16: function (a, c) {
  1622. var b = null;
  1623. "number" === typeof a &&
  1624. ((b = a),
  1625. (a = function () {
  1626. return null;
  1627. }));
  1628. for (; null !== b || null !== (b = a()); ) 65535 >= b ? c(b) : ((b -= 65536), c((b >> 10) + 55296), c((b % 1024) + 56320)), (b = null);
  1629. },
  1630. encodeUTF16toUTF8: function (b, c) {
  1631. a.UTF16toUTF8(b, function (b) {
  1632. a.encodeUTF8(b, c);
  1633. });
  1634. },
  1635. decodeUTF8toUTF16: function (b, c) {
  1636. a.decodeUTF8(b, function (b) {
  1637. a.UTF8toUTF16(b, c);
  1638. });
  1639. },
  1640. calculateCodePoint: function (a) {
  1641. return 128 > a ? 1 : 2048 > a ? 2 : 65536 > a ? 3 : 4;
  1642. },
  1643. calculateUTF8: function (a) {
  1644. for (var b, d = 0; null !== (b = a()); ) d += 128 > b ? 1 : 2048 > b ? 2 : 65536 > b ? 3 : 4;
  1645. return d;
  1646. },
  1647. calculateUTF16asUTF8: function (b) {
  1648. var c = 0,
  1649. d = 0;
  1650. a.UTF16toUTF8(b, function (a) {
  1651. ++c;
  1652. d += 128 > a ? 1 : 2048 > a ? 2 : 65536 > a ? 3 : 4;
  1653. });
  1654. return [c, d];
  1655. },
  1656. };
  1657. return a;
  1658. })();
  1659. d.toUTF8 = function (a, b) {
  1660. "undefined" === typeof a && (a = this.offset);
  1661. "undefined" === typeof b && (b = this.limit);
  1662. if (!this.noAssert) {
  1663. if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
  1664. a >>>= 0;
  1665. if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
  1666. b >>>= 0;
  1667. if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
  1668. }
  1669. var c;
  1670. try {
  1671. m.decodeUTF8toUTF16(
  1672. function () {
  1673. return a < b ? this.view[a++] : null;
  1674. }.bind(this),
  1675. (c = t())
  1676. );
  1677. } catch (e) {
  1678. if (a !== b) throw RangeError("Illegal range: Truncated data, " + a + " != " + b);
  1679. }
  1680. return c();
  1681. };
  1682. g.fromUTF8 = function (a, b, c) {
  1683. if (!c && "string" !== typeof a) throw TypeError("Illegal str: Not a string");
  1684. var d = new g(m.calculateUTF16asUTF8(l(a), !0)[1], b, c),
  1685. h = 0;
  1686. m.encodeUTF16toUTF8(l(a), function (a) {
  1687. d.view[h++] = a;
  1688. });
  1689. d.limit = h;
  1690. return d;
  1691. };
  1692. return g;
  1693. });
  1694. const { ByteBuffer } = dcodeIO;
  1695.  
  1696. /**
  1697. * Optimized Priority Queue Implementation (Min-Heap)
  1698. * Stores elements with associated priorities (keys in D* Lite).
  1699. * Uses a map for O(1) average time complexity for finding elements.
  1700. */
  1701. class PriorityQueue {
  1702. constructor() {
  1703. // Array to store heap elements: { element: string (key "x,y"), priority: number[] }
  1704. this.heap = [];
  1705. // Map to store the index of each element in the heap: { elementKey: index }
  1706. this.indices = new Map();
  1707. }
  1708.  
  1709. // Helper function to compare priorities (keys in D* Lite)
  1710. compare(keyA, keyB) {
  1711. if (keyA[0] < keyB[0]) return -1;
  1712. if (keyA[0] > keyB[0]) return 1;
  1713. // If k1 is equal, compare k2
  1714. if (keyA[1] < keyB[1]) return -1;
  1715. if (keyA[1] > keyB[1]) return 1;
  1716. return 0; // Keys are equal
  1717. }
  1718.  
  1719. // Add an element (string key) with its priority
  1720. push(elementKey, priority) {
  1721. if (this.indices.has(elementKey)) {
  1722. // If element already exists, update its priority instead of pushing
  1723. this.update(elementKey, priority);
  1724. return;
  1725. }
  1726. const index = this.heap.length;
  1727. this.heap.push({ element: elementKey, priority });
  1728. this.indices.set(elementKey, index);
  1729. this.bubbleUp(index);
  1730. }
  1731.  
  1732. // Remove and return the element (string key) with the lowest priority
  1733. pop() {
  1734. if (this.isEmpty()) {
  1735. return null;
  1736. }
  1737. const topItem = this.heap[0];
  1738. const lastItem = this.heap.pop(); // Remove last element
  1739.  
  1740. this.indices.delete(topItem.element); // Remove top element's index
  1741.  
  1742. if (!this.isEmpty()) {
  1743. // Move the last item to the top
  1744. this.heap[0] = lastItem;
  1745. this.indices.set(lastItem.element, 0); // Update index of moved element
  1746. this.bubbleDown(0); // Restore heap property
  1747. }
  1748.  
  1749. return topItem.element; // Return only the element key
  1750. }
  1751.  
  1752. // Get the element (string key) and priority with the lowest priority without removing it
  1753. peek() {
  1754. return this.isEmpty() ? null : this.heap[0]; // Return { element: key, priority: [...] }
  1755. }
  1756.  
  1757. // Update the priority of an element (string key)
  1758. update(elementKey, newPriority) {
  1759. if (!this.indices.has(elementKey)) {
  1760. // If element not found, push it
  1761. this.push(elementKey, newPriority);
  1762. return;
  1763. // Alternatively, throw an error or return if update implies existence
  1764. // console.warn(`Element ${elementKey} not found for update.`);
  1765. // return;
  1766. }
  1767.  
  1768. const index = this.indices.get(elementKey);
  1769. const oldPriority = this.heap[index].priority;
  1770. this.heap[index].priority = newPriority;
  1771.  
  1772. // Decide whether to bubble up or down based on priority change
  1773. if (this.compare(newPriority, oldPriority) < 0) {
  1774. this.bubbleUp(index);
  1775. } else {
  1776. this.bubbleDown(index);
  1777. }
  1778. }
  1779.  
  1780. // Remove an element (string key) from the queue
  1781. remove(elementKey) {
  1782. if (!this.indices.has(elementKey)) {
  1783. return false; // Element not found
  1784. }
  1785.  
  1786. const indexToRemove = this.indices.get(elementKey);
  1787. const lastItem = this.heap.pop(); // Remove last element
  1788.  
  1789. this.indices.delete(elementKey); // Remove target element's index
  1790.  
  1791. // If the element to remove wasn't the last element
  1792. if (indexToRemove < this.heap.length) {
  1793. const oldPriority = this.heap[indexToRemove].priority; // Priority before overwriting
  1794. this.heap[indexToRemove] = lastItem; // Move last element to the removed spot
  1795. this.indices.set(lastItem.element, indexToRemove); // Update index map
  1796.  
  1797. // Re-heapify: Bubble up or down based on priority comparison
  1798. if (this.compare(lastItem.priority, oldPriority) < 0) {
  1799. this.bubbleUp(indexToRemove);
  1800. } else {
  1801. this.bubbleDown(indexToRemove);
  1802. }
  1803. }
  1804. return true; // Indicate removal was successful
  1805. }
  1806.  
  1807. // Check if the queue is empty
  1808. isEmpty() {
  1809. return this.heap.length === 0;
  1810. }
  1811.  
  1812. // Get the size of the queue
  1813. size() {
  1814. return this.heap.length;
  1815. }
  1816.  
  1817. // Check if an element (string key) exists in the queue (O(1) average)
  1818. includes(elementKey) {
  1819. return this.indices.has(elementKey);
  1820. }
  1821.  
  1822. // --- Heap Helper Methods ---
  1823.  
  1824. parent(index) {
  1825. return Math.floor((index - 1) / 2);
  1826. }
  1827.  
  1828. leftChild(index) {
  1829. return 2 * index + 1;
  1830. }
  1831.  
  1832. rightChild(index) {
  1833. return 2 * index + 2;
  1834. }
  1835.  
  1836. // Swap elements at indices i and j, updating the index map
  1837. swap(i, j) {
  1838. const temp = this.heap[i];
  1839. this.heap[i] = this.heap[j];
  1840. this.heap[j] = temp;
  1841. // Update indices map
  1842. this.indices.set(this.heap[i].element, i);
  1843. this.indices.set(this.heap[j].element, j);
  1844. }
  1845.  
  1846. // Bubble up element at index, maintaining index map
  1847. bubbleUp(index) {
  1848. while (index > 0) {
  1849. const parentIndex = this.parent(index);
  1850. if (this.compare(this.heap[index].priority, this.heap[parentIndex].priority) < 0) {
  1851. this.swap(index, parentIndex);
  1852. index = parentIndex;
  1853. } else {
  1854. break;
  1855. }
  1856. }
  1857. }
  1858.  
  1859. // Bubble down element at index, maintaining index map
  1860. bubbleDown(index) {
  1861. const size = this.heap.length;
  1862. while (true) {
  1863. let smallestIndex = index;
  1864. const leftIndex = this.leftChild(index);
  1865. const rightIndex = this.rightChild(index);
  1866.  
  1867. if (leftIndex < size && this.compare(this.heap[leftIndex].priority, this.heap[smallestIndex].priority) < 0) {
  1868. smallestIndex = leftIndex;
  1869. }
  1870.  
  1871. if (rightIndex < size && this.compare(this.heap[rightIndex].priority, this.heap[smallestIndex].priority) < 0) {
  1872. smallestIndex = rightIndex;
  1873. }
  1874.  
  1875. if (smallestIndex !== index) {
  1876. this.swap(index, smallestIndex);
  1877. index = smallestIndex;
  1878. } else {
  1879. break;
  1880. }
  1881. }
  1882. }
  1883. }
  1884.  
  1885. /**
  1886. * D* Lite Algorithm Implementation (Using Optimized Priority Queue)
  1887. */
  1888. class DStarLite {
  1889. constructor(gridWidth, gridHeight) {
  1890. this.gridWidth = gridWidth;
  1891. this.gridHeight = gridHeight;
  1892.  
  1893. // --- Core D* Lite Data Structures ---
  1894. // Store g, rhs values. Key: "x,y" string. Value: { g: number, rhs: number }
  1895. this.cellData = new Map();
  1896. // Optimized Priority queue (U) storing node keys ("x,y") to be expanded
  1897. this.openList = new PriorityQueue();
  1898. // Key modifier for dynamic updates
  1899. this.km = 0;
  1900.  
  1901. // --- Start and Goal ---
  1902. // Store start/goal as objects {x, y} but use their keys ("x,y") for lookups/storage
  1903. this.start = null;
  1904. this.goal = null;
  1905. this.lastStart = null;
  1906.  
  1907. // --- Obstacles ---
  1908. // Set of obstacle coordinates (Key: "x,y" string)
  1909. this.obstacles = new Set();
  1910. // Store costs of edges that have changed (for dynamic updates)
  1911. // Key: "x1,y1_x2,y2", Value: new_cost
  1912. this.updatedEdgeCosts = new Map();
  1913.  
  1914. // --- Heuristic ---
  1915. // Using Manhattan distance for grid environments
  1916. this.heuristic = (a, b) => {
  1917. // Input can be node object {x,y} or string key "x,y"
  1918. const nodeA = (typeof a === 'string') ? this.parseKey(a) : a;
  1919. const nodeB = (typeof b === 'string') ? this.parseKey(b) : b;
  1920. if (!nodeA || !nodeB) return Infinity; // Should not happen in normal operation
  1921. return Math.abs(nodeA.x - nodeB.x) + Math.abs(nodeA.y - nodeB.y);
  1922. };
  1923.  
  1924. // --- Cost Function ---
  1925. // Cost between adjacent cells (can be dynamic)
  1926. this.cost = (nodeA, nodeB) => {
  1927. // Ensure nodes are objects for key generation and obstacle check
  1928. const objA = (typeof nodeA === 'string') ? this.parseKey(nodeA) : nodeA;
  1929. const objB = (typeof nodeB === 'string') ? this.parseKey(nodeB) : nodeB;
  1930. if (!objA || !objB) return Infinity; // Invalid node input
  1931.  
  1932. const keyA = this.getKey(objA);
  1933. const keyB = this.getKey(objB);
  1934.  
  1935. const edgeKey = `${keyA}_${keyB}`;
  1936. const reverseEdgeKey = `${keyB}_${keyA}`;
  1937.  
  1938. // Check if this specific edge has an updated cost
  1939. if (this.updatedEdgeCosts.has(edgeKey)) {
  1940. return this.updatedEdgeCosts.get(edgeKey);
  1941. }
  1942. if (this.updatedEdgeCosts.has(reverseEdgeKey)) {
  1943. return this.updatedEdgeCosts.get(reverseEdgeKey);
  1944. }
  1945.  
  1946. // Check if either node is an obstacle
  1947. if (this.isObstacle(keyA) || this.isObstacle(keyB)) {
  1948. return Infinity; // Moving into or out of an obstacle has infinite cost
  1949. }
  1950. // Basic cost for adjacent non-obstacle cells (can be adjusted e.g., for diagonals)
  1951. const dx = objA.x - objB.x;
  1952. const dy = objA.y - objB.y;
  1953. if (dx !== 0 && dy !== 0) return Math.sqrt(2);
  1954. else return 1;
  1955. };
  1956. }
  1957.  
  1958. // --- Node Key and Data Management ---
  1959. getKey(node) { // Input: {x, y} object
  1960. return `${node.x},${node.y}`;
  1961. }
  1962.  
  1963. parseKey(key) { // Input: "x,y" string
  1964. const parts = key.split(',');
  1965. if (parts.length !== 2) return null; // Invalid key
  1966. return { x: parseInt(parts[0], 10), y: parseInt(parts[1], 10) };
  1967. }
  1968.  
  1969. // Get/Set g and rhs using string keys
  1970. getNodeData(key) {
  1971. if (!this.cellData.has(key)) {
  1972. // Lazy initialization: Default g and rhs to Infinity
  1973. this.cellData.set(key, { g: Infinity, rhs: Infinity });
  1974. }
  1975. return this.cellData.get(key);
  1976. }
  1977.  
  1978. getG(key) {
  1979. return this.getNodeData(key).g;
  1980. }
  1981.  
  1982. getRHS(key) {
  1983. return this.getNodeData(key).rhs;
  1984. }
  1985.  
  1986. setG(key, value) {
  1987. this.getNodeData(key).g = value;
  1988. }
  1989.  
  1990. setRHS(key, value) {
  1991. this.getNodeData(key).rhs = value;
  1992. }
  1993.  
  1994. // --- Obstacle Management (using string keys) ---
  1995. addObstacle(x, y) {
  1996. this.obstacles.add(`${x},${y}`);
  1997. }
  1998.  
  1999. removeObstacle(x, y) {
  2000. this.obstacles.delete(`${x},${y}`);
  2001. }
  2002.  
  2003. isObstacle(key) { // Input: "x,y" string key
  2004. return this.obstacles.has(key);
  2005. }
  2006.  
  2007. // --- Initialization ---
  2008. initialize(start, goal) { // Input: {x, y} objects
  2009. this.openList = new PriorityQueue();
  2010. this.cellData = new Map(); // Clear previous data
  2011. this.km = 0;
  2012.  
  2013. this.start = start;
  2014. this.goal = goal;
  2015. this.lastStart = start; // Initialize lastStart
  2016.  
  2017. const goalKey = this.getKey(this.goal);
  2018.  
  2019. // Initialize goal node
  2020. this.setRHS(goalKey, 0);
  2021. // g(goal) is initially infinity (handled by getNodeData default)
  2022.  
  2023. // Add goal key to the open list
  2024. this.openList.push(goalKey, this.calculateKey(goalKey));
  2025. }
  2026.  
  2027. // --- Core D* Lite Functions ---
  2028.  
  2029. // Calculate the key (priority) for a node (using string key)
  2030. calculateKey(key) {
  2031. const g = this.getG(key);
  2032. const rhs = this.getRHS(key);
  2033. const minVal = Math.min(g, rhs);
  2034. // Key: [k1, k2]
  2035. // k1 = min(g, rhs) + h(start, node) + km
  2036. // k2 = min(g, rhs)
  2037. // Heuristic needs the start object and the node object (parsed from key)
  2038. const h = this.heuristic(this.start, key); // heuristic handles parsing key
  2039. return [minVal + h + this.km, minVal];
  2040. }
  2041.  
  2042. // Update the rhs value of a node (using string key) and manage open list
  2043. updateVertex(key) {
  2044. const goalKey = this.getKey(this.goal);
  2045.  
  2046. // Don't update the goal node's rhs based on neighbors
  2047. if (key !== goalKey) {
  2048. let minRhs = Infinity;
  2049. const node = this.parseKey(key); // Need object for getNeighbors
  2050. if (!node) return; // Invalid key
  2051.  
  2052. const neighbors = this.getNeighbors(node); // Returns neighbor objects {x,y}
  2053. for (const successorObj of neighbors) {
  2054. const successorKey = this.getKey(successorObj);
  2055. // Cost function needs objects or keys, ensure consistency
  2056. const costVal = this.cost(key, successorKey); // Pass keys to cost function
  2057. if (costVal === Infinity) continue; // Skip impassable successors
  2058. minRhs = Math.min(minRhs, costVal + this.getG(successorKey));
  2059. }
  2060. this.setRHS(key, minRhs);
  2061. }
  2062.  
  2063. // Remove node key from open list if it's already there (O(log n) now)
  2064. if (this.openList.includes(key)) {
  2065. this.openList.remove(key);
  2066. }
  2067.  
  2068. // If node is locally inconsistent (g != rhs), add its key to the open list
  2069. if (this.getG(key) !== this.getRHS(key)) {
  2070. // Check if it's an obstacle before adding
  2071. if (!this.isObstacle(key)) {
  2072. this.openList.push(key, this.calculateKey(key));
  2073. }
  2074. }
  2075. }
  2076.  
  2077. // Compute the shortest path from start to goal
  2078. computeShortestPath() {
  2079. if (!this.start || !this.goal) {
  2080. console.error("Start or Goal not set!");
  2081. return false; // Indicate failure
  2082. }
  2083.  
  2084. const startKey = this.getKey(this.start);
  2085. const goalKey = this.getKey(this.goal);
  2086. let iterations = 0; // Safety counter
  2087. const maxIterations = this.gridWidth * this.gridHeight * 5; // Heuristic limit
  2088.  
  2089. // Continue while the start node is inconsistent or the top key is less than start's key
  2090. while (
  2091. !this.openList.isEmpty() &&
  2092. (this.openList.compare(this.openList.peek().priority, this.calculateKey(startKey)) < 0 ||
  2093. this.getRHS(startKey) !== this.getG(startKey))
  2094. ) {
  2095. // Safety Break
  2096. if (++iterations > maxIterations) {
  2097. console.warn(`Max iterations (${maxIterations}) reached in computeShortestPath. Aborting.`);
  2098. return false; // Indicate potential issue or unreachable goal
  2099. }
  2100.  
  2101. const topItem = this.openList.peek(); // { element: key, priority: [...] }
  2102. if (!topItem) break; // Should not happen if !isEmpty, but safety check
  2103.  
  2104. const k_old = topItem.priority;
  2105. const uKey = topItem.element; // The node key to process
  2106. const k_new = this.calculateKey(uKey);
  2107.  
  2108. // Condition 1: Node needs update (key increased) -> Update priority in PQ
  2109. if (this.openList.compare(k_old, k_new) < 0) {
  2110. this.openList.update(uKey, k_new); // O(log n)
  2111. }
  2112. // Condition 2: Node is locally consistent (g > rhs) -> Make it overconsistent
  2113. else if (this.getG(uKey) > this.getRHS(uKey)) {
  2114. this.setG(uKey, this.getRHS(uKey));
  2115. this.openList.pop(); // Remove uKey from queue (O(log n))
  2116.  
  2117. // Update predecessors (neighbors)
  2118. const uNode = this.parseKey(uKey);
  2119. if (!uNode) continue; // Should not happen
  2120. const predecessors = this.getNeighbors(uNode); // Neighbors are predecessors in grid
  2121. for (const predObj of predecessors) {
  2122. const predKey = this.getKey(predObj);
  2123. if (!this.isObstacle(predKey) && predKey !== goalKey) { // Don't update goal's RHS this way
  2124. this.updateVertex(predKey); // Update non-obstacle predecessors
  2125. }
  2126. }
  2127. }
  2128. // Condition 3: Node is locally inconsistent (g < rhs) -> Make it consistent or overconsistent
  2129. else {
  2130. // const g_old = this.getG(uKey); // g_old not strictly needed here
  2131. this.setG(uKey, Infinity); // Make g infinite temporarily
  2132.  
  2133. // Update u itself first (if not an obstacle)
  2134. if (!this.isObstacle(uKey)) {
  2135. this.updateVertex(uKey);
  2136. }
  2137.  
  2138. // Update predecessors (neighbors)
  2139. const uNode = this.parseKey(uKey);
  2140. if (!uNode) continue; // Should not happen
  2141. const predecessors = this.getNeighbors(uNode);
  2142. for (const predObj of predecessors) {
  2143. const predKey = this.getKey(predObj);
  2144. if (!this.isObstacle(predKey) && predKey !== goalKey) { // Don't update goal's RHS this way
  2145. this.updateVertex(predKey);
  2146. }
  2147. }
  2148. }
  2149. }
  2150. // Check if a path was found (start node is consistent and reachable)
  2151. return this.getRHS(startKey) !== Infinity && this.getG(startKey) !== Infinity;
  2152. }
  2153.  
  2154. // --- Path Reconstruction ---
  2155. getPath() {
  2156. const startKey = this.getKey(this.start);
  2157. const goalKey = this.getKey(this.goal);
  2158.  
  2159. if (!this.start || !this.goal || this.getG(startKey) === Infinity) {
  2160. console.log("No path found or algorithm not run/finished.");
  2161. return []; // No path
  2162. }
  2163.  
  2164. const path = [this.start]; // Store path as node objects {x, y}
  2165. let currentKey = startKey;
  2166. let safetyCounter = 0;
  2167. const maxPathLength = this.gridWidth * this.gridHeight;
  2168.  
  2169. while (currentKey !== goalKey) {
  2170. if (++safetyCounter > maxPathLength) {
  2171. console.error("Path reconstruction exceeded max length. Possible loop or issue.");
  2172. return []; // Abort
  2173. }
  2174.  
  2175. let bestNextNode = null; // Store as object {x, y}
  2176. let minCost = Infinity;
  2177. const currentNode = this.parseKey(currentKey);
  2178. if (!currentNode) return []; // Error
  2179.  
  2180. const neighbors = this.getNeighbors(currentNode); // Get neighbor objects
  2181. for (const neighborObj of neighbors) {
  2182. const neighborKey = this.getKey(neighborObj);
  2183. if (this.isObstacle(neighborKey)) continue; // Skip obstacles
  2184.  
  2185. // Cost function expects keys or objects, ensure consistency
  2186. const costVal = this.cost(currentKey, neighborKey);
  2187. if (costVal === Infinity) continue; // Skip impassable edges
  2188.  
  2189. const costToGo = costVal + this.getG(neighborKey);
  2190.  
  2191. // Tie-breaking: Prefer lower heuristic, then lower coordinates if needed (optional)
  2192. if (costToGo < minCost) {
  2193. minCost = costToGo;
  2194. bestNextNode = neighborObj;
  2195. } else if (costToGo === minCost && bestNextNode) {
  2196. // Optional tie-breaking (e.g., prefer lower heuristic to goal)
  2197. const hCurrentBest = this.heuristic(bestNextNode, this.goal);
  2198. const hNeighbor = this.heuristic(neighborObj, this.goal);
  2199. if (hNeighbor < hCurrentBest) {
  2200. bestNextNode = neighborObj;
  2201. }
  2202. // Further tie-breaking (e.g., x, then y) if heuristics are equal
  2203. else if (hNeighbor === hCurrentBest) {
  2204. if (neighborObj.x < bestNextNode.x || (neighborObj.x === bestNextNode.x && neighborObj.y < bestNextNode.y)) {
  2205. bestNextNode = neighborObj;
  2206. }
  2207. }
  2208. }
  2209. }
  2210.  
  2211. if (bestNextNode === null || minCost === Infinity) {
  2212. console.warn("Path reconstruction failed - stuck at", currentKey, " No valid non-obstacle neighbor found.");
  2213. return path; // Return partial path up to blockage
  2214. }
  2215.  
  2216. path.push(bestNextNode);
  2217. currentKey = this.getKey(bestNextNode);
  2218. }
  2219. return path; // Return array of {x, y} objects
  2220. }
  2221.  
  2222. // --- Handling Dynamic Changes ---
  2223.  
  2224. // Update the cost of moving between two adjacent nodes (input: {x,y} objects)
  2225. updateEdgeCost(nodeA, nodeB, newCost) {
  2226. const keyA = this.getKey(nodeA);
  2227. const keyB = this.getKey(nodeB);
  2228. const edgeKey = `${keyA}_${keyB}`;
  2229. this.updatedEdgeCosts.set(edgeKey, newCost);
  2230.  
  2231. // Update the vertex *from* which the edge originates, as its RHS depends on cost(A, B) + g(B)
  2232. // If the edge cost changes, recalculate RHS for node A.
  2233. // Also update B, as its RHS might depend on cost(B, A) + g(A) if the graph is undirected or cost changes symmetrically.
  2234. // For simplicity and safety in potentially changing environments, update both.
  2235. this.updateVertex(keyA);
  2236. this.updateVertex(keyB);
  2237.  
  2238. // Recompute the shortest path *after* all batch updates are done.
  2239. // this.computeShortestPath();
  2240. }
  2241.  
  2242. // Add or remove an obstacle dynamically (input: x, y coordinates)
  2243. updateObstacle(x, y, isObstacle) {
  2244. const nodeKey = `${x},${y}`;
  2245. const currentlyIsObstacle = this.obstacles.has(nodeKey);
  2246.  
  2247. if (isObstacle && !currentlyIsObstacle) {
  2248. // --- Adding an obstacle ---
  2249. this.obstacles.add(nodeKey);
  2250.  
  2251. // Make g and rhs infinite for the obstacle node itself
  2252. // Note: g/rhs might already be Inf if unreachable, but set explicitly for clarity.
  2253. // const oldG = this.getG(nodeKey); // Store old G if needed, but D* Lite logic handles this implicitly
  2254. this.setG(nodeKey, Infinity);
  2255. this.setRHS(nodeKey, Infinity);
  2256.  
  2257. // If the node was in the open list, remove it (O(log n))
  2258. if (this.openList.includes(nodeKey)) {
  2259. this.openList.remove(nodeKey);
  2260. }
  2261.  
  2262. // Update neighbors (now predecessors of the obstacle)
  2263. // Their RHS might increase because the path through the obstacle is gone
  2264. const node = this.parseKey(nodeKey);
  2265. if (!node) return; // Should not happen
  2266. const neighbors = this.getNeighbors(node);
  2267. for (const neighborObj of neighbors) {
  2268. const neighborKey = this.getKey(neighborObj);
  2269. if (!this.isObstacle(neighborKey)) { // Don't update other obstacles
  2270. // updateVertex handles the recalculation needed if RHS depended on the now-obstacle node
  2271. this.updateVertex(neighborKey);
  2272. }
  2273. }
  2274. // No need to explicitly update the obstacle node itself via updateVertex,
  2275. // as it's marked as an obstacle and won't be added to openList or used in paths.
  2276.  
  2277. } else if (!isObstacle && currentlyIsObstacle) {
  2278. // --- Removing an obstacle ---
  2279. this.obstacles.delete(nodeKey);
  2280.  
  2281. // We need to potentially recalculate the RHS for the now-clear node
  2282. // based on its neighbors, and update its neighbors as they might now
  2283. // have a better path through the cleared node.
  2284. // Update the cleared node first.
  2285. this.updateVertex(nodeKey);
  2286.  
  2287. // Update neighbors
  2288. const node = this.parseKey(nodeKey);
  2289. if (!node) return; // Should not happen
  2290. const neighbors = this.getNeighbors(node);
  2291. for (const neighborObj of neighbors) {
  2292. const neighborKey = this.getKey(neighborObj);
  2293. if (!this.isObstacle(neighborKey)) {
  2294. this.updateVertex(neighborKey);
  2295. }
  2296. }
  2297. }
  2298. // If state didn't change, do nothing
  2299. // Remember to call computeShortestPath() after a batch of updates.
  2300. }
  2301.  
  2302.  
  2303. // Handle changes when the start position moves (input: new {x,y} object)
  2304. handleStartMoved(newStart) {
  2305. const oldStartKey = this.getKey(this.start);
  2306. const newStartKey = this.getKey(newStart);
  2307.  
  2308. this.lastStart = this.start; // Store the previous start object
  2309. this.start = newStart;
  2310.  
  2311. // Update the key modifier based on the heuristic change between old and new start, relative to the goal.
  2312. // This compensates for the change in h(s, u) for all nodes u in the priority queue keys.
  2313. // km = km + h(last, goal) - h(new, goal) -- though the original paper uses h(last, s_new)
  2314. // Let's stick to the common implementation using h relative to goal:
  2315. this.km += this.heuristic(this.lastStart, this.goal);
  2316.  
  2317. // It's crucial that calculateKey uses the *current* this.start
  2318. // and the current this.km. The priority queue doesn't need explicit updates
  2319. // for all nodes just because km changed; the comparison logic handles it implicitly
  2320. // when calculateKey is called during computeShortestPath.
  2321.  
  2322. // No need to re-initialize g/rhs values.
  2323.  
  2324. // Trigger computeShortestPath to find the path from the new start.
  2325. // this.computeShortestPath();
  2326. }
  2327.  
  2328.  
  2329. // --- Utility Functions ---
  2330.  
  2331. // Get valid neighbors of a node (input: {x,y} object, output: array of {x,y} objects)
  2332. getNeighbors(node) {
  2333. const neighbors = [];
  2334. const directions = [
  2335. { dx: 1, dy: 0 }, { dx: -1, dy: 0 },
  2336. { dx: 0, dy: 1 }, { dx: 0, dy: -1 },
  2337. // Add diagonals if needed (remember to adjust cost function if diagonal cost != 1):
  2338. { dx: 1, dy: 1 }, { dx: 1, dy: -1 },
  2339. { dx: -1, dy: 1 }, { dx: -1, dy: -1 }
  2340. ];
  2341.  
  2342. for (const dir of directions) {
  2343. const nextX = node.x + dir.dx;
  2344. const nextY = node.y + dir.dy;
  2345.  
  2346. // Check grid boundaries
  2347. if (nextX >= 0 && nextX < this.gridWidth && nextY >= 0 && nextY < this.gridHeight) {
  2348. // We don't check for obstacles here; cost function or caller handles that.
  2349. neighbors.push({ x: nextX, y: nextY });
  2350. }
  2351. }
  2352. return neighbors;
  2353. }
  2354. }
  2355.  
  2356. // @WasmModule
  2357. let PacketIds_1 = {
  2358. default: {
  2359. 0: "PACKET_ENTITY_UPDATE",
  2360. 1: "PACKET_PLAYER_COUNTER_UPDATE",
  2361. 2: "PACKET_SET_WORLD_DIMENSIONS",
  2362. 3: "PACKET_INPUT",
  2363. 4: "PACKET_ENTER_WORLD",
  2364. 5: "PACKET_PRE_ENTER_WORLD",
  2365. 6: "PACKET_ENTER_WORLD2",
  2366. 7: "PACKET_PING",
  2367. 9: "PACKET_RPC",
  2368. 10: "PACKET_BLEND",
  2369. PACKET_PRE_ENTER_WORLD: 5,
  2370. PACKET_ENTER_WORLD: 4,
  2371. PACKET_ENTER_WORLD2: 6,
  2372. PACKET_ENTITY_UPDATE: 0,
  2373. PACKET_INPUT: 3,
  2374. PACKET_PING: 7,
  2375. PACKET_PLAYER_COUNTER_UPDATE: 1,
  2376. PACKET_RPC: 9,
  2377. PACKET_SET_WORLD_DIMENSIONS: 2,
  2378. PACKET_BLEND: 10,
  2379. },
  2380. },
  2381. e_AttributeType = {
  2382. 0: "Uninitialized",
  2383. 1: "Uint32",
  2384. 2: "Int32",
  2385. 3: "Float",
  2386. 4: "String",
  2387. 5: "Vector2",
  2388. 6: "EntityType",
  2389. 7: "ArrayVector2",
  2390. 8: "ArrayUint32",
  2391. 9: "Uint16",
  2392. 10: "Uint8",
  2393. 11: "Int16",
  2394. 12: "Int8",
  2395. 13: "Uint64",
  2396. 14: "Int64",
  2397. 15: "Double",
  2398. Uninitialized: 0,
  2399. Uint32: 1,
  2400. Int32: 2,
  2401. Float: 3,
  2402. String: 4,
  2403. Vector2: 5,
  2404. EntityType: 6,
  2405. ArrayVector2: 7,
  2406. ArrayUint32: 8,
  2407. Uint16: 9,
  2408. Uint8: 10,
  2409. Int16: 11,
  2410. Int8: 12,
  2411. Uint64: 13,
  2412. Int64: 14,
  2413. Double: 15,
  2414. },
  2415. e_ParameterType = { 0: "Uint32", 1: "Int32", 2: "Float", 3: "String", 4: "Uint64", 5: "Int64", Uint32: 0, Int32: 1, Float: 2, String: 3, Uint64: 4, Int64: 5 };
  2416. class BinCodec {
  2417. constructor() {
  2418. (this.attributeMaps = {}), (this.entityTypeNames = {}), (this.rpcMaps = []), (this.rpcMapsByName = {}), (this.sortedUidsByType = {}), (this.removedEntities = {}), (this.absentEntitiesFlags = []), (this.updatedEntityFlags = []);
  2419. }
  2420. encode(e, t, a) {
  2421. let r = new dcodeIO.ByteBuffer(100, !0);
  2422. switch (e) {
  2423. case PacketIds_1.default.PACKET_ENTER_WORLD:
  2424. r.writeUint8(PacketIds_1.default.PACKET_ENTER_WORLD), this.encodeEnterWorld(r, t);
  2425. break;
  2426. case PacketIds_1.default.PACKET_ENTER_WORLD2:
  2427. r.writeUint8(PacketIds_1.default.PACKET_ENTER_WORLD2), this.encodeEnterWorld2(r, a);
  2428. break;
  2429. case PacketIds_1.default.PACKET_INPUT:
  2430. r.writeUint8(PacketIds_1.default.PACKET_INPUT), this.encodeInput(r, t);
  2431. break;
  2432. case PacketIds_1.default.PACKET_PING:
  2433. r.writeUint8(PacketIds_1.default.PACKET_PING), this.encodePing(r, t);
  2434. break;
  2435. case PacketIds_1.default.PACKET_RPC:
  2436. r.writeUint8(PacketIds_1.default.PACKET_RPC), this.encodeRpc(r, t);
  2437. break;
  2438. case PacketIds_1.default.PACKET_BLEND:
  2439. r.writeUint8(PacketIds_1.default.PACKET_BLEND), this.encodeBlend(r, t);
  2440. }
  2441. return r.flip(), r.compact(), r.toArrayBuffer(!1);
  2442. }
  2443. decode(e, t) {
  2444. let a = dcodeIO.ByteBuffer.wrap(e);
  2445. a.littleEndian = !0;
  2446. let r = a.readUint8(),
  2447. n;
  2448. switch (r) {
  2449. case PacketIds_1.default.PACKET_PRE_ENTER_WORLD:
  2450. n = this.decodePreEnterWorldResponse(a, t);
  2451. break;
  2452. case PacketIds_1.default.PACKET_ENTER_WORLD:
  2453. n = this.decodeEnterWorldResponse(a);
  2454. break;
  2455. case PacketIds_1.default.PACKET_ENTITY_UPDATE:
  2456. n = this.decodeEntityUpdate(a);
  2457. break;
  2458. case PacketIds_1.default.PACKET_PING:
  2459. n = this.decodePing(a);
  2460. break;
  2461. case PacketIds_1.default.PACKET_RPC:
  2462. n = this.decodeRpc(a);
  2463. break;
  2464. case PacketIds_1.default.PACKET_BLEND:
  2465. n = this.decodeBlend(a, t);
  2466. }
  2467. return (n.opcode = r), n;
  2468. }
  2469. safeReadVString(e) {
  2470. let t = e.offset,
  2471. a = e.readVarint32(t);
  2472. try {
  2473. var r = e.readUTF8String.bind(e)(a.value, "b", (t += a.length));
  2474. return (t += r.length), (e.offset = t), r.string;
  2475. } catch (n) {
  2476. return (t += a.value), (e.offset = t), "?";
  2477. }
  2478. }
  2479. decodePreEnterWorldResponse(e, t) {
  2480. return t._MakeBlendField(255, 140), { extra: this.decodeBlendInternal(e, t) };
  2481. }
  2482. decodeEnterWorldResponse(e) {
  2483. let t = {
  2484. allowed: e.readUint32(),
  2485. uid: e.readUint32(),
  2486. startingTick: e.readUint32(),
  2487. tickRate: e.readUint32(),
  2488. effectiveTickRate: e.readUint32(),
  2489. players: e.readUint32(),
  2490. maxPlayers: e.readUint32(),
  2491. chatChannel: e.readUint32(),
  2492. effectiveDisplayName: this.safeReadVString(e),
  2493. x1: e.readInt32(),
  2494. y1: e.readInt32(),
  2495. x2: e.readInt32(),
  2496. y2: e.readInt32(),
  2497. },
  2498. a = e.readUint32();
  2499. (this.attributeMaps = {}), (this.entityTypeNames = {});
  2500. for (let r = 0; r < a; r++) {
  2501. let n = [],
  2502. i = e.readUint32(),
  2503. s = e.readVString(),
  2504. d = e.readUint32();
  2505. for (let o = 0; o < d; o++) {
  2506. let c = e.readVString(),
  2507. l = e.readUint32();
  2508. n.push({ name: c, type: l });
  2509. }
  2510. (this.attributeMaps[i] = n), (this.entityTypeNames[i] = s), (this.sortedUidsByType[i] = []);
  2511. }
  2512. let p = e.readUint32();
  2513. (this.rpcMaps = []), (this.rpcMapsByName = {});
  2514. for (let h = 0; h < p; h++) {
  2515. let f = e.readVString(),
  2516. U = e.readUint8(),
  2517. u = 0 != e.readUint8(),
  2518. y = [];
  2519. for (let E = 0; E < U; E++) {
  2520. let $ = e.readVString(),
  2521. m = e.readUint8();
  2522. y.push({ name: $, type: m });
  2523. }
  2524. let b = { name: f, parameters: y, isArray: u, index: this.rpcMaps.length };
  2525. this.rpcMaps.push(b), (this.rpcMapsByName[f] = b);
  2526. }
  2527. return t;
  2528. }
  2529. decodeEntityUpdate(e) {
  2530. var t = e.readUint32(),
  2531. a = e.readVarint32(),
  2532. r = {};
  2533. for (var n in ((r.tick = t), (r.entities = {}), this.removedEntities)) delete this.removedEntities[n];
  2534. for (var i = 0; i < a; i++) {
  2535. var n = e.readUint32();
  2536. this.removedEntities[n] = 1;
  2537. }
  2538. for (var s = e.readVarint32(), i = 0; i < s; i++) {
  2539. var d = e.readVarint32(),
  2540. o = e.readUint32();
  2541. this.entityTypeNames[o];
  2542. for (var c = 0; c < d; c++) {
  2543. var l = e.readUint32();
  2544. this.sortedUidsByType[o].push(l);
  2545. }
  2546. }
  2547. for (var i in this.sortedUidsByType) {
  2548. for (var p = this.sortedUidsByType[i], h = [], c = 0; c < p.length; c++) {
  2549. var n = p[c];
  2550. n in this.removedEntities || h.push(n);
  2551. }
  2552. h.sort(function (e, t) {
  2553. return e < t ? -1 : e > t ? 1 : 0;
  2554. }),
  2555. (this.sortedUidsByType[i] = h);
  2556. }
  2557. for (; e.remaining(); ) {
  2558. var f = e.readUint32();
  2559. if ((this.entityTypeNames[f], !(f in this.attributeMaps))) throw Error("Entity type is not in attribute map: " + f);
  2560. var U = Math.floor((this.sortedUidsByType[f].length + 7) / 8);
  2561. this.absentEntitiesFlags.length = 0;
  2562. for (var i = 0; i < U; i++) this.absentEntitiesFlags.push(e.readUint8());
  2563. for (var u = this.attributeMaps[f], y = 0; y < this.sortedUidsByType[f].length; y++) {
  2564. var n = this.sortedUidsByType[f][y];
  2565. if ((this.absentEntitiesFlags[Math.floor(y / 8)] & (1 << y % 8)) != 0) {
  2566. r.entities[n] = !0;
  2567. continue;
  2568. }
  2569. var E = { uid: n };
  2570. this.updatedEntityFlags.length = 0;
  2571. for (var c = 0; c < Math.ceil(u.length / 8); c++) this.updatedEntityFlags.push(e.readUint8());
  2572. for (var c = 0; c < u.length; c++) {
  2573. var $ = u[c],
  2574. m = Math.floor(c / 8),
  2575. b = c % 8,
  2576. v = void 0,
  2577. g = [];
  2578. if (this.updatedEntityFlags[m] & (1 << b))
  2579. switch ($.type) {
  2580. case e_AttributeType.Uint32:
  2581. E[$.name] = e.readUint32();
  2582. break;
  2583. case e_AttributeType.Int32:
  2584. E[$.name] = e.readInt32();
  2585. break;
  2586. case e_AttributeType.Float:
  2587. E[$.name] = e.readInt32() / 100;
  2588. break;
  2589. case e_AttributeType.String:
  2590. E[$.name] = this.safeReadVString(e);
  2591. break;
  2592. case e_AttributeType.Vector2:
  2593. var T = e.readInt32() / 100,
  2594. k = e.readInt32() / 100;
  2595. E[$.name] = { x: T, y: k };
  2596. break;
  2597. case e_AttributeType.ArrayVector2:
  2598. (v = e.readInt32()), (g = []);
  2599. for (var i = 0; i < v; i++) {
  2600. var P = e.readInt32() / 100,
  2601. I = e.readInt32() / 100;
  2602. g.push({ x: P, y: I });
  2603. }
  2604. E[$.name] = g;
  2605. break;
  2606. case e_AttributeType.ArrayUint32:
  2607. (v = e.readInt32()), (g = []);
  2608. for (var i = 0; i < v; i++) {
  2609. var B = e.readInt32();
  2610. g.push(B);
  2611. }
  2612. E[$.name] = g;
  2613. break;
  2614. case e_AttributeType.Uint16:
  2615. E[$.name] = e.readUint16();
  2616. break;
  2617. case e_AttributeType.Uint8:
  2618. E[$.name] = e.readUint8();
  2619. break;
  2620. case e_AttributeType.Int16:
  2621. E[$.name] = e.readInt16();
  2622. break;
  2623. case e_AttributeType.Int8:
  2624. E[$.name] = e.readInt8();
  2625. break;
  2626. case e_AttributeType.Uint64:
  2627. E[$.name] = e.readUint32() + 4294967296 * e.readUint32();
  2628. break;
  2629. case e_AttributeType.Int64:
  2630. var R = e.readUint32(),
  2631. w = e.readInt32();
  2632. w < 0 && (R *= -1), (R += 4294967296 * w), (E[$.name] = R);
  2633. break;
  2634. case e_AttributeType.Double:
  2635. var _ = e.readUint32(),
  2636. A = e.readInt32();
  2637. A < 0 && (_ *= -1), (_ += 4294967296 * A), (_ /= 100), (E[$.name] = _);
  2638. break;
  2639. default:
  2640. throw Error("Unsupported attribute type: " + $.type);
  2641. }
  2642. }
  2643. r.entities[E.uid] = E;
  2644. }
  2645. }
  2646. return (r.byteSize = e.capacity()), r;
  2647. }
  2648. decodePing() {
  2649. return {};
  2650. }
  2651. encodeRpc(e, t) {
  2652. if (!(t.name in this.rpcMapsByName)) throw Error("RPC not in map: " + t.name);
  2653. var a = this.rpcMapsByName[t.name];
  2654. e.writeUint32(a.index);
  2655. for (var r = 0; r < a.parameters.length; r++) {
  2656. var n = t[a.parameters[r].name];
  2657. switch (a.parameters[r].type) {
  2658. case e_ParameterType.Float:
  2659. e.writeInt32(Math.floor(100 * n));
  2660. break;
  2661. case e_ParameterType.Int32:
  2662. e.writeInt32(n);
  2663. break;
  2664. case e_ParameterType.String:
  2665. e.writeVString(n);
  2666. break;
  2667. case e_ParameterType.Uint32:
  2668. e.writeUint32(n);
  2669. }
  2670. }
  2671. }
  2672. decodeBlend(e, t) {
  2673. return { extra: this.decodeBlendInternal(e, t) };
  2674. }
  2675. decodeBlendInternal(e, t) {
  2676. t._MakeBlendField(24, 132);
  2677. for (let a = t._MakeBlendField(228, e.remaining()), r = 0; e.remaining(); ) (t.HEAPU8[a + r] = e.readUint8()), r++;
  2678. t._MakeBlendField(172, 36);
  2679. for (var n = new ArrayBuffer(64), i = new Uint8Array(n), s = t._MakeBlendField(4, 152), d = 0; d < 64; d++) i[d] = t.HEAPU8[s + d];
  2680. return n;
  2681. }
  2682. decodeRpcObject(e, t) {
  2683. for (var a = {}, r = 0; r < t.length; r++)
  2684. switch (t[r].type) {
  2685. case e_ParameterType.Uint32:
  2686. a[t[r].name] = e.readUint32();
  2687. break;
  2688. case e_ParameterType.Int32:
  2689. a[t[r].name] = e.readInt32();
  2690. break;
  2691. case e_ParameterType.Float:
  2692. a[t[r].name] = e.readInt32() / 100;
  2693. break;
  2694. case e_ParameterType.String:
  2695. a[t[r].name] = this.safeReadVString(e);
  2696. break;
  2697. case e_ParameterType.Uint64:
  2698. a[t[r].name] = e.readUint32() + 4294967296 * e.readUint32();
  2699. }
  2700. return a;
  2701. }
  2702. decodeRpc(e) {
  2703. var t = e.readUint32(),
  2704. a = this.rpcMaps[t],
  2705. r = { name: a.name, response: null };
  2706. if (a.isArray) {
  2707. for (var n = [], i = e.readUint16(), s = 0; s < i; s++) n.push(this.decodeRpcObject(e, a.parameters));
  2708. r.response = n;
  2709. } else r.response = this.decodeRpcObject(e, a.parameters);
  2710. return r;
  2711. }
  2712. encodeBlend(e, t) {
  2713. for (var a = new Uint8Array(t.extra), r = 0; r < t.extra.byteLength; r++) e.writeUint8(a[r]);
  2714. }
  2715. encodeEnterWorld(e, t) {
  2716. e.writeVString(t.displayName);
  2717. for (var a = new Uint8Array(t.extra), r = 0; r < t.extra.byteLength; r++) e.writeUint8(a[r]);
  2718. }
  2719. encodeEnterWorld2(e, t) {
  2720. for (var a = t._MakeBlendField(187, 22), r = 0; r < 16; r++) e.writeUint8(t.HEAPU8[a + r]);
  2721. }
  2722. encodeInput(e, t) {
  2723. e.writeVString(JSON.stringify(t));
  2724. }
  2725. encodePing(e) {
  2726. e.writeUint8(0);
  2727. }
  2728. }
  2729. let codec = new BinCodec(),
  2730. wasmBuffers;
  2731. fetch("/asset/zombs_wasm.wasm").then((e) =>
  2732. e.arrayBuffer().then((e) => {
  2733. wasmBuffers = e;
  2734. })
  2735. );
  2736. const wasmModule = (callback, data_12, hostname) => {
  2737. function _a(e, t, r) {
  2738. for (var a = t + r, n = t; e[n] && !(n >= a); ) ++n;
  2739. if (n - t > 16 && e.subarray && _n) return _n.decode(e.subarray(t, n));
  2740. for (var i = ""; t < n; ) {
  2741. let d = e[t++];
  2742. if (128 & d) {
  2743. var s = 63 & e[t++];
  2744. if (192 != (224 & d)) {
  2745. var l = 63 & e[t++];
  2746. if ((d = 224 == (240 & d) ? ((15 & d) << 12) | (s << 6) | l : ((7 & d) << 18) | (s << 12) | (l << 6) | (63 & e[t++])) < 65536) i += String.fromCharCode(d);
  2747. else {
  2748. var c = d - 65536;
  2749. i += String.fromCharCode(55296 | (c >> 10), 56320 | (1023 & c));
  2750. }
  2751. } else i += String.fromCharCode(((31 & d) << 6) | s);
  2752. } else i += String.fromCharCode(d);
  2753. }
  2754. return i;
  2755. }
  2756. function _b(e, t) {
  2757. return e ? _a(_k, e, t) : "";
  2758. }
  2759. function _c(e, t, r, a) {
  2760. if (!(a > 0)) return 0;
  2761. for (var n = r, i = r + a - 1, d = 0; d < e.length; ++d) {
  2762. var s = e.charCodeAt(d);
  2763. if ((s >= 55296 && s <= 57343 && (s = (65536 + ((1023 & s) << 10)) | (1023 & e.charCodeAt(++d))), s <= 127)) {
  2764. if (r >= i) break;
  2765. t[r++] = s;
  2766. } else if (s <= 2047) {
  2767. if (r + 1 >= i) break;
  2768. (t[r++] = 192 | (s >> 6)), (t[r++] = 128 | (63 & s));
  2769. } else if (s <= 65535) {
  2770. if (r + 2 >= i) break;
  2771. (t[r++] = 224 | (s >> 12)), (t[r++] = 128 | ((s >> 6) & 63)), (t[r++] = 128 | (63 & s));
  2772. } else {
  2773. if (r + 3 >= i) break;
  2774. (t[r++] = 240 | (s >> 18)), (t[r++] = 128 | ((s >> 12) & 63)), (t[r++] = 128 | ((s >> 6) & 63)), (t[r++] = 128 | (63 & s));
  2775. }
  2776. }
  2777. return (t[r] = 0), r - n;
  2778. }
  2779. function _d(e, t, r) {
  2780. return _c(e, _k, t, r);
  2781. }
  2782. function _e(e) {
  2783. for (var t = 0, r = 0; r < e.length; ++r) {
  2784. var a = e.charCodeAt(r);
  2785. a >= 55296 && a <= 57343 && (a = (65536 + ((1023 & a) << 10)) | (1023 & e.charCodeAt(++r))), a <= 127 ? ++t : (t += a <= 2047 ? 2 : a <= 65535 ? 3 : 4);
  2786. }
  2787. return t;
  2788. }
  2789. function _f(e) {
  2790. (_m.HEAP8 = new Int8Array(e)),
  2791. (_m.HEAP16 = new Int16Array(e)),
  2792. (_m.HEAP32 = _l = new Int32Array(e)),
  2793. (_m.HEAPU8 = _k = new Uint8Array(e)),
  2794. (_m.HEAPU16 = new Uint16Array(e)),
  2795. (_m.HEAPU32 = new Uint32Array(e)),
  2796. (_m.HEAPF32 = new Float32Array(e)),
  2797. (_m.HEAPF64 = new Float64Array(e));
  2798. }
  2799. function _g() {
  2800. function e(e) {
  2801. (_m.asm = e.exports), _f(_m.asm.g.buffer), _o(), _j();
  2802. }
  2803. function t(t) {
  2804. e(t.instance);
  2805. }
  2806. function r(e) {
  2807. WebAssembly.instantiate(wasmBuffers, a).then((t) => {
  2808. e(t), "function" == typeof callback && callback(_m.decodeOpcode5(hostname, data_12));
  2809. });
  2810. }
  2811. var a = { a: { d() {}, e() {}, c() {}, f() {}, b: _h, a: _i } };
  2812. if (_m.instantiateWasm)
  2813. try {
  2814. return _m.instantiateWasm(a, e);
  2815. } catch (n) {
  2816. return console.log("Module.instantiateWasm callback failed with error: " + n), !1;
  2817. }
  2818. return r(t), {};
  2819. }
  2820. function _h(_hh) {
  2821. let e = _b(_hh);
  2822. if (e.includes('typeof window === "undefined" ? 1 : 0;') || e.includes("typeof process !== 'undefined' ? 1 : 0;")) return 0;
  2823. if (e.includes("Game.currentGame.network.connected ? 1 : 0")) return 1;
  2824. if (e.includes("Game.currentGame.world.myUid === null ? 0 : Game.currentGame.world.myUid;")) return 0;
  2825. if (e.includes('document.getElementById("hud").children.length;')) return 24;
  2826. if (e.includes("hostname")) return hostname;
  2827. let data;
  2828. return 0 | eval(_b(_hh));
  2829. }
  2830. function _i(e) {
  2831. var t = hostname;
  2832. if (null == t) return 0;
  2833. t = String(t);
  2834. var r = _i,
  2835. a = _e(t);
  2836. return (!r.bufferSize || r.bufferSize < a + 1) && (r.bufferSize && _s(r.buffer), (r.bufferSize = a + 1), (r.buffer = _r(r.bufferSize))), _d(t, r.buffer, r.bufferSize), r.buffer;
  2837. }
  2838. function _j() {
  2839. (_l[1328256] = 5313008), (_l[1328257] = 0), _m._main(1, 5313024);
  2840. }
  2841. var _k,
  2842. _l,
  2843. _m = {},
  2844. _n = new TextDecoder("utf8");
  2845. _g();
  2846. var _o = (_m.___wasm_call_ctors = function () {
  2847. return (_o = _m.___wasm_call_ctors = _m.asm.h).apply(null, arguments);
  2848. }),
  2849. _p = (_m._main = function () {
  2850. return (_p = _m._main = _m.asm.i).apply(null, arguments);
  2851. }),
  2852. _q = (_m._MakeBlendField = function () {
  2853. return (_q = _m._MakeBlendField = _m.asm.j).apply(null, arguments);
  2854. }),
  2855. _r = (_m._malloc = function () {
  2856. return (_r = _m._malloc = _m.asm.l).apply(null, arguments);
  2857. }),
  2858. _s = (_m._free = function () {
  2859. return (_s = _m._free = _m.asm.m).apply(null, arguments);
  2860. });
  2861. return (
  2862. (_m.decodeOpcode5 = function (e, t) {
  2863. _m.hostname = e;
  2864. let r = codec.decode(new Uint8Array(t), _m),
  2865. a = codec.encode(6, {}, _m);
  2866. return { 5: r, 6: a, 10: _m };
  2867. }),
  2868. _m
  2869. );
  2870. };
  2871.  
  2872. // @FontAwesome
  2873. const fontAwesome = document.createElement("script");
  2874. fontAwesome.type = "text/javascript";
  2875. fontAwesome.src = "https://kit.fontawesome.com/1c239b2e80.js";
  2876. document.head.appendChild(fontAwesome);
  2877.  
  2878. document.querySelectorAll('#hud-respawn > div > div > div > h2, #hud-respawn > div > div > div > p, #hud-respawn > div > div > div > div, .ad-unit, #hud-intro > div.hud-intro-footer > a:nth-child(2), #hud-intro > div.hud-intro-footer > a:nth-child(4), #hud-intro > div.hud-intro-wrapper > h1, #hud-intro > div.hud-intro-wrapper > h2, .hud-intro-left, .hud-intro-guide, .hud-intro > .hud-intro-stone, .hud-intro >.hud-intro-tree, .hud-intro-youtuber, .hud-intro-more-games, .hud-intro-social, .hud-respawn-corner-bottom-left, .hud-respawn-twitter-btn, .hud-respawn-facebook-btn').forEach(el => el.remove());
  2879. const css = `
  2880. /* @Root */
  2881. :root {
  2882. --normal-btn: rgb(40 152 231);
  2883. --light-hover-btn: rgb(111 208 247);
  2884. }
  2885.  
  2886. ::-webkit-scrollbar {
  2887. width: 12px;
  2888. height: 0px;
  2889. border-radius: 10px;
  2890. background-color: rgba(0, 0, 0, 0);
  2891. }
  2892. ::-webkit-scrollbar-thumb {
  2893. border-radius: 10px;
  2894. background-image: url(https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/whiteslider.png?v=1714878503407);
  2895. }
  2896.  
  2897. input[type='range'] {
  2898. accent-color: var(--normal-btn);
  2899. }
  2900.  
  2901. .btn-theme {
  2902. background: var(--normal-btn);
  2903. }
  2904. .btn-theme:hover {
  2905. background: var(--light-hover-btn);
  2906. }
  2907.  
  2908. /* @CustomKeyframes */
  2909. @keyframes bounce {
  2910. 50% { transform: translateY(-30px); }
  2911. 100% { transform: translateY(-10px); }
  2912. }
  2913.  
  2914. .hud-intro::before {
  2915. background-image: var(--bg-image);
  2916. background-size: cover;
  2917. background-position: center;
  2918. transition: all 0.5s ease-out;
  2919. }
  2920. .hud-intro::after {
  2921. background: unset;
  2922. }
  2923.  
  2924. #hud-intro > div.hud-intro-corner-top-left > div {
  2925. padding: 10px;
  2926. backdrop-filter: blur(10px);
  2927. background: rgba(0, 0, 0, 0.1);
  2928. box-shadow: 0px 0px 10px 10px rgba(0, 0, 0, 0.2);
  2929. display: flex;
  2930. line-height: 20px;
  2931. margin: 0 0 10px;
  2932. font-size: 14px;
  2933. color: rgba(255, 255, 255, 0.4);
  2934. border-radius: 4px;
  2935. flex-direction: column;
  2936. }
  2937.  
  2938. #hud-intro > div.hud-intro-corner-top-right > div {
  2939. padding: 10px;
  2940. backdrop-filter: blur(10px);
  2941. background: rgba(0, 0, 0, 0.1);
  2942. box-shadow: 0px 0px 10px 10px rgba(0, 0, 0, 0.2);
  2943. }
  2944.  
  2945. #hud-intro > div.hud-intro-wrapper {
  2946. justify-content: flex-end;
  2947. margin: 40px 0 0;
  2948. }
  2949. #hud-intro > div.hud-intro-wrapper > div > div {
  2950. padding: 10px;
  2951. background: rgba(0, 0, 0, 0.1);
  2952. }
  2953. #hud-intro > div.hud-intro-wrapper > div > div > input {
  2954. color: white;
  2955. backdrop-filter: blur(10px);
  2956. background: rgba(0, 0, 0, 0.1);
  2957. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.2);
  2958. }
  2959. #hud-intro > div.hud-intro-wrapper > div > div > select {
  2960. color: white;
  2961. backdrop-filter: blur(10px);
  2962. background: rgba(0, 0, 0, 0.1);
  2963. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.2);
  2964. border: 0px;
  2965. margin: 0 0 10px;
  2966. }
  2967.  
  2968. #hud-intro > div.hud-intro-footer {
  2969. left: unset;
  2970. right: 20px;
  2971. }
  2972.  
  2973. /* @CustomIntroStyles */
  2974. #intro-animation {
  2975. display: block;
  2976. position: absolute;
  2977. top: 0px;
  2978. left: 0px;
  2979. width: 100%;
  2980. height: 100%;
  2981. z-index: 0;
  2982. }
  2983. #background-canvas {
  2984. display: block;
  2985. position: absolute;
  2986. top: 0px;
  2987. left: 0px;
  2988. width: 100%;
  2989. height: 100%;
  2990. z-index: 1;
  2991. filter: blur(2px);
  2992. }
  2993. #intro-animation > img {
  2994. position: absolute;
  2995. z-index: 2;
  2996. height: calc(1400px + 5vw);
  2997. max-height: 170vh;
  2998. left: calc(15vw - 300px);
  2999. bottom: calc(20vh - 600px - 2.5vw);
  3000. top: unset;
  3001. z-index: 2;
  3002. transform: translateY(-10px);
  3003. transition: all 0.5s ease-out;
  3004. animation-name: bounce;
  3005. animation-duration: 5s;
  3006. animation-iteration-count: infinite;
  3007. }
  3008. #foreground-canvas {
  3009. display: block;
  3010. position: absolute;
  3011. top: 0px;
  3012. left: 0px;
  3013. width: 100%;
  3014. height: 100%;
  3015. z-index: 3;
  3016. }
  3017.  
  3018. #start-btn {
  3019. display: flex;
  3020. flex-direction: column;
  3021. align-items: flex-end;
  3022. justify-content: center;
  3023. margin: auto;
  3024. position: absolute;
  3025. top: calc(50vh - 75px);
  3026. right: 0px;
  3027. height: 150px;
  3028. zoom: 140%;
  3029. cursor: pointer;
  3030. background: rgba(0, 0, 0, 0.1);
  3031. backdrop-filter: blur(3px);
  3032. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3033. border-top-left-radius: 15px;
  3034. border-bottom-left-radius: 15px;
  3035. }
  3036. #start-btn > h1 {
  3037. color: white;
  3038. margin-right: 20px;
  3039. font-size: 60px;
  3040. text-transform: none;
  3041. }
  3042. #start-btn > hr {
  3043. border: 2px solid white;
  3044. width: 225px;
  3045. }
  3046. #start-btn > h2 {
  3047. margin-right: 20px;
  3048. font-size: 20px;
  3049. color: rgba(255, 255, 255, 0.8);
  3050. }
  3051.  
  3052. #sesSelect {
  3053. display: none;
  3054. float: left;
  3055. width: 100%;
  3056. height: 50px;
  3057. line-height: 34px;
  3058. padding: 8px 14px;
  3059. margin: 0 0 10px;
  3060. border: 0;
  3061. font-size: 14px;
  3062. border-radius: 4px;
  3063. color: white;
  3064. backdrop-filter: blur(10px);
  3065. background: rgba(0, 0, 0, 0.1);
  3066. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.2);
  3067. }
  3068. #sesSelect:disabled {
  3069. opacity: 0.4;
  3070. }
  3071. #delBtn, #addBtn {
  3072. display: none;
  3073. width: calc(50% - 5px);
  3074. height: 50px;
  3075. line-height: 34px;
  3076. padding: 8px 14px;
  3077. font-size: 14px;
  3078. border-left: 0;
  3079. border-right: 0;
  3080. border-top: 0;
  3081. border-radius: 4px;
  3082. color: #eee;
  3083. cursor: pointer;
  3084. backdrop-filter: blur(10px);
  3085. background: rgba(0, 0, 0, 0.1);
  3086. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.2);
  3087. }
  3088.  
  3089. #delBtn {
  3090. margin: 0 5px 10px 0;
  3091. border-bottom: 2px solid red;
  3092. }
  3093. #addBtn {
  3094. margin: 0 0 10px 5px;
  3095. border-bottom: 2px solid white;
  3096. }
  3097.  
  3098. #hud-intro-overlay {
  3099. display: none;
  3100. opacity: 0;
  3101. position: absolute;
  3102. top: 0px;
  3103. left: 0px;
  3104. z-index: 999;
  3105. backdrop-filter: blur(10px);
  3106. width: 100%;
  3107. height: 100%;
  3108. background: rgba(0, 0, 0, 0.3);
  3109. justify-content: center;
  3110. align-items: center;
  3111. flex-direction: column;
  3112. transition: all 0.5s;
  3113. }
  3114. #hud-intro-overlay h2 {
  3115. color: white;
  3116. font-size: 30px;
  3117. text-shadow: 0 0 20px black;
  3118. margin-bottom: 15px;
  3119. }
  3120. #hud-intro-overlay strong {
  3121. margin: -15px 0 5px;
  3122. color: #aaa;
  3123. }
  3124. #hud-intro-overlay p {
  3125. color: #eee;
  3126. margin: 10px 0;
  3127. font-weight: bold;
  3128. }
  3129. #hud-intro-overlay input, #hud-intro-overlay select, #hud-intro-overlay button:not(.session-back):not(#create-session):not(#create-endpoint) {
  3130. width: 100%;
  3131. height: 50px;
  3132. line-height: 34px;
  3133. padding: 8px 14px;
  3134. margin: 0 0 15px;
  3135. border: 0;
  3136. text-align: start;
  3137. font-size: 15px;
  3138. border-radius: 10px;
  3139. color: white;
  3140. backdrop-filter: blur(10px);
  3141. background: rgba(0, 0, 0, 0.1);
  3142. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.2);
  3143. }
  3144. #hud-intro-overlay button {
  3145. cursor: pointer;
  3146. }
  3147. #loading-div {
  3148. display: none;
  3149. pointer-events: none;
  3150. justify-content: center;
  3151. align-items: center;
  3152. flex-direction: column;
  3153. }
  3154. #loading-div > span {
  3155. width: 100px;
  3156. height: 100px;
  3157. }
  3158. #loading-div > a {
  3159. margin-top: 20px;
  3160. color: rgba(255, 255, 255, 0.4);
  3161. pointer-events: all;
  3162. }
  3163. #select-session-add, #endpoint-add-menu, #session-add-menu {
  3164. width: 40vw;
  3165. display: none;
  3166. align-items: flex-start;
  3167. flex-direction: column;
  3168. padding: 20px;
  3169. border-radius: 10px;
  3170. background: rgba(0, 0, 0, 0.2);
  3171. }
  3172. .session-navigator {
  3173. display: flex;
  3174. justify-content: space-between;
  3175. width: 100%;
  3176. margin-top: 10px;
  3177. }
  3178. .session-navigator button {
  3179. height: 20px;
  3180. background: none;
  3181. border: 0;
  3182. color: #eee;
  3183. font-weight: bold;
  3184. zoom: 130%;
  3185. }
  3186.  
  3187. /* @CustomUIStyles */
  3188. .dragBox {
  3189. position: absolute;
  3190. background-color: rgba(233, 233, 233, 0.3);
  3191. border: 5px solid rgba(255, 255, 255, 0.3);
  3192. border-radius: 3px;
  3193. }
  3194. .dragBoxMenu {
  3195. background-color: whitesmoke;
  3196. border-radius: 5px;
  3197. color: #111;
  3198. transform: translate(-50%, -50%);
  3199. position: absolute;
  3200. padding: 3px;
  3201. width: auto;
  3202. z-index: 999;
  3203. }
  3204. .dragBoxMenu > button, .dragBoxMenu > input {
  3205. width: 100%;
  3206. background-color: whitesmoke;
  3207. border: none;
  3208. border-radius: 2px;
  3209. cursor: default;
  3210. transition: none;
  3211. }
  3212. .dragBoxMenu > button:hover, .dragBoxMenu > input:focus {
  3213. background-color: grey;
  3214. color: whitesmoke;
  3215. }
  3216. .dragBoxMenu > input:focus::placeholder {
  3217. color: whitesmoke;
  3218. }
  3219.  
  3220. #joinWithPsk {
  3221. display: none;
  3222. backdrop-filter: blur(5px);
  3223. background: rgba(255, 255, 255, 0.1);
  3224. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3225. padding: 4px 5px;
  3226. border-radius: 8px;
  3227. color: white;
  3228. width: 30vw;
  3229. height: 40px;
  3230. position: fixed;
  3231. left: 35vw;
  3232. top: 60vh;
  3233. }
  3234.  
  3235. .interaction-wheel {
  3236. display: none;
  3237. height: 250px;
  3238. width: 250px;
  3239. border: 80px solid rgba(255, 255, 255, 0.1);
  3240. backdrop-filter: blur(3px);
  3241. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3242. border-radius: 125px;
  3243. position: fixed;
  3244. top: calc(50vh - 125px);
  3245. left: calc(50vw - 125px);
  3246. }
  3247. .tag-is-disabled {
  3248. opacity: 0.4;
  3249. pointer-events: none;
  3250. cursor: no-drop;
  3251. }
  3252. #next-wheel {
  3253. background: rgba(255, 255, 255, 0.1);
  3254. backdrop-filter: blur(3px);
  3255. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3256. color: white;
  3257. right: -120px;
  3258. position: absolute;
  3259. top: -80px;
  3260. height: 60px;
  3261. width: 60px;
  3262. border-radius: 50%;
  3263. border: none;
  3264. cursor: pointer;
  3265. }
  3266. #next-wheel::after {
  3267. content: '\\f363';
  3268. position: absolute;
  3269. width: 100%;
  3270. height: 100%;
  3271. top: 5%;
  3272. left: 5%;
  3273. }
  3274. #zoom-mode {
  3275. background: rgba(255, 255, 255, 0.1);
  3276. backdrop-filter: blur(3px);
  3277. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3278. color: white;
  3279. left: -120px;
  3280. position: absolute;
  3281. bottom: -80px;
  3282. height: 60px;
  3283. width: 60px;
  3284. border-radius: 50%;
  3285. border: none;
  3286. text-align: center;
  3287. padding: 20px 0;
  3288. font-family: 'Hammersmith One';
  3289. }
  3290. .hud-zoom-item {
  3291. width: 48px;
  3292. height: 48px;
  3293. color: white;
  3294. position: absolute;
  3295. transition: all 0.15s ease-in-out;
  3296. }
  3297. .zoom-reset {
  3298. top: -60px;
  3299. left: calc(50% - 15px);
  3300. }
  3301. .zoom-up {
  3302. left: -60px;
  3303. top: calc(50% - 15px);
  3304. }
  3305. .zoom-down {
  3306. top: calc(50% - 15px);
  3307. right: -80px;
  3308. }
  3309. .zoom-prop {
  3310. font-size: 20px;
  3311. bottom: -80px;
  3312. left: 25%;
  3313. }
  3314.  
  3315. #ent-settings {
  3316. flex-direction: column;
  3317. padding: 20px;
  3318. position: absolute;
  3319. color: white;
  3320. background: rgba(255, 255, 255, 0.1);
  3321. backdrop-filter: blur(3px);
  3322. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3323. border-radius: 10px;
  3324. max-width: 180px;
  3325. }
  3326. #current-side {
  3327. background: none;
  3328. border: none;
  3329. margin-top: 5px;
  3330. color: white;
  3331. width: 100%;
  3332. }
  3333. #ent-width {
  3334. margin: 5px -1px 10px;
  3335. width: calc(100% - 45px);
  3336. }
  3337. #ent-width::after {
  3338. content: attr(data-width);
  3339. position: absolute;
  3340. right: 20px;
  3341. color: white;
  3342. }
  3343. #ent-controls {
  3344. display: flex;
  3345. justify-content: space-between;
  3346. margin: 5px -5px 0;
  3347. zoom: 130%;
  3348. }
  3349. #ent-controls button {
  3350. color: white;
  3351. background: none;
  3352. border: none;
  3353. cursor: pointer;
  3354. }
  3355.  
  3356. #hud-debug {
  3357. color: rgb(0, 255, 255);
  3358. }
  3359. #hud-debug > strong {
  3360. font-family: "HammerSmith One";
  3361. color: red;
  3362. font-weight: 700;
  3363. }
  3364.  
  3365. .hud-popup-overlay > div.hud-popup-message {
  3366. background: rgba(255, 255, 255, 0.1);
  3367. backdrop-filter: blur(3px);
  3368. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3369. }
  3370. .hud-popup-overlay .hud-popup-confirmation .hud-confirmation-actions .btn.btn-green {
  3371. background: var(--normal-btn);
  3372. }
  3373.  
  3374. .hud-tooltip {
  3375. background: rgba(255, 255, 255, 0.1);
  3376. backdrop-filter: blur(3px);
  3377. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3378. border-radius: 10px;
  3379. }
  3380. .hud-tooltip-left::after {
  3381. left: calc(100% + 5px);
  3382. border-left: 6px solid rgba(255, 255, 255, 0.2);
  3383. }
  3384. .hud-tooltip-right::after {
  3385. right: calc(100% + 5px);
  3386. border-right: 6px solid rgba(255, 255, 255, 0.2);
  3387. }
  3388. .hud-tooltip-top::after {
  3389. top: calc(100% + 5px);
  3390. border-top: 6px solid rgba(255, 255, 255, 0.2);
  3391. }
  3392. .hud-tooltip-bottom::after {
  3393. bottom: calc(100% + 5px);
  3394. border-bottom: 6px solid rgba(255, 255, 255, 0.2);
  3395. }
  3396. .hud-building-view, .hud-building-ahrc {
  3397. position: relative;
  3398. display: block;
  3399. padding: 0 10px;
  3400. margin: 0 0 6px;
  3401. font-family: 'Hammersmith One', sans-serif;
  3402. text-shadow: 0 1px 3px rgb(0 0 0 / 20%);
  3403. text-align: left;
  3404. }
  3405.  
  3406. .hud-chat {
  3407. resize: vertical;
  3408. max-height: 380px;
  3409. min-height: 75px;
  3410. overflow-y: auto;
  3411. border-radius: 4px 4px 4px 0;
  3412. }
  3413. .hud-chat .hud-chat-message {
  3414. display: block;
  3415. position: relative;
  3416. width: 90%;
  3417. white-space: unset;
  3418. word-break: break-all;
  3419. overflow: visible;
  3420. }
  3421. .hud-chat .hud-chat-message strong {
  3422. display: inline-block;
  3423. }
  3424. .hud-chat .hud-chat-message > small {
  3425. position: absolute;
  3426. right: -12%;
  3427. font-weight: bold;
  3428. opacity: 0.4;
  3429. }
  3430.  
  3431. #hud-spell-icons {
  3432. background: rgba(255, 255, 255, 0.1);
  3433. backdrop-filter: blur(3px);
  3434. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3435. border-top-right-radius: 10px;
  3436. border-bottom-right-radius: 10px;
  3437. }
  3438. #hud-spell-icons > div {
  3439. background: none;
  3440. }
  3441.  
  3442. #hud-menu-icons {
  3443. background: rgba(255, 255, 255, 0.1);
  3444. backdrop-filter: blur(3px);
  3445. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3446. border-top-left-radius: 10px;
  3447. border-bottom-left-radius: 10px;
  3448. }
  3449. #hud-menu-icons > div {
  3450. background: none;
  3451. }
  3452.  
  3453. #hud > div.hud-bottom-left {
  3454. z-index: 20;
  3455. backdrop-filter: blur(3px);
  3456. background: rgba(255, 255, 255, 0.15);
  3457. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3458. padding: 10px;
  3459. border-radius: 4px;
  3460. }
  3461. #hud-map {
  3462. cursor: crosshair;
  3463. pointer-events: all;
  3464. background: rgba(0, 0, 0, 0.4);
  3465. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3466. }
  3467. #hud-day-night-ticker {
  3468. background: rgba(0, 0, 0, 0.4);
  3469. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3470. margin-top: 0px;
  3471. }
  3472.  
  3473. #hud-resources {
  3474. background: rgba(255, 255, 255, 0.1);
  3475. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3476. backdrop-filter: blur(3px);
  3477. }
  3478. #hud-health-bar {
  3479. height: 3px;
  3480. padding: 0px;
  3481. }
  3482. #hud-health-bar::after {
  3483. content: unset;
  3484. }
  3485. #hud-health-bar > div {
  3486. height: 3px;
  3487. }
  3488. #hud-shield-bar {
  3489. height: 3px;
  3490. padding: 0px;
  3491. margin: 0px 0px 5px !important;
  3492. }
  3493. #hud-shield-bar > div {
  3494. height: 3px;
  3495. border-radius: 0px;
  3496. }
  3497. #hud-party-icons > div {
  3498. background: rgba(255, 255, 255, 0.1);
  3499. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3500. backdrop-filter: blur(3px);
  3501. }
  3502. #hud-party-icons > div.is-empty {
  3503. background: rgba(255, 255, 255, 0.1) !important;
  3504. opacity: 0.4;
  3505. }
  3506. .hud-buff-bar .hud-buff-bar-item::before {
  3507. content: attr(data-tier);
  3508. }
  3509. #hud-buff-bar > a {
  3510. background: rgba(255, 255, 255, 0.1);
  3511. box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.1);
  3512. backdrop-filter: blur(2px);
  3513. }
  3514.  
  3515. #hud-toolbar > div.hud-toolbar-buildings > a {
  3516. background: rgba(255, 255, 255, 0.1);
  3517. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3518. backdrop-filter: blur(3px);
  3519. }
  3520. #hud-toolbar > div.hud-toolbar-buildings > a.is-disabled {
  3521. background: rgba(255, 255, 255, 0.1) !important;
  3522. }
  3523.  
  3524. #hud-respawn {
  3525. background: none;
  3526. z-index: 9999;
  3527. width: 600px;
  3528. height: 200px;
  3529. top: calc(50vh - 100px);
  3530. left: calc(50vw - 300px);
  3531. }
  3532. #hud-respawn > div {
  3533. margin: 0px;
  3534. }
  3535. #hud-respawn > div > div > div {
  3536. display: flex;
  3537. width: 500px;
  3538. backdrop-filter: blur(3px);
  3539. background: rgba(255, 255, 255, 0.1);
  3540. box-shadow: 0px 0px 30px 10px rgba(0, 0, 0, 0.1);
  3541. border-radius: 10px;
  3542. align-items: flex-end;
  3543. justify-content: space-between;
  3544. padding: 10px 20px 30px;
  3545. }
  3546.  
  3547. /* @CustomMenuStyles */
  3548. #hud-menu-shop {
  3549. top: calc(50vh - 215px);
  3550. left: calc(50vw - 345px);
  3551. width: 690px;
  3552. height: 430px;
  3553. backdrop-filter: blur(3px);
  3554. background: rgba(255, 255, 255, 0.1);
  3555. box-shadow: 0px 0px 30px 10px rgba(0, 0, 0, 0.1);
  3556. margin: 0 0 0 0;
  3557. padding: 0px;
  3558. z-index: 20;
  3559. overflow: hidden;
  3560. border-radius: 10px;
  3561. }
  3562. #hud-menu-shop > h3 {
  3563. margin: 20px;
  3564. }
  3565. .hud-menu-shop .hud-shop-grid {
  3566. height: 360px;
  3567. border-radius: 0px;
  3568. background: rgba(0, 0, 0, 0.1);
  3569. }
  3570. .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip {
  3571. background: var(--normal-btn);
  3572. }
  3573. .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip:hover, .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip:active {
  3574. background: var(--light-hover-btn);
  3575. }
  3576. .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip.is-disabled {
  3577. background: none;
  3578. }
  3579. .hud-menu-shop .hud-shop-grid .hud-shop-item[data-item=HatComingSoon] .hud-shop-item-coming-soon {
  3580. background: none;
  3581. }
  3582. #hud-menu-shop > div.hud-shop-tabs > a.hud-shop-tabs-link.is-active {
  3583. background: rgba(0, 0, 0, 0.1);
  3584. }
  3585. #hud-menu-shop > div.hud-shop-tabs > a.hud-shop-tabs-link:first-child {
  3586. border-radius: 0px;
  3587. }
  3588.  
  3589. .hud-menu-party .hud-party-members .hud-member-link::before {
  3590. display: block;
  3591. position: absolute;
  3592. content: " ";
  3593. left: 0px;
  3594. bottom: 0px;
  3595. height: 3px;
  3596. width: 30%;
  3597. }
  3598. .hud-menu-party .hud-party-grid .hud-party-link span:nth-child(4) {
  3599. display: none;
  3600. position: absolute;
  3601. top: 10px;
  3602. right: 15px;
  3603. }
  3604. #hud-menu-party > div.hud-party-members > div:nth-child(1)::before {
  3605. background: #8473d4;
  3606. }
  3607. #hud-menu-party > div.hud-party-members > div:nth-child(2)::before {
  3608. background: #d6ab35;
  3609. }
  3610. #hud-menu-party > div.hud-party-members > div:nth-child(3)::before {
  3611. background: #76bd2f;
  3612. }
  3613. #hud-menu-party > div.hud-party-members > div:nth-child(4)::before {
  3614. background: #d67820;
  3615. }
  3616. #hud-menu-party {
  3617. top: calc(50vh - 240px);
  3618. left: calc(50vw - 305px);
  3619. margin: 0;
  3620. width: 610px;
  3621. height: 480px;
  3622. backdrop-filter: blur(3px);
  3623. background: rgba(255, 255, 255, 0.1);
  3624. box-shadow: 0px 0px 30px 10px rgba(0, 0, 0, 0.1);
  3625. z-index: 20;
  3626. border-radius: 10px;
  3627.  
  3628. /* Alternative
  3629. backdrop-filter: blur(5px);
  3630. background: rgba(111, 208, 247, 0.05);
  3631. box-shadow: 0px 0px 10px 10px rgba(0, 0, 0, 0.1);
  3632. z-index: 20;
  3633. */
  3634. }
  3635. .hud-menu-party .hud-party-grid .hud-party-link.is-active {
  3636. background: var(--normal-btn) !important;
  3637. }
  3638. .hud-menu-party .hud-party-visibility {
  3639. width: 275.5px;
  3640. margin: 10px 3px 0 0;
  3641. background: var(--normal-btn);
  3642. }
  3643. .hud-menu-party .hud-party-share {
  3644. width: 395px;
  3645. margin: 0 0 0 5px;
  3646. }
  3647. .hud-menu-party .hud-party-visibility:hover, .hud-menu-party .hud-party-visibility:active {
  3648. background: var(--light-hover-btn);
  3649. }
  3650.  
  3651. /* @CustomModMenuStyles */
  3652. #hud-menu-settings {
  3653. backdrop-filter: blur(3px);
  3654. background: rgba(255, 255, 255, 0.1);
  3655. box-shadow: 0px 0px 30px 10px rgba(0, 0, 0, 0.1);
  3656. margin: 0px;
  3657. top: calc(50vh - 250px);
  3658. left: calc(50vw - 360px);
  3659. width: 720px;
  3660. height: 500px;
  3661. padding: 0px;
  3662. border-radius: 10px;
  3663. overflow: hidden;
  3664. z-index: 20;
  3665. }
  3666. .hud-menu-tabs {
  3667. position: relative;
  3668. height: 40px;
  3669. line-height: 40px;
  3670. margin-top: 30px;
  3671. }
  3672. .hud-menu-tabs-link {
  3673. display: block;
  3674. float: left;
  3675. padding: 0 14px;
  3676. margin: 0 1px 0 0;
  3677. font-size: 14px;
  3678. background: rgba(0, 0, 0, 0.1);
  3679. color: rgba(255, 255, 255, 0.4);
  3680. transition: all 0.15s ease-in-out;
  3681. }
  3682. .hud-menu-tabs-link.is-active, .hud-menu-tabs-link:hover {
  3683. background: rgba(0, 0, 0, 0.36);
  3684. color: #eee;
  3685. }
  3686. .hud-menu-tabs-link:last-child {
  3687. border-top-right-radius: 3px;
  3688. }
  3689. .hint-controls {
  3690. position: absolute;
  3691. display: flex;
  3692. flex-direction: column;
  3693. zoom: 83%;
  3694. width: fit-content;
  3695. height: 65px;
  3696. top: 55px;
  3697. left: 53%;
  3698. overflow-y: scroll;
  3699. }
  3700. .hint-controls > li {
  3701. opacity: 0.5;
  3702. -webkit-font-smoothing: antialiased;
  3703. margin: 0 5px 0 0;
  3704. }
  3705. #hud-menu-settings > h3 {
  3706. margin: 20px;
  3707. }
  3708. .hud-menu-settings .hud-settings-grid {
  3709. height: 390px;
  3710. margin: 0px;
  3711. overflow: hidden;
  3712. padding: unset;
  3713. border-top-left-radius: 0px;
  3714. border-top-right-radius: 0px;
  3715. }
  3716. .hud-settings-page {
  3717. width: 100%;
  3718. height: 100%;
  3719. }
  3720. .hud-settings-page > span {
  3721. position: relative;
  3722. margin: auto;
  3723. font-size: 17px;
  3724. opacity: 0.7;
  3725. }
  3726. .hud-settings-options {
  3727. display: inline-block;
  3728. position: relative;
  3729. width: 50%;
  3730. height: 100%;
  3731. background: rgba(0, 0, 0, 0.2);
  3732. overflow: auto;
  3733. scrollbar-width: none;
  3734. }
  3735. .hud-settings-options > div {
  3736. opacity: 0.8;
  3737. display: block;
  3738. position: relative;
  3739. height: 120px;
  3740. border-bottom: 3px solid rgba(255, 255, 255, 0.2);
  3741. padding: 15px;
  3742. }
  3743. .hud-settings-options > div.disabled {
  3744. pointer-events: none;
  3745. opacity: 0.4;
  3746. }
  3747. .hud-settings-options > div:nth-child(even) {
  3748. background: rgba(0, 0, 0, 0.15);
  3749. }
  3750. .hud-settings-options > div:last-child {
  3751. border-bottom: none;
  3752. }
  3753. .hud-settings-options > div > div {
  3754. display: flex;
  3755. position: absolute;
  3756. bottom: 11px;
  3757. right: 11px;
  3758. justify-content: flex-end;
  3759. }
  3760. .hud-settings-options h2 {
  3761. font-family: "Open Sans";
  3762. margin: 5px 0;
  3763. font-size: 1.4em;
  3764. }
  3765. .hud-settings-options span {
  3766. display: block;
  3767. position: absolute;
  3768. opacity: 0.7;
  3769. width: 55%;
  3770. -webkit-font-smoothing: antialiased;
  3771. font-size: 14px;
  3772. }
  3773. .hud-settings-options > div > div span {
  3774. position: relative;
  3775. width: 60px;
  3776. }
  3777. .hud-settings-options button {
  3778. position: absolute;
  3779. top: calc(50% - 20px);
  3780. right: 50px;
  3781. height: 40px;
  3782. width: 25%;
  3783. background: #fff;
  3784. border: none;
  3785. border-bottom: 3px solid lightgreen;
  3786. color: #111;
  3787. font-size: 16px;
  3788. cursor: pointer;
  3789. transition: all 0.15s ease-in-out;
  3790. border-radius: 5px;
  3791. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.05);
  3792. }
  3793. .hud-settings-options .underline-red {
  3794. border-bottom: 3px solid red;
  3795. }
  3796. .hud-settings-options a {
  3797. position: absolute;
  3798. top: calc(50% - 10px);
  3799. right: 10px;
  3800. height: 20px;
  3801. width: 20px;
  3802. background: unset;
  3803. opacity: 0.4;
  3804. transition: all 0.15s ease-in-out;
  3805. }
  3806. .hud-settings-options a::before {
  3807. font-family: "Font Awesome 5 Free";
  3808. content: "\\f054";
  3809. font-size: 20px;
  3810. height: 100%;
  3811. width: 100%;
  3812. display: block;
  3813. font-weight: 900;
  3814. }
  3815. .hud-settings-options a:hover {
  3816. opacity: 1;
  3817. }
  3818. .hud-settings-options input {
  3819. position: relative;
  3820. margin-bottom: 0px;
  3821. }
  3822. .hud-settings-more {
  3823. position: relative;
  3824. display: inline-block;
  3825. width: 50%;
  3826. height: 100%;
  3827. padding: 15px;
  3828. overflow: auto;
  3829. }
  3830. .hud-settings-more h2 {
  3831. margin: 5px 0px 10px;
  3832. }
  3833. .hud-settings-more select {
  3834. height: 40px;
  3835. width: 35%;
  3836. background: #fff;
  3837. border: none;
  3838. color: #111;
  3839. cursor: pointer;
  3840. transition: all 0.15s ease-in-out;
  3841. border-radius: 5px;
  3842. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.1);
  3843. float: right;
  3844. padding: 0px 10px;
  3845. }
  3846. .hud-settings-more select:hover {
  3847. background: #fff;
  3848. color: black;
  3849. }
  3850. .hud-settings-more input:not([type="checkbox"]) {
  3851. height: 40px;
  3852. width: 100%;
  3853. background: rgba(0, 0, 0, 0.2);
  3854. border: none;
  3855. border-radius: 4px;
  3856. padding: 5px 10px;
  3857. color: #eee;
  3858. margin: 10px 0;
  3859. box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
  3860. }
  3861. .hud-settings-more span {
  3862. display: block;
  3863. opacity: 0.5;
  3864. }
  3865. .hud-menu-settings > .hud-settings-grid label > span {
  3866. display: inline-block;
  3867. color: white;
  3868. text-transform: unset;
  3869. font-size: 16px;
  3870. }
  3871. .hud-settings-more p {
  3872. display: inline-block;
  3873. height: 40px;
  3874. align-content: center;
  3875. margin: unset;
  3876. opacity: 0.8;
  3877. font-size: 15px;
  3878. }
  3879. .hud-settings-more span {
  3880. display: block;
  3881. opacity: 0.5;
  3882. }
  3883. .hud-settings-more hr {
  3884. width: 8%;
  3885. float: left;
  3886. margin-top: -5px;
  3887. opacity: 0.4;
  3888. }
  3889.  
  3890. /* @CustomMoreSettings */
  3891. .base-card {
  3892. position: relative;
  3893. display: block;
  3894. width: 100%;
  3895. height: 64px;
  3896. margin: 0 0 10px;
  3897. padding: 10px 10px 10px 10px;
  3898. text-decoration: none;
  3899. background: rgba(255, 255, 255, 0.1);
  3900. cursor: pointer;
  3901. color: #eee;
  3902. border-radius: 3px;
  3903. transition: all 0.15s ease-in-out;
  3904. text-align: left;
  3905. }
  3906. .base-card:hover {
  3907. background: rgba(255, 255, 255, 0.2);
  3908. }
  3909. #base-management {
  3910. position: absolute;
  3911. top: 0px;
  3912. width: 100%;
  3913. height: 75%;
  3914. margin: 0px -15px;
  3915. padding: 0 15px;
  3916. overflow-y: scroll;
  3917. overflow-x: visible;
  3918. scrollbar-width: none;
  3919. }
  3920. #base-management input {
  3921. margin: 0px;
  3922. }
  3923. #target-base-name {
  3924. background: none;
  3925. box-shadow: none;
  3926. text-align: left;
  3927. font-weight: bold;
  3928. padding: 0px;
  3929. font-size: 16px;
  3930. }
  3931. #target-base-description {
  3932. background: none;
  3933. box-shadow: none;
  3934. text-align: left;
  3935. padding: 0px;
  3936. opacity: 0.8;
  3937. height: 20px;
  3938. margin-bottom: 10px;
  3939. }
  3940. #target-base-design {
  3941. background: none;
  3942. box-shadow: none;
  3943. text-align: left;
  3944. padding: 0px;
  3945. opacity: 0.4;
  3946. height: 20px;
  3947. margin-bottom: 20px;
  3948. font-size: 8px;
  3949. }
  3950. #action-tab {
  3951. display: flex;
  3952. flex-direction: row;
  3953. justify-content: space-around;
  3954. height: 40px;
  3955. margin: 0 -15px -10px;
  3956. overflow-x: visible;
  3957. background: rgba(0, 0, 0, 0.1);
  3958. }
  3959. #action-tab > button {
  3960. width: 40px;
  3961. background: none;
  3962. border: none;
  3963. color: #eee;
  3964. filter: drop-shadow(2px 2px 0px rgba(0, 0, 0, 0.1));
  3965. font-size: 16px;
  3966. cursor: pointer;
  3967. }
  3968. #useful-info {
  3969. display: flex;
  3970. flex-wrap: wrap;
  3971. flex-direction: column;
  3972. align-items: flex-start;
  3973. height: 50px;
  3974. margin-top: 10px;
  3975. font-size: 14px;
  3976. }
  3977.  
  3978. #switch-ses {
  3979. display: flex;
  3980. }
  3981. #switch-ses select {
  3982. display: block;
  3983. width: 85%;
  3984. margin: 0px 10px 0 0;
  3985. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.1);
  3986. }
  3987. #switch-ses button {
  3988. background: none;
  3989. box-shadow: unset;
  3990. border: 0px;
  3991. color: white;
  3992. cursor: pointer;
  3993. width: 40px;
  3994. font-size: 20px;
  3995. }
  3996.  
  3997. .more-title {
  3998. display: flex;
  3999. flex-direction: row;
  4000. justify-content: space-between;
  4001. align-items: stretch;
  4002. margin: 20px -15px 10px;
  4003. padding: 5px 15px 10px;
  4004. background: rgba(0, 0, 0, 0.2);
  4005. height: 50px;
  4006. }
  4007. .more-title:first-child {
  4008. margin: -15px -15px 10px;
  4009. }
  4010. #general-control, #multibox-control {
  4011. margin: 20px 0;
  4012. display: flex;
  4013. flex-direction: row;
  4014. flex-wrap: wrap;
  4015. }
  4016. #general-control button, #multibox-control button {
  4017. height: 40px;
  4018. background: #fff;
  4019. border: none;
  4020. border-bottom: 2px solid red;
  4021. color: #111;
  4022. font-size: 16px;
  4023. cursor: pointer;
  4024. border-radius: 5px;
  4025. box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.05);
  4026. padding: 0 20px;
  4027. }
  4028. #socket-info {
  4029. display: flex;
  4030. align-items: baseline;
  4031. gap: 12px;
  4032. }
  4033. .more-title > * {
  4034. margin: 0;
  4035. }
  4036. #clone-status > p {
  4037. position: relative;
  4038. margin: 10px 0 0;
  4039. }
  4040.  
  4041. #heat-range, #scene-alpha-range {
  4042. display: flex;
  4043. margin: 10px 0;
  4044. }
  4045. #heat-range input[type="number"], #scene-alpha-range input[type="number"] {
  4046. width: 26%;
  4047. }
  4048. #heat-range input[type="range"], #scene-alpha-range input[type="range"] {
  4049. margin: 10px;
  4050. box-shadow: none;
  4051. }
  4052. `;
  4053. let styles = document.createElement("style");
  4054. styles.type = "text/css";
  4055. styles.appendChild(document.createTextNode(css));
  4056. document.head.appendChild(styles);
  4057.  
  4058. window.getClass = (DOMClass) => {
  4059. return document.getElementsByClassName(DOMClass);
  4060. };
  4061.  
  4062. window.getId = (DOMId) => {
  4063. return document.getElementById(DOMId);
  4064. };
  4065.  
  4066. const getClass = window.getClass;
  4067. const getId = window.getId;
  4068.  
  4069. /* @IntroJsStyles */
  4070. document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div").removeChild(document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > button"));
  4071.  
  4072. getClass("hud-intro-corner-top-left")[0].insertAdjacentHTML("afterbegin", `
  4073. <div>
  4074. <label>
  4075. <input type="checkbox" id="useSes">
  4076. <span>Session Mode</span>
  4077. </label>
  4078. <label>
  4079. <input type="checkbox" id="shouldUseOptimization">
  4080. <span>Enhanced Optimization</span>
  4081. </label>
  4082. </div>
  4083. `);
  4084. document.querySelector(".hud-intro-corner-top-left > div").insertAdjacentElement("beforeend", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > label"));
  4085.  
  4086. document.querySelector("#hud-intro").setAttribute("style", "--bg-image: url('https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/BG_eden_append_light.webp?v=1717285760533');");
  4087. document.querySelector("#hud-intro").insertAdjacentHTML("afterbegin", `
  4088. <div id="intro-animation">
  4089. <canvas id="background-canvas"></canvas>
  4090. <img src="https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/eto_large.png?v=1717285769725" />
  4091. <canvas id="foreground-canvas"></canvas>
  4092. </div>
  4093. `);
  4094. document.querySelector("#hud-intro").insertAdjacentHTML("beforeend", `
  4095. <div id="start-btn">
  4096. <h1>Play</h1>
  4097. <hr />
  4098. <h2>Click to play</h2>
  4099. </div>
  4100. <div id="hud-intro-overlay">
  4101. <div id="loading-div">
  4102. <span class="hud-loading"></span>
  4103. <a href="javascript:void(0);" onclick="game.ui.components.Intro.hideLoadingScreen();">Click to return</a>
  4104. </div>
  4105. </div>
  4106. `);
  4107. document.getElementsByClassName('hud-party-tag')[0].setAttribute('maxlength', 49);
  4108. document.getElementsByClassName('hud-intro-name')[0].setAttribute('maxlength', 29);
  4109.  
  4110. const allLines = {};
  4111. function createLines(linesOnScreen) {
  4112. // if (Object.keys(allLines).length >= linesOnScreen) return;
  4113. for (const lineId in allLines) {
  4114. const line = allLines[lineId];
  4115. if (line.x < -line.length) delete allLines[lineId];
  4116. };
  4117. for (let i = 0; i < (linesOnScreen - Object.keys(allLines).length); i++) {
  4118. const rctx = ["background-canvas", "foreground-canvas"][Math.floor(Math.random() * 2)];
  4119. const rLineLength = getRandomArbitrary(50, 400);
  4120. const rPosY = getRandomArbitrary(50, window.innerHeight - 50);
  4121. const rSpeed = getRandomArbitrary(20, 50);
  4122. const rTimeout = getRandomArbitrary(20, 5000);
  4123.  
  4124. allLines[genUUID()] = {x: window.innerWidth, y: rPosY, length: rLineLength, speed: rSpeed, ctxId: rctx, timeout: rTimeout, shouldTimeout: true};
  4125. };
  4126. };
  4127.  
  4128. function drawLine() {
  4129. for (const lineId in allLines) {
  4130. const line = allLines[lineId];
  4131. // console.log(line);
  4132.  
  4133. // setTimeout(() => {
  4134. const ctx = getId(line.ctxId).getContext("2d");
  4135. ctx.strokeStyle = "White";
  4136. ctx.lineCap = "round";
  4137. ctx.lineWidth = 5;
  4138.  
  4139. ctx.beginPath();
  4140. ctx.moveTo(line.x, line.y);
  4141. ctx.lineTo(line.x + line.length, line.y);
  4142. ctx.stroke();
  4143. line.shouldTimeout = false;
  4144. // }, line.shouldTimeout ? line.timeout : 0);
  4145. };
  4146. }
  4147.  
  4148. function moveLine(lineIndex) {
  4149. for (const lineId in allLines) {
  4150. allLines[lineId].x -= allLines[lineId].speed;
  4151. };
  4152. }
  4153.  
  4154. let drawLoopId;
  4155. function drawLoop() {
  4156. const linesOnScreen = 5;
  4157. createLines(linesOnScreen);
  4158.  
  4159. const background = getId("background-canvas");
  4160. const bctx = background.getContext("2d");
  4161. bctx.clearRect(0, 0, background.width, background.height);
  4162.  
  4163. const foreground = getId("foreground-canvas");
  4164. const fctx = foreground.getContext("2d");
  4165. fctx.clearRect(0, 0, foreground.width, foreground.height);
  4166.  
  4167. moveLine();
  4168. drawLine();
  4169.  
  4170. drawLoopId = requestAnimationFrame(drawLoop);
  4171. }
  4172. drawLoopId = requestAnimationFrame(drawLoop);
  4173.  
  4174. game.network.addEnterWorldHandler((e) => {
  4175. if (!e.allowed) return game.ui.components.Intro.hideLoadingScreen();
  4176. cancelAnimationFrame(drawLoopId);
  4177. });
  4178.  
  4179. function resizeIntroCanvases() {
  4180. const background = getId("background-canvas");
  4181. background.width = window.innerWidth;
  4182. background.height = window.innerHeight;
  4183.  
  4184. const foreground = getId("foreground-canvas");
  4185. foreground.width = window.innerWidth;
  4186. foreground.height = window.innerHeight;
  4187. };
  4188. resizeIntroCanvases();
  4189. window.addEventListener("resize", resizeIntroCanvases);
  4190.  
  4191. // game.ui.components.Intro.submitElem = getId("start-btn");
  4192. game.ui.components.Intro.hideLoadingScreen = function() {
  4193. getId("hud-intro-overlay").style.display = "none";
  4194. getId("hud-intro-overlay").style.opacity = 0;
  4195. getId("loading-div").style.display = "none";
  4196. };
  4197. game.ui.components.Intro.showLoadingScreen = function() {
  4198. getId("select-session-add").style.display = "none";
  4199. getId("endpoint-add-menu").style.display = "none";
  4200. getId("session-add-menu").style.display = "none";
  4201.  
  4202. getId("hud-intro-overlay").style.display = "flex";
  4203. getId("hud-intro-overlay").style.opacity = 1;
  4204. getId("loading-div").style.display = "flex";
  4205. };
  4206.  
  4207. game.ui.components.Intro.onSubmitClick = function () {
  4208. const realNicknameLength = new Blob([this.nameInputElem.value]).size;
  4209. if (realNicknameLength > 29) return void game.ui.components.Intro.onConnectionError('Your nickname length is too long. Please shorten it/use less special characters.');
  4210. const server = this.ui.getOption(`servers`)[this.serverElem.value];
  4211. localStorage.setItem(`name`, this.nameInputElem.value.trim());
  4212. this.connecting || (
  4213. this.connecting = true,
  4214. getId("hud-intro-overlay").style.display = "flex",
  4215. getId("hud-intro-overlay").style.opacity = 1,
  4216. getId("loading-div").style.display = "flex",
  4217. this.connectionTimer = setTimeout(() => {
  4218. const _this = game.ui.components.Intro;
  4219. _this.connecting = false;
  4220. game.network.disconnect();
  4221. _this.hideLoadingScreen();
  4222. _this.serverElem?.classList.add('has-error');
  4223. _this.errorElem.style.display = 'block';
  4224. _this.errorElem.innerText = `We failed to join the game - this is a known issue with anti-virus software. Please try disabling any web filtering features.`;
  4225. }, 15000),
  4226. this.errorElem.style.display = `none`,
  4227. this.ui.setOption(`nickname`,this.nameInputElem.value.trim()),
  4228. this.ui.setOption(`serverId`, this.serverElem.value),
  4229. game.network.connect(server)
  4230. );
  4231. }
  4232. getId("start-btn").onclick = game.ui.components.Intro.onSubmitClick.bind(game.ui.components.Intro);
  4233.  
  4234. game.ui.components.Intro.onEnterWorld = function (data) {
  4235. this.connecting = false;
  4236. if (this.connectionTimer) {
  4237. clearInterval(this.connectionTimer);
  4238. delete this.connectionTimer;
  4239. }
  4240. if (!data.allowed) {
  4241. _this.hideLoadingScreen();
  4242. this.serverElem.classList.add('has-error');
  4243. this.errorElem.style.display = 'block';
  4244. this.errorElem.innerText = 'This server is currently full. Please try again later or select another server.';
  4245. return;
  4246. }
  4247. this.hide();
  4248. };
  4249.  
  4250. game.ui.components.Intro.onConnectionError = function (errorText) {
  4251. errorText ||= `We were unable to connect to the gameserver. Please try another server.`;
  4252. this.connecting = false;
  4253. this.connectionTimer && (
  4254. clearInterval(this.connectionTimer),
  4255. delete this.connectionTimer
  4256. );
  4257. this.hideLoadingScreen();
  4258. this.serverElem.classList.add('has-error');
  4259. this.errorElem.style.display = 'block';
  4260. this.errorElem.innerText = errorText;
  4261. };
  4262.  
  4263. document.addEventListener('keyup', function(e) {
  4264. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  4265. if (e.code == 'Escape') {
  4266. game.ui.components.Intro.hideLoadingScreen();
  4267. };
  4268. if (e.key == "Enter") {
  4269. (game.ui?.playerTick?.dead === 1) && game.ui.components.Chat.startTyping();
  4270. };
  4271. if (e.key == ";") {
  4272. game.ui.getPlayerPetUid() && Game.currentGame.network.sendRpc({name: "DeleteBuilding", uid: game.ui.getPlayerPetUid()});
  4273. }
  4274. if (e.key == "'") {
  4275. if (game.ui.getPlayerPetUid()) {
  4276. game.network.sendRpc({name: "BuyItem", itemName: "PetRevive", tier: 1});
  4277. game.network.sendRpc({name: "EquipItem", itemName: "PetRevive", tier: 1});
  4278. };
  4279. };
  4280. if (e.code == 'KeyC' && !e.ctrlKey) {
  4281. setTimeout(() => {
  4282. document.querySelector('#joinWithPsk').style.display = 'block';
  4283. document.querySelector('#joinWithPsk').focus();
  4284. document.querySelector('#joinWithPsk').value = "";
  4285. }, 100);
  4286. }
  4287. };
  4288. });
  4289.  
  4290. /* @Misc. */
  4291. getId('hud').insertAdjacentHTML('beforeend', `
  4292. <input id="joinWithPsk" type="tel" placeholder="insert PSK..." class="btn">
  4293. `);
  4294. document.querySelector('#joinWithPsk').addEventListener('keyup', (e) => {
  4295. if (e.key == "Enter" || e.key == "Escape") {
  4296. e.target.style.display = 'none';
  4297. e.key == "Enter" && game.network.sendRpc({name: "JoinPartyByShareKey", partyShareKey: e.target.value});
  4298. };
  4299. });
  4300.  
  4301. document.querySelector("#hud-resources").appendChild(getId("hud-shield-bar"));
  4302. document.querySelector("#hud-resources").appendChild(getId("hud-health-bar"));
  4303.  
  4304. document.querySelector("#hud-respawn > div > div > div").insertAdjacentHTML("afterbegin", `
  4305. <div id="respawn-text-div" style="display: flex;flex-direction: column;flex-wrap: wrap;width: fit-content;padding: 0 10px;opacity: 0.7;align-items: flex-start;"></div>
  4306. <button class="hud-respawn-btn" id="hud-spectate-btn">Spectate</button>
  4307. `);
  4308.  
  4309. game.ui.components.Respawn.respawnTextElem = getId("respawn-text-div");
  4310. game.ui.components.Respawn.onPlayerDeath = function (deadResponse) {
  4311. window.deadPos = game.ui.playerTick.position;
  4312. const player = Game.currentGame.world.getEntityByUid(Game.currentGame.world.getMyUid()),
  4313. playerTick = player.getTargetTick();
  4314. this.lastTick = playerTick;
  4315. this.respawnTextElem.innerHTML = `<li>Wave: ` + playerTick.wave + `</li><li>Score: ` + playerTick.score.toLocaleString() + `</li><li>Leaderboard: #` + (game.ui.components.Leaderboard.leaderboardData.find(e => e.uid == game.world.myUid).rank + 1) + `</li>`;
  4316. this.show();
  4317. }
  4318. game.network.addRpcHandler("Dead", game.ui.components.Respawn.onPlayerDeath.bind(game.ui.components.Respawn));
  4319.  
  4320. /* @ModMenuJsStyles */
  4321. getId('hud-menu-settings').innerHTML = `
  4322. <a class="hud-menu-close" onclick="getId('hud-menu-settings').style.display = 'none';"></a>
  4323. <h3>Advanced</h3>
  4324. <div class="hud-menu-tabs">
  4325. <a class="hud-menu-tabs-link" data-menu="0">Build</a>
  4326. <a class="hud-menu-tabs-link" data-menu="1">Player</a>
  4327. <a class="hud-menu-tabs-link" data-menu="2">WS & Raid</a>
  4328. <a class="hud-menu-tabs-link" data-menu="3">Visual</a>
  4329. <a class="hud-menu-tabs-link" data-menu="4">Misc.</a>
  4330. </div>
  4331. <div class="hint-controls"></div>
  4332. <div class="hud-settings-grid" page="0"></div>
  4333. `;
  4334.  
  4335. getClass('hud-settings-grid')[0].innerHTML = `
  4336. <div class="hud-settings-page" id="page0">
  4337. <div class="hud-settings-options"></div>
  4338. <div class="hud-settings-more"></div>
  4339. </div>
  4340. <div class="hud-settings-page" id="page1">
  4341. <div class="hud-settings-options"></div>
  4342. <div class="hud-settings-more"></div>
  4343. </div>
  4344. <div class="hud-settings-page" id="page2">
  4345. <div class="hud-settings-options"></div>
  4346. <div class="hud-settings-more"></div>
  4347. </div>
  4348. <div class="hud-settings-page" id="page3">
  4349. <div class="hud-settings-options"></div>
  4350. <div class="hud-settings-more"></div>
  4351. </div>
  4352. <div class="hud-settings-page" id="page4">
  4353. <div class="hud-settings-options"></div>
  4354. <div class="hud-settings-more"></div>
  4355. </div>
  4356. `;
  4357.  
  4358. const hint_enum = {
  4359. 0: `<li><strong>Shift + 1</strong> [!] toggles Wall Block.</li>
  4360. <li><strong>Comma</strong> [,] toggles Rebuilder.</li>
  4361. <li><strong>Period</strong> [.] toggles Auto Upgrade.</li>`,
  4362.  
  4363. 1: `<li><strong>Shift-click</strong> on the minimap to navigate.</li>
  4364. <li><strong>Equal</strong> [=] toggles Auto Bow.</li>
  4365. <li><strong>C</strong> toggles quick join via PSK input.</li>
  4366. <li><strong>G</strong> toggles zoom menu.</li>
  4367. <li><strong>Dash</strong> [-] toggles local info indicators.</li>
  4368. <li><strong>Semi-colon</strong> [;] deletes your pet.</li>
  4369. <li><strong>Back-tick</strong> ['] revives your pet.</li>`,
  4370. 2: ``,
  4371.  
  4372. 3: /*`<li><strong>?</strong> toggles Screenshot Mode.</li>
  4373. <li><strong>~</strong> marks your position.</li>
  4374. <li><strong>+</strong> toggles Map Inspector.</li>`*/``,
  4375. 4: ``,
  4376. };
  4377.  
  4378. function refreshMore(page) {
  4379. const container = document.querySelector("#" + page + " > div.hud-settings-more");
  4380. for (let children of container.children) {
  4381. children.style.display = "none";
  4382. }
  4383. }
  4384.  
  4385. function refreshPage() {
  4386. for (let i = 0; i < getClass('hud-settings-grid')[0].children.length; i++) getId(`page${i}`).style.display = "none";
  4387. };
  4388.  
  4389. function setPage(page) {
  4390. const lastPage = parseInt(getClass('hud-settings-grid')[0].getAttribute('page'));
  4391.  
  4392. refreshPage();
  4393.  
  4394. getClass("hud-menu-tabs")[0].children[lastPage].classList.remove("is-active");
  4395. getClass("hud-menu-tabs")[0].children[page].classList.add("is-active");
  4396.  
  4397. getId(`page${page}`).style.display = "flex";
  4398. getClass('hint-controls')[0].innerHTML = hint_enum[page];
  4399. getClass('hud-settings-grid')[0].setAttribute('page', page);
  4400. };
  4401. setPage('0');
  4402. Array.from(getClass("hud-menu-tabs")[0].children).forEach((e) => {
  4403. e.onclick = () => { setPage(e.getAttribute("data-menu")); };
  4404. });
  4405.  
  4406. const menu = {
  4407. page0: {
  4408. AHRC: {
  4409. name: `AHRC`,
  4410. description: `Automatically harvests resources.`,
  4411. more: {
  4412. html: `
  4413. <p>AHRC type: </p>
  4414. <select id="ahrcOptions">
  4415. <option value="ch" selected>All</option>
  4416. <option value="h">Harvest</option>
  4417. <option value="c">Collect</option>
  4418. </select>
  4419. <br><br>
  4420. <span>The <strong>All</strong> option is both Harvest + Collect.</span>
  4421. `,
  4422. functions: () => {},
  4423. },
  4424. },
  4425. wallBlock: {
  4426. name: `Defense Block`,
  4427. description: `Allows you to place mulitple defenses at once.`,
  4428. more: {
  4429. html: `
  4430. <p>Block width: </p>
  4431. <select id="blockX" class="btn">
  4432. ${[3, 5, 7, 9, 11, 13, 15].map(size => {
  4433. return `<option value="${size}" ${size == 5 ? "selected" : ""}>${size} blocks</option>`;
  4434. }).join("\n")}
  4435. </select>
  4436. <br><br>
  4437. <p>Block height: </p>
  4438. <select id="blockY" class="btn">
  4439. ${[3, 5, 7, 9, 11, 13, 15].map(size => {
  4440. return `<option value="${size}" ${size == 5 ? "selected" : ""}>${size} blocks</option>`;
  4441. }).join("\n")}
  4442. </select>
  4443. <br><br>
  4444. <p>Type of defense: </p>
  4445. <select id="defense-select" class="btn">
  4446. <option value="Wall" selected>Wall</option>
  4447. <option value="Door">Door</option>
  4448. </select>
  4449. <br><br>
  4450. <span>Default value is 5x5, maximum is 15x15 (cells).</span>
  4451. `,
  4452. functions: () => {
  4453. getId("blockX").onchange = () => { game.script.wallBlock.wallElem.setAttribute("data-tier", `${getId("blockX").value}x${getId("blockY").value}`); };
  4454. getId("blockY").onchange = () => { game.script.wallBlock.wallElem.setAttribute("data-tier", `${getId("blockX").value}x${getId("blockY").value}`); };
  4455. getId("defense-select").onchange = ({target}) => {
  4456. game.script.wallBlock.typeOfDefense = target.value;
  4457. game.script.wallBlock.wallElem.setAttribute("data-building", target.value);
  4458. };
  4459. }
  4460. },
  4461. onCallback: () => {
  4462. game.script.wallBlock.wallElem.style.display = "block";
  4463. },
  4464. offCallback: () => {
  4465. game.script.wallBlock.wallElem.style.display = "none";
  4466. },
  4467. },
  4468. autoTrap: {
  4469. name: `Auto Trap`,
  4470. description: `Automatically traps players with wall blocks.`,
  4471. more: {
  4472. html: `
  4473. <p>Should trap: </p>
  4474. <select id="autoTrapOptions" class="btn">
  4475. <option value="pl" selected>Non-party members</option>
  4476. <option value="al">All players</option>
  4477. </select>
  4478. <br><br>
  4479. <span>Each block is always 7x7.</span>
  4480. `,
  4481. functions: () => {}
  4482. },
  4483. },
  4484. rebuild: {
  4485. name: `Auto Rebuild`,
  4486. description: `Automatically rebuilds dead towers and upgrades them.`,
  4487. more: {
  4488. html: `
  4489. <p>Rebuild to tier: </p>
  4490. <select id="rebuilderTierOptions" class="btn">
  4491. <option value="current" selected>Current</option>
  4492. ${[1, 2, 3, 4, 5, 6, 7, 8].map(tier => {
  4493. return `<option value="tier-${tier}">Tier ${tier}</option>`;
  4494. }).join("\n")}
  4495. </select>
  4496. <br><br>
  4497. <span>By behaviour, if the previously destroyed tower has a lower tier than the selected tier, it will be rebuilt to the old tier.</span>
  4498. `,
  4499. functions: () => {
  4500. const tierEnum = {
  4501. 'current': null,
  4502. 'tier-1': 1,
  4503. 'tier-2': 2,
  4504. 'tier-3': 3,
  4505. 'tier-4': 4,
  4506. 'tier-5': 5,
  4507. 'tier-6': 6,
  4508. 'tier-7': 7,
  4509. 'tier-8': 8
  4510. };
  4511. getId("rebuilderTierOptions").onchange = function({target}) {
  4512. game.script.rebuild.shouldRebuildToTier = tierEnum[target.value];
  4513. };
  4514. },
  4515. },
  4516. onCallback: () => {
  4517. for (let i in Game.currentGame.ui.buildings) {
  4518. const building = Game.currentGame.ui.buildings[i];
  4519. game.script.rebuild.savedBase[building.type] ||= {};
  4520. game.script.rebuild.savedBase[building.type][building.x] ||= {};
  4521. game.script.rebuild.savedBase[building.type][building.x][building.y] = building.tier;
  4522. }
  4523. },
  4524. offCallback: () => {
  4525. game.script.rebuild.savedBase = {};
  4526. game.script.rebuild.toBeReplaced = {};
  4527. game.script.rebuild.toBeUpgraded = {};
  4528. },
  4529. },
  4530. autoUpgrade: {
  4531. name: `Auto Upgrader`,
  4532. description: `Automatically upgrades towers to maximum tier.`,
  4533. more: null,
  4534. onCallback: () => {
  4535. for (let building of Object.values(game.ui.buildings)) {
  4536. if (building.tier < 8) {
  4537. game.script.autoUpgrade.autoUpgradeList[building.uid] = true;
  4538. }
  4539. }
  4540. },
  4541. offCallback: () => {
  4542. game.script.autoUpgrade.autoUpgradeList = {};
  4543. }
  4544. },
  4545. AULHT: {
  4546. name: `AULHT`,
  4547. description: `Automatically upgrades low-health towers.`,
  4548. },
  4549. autoBuild: {
  4550. name: "Auto Builder",
  4551. description: `Automatically builds a base when placing stash.`,
  4552. },
  4553. baseSaver: {
  4554. name: "Base Saver",
  4555. description: `Manage all your saved bases here.`,
  4556. more: {
  4557. html: `
  4558. <div id="base-container"></div>
  4559. <div id="base-management" style="display: none;">
  4560. <div id="action-tab">
  4561. <button id="return-to-manager"><i class="fa-solid fa-chevron-left"></i></button>
  4562. <button id="save-config" onclick="window.saveCurrentBaseConfig();"><i class="fa-solid fa-floppy-disk"></i></button>
  4563. <button id="encode-target-design"><i class="fa-solid fa-code"></i></button>
  4564. <button id="view-target-design"><i class="fa-solid fa-eye"></i></button>
  4565. <button id="build-design"><i class="fa-solid fa-hammer"></i></button>
  4566. <button id="clear-target-design"><i class="fa-solid fa-trash-can"></i></button>
  4567. </div>
  4568. <br><h2>Info</h2><hr />
  4569. <input id="target-base-name" type="tel" placeholder="Base name" class="btn" maxlength="20">
  4570. <input id="target-base-description" type="tel" placeholder="Base description" class="btn" maxlength="40">
  4571. <input id="target-base-design" type="tel" placeholder="Base string" class="btn">
  4572. <div id="useful-info"></div>
  4573. <label>
  4574. <input type="checkbox" id="shouldBuildBase">
  4575. <span>Set default for Auto Builder</span>
  4576. </label>
  4577. </div>
  4578. `,
  4579. functions: () => {
  4580. localStorage.totalSlots ||= 2;
  4581. getId("return-to-manager").onclick = () => document.querySelector("#more-baseSaver").click();
  4582. localStorage.baseslot0 = `3,0,-96,0;3,-96,0,0;3,0,-192,0;3,-96,-240,0;3,-192,0,0;3,-240,-96,0;4,-336,-96,0;4,-432,-288,0;4,-96,-336,0;4,-288,-432,0;8,-192,-384,0;8,-384,-192,0;8,-288,-192,0;8,-192,-192,0;8,-192,-288,0;8,-288,-288,0;8,-384,-384,0;8,-96,-96,0;7,-288,0,0;7,-384,0,0;7,-432,-96,0;7,0,-288,0;7,0,-384,0;7,-96,-432,0;0,-168,-504,0;0,-216,-504,0;0,-264,-552,0;0,-312,-552,0;0,-312,-504,0;0,-504,-216,0;0,-504,-168,0;0,-552,-264,0;0,-552,-312,0;0,-504,-312,0;1,-360,-456,0;1,-456,-360,0;9,96,-96,0;9,-96,96,0;|Lucky's 1P corner farm base|Can be changed for current session|default`;
  4583.  
  4584. window.isSlotEmpty = function(index) {
  4585. const baseData = localStorage[`baseslot${index}`]?.split("|");
  4586. return !!baseData?.[0];
  4587. };
  4588.  
  4589. window.createBaseSlot = function() {
  4590. const oldTotalSlots = parseInt(localStorage.totalSlots);
  4591. const nextItem = oldTotalSlots + 1;
  4592. localStorage.totalSlots = nextItem;
  4593. localStorage[`baseslot${nextItem}`] = '|||';
  4594. document.querySelector("#more-baseSaver").click();
  4595. };
  4596.  
  4597. window.saveCurrentBaseConfig = function() {
  4598. const [design, title, description, date] = [...document.querySelectorAll("#target-base-design, #target-base-name, #target-base-description"), new Date().toLocaleDateString()];
  4599. const baseManagement = getId('base-management');
  4600. const currentBaseItem = baseManagement.getAttribute('current-item');
  4601. localStorage[`baseslot${currentBaseItem}`] = `${design.value}|${title.value}|${description.value}|${date}`;
  4602. return void game.ui.components.PopupOverlay.showHint('Current base configuration saved.');
  4603. };
  4604. },
  4605. bind: () => {
  4606. const baseContainer = getId('base-container');
  4607. const baseManagement = getId('base-management');
  4608. baseContainer.innerHTML = '';
  4609. baseManagement.style.display = "none";
  4610.  
  4611. for (let i = 0; i < parseInt(localStorage.totalSlots) + 1; i++) {
  4612. const baseItem = document.createElement('div');
  4613. const baseData = localStorage[`baseslot${i}`]?.split("|");
  4614. const baseId = genUUID();
  4615.  
  4616. baseData?.[1] && (baseData[1] = window.filterXSS(baseData[1]));
  4617. baseData?.[2] && (baseData[2] = window.filterXSS(baseData[2]));
  4618.  
  4619. baseItem.classList.add('base-card');
  4620. baseItem.id = `base-item-${i}`;
  4621. baseItem.setAttribute('item-base', i);
  4622. baseItem.innerHTML = `
  4623. <strong></strong>
  4624. <span style="color: rgba(255, 255, 255, 0.4);font-size: 13px;display: flex;"></span>
  4625. <span style="color: rgba(255, 255, 255, 0.4);font-size: 13px;display: flex;justify-content: flex-end;transform: translate(0px, -40px);"></span>
  4626. `;
  4627.  
  4628. const [title, description, date] = baseItem.children;
  4629. title.innerText = baseData?.[1] || "Unoccupied";
  4630. description.innerText = baseData?.[2] || "-";
  4631. date.innerText = baseData?.[3] || "";
  4632.  
  4633. baseItem.onclick = function() {
  4634. const [titleField, descriptionField, designField] = [...document.querySelectorAll("#target-base-name, #target-base-description, #target-base-design")];
  4635. designField.value = baseData?.[0] || "";
  4636. titleField.value = baseData?.[1] || "";
  4637. descriptionField.value = baseData?.[2] || "";
  4638.  
  4639. getId("encode-target-design").onclick = game.script.builder.recordBase.bind(game.script.builder);
  4640. getId("view-target-design").onclick = () => game.script.builder.showOverlay(designField.value, 10000);
  4641.  
  4642. baseManagement.setAttribute('current-item', i);
  4643. for (let otherItem = 0; otherItem < parseInt(localStorage.totalSlots) + 1; otherItem++) {
  4644. const item = getId(`base-item-${otherItem}`);
  4645. const isThisItem = item.getAttribute('item-base') == i;
  4646. if (isThisItem) continue;
  4647. item.style.display = "none";
  4648. };
  4649.  
  4650. baseItem.style.transform = 'translate(0px, 306px)';
  4651. getId('add-base-slot').style.display = "none";
  4652. baseManagement.style.display = "block";
  4653.  
  4654. getId("build-design").onclick = function() {
  4655. game.ui.components.PopupOverlay.showConfirmation("Are you sure you want to build base?", 5000, function() {
  4656. game.script.builder.buildBase(designField.value);
  4657. });
  4658. };
  4659.  
  4660. const {wood, stone} = game.script.builder.calculateResourceNeeded(designField.value);
  4661. const neededPlayers = game.script.builder.calculateNeededPlayers(designField.value);
  4662. getId("useful-info").innerHTML = `
  4663. <li>Wood: ${wood}</li>
  4664. <li>Needed players: ${neededPlayers}</li>
  4665. <li>Stone: ${stone}</li>
  4666. `;
  4667.  
  4668. const autoBuildElem = getId("shouldBuildBase");
  4669. autoBuildElem.checked = sessionStorage[`base-item-${i}`] && sessionStorage[`base-item-${i}`] == "true";
  4670. autoBuildElem.onchange = function() {
  4671. if (autoBuildElem.checked == true) {
  4672. for (let otherItem = 0; otherItem < parseInt(localStorage.totalSlots) + 1; otherItem++) sessionStorage[`base-item-${otherItem}`] = false;
  4673. sessionStorage[`base-item-${i}`] = true;
  4674. game.script.autoBuild.defaultBase = designField.value;
  4675. }
  4676. };
  4677. };
  4678. baseContainer.appendChild(baseItem);
  4679. }
  4680. const addItem = document.createElement('div');
  4681. addItem.classList.add('base-card');
  4682. addItem.id = "add-base-slot";
  4683. addItem.innerHTML = `
  4684. <strong style="position: absolute;top: 20px;left: 40px;opacity: 0.4;"><i class="fas fa-plus"></i></strong>
  4685. <span style="color: rgba(255, 255, 255, 0.4);display: flex;justify-content: flex-end;position: absolute;left: 65px;top: 20px;">Add another base slot</span>
  4686. `;
  4687. addItem.onclick = window.createBaseSlot;
  4688. baseContainer.appendChild(addItem);
  4689. },
  4690. },
  4691. },
  4692. },
  4693. page1: {
  4694. autoAim: {
  4695. name: "Auto Aim",
  4696. description: "Automate attacks against enemies.",
  4697. more: {
  4698. html: `
  4699. <p>Aim for: </p>
  4700. <select id="autoAimOptions">
  4701. <option value="player" selected>Players</option>
  4702. <option value="zombie">Zombies</option>
  4703. <option value="zom/dem">Zombies/Demons</option>
  4704. <option value="all">All</option>
  4705. </select>
  4706. `,
  4707. },
  4708. },
  4709. autoHeal: {
  4710. name: "Auto Heal",
  4711. description: "Heals your player/pet automatically.",
  4712. more: {
  4713. html: `
  4714. <strong>Define the health percentage where the Auto Heal will kick in.</strong>
  4715. <span>Default value is 15%.</span>
  4716. <input id="auto-heal-threshold" type="number" placeholder="Enter a valid percentile here..." min="1" max="100" value="15" />
  4717. `,
  4718. functions: () => {},
  4719. }
  4720. },
  4721. autoRespawn: {
  4722. name: "Auto Respawn",
  4723. description: "Automatically respawns player upon death.",
  4724. },
  4725. spam: {
  4726. name: `Chat Spam`,
  4727. description: `Annoys other players with messages.`,
  4728. more: {
  4729. html: `
  4730. <strong>Input the text that you want to spam.</strong>
  4731. <span>If no text is inputted, random messages with be sent.</span>
  4732. <input id="chat-spam-input" placeholder="Spam text here..." />
  4733. `,
  4734. functions: () => {
  4735. const spamInputElem = getId("chat-spam-input");
  4736. spamInputElem.oninput = game.script.spam.onchange.bind(game.script.spam);
  4737. }
  4738. },
  4739. onCallback: () => { game.script.spam.start(); },
  4740. offCallback: () => { game.script.spam.stop(); },
  4741. },
  4742. movementCopy: {
  4743. name: `Movement Copy`,
  4744. description: `Copies the closest player's movement.`,
  4745. more: null,
  4746. offCallback: () => {
  4747. game.script.movementCopy.target = null;
  4748. },
  4749. },
  4750. },
  4751. page2: {
  4752. sessions: {
  4753. name: "Session Saver",
  4754. description: "Switch sockets on the fly.",
  4755. more: {
  4756. html: `
  4757. <div class="more-title">
  4758. <h2>Manage</h2>
  4759. <button id="refresh-ses" style="background: none;box-shadow: unset;border: 0px;color: white;cursor: pointer;"><i class="fa-solid fa-arrows-rotate"></i></button>
  4760. </div>
  4761. <div id="switch-ses">
  4762. <button id="switch-btn"><i class="fa-solid fa-repeat"></i></button>
  4763. </div>
  4764. `,
  4765. functions: () => {
  4766. let isInit = false;
  4767. game.network.addEnterWorldHandler(() => {
  4768. if (isInit) return;
  4769. isInit = true;
  4770.  
  4771. getId("switch-ses").insertBefore(getId("sesSelect"), getId("switch-btn"));
  4772. getId("switch-ses").insertAdjacentElement("afterend", getId("addBtn"));
  4773. getId("switch-ses").insertAdjacentElement("afterend", getId("delBtn"));
  4774. getId("switch-ses").insertAdjacentHTML("afterend", `<br>`);
  4775.  
  4776. getId("sesSelect").style.display = "block";
  4777. getId("delBtn").style.display = "inline-block";
  4778. getId("addBtn").style.display = "inline-block";
  4779. });
  4780. getId("refresh-ses").onclick = () => game.script.sessions.fetchSessions();
  4781. getId("switch-btn").onclick = () => {
  4782. if (!getId("useSes").checked) {
  4783. getId("useSes").checked = true;
  4784. getId("useSes").onchange();
  4785. };
  4786.  
  4787. game.network.disconnect();
  4788. game.network.connect();
  4789. };
  4790. },
  4791. },
  4792. },
  4793. cloneSockets: {
  4794. name: "Clones",
  4795. description: "Otherwise known as sockets, alts, etc.",
  4796. more: {
  4797. html: `
  4798. <div class="more-title">
  4799. <div id="socket-info">
  4800. <h2>Status</h2>
  4801. <span id="clone-amount">0 active</span>
  4802. </div>
  4803. <button id="toggle-status" style="background: none;box-shadow: unset;border: 0px;color: white;cursor: pointer;"><i class="fa-solid fa-chevron-up"></i></button>
  4804. </div>
  4805. <div id="clone-status" style="display: block;"><span>Nothing here yet...</span></div>
  4806.  
  4807. <div class="more-title"><h2>General</h2></div>
  4808. <div id="general-control">
  4809. <button id="control-delete-all" style="border-bottom: 2px solid red;">Delete all</button>
  4810. </div>
  4811. <label>
  4812. <input type="checkbox" id="alt-useProxy">
  4813. <span>Use proxies (if available)</span>
  4814. </label>
  4815. <label>
  4816. <input type="checkbox" id="alt-autoFill">
  4817. <span>Auto fill server</span>
  4818. </label>
  4819. <label>
  4820. <input type="checkbox" id="alt-randomizeName" checked>
  4821. <span>Use randomized names</span>
  4822. </label>
  4823. <p>Default socket type: </p>
  4824. <select id="socketTypeOptions" class="btn">
  4825. <option value="Multibox">Multibox</option>
  4826. <option value="Filler">Filler</option>
  4827. <option value="PlayerTrick">Player Trick</option>
  4828. <option value="AITO">AITO</option>
  4829. </select>
  4830. <div class="more-title"><h2>Multibox</h2></div>
  4831. <div id="multibox-control">
  4832. <button id="multibox-set-default" style="border-bottom: 3px solid deepskyblue;">Set all to default type</button>
  4833. </div>
  4834. <label>
  4835. <input type="checkbox" id="alt-control" checked>
  4836. <span>Control clones</span>
  4837. </label>
  4838. <p>Default movement type: </p>
  4839. <select id="movementTypeOptions" class="btn">
  4840. <option value="0">Copy</option>
  4841. <option value="1" selected>Mouse</option>
  4842. <option value="2">Lock</option>
  4843. <option value="3">Player</option>
  4844. </select>
  4845. `,
  4846. functions: () => {
  4847. getId("toggle-status").onclick = () => {
  4848. const cloneStatus = getId("clone-status");
  4849. getId("toggle-status").innerHTML = `<i class="fa-solid fa-chevron-${cloneStatus.style.display === "none" ? "up" : "down"}"></i>`;
  4850. cloneStatus.style.display = cloneStatus.style.display === "none" ? "block" : "none";
  4851. };
  4852. const observer = new MutationObserver((mutationsList) => {
  4853. for (const mutation of mutationsList) {
  4854. if (mutation.type == 'childList') {
  4855. getId("clone-status").firstChild.localName == "span" && getId("clone-status").removeChild(getId("clone-status").firstChild);
  4856. };
  4857. };
  4858. });
  4859. observer.observe(getId("clone-status"), { attributes: true, childList: true, subtree: true });
  4860.  
  4861. for (const option in game.script.sockets.shared.options) {
  4862. const toggleElem = getId("alt-" + option);
  4863. toggleElem.addEventListener("change", ({target}) => {
  4864. if (target.checked) {
  4865. game.script.sockets.shared.options[option].enabled = true;
  4866. game.script.sockets.shared.options[option]?.onCallback?.();
  4867. } else {
  4868. game.script.sockets.shared.options[option].enabled = false;
  4869. game.script.sockets.shared.options[option]?.offCallback?.();
  4870. };
  4871. });
  4872. }
  4873.  
  4874. getId("control-delete-all").onclick = () => {
  4875. game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all clones?`, 5000, function() {
  4876. for (let uuid in game.script.sockets.shared.all) {
  4877. game.script.sockets.shared.all[uuid].ws.readyState != 3 && game.script.sockets.shared.all[uuid].ws.close();
  4878. };
  4879. });
  4880. };
  4881. getId("multibox-set-default").onclick = () => {
  4882. for (let uuid in game.script.sockets.shared.all) {
  4883. game.script.sockets.shared.all[uuid].switchType(getId("socketTypeOptions").value);
  4884. };
  4885. };
  4886.  
  4887. getId("movementTypeOptions").onchange = ({target}) => {
  4888. for (const uuid in game.script.sockets.shared.all) {
  4889. const socket = game.script.sockets.shared.all[uuid];
  4890. if (socket.typeSpecificVariables.overrides && !socket.typeSpecificVariables.overrides.autoMove) {
  4891. socket.typeSpecificVariables.autoMove = parseInt(target.value);
  4892. };
  4893. };
  4894. };
  4895. },
  4896. },
  4897. isToggle: false,
  4898. customButtonText: "Send",
  4899. callback: () => {
  4900. const type = getId("socketTypeOptions").value;
  4901. game.script.sockets.createSocket(type);
  4902. },
  4903. },
  4904. },
  4905. page3: {
  4906. optimize: {
  4907. name: "Optimizers",
  4908. description: "Disables rendering features for better performance.",
  4909. more: {
  4910. html: `
  4911. <h2>Sprite refreshing</h2>
  4912. <label>
  4913. <input type="checkbox" id="zombieSprite" checked>
  4914. <span>Zombie sprites</span>
  4915. </label>
  4916. <label>
  4917. <input type="checkbox" id="towerSprite" checked>
  4918. <span>Tower sprites</span>
  4919. </label>
  4920. <label>
  4921. <input type="checkbox" id="projectileSprite" checked>
  4922. <span>Projectile sprites</span>
  4923. </label>
  4924. <h2>Other</h2>
  4925. <label>
  4926. <input type="checkbox" id="updateAnimation" checked>
  4927. <span>Update entity models</span>
  4928. </label>
  4929. `,
  4930. functions: () => {
  4931. for (const option in game.script.optimize) {
  4932. if (["background", "init"].indexOf(option) > -1) continue;
  4933. getId(option).addEventListener("change", ({target}) => {
  4934. game.script.optimize[option] = target.checked;
  4935. });
  4936. }
  4937. }
  4938. },
  4939. },
  4940. showAoe: {
  4941. name: "AOE Map",
  4942. description: "Shows the area of damage for all AOE towers.",
  4943. more: null,
  4944. },
  4945. stashIndicators: {
  4946. name: "Stash Indicators",
  4947. description: "Shows useful borders Gold Stash-related.",
  4948. more: null,
  4949. onCallback: () => {
  4950. const { indicators } = game.script.stashIndicators.currentIndicators;
  4951. for (const indicator of indicators) indicator.setVisible(true);
  4952. },
  4953. offCallback: () => {
  4954. const { indicators } = game.script.stashIndicators.currentIndicators;
  4955. for (const indicator of indicators) indicator.setVisible(false);
  4956. },
  4957. },
  4958. buildingLife: {
  4959. name: "Building Lifetime",
  4960. description: "Shows a heat map indicating buildings' lifespan.",
  4961. more: {
  4962. html: `
  4963. <strong>Limit the amount of towers to be indicated via heat map</strong>
  4964. <span>counting from most recently placed towers</span>
  4965. <div id="heat-range">
  4966. <input type="number" id="heat-min" min="0" value="0" disabled />
  4967. <input type="range" id="heat-slider" step="1" min="0" max="0" />
  4968. <input type="number" id="heat-max" min="0" value="0" disabled />
  4969. </div>
  4970. <div id="scene-alpha-range">
  4971. <input type="number" id="scene-alpha-val" value="0.5" disabled />
  4972. <input type="range" id="scene-alpha-slider" step="0.1" min="0" max="1" />
  4973. </div>
  4974. `,
  4975. functions: () => {
  4976. getId("heat-slider").addEventListener("input", ({target}) => {
  4977. game.script.buildingLife.startingIndex = target.valueAsNumber;
  4978. getId("heat-min").value = target.valueAsNumber;
  4979.  
  4980. clearTimeout(game.script.buildingLife.refreshTimeout);
  4981. game.script.buildingLife.refreshTimeout = setTimeout(() => {
  4982. game.script.buildingLife.refreshMap();
  4983. game.options.options.buildingLife && (
  4984. game.script.buildingLife.hideMap(),
  4985. game.script.buildingLife.showMap()
  4986. );
  4987. }, 50);
  4988. });
  4989. getId("scene-alpha-slider").addEventListener("input", ({target}) => {
  4990. getId("scene-alpha-val").value = target.valueAsNumber;
  4991. game.script.buildingLife.setSceneryAlpha(target.valueAsNumber);
  4992. });
  4993. },
  4994. },
  4995. onCallback: () => { game.script.buildingLife.showMap(); },
  4996. offCallback: () => { game.script.buildingLife.hideMap(); },
  4997. },
  4998. grouping: {
  4999. name: "Grouping Grid",
  5000. description: "Shows the grids of tower ranges' groups.",
  5001. more: null,
  5002. isToggle: false,
  5003. customButtonText: "Cycle",
  5004. callback: () => {
  5005. game.script.grouping.cycleGrid();
  5006. },
  5007. },
  5008. bossAlert: {
  5009. name: "Boss Alert",
  5010. description: "Alerts you before a boss wave.",
  5011. more: null,
  5012. },
  5013. },
  5014. page4: {},
  5015. };
  5016.  
  5017. const addFunctionToElem = ({ id, option, buttonText, colors, isToggle, isCheckBox, callback, onCallback, offCallback }) => {
  5018. const options = game.options.options;
  5019. colors ||= 'btn-red?btn-theme';
  5020.  
  5021. if (isCheckBox) {
  5022. getId(id).addEventListener('change', e => {
  5023. if (options[option].multibox === false) {
  5024. options[option].multibox = true;
  5025. onCallback?.();
  5026. } else {
  5027. options[option].multibox = false;
  5028. offCallback?.();
  5029. };
  5030. });
  5031. return;
  5032. };
  5033.  
  5034. getId(id).addEventListener('click', e => {
  5035. if (isToggle === false) {
  5036. callback?.();
  5037. } else {
  5038. let toggleColor = colors.split('?');
  5039. if (typeof options[option] == "object") {
  5040. if (options[option].enabled === false) {
  5041. options[option].enabled = true;
  5042. toggleColor[1] && e.target.classList.remove(toggleColor[1]);
  5043. e.target.classList.add(toggleColor[0]);
  5044. buttonText === undefined || (e.target.innerText = `Disable ${buttonText}`);
  5045. onCallback?.();
  5046. } else {
  5047. options[option].enabled = false;
  5048. e.target.classList.remove(toggleColor[0]);
  5049. toggleColor[1] && e.target.classList.add(toggleColor[1]);
  5050. buttonText === undefined || (e.target.innerText = `Enable ${buttonText}`);
  5051. offCallback?.();
  5052. };
  5053. } else {
  5054. if (options[option] === false) {
  5055. options[option] = true;
  5056. toggleColor[1] && e.target.classList.remove(toggleColor[1]);
  5057. e.target.classList.add(toggleColor[0]);
  5058. buttonText === undefined || (e.target.innerText = `Disable ${buttonText}`);
  5059. onCallback?.();
  5060. } else {
  5061. options[option] = false;
  5062. e.target.classList.remove(toggleColor[0]);
  5063. toggleColor[1] && e.target.classList.add(toggleColor[1]);
  5064. buttonText === undefined || (e.target.innerText = `Enable ${buttonText}`);
  5065. offCallback?.();
  5066. }
  5067. };
  5068. };
  5069. });
  5070. };
  5071.  
  5072. /* @GeneralFunctions + Enums */
  5073. const towerCodes = ["Wall", "Door", "SlowTrap", "ArrowTower", "CannonTower", "MeleeTower", "BombTower", "MagicTower", "GoldMine", "Harvester"];
  5074. const allBossWaves = [9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 121];
  5075.  
  5076. function bindTooltip(elem, innerHTML, anchor = 'top') {
  5077. elem.targetElem = elem;
  5078. elem.anchor = anchor;
  5079. elem.hide = function() { this.tooltipElem && (this.tooltipElem.remove(), delete this.tooltipElem); };
  5080. elem.targetElem.addEventListener('mouseenter', function() {
  5081. let toolTip = innerHTML;
  5082. document.body.insertAdjacentHTML(`beforeend`, toolTip);
  5083. this.tooltipElem = document.getElementById(`hud-tooltip`);
  5084.  
  5085. let clientRect = this.targetElem.getBoundingClientRect();
  5086. let position = {'left': 0, 'top': 0};
  5087. switch(this.anchor) {
  5088. case 'top':
  5089. position.left = clientRect.left + clientRect.width / 0x2 - this.tooltipElem.offsetWidth / 0x2;
  5090. position.top = clientRect.top - this.tooltipElem.offsetHeight - 0x14;
  5091. break;
  5092. case 'bottom':
  5093. position.left = clientRect.left + clientRect.width / 0x2 - this.tooltipElem.offsetWidth / 0x2;
  5094. position.top = clientRect.top + clientRect.height + 0x14;
  5095. break;
  5096. case 'left':
  5097. position.left = clientRect.left - this.tooltipElem.offsetWidth - 0x14;
  5098. position.top = clientRect.top + clientRect.height / 0x2 - this.tooltipElem.offsetHeight / 0x2;
  5099. break;
  5100. case 'right':
  5101. position.left = clientRect.left + clientRect.width + 0x14;
  5102. position.top = clientRect.top + clientRect.height / 0x2 - this.tooltipElem.offsetHeight / 0x2;
  5103. break;
  5104. }
  5105. this.tooltipElem.className = `hud-tooltip hud-tooltip-` + this.anchor;
  5106. this.tooltipElem.style.left = position.left + 'px';
  5107. this.tooltipElem.style.top = position.top + 'px';
  5108. this.tooltipElem.style.zIndex = "999";
  5109. });
  5110. elem.targetElem.addEventListener(`mouseleave`, elem.hide);
  5111. }
  5112.  
  5113. function inRange(pos, target, range) {
  5114. return pos < target + range && pos > target - range;
  5115. }
  5116.  
  5117. function getRandomArbitrary(min, max) {
  5118. return Math.random() * (max - min) + min;
  5119. }
  5120.  
  5121. function isPointInCircle(circle, point, radius) {
  5122. if ((point.x - circle.x)**2 + (point.y - circle.y)**2 <= radius**2) return true;
  5123. return false;
  5124. }
  5125.  
  5126. function genUUID() {
  5127. if (crypto?.randomUUID) {
  5128. return crypto.randomUUID();
  5129. } else {
  5130. return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(
  5131. /[018]/g, c => (
  5132. c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4
  5133. ).toString(16)
  5134. );
  5135. };
  5136. };
  5137.  
  5138. function getRandomItem(array) {
  5139. return array[Math.floor(Math.random() * array.length)];
  5140. };
  5141.  
  5142. function msToTime(s) {
  5143.  
  5144. // Pad to 2 or 3 digits, default is 2
  5145. function pad(n, z) {
  5146. z = z || 2;
  5147. return ('00' + n).slice(-z);
  5148. }
  5149.  
  5150. var ms = s % 1000;
  5151. s = (s - ms) / 1000;
  5152. var secs = s % 60;
  5153. s = (s - secs) / 60;
  5154. var mins = s % 60;
  5155. var hrs = (s - mins) / 60;
  5156.  
  5157. return pad(hrs) + ':' + pad(mins) + ':' + pad(secs) + '.' + pad(ms, 3);
  5158. }
  5159.  
  5160. function hexToRgb(hex) {
  5161. var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  5162. if(result){
  5163. var r= parseInt(result[1], 16);
  5164. var g= parseInt(result[2], 16);
  5165. var b= parseInt(result[3], 16);
  5166. return [r, g, b];
  5167. }
  5168. return null;
  5169. };
  5170.  
  5171. function shuffleArray(array) {
  5172. for (let i = array.length - 1; i > 0; i--) {
  5173. const j = Math.floor(Math.random() * (i + 1));
  5174. const temp = array[i];
  5175. array[i] = array[j];
  5176. array[j] = temp;
  5177. };
  5178. return array;
  5179. }
  5180.  
  5181. function garbageGenerator(garbageLength = 25) {
  5182. let garbageCharacters = localStorage.literallyEveryUnicodeEver;
  5183. let garbage = "";
  5184. for (let i = 0; i < garbageLength; i++) garbage += garbageCharacters[Math.floor(Math.random() * garbageCharacters.length)];
  5185. return garbage;
  5186. }
  5187.  
  5188. function counter(e = 0) {
  5189. if (e <= -0.99949999999999999e24) {
  5190. return Math.round(e/-1e23)/-10 + "TT";
  5191. }
  5192. if (e <= -0.99949999999999999e21) {
  5193. return Math.round(e/-1e20)/-10 + "TB";
  5194. }
  5195. if (e <= -0.99949999999999999e18) {
  5196. return Math.round(e/-1e17)/-10 + "TM";
  5197. }
  5198. if (e <= -0.99949999999999999e15) {
  5199. return Math.round(e/-1e14)/-10 + "TK";
  5200. }
  5201. if (e <= -0.99949999999999999e12) {
  5202. return Math.round(e/-1e11)/-10 + "T";
  5203. }
  5204. if (e <= -0.99949999999999999e9) {
  5205. return Math.round(e/-1e8)/-10 + "B";
  5206. }
  5207. if (e <= -0.99949999999999999e6) {
  5208. return Math.round(e/-1e5)/-10 + "M";
  5209. }
  5210. if (e <= -0.99949999999999999e3) {
  5211. return Math.round(e/-1e2)/-10 + "K";
  5212. }
  5213. if (e <= 0.99949999999999999e3) {
  5214. return Math.round(e) + "";
  5215. }
  5216. if (e <= 0.99949999999999999e6) {
  5217. return Math.round(e/1e2)/10 + "K";
  5218. }
  5219. if (e <= 0.99949999999999999e9) {
  5220. return Math.round(e/1e5)/10 + "M";
  5221. }
  5222. if (e <= 0.99949999999999999e12) {
  5223. return Math.round(e/1e8)/10 + "B";
  5224. }
  5225. if (e <= 0.99949999999999999e15) {
  5226. return Math.round(e/1e11)/10 + "T";
  5227. }
  5228. if (e <= 0.99949999999999999e18) {
  5229. return Math.round(e/1e14)/10 + "TK";
  5230. }
  5231. if (e <= 0.99949999999999999e21) {
  5232. return Math.round(e/1e17)/10 + "TM";
  5233. }
  5234. if (e <= 0.99949999999999999e24) {
  5235. return Math.round(e/1e20)/10 + "TB";
  5236. }
  5237. if (e <= 0.99949999999999999e27) {
  5238. return Math.round(e/1e+23)/10 + "TT";
  5239. }
  5240. if (e >= 0.99949999999999999e27) {
  5241. return Math.round(e/1e+23)/10 + "TT";
  5242. }
  5243. }
  5244.  
  5245. const getClock = (_date) => {
  5246. let date = _date || new Date(),
  5247. d = date.getDate(),
  5248. d1 = date.getDay(),
  5249. h = date.getHours(),
  5250. m = date.getMinutes(),
  5251. s = date.getSeconds(),
  5252. session = "PM";
  5253.  
  5254. if (h == 2) h = 12;
  5255.  
  5256. if (h < 13) session = "AM"
  5257. if (h > 12) {
  5258. session = "PM";
  5259. h -= 12;
  5260. };
  5261.  
  5262. h = (h < 10) ? "0" + h : h;
  5263. m = (m < 10) ? "0" + m : m;
  5264. s = (s < 10) ? "0" + s : s;
  5265. return `${h}:${m} ${session}`;
  5266. }
  5267.  
  5268. const measureDistance = (obj1, obj2) => {
  5269. if (!(obj1.x && obj1.y && obj2.x && obj2.y)) return Infinity;
  5270. let xDif = obj2.x - obj1.x;
  5271. let yDif = obj2.y - obj1.y;
  5272. return Math.abs((xDif**2) + (yDif**2));
  5273. };
  5274.  
  5275. const getEntityAtPos = (x, y, width = 1, height = 1) => {
  5276. const cell = game.world.entityGrid.getCellIndexes(x, y, { width, height });
  5277. return game.world.entityGrid.getEntitiesInCell(cell);
  5278. }
  5279.  
  5280. const isEntityOccupied = (x, y, width = 1, height = 1) => {
  5281. const cell = game.world.entityGrid.getCellIndexes(x, y, { width, height });
  5282. const entity = game.world.entityGrid.getEntitiesInCell(cell);
  5283. return Object.keys(entity).length > 0;
  5284. }
  5285.  
  5286. const canAfford = (resources, costs, tier) => {
  5287. const { gold, wood, stone } = resources;
  5288. const goldCosts = costs.goldCosts[tier - 1];
  5289. const stoneCosts = costs.stoneCosts[tier - 1];
  5290. const woodCosts = costs.woodCosts[tier - 1];
  5291. return !(gold < goldCosts || wood < woodCosts || stone < stoneCosts);
  5292. }
  5293.  
  5294. const predictDirection = (lastPos, currentPos, acc = 2) => {
  5295. const anchors = {up: 0, down: 0, left: 0, right: 0};
  5296. if (!lastPos || !currentPos) return anchors;
  5297. if (acc > 100) acc = 100;
  5298. // limitation might be position changes in the slightest
  5299. // rounding numbers may help
  5300. const xDelta = lastPos.x - currentPos.x;
  5301. const yDelta = lastPos.y - currentPos.y;
  5302. xDelta < -acc ? (anchors.right = 1) : xDelta > acc && (anchors.left = 1);
  5303. yDelta < -acc ? (anchors.down = 1) : yDelta > acc && (anchors.up = 1);
  5304. return anchors;
  5305. };
  5306.  
  5307. const moveTowards = (a, b, acc = 24) => {
  5308. const packet = {down: 0, up: 0, left: 0, right: 0};
  5309.  
  5310. if (a.y - b.y <= acc) packet.down = 1;
  5311. if (-a.y + b.y <= acc) packet.up = 1;
  5312. if (-a.x + b.x <= acc) packet.left = 1;
  5313. if (a.x - b.x <= acc) packet.right = 1;
  5314.  
  5315. return packet;
  5316. };
  5317.  
  5318. function getIsNextWaveActive() {
  5319. let isNextWaveActive = false;
  5320. const allComingBossWaves = allBossWaves.map(wave => wave - 1);
  5321. for (let wave of allComingBossWaves) {
  5322. isNextWaveActive = game.ui.playerTick.wave == wave;
  5323. }
  5324. return isNextWaveActive;
  5325. };
  5326.  
  5327. class EventEmitter extends EventTarget {
  5328. constructor() {
  5329. super();
  5330. this._events = {};
  5331. };
  5332. on(event, callback, options) {
  5333. this._events[event] ||= [];
  5334. this._events[event].push(callback);
  5335. this.addEventListener(event, ({detail: data}) => {
  5336. callback(data);
  5337. }, options);
  5338. };
  5339. once(event, callback) {
  5340. this.on(event, callback, {once: true});
  5341. };
  5342. emit(event, data) {
  5343. const Event = new CustomEvent(event, { detail: data });
  5344. this.dispatchEvent(Event);
  5345. };
  5346. };
  5347.  
  5348. /* @CustomFunctions */
  5349. game.options.options = {
  5350. AHRC: {
  5351. enabled: false,
  5352. multibox: true,
  5353. },
  5354. wallBlock: false,
  5355. rebuild: false,
  5356. autoTrap: false,
  5357. autoUpgrade: false,
  5358. AULHT: false,
  5359. autoBuild: false,
  5360. dragBox: false,
  5361.  
  5362. lockAim: false,
  5363. movementCopy: false,
  5364. spam: false,
  5365. autoHeal: {
  5366. enabled: true,
  5367. multibox: true,
  5368. },
  5369. getRSS: false,
  5370. autoBow: false,
  5371. autoAim: false,
  5372. autoRespawn: false,
  5373.  
  5374. showAoe: false,
  5375. stashIndicators: false,
  5376. buildingLife: false,
  5377. bossAlert: true,
  5378.  
  5379. spectate: false,
  5380. navigator: false,
  5381. XKey: false,
  5382. };
  5383.  
  5384. game.script = {
  5385. AHRC: {
  5386. handlers: [{type: "entityUpdate", names: "onTick"}],
  5387. checkedHarvesters: new Set(),
  5388. workingHarvesters: new Set(),
  5389. excludedHarvesters: new Set(),
  5390. onTick: function() {
  5391. const options = game.options.options;
  5392. if (options.AHRC.enabled) {
  5393. for (let uid in game.world.entities) {
  5394. if (this.excludedHarvesters.has(parseInt(uid))) continue;
  5395. const entity = game.world.entities[uid];
  5396. if (entity.targetTick.model == "Harvester" && entity.targetTick.partyId == game.ui.playerPartyId && game.ui.playerTick.gold > 0.69) {
  5397. if (this.checkedHarvesters.has(uid)) {
  5398. if (entity.targetTick.stone != 0 || entity.targetTick.wood != 0) this.workingHarvesters.add(uid);
  5399. } else {
  5400. this.checkedHarvesters.add(uid);
  5401. game.network.sendRpc({
  5402. name: "AddDepositToHarvester",
  5403. uid: parseInt(uid),
  5404. deposit: 0.69
  5405. });
  5406. };
  5407. };
  5408. if (this.workingHarvesters.has(uid)) {
  5409. if (entity.targetTick.stone >= entity.targetTick.harvestMax || entity.targetTick.wood >= entity.targetTick.harvestMax) continue;
  5410. const amount = entity.fromTick.tier * 0.05 - 0.02;
  5411. const ahrcOptions = getId('ahrcOptions');
  5412. ahrcOptions.value !== "c" && game.network.sendRpc({name: "AddDepositToHarvester", uid: parseInt(uid), deposit: amount});
  5413. ahrcOptions.value !== "h" && game.network.sendRpc({name: "CollectHarvester", uid: parseInt(uid)});
  5414. };
  5415. };
  5416. };
  5417. },
  5418. },
  5419. wallBlock: {
  5420. handlers: [{type: "packetFunc", names: ["sendRpc", "onSendRpc", 9]}, {type: "keybind", names: "keyup"}],
  5421. wallElem: document.createElement("a"),
  5422. typeOfDefense: "Wall",
  5423. isEven: function(number) {
  5424. return number % 2 === 0;
  5425. },
  5426. placeWallBlock: function(blockWidth, blockHeight, data, offset) {
  5427. let offsetFromTarget,
  5428. isOffsetUsed = !!offset;
  5429. isOffsetUsed && (offsetFromTarget = 48 * offset);
  5430. for (let x =
  5431. -((blockWidth -
  5432. (this.isEven(blockWidth) ? 0 : 1)) / 2) * 48;
  5433. x <= (blockWidth -
  5434. (this.isEven(blockWidth) ? 0 : 1)) / 2 * 48;
  5435. x += 48) {
  5436. // if (isOffsetUsed && (Math.abs(x) <= offsetFromTarget)) continue;
  5437. for (let y =
  5438. -((blockHeight -
  5439. (this.isEven(blockHeight) ? 0 : 1)) / 2) * 48;
  5440. y <= (blockHeight -
  5441. (this.isEven(blockHeight) ? 0 : 1)) / 2 * 48;
  5442. y += 48) {
  5443. if (isOffsetUsed && Math.abs(y) <= offsetFromTarget && Math.abs(x) <= offsetFromTarget) continue;
  5444. const posX = data.x + x,
  5445. posY = data.y + y,
  5446. shouldPlace = !isEntityOccupied(posX, posY);
  5447. shouldPlace && (x !== 0 || y !== 0) && game.network.sendPacket(9, {name: "MakeBuilding", type: this.typeOfDefense, x: posX, y: posY, yaw: 0});
  5448. };
  5449. };
  5450. },
  5451. onSendRpc: function(data) {
  5452. if (data.name === "MakeBuilding" && data.type === this.typeOfDefense && game.options.options.wallBlock) {
  5453. if (!game.script.rebuild.savedBase?.[data.type]?.[data.x]?.[data.y]) {
  5454. const blockWidth = parseInt(document.querySelector('#blockX').value);
  5455. const blockHeight = parseInt(document.querySelector('#blockY').value);
  5456. this.placeWallBlock(blockWidth, blockHeight, data);
  5457. };
  5458. };
  5459. },
  5460. keyup: function(e) {
  5461. if (e.key == "!") getId("toggle-wallBlock").click();
  5462. },
  5463. init: function() {
  5464. this.wallElem.classList.add("hud-buff-bar-item");
  5465. this.wallElem.setAttribute("data-building", "Wall");
  5466. this.wallElem.style.display = "none";
  5467. this.wallElem.setAttribute("data-tier", `${getId("blockX").value}x${getId("blockY").value}`);
  5468. document.getElementsByClassName("hud-buff-bar")[0].appendChild(this.wallElem);
  5469. },
  5470. },
  5471. autoTrap: {
  5472. handlers: [{type: "entityUpdate", names: "onEntityUpdate"}],
  5473. onEntityUpdate: function() {
  5474. if (game.options.options.diep) {
  5475. for (let i of game.renderer.npcs.attachments) {
  5476. const criteria = document.querySelector("#autoTrapOptions").value == "pl" ? i.targetTick.partyId !== game.ui.playerPartyId : i.targetTick.uid !== game.world.myUid;
  5477. if (i.entityClass === "PlayerEntity" && criteria) {
  5478. if (isPointInCircle(i.targetTick.position, game.ui.playerTick.position, 500)) {
  5479. const position = i.targetTick.position;
  5480. const data = { x: Math.round(position.x / 24) * 24, y: Math.round(position.y / 24) * 24 };
  5481. game.script.wallBlock.placeWallBlock(7, 7, data, 1);
  5482. };
  5483. };
  5484. };
  5485. };
  5486. },
  5487. },
  5488. rebuild: {
  5489. handlers: [{type: "entityUpdate", names: "onEntityUpdate"}, {type: "rpc", names: ["LocalBuilding"]}, {type: "keybind", names: "keyup"}],
  5490. goldStashTier: null,
  5491. savedBase: {},
  5492. toBeReplaced: {},
  5493. toBeUpgraded: {},
  5494. shouldRebuildToTier: null,
  5495. LocalBuilding: function(buildings) {
  5496. const options = game.options.options;
  5497. const allBuildings = Object.values(Game.currentGame.ui.buildings);
  5498. this.goldStashTier = game.ui.components.BuildingOverlay.getGoldStashTier();
  5499.  
  5500. if (options.rebuild) {
  5501. for (let i in buildings) {
  5502. const building = buildings[i];
  5503. if (building.dead === 1) {
  5504. // The building has died
  5505. if (this.savedBase[building.type]?.[building.x]?.[building.y]) {
  5506. this.toBeReplaced[building.type] ||= {};
  5507. this.toBeReplaced[building.type][building.x] ||= {};
  5508. this.toBeReplaced[building.type][building.x][building.y] = true;
  5509. delete this.toBeUpgraded[building.uid];
  5510. }
  5511. } else {
  5512. // The building was upgraded/placed
  5513. if (this.savedBase[building.type]?.[building.x]?.[building.y] !== undefined) {
  5514. if (typeof this.toBeUpgraded[building.uid] === "number" && this.toBeUpgraded[building.uid] <= 1) {
  5515. this.toBeUpgraded[building.uid] = false;
  5516. } else if (this.toBeUpgraded[building.uid] === undefined) {
  5517. if (this.shouldRebuildToTier !== null && this.savedBase[building.type][building.x][building.y] > this.shouldRebuildToTier) {
  5518. this.toBeUpgraded[building.uid] = this.shouldRebuildToTier;
  5519. } else if (building.tier < this.savedBase[building.type][building.x][building.y]) {
  5520. this.toBeUpgraded[building.uid] = this.savedBase[building.type][building.x][building.y];
  5521. };
  5522. };
  5523. delete this.toBeReplaced[building.type]?.[building.x]?.[building.y];
  5524. }
  5525. }
  5526. }
  5527. }
  5528. },
  5529. onEntityUpdate: function({ entities }) {
  5530. const options = game.options.options;
  5531. if (options.rebuild && this.goldStashTier) {
  5532. for (let i in this.toBeReplaced) {
  5533. for (let x in this.toBeReplaced[i]) {
  5534. for (let y in this.toBeReplaced[i][x]) {
  5535. Game.currentGame.network.sendRpc({
  5536. name: "MakeBuilding",
  5537. type: i,
  5538. x: parseInt(x),
  5539. y: parseInt(y),
  5540. yaw: 0
  5541. });
  5542. }
  5543. }
  5544. }
  5545. for (let uid in this.toBeUpgraded) {
  5546. if (!(uid in entities)) {
  5547. delete this.toBeUpgraded[uid];
  5548. continue;
  5549. };
  5550. if (this.toBeUpgraded[uid] == false || this.toBeUpgraded[uid] <= 1) continue;
  5551. Game.currentGame.network.sendRpc({
  5552. name: "UpgradeBuilding",
  5553. uid: parseInt(uid)
  5554. });
  5555. this.toBeUpgraded[uid]--;
  5556. };
  5557. };
  5558. },
  5559. keyup: function(e) {
  5560. if (e.key == ",") getId("toggle-rebuild").click();
  5561. },
  5562. },
  5563. autoUpgrade: {
  5564. handlers: [{type: "entityUpdate", names: "onEntityUpdate"}, {type: "rpc", names: ["LocalBuilding"]}, {type: "keybind", names: "keyup"}],
  5565. autoUpgradeList: {},
  5566. goldStashTier: null,
  5567. LocalBuilding: function(buildings) {
  5568. const options = game.options.options;
  5569. this.goldStashTier = game.ui.components.BuildingOverlay.getGoldStashTier();
  5570. if (options.autoUpgrade) {
  5571. for (let i in buildings) {
  5572. const building = buildings[i];
  5573. if (building.dead !== 1) {
  5574. if (building.tier < 8) this.autoUpgradeList[building.uid] = true;
  5575. else delete this.autoUpgradeList[building.uid];
  5576. };
  5577. };
  5578. };
  5579. },
  5580. onEntityUpdate: function({entities}) {
  5581. const options = game.options.options;
  5582. if (options.autoUpgrade && this.goldStashTier) {
  5583. let resourcesClone = {
  5584. wood: game.ui.playerTick.wood,
  5585. stone: game.ui.playerTick.stone,
  5586. gold: game.ui.playerTick.gold
  5587. }
  5588.  
  5589. for (let i in this.autoUpgradeList) {
  5590. const building = game.ui.buildings[i];
  5591. if (building?.type !== "GoldStash" && building?.tier >= this.goldStashTier) continue;
  5592. if (!(i in game.world.entities)) continue;
  5593.  
  5594. const costs = game.ui.buildingSchema[building.type];
  5595. if (canAfford(resourcesClone, costs, building.tier + 1)) {
  5596. resourcesClone.wood -= costs.woodCosts[building.tier];
  5597. resourcesClone.stone -= costs.stoneCosts[building.tier];
  5598. resourcesClone.gold -= costs.goldCosts[building.tier];
  5599.  
  5600. game.network.sendRpc({name: "UpgradeBuilding", uid: parseInt(i)});
  5601. }
  5602. }
  5603. }
  5604. },
  5605. keyup: function(e) {
  5606. if (e.key == ".") getId("toggle-autoUpgrade").click();
  5607. },
  5608. },
  5609. AULHT: {
  5610. handlers: [{type: "entityUpdate", names: "onTick"}, {type: "rpc", names: ["LocalBuilding"]}],
  5611. shouldHaveBeenUpgraded: {},
  5612. LocalBuilding: function(buildings) {
  5613. if (game.options.options.AULHT) {
  5614. for (let i in buildings) {
  5615. const building = buildings[i];
  5616. if (building.dead === 0 && building.uid in this.shouldHaveBeenUpgraded) {
  5617. building.tier > this.shouldHaveBeenUpgraded[building.uid] && delete this.shouldHaveBeenUpgraded[building.uid];
  5618. }
  5619. }
  5620. }
  5621. },
  5622. onTick: function({entities}) {
  5623. if (game.options.options.AULHT) {
  5624. for (let uid in entities) {
  5625. const currentEntity = entities[uid];
  5626. const worldEntity = game.world.entities[uid];
  5627.  
  5628. if (currentEntity == true || worldEntity == undefined) continue;
  5629. if (uid in this.shouldHaveBeenUpgraded) continue;
  5630.  
  5631. if (uid in game.ui.buildings && typeof currentEntity.health == 'number') {
  5632. const buildingHealth = (currentEntity.health / worldEntity.targetTick.maxHealth) * 100;
  5633. if (buildingHealth <= 20 && worldEntity.targetTick.tier != game.ui.components.BuildingOverlay.getGoldStashTier()) {
  5634. game.network.sendRpc({name: "UpgradeBuilding", uid: parseInt(uid)});
  5635. this.shouldHaveBeenUpgraded[uid] = structuredClone(worldEntity.targetTick.tier);
  5636. };
  5637. };
  5638. };
  5639. };
  5640. },
  5641. },
  5642. autoBuild: {
  5643. handlers: [{type: "rpc", names: ["LocalBuilding"]}],
  5644. defaultBase: '3,0,-96,0;3,-96,0,0;3,0,-192,0;3,-96,-240,0;3,-192,0,0;3,-240,-96,0;4,-336,-96,0;4,-432,-288,0;4,-96,-336,0;4,-288,-432,0;8,-192,-384,0;8,-384,-192,0;8,-288,-192,0;8,-192,-192,0;8,-192,-288,0;8,-288,-288,0;8,-384,-384,0;8,-96,-96,0;7,-288,0,0;7,-384,0,0;7,-432,-96,0;7,0,-288,0;7,0,-384,0;7,-96,-432,0;0,-168,-504,0;0,-216,-504,0;0,-264,-552,0;0,-312,-552,0;0,-312,-504,0;0,-504,-216,0;0,-504,-168,0;0,-552,-264,0;0,-552,-312,0;0,-504,-312,0;1,-360,-456,0;1,-456,-360,0;9,96,-96,0;9,-96,96,0;',
  5645. LocalBuilding: function(buildings) {
  5646. if (game.options.options.autoBuild) {
  5647. for (let i in buildings) {
  5648. const building = buildings[i];
  5649. if (building.type == "GoldStash" && building.dead === 0) game.script.builder.buildBase(this.defaultBase);
  5650. };
  5651. };
  5652. },
  5653. },
  5654. reconstruct: {
  5655. HORIZONTAL_DELTA: 500,
  5656. VERTICAL_DELTA: 1,
  5657.  
  5658. isMapping: false,
  5659. isMappingNow: false,
  5660.  
  5661. currentMap: {},
  5662. currentEntTowers: {},
  5663.  
  5664. currentWidth: 2,
  5665. currentlyMapping: null,
  5666.  
  5667. buildNote: document.createElement('p'),
  5668. entSettings: document.createElement('div'),
  5669.  
  5670. pathWayIndicators: {},
  5671. validCellsIndicators: {},
  5672.  
  5673. currentBase: '',
  5674. entranceGroups: {},
  5675. entPriority: ["right", "bottom", "top", "left"],
  5676.  
  5677. init: function() {
  5678. this.buildNote.innerHTML = `Map out the entrance path by drag-clicking the right mouse button.<br>Press Esc to save the current configuration.`;
  5679. this.buildNote.style.display = "none";
  5680. this.buildNote.style.color = "white";
  5681. this.buildNote.style.opacity = '0.5';
  5682. this.buildNote.style.textAlign = "center";
  5683. getClass('hud-top-center')[0].appendChild(this.buildNote);
  5684.  
  5685. this.entSettings.id = "ent-settings";
  5686. this.entSettings.innerHTML = `
  5687. Anchor: <select id="current-side">
  5688. <option value="top">Top</option>
  5689. <option value="bottom">Bottom</option>
  5690. <option value="left">Left</option>
  5691. <option value="right">Right</option>
  5692. </select><br>
  5693. Entrance span: <input id="ent-width" type="range" step="1" data-width="2 cells" value="2" min="2" max="8" /><br>
  5694.  
  5695. <div id="ent-controls">
  5696. <button id="undo-ent"><i class="fa-solid fa-xmark"></i></button>
  5697. <button id="create-ent"><i class="fa-solid fa-check"></i></button>
  5698. </div>
  5699. `;
  5700. this.entSettings.style.display = "none";
  5701. getClass("hud")[0].appendChild(this.entSettings);
  5702.  
  5703. document.addEventListener("keyup", (e) => {
  5704. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  5705. if (e.key == "Escape") {
  5706. if (this.isMapping) {
  5707. this.isMapping = false;
  5708. this.buildNote.style.display = "none";
  5709. game.renderer.follow(game.world.entities[game.world.myUid]);
  5710.  
  5711. this.currentMap = {};
  5712. this.currentEntTowers = {};
  5713.  
  5714. this.removeAllIndicators();
  5715. this.entSettings.style.display = "none";
  5716. };
  5717. };
  5718. };
  5719. });
  5720.  
  5721. getId("current-side").addEventListener("select", ({target}) => {
  5722. this.currentlyMapping = target.value;
  5723. });
  5724. getId("ent-width").addEventListener("input", ({target}) => {
  5725. target.setAttribute("data-width", target.value + ` cells`);
  5726. this.currentWidth = target.valueAsNumber;
  5727. this.updateEntranceTowers();
  5728. });
  5729. getId("undo-ent").addEventListener("click", ({target}) => {
  5730. this.currentMap = {};
  5731. this.currentEntTowers = {};
  5732.  
  5733. this.removeAllIndicators();
  5734. this.entSettings.style.display = "none";
  5735. });
  5736. getId("create-ent").addEventListener("click", ({target}) => {
  5737. this.entranceGroups[this.currentlyMapping] = Object.values(this.currentEntTowers).map(({x, y, type, yaw}) => {
  5738. return `${type},${x},${y},${yaw};`;
  5739. }).join("");
  5740.  
  5741. this.currentMap = {};
  5742. this.currentEntTowers = {};
  5743. for (const validCellIndex in this.validCellsIndicators) {
  5744. game.renderer.npcs.removeAttachment(this.validCellsIndicators[validCellIndex]);
  5745. delete this.validCellsIndicators[validCellIndex];
  5746. };
  5747. this.entSettings.style.display = "none";
  5748. });
  5749.  
  5750. game.network.addRpcHandler("LocalBuilding", this.onLocalBuilding.bind(this));
  5751. getId("hud").addEventListener("mousedown", this.onMouseDown.bind(this));
  5752. getId("hud").addEventListener("mousemove", this.onMouseMove.bind(this));
  5753. getId("hud").addEventListener("mouseup", this.onMouseUp.bind(this));
  5754. },
  5755. reconstructBaseByPriority: function() {
  5756. for (const side of this.entPriority) {
  5757. game.script.builder.buildBase(this.entranceGroups[side]);
  5758. };
  5759.  
  5760. },
  5761. removeAllIndicators: function() {
  5762. for (const cellIndex in this.currentMap) {
  5763. game.renderer.npcs.removeAttachment(this.pathWayIndicators[cellIndex]);
  5764. delete this.pathWayIndicators[cellIndex];
  5765. };
  5766. for (const validCellIndex in this.validCellsIndicators) {
  5767. game.renderer.npcs.removeAttachment(this.validCellsIndicators[validCellIndex]);
  5768. delete this.validCellsIndicators[validCellIndex];
  5769. };
  5770. },
  5771. getNonEntTowers: function() {
  5772. const map = {};
  5773. for (let x = this.goldStash.x - 12 * 48; x < this.goldStash.x + 12 * 48; x++) {
  5774. for (let y = this.goldStash.y - 12 * 48; y < this.goldStash.y + 12 * 48; y++) {
  5775. map[x] ||= {};
  5776. map[x][y] = false;
  5777. };
  5778. };
  5779. for (const relativePos of Object.values(this.currentMap)) {
  5780. map[this.goldStash.x - relativePos.x][this.goldStash.y - relativePos.y] = true;
  5781. };
  5782.  
  5783. // <tab>
  5784.  
  5785. const movementsX = [1, 0, -1, 0];
  5786. const movementsY = [0, 1, 0, -1];
  5787.  
  5788.  
  5789. let yourFuckinAnswer = [];
  5790.  
  5791. for (let XxX = this.goldStash.x - 12 * 48; XxX < this.goldStash.x + 12 * 48; XxX++) {
  5792. for (let YyY = this.goldStash.y - 12 * 48; YyY < this.goldStash.y + 12 * 48; YyY++) {
  5793. if (map[XxX][YyY]) continue;
  5794.  
  5795. let newAnswer = [];
  5796.  
  5797. let queueX = [];
  5798. let queueY = [];
  5799.  
  5800. queueX.push(XxX);
  5801. queueY.push(YyY);
  5802. map[XxX][YyY] = true;
  5803.  
  5804. while (queueX.length != 0) {
  5805. let x = queueX.shift();
  5806. let y = queueY.shift();
  5807.  
  5808. newAnswer.push({x, y});
  5809.  
  5810. for (let i = 0; i < 4; i++) {
  5811. let newX = x + movementsX[i];
  5812. let newY = y + movementsY[i];
  5813.  
  5814. if (map[newX][newY]) continue;
  5815. if (newX < this.goldStash.x - 12 * 48 || newX >= this.goldStash.x + 12 * 48) continue;
  5816. if (newY < this.goldStash.y - 12 * 48 || newY >= this.goldStash.y + 12 * 48) continue;
  5817.  
  5818. map[newX][newY] = true;
  5819.  
  5820. queueX.push(newX);
  5821. queueY.push(newY);
  5822. }
  5823. }
  5824.  
  5825. yourFuckinAnswer.push(newAnswer);
  5826. }
  5827. }
  5828. console.log(yourFuckinAnswer);
  5829. // </tab>
  5830.  
  5831. },
  5832. updateEntranceTowers: function() {
  5833. for (const validCellIndex in this.validCellsIndicators) {
  5834. game.renderer.npcs.removeAttachment(this.validCellsIndicators[validCellIndex]);
  5835. delete this.validCellsIndicators[validCellIndex];
  5836. };
  5837. this.currentEntTowers = {};
  5838.  
  5839. for (let cellIndex in this.currentMap) {
  5840. cellIndex = parseInt(cellIndex);
  5841. for (let CIx = cellIndex - this.HORIZONTAL_DELTA * this.currentWidth; CIx <= cellIndex + this.HORIZONTAL_DELTA * this.currentWidth; CIx += this.HORIZONTAL_DELTA) {
  5842. if (CIx < 0 || CIx > this.HORIZONTAL_DELTA ** 2) continue;
  5843. for (let CIy = CIx - this.VERTICAL_DELTA * this.currentWidth; CIy <= CIx + this.VERTICAL_DELTA * this.currentWidth; CIy += this.VERTICAL_DELTA) {
  5844. if (CIy < 0 || CIy > this.HORIZONTAL_DELTA ** 2) continue;
  5845. if (!(CIy in this.currentMap)) this.validCellsIndicators[CIy] = null;
  5846. };
  5847. };
  5848. };
  5849. for (const validCellIndex in this.validCellsIndicators) {
  5850. const entities = game.world.entityGrid.getEntitiesInCell(validCellIndex);
  5851. if (this.validCellsIndicators[validCellIndex] !== null) continue;
  5852. for (const uid in entities) {
  5853. const building = game.ui.buildings[uid];
  5854. if (!building || building.dead === 1) continue;
  5855.  
  5856. this.currentEntTowers[uid] = {
  5857. type: towerCodes.indexOf(building.type),
  5858. x: this.goldStash.x - building.x,
  5859. y: this.goldStash.y - building.y,
  5860. yaw: game.world.entities[building.uid]?.targetTick?.yaw
  5861. };
  5862.  
  5863. const buildingSchema = game.ui.buildingSchema[building.type];
  5864. const buildingSize = buildingSchema.gridWidth * 48;
  5865.  
  5866. const indicator = game.assetManager.models.rangeIndicatorModel({
  5867. width: buildingSize,
  5868. height: buildingSize,
  5869. }, {r: 111, g: 208, b: 247}, {r: 111, g: 208, b: 247}, 0);
  5870. indicator.setPosition(building.x, building.y);
  5871.  
  5872. this.validCellsIndicators[validCellIndex] = indicator;
  5873. game.renderer.npcs.addAttachment(indicator);
  5874. };
  5875. this.validCellsIndicators[validCellIndex] === null && delete this.validCellsIndicators[validCellIndex];
  5876. };
  5877. console.log(this.validCellsIndicators);
  5878. },
  5879. startReconstruction: function() {
  5880. if (!this.goldStash) return;
  5881.  
  5882. game.ui.components.MenuParty.hide();
  5883. game.ui.components.MenuShop.hide();
  5884. game.ui.components.MenuSettings.hide();
  5885.  
  5886. this.isMapping = true;
  5887. this.buildNote.style.display = "block";
  5888. this.currentBase = game.script.builder.recordBase(false);
  5889. game.renderer.follow(game.world.entities[this.goldStash.uid]);
  5890. },
  5891. onLocalBuilding: function(buildings) {
  5892. for (const building of buildings) {
  5893. if (building.type == "GoldStash") {
  5894. this.goldStash = building.dead === 0 ? building : null;
  5895. };
  5896. };
  5897. },
  5898. onMouseDown: function(e) {
  5899. if (!this.isMapping || e.button !== 2) return;
  5900. if (!e.repeat) {
  5901. console.log('a');
  5902. this.currentMap = {};
  5903. this.isMappingNow = true;
  5904. };
  5905. },
  5906. onMouseMove: function(e) {
  5907. if (!this.isMappingNow) return;
  5908.  
  5909. const absolutePos = game.renderer.screenToWorld(e.clientX, e.clientY);
  5910. const cellBeneath = game.world.entityGrid.getCellIndexes(absolutePos.x, absolutePos.y, {width: 1, height: 1})[0];
  5911.  
  5912. const cellCoordByCells = game.world.entityGrid.getCellCoords(cellBeneath);
  5913. const cellCoordsByAbsPos = {x: cellCoordByCells.x * 48, y: cellCoordByCells.y * 48};
  5914.  
  5915. this.currentMap[cellBeneath] = {
  5916. x: this.goldStash.x - cellCoordsByAbsPos.x,
  5917. y: this.goldStash.y - cellCoordsByAbsPos.y,
  5918. };
  5919.  
  5920. if (!this.pathWayIndicators[cellBeneath]) {
  5921. console.log(cellBeneath, cellCoordByCells, cellCoordsByAbsPos);
  5922. const indicator = game.assetManager.models.rangeIndicatorModel({
  5923. width: 48,
  5924. height: 48,
  5925. }, {r: 255, g: 0, b: 0}, {r: 255, g: 0, b: 0}, 0);
  5926.  
  5927. indicator.setPosition(cellCoordsByAbsPos.x + 24, cellCoordsByAbsPos.y + 24);
  5928. game.renderer.npcs.addAttachment(indicator);
  5929. this.pathWayIndicators[cellBeneath] = indicator;
  5930. };
  5931. },
  5932. onMouseUp: function(e) {
  5933. if (!this.isMappingNow) return;
  5934. this.isMappingNow = false;
  5935.  
  5936. this.entSettings.style.display = "block";
  5937. this.entSettings.style.left = e.clientX + "px";
  5938. this.entSettings.style.top = e.clientY + "px";
  5939.  
  5940. this.updateEntranceTowers();
  5941. },
  5942. },
  5943. autoHeal: {
  5944. init: function() {
  5945. Game.currentGame.ui._events.playerPetTickUpdate.push(pet => this.petTickUpdate.onTick(pet));
  5946. game.ui._events.playerTickUpdate.push(player => this.playerTickUpdate.onTick(player));
  5947. },
  5948. playerTickUpdate: {
  5949. hasEquipedPotion: false,
  5950. lastTickHealth: 100,
  5951. onTick: function(player) {
  5952. const options = game.options.options;
  5953.  
  5954. if (options.autoHeal) {
  5955. if (!game.ui.inventory.HealthPotion && player.gold >= 100) {
  5956. Game.currentGame.network.sendRpc({name: "BuyItem", itemName: "HealthPotion", tier: 1});
  5957. };
  5958. const playerHealth = (player.health / player.maxHealth) * 100;
  5959. this.hasEquipedPotion = (this.lastTickHealth <= playerHealth);
  5960. const healThreshold = getId("auto-heal-threshold").valueAsNumber || 15;
  5961. if (playerHealth <= healThreshold && !this.hasEquipedPotion) {
  5962. Game.currentGame.network.sendRpc({name: "EquipItem", itemName: "HealthPotion", tier: 1});
  5963. };
  5964. this.lastTickHealth = playerHealth;
  5965. };
  5966. },
  5967. },
  5968. petTickUpdate: {
  5969. buyItem: (itemName, tier = 1) => Game.currentGame.network.sendRpc({name: "BuyItem", itemName, tier}),
  5970. equipItem: (itemName, tier = 1) => Game.currentGame.network.sendRpc({name: "EquipItem", itemName, tier}),
  5971. petLevelEnum: [8, 16, 24, 32, 48, 64, 96],
  5972. petTokenEnum: [100, 100, 100, 100, 200, 200, 300, Infinity],
  5973. onTick: function(pet) {
  5974. const options = game.options.options;
  5975. if (options.autoHeal) {
  5976. if (pet.health <= 0) {
  5977. this.buyItem("PetRevive");
  5978. this.equipItem("PetRevive");
  5979. }
  5980. let petHealth = (pet.health / pet.maxHealth) * 100;
  5981. const healThreshold = getId("auto-heal-threshold").valueAsNumber || 15;
  5982. if (petHealth <= healThreshold) {
  5983. this.buyItem('PetHealthPotion');
  5984. this.equipItem("PetHealthPotion");
  5985. }
  5986. };
  5987. this.petLevelEnum.indexOf(game.ui.components.MenuShop.shopItems[pet.model].level) > -1 && (
  5988. game.ui.playerTick.token >= this.petTokenEnum[pet.tier - 1] && this.buyItem(pet.model, pet.tier + 1)
  5989. );
  5990. },
  5991. },
  5992. },
  5993. spam: {
  5994. randomSpamText: [
  5995. `?verify`,
  5996. "hi",
  5997. "ez",
  5998. "Super Idol的笑容都没你的甜八月正午的阳光都没你耀眼热爱 105 °C的你滴滴清纯的蒸馏水",
  5999. "Zǎoshang hǎo zhōngguó xiànzài wǒ yǒu BING CHILLING 🥶🍦",
  6000. "Wǒ hěn xǐhuān BING CHILLING 🥶🍦 Dànshì sùdù yǔ jīqíng 9 bǐ BING CHILLING 🥶🍦",
  6001. ],
  6002. spamInterval: null,
  6003. spamText: '',
  6004. fetchUnicode: async function() {
  6005. if (!localStorage.literallyEveryUnicodeEver) {
  6006. localStorage.literallyEveryUnicodeEver = await fetch('https://raw.githubusercontent.com/bits/UTF-8-Unicode-Test-Documents/master/UTF-8_sequence_unseparated/utf8_sequence_0-0xffff_assigned_printable_unseparated.txt')
  6007. .then(response => response.text());
  6008. this.randomSpamText.push(`${garbageGenerator()} BIG RAID ${garbageGenerator()}`);
  6009. }
  6010. },
  6011. onchange: function({target}) {
  6012. this.spamText = target.value;
  6013. },
  6014. start: function() {
  6015. this.spamInterval = setInterval(() => {
  6016. let text;
  6017. if (this.spamText !== '') text = `${garbageGenerator()} ${this.spamText} ${garbageGenerator()}`;
  6018. else text = getRandomItem(this.randomSpamText);
  6019. game.network.sendRpc({
  6020. name: "SendChatMessage",
  6021. channel: "Local",
  6022. message: text
  6023. });
  6024. }, 1050);
  6025. },
  6026. stop: function() {
  6027. clearInterval(this.spamInterval);
  6028. },
  6029. init: function() {
  6030. this.fetchUnicode();
  6031. },
  6032. },
  6033. autoBow: {
  6034. handlers: [{type: "entityUpdate", names: "onEntityUpdate"}, {type: "keybind", names: "keyup"}],
  6035. onEntityUpdate: function() {
  6036. if (game.options.options.autoBow) {
  6037. game.network.sendInput({space: 0});
  6038. game.network.sendInput({space: 1});
  6039. };
  6040. },
  6041. keyup: function(e) {
  6042. if (e.key == "=" && game.world.inWorld) {
  6043. if (game.ui.inventory.Bow) {
  6044. game.options.options.autoBow = !game.options.options.autoBow;
  6045. game.options.options.autoBow && game.network.sendRpc({name: "EquipItem", itemName: "Bow", tier: game.ui.inventory.Bow.tier});
  6046. } else if (game.ui.playerTick.gold > 100) {
  6047. game.network.sendRpc({name: "BuyItem", itemName: "Bow", tier: 1});
  6048. };
  6049. }
  6050. },
  6051. },
  6052. autoAim: {
  6053. handlers: [{type: "entityUpdate", names: "onEntityUpdate"}],
  6054. aimTarget: "player",
  6055. targets: [],
  6056. init: function() {
  6057. getId("autoAimOptions").addEventListener("change", ({target}) => {
  6058. this.aimTarget = target.value;
  6059. });
  6060. },
  6061. onEntityUpdate: function() {
  6062. const options = game.options.options;
  6063. if (options.autoAim) {
  6064. this.targets = [];
  6065. const entities = game.renderer.npcs.attachments;
  6066.  
  6067. for (let entity of entities) {
  6068. switch(this.aimTarget) {
  6069. case "player":
  6070. if (entity.fromTick.model == "GamePlayer" && entity.targetTick.partyId !== game.ui.playerPartyId && entity.fromTick.dead == 0) {
  6071. this.targets.push(entity.fromTick);
  6072. };
  6073. break;
  6074. case "zombie":
  6075. if (entity.fromTick.model !== "NeutralTier1" && entity.fromTick.entityClass == "Npc") {
  6076. this.targets.push(entity.fromTick);
  6077. };
  6078. break;
  6079. case "zom/dem":
  6080. if (entity.fromTick.entityClass == "Npc") {
  6081. this.targets.push(entity.fromTick);
  6082. };
  6083. break;
  6084. default:
  6085. if (entity.fromTick.uid !== game.world.myUid) {
  6086. this.targets.push(entity.fromTick);
  6087. };
  6088. };
  6089. };
  6090.  
  6091. if (this.targets.length > 0) {
  6092. const myPos = game.ui.playerTick.position;
  6093. this.targets.sort((a, b) => {
  6094. const distThisToA = measureDistance(myPos, a.position);
  6095. const distThisToB = measureDistance(myPos, b.position);
  6096.  
  6097. if (distThisToA < distThisToB) return -1;
  6098. else if (distThisToA > distThisToB) return 1;
  6099.  
  6100. return 0;
  6101. });
  6102.  
  6103. const target = this.targets[0];
  6104. const clientPos = game.renderer.worldToScreen(target.position.x, target.position.y);
  6105. game.inputManager.onMouseMoved({clientX: clientPos.x, clientY: clientPos.y});
  6106. }
  6107. };
  6108. }
  6109. },
  6110. autoRespawn: {
  6111. handlers: [{type: "rpc", names: ["Dead"]}],
  6112. Dead: function() {
  6113. if (!game.options.options.autoRespawn) return;
  6114. document.querySelector("#hud-respawn > div > div > div > button:nth-child(3)").click();
  6115. },
  6116. },
  6117. getRSS: {
  6118. handlers: [{type: "entityUpdate", names: "onTick"}, {type: "keybind", names: ["keyup", "mousemove"]}, {type: "rpc", names: ["DayCycle"]}],
  6119. dayTickData: null,
  6120. scoreData: {},
  6121.  
  6122. lastHoveredPlayers: {},
  6123. allowedRSS: true,
  6124. assignOldTick: function(player, playerTick) {
  6125. const [wood_1, stone_1, gold_1, token_1, px_1, py_1, info] = playerTick;
  6126. player.targetTick.oldWood = wood_1;
  6127. player.targetTick.oldStone = stone_1;
  6128. player.targetTick.oldGold = gold_1;
  6129. player.targetTick.oldToken = token_1;
  6130. player.targetTick.oldPX = px_1;
  6131. player.targetTick.oldPY = py_1;
  6132. player.targetTick.info = info;
  6133. player.targetTick.name = player.targetTick.info;
  6134. },
  6135. highlightColor: function(uid, rgb) {
  6136. // const hr = hexToRgb(hex);
  6137. game.world.entities[uid].currentModel.nameEntity.setColor(111, 208, 247);
  6138. },
  6139. resetColor: function(uid) {
  6140. game.world.entities[uid].currentModel.nameEntity.setColor(220, 220, 220);
  6141. },
  6142. DayCycle: function(e) {
  6143. this.dayTickData = e;
  6144. if (!game.ui.playerTick) return;
  6145. if (game.ui.playerTick.wave == 0) return;
  6146. for (const player of game.ui.playerPartyMembers) {
  6147. if (!e.isDay) {
  6148. const { playerUid } = player;
  6149. const playerTick = game.world.entities[playerUid].targetTick;
  6150. this.scoreData[playerUid] ||= {
  6151. spw: 0,
  6152. lastWaveScore: playerTick.score,
  6153. };
  6154. this.scoreData[playerUid].spw = playerTick.score - this.scoreData[playerUid].lastWaveScore;
  6155. this.scoreData[playerUid].lastWaveScore = playerTick.score;
  6156. };
  6157. };
  6158. for (const uid in this.scoreData) {
  6159. game.ui.playerPartyMembers.findIndex(e => e.playerUid == uid) == -1 && delete this.scoreData[uid];
  6160. };
  6161. },
  6162. onTick: function() {
  6163. const options = game.options.options;
  6164. if (options.getRSS) !this.allowedRSS && (this.allowedRSS = true);
  6165. if (options.getRSS || this.allowedRSS) {
  6166. // game.debug.allEntities = [];
  6167. for (let player of game.renderer.npcs.attachments) {
  6168. if (!!player.fromTick.name) {
  6169. let wood_1 = counter(player.targetTick.wood);
  6170. let stone_1 = counter(player.targetTick.stone);
  6171. let gold_1 = counter(player.targetTick.gold);
  6172. let token_1 = counter(player.targetTick.token);
  6173. let px_1 = counter(player.targetTick.position.x);
  6174. let py_1 = counter(player.targetTick.position.y);
  6175. let timeout_1 = player.targetTick.isPaused ? "On Timeout" : "";
  6176. if (options.getRSS && !player.targetTick.oldName) {
  6177. player.targetTick.oldName = player.targetTick.name;
  6178. let info = `
  6179. ${window.filterXSS(player.targetTick.oldName)}; score: ${player.targetTick.score.toLocaleString()}
  6180. UID: ${player.targetTick.uid}
  6181. W: ${wood_1}, S: ${stone_1}, G: ${gold_1}, T: ${token_1}
  6182. partyId: ${Math.round(player.targetTick.partyId)}
  6183. timeDead: ${msToTime(player.targetTick.timeDead)}
  6184. ${(player.targetTick.uid in this.scoreData) ? `SPW: ${this.scoreData[player.targetTick.uid].spw.toLocaleString()}` : ""}
  6185. ${timeout_1}
  6186.  
  6187.  
  6188.  
  6189.  
  6190.  
  6191. `;
  6192. this.assignOldTick(player, [wood_1, stone_1, gold_1, token_1, px_1, py_1, info]);
  6193. }
  6194. if (!options.getRSS && player.targetTick.oldName) {
  6195. player.targetTick.info = player.targetTick.oldName;
  6196. player.targetTick.name = player.targetTick.info;
  6197. player.targetTick.oldName = null;
  6198. }
  6199. if (options.getRSS) {
  6200. if (player.targetTick.oldGold !== gold_1
  6201. || player.targetTick.oldWood !== wood_1
  6202. || player.targetTick.oldStone !== stone_1
  6203. || player.targetTick.oldToken !== token_1
  6204. || player.targetTick.oldPX !== px_1
  6205. || player.targetTick.oldPY !== py_1) {
  6206. let info = `
  6207. ${window.filterXSS(player.targetTick.oldName)}; score: ${player.targetTick.score.toLocaleString()}
  6208. UID: ${player.targetTick.uid}
  6209. W: ${wood_1}, S: ${stone_1}, G: ${gold_1}, T: ${token_1}
  6210. partyId: ${Math.round(player.targetTick.partyId)}
  6211. timeDead: ${msToTime(player.targetTick.timeDead)}
  6212. ${(player.targetTick.uid in this.scoreData) ? `SPW: ${this.scoreData[player.targetTick.uid].spw.toLocaleString()}` : ""}
  6213. ${timeout_1}
  6214.  
  6215.  
  6216.  
  6217.  
  6218.  
  6219. `;
  6220. this.assignOldTick(player, [wood_1, stone_1, gold_1, token_1, px_1, py_1, info]);
  6221. }
  6222. }
  6223. }
  6224. }
  6225. }
  6226. if (!options.getRSS) this.allowedRSS = false;
  6227. },
  6228. mousemove: function(e) {
  6229. if (!game.options.options.getRSS) return;
  6230. const worldPos = game.renderer.screenToWorld(e.clientX, e.clientY);
  6231. const entitiesUnderMouse = getEntityAtPos(worldPos.x, worldPos.y);
  6232. for (const uid in this.lastHoveredPlayers) {
  6233. if (!(uid in entitiesUnderMouse)) {
  6234. uid in game.world.entities && this.resetColor(uid);
  6235. delete this.lastHoveredPlayers[uid];
  6236. }
  6237. }
  6238. for (const uid in entitiesUnderMouse) {
  6239. if (game.world.entities[uid].targetTick.name && !(uid in this.lastHoveredPlayers)) {
  6240. this.lastHoveredPlayers[uid] = true;
  6241. this.highlightColor(uid);
  6242. }
  6243. }
  6244. },
  6245. keyup: function(e) {
  6246. if (e.key == "-") game.options.options.getRSS = !game.options.options.getRSS;
  6247. },
  6248. },
  6249. showAoe: {
  6250. modelIndicatorsPool: {},
  6251. projectileEnums: {
  6252. "CannonProjectile": {
  6253. parent: 'CannonTower',
  6254. innerRGB: {r: 60, g: 188, b: 92},
  6255. borderRGB: {r: 58, g: 170, b: 86},
  6256. aoe: 250,
  6257. },
  6258. "BombProjectile": {
  6259. parent: 'BombTower',
  6260. innerRGB: {r: 0xd8, g: 0x0, b: 0x27},
  6261. borderRGB: {r: 0xd8, g: 0x4d, b: 0x5c},
  6262. aoe: 250,
  6263. },
  6264. "FireballProjectile": {
  6265. parent: "MagicTower",
  6266. innerRGB: {r: 73, g: 178, b: 204},
  6267. borderRGB: {r: 48, g: 130, b: 150},
  6268. aoe: 100
  6269. }
  6270. },
  6271. init: function() {
  6272. const poolSize = 50;
  6273. for (let modelName in this.projectileEnums) {
  6274. this.modelIndicatorsPool[modelName] = [];
  6275. for (let i = 0; i < poolSize; i++) {
  6276. const {innerRGB, borderRGB, aoe, parent} = this.projectileEnums[modelName];
  6277. const aoeIndicator = game.assetManager.models.rangeIndicatorModel({
  6278. isCircular: true,
  6279. radius: aoe,
  6280. }, innerRGB, borderRGB);
  6281. aoeIndicator.setVisible(true);
  6282. this.modelIndicatorsPool[modelName].push(aoeIndicator);
  6283. }
  6284. }
  6285. },
  6286. onEntityRemoved: function(t) {
  6287. if (game.options.options.showAoe) {
  6288. const entityTick = game.world.entities[t].targetTick;
  6289. if (entityTick.model in this.projectileEnums) {
  6290. const { msBetweenFiresTiers, lifetimeTiers } = game.ui.buildingSchema[this.projectileEnums[entityTick.model].parent];
  6291. let aoeIndicator;
  6292. if (this.modelIndicatorsPool[entityTick.model].length > 0) {
  6293. aoeIndicator = this.modelIndicatorsPool[entityTick.model].shift();
  6294. } else {
  6295. const {innerRGB, borderRGB, aoe, parent} = this.projectileEnums[entityTick.model];
  6296. aoeIndicator = game.assetManager.models.rangeIndicatorModel({
  6297. isCircular: true,
  6298. radius: aoe,
  6299. }, innerRGB, borderRGB);
  6300. aoeIndicator.setVisible(true);
  6301. }
  6302. aoeIndicator.setPosition(entityTick.position.x, entityTick.position.y);
  6303. game.renderer.ground.addAttachment(aoeIndicator);
  6304.  
  6305. setTimeout(() => {
  6306. game.renderer.ground.removeAttachment(aoeIndicator);
  6307. this.modelIndicatorsPool[entityTick.model].push(aoeIndicator);
  6308. }, msBetweenFiresTiers[7]);
  6309. }
  6310. }
  6311. },
  6312. },
  6313. stashIndicators: {
  6314. BUILDING_DISTANCE: 864,
  6315. MIN_STASH_DISTANCE: 2496,
  6316. ZOMBIE_SPAWN_RANGE: 48 * Math.sqrt(2 * (18 ** 2)),
  6317. currentIndicators: {
  6318. uid: null,
  6319. indicators: [],
  6320. },
  6321. onEntityCreated: function(t) {
  6322. if (t.model == "GoldStash") {
  6323. if (this.currentIndicators.uid == t.uid) return;
  6324.  
  6325. for (const indicator of this.currentIndicators.indicators) game.renderer.ground.removeAttachment(indicator);
  6326.  
  6327. const buildLimitIndicator = game.assetManager.models.rangeIndicatorModel({
  6328. width: this.BUILDING_DISTANCE * 2,
  6329. height: this.BUILDING_DISTANCE * 2,
  6330. }, null, {r: 0xee, g: 0xee, b: 0xee}, 12);
  6331. buildLimitIndicator.setVisible(game.options.options.stashIndicators);
  6332. buildLimitIndicator.setPosition(t.position.x, t.position.y);
  6333. game.renderer.ground.addAttachment(buildLimitIndicator);
  6334.  
  6335. const stashLimitIndicator = game.assetManager.models.rangeIndicatorModel({
  6336. width: this.MIN_STASH_DISTANCE * 2,
  6337. height: this.MIN_STASH_DISTANCE * 2,
  6338. }, null, {r: 0xee, g: 0xee, b: 0xee}, 12);
  6339. stashLimitIndicator.setVisible(game.options.options.stashIndicators);
  6340. stashLimitIndicator.setPosition(t.position.x, t.position.y);
  6341. game.renderer.ground.addAttachment(stashLimitIndicator);
  6342.  
  6343. const zombieSpawnIndicator = game.assetManager.models.rangeIndicatorModel({
  6344. isCircular: true,
  6345. radius: this.ZOMBIE_SPAWN_RANGE,
  6346. }, {r: 0xff, g: 0xff, b: 0xff}, {r: 0xee, g: 0xee, b: 0xee});
  6347. zombieSpawnIndicator.setVisible(game.options.options.stashIndicators);
  6348. zombieSpawnIndicator.setPosition(t.position.x, t.position.y);
  6349. game.renderer.ground.addAttachment(zombieSpawnIndicator);
  6350.  
  6351. this.currentIndicators = {
  6352. uid: t.uid,
  6353. indicators: [buildLimitIndicator, stashLimitIndicator, zombieSpawnIndicator],
  6354. };
  6355. }
  6356. },
  6357. },
  6358. grouping: {
  6359. loadedGrid: false,
  6360. displays: ["none", "blue", "purple"],
  6361. currentlyDisplaying: "none",
  6362. init: function() {
  6363. game.network.addEnterWorldHandler(() => {
  6364. if (this.loadedGrid) return;
  6365. this.makeGrid();
  6366. });
  6367. document.addEventListener("keyup", function(e) {
  6368. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  6369. if (e.key == "v") getId("Grouping Grid").click();
  6370. };
  6371. });
  6372. },
  6373. makeGrid: function(width, height) {
  6374. this.loadedGrid = true;
  6375. const blueCell = game.assetManager.models.rangeIndicatorModel({
  6376. width: 196,
  6377. height: 196,
  6378. }, null, {r: 111, g: 208, b: 247}, 4);
  6379.  
  6380. const purpleCell = game.assetManager.models.rangeIndicatorModel({
  6381. width: 196,
  6382. height: 196,
  6383. }, null, {r: 213, g: 118, b: 211}, 4);
  6384.  
  6385. this.blueGrid = new game.renderer.spriteType(blueCell.goldRegion.getTexture(), true);
  6386. this.blueGrid.setDimensions(0, 0, 24000, 24000);
  6387. this.blueGrid.setAnchor(0, 0);
  6388. this.blueGrid.setAlpha(1.5);
  6389. this.blueGrid.setVisible(this.currentlyDisplaying == "blue");
  6390.  
  6391. this.purpleGrid = new game.renderer.spriteType(purpleCell.goldRegion.getTexture(), true);
  6392. this.purpleGrid.setDimensions(48, 48, 23952, 23952);
  6393. this.purpleGrid.setAnchor(0, 0);
  6394. this.purpleGrid.setAlpha(1.75);
  6395. this.purpleGrid.setVisible(this.currentlyDisplaying == "purple");
  6396.  
  6397. game.renderer.ground.addAttachment(this.blueGrid);
  6398. game.renderer.ground.addAttachment(this.purpleGrid);
  6399. },
  6400. refreshGrid: function() {
  6401. this.blueGrid.setVisible(this.currentlyDisplaying == "blue");
  6402. this.purpleGrid.setVisible(this.currentlyDisplaying == "purple");
  6403. },
  6404. cycleGrid: function() {
  6405. this.currentlyDisplaying = this.displays[(this.displays.indexOf(this.currentlyDisplaying) + 1) % 3];
  6406. this.refreshGrid();
  6407. },
  6408. },
  6409. buildingLife: {
  6410. handlers: [{type: "rpc", names: ["LocalBuilding"]}],
  6411.  
  6412. MAX_ALPHA: 5,
  6413.  
  6414. buildingWeights: {},
  6415. indicators: [],
  6416. sceneryAlpha: 0.5,
  6417.  
  6418. startingIndex: 0,
  6419. refreshTimeout: null,
  6420.  
  6421. LocalBuilding: function(buildings) {
  6422. for (let building of buildings) {
  6423. if (building.dead === 1) {
  6424. building.uid in this.buildingWeights && delete this.buildingWeights[building.uid];
  6425. } else {
  6426. if (building.uid in this.buildingWeights) continue;
  6427. this.buildingWeights[building.uid] = null;
  6428. };
  6429. };
  6430. getId("heat-slider").max = Object.keys(this.buildingWeights).length - 1;
  6431. getId("heat-max").value = Object.keys(this.buildingWeights).length;
  6432.  
  6433. this.refreshMap();
  6434. },
  6435. refreshMap: function() {
  6436. const sortedUids = Object.keys(this.buildingWeights).sort((a, b) => a - b);
  6437. const gap = this.MAX_ALPHA / (sortedUids.length - this.startingIndex);
  6438.  
  6439. let i = 0,
  6440. _i = -1;
  6441. for (let uid of sortedUids) {
  6442. _i++;
  6443. if (_i < this.startingIndex) {
  6444. this.buildingWeights[uid] = null;
  6445. continue;
  6446. } else if (_i == this.startingIndex) i = 0;
  6447.  
  6448. this.buildingWeights[uid] = gap * i++;
  6449. };
  6450. },
  6451. setSceneryAlpha: function(alpha) {
  6452. this.sceneryAlpha = alpha;
  6453. game.options.options.buildingLife && game.renderer.scenery.setAlpha(this.sceneryAlpha);
  6454. },
  6455. showMap: function() {
  6456. for (let uid in this.buildingWeights) {
  6457. if (this.buildingWeights[uid] === null) {
  6458. const entity = game.renderer.scenery.attachments.find(e => e.uid == uid);
  6459. entity?.setAlpha?.(0);
  6460. continue;
  6461. };
  6462. const building = game.ui.buildings[uid];
  6463. if (!building || building.dead === 1) continue;
  6464.  
  6465. const buildingSchema = game.ui.buildingSchema[building.type];
  6466. const buildingSize = buildingSchema.gridWidth * 48;
  6467.  
  6468. const indicator = game.assetManager.models.rangeIndicatorModel({
  6469. width: buildingSize,
  6470. height: buildingSize,
  6471. }, {r: 255, g: 0, b: 0}, {r: 255, g: 0, b: 0}, 0);
  6472. indicator.setAlpha(this.MAX_ALPHA - this.buildingWeights[uid]);
  6473. indicator.setPosition(building.x, building.y);
  6474.  
  6475. this.indicators.push(indicator);
  6476. game.renderer.npcs.addAttachment(indicator);
  6477. };
  6478. game.renderer.scenery.setAlpha(this.sceneryAlpha);
  6479. },
  6480. hideMap: function() {
  6481. for (const indicator of this.indicators) game.renderer.npcs.removeAttachment(indicator);
  6482. for (const entities of game.renderer.scenery.attachments) entities.setAlpha(1);
  6483. game.renderer.scenery.setAlpha(1);
  6484. },
  6485. },
  6486. bossAlert: {
  6487. handlers: [{type: "keybind", names: ["DayCycle"]}],
  6488. init: function() {
  6489. this.bossAlert = document.createElement('p');
  6490. this.bossAlert.innerHTML = `<i class="fa fa-exclamation-triangle"></i> Boss wave incoming`;
  6491. this.bossAlert.style.display = "none";
  6492. this.bossAlert.style.color = "white";
  6493. this.bossAlert.style.opacity = '0.5';
  6494. getClass('hud-top-center')[0].appendChild(this.bossAlert);
  6495. },
  6496. DayCycle: function(e) {
  6497. if (!game.ui.playerTick) return;
  6498. if (e.isDay) this.bossAlert.style.display = (getIsNextWaveActive() && game.options.options.bossAlert) ? "block" : "none";
  6499. },
  6500. },
  6501. lockAim: {
  6502. handlers: [{type: "keybind", names: "keyup"}],
  6503. init: function() {
  6504. game.inputManager._emit = game.inputManager.emit;
  6505. game.inputManager.emit = function(...args) {
  6506. if (args[0].indexOf("mouse") > -1 && game.options.options.lockAim) return;
  6507. return this._emit(...args);
  6508. };
  6509. },
  6510. keyup: function(e) {
  6511. if (e.key == "u") game.options.options.lockAim = !game.options.options.lockAim;
  6512. },
  6513. },
  6514. /* @Rebinds */
  6515. sell: {
  6516. sellAllByType: function(type) {
  6517. if (!game.ui.playerPartyCanSell) return;
  6518. let lastSoldBuilding = null;
  6519. let allBuildings = [Infinity, ...Object.values(game.ui.buildings).filter(e => e.type == type)];
  6520. let sellInterval = () => {
  6521. if (!game.ui.buildings[lastSoldBuilding?.uid]) allBuildings.shift();
  6522. if (window.sellBreak || allBuildings.length == 0) return;
  6523. const target = allBuildings[0];
  6524. if (target !== undefined && !game.ui.buildings[target]?.dead) {
  6525. lastSoldBuilding = target;
  6526. Game.currentGame.network.sendRpc({
  6527. name: "DeleteBuilding",
  6528. uid: parseInt(target.uid)
  6529. });
  6530. setTimeout(sellInterval, 50);
  6531. };
  6532. };
  6533. sellInterval();
  6534. },
  6535. sellAllWithUids: function(uids) {
  6536. if (!game.ui.playerPartyCanSell) return;
  6537. let lastSoldBuilding = null;
  6538.  
  6539. uids = uids.filter(e => game.ui.buildings[e]?.type !== "GoldStash");
  6540. let allBuildings = [Infinity, ...uids];
  6541.  
  6542. let sellInterval = () => {
  6543. if (!game.ui.buildings[lastSoldBuilding]) allBuildings.shift();
  6544. if (window.sellBreak || allBuildings.length == 0) return;
  6545. const target = allBuildings[0];
  6546. if (target !== undefined && !game.ui.buildings[target]?.dead) {
  6547. lastSoldBuilding = target;
  6548. Game.currentGame.network.sendRpc({
  6549. name: "DeleteBuilding",
  6550. uid: parseInt(target)
  6551. });
  6552. setTimeout(sellInterval, 50);
  6553. };
  6554. };
  6555. sellInterval();
  6556. },
  6557. sellAll: function() {
  6558. this.isSellingAll = true;
  6559. const sellInterval = () => {
  6560. if (window.sellBreak) return;
  6561. if (Object.keys(game.ui.buildings).length > 1 && game.ui.playerPartyCanSell) {
  6562. Game.currentGame.network.sendRpc({
  6563. name: "DeleteBuilding",
  6564. uid: parseInt(Object.keys(game.ui.buildings)[1])
  6565. });
  6566. setTimeout(() => { sellInterval(); }, 100);
  6567. Object.keys(game.ui.buildings).length == 2 && (this.isSellingAll = false);
  6568. }
  6569. }
  6570. sellInterval();
  6571. },
  6572. sellBuilding: function () {
  6573. if (this.buildingUid) {
  6574. if ('GoldStash' == this.buildingId) {
  6575. game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all buildings?`, 5000, function() {
  6576. game.script.sell.sellAll();
  6577. });
  6578. return this.stopWatching();
  6579. }
  6580. if (this.shouldUpgradeAll) {
  6581. const id = this.buildingId;
  6582. game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all buildings of this type?`, 5000, function() {
  6583. game.script.sell.sellAllByType(id);
  6584. });
  6585. } else Game.currentGame.network.sendRpc({name: 'DeleteBuilding', uid: this.buildingUid});
  6586. };
  6587. },
  6588. init: function() {
  6589. game.ui.components.BuildingOverlay.sellBuilding = this.sellBuilding.bind(game.ui.components.BuildingOverlay);
  6590. },
  6591. },
  6592. chat: {
  6593. blockedUids: [],
  6594. emojiList: {
  6595. hmm: "https://cdn.discordapp.com/emojis/724365641963929611.png?size=48",
  6596. pog: "https://cdn.discordapp.com/emojis/721070353337811026.png?size=48",
  6597. pepehands: "https://cdn.discordapp.com/emojis/733406770139103293.png?size=48",
  6598. pepeEyes: "https://cdn.discordapp.com/emojis/869573233794486323.gif?size=48",
  6599. pepeHappy: "https://cdn.discordapp.com/emojis/801475958883614811.png?size=48",
  6600. sadge: "https://cdn.discordapp.com/emojis/826530556974989344.png?size=48",
  6601. ha: "https://cdn.discordapp.com/emojis/782756472886525953.png?size=48",
  6602. kekw: "https://cdn.discordapp.com/emojis/748511358076846183.png?size=48",
  6603. pogEyes: "https://cdn.discordapp.com/emojis/786979080406564885.png?size=48",
  6604. appalled: "https://cdn.discordapp.com/emojis/830880294881853530.png?size=48",
  6605. pogYou: "https://cdn.discordapp.com/emojis/790293794716516430.png?size=48",
  6606. pogChag: "https://cdn.discordapp.com/emojis/831156303497134090.png?size=48",
  6607. pogey: "https://cdn.discordapp.com/emojis/790293759861719050.png?size=48",
  6608. weirdChamp: "https://cdn.discordapp.com/emojis/757553915389673502.png?size=48",
  6609. monkaS: "https://cdn.discordapp.com/emojis/757179783573405766.png?size=48",
  6610. yep: "https://cdn.discordapp.com/emojis/758356179477987339.png?size=48",
  6611.  
  6612. weirdButOkay: "https://cdn.discordapp.com/emojis/831156194247966782.gif?size=48",
  6613. pogpogpogpog: "https://cdn.discordapp.com/emojis/869580566096379974.gif?size=48",
  6614. wooyeah: "https://cdn.discordapp.com/emojis/791008461420888084.gif?size=48",
  6615. idk: "https://cdn.discordapp.com/emojis/882513306164805642.gif?size=48",
  6616. },
  6617. blockPlayer: function(name, uid) {
  6618. game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to block ${window.filterXSS(name)} (${uid})?`, 3500, () => {
  6619. this.blockedUids.push(uid);
  6620. for (let bl of Array.from(document.getElementsByClassName(`uid${uid}`))) {
  6621. bl.innerHTML = "Unblock";
  6622. bl.style.color = "blue";
  6623. bl.onclick = () => this.unblockPlayer(name, uid);
  6624. };
  6625. }, () => {});
  6626. },
  6627. unblockPlayer: function(name, uid) {
  6628. this.blockedUids.splice(this.blockedUids.indexOf(uid), 1);
  6629. for (let bl of Array.from(document.getElementsByClassName(`uid${uid}`))) {
  6630. bl.innerHTML = "Block";
  6631. bl.style.color = "red";
  6632. bl.onclick = () => this.blockPlayer(name, uid);
  6633. };
  6634. },
  6635. onMessageReceived: function(e) {
  6636. if (this.blockedUids.includes(e.uid) || window.chatDisabled) return;
  6637. let a = Game.currentGame.ui.getComponent("Chat"),
  6638. b = window.filterXSS(e.displayName),
  6639. c = window.filterXSS(e.message)
  6640. .replace(/(?:f|F)uck/gi, `<img src="https://cdn.discordapp.com/emojis/907625398832070667.png?size=80" height="16" width="18" style="margin: 1px 0 0 0;"></img>`)
  6641. .replace(/s[3e]x+/gi, `<img src="https://cdn.discordapp.com/emojis/953759638350872666.gif?size=80&quality=lossless" height="16" width="18" style="margin: 1px 0 0 0;"></img>`)
  6642. .replace(/n+[i1]+gg+[a@]+/i, `<img src="https://cdn.discordapp.com/emojis/902742239996936226.webp?size=80" height="16" width="17" style="margin: 1px 0 0 0;"></img>`);
  6643. let arr = c.split(':');
  6644.  
  6645. for (let i = 1; i < arr.length; i += 2) {
  6646. if (!this.emojiList[arr[i]]) arr = [c];
  6647. else arr[i] = `<img src="${this.emojiList[arr[i]]}" height="16" width="18" style="margin: 1px 0 0 0;"></img>`;
  6648. }
  6649.  
  6650. let d = a.ui.createElement(`<div class="hud-chat-message"><a href="javascript:void(0);" style="color: red;margin: 0 5px 0 0;display: inline-block;" class="uid${e.uid}">Block</a><strong> ${b}</strong>: ${arr.join(" ")}<small>${getClock()}</small></div>`);
  6651. d.children[0].onclick = () => game.script.chat.blockPlayer(b, e.uid);
  6652. a.messagesElem.appendChild(d);
  6653. a.messagesElem.scrollTop = a.messagesElem.scrollHeight;
  6654. },
  6655. init: function() {
  6656. Game.currentGame.network.emitter.removeListener("PACKET_RPC", Game.currentGame.network.emitter._events.PACKET_RPC[1]);
  6657. Game.currentGame.network.addRpcHandler("ReceiveChatMessage", this.onMessageReceived.bind(this));
  6658. document.addEventListener('keyup', function(e) {
  6659. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  6660. if (e.key == "Enter") {
  6661. (game.ui?.playerTick?.dead === 1) && game.ui.components.Chat.startTyping();
  6662. };
  6663. };
  6664. });
  6665. },
  6666. },
  6667. parties: {
  6668. serverPopulation: 0,
  6669.  
  6670. partyMenu: getClass("hud-menu-party")[0],
  6671. partyTabs: getClass("hud-party-tabs")[0],
  6672.  
  6673. partyMembers: getClass("hud-party-members")[0],
  6674. partyGrid: getClass("hud-party-grid")[0],
  6675. closedParties: null,
  6676. shareKeyLog: null,
  6677.  
  6678. init: function() {
  6679. this.partyMembers.style.display = "block";
  6680. this.partyGrid.style.display = "none";
  6681.  
  6682. const privateTab2 = document.createElement("a");
  6683. privateTab2.className = "hud-party-tabs-link";
  6684. privateTab2.id = "privateTab2";
  6685. privateTab2.innerHTML = "Closed Parties";
  6686.  
  6687. this.closedParties = document.createElement("div");
  6688. this.closedParties.className = "hud-private hud-party-grid";
  6689. this.closedParties.id = "privateHud2";
  6690. this.closedParties.style.display = "none";
  6691.  
  6692. this.partyTabs.appendChild(privateTab2);
  6693. this.partyMenu.insertBefore(this.closedParties, getClass("hud-party-actions")[0]);
  6694.  
  6695.  
  6696. const privateTab = document.createElement("a");
  6697. privateTab.className = "hud-party-tabs-link";
  6698. privateTab.id = "privateTab";
  6699. privateTab.innerHTML = "Key Logs";
  6700.  
  6701. this.shareKeyLog = document.createElement("div");
  6702. this.shareKeyLog.className = "hud-private hud-party-grid";
  6703. this.shareKeyLog.id = "privateHud";
  6704. this.shareKeyLog.style.display = "none";
  6705.  
  6706. this.partyTabs.appendChild(privateTab);
  6707. this.partyMenu.insertBefore(this.shareKeyLog, getClass("hud-party-actions")[0]);
  6708.  
  6709. privateTab.addEventListener("click", e => {
  6710. for (let menu of [this.partyMembers, this.partyGrid, this.closedParties, this.shareKeyLog]) {
  6711. menu.style.display == "block" && (menu.style.display = "none");
  6712. }
  6713.  
  6714. for (let i of getClass("hud-party-tabs-link")) i.className = "hud-party-tabs-link";
  6715. privateTab.className = "hud-party-tabs-link is-active";
  6716.  
  6717. this.shareKeyLog.style.display = "block";
  6718. })
  6719.  
  6720. privateTab2.addEventListener("click", e => {
  6721. for (let menu of [this.partyMembers, this.partyGrid, this.closedParties, this.shareKeyLog]) {
  6722. menu.style.display == "block" && (menu.style.display = "none");
  6723. }
  6724.  
  6725. for (let i of getClass("hud-party-tabs-link")) i.className = "hud-party-tabs-link";
  6726. privateTab2.className = "hud-party-tabs-link is-active";
  6727.  
  6728. this.closedParties.style.display = "block";
  6729. })
  6730.  
  6731. getClass("hud-party-tabs-link")[0].addEventListener("click", e => {
  6732. this.shareKeyLog.style.display = "none";
  6733. privateTab.className = "hud-party-tabs-link";
  6734.  
  6735. this.closedParties.style.display = "none";
  6736. privateTab2.className = "hud-party-tabs-link";
  6737. })
  6738.  
  6739. getClass("hud-party-tabs-link")[1].addEventListener("click", e => {
  6740. this.shareKeyLog.style.display = "none";
  6741. privateTab.className = "hud-party-tabs-link";
  6742.  
  6743. this.closedParties.style.display = "none";
  6744. privateTab2.className = "hud-party-tabs-link";
  6745. });
  6746. game.network.addRpcHandler("PartyShareKey", (e) => game.script.parties.onPartyShareKey(e));
  6747. game.network.addRpcHandler("SetPartyList", (e) => game.script.parties.onSetPartyList(e));
  6748. },
  6749. onSetPartyList: function(parties) {
  6750. this.serverPopulation = 0;
  6751. for (let party of parties) {
  6752. this.serverPopulation += party.memberCount;
  6753. }
  6754. document.getElementsByClassName("hud-party-server")[0].innerHTML = `${this.serverPopulation}/32<small id="serverRegion"></small>`;
  6755. },
  6756. onPartyShareKey: function(e) {
  6757. const psk = e.partyShareKey,
  6758. lnk = `https://zombs.io/#/${game.options.serverId}/${psk}/`;
  6759. this.shareKeyLog.innerHTML += `
  6760. <div style="display:inline-block;margin:10px 5px 0;">
  6761. <li>
  6762. <strong
  6763. style="cursor: pointer;" onclick="game.network.sendRpc({ name: 'JoinPartyByShareKey', partyShareKey: '${psk}' });">${psk}
  6764. </strong> - <a href="${lnk}" target="_blank" color="purple">
  6765. [Link]
  6766. </a>
  6767. </li>
  6768. </div>
  6769. <br />
  6770. `;
  6771. },
  6772. },
  6773. /* @NonToggle */
  6774. builder: {
  6775. buildBase: function(design) {
  6776. const goldStash = Object.values(game.ui.buildings).find(building => building.type == "GoldStash");
  6777.  
  6778. if (typeof design !== "string") throw new Error("Argument must be given as a string.");
  6779. if (goldStash === undefined) throw new Error("You must have a gold stash to be able to use this.");
  6780.  
  6781. const towers = design.split(";");
  6782.  
  6783. for (let towerStr of towers) {
  6784. const tower = towerStr.split(",");
  6785.  
  6786. if (tower[0] === "") continue;
  6787. if (tower.length < 4) throw new Error(`${JSON.stringify(tower)} contains an issue that must be fixed before this design can be replicated.`);
  6788.  
  6789. Game.currentGame.network.sendRpc({
  6790. name: "MakeBuilding",
  6791. type: towerCodes[parseInt(tower[0])],
  6792. x: goldStash.x - parseInt(tower[1]),
  6793. y: goldStash.y - parseInt(tower[2]),
  6794. yaw: parseInt(tower[3])
  6795. });
  6796. };
  6797. },
  6798.  
  6799. recordBase: function(pasteValue = true) {
  6800. const goldStash = Object.values(game.ui.buildings).find(building => building.type == "GoldStash");
  6801. let baseStr = "";
  6802. for (let i in game.ui.buildings) {
  6803. const building = game.ui.buildings[i];
  6804. if (towerCodes.indexOf(building.type) < 0) continue;
  6805.  
  6806. let yaw = 0;
  6807.  
  6808. if (["Harvester", "MeleeTower"].includes(building.type)) {
  6809. if (game.world.entities[building.uid] !== undefined) yaw = game.world.entities[building.uid].targetTick.yaw;
  6810. }
  6811. baseStr += `${towerCodes.indexOf(building.type)},${goldStash.x - building.x},${goldStash.y - building.y},${yaw};`;
  6812. }
  6813. if (pasteValue) getId('target-base-design').value = baseStr;
  6814. else return baseStr;
  6815. },
  6816. calculateResourceNeeded(design) {
  6817. const rssNeeded = {wood: 0, stone: 0};
  6818. const schema = game.ui.buildingSchema;
  6819.  
  6820. if (typeof design !== "string") throw new Error("Argument must be given as a string.");
  6821.  
  6822. const towers = design.split(";");
  6823. for (let towerStr of towers) {
  6824. const tower = towerStr.split(",");
  6825.  
  6826. if (tower[0] === "") continue;
  6827. if (tower.length < 4) throw new Error(`${JSON.stringify(tower)} contains an issue that must be fixed before this design can be calculated for resources needed.`);
  6828.  
  6829. rssNeeded.wood += schema[towerCodes[parseInt(tower[0])]].woodCosts[0];
  6830. rssNeeded.stone += schema[towerCodes[parseInt(tower[0])]].stoneCosts[0];
  6831. };
  6832. return rssNeeded;
  6833. },
  6834. calculateNeededPlayers(design) {
  6835. if (typeof design !== "string") throw new Error("Argument must be given as a string.");
  6836.  
  6837. const allTowers = {};
  6838. const schema = game.ui.buildingSchema;
  6839.  
  6840. const towers = design.split(";");
  6841. for (let towerStr of towers) {
  6842. const tower = towerStr.split(",");
  6843.  
  6844. if (tower[0] === "") continue;
  6845. if (tower.length < 4) throw new Error(`${JSON.stringify(tower)} contains an issue that must be fixed before this design can be calculated for resources needed.`);
  6846.  
  6847. allTowers[tower[0]] ||= 0;
  6848. allTowers[tower[0]]++;
  6849. };
  6850. let highestNeededAmount = 1;
  6851. for (const towerName in allTowers) {
  6852. const amount = allTowers[towerName];
  6853. const neededAmount = Math.ceil(amount / (schema[towerCodes[parseInt(towerName)]].limit / game.ui.playerPartyMembers.length));
  6854. neededAmount > highestNeededAmount && (highestNeededAmount = neededAmount);
  6855. };
  6856. return highestNeededAmount;
  6857. },
  6858. showOverlay: function (design, timeout) {
  6859. const goldStash = Object.values(game.ui.buildings).find(building => building.type == "GoldStash");
  6860.  
  6861. if (typeof design !== "string") throw new Error("Argument must be given as a string.");
  6862. if (goldStash === null) throw new Error("You must have a gold stash to be able to use this.");
  6863.  
  6864. this.overlayEntities && (this.overlayEntities.length > 0 && this.overlayEntities.map(e => game.renderer.ui.removeAttachment(e)));
  6865. this.overlayEntities = [];
  6866. this.overlayDesign = design;
  6867. this.isShowingOverlay = true;
  6868. game.renderer.follow(game.world.entities[goldStash.uid]);
  6869. setTimeout(() => {
  6870. const towers = design.split(";"),
  6871. schema = game.ui.getBuildingSchema();
  6872.  
  6873. for (let towerStr of towers) {
  6874. const towerData = towerStr.split(",");
  6875. const [type, xWorld, yWorld, yaw] = towerData;
  6876. const towerLength = towerData.length
  6877.  
  6878. if (type === "") continue;
  6879. if (towerLength.length < 4) throw new Error(`${JSON.stringify(towerLength)} contains an issue that must be fixed before this design can be replicated.`);
  6880.  
  6881. const buildingType = schema[towerCodes[parseInt(type)]],
  6882. placeholderEntity = Game.currentGame.assetManager.loadModel(buildingType.modelName, {}),
  6883. { x, y } = game.renderer.worldToUi(goldStash.x - parseInt(xWorld), goldStash.y - parseInt(yWorld));
  6884. placeholderEntity.setAlpha(0.5);
  6885. placeholderEntity.setRotation(parseInt(yaw));
  6886. placeholderEntity.setPosition(x, y);
  6887.  
  6888. Game.currentGame.renderer.ui.addAttachment(placeholderEntity);
  6889. this.overlayEntities.push(placeholderEntity);
  6890. }
  6891. timeout && setTimeout(this.hideOverlay.bind(this), timeout);
  6892. }, 50);
  6893. },
  6894.  
  6895. hideOverlay: function() {
  6896. for (let entity of this.overlayEntities) game.renderer.ui.removeAttachment(entity);
  6897. game.renderer.follow(game.world.entities[game.world.myUid]);
  6898. this.isShowingOverlay = false;
  6899. this.overlayDesign = null;
  6900. },
  6901.  
  6902. onResize: function() {
  6903. this.isShowingOverlay && this.showOverlay(this.overlayDesign);
  6904. },
  6905. init: function() {
  6906. window.addEventListener("resize", this.onResize.bind(this));
  6907. document.addEventListener("zoom", this.onResize.bind(this));
  6908. },
  6909. },
  6910. sessions: {
  6911. SESSION_CREATE_TIMEOUT: 15000,
  6912. SESSION_FETCH_TIMEOUT: 10000,
  6913.  
  6914. staticJSONs: [{name:"BuildingShopPrices",response:{json:'[{"Name":"Wall","Class":"PlayerObject","GoldCosts":[0,5,30,60,80,100,250,800],"WoodCosts":[2,0,0,0,0,0,0,0],"StoneCosts":[0,2,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0,0],"Width":47.99,"Height":47.99,"Health":[150,200,300,400,600,800,1500,2500],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[5,7,12,17,25,40,80,250]},{"Name":"GoldStash","Class":"GoldStash","GoldCosts":[0,5000,10000,16000,20000,32000,100000,400000],"WoodCosts":[0,0,0,0,0,0,0,0],"StoneCosts":[0,0,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0,0],"Width":95.99,"Height":95.99,"Health":[1500,1800,2300,3000,5000,8000,12000,20000],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[50,60,70,90,110,150,400,700]},{"Name":"GoldMine","Class":"GoldMine","GoldCosts":[0,200,300,600,800,1200,8000,30000],"WoodCosts":[5,15,25,35,45,55,700,1600],"StoneCosts":[5,15,25,35,45,55,700,1600],"TokenCosts":[0,0,0,0,0,0,0,0],"Width":95.99,"Height":95.99,"Health":[150,250,350,500,800,1400,1800,2800],"GoldPerSecond":[4,6,7,10,12,15,25,35],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[5,7,12,17,25,40,70,120]},{"Name":"Door","Class":"Door","GoldCosts":[0,10,50,70,150,200,400,800],"WoodCosts":[5,5,0,0,0,0,0,0],"StoneCosts":[5,5,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0,0],"Width":47.99,"Height":47.99,"Health":[150,200,300,500,700,1000,1500,2000],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,1000],"HealthRegenPerSecond":[5,7,12,17,25,40,70,100]},{"Name":"CannonTower","Class":"Tower","GoldCosts":[0,100,200,600,1200,2000,8000,35000],"WoodCosts":[15,25,30,40,60,80,300,800],"StoneCosts":[15,25,40,50,80,120,300,800],"TokenCosts":[0,0,0,0,0,0,0,0],"TowerRadius":[500,500,500,500,600,600,600,600],"MsBetweenFires":[1000,769,625,500,400,350,250,250],"Height":95.99,"Width":95.99,"Health":[150,200,400,800,1200,1600,2200,3600],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,110,150],"DamageToZombies":[20,30,50,70,120,150,200,300],"DamageToPlayers":[5,5,6,6,7,7,8,8],"DamageToPets":[5,5,5,5,5,5,6,8],"DamageToNeutrals":[250,350,450,550,650,750,850,1000],"ProjectileLifetime":[1000,1000,1000,1000,1000,1000,1000,1000],"ProjectileVelocity":[60,65,70,70,75,80,100,140],"ProjectileName":"CannonProjectile","ProjectileAoe":[true,true,true,true,true,true,true,true],"ProjectileAoeRadius":[250,250,250,250,250,250,250,250],"ProjectileCollisionRadius":[10,10,10,10,10,10,10,10]},{"Name":"ArrowTower","Class":"ArrowTower","GoldCosts":[0,100,200,600,1200,2000,8000,35000],"WoodCosts":[5,25,30,40,50,70,300,800],"StoneCosts":[5,20,30,40,60,80,300,800],"TokenCosts":[0,0,0,0,0,0,0,0],"TowerRadius":[600,650,700,750,800,850,900,1000],"MsBetweenFires":[400,333,285,250,250,250,250,250],"Height":95.99,"Width":95.99,"Health":[150,200,400,800,1200,1600,2200,3600],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,110,150],"DamageToZombies":[20,40,70,120,180,250,400,500],"DamageToPlayers":[5,5,6,6,7,7,8,8],"DamageToPets":[5,5,5,5,5,5,6,6],"DamageToNeutrals":[250,350,450,550,650,750,850,1000],"ProjectileLifetime":[1300,1300,1300,1300,1300,1300,1300,1300],"ProjectileVelocity":[60,65,70,70,75,80,120,140],"ProjectileName":"ArrowProjectile","ProjectileAoe":[false,false,false,false,false,false,false,false],"ProjectileCollisionRadius":[10,10,10,10,10,10,10,10]},{"Name":"Harvester","Class":"Harvester","GoldCosts":[0,100,200,600,1200,2000,8000,10000],"WoodCosts":[5,25,30,40,50,70,300,600],"StoneCosts":[5,20,30,40,60,80,300,600],"TokenCosts":[0,0,0,0,0,0,0,0],"Height":95.99,"Width":95.99,"Health":[150,200,400,800,1200,1600,2200,2800],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,110,130],"HarvestAmount":[2.5,4.65,4.55,7.2,8.25,10,13.5,16],"HarvestCooldown":[1500,1400,1300,1200,1100,1000,900,800],"HarvestMax":[400,800,1200,1600,2000,2400,2800,3600],"HarvestRange":[300,300,300,300,300,300,300,300],"DepositCostPerMinute":[200,300,350,500,600,700,1200,1400],"DepositMax":[800,1200,1400,2000,2400,2800,4800,6000],"MaxYawDeviation":[70,70,70,70,70,70,70,70]},{"Name":"BombTower","Class":"Tower","GoldCosts":[0,100,200,600,1200,2000,8000,35000],"WoodCosts":[10,25,40,50,80,120,300,800],"StoneCosts":[10,25,40,50,80,120,300,800],"TokenCosts":[0,0,0,0,0,0,0,0],"TowerRadius":[1000,1000,1000,1000,1000,1000,1000,1000],"MsBetweenFires":[1000,1000,1000,1000,1000,1000,900,900],"Height":95.99,"Width":95.99,"Health":[150,200,400,800,1200,1600,2200,3600],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,110,150],"DamageToZombies":[30,60,100,140,200,600,1200,1600],"DamageToPlayers":[9,9,10,10,11,11,12,12],"DamageToPets":[10,10,10,10,10,10,10,10],"DamageToNeutrals":[250,350,450,550,650,750,850,1000],"ProjectileLifetime":[1000,1000,1000,1000,1000,1000,1000,1000],"ProjectileVelocity":[20,20,20,20,20,20,20,20],"ProjectileName":"BombProjectile","ProjectileAoe":[true,true,true,true,true,true,true,true],"ProjectileIgnoresCollisions":[true,true,true,true,true,true,true,true],"ProjectileAoeRadius":[250,250,250,250,250,250,250,250],"ProjectileCollisionRadius":[10,10,10,10,10,10,10,10],"ProjectileMaxRange":[1000,1000,1000,1000,1000,1000,1000,1000]},{"Name":"MagicTower","Class":"MagicTower","GoldCosts":[0,100,200,600,1200,2000,8000,35000],"WoodCosts":[15,25,40,50,70,100,300,800],"StoneCosts":[15,25,40,50,70,100,300,800],"TokenCosts":[0,0,0,0,0,0,0,0],"TowerRadius":[400,400,400,400,400,400,400,400],"MsBetweenFires":[800,800,700,600,500,400,300,300],"Height":95.99,"Width":95.99,"Health":[150,200,400,800,1200,1600,2200,3600],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,110,150],"DamageToZombies":[10,20,40,50,70,80,120,160],"DamageToPlayers":[5,5,5,6,6,6,7,7],"DamageToPets":[5,5,5,5,5,5,5,5],"DamageToNeutrals":[250,350,450,550,650,750,850,1000],"ProjectileLifetime":[500,500,500,500,500,500,500,500],"ProjectileVelocity":[45,45,45,45,45,45,45,45],"ProjectileName":"FireballProjectile","ProjectileAoe":[true,true,true,true,true,true,true,true],"ProjectileAoeRadius":[100,100,100,100,100,100,100,100],"ProjectileCollisionRadius":[10,10,10,10,10,10,10,10]},{"Name":"MeleeTower","Class":"MeleeTower","GoldCosts":[0,100,200,600,1200,2000,8000,35000],"WoodCosts":[10,25,30,40,50,70,300,800],"StoneCosts":[10,20,30,40,60,80,300,800],"TokenCosts":[0,0,0,0,0,0,0,0],"TowerRadius":[110,110,110,110,110,110,110,110],"MsBetweenFires":[400,333,285,250,250,250,250,250],"Height":95.99,"Width":95.99,"Health":[200,400,800,1200,1600,2200,4000,9000],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,220,350],"DamageToZombies":[80,120,200,280,500,1000,2000,3000],"DamageToPlayers":[5,6,7,8,9,10,11,12],"DamageToPets":[5,5,5,5,5,5,6,6],"DamageToNeutrals":[250,350,450,550,650,750,850,1000],"MaxYawDeviation":[30,30,30,30,30,30,30,30]},{"Name":"SlowTrap","Class":"Trap","GoldCosts":[0,100,200,400,600,800,1000,1500],"WoodCosts":[5,25,30,40,50,70,300,800],"StoneCosts":[5,20,30,40,60,80,300,800],"TokenCosts":[0,0,0,0,0,0,0,0],"Height":47.99,"Width":47.99,"Health":[150,200,400,800,1200,1600,2200,3000],"MsBeforeRegen":[10000,10000,10000,10000,10000,10000,10000,10000],"HealthRegenPerSecond":[2,5,10,20,40,80,110,150],"SlowDuration":[2500,2500,2500,3000,3000,3250,3500,4000],"SlowAmount":[0.4,0.45,0.5,0.55,0.6,0.65,0.7,0.7]}]'},opcode:9},{name:"ItemShopPrices",response:{json:'[{"Name":"Spear","Class":"MeleeWeapon","MsBetweenFires":[250,250,250,250,250,250,250],"DamageToZombies":[30,80,120,300,2000,8000,10000],"DamageToNeutrals":[50,80,100,200,250,400,600],"DamageToBuildings":[0.75,1.5,2.25,3,3.75,4.5,5.25],"DamageToPlayers":[15,16,17,18,20,22,22],"DamageToPets":[3,3.5,4,4.5,5,5.5,5.5],"GoldCosts":[1400,2800,5600,11200,22500,45000,90000],"StoneCosts":[0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0],"Range":[100,100,100,100,100,100,100],"MaxYawDeviation":[50,50,50,50,50,50,50]},{"Name":"Pickaxe","Class":"MeleeWeapon","MsBetweenFires":[300,300,285,250,200,200,200],"DamageToZombies":[20,20,20,20,20,20,20],"DamageToBuildings":[0,0,0,0,0,0,0],"DamageToPlayers":[0,0,0,0,0,0,0],"DamageToNeutrals":[10,10,10,10,10,10,10],"DamageToPets":[0,0,0,0,0,0,0],"GoldCosts":[0,1000,3000,6000,8000,24000,90000],"StoneCosts":[0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0],"Range":[100,100,100,100,100,100,100],"MaxYawDeviation":[70,70,70,70,70,70,70],"IsTool":true,"HarvestCount":[1,2,2,3,3,4,6]},{"Name":"Bow","Class":"RangedWeapon","DamageToZombies":[20,40,100,300,2400,10000,14000],"DamageToBuildings":[2,2.3,2.5,2.7,3,3,3],"DamageToPlayers":[22,24,26,28,30,32,32],"DamageToNeutrals":[50,100,150,200,250,400,700],"DamageToPets":[2,2.3,2.5,2.7,3,3,3],"GoldCosts":[100,400,2000,7000,24000,30000,90000],"StoneCosts":[0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0],"MsBetweenFires":[500,500,500,500,500,500,500],"ChargeTime":[150,150,150,150,150,150,150],"ProjectileVelocity":[100,100,100,100,100,100,100],"ProjectileName":"BowProjectile","ProjectileCollisionRadius":[10,10,10,10,10,10,10],"ProjectileLifetime":[550,550,550,550,550,550,550]},{"Name":"Bomb","Class":"RangedWeapon","GoldCosts":[100,400,3000,5000,24000,30000,90000],"DamageToNeutrals":[50,100,150,200,250,300,500],"StoneCosts":[0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0],"MsBetweenFires":[500,500,500,500,500,500,500],"DamageToZombies":[10,30,80,150,1200,6000,9000],"DamageToBuildings":[1,1,1,1,1,1,1],"DamageToPlayers":[20,22,24,26,28,30,30],"DamageToPets":[1,1,1,1,1,1,1],"ProjectileVelocity":[40,40,40,40,40,40,40],"ProjectileName":"BombProjectile","ProjectileCollisionRadius":[10,10,10,10,10,10,10],"ProjectileLifetime":[700,700,700,700,700,700,700],"ProjectileAoe":[true,true,true,true,true,true,true],"ProjectileAoeRadius":[50,50,50,50,50,50,50],"ProjectileIgnoresCollisions":[false,false,false,false,false,false,false],"ProjectileMaxRange":[700,700,700,700,700,700,700]},{"Name":"HealthPotion","Class":"HealthPotion","GoldCosts":[100],"StoneCosts":[0],"WoodCosts":[0],"TokenCosts":[0],"PurchaseCooldown":15000},{"Name":"ZombieShield","Class":"ZombieShield","GoldCosts":[1000,3000,7000,14000,18000,22000,24000,30000,45000,70000],"StoneCosts":[0,0,0,0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0,0,0,0],"TokenCosts":[0,0,0,0,0,0,0,0,0,0],"Health":[500,1000,1800,4000,10000,20000,35000,50000,65000,85000],"RechargePerSecond":[50,100,200,400,1000,2000,3500,5000,6500,8500],"MsBeforeRecharge":[10000,9000,8000,7000,6000,6000,6000,6000,6000,6000]},{"Name":"Pause","Class":"Pause","GoldCosts":[10000],"StoneCosts":[0],"WoodCosts":[0],"TokenCosts":[0],"PurchaseCooldown":240000},{"Name":"PetMiner","Class":"Pet","GoldCosts":[0,0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0,0],"StoneCosts":[0,0,0,0,0,0,0,0],"TokenCosts":[0,100,100,100,100,200,200,300],"CollisionRadius":25,"Health":[400,800,1500,3000,5000,8000,10000,16000],"MsBeforeRegen":[8000,8000,8000,8000,8000,8000,8000,8000],"HealthRegenPerSecond":[5,5,5,5,5,5,5,5],"Speed":[30,32,34,35,35,37,37,38],"DamageToNeutrals":[80,100,150,200,250,400,500,600],"HarvestCount":[1,1,2,2,3,3,4,4],"Ranged":[false,false,false,false,false,false,false,false],"CanAttackPlayers":[false,false,false,false,false,false,false,false],"CanMine":[true,true,true,true,true,true,true,true],"LeashRange":[500,500,500,500,500,500,500,500],"HarvestLeashRange":[0,0,0,0,0,0,0,0],"AttackRange":[80,80,80,80,80,80,80,80],"MsBetweenFires":[500,450,450,400,400,380,380,350],"EvolvesAtLevel":[0,8,16,24,32,48,64,96],"ExperienceFromMiningPerHalfSecond":[1,1,1,1,1,1,1,1]},{"Name":"PetCARL","Class":"Pet","GoldCosts":[0,0,0,0,0,0,0,0],"WoodCosts":[0,0,0,0,0,0,0,0],"StoneCosts":[0,0,0,0,0,0,0,0],"TokenCosts":[0,100,100,100,100,200,200,300],"CollisionRadius":25,"Health":[400,800,1500,3000,5000,8000,10000,16000],"MsBeforeRegen":[8000,8000,8000,8000,8000,8000,8000,8000],"HealthRegenPerSecond":[5,5,5,5,5,5,5,5],"Speed":[30,32,34,35,35,37,37,38],"DamageToNeutrals":[80,100,150,200,250,400,500,600],"Ranged":[false,false,false,false,false,false,false,false],"CanAttackPlayers":[true,true,true,true,true,true,true,true],"LeashRange":[500,500,500,500,500,500,500,500],"AttackRange":[80,80,80,80,80,80,80,80],"MsBetweenFires":[500,490,490,490,480,480,470,470],"ProjectileLifetime":[1000,1000,1000,1000,1000,1000,1000,1000],"ProjectileVelocity":[60,60,60,60,60,60,60,60],"ProjectileName":"PetCARLProjectile","ProjectileAoe":[true,true,true,true,true,true,true,true],"ProjectileAoeRadius":[250,250,250,250,250,250,250,250],"ProjectileCollisionRadius":[10,10,10,10,10,10,10,10],"DamageToZombies":[30,100,400,600,1000,3000,6000,8000],"DamageToPlayers":[30,31,32,33,34,35,36,37],"DamageToBuildings":[2,2,2,3,3,3,4,4],"EvolvesAtLevel":[0,8,16,24,32,48,64,96],"ExperienceFromZombies":[30,28,25,25,25,25,25,25],"ExperienceFromNeutrals":[30,28,25,25,25,25,25,25]},{"Name":"HatHorns","Class":"Hat","GoldCosts":[0],"WoodCosts":[0],"StoneCosts":[0],"TokenCosts":[0]},{"Name":"PetHealthPotion","Class":"PetHealthPotion","GoldCosts":[100],"StoneCosts":[0],"WoodCosts":[0],"TokenCosts":[0]},{"Name":"PetWhistle","Class":"PetWhistle","GoldCosts":[0],"StoneCosts":[0],"WoodCosts":[0],"TokenCosts":[0]},{"Name":"PetRevive","Class":"PetRevive","GoldCosts":[0],"StoneCosts":[0],"WoodCosts":[0],"TokenCosts":[0]}]'},opcode:9},{name:"Spells",response:{json:'[{"Name":"HealTowersSpell","VisualLifetime":10000,"VisualRadius":600,"Cooldown":[240000],"IsCooldownForParty":true,"Healing":[{"Type":"Tower","Amount":[50],"Over":[10000],"Radius":[600]}],"GoldCosts":[1000],"WoodCosts":[0],"StoneCosts":[0],"TokenCosts":[0]}]'},opcode:9}],
  6915. codecJSON: '{"attributeMaps":{"667546015":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1},{"name":"lastPetDamage","type":3},{"name":"lastPetDamageTick","type":1},{"name":"lastPetDamageTarget","type":1},{"name":"firingTick","type":1},{"name":"experience","type":1},{"name":"stoneGain","type":3},{"name":"woodGain","type":3},{"name":"stoneGainTick","type":1},{"name":"woodGainTick","type":1}],"742594995":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1}],"1059671174":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"firingTick","type":1},{"name":"lastDamagedTick","type":1}],"1372600389":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"hits","type":8}],"1496910567":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"firingTick","type":1}],"1566069472":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1}],"1672634632":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1}],"1816895259":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1}],"2092990061":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1}],"2093252446":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"hits","type":8}],"2347737811":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"reconnectSecret","type":4},{"name":"name","type":4},{"name":"score","type":13},{"name":"baseSpeed","type":3},{"name":"speedAttribute","type":3},{"name":"availableSkillPoints","type":2},{"name":"experience","type":3},{"name":"level","type":1},{"name":"msBetweenFires","type":3},{"name":"aimingYaw","type":2},{"name":"energy","type":3},{"name":"maxEnergy","type":3},{"name":"energyRegenerationRate","type":3},{"name":"kills","type":2},{"name":"weaponName","type":4},{"name":"weaponTier","type":1},{"name":"firingTick","type":1},{"name":"startChargingTick","type":1},{"name":"stone","type":15},{"name":"wood","type":15},{"name":"gold","type":15},{"name":"token","type":15},{"name":"wave","type":1},{"name":"partyId","type":1},{"name":"zombieShieldHealth","type":3},{"name":"zombieShieldMaxHealth","type":3},{"name":"isPaused","type":1},{"name":"isInvulnerable","type":1},{"name":"lastPetDamage","type":3},{"name":"lastPetDamageTick","type":1},{"name":"lastPetDamageTarget","type":1},{"name":"lastDamage","type":3},{"name":"lastDamageTick","type":1},{"name":"lastDamageTarget","type":1},{"name":"hatName","type":4},{"name":"petUid","type":1},{"name":"isBuildingWalking","type":10}],"2402467733":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1}],"2462472648":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1}],"2464630638":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1}],"2899981078":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1},{"name":"harvestMax","type":1},{"name":"stone","type":1},{"name":"wood","type":1},{"name":"firingTick","type":1},{"name":"deposit","type":3},{"name":"depositMax","type":3},{"name":"lastHarvestedBy","type":4}],"2969697641":[{"name":"position","type":5},{"name":"yaw","type":2},{"name":"health","type":3},{"name":"maxHealth","type":3},{"name":"damage","type":3},{"name":"height","type":3},{"name":"width","type":3},{"name":"collisionRadius","type":1},{"name":"model","type":4},{"name":"entityClass","type":4},{"name":"dead","type":1},{"name":"timeDead","type":3},{"name":"slowed","type":1},{"name":"stunned","type":1},{"name":"tier","type":1},{"name":"partyId","type":1},{"name":"towerYaw","type":3},{"name":"firingTick","type":1},{"name":"healingTick","type":1}]},"entityTypeNames":{"667546015":"Pet","742594995":"GoldMine","1059671174":"Zombie","1372600389":"Stone","1496910567":"Neutral","1566069472":"PlayerObject","1672634632":"NeutralCamp","1816895259":"GameProjectile","2092990061":"Trap","2093252446":"Tree","2347737811":"GamePlayer","2402467733":"GoldStash","2462472648":"Spell","2464630638":"Door","2899981078":"Harvester","2969697641":"Tower"},"rpcMaps":[{"name":"Shutdown","parameters":[{"name":"reason","type":3},{"name":"shutdownUnix","type":0}],"isArray":false,"index":0},{"name":"ReceiveChatMessage","parameters":[{"name":"displayName","type":3},{"name":"channel","type":3},{"name":"message","type":3},{"name":"uid","type":0}],"isArray":false,"index":1},{"name":"SendChatMessage","parameters":[{"name":"channel","type":3},{"name":"message","type":3}],"isArray":false,"index":2},{"name":"Login","parameters":[{"name":"token","type":3}],"isArray":false,"index":3},{"name":"LoginResponse","parameters":[{"name":"json","type":3}],"isArray":false,"index":4},{"name":"AccountSession","parameters":[{"name":"json","type":3}],"isArray":false,"index":5},{"name":"Metrics","parameters":[{"name":"minFps","type":2},{"name":"maxFps","type":2},{"name":"currentFps","type":2},{"name":"averageFps","type":2},{"name":"framesRendered","type":2},{"name":"framesInterpolated","type":2},{"name":"framesExtrapolated","type":2},{"name":"allocatedNetworkEntities","type":2},{"name":"currentClientLag","type":2},{"name":"minClientLag","type":2},{"name":"maxClientLag","type":2},{"name":"currentPing","type":2},{"name":"minPing","type":2},{"name":"maxPing","type":2},{"name":"averagePing","type":2},{"name":"longFrames","type":2},{"name":"stutters","type":2},{"name":"group","type":0},{"name":"isMobile","type":0},{"name":"timeResets","type":2},{"name":"maxExtrapolationTime","type":2},{"name":"extrapolationIncidents","type":2},{"name":"totalExtrapolationTime","type":2},{"name":"differenceInClientTime","type":2}],"isArray":false,"index":6},{"name":"DayCycle","parameters":[{"name":"cycleStartTick","type":0},{"name":"nightEndTick","type":0},{"name":"dayEndTick","type":0},{"name":"isDay","type":0}],"isArray":false,"index":7},{"name":"MakeBuilding","parameters":[{"name":"x","type":1},{"name":"y","type":1},{"name":"type","type":3},{"name":"yaw","type":1}],"isArray":false,"index":8},{"name":"BuildingShopPrices","parameters":[{"name":"json","type":3}],"isArray":false,"index":9},{"name":"ItemShopPrices","parameters":[{"name":"json","type":3},{"name":"json","type":3}],"isArray":false,"index":10},{"name":"LocalBuilding","parameters":[{"name":"x","type":1},{"name":"y","type":1},{"name":"type","type":3},{"name":"dead","type":0},{"name":"uid","type":0},{"name":"tier","type":0}],"isArray":true,"index":11},{"name":"Dead","parameters":[{"name":"stashDied","type":0}],"isArray":false,"index":12},{"name":"Admin","parameters":[{"name":"password","type":3},{"name":"command","type":3}],"isArray":false,"index":13},{"name":"UpgradeBuilding","parameters":[{"name":"uid","type":0}],"isArray":false,"index":14},{"name":"DeleteBuilding","parameters":[{"name":"uid","type":0}],"isArray":false,"index":15},{"name":"BuyItem","parameters":[{"name":"itemName","type":3},{"name":"tier","type":0}],"isArray":false,"index":16},{"name":"SetItem","parameters":[{"name":"itemName","type":3},{"name":"tier","type":0},{"name":"stacks","type":0}],"isArray":false,"index":17},{"name":"EquipItem","parameters":[{"name":"itemName","type":3},{"name":"tier","type":0}],"isArray":false,"index":18},{"name":"SetOpenParty","parameters":[{"name":"isOpen","type":0}],"isArray":false,"index":19},{"name":"SetPartyName","parameters":[{"name":"partyName","type":3}],"isArray":false,"index":20},{"name":"SetPartyMemberCanSell","parameters":[{"name":"uid","type":0},{"name":"canSell","type":0}],"isArray":false,"index":21},{"name":"JoinParty","parameters":[{"name":"partyId","type":0}],"isArray":false,"index":22},{"name":"JoinPartyByShareKey","parameters":[{"name":"partyShareKey","type":3}],"isArray":false,"index":23},{"name":"PartyApplicant","parameters":[{"name":"displayName","type":3},{"name":"applicantUid","type":0}],"isArray":false,"index":24},{"name":"PartyApplicantDecide","parameters":[{"name":"applicantUid","type":0},{"name":"accepted","type":0}],"isArray":false,"index":25},{"name":"PartyApplicantDenied","parameters":[],"isArray":false,"index":26},{"name":"PartyApplicantExpired","parameters":[{"name":"applicantUid","type":0}],"isArray":false,"index":27},{"name":"PartyShareKey","parameters":[{"name":"partyShareKey","type":3}],"isArray":false,"index":28},{"name":"PartyInfo","parameters":[{"name":"playerUid","type":0},{"name":"displayName","type":3},{"name":"isLeader","type":0},{"name":"canSell","type":0}],"isArray":true,"index":29},{"name":"AddParty","parameters":[{"name":"partyId","type":0},{"name":"partyName","type":3},{"name":"isOpen","type":0},{"name":"memberCount","type":0}],"isArray":false,"index":30},{"name":"RemoveParty","parameters":[{"name":"partyId","type":0}],"isArray":false,"index":31},{"name":"Leaderboard","parameters":[{"name":"name","type":3},{"name":"uid","type":0},{"name":"rank","type":0},{"name":"score","type":4},{"name":"wave","type":0}],"isArray":true,"index":32},{"name":"Failure","parameters":[{"name":"category","type":3},{"name":"reason","type":3},{"name":"x","type":0},{"name":"y","type":0},{"name":"type","type":3}],"isArray":false,"index":33},{"name":"RecallPet","parameters":[],"isArray":false,"index":34},{"name":"LeaveParty","parameters":[],"isArray":false,"index":35},{"name":"KickParty","parameters":[{"name":"uid","type":0}],"isArray":false,"index":36},{"name":"AddDepositToHarvester","parameters":[{"name":"uid","type":0},{"name":"deposit","type":2}],"isArray":false,"index":37},{"name":"CollectHarvester","parameters":[{"name":"uid","type":0}],"isArray":false,"index":38},{"name":"CastSpell","parameters":[{"name":"spell","type":3},{"name":"x","type":1},{"name":"y","type":1},{"name":"tier","type":0}],"isArray":false,"index":39},{"name":"CastSpellResponse","parameters":[{"name":"spell","type":3},{"name":"cooldown","type":0},{"name":"cooldownStartTick","type":0}],"isArray":false,"index":40},{"name":"Spells","parameters":[{"name":"json","type":3}],"isArray":false,"index":41},{"name":"SetPartyList","parameters":[{"name":"partyId","type":0},{"name":"partyName","type":3},{"name":"isOpen","type":0},{"name":"memberCount","type":0}],"isArray":true,"index":42}],"rpcMapsByName":{"Shutdown":{"name":"Shutdown","parameters":[{"name":"reason","type":3},{"name":"shutdownUnix","type":0}],"isArray":false,"index":0},"ReceiveChatMessage":{"name":"ReceiveChatMessage","parameters":[{"name":"displayName","type":3},{"name":"channel","type":3},{"name":"message","type":3},{"name":"uid","type":0}],"isArray":false,"index":1},"SendChatMessage":{"name":"SendChatMessage","parameters":[{"name":"channel","type":3},{"name":"message","type":3}],"isArray":false,"index":2},"Login":{"name":"Login","parameters":[{"name":"token","type":3}],"isArray":false,"index":3},"LoginResponse":{"name":"LoginResponse","parameters":[{"name":"json","type":3}],"isArray":false,"index":4},"AccountSession":{"name":"AccountSession","parameters":[{"name":"json","type":3}],"isArray":false,"index":5},"Metrics":{"name":"Metrics","parameters":[{"name":"minFps","type":2},{"name":"maxFps","type":2},{"name":"currentFps","type":2},{"name":"averageFps","type":2},{"name":"framesRendered","type":2},{"name":"framesInterpolated","type":2},{"name":"framesExtrapolated","type":2},{"name":"allocatedNetworkEntities","type":2},{"name":"currentClientLag","type":2},{"name":"minClientLag","type":2},{"name":"maxClientLag","type":2},{"name":"currentPing","type":2},{"name":"minPing","type":2},{"name":"maxPing","type":2},{"name":"averagePing","type":2},{"name":"longFrames","type":2},{"name":"stutters","type":2},{"name":"group","type":0},{"name":"isMobile","type":0},{"name":"timeResets","type":2},{"name":"maxExtrapolationTime","type":2},{"name":"extrapolationIncidents","type":2},{"name":"totalExtrapolationTime","type":2},{"name":"differenceInClientTime","type":2}],"isArray":false,"index":6},"DayCycle":{"name":"DayCycle","parameters":[{"name":"cycleStartTick","type":0},{"name":"nightEndTick","type":0},{"name":"dayEndTick","type":0},{"name":"isDay","type":0}],"isArray":false,"index":7},"MakeBuilding":{"name":"MakeBuilding","parameters":[{"name":"x","type":1},{"name":"y","type":1},{"name":"type","type":3},{"name":"yaw","type":1}],"isArray":false,"index":8},"BuildingShopPrices":{"name":"BuildingShopPrices","parameters":[{"name":"json","type":3}],"isArray":false,"index":9},"ItemShopPrices":{"name":"ItemShopPrices","parameters":[{"name":"json","type":3},{"name":"json","type":3}],"isArray":false,"index":10},"LocalBuilding":{"name":"LocalBuilding","parameters":[{"name":"x","type":1},{"name":"y","type":1},{"name":"type","type":3},{"name":"dead","type":0},{"name":"uid","type":0},{"name":"tier","type":0}],"isArray":true,"index":11},"Dead":{"name":"Dead","parameters":[{"name":"stashDied","type":0}],"isArray":false,"index":12},"Admin":{"name":"Admin","parameters":[{"name":"password","type":3},{"name":"command","type":3}],"isArray":false,"index":13},"UpgradeBuilding":{"name":"UpgradeBuilding","parameters":[{"name":"uid","type":0}],"isArray":false,"index":14},"DeleteBuilding":{"name":"DeleteBuilding","parameters":[{"name":"uid","type":0}],"isArray":false,"index":15},"BuyItem":{"name":"BuyItem","parameters":[{"name":"itemName","type":3},{"name":"tier","type":0}],"isArray":false,"index":16},"SetItem":{"name":"SetItem","parameters":[{"name":"itemName","type":3},{"name":"tier","type":0},{"name":"stacks","type":0}],"isArray":false,"index":17},"EquipItem":{"name":"EquipItem","parameters":[{"name":"itemName","type":3},{"name":"tier","type":0}],"isArray":false,"index":18},"SetOpenParty":{"name":"SetOpenParty","parameters":[{"name":"isOpen","type":0}],"isArray":false,"index":19},"SetPartyName":{"name":"SetPartyName","parameters":[{"name":"partyName","type":3}],"isArray":false,"index":20},"SetPartyMemberCanSell":{"name":"SetPartyMemberCanSell","parameters":[{"name":"uid","type":0},{"name":"canSell","type":0}],"isArray":false,"index":21},"JoinParty":{"name":"JoinParty","parameters":[{"name":"partyId","type":0}],"isArray":false,"index":22},"JoinPartyByShareKey":{"name":"JoinPartyByShareKey","parameters":[{"name":"partyShareKey","type":3}],"isArray":false,"index":23},"PartyApplicant":{"name":"PartyApplicant","parameters":[{"name":"displayName","type":3},{"name":"applicantUid","type":0}],"isArray":false,"index":24},"PartyApplicantDecide":{"name":"PartyApplicantDecide","parameters":[{"name":"applicantUid","type":0},{"name":"accepted","type":0}],"isArray":false,"index":25},"PartyApplicantDenied":{"name":"PartyApplicantDenied","parameters":[],"isArray":false,"index":26},"PartyApplicantExpired":{"name":"PartyApplicantExpired","parameters":[{"name":"applicantUid","type":0}],"isArray":false,"index":27},"PartyShareKey":{"name":"PartyShareKey","parameters":[{"name":"partyShareKey","type":3}],"isArray":false,"index":28},"PartyInfo":{"name":"PartyInfo","parameters":[{"name":"playerUid","type":0},{"name":"displayName","type":3},{"name":"isLeader","type":0},{"name":"canSell","type":0}],"isArray":true,"index":29},"AddParty":{"name":"AddParty","parameters":[{"name":"partyId","type":0},{"name":"partyName","type":3},{"name":"isOpen","type":0},{"name":"memberCount","type":0}],"isArray":false,"index":30},"RemoveParty":{"name":"RemoveParty","parameters":[{"name":"partyId","type":0}],"isArray":false,"index":31},"Leaderboard":{"name":"Leaderboard","parameters":[{"name":"name","type":3},{"name":"uid","type":0},{"name":"rank","type":0},{"name":"score","type":4},{"name":"wave","type":0}],"isArray":true,"index":32},"Failure":{"name":"Failure","parameters":[{"name":"category","type":3},{"name":"reason","type":3},{"name":"x","type":0},{"name":"y","type":0},{"name":"type","type":3}],"isArray":false,"index":33},"RecallPet":{"name":"RecallPet","parameters":[],"isArray":false,"index":34},"LeaveParty":{"name":"LeaveParty","parameters":[],"isArray":false,"index":35},"KickParty":{"name":"KickParty","parameters":[{"name":"uid","type":0}],"isArray":false,"index":36},"AddDepositToHarvester":{"name":"AddDepositToHarvester","parameters":[{"name":"uid","type":0},{"name":"deposit","type":2}],"isArray":false,"index":37},"CollectHarvester":{"name":"CollectHarvester","parameters":[{"name":"uid","type":0}],"isArray":false,"index":38},"CastSpell":{"name":"CastSpell","parameters":[{"name":"spell","type":3},{"name":"x","type":1},{"name":"y","type":1},{"name":"tier","type":0}],"isArray":false,"index":39},"CastSpellResponse":{"name":"CastSpellResponse","parameters":[{"name":"spell","type":3},{"name":"cooldown","type":0},{"name":"cooldownStartTick","type":0}],"isArray":false,"index":40},"Spells":{"name":"Spells","parameters":[{"name":"json","type":3}],"isArray":false,"index":41},"SetPartyList":{"name":"SetPartyList","parameters":[{"name":"partyId","type":0},{"name":"partyName","type":3},{"name":"isOpen","type":0},{"name":"memberCount","type":0}],"isArray":true,"index":42}}}',
  6916.  
  6917. useSes: false,
  6918. currentSesId: null,
  6919.  
  6920. allSessions: null,
  6921. endpoints: {
  6922. localhost: {
  6923. secret: 'f07cbf563d19619ba4afe3ae1e2ec95710a72b3e',
  6924. https: false,
  6925. wss: "localhost:727",
  6926. api: "localhost:728",
  6927. },
  6928. },
  6929.  
  6930. nameInput: getClass("hud-intro-name")[0],
  6931. serverSelect: getClass("hud-intro-server")[0],
  6932. overlayElem: getId("hud-intro-overlay"),
  6933.  
  6934. sesSelect: document.createElement("select"),
  6935. delBtn: document.createElement("button"),
  6936. addBtn: document.createElement("button"),
  6937. init: async function() {
  6938. this.addBtn.id = "addBtn";
  6939. this.addBtn.innerText = "Add...";
  6940. document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div").insertAdjacentElement("afterbegin", this.addBtn);
  6941.  
  6942. this.delBtn.id = "delBtn";
  6943. this.delBtn.innerText = "Delete";
  6944. document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div").insertAdjacentElement("afterbegin", this.delBtn);
  6945.  
  6946. this.sesSelect.disabled = true;
  6947. this.sesSelect.id = "sesSelect";
  6948. document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div").insertAdjacentElement("afterbegin", this.sesSelect);
  6949.  
  6950. getId("hud-intro-overlay").insertAdjacentHTML("beforeend", `
  6951. <div id="select-session-add">
  6952. <h2>Which one do wish to add?</h2>
  6953. <button id="add-endpoint">Add a new endpoint</button>
  6954. <button id="add-session">Add a new session</button>
  6955. </div>
  6956. <div id="endpoint-add-menu">
  6957. <h2>Endpoint info</h2>
  6958. <p>Nickname</p>
  6959. <input id="endpoint-name" placeholder="somecoolname" />
  6960. <p>Server URL</p>
  6961. <input id="endpoint-server" placeholder="domain:port" />
  6962. <p>API URL</p>
  6963. <input id="endpoint-api" placeholder="domain:port" />
  6964. <p>Secret key</p>
  6965. <input id="endpoint-secret" placeholder="0123456789abcdef" />
  6966. <p>Protocol</p>
  6967. <select id="endpoint-protocol">
  6968. <option value="http" selected>HTTP</option>
  6969. <option value="https">HTTPS</option>
  6970. </select>
  6971. <div class="session-navigator">
  6972. <button class="session-back"><i class="fa-solid fa-chevron-left"></i></button>
  6973. <button id="create-endpoint"><i class="fa-solid fa-check"></i></button>
  6974. </div>
  6975. </div>
  6976. <div id="session-add-menu">
  6977. <h2>Session creation info</h2>
  6978. <strong>You can leave the Party share key field empty.</strong>
  6979. <p>Endpoint</p>
  6980. <select id="session-endpoint">
  6981. ${Object.keys(this.endpoints).map((name) => {
  6982. return `<option value="${window.filterXSS(name)}" selected>${window.filterXSS(name)}</option>`;
  6983. }).join("\n")}
  6984. </select>
  6985. <p>Username</p>
  6986. <input id="session-nickname" placeholder="AyuLover2911" />
  6987. <p>Server</p>
  6988. <select id="session-server">${this.serverSelect.innerHTML}</select>
  6989. <p>Party share key</p>
  6990. <input id="session-psk" placeholder="abcdefghijklmnopqrstuvwxyz" />
  6991. <div class="session-navigator">
  6992. <button class="session-back"><i class="fa-solid fa-chevron-left"></i></button>
  6993. <button id="create-session"><i class="fa-solid fa-check"></i></button>
  6994. </div>
  6995. </div>
  6996. `);
  6997.  
  6998. getId("useSes").onchange = () => {
  6999. this.useSes = getId("useSes").checked;
  7000. if (this.useSes) {
  7001. this.sesSelect.style.display = "block";
  7002. this.delBtn.style.display = "inline-block";
  7003. this.addBtn.style.display = "inline-block";
  7004.  
  7005. this.nameInput.style.display = "none";
  7006. this.serverSelect.style.display = "none";
  7007.  
  7008. document.documentElement.style.setProperty('--normal-btn', 'rgb(158 74 208)');
  7009. document.documentElement.style.setProperty('--light-hover-btn', 'rgb(213 118 211)');
  7010. document.querySelector("#intro-animation > img").src = "https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/luna.png?v=1720346619482";
  7011. document.querySelector("#intro-animation > img").style.left = "calc(15vw - 600px)";
  7012. document.querySelector("#hud-intro").setAttribute("style", "--bg-image: url('https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Eden%20Conflict.webp?v=1717298976083');");
  7013. } else {
  7014. this.sesSelect.style.display = "none";
  7015. this.delBtn.style.display = "none";
  7016. this.addBtn.style.display = "none";
  7017.  
  7018. this.nameInput.style.display = "block";
  7019. this.serverSelect.style.display = "block";
  7020.  
  7021. document.documentElement.style.setProperty('--normal-btn', 'rgb(40 152 231)');
  7022. document.documentElement.style.setProperty('--light-hover-btn', 'rgb(111 208 247)');
  7023. document.querySelector("#intro-animation > img").src = "https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/eto_large.png?v=1717285769725";
  7024. document.querySelector("#intro-animation > img").style.left = "calc(15vw - 300px)";
  7025. document.querySelector("#hud-intro").setAttribute("style", "--bg-image: url('https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/BG_eden_append_light.webp?v=1717285760533');");
  7026. };
  7027. };
  7028.  
  7029. this.delBtn.onclick = () => {
  7030. const [endpoint, sessionId] = this.sesSelect.value.split("/");
  7031. this.deleteSes(endpoint, sessionId);
  7032. };
  7033.  
  7034. this.addBtn.onclick = () => {
  7035. getId("hud-intro").style.display = "block";
  7036. game.ui.components.Intro.hideLoadingScreen();
  7037.  
  7038. this.overlayElem.style.display = "flex";
  7039. this.overlayElem.style.opacity = 1;
  7040. getId("select-session-add").style.display = "flex";
  7041. getId("endpoint-add-menu").style.display = "none";
  7042. getId("session-add-menu").style.display = "none";
  7043. };
  7044. getId("add-endpoint").onclick = () => {
  7045. getId("select-session-add").style.display = "none";
  7046. getId("endpoint-add-menu").style.display = "flex";
  7047. getId("session-add-menu").style.display = "none";
  7048. };
  7049. getId("add-session").onclick = () => {
  7050. getId("select-session-add").style.display = "none";
  7051. getId("endpoint-add-menu").style.display = "none";
  7052. getId("session-add-menu").style.display = "flex";
  7053. };
  7054. for (const backElem of getClass("session-back")) backElem.onclick = () => { this.addBtn.click(); };
  7055. getId("create-endpoint").onclick = () => this.addNewEndpoint(
  7056. getId("endpoint-name").value,
  7057. getId("endpoint-server").value,
  7058. getId("endpoint-api").value,
  7059. getId("endpoint-protocol").value,
  7060. getId("endpoint-secret").value,
  7061. );
  7062. getId("create-session").onclick = () => this.createNewSession(
  7063. getId("session-nickname").value,
  7064. getId("session-server").value,
  7065. getId("session-psk").value,
  7066. getId("session-endpoint").value,
  7067. );
  7068.  
  7069. game.network.establishSessionConnection = function() {
  7070. const [endpoint, sessionId] = game.script.sessions.sesSelect.value.split("/");
  7071. this.connectionOptions = game.script.sessions.allSessions[endpoint][sessionId].connectionOptions;
  7072. this.connected = false;
  7073. this.connecting = true;
  7074. this.codec.rpcMaps = [{
  7075. "name": "SyncData",
  7076. "parameters": [{
  7077. "name": "json",
  7078. "type": 3
  7079. }],
  7080. "isArray": false,
  7081. "index": 0
  7082. }, {
  7083. "name": "VerifyUser",
  7084. "parameters": [{
  7085. "name": "secretKey",
  7086. "type": 3,
  7087. }],
  7088. "isArray": false,
  7089. "index": 1
  7090. }, {
  7091. "name": "ConnectSession",
  7092. "parameters": [{
  7093. "name": "id",
  7094. "type": 3
  7095. }],
  7096. "isArray": false,
  7097. "index": 2
  7098. }];
  7099. this.codec.rpcMapsByName = {
  7100. "SyncData": {
  7101. "name": "SyncData",
  7102. "parameters": [{
  7103. "name": "json",
  7104. "type": 3
  7105. }],
  7106. "isArray": false,
  7107. "index": 0
  7108. },
  7109. "VerifyUser": {
  7110. "name": "VerifyUser",
  7111. "parameters": [{
  7112. "name": "secretKey",
  7113. "type": 3
  7114. }],
  7115. "isArray": false,
  7116. "index": 1
  7117. },
  7118. "ConnectSession": {
  7119. "name": "ConnectSession",
  7120. "parameters": [{
  7121. "name": "id",
  7122. "type": 3
  7123. }],
  7124. "isArray": false,
  7125. "index": 2
  7126. },
  7127. };
  7128. this.socket = new WebSocket(`ws${game.script.sessions.endpoints[endpoint].https ? "s" : ""}://${game.script.sessions.endpoints[endpoint].wss}`);
  7129. this.socket.binaryType = `arraybuffer`;
  7130. this.socket.addEventListener("open", () => {
  7131. this.socket.send(this.codec.encode(9, {
  7132. name: "VerifyUser",
  7133. secretKey: game.script.sessions.endpoints[endpoint].secret
  7134. }));
  7135. this.socket.send(this.codec.encode(9, {
  7136. name: "ConnectSession",
  7137. id: sessionId,
  7138. }));
  7139. });
  7140. this.bindEventListeners();
  7141. this.addRpcHandler("SyncData", (response) => {
  7142. try {
  7143. const data = JSON.parse(response.json);
  7144.  
  7145. this.connectionOptions = data.connectionOptions;
  7146. game.options.serverId = data.connectionOptions.id;
  7147. game.options.nickname = data.syncNeeds[0].effectiveDisplayName;
  7148.  
  7149. const staticCodecData = JSON.parse(game.script.sessions.codecJSON);
  7150. for (let i in staticCodecData) {
  7151. this.codec[i] = staticCodecData[i];
  7152. };
  7153. this.codec.sortedUidsByType = data.sortedUidsByType;
  7154. this.codec.removedEntities = data.removedEntities;
  7155. this.codec.absentEntitiesFlags = data.absentEntitiesFlags;
  7156. this.codec.updatedEntityFlags = data.updatedEntityFlags;
  7157.  
  7158. for (let i = 0; i < game.script.sessions.staticJSONs.length; i++) {
  7159. this.emitter.emit(PacketIds_1.default[game.script.sessions.staticJSONs[i].opcode], game.script.sessions.staticJSONs[i]);
  7160. };
  7161.  
  7162. for (let i = 0; i < data.syncNeeds.length; i++) {
  7163. this.emitter.emit(PacketIds_1.default[data.syncNeeds[i].opcode], data.syncNeeds[i]);
  7164. };
  7165.  
  7166. for (let i = 0; i < data.messages.length; i++) {
  7167. this.emitter.emit(PacketIds_1.default[9], {
  7168. name: "ReceiveChatMessage",
  7169. response: data.messages[i],
  7170. opcode: 9
  7171. });
  7172. };
  7173.  
  7174. if (data.castSpellResponse && data.castSpellResponse.cooldownStartTick && (data.tick - data.castSpellResponse.cooldownStartTick) * 50 < 240000) {
  7175. this.emitter.emit(PacketIds_1.default[9], {
  7176. name: 'CastSpellResponse',
  7177. response: data.castSpellResponse,
  7178. opcode: 9
  7179. });
  7180. };
  7181.  
  7182. for (let i in data.inventory) {
  7183. this.emitter.emit(PacketIds_1.default[9], {
  7184. name: "SetItem",
  7185. response: {
  7186. itemName: data.inventory[i].itemName,
  7187. tier: data.inventory[i].tier,
  7188. stacks: data.inventory[i].stacks
  7189. },
  7190. opcode: 9
  7191. });
  7192. };
  7193.  
  7194. this.emitter.emit(PacketIds_1.default[9], {
  7195. name: "LocalBuilding",
  7196. response: data.localBuildings,
  7197. opcode: 9
  7198. });
  7199.  
  7200. this.emitter.emit(PacketIds_1.default[0], {
  7201. tick: data.tick,
  7202. entities: data.entities,
  7203. byteSize: data.byteSize,
  7204. opcode: 0
  7205. });
  7206.  
  7207. this.emitter.once(PacketIds_1.default[0], () => {
  7208. const myPlayer = data.entities[data.syncNeeds[0].uid];
  7209. myPlayer?.dead && this.emitter.emit(PacketIds_1.default[9], {
  7210. name: "Dead",
  7211. response: {stashDied: 0},
  7212. opcode: 9
  7213. });
  7214. myPlayer?.isPaused && (
  7215. game.ui.onLocalItemUpdate({
  7216. itemName: 'Pause',
  7217. tier: 1,
  7218. stacks: 1
  7219. }),
  7220. game.ui.emit('wavePaused')
  7221. );
  7222. });
  7223. } catch(e) { console.log(e); };
  7224. });
  7225. };
  7226.  
  7227. game.network.connect = async function (options) {
  7228. if (!this.connecting) {
  7229. if (game.script.sessions.useSes) return this.establishSessionConnection();
  7230. this.connectionOptions = options;
  7231. this.connected = false;
  7232. this.connecting = true;
  7233. this.socket = new WebSocket('wss://' + options.hostname + ':' + options.port);
  7234. this.socket.binaryType = `arraybuffer`;
  7235. this.bindEventListeners();
  7236. };
  7237. };
  7238.  
  7239. game.network.reconnect = function () {
  7240. return this.connect(this.connectionOptions);
  7241. };
  7242.  
  7243. await this.fetchSessions();
  7244. },
  7245. fetchSessions: async function() {
  7246. for (const endpointName in this.endpoints) {
  7247. const endpointData = this.endpoints[endpointName];
  7248. try {
  7249. let data = await fetch(
  7250. `http${endpointData.https ? "s" : ""}://${endpointData.api}/sessions`,
  7251. {
  7252. signal: AbortSignal.timeout(this.SESSION_FETCH_TIMEOUT),
  7253. method: "get",
  7254. headers: new Headers({
  7255. "ngrok-skip-browser-warning": "69420",
  7256. }),
  7257. }
  7258. );
  7259. data = await data.json();
  7260.  
  7261. this.allSessions ||= {};
  7262. this.sesSelect.disabled = false;
  7263.  
  7264. this.allSessions[endpointName] = data;
  7265. } catch(e) {
  7266. console.warn(`Failed to fetch available sessions for ${endpointName}: ` + e);
  7267. };
  7268. };
  7269. this.mapSessions();
  7270. },
  7271. mapSessions() {
  7272. if (this.allSessions === null) return;
  7273. let sessionHTML = '';
  7274. for (const endpointName in this.allSessions) {
  7275. sessionHTML += `
  7276. <optgroup label="${window.filterXSS(endpointName)}">
  7277. ${Object.entries(this.allSessions[endpointName]).map(([key, data]) => {
  7278. const { connectionOptions: { id }, name } = data;
  7279. return `<option value="${endpointName}/${key}">${window.filterXSS(name)} [${id}]</option>`;
  7280. }).join("\n")}
  7281. </optgroup>
  7282. `;
  7283. };
  7284. this.sesSelect.innerHTML = sessionHTML;
  7285. getId("session-endpoint").innerHTML = Object.keys(this.endpoints).map((name) => {
  7286. return `<option value="${window.filterXSS(name)}" selected>${window.filterXSS(name)}</option>`;
  7287. }).join("\n");
  7288. },
  7289. addNewEndpoint: async function(name, server, api, protocol, secret) {
  7290. game.ui.components.Intro.showLoadingScreen();
  7291. if (name && secret && server && api && protocol) {
  7292. this.endpoints[name] = {https: protocol == "https", secret, wss: server, api};
  7293. await this.fetchSessions();
  7294. } else game.ui.components.Intro.onConnectionError("Please fill in ALL necessary details to add a new endpoint.");
  7295. game.ui.components.Intro.hideLoadingScreen();
  7296. game.world.isInitialized && (getId("hud-intro").style.display = "none");
  7297. },
  7298. createNewSession: async function(nickname, server, psk = "", endpoint) {
  7299. game.ui.components.Intro.showLoadingScreen();
  7300. try {
  7301. const {https, api} = this.endpoints[endpoint];
  7302. console.log(nickname, server, psk, endpoint);
  7303. let data = await fetch(
  7304. `http${https ? "s" : ""}://${api}/create?name=${nickname}&serverId=${server}&psk=${psk}`,
  7305. {
  7306. signal: AbortSignal.timeout(this.SESSION_CREATE_TIMEOUT),
  7307. method: "get",
  7308. headers: new Headers({
  7309. "ngrok-skip-browser-warning": "69420",
  7310. }),
  7311. }
  7312. );
  7313. data = await data.json();
  7314.  
  7315. this.allSessions ||= {};
  7316. this.sesSelect.disabled = false;
  7317.  
  7318. this.allSessions[endpoint] = data.data;
  7319. this.mapSessions();
  7320.  
  7321. this.sesSelect.value = `${endpoint}/${data.createdSession}`;
  7322. } catch(e) {
  7323. console.log(e);
  7324. game.ui.components.Intro.onConnectionError(e);
  7325. };
  7326. game.ui.components.Intro.hideLoadingScreen();
  7327. game.world.isInitialized && (getId("hud-intro").style.display = "none");
  7328. },
  7329. deleteSes: async function(endpoint, sesId) {
  7330. const { api, https } = this.endpoints[endpoint];
  7331. await fetch(
  7332. `http${https ? "s" : ""}://${api}/delete?sessionId=${sesId}`,
  7333. { signal: AbortSignal.timeout(this.SESSION_CREATE_TIMEOUT) }
  7334. );
  7335. setTimeout(this.fetchSessions.bind(this), 500);
  7336. },
  7337. },
  7338. sockets: {
  7339. statusEnum: {
  7340. "Population Full": "red",
  7341. "Failed": "red",
  7342. "Closed": "red",
  7343. "Connecting": "yellow",
  7344. "Open": "green"
  7345. },
  7346. shared: {
  7347. all: {},
  7348. uiHooks: {},
  7349. availableNames: shuffleArray([
  7350. "Hikari",
  7351. "Tairitsu",
  7352. "Kou",
  7353. "Sapphire",
  7354. "Lethe",
  7355. "Tairitsu (Axium)",
  7356. "Tairitsu (Grievous Lady)",
  7357. "Stella",
  7358. "Hikari & Fisica",
  7359. "Ilith",
  7360. "Eto",
  7361. "Luna",
  7362. "Shirabe",
  7363. "Hikari (Zero)",
  7364. "Hikari (Fracture)",
  7365. "Hikari (Summer)",
  7366. "Tairitsu (Summer)",
  7367. "Tairitsu & Trin",
  7368. "Ayu",
  7369. "Eto & Luna (Winter)",
  7370. "Hikari & Seine",
  7371. "Yume",
  7372. "Saya",
  7373. "Tairitsu (Grievous Lady) & Chuni Penguin",
  7374. "Nono Shibusawa",
  7375. "Haruna Mishima",
  7376. "Regulus (MDA-21)",
  7377. "Pandora Nemesis (MTA-XXX)",
  7378. "Chuni Penguin",
  7379. "Kanae",
  7380. "Hikari (Fantasia)",
  7381. "Tairitsu (Sonata)",
  7382. "Sia",
  7383. "DORO*C",
  7384. "Tairitsu (Tempest)",
  7385. "Brillante (E/S Primera)",
  7386. "Ilith (Summer)",
  7387. "Saya (Etude)",
  7388. "Alice & Tenniel",
  7389. "Luna & Mia",
  7390. "Areus",
  7391. "Seele Haze",
  7392. "Isabelle Yagrush",
  7393. "Mir",
  7394. "Lagrange",
  7395. "Shirahime",
  7396. "Linka",
  7397. "Nami",
  7398. "Saya & Elizabeth",
  7399. "Lily",
  7400. "Kanae (Midsummer)",
  7401. "Alice & Tenniel (Minuet)",
  7402. "Tairitsu (Elegy)",
  7403. "Marija",
  7404. "Vita",
  7405. "Hikari (Fatalis)",
  7406. "Hikari & Tairitsu (Reunion)",
  7407. "Saki",
  7408. "Setsuna",
  7409. "Amane",
  7410. "Kou (Winter)",
  7411. "Lethe (Apophenia)",
  7412. "Lagrange (Aria)",
  7413. "Milk (UNiVERSE)",
  7414. "Shama (UNiVERSE)",
  7415. "Mika Yurisaki",
  7416. "Shikoku",
  7417. "Toa Kozukata",
  7418. "Mithra Tercera",
  7419. "Nami (Twilight)",
  7420. "Ilith & Ivy",
  7421. "Hikari & Vanessa",
  7422. "Maya",
  7423. "Luin",
  7424. "Vita (Cadenza)",
  7425. "Ai-chan",
  7426. "Luna & Ilot",
  7427. "Eto & Hoppe",
  7428. "Nell",
  7429. "Lacrymira",
  7430. "Tsumugi",
  7431. "Chinatsu",
  7432. ]),
  7433. options: {
  7434. useProxy: {
  7435. enabled: false,
  7436. },
  7437. control: {
  7438. enabled: true,
  7439. },
  7440. autoFill: {
  7441. enabled: false,
  7442. onCallback: () => {
  7443. game.network.emitter.emit("PACKET_RPC", {
  7444. name: "SetPartyList",
  7445. response: Object.values(game.ui.parties),
  7446. opcode: 9
  7447. });
  7448. },
  7449. },
  7450. randomizeName: {
  7451. enabled: true,
  7452. },
  7453. },
  7454. },
  7455. init: function() {
  7456. game.network.addRpcHandler("SetPartyList", (parties) => {
  7457. if (this.shared.options.autoFill.enabled) {
  7458. let serverPopulation = 0;
  7459. for (let party of parties) {
  7460. serverPopulation += party.memberCount;
  7461. };
  7462. const emptyAmount = 32 - serverPopulation;
  7463. if (emptyAmount > 0) {
  7464. let connectedSockets = 0;
  7465. for (const socket of Object.values(this.shared.all)) {
  7466. if (socket.hasEnteredWorld && socket.ws.readyState === 1) connectedSockets++;
  7467. };
  7468. const shouldWait = ((connectedSockets + 1) % 7) === 0;
  7469. shouldWait && game.ui.components.PopupOverlay.showHint("Please change your IP Address for the auto-filling to continue.");
  7470. this.createSocket("Filler");
  7471. };
  7472. };
  7473. });
  7474. },
  7475. updateActiveSocketsAmount: function() {
  7476. let openSockets = 0;
  7477. const allSockets = Object.values(this.shared.all);
  7478. for (let i = 0; i < allSockets.length; i++) {
  7479. allSockets[i].ws.readyState == 1 && openSockets++;
  7480. };
  7481. getId("clone-amount").innerText = openSockets + " active";
  7482. },
  7483. addUiHook: function(UUID, elemSelector, event, callback) {
  7484. this.shared.uiHooks[elemSelector] ||= {};
  7485. if (!this.shared.uiHooks[elemSelector][event]) {
  7486. this.shared.uiHooks[elemSelector][event] = {};
  7487. document.querySelector(elemSelector)["on" + event] = (e) => {
  7488. for (let uuid in this.shared.uiHooks[elemSelector][event]) {
  7489. this.shared.uiHooks[elemSelector][event][uuid]();
  7490. };
  7491. };
  7492. };
  7493. this.shared.uiHooks[elemSelector][event][UUID] = callback;
  7494. },
  7495. removeUiHook: function(UUID, elemSelector, event) {
  7496. delete this.shared.uiHooks[elemSelector][event][UUID];
  7497. },
  7498. Socket: class Socket {
  7499. constructor(url, identifiers) {
  7500. this.parent = game.script.sockets;
  7501. if (this.parent.shared.options.useProxy.enabled) {
  7502. const serverId = game.network.connectionOptions.id;
  7503. url = `ws://localhost:1003/${serverId}`;
  7504. }
  7505. this.ws = new WebSocket(url);
  7506. this.ws.binaryType = "arraybuffer";
  7507.  
  7508. this.identifiers = identifiers;
  7509. this.player = {
  7510. uid: null,
  7511. partyShareKey: null,
  7512.  
  7513. targetTick: {},
  7514. petTick: {},
  7515.  
  7516. // entities: {},
  7517.  
  7518. inventory: {},
  7519. buildings: {},
  7520. parties: {},
  7521.  
  7522. hasHealed: false,
  7523. lastTickHealth: 100,
  7524. };
  7525. this.hasEnteredWorld = false;
  7526.  
  7527. this.pingStart = null;
  7528. this.pingCompletion = null;
  7529. this.ping = 0;
  7530.  
  7531. this.keybinds = {
  7532. keyup: {},
  7533. keydown: {},
  7534. mousedown: {},
  7535. mouseup: {},
  7536. mousemove: () => {},
  7537. };
  7538.  
  7539. /*
  7540. this.msElapsedSinceInputSent = 0;
  7541. this.currentInput = {};
  7542. this.shouldInput = false;
  7543. */
  7544.  
  7545. this.statusDisplay = getId(`alt${this.identifiers.id}`) || document.createElement("p");
  7546. this.statusDisplay.style.position = "relative";
  7547. this.statusDisplay.style.width = "100%";
  7548.  
  7549. this.minimapDisplay = document.createElement('div');
  7550.  
  7551. this.timeCreation = Date.now();
  7552.  
  7553. this.init(this.identifiers.type);
  7554. };
  7555. init(type) {
  7556. this.ws.addEventListener("open", () => {
  7557. this.updateStatus("Connecting");
  7558. this.codec = new BinCodec();
  7559. this.resetListeners(type);
  7560. this.bindKeys();
  7561. });
  7562. this.ws.addEventListener("message", this.onMessage.bind(this));
  7563. this.ws.addEventListener("close", this.onClose.bind(this));
  7564. this.ws.addEventListener("error", this.onError.bind(this));
  7565. // game.renderer.addTickCallback(this.onRendererTick.bind(this));
  7566. };
  7567. decodeData(data) {
  7568. this.data = {};
  7569. const m = new Uint8Array(data);
  7570. this.data.opcode = m[0];
  7571. switch(m[0]) {
  7572. case 5:
  7573. wasmModule(e => {
  7574. this.sendPacket(4, {
  7575. displayName: this.identifiers.name,
  7576. extra: e[5].extra
  7577. });
  7578. this.wasmModule = e;
  7579. }, m, game.network.connectionOptions.ipAddress);
  7580. break;
  7581. case 10:
  7582. this.sendPacket(10, {extra: codec.decode(data, this.wasmModule[10]).extra});
  7583. break;
  7584. default:
  7585. this.data = this.codec.decode(data);
  7586. };
  7587. if (m[0] == 4 && this.data.allowed) {
  7588. this.ws.send(this.wasmModule[6]);
  7589. this.hasEnteredWorld = true;
  7590. };
  7591. };
  7592. onError() {
  7593. game.ui.components.PopupOverlay.showHint("Socket failed to connect. Maybe switch your IP?");
  7594. };
  7595. onClose() {
  7596. this.parent.updateActiveSocketsAmount();
  7597. this.updateStatus("Closed");
  7598.  
  7599. this.minimapDisplay.remove();
  7600.  
  7601. this.wasmModule = null;
  7602.  
  7603. this.identifiers.name != game.ui.playerTick.name && this.parent.shared.availableNames.push(this.identifiers.name);
  7604.  
  7605. if (this.parent.shared.options.autoFill.enabled) {
  7606. setTimeout(() => {
  7607. game.network.emitter.emit("PACKET_RPC", {
  7608. name: "SetPartyList",
  7609. response: Object.values(game.ui.parties),
  7610. opcode: 9
  7611. });
  7612. }, 1000);
  7613. };
  7614. };
  7615. onMessage({data}) {
  7616. this.sendPingIfNecessary();
  7617. this.decodeData(data);
  7618. this.emitter.emit(PacketIds_1.default[this.data.opcode], this.data);
  7619. };
  7620. /*
  7621. onRendererTick(delta) {
  7622. this.msElapsedSinceInputSent += delta;
  7623. this.sendInputKeys();
  7624. };
  7625. */
  7626. addOnceHandler(opcode, callback) {
  7627. this.emitter.once(PacketIds_1.default[opcode], callback.bind(this));
  7628. };
  7629. addPacketHandler(opcode, callback) {
  7630. this.emitter.on(PacketIds_1.default[opcode], callback.bind(this));
  7631. };
  7632. sendPacket(e, t) {
  7633. const enc = this.codec.encode(e, t);
  7634. this.ws.readyState == 1 && this.ws.send(enc);
  7635. };
  7636. sendInput(t) {
  7637. this.sendPacket(3, t);
  7638. };
  7639. sendRpc(t) {
  7640. this.sendPacket(9, t);
  7641. };
  7642. sendPingIfNecessary() {
  7643. var pingInProgress = (this.pingStart != null);
  7644. if (pingInProgress) {
  7645. return;
  7646. }
  7647. if (this.pingCompletion != null) {
  7648. var msSinceLastPing = (new Date().getTime() - this.pingCompletion.getTime());
  7649. if (msSinceLastPing <= 5000) {
  7650. return;
  7651. }
  7652. }
  7653. this.pingStart = new Date();
  7654. this.sendPacket(7, { nonce: 0 });
  7655. };
  7656. /*
  7657. scheduleInput(data) {
  7658. this.currentInput = data;
  7659. this.shouldInput = true;
  7660. this.sendInputKeys();
  7661. };
  7662. sendInputKeys() {
  7663. const msPerTick = game.world.msPerTick;
  7664. if (!(this.msElapsedSinceInputSent < msPerTick)) {
  7665. if (this.shouldInput) {
  7666. this.sendInput(this.currentInput);
  7667. this.currentInput = {};
  7668. this.shouldInput = false;
  7669. };
  7670. };
  7671. };
  7672. */
  7673. resetListeners(type) {
  7674. this.keybinds = {
  7675. keyup: {},
  7676. keydown: {},
  7677. mousedown: {},
  7678. mouseup: {},
  7679. mousemove: () => {},
  7680. };
  7681. this.emitter = new EventEmitter();
  7682.  
  7683. this.bindDefaultListeners();
  7684. this.bindTypeHandlers(type);
  7685. };
  7686. bindDefaultListeners() {
  7687. this.addPacketHandler(0, (data) => {
  7688. try {
  7689. if (data.entities[this.player?.uid].name) {
  7690. this.player.targetTick = data.entities[this.player.uid];
  7691. };
  7692. for (let g in this.player.targetTick) {
  7693. if (this.player.targetTick[g] !== data.entities[this.player.uid][g] && data.entities[this.player.uid][g] !== undefined) {
  7694. this.player.targetTick[g] = data.entities[this.player.uid][g];
  7695. };
  7696. };
  7697. if (this.player.targetTick.petUid) {
  7698. if (data.entities?.[this.player.targetTick.petUid]?.model) {
  7699. this.player.petTick = data.entities[this.player.targetTick.petUid];
  7700. }
  7701. for (let g in this.player.petTick) {
  7702. if (this.player.petTick[g] !== data.entities?.[this.player.targetTick.petUid][g] && data.entities?.[this.player.targetTick.petUid][g] !== undefined) {
  7703. this.player.petTick[g] = data.entities[this.player.targetTick.petUid][g];
  7704. };
  7705. };
  7706. };
  7707.  
  7708. for (let i in data.entities) {
  7709. if (["Tree", "Stone", "NeutralCamp"].indexOf(data.entities[i].model) > -1) {
  7710. game.world.createEntity(data.entities[i]);
  7711. };
  7712. };
  7713. } catch {};
  7714. });
  7715. this.addPacketHandler(4, (e) => {
  7716. if (e.allowed) {
  7717. this.player.uid = e.uid;
  7718.  
  7719. this.parent.updateActiveSocketsAmount();
  7720. this.updateStatus("Open");
  7721.  
  7722. console.log(`%c [SOCKET ${this.identifiers.id}]`, 'color: #54ebd9', '\n', `${e.players + 1}/32 players`);
  7723.  
  7724. this.sendRpc({name: "BuyItem", itemName: "PetCARL", tier: 1});
  7725. this.sendRpc({name: "BuyItem", itemName: "PetMiner", tier: 1});
  7726.  
  7727. this.sendInput({left: 1, up: 1});
  7728. this.sendInput({space: 1});
  7729. } else {
  7730. console.log(`%c [SOCKET ${this.identifiers.id}]`, 'color: #54ebd9', '\n', `32/32 players`);
  7731. this.updateStatus("Population Full");
  7732. };
  7733. });
  7734. this.addPacketHandler(5, () => {
  7735. setTimeout(() => {
  7736. if (this.data.opcode === 5) this.ws.close();
  7737. }, 5000);
  7738. });
  7739. this.addPacketHandler(7, () => {
  7740. const now = new Date();
  7741. this.ping = (now.getTime() - this.pingStart.getTime()) / 2;
  7742. this.pingStart = null;
  7743. this.pingCompletion = now;
  7744. });
  7745. this.addPacketHandler(9, (e) => {
  7746. this.updateStatus("Open");
  7747. switch(e.name) {
  7748. case "PartyShareKey":
  7749. if (!this.player.partyShareKey) {
  7750. this.sendRpc({
  7751. name: "JoinPartyByShareKey",
  7752. partyShareKey: game.ui.getPlayerPartyShareKey()
  7753. });
  7754. this.minimapDisplay.classList.add('hud-map-player');
  7755. this.minimapDisplay.style.display = "block";
  7756. getClass('hud-map')[0].appendChild(this.minimapDisplay);
  7757. };
  7758. this.player.partyShareKey = e.response.partyShareKey;
  7759. this.minimapDisplay.style.display = (e.response.partyShareKey == game.ui.getPlayerPartyShareKey()) ? "none" : "block";
  7760. break;
  7761. case "SetItem":
  7762. this.player.inventory[e.response.itemName] = e.response;
  7763. if (!this.player.inventory[e.response.itemName].stacks) {
  7764. delete this.player.inventory[e.response.itemName];
  7765. };
  7766. break;
  7767. case "Leaderboard":
  7768. this.sendRpc(game.metrics.metrics);
  7769.  
  7770. this.minimapDisplay.style.left = (Math.round(this.player?.targetTick?.position?.x) / 24000 * 100) + '%';
  7771. this.minimapDisplay.style.top = (Math.round(this.player?.targetTick?.position?.y) / 24000 * 100) + '%';
  7772. break;
  7773. };
  7774. });
  7775. };
  7776. bindKeys() {
  7777. for (let event in this.keybinds) {
  7778. switch(event) {
  7779. case "keyup":
  7780. case "keydown":
  7781. document.addEventListener(event, (e) => {
  7782. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  7783. for (let keyCode in this.keybinds[event]) {
  7784. if (e.keyCode == keyCode && this.ws.readyState == 1) this.keybinds[event][keyCode].call(this, e);
  7785. };
  7786. }
  7787. });
  7788. break;
  7789. case "mouseup":
  7790. case "mousedown":
  7791. document.addEventListener(event, (e) => {
  7792. for (let which in this.keybinds[event]) {
  7793. if (e.which == which && this.ws.readyState == 1) this.keybinds[event][which].call(this, e);
  7794. };
  7795. });
  7796. break;
  7797. case "mousemove":
  7798. document.addEventListener(event, (e) => {
  7799. this.ws.readyState == 1 && this.keybinds[event].call(this, e);
  7800. });
  7801. break;
  7802. };
  7803. };
  7804. };
  7805. bindTypeHandlers(type) {
  7806. if (this.parent[type]) {
  7807. this.typeHandlers = [];
  7808. this.typeSpecificVariables = {};
  7809.  
  7810. typeof this.parent[type].init == "function" && this.parent[type].init.call(this);
  7811.  
  7812. const handlersForType = this.parent[type];
  7813. for (const handler in handlersForType) {
  7814. if (typeof handlersForType[handler] !== "function" || ["init", "deinit"].indexOf(handler) > -1) continue;
  7815. this.typeHandlers.push(handler);
  7816. };
  7817. for (const handler of this.typeHandlers) this.addPacketHandler(PacketIds_1.default[handler], (data) => { handlersForType[handler].call(this, data, handlersForType); });
  7818.  
  7819. if (this.parent[type].keybinds) {
  7820. Object.assign(this.keybinds, this.parent[type].keybinds);
  7821. };
  7822. };
  7823. };
  7824. switchType(type) {
  7825. typeof this.parent[this.identifiers.type].deinit == "function" && this.parent[this.identifiers.type].deinit.call(this);
  7826. this.identifiers.type = type;
  7827. this.resetListeners(type);
  7828. };
  7829. updateStatus(status) {
  7830. this.statusDisplay.innerHTML = `
  7831. <strong>${this.identifiers.name}</strong>
  7832. <select style="position: absolute;top: -10px;right: -5px;width: 130px;background: unset;box-shadow: none;color:white;" id="switch${this.identifiers.id}" ${status === "Open" ? "" : "disabled"}>
  7833. <option value="Multibox" ${this.identifiers.type == "Multibox" ? "selected" : ""}>Multibox</option>
  7834. <option value="Filler" ${this.identifiers.type == "Filler" ? "selected" : ""}>Filler</option>
  7835. <option value="PlayerTrick" ${this.identifiers.type == "PlayerTrick" ? "selected" : ""}>Player Trick</option>
  7836. <option value="AITO" ${this.identifiers.type == "AITO" ? "selected" : ""}>AITO</option>
  7837. </select><br>
  7838. State: <strong style="color: ${this.parent.statusEnum[status]};">[${status}]</strong>${["Population Full", "Failed", "Closed"].indexOf(status) == -1 ? `, ping: ${this.ping}ms` : `, created: ${getClock(new Date(this.timeCreation))}`}<br>
  7839. ${status === "Open" ? `
  7840. UID: ${this.player.uid}, partyId: <strong>${this.player.targetTick.partyId || 0}</strong><br>
  7841. <strong>W: ${counter(this.player?.targetTick?.wood || 0)}, S: ${counter(this.player?.targetTick?.stone || 0)}, G: ${counter(this.player?.targetTick?.gold || 0)}, T: ${counter(this.player?.targetTick?.token || 0)}</strong><br>
  7842. <a href="javascript:void(0);" style="margin: 5px 0 0 0;color: red;" onclick="game.script.sockets.shared.all['${this.identifiers.id}'].ws.close();">Delete</a>
  7843. ${this.identifiers.type == "Multibox" ? `
  7844. ${this.player.targetTick.partyId != game.ui.playerPartyId && this.player.targetTick.partyId ? `
  7845. <a href="javascript:void(0);"
  7846. style="margin: 5px 0 0 0;color: lightblue;"
  7847. onclick="game.network.sendRpc({name: 'JoinPartyByShareKey', partyShareKey: game.script.sockets.shared.all['${this.identifiers.id}'].player.partyShareKey});"
  7848. >Join Party</a>
  7849. ` : ""}
  7850. ` : ""}
  7851. <!-- Type: <select href="javascript:void(0);" style="margin: 5px 0 0 0;color: red;" onselect="game.script.sockets.shared.all['${this.identifiers.id}'].ws.close();">Switch...</select> -->
  7852. <!--
  7853. <a href="javascript:void(0);"
  7854. style="margin: 5px 0 0 0;color: lightblue;"
  7855. class="elem-is-disabled"
  7856. id="respawnAlt#${this.identifiers.id}"
  7857. onclick="
  7858. game.script.cloneSockets.allSockets[${this.identifiers.id}].network.sendInput({respawn: 1});
  7859. document.getElementById('respawnAlt#${this.identifiers.id}').classList.add('elem-is-disabled');
  7860. "
  7861. >Respawn</a> -->
  7862. ` : ""}
  7863. `;
  7864. if (status === "Connecting" && !getId(`alt${this.identifiers.id}`)) {
  7865. this.statusDisplay.id = `alt${this.identifiers.id}`;
  7866. getId("clone-status").appendChild(this.statusDisplay);
  7867. };
  7868. getId(`switch${this.identifiers.id}`).onchange = ({target}) => {
  7869. this.switchType(target.value);
  7870. };
  7871. };
  7872. },
  7873. createSocket: function(type) {
  7874. const socketId = genUUID(),
  7875. socketName = this.shared.options.randomizeName.enabled ? this.shared.availableNames.shift() : game.ui.playerTick.name;
  7876. this.shared.all[socketId] = new this.Socket(`wss://${game.network.connectionOptions.hostname}:443/`, {
  7877. id: socketId,
  7878. name: socketName,
  7879. type,
  7880. });
  7881. },
  7882. Builder: {
  7883.  
  7884. },
  7885. Multibox: {
  7886. init: function() {
  7887. this.typeSpecificVariables.mouseData = {
  7888. yaw: 1,
  7889. worldX: 1,
  7890. worldY: 1,
  7891. distance: 1,
  7892.  
  7893. mouseUp: 1,
  7894. mouseDown: 0,
  7895. mousePos: {x: 0, y: 0},
  7896. };
  7897.  
  7898. this.typeSpecificVariables.overrides = {
  7899. autoMove: false,
  7900. };
  7901.  
  7902. this.typeSpecificVariables.FOLLOW_ACCURACY = 50;
  7903. this.typeSpecificVariables.FOLLOW_TYPE = {
  7904. NONE: 0,
  7905. MOUSE: 1,
  7906. LOCK: 2,
  7907. PLAYER: 3,
  7908. };
  7909. this.typeSpecificVariables.autoMove = parseInt(getId("movementTypeOptions").value); // this.parent.shared.overridables.autoMove;
  7910. this.typeSpecificVariables.followPoint = {x: 0, y: 0};
  7911.  
  7912. this.typeSpecificVariables.autoHeal = {
  7913. hasHealed: false,
  7914. lastTickHealth: 100,
  7915. };
  7916.  
  7917. const shopItems = ['Pickaxe', 'Spear', 'Bow', 'Bomb', 'ZombieShield'];
  7918. for (let i in shopItems) {
  7919. this.parent.addUiHook(this.identifiers.id, `#hud-menu-shop > div.hud-shop-grid > a:nth-child(${parseInt(i) + 1})`, "click", () => {
  7920. const item = shopItems[i];
  7921. if (this.parent.shared.options.control.enabled && this.ws.readyState == 1) {
  7922. this.sendRpc({
  7923. name: "BuyItem",
  7924. itemName: item,
  7925. tier: this.player.inventory[item] ? this.player.inventory[item].tier + 1 : 1
  7926. });
  7927. };
  7928. });
  7929. };
  7930.  
  7931. const itemArray = ['Pickaxe', 'Spear', 'Bow', 'Bomb', 'HealthPotion', 'PetHealthPotion', 'PetWhistle'];
  7932. for (let i in itemArray) {
  7933. this.parent.addUiHook(this.identifiers.id, `#hud-toolbar > div.hud-toolbar-inventory > a:nth-child(${parseInt(i) + 1})`, "click", () => {
  7934. if (this.parent.shared.options.control.enabled && this.ws.readyState == 1) {
  7935. this.player.inventory[itemArray[i]] && this.sendRpc({
  7936. name: "EquipItem",
  7937. itemName: itemArray[i],
  7938. tier: this.player.inventory[itemArray[i]].tier
  7939. });
  7940. };
  7941. });
  7942. };
  7943. },
  7944. deinit: function() {
  7945. const shopItems = ['Pickaxe', 'Spear', 'Bow', 'Bomb', 'ZombieShield'];
  7946. for (let i in shopItems) {
  7947. this.parent.removeUiHook(this.identifiers.id, `#hud-menu-shop > div.hud-shop-grid > a:nth-child(${parseInt(i) + 1})`, "click");
  7948. };
  7949.  
  7950. const itemArray = ['Pickaxe', 'Spear', 'Bow', 'Bomb', 'HealthPotion', 'PetHealthPotion', 'PetWhistle'];
  7951. for (let i in itemArray) {
  7952. this.parent.removeUiHook(this.identifiers.id, `#hud-toolbar > div.hud-toolbar-inventory > a:nth-child(${parseInt(i) + 1})`, "click");
  7953. };
  7954. },
  7955. keybinds: {
  7956. keyup: {
  7957. 87: function() {
  7958. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  7959. this.sendInput({up: 0});
  7960. };
  7961. },
  7962. 83: function() {
  7963. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  7964. this.sendInput({down: 0});
  7965. };
  7966. },
  7967. 68: function() {
  7968. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  7969. this.sendInput({right: 0});
  7970. };
  7971. },
  7972. 65: function() {
  7973. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  7974. this.sendInput({left: 0});
  7975. };
  7976. },
  7977. 81: function(data) {
  7978. if (this.parent.shared.options.control.enabled) {
  7979. let nextWeapon = 'Pickaxe',
  7980. weaponOrder = ['Pickaxe', 'Spear', 'Bow', 'Bomb'],
  7981. foundCurrent = false;
  7982. for (let i in weaponOrder) {
  7983. if (foundCurrent) {
  7984. if (this.player.inventory[weaponOrder[i]]) {
  7985. nextWeapon = weaponOrder[i];
  7986. break;
  7987. };
  7988. } else if (weaponOrder[i] == this.player.targetTick.weaponName) {
  7989. foundCurrent = true;
  7990. };
  7991. };
  7992. this.sendRpc({name: 'EquipItem', itemName: nextWeapon, tier: this.player.inventory[nextWeapon].tier});
  7993. };
  7994. },
  7995. 72: function() {
  7996. this.parent.shared.options.control.enabled && this.sendRpc({name: 'LeaveParty'});
  7997. },
  7998. 74: function() {
  7999. this.parent.shared.options.control.enabled && this.sendRpc({name: 'JoinPartyByShareKey', partyShareKey: game.ui.playerPartyShareKey});
  8000. },
  8001. 32: function() {
  8002. if (this.parent.shared.options.control.enabled) {
  8003. this.sendInput({space: 0});
  8004. };
  8005. },
  8006. 82: function() {
  8007. if (this.parent.shared.options.control.enabled) {
  8008. const buildingOverlay = game.ui.components.BuildingOverlay;
  8009. const buildings = game.ui.buildings;
  8010. if (buildingOverlay.shouldUpgradeAll) {
  8011. for (let i in buildings) {
  8012. if (buildings[i].type == buildingOverlay.buildingId && buildings[i].tier == buildingOverlay.buildingTier) {
  8013. this.sendRpc({name: "UpgradeBuilding", uid: buildings[i].uid});
  8014. };
  8015. };
  8016. } else if (buildingOverlay.buildingUid) {
  8017. this.sendRpc({name: "UpgradeBuilding", uid: buildingOverlay.buildingUid});
  8018. };
  8019. };
  8020. },
  8021. 89: function() {
  8022. if (this.parent.shared.options.control.enabled) {
  8023. const buildingOverlay = game.ui.components.BuildingOverlay;
  8024. if (buildingOverlay.buildingUid) {
  8025. this.sendRpc({name: "DeleteBuilding", uid: buildingOverlay.buildingUid});
  8026. };
  8027. };
  8028. },
  8029. 76: function() {
  8030. if (this.parent.shared.options.control.enabled) {
  8031. this.sendRpc({
  8032. name: "BuyItem",
  8033. itemName: "PetRevive",
  8034. tier: 1
  8035. });
  8036. this.sendRpc({
  8037. name: "EquipItem",
  8038. itemName: "PetRevive",
  8039. tier: 1
  8040. });
  8041. };
  8042. },
  8043. 186: function() {
  8044. if (this.parent.shared.options.control.enabled && this.player.petTick) {
  8045. this.sendRpc({name: "DeleteBuilding", uid: this.player.petTick.uid});
  8046. }
  8047. }
  8048. /*
  8049. 221: function() {
  8050. this.parent.shared.options.control.enabled && game.network.sendRpc({name: "JoinPartyByShareKey", partyShareKey: this.player.partyShareKey});
  8051. }
  8052. */
  8053. },
  8054. keydown: {
  8055. 87: function(e) {
  8056. if (e.repeat) return;
  8057. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  8058. this.sendInput({up: 1, down: 0});
  8059. };
  8060. },
  8061. 83: function(e) {
  8062. if (e.repeat) return;
  8063. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  8064. this.sendInput({up: 0, down: 1});
  8065. };
  8066. },
  8067. 68: function(e) {
  8068. if (e.repeat) return;
  8069. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  8070. this.sendInput({right: 1, left: 0});
  8071. };
  8072. },
  8073. 65: function(e) {
  8074. if (e.repeat) return;
  8075. if (this.parent.shared.options.control.enabled && !this.typeSpecificVariables.autoMove) {
  8076. this.sendInput({right: 0, left: 1});
  8077. };
  8078. },
  8079. 32: function() {
  8080. if (this.parent.shared.options.control.enabled) {
  8081. this.sendInput({space: 1});
  8082. };
  8083. },
  8084. 82: function() {
  8085. if (this.parent.shared.options.control.enabled) {
  8086. this.sendRpc({name: "BuyItem", itemName: "HealthPotion", tier: 1});
  8087. this.sendRpc({name: "EquipItem", itemName: "HealthPotion", tier: 1});
  8088. };
  8089. },
  8090. 222: function() {
  8091. if (this.parent.shared.options.control.enabled) {
  8092. this.sendRpc({
  8093. name: "EquipItem",
  8094. itemName: "PetCARL",
  8095. tier: this.player.inventory.PetCARL.tier
  8096. });
  8097. this.sendRpc({
  8098. name: "BuyItem",
  8099. itemName: "PetCARL",
  8100. tier: this.player.inventory.PetCARL.tier + 1
  8101. });
  8102. };
  8103. },
  8104. },
  8105. mouseup: {
  8106. 1: function() {
  8107. if (this.parent.shared.options.control.enabled) {
  8108. this.typeSpecificVariables.mouseData.mouseDown = 0;
  8109. this.typeSpecificVariables.mouseData.mouseUp = 1;
  8110. const {worldX, worldY, distance} = this.typeSpecificVariables.mouseData;
  8111. this.sendInput({mouseUp: 1, worldX, worldY, distance});
  8112. };
  8113. },
  8114. 3: function(e) {
  8115. if (this.parent.shared.options.control.enabled) {
  8116. if (this.typeSpecificVariables.autoMove == this.typeSpecificVariables.FOLLOW_TYPE.LOCK) {
  8117. this.typeSpecificVariables.followPoint = game.renderer.screenToWorld(e.clientX, e.clientY);
  8118. };
  8119. };
  8120. },
  8121. },
  8122. mousedown: {
  8123. 3: function() {
  8124. /*
  8125. const mouseToWorld = game.renderer.screenToWorld(e.clientX, e.clientY);
  8126. const options = game.script.options;
  8127. if (!ws.isclosed && ws.local.isOnControl) {
  8128. if (e.which === 3) {
  8129. ws.local.moveaway = true;
  8130. const packet = {};
  8131. if (ws.entities.myPlayer.position.y - mouseToWorld.y > 1) {
  8132. packet.down = 0;
  8133. } else {
  8134. packet.down = 1;
  8135. }
  8136. if (-ws.entities.myPlayer.position.y + mouseToWorld.y > 1) {
  8137. packet.up = 0;
  8138. } else {
  8139. packet.up = 1;
  8140. }
  8141. if (-ws.entities.myPlayer.position.x + mouseToWorld.x > 1) {
  8142. packet.left = 0;
  8143. } else {
  8144. packet.left = 1;
  8145. }
  8146. if (ws.entities.myPlayer.position.x - mouseToWorld.x > 1) {
  8147. packet.right = 0;
  8148. } else {
  8149. packet.right = 1;
  8150. }
  8151. ws.move(packet);
  8152. }
  8153. }
  8154. */
  8155. },
  8156. 1: function() {
  8157. if (this.parent.shared.options.control.enabled) {
  8158. /*
  8159. if (options.raid) {
  8160. if (_this.nearestToCursor !== ws.player.uid) {
  8161. ws.network.sendInput({mouseUp: 0});
  8162. }
  8163. if (_this.nearestToCursor === ws.player.uid) {
  8164. ws.network.sendInput({space: 1});
  8165. ws.network.sendInput({space: 0});
  8166. ws.network.sendRpc({name: "JoinPartyByShareKey", partyShareKey: Game.currentGame.ui.getPlayerPartyShareKey() + ""});
  8167. }
  8168. if (game.ui.playerPartyShareKey === ws.player.psk.partyShareKey && ws.entities.myPlayer.dead) {
  8169. ws.network.sendRpc({name: "LeaveParty"});
  8170. ws.network.sendInput({mouseUp: 0});
  8171. } else {
  8172. ws.network.sendInput({mouseUp: 0});
  8173. }
  8174. } else {
  8175. */
  8176. this.typeSpecificVariables.mouseData.mouseDown = 1;
  8177. this.typeSpecificVariables.mouseData.mouseUp = 0;
  8178. const {yaw, worldX, worldY, distance} = this.typeSpecificVariables.mouseData;
  8179. this.sendInput({mouseDown: yaw, worldX, worldY, distance});
  8180. // }
  8181. };
  8182. }
  8183. },
  8184. mousemove: function(e) {
  8185. if (this.parent.shared.options.control.enabled) {
  8186. this.typeSpecificVariables.mouseData.mousePos = {x: e.clientX, y: e.clientY};
  8187. const worldMouse = game.renderer.screenToWorld(e.clientX, e.clientY);
  8188. if (this.typeSpecificVariables.autoMove == this.typeSpecificVariables.FOLLOW_TYPE.MOUSE) this.typeSpecificVariables.followPoint = worldMouse;
  8189.  
  8190. if (this.player?.targetTick?.position && !this.player?.targetTick?.dead) {
  8191. const xPos = (-this.player.targetTick.position.x + worldMouse.x) * 100,
  8192. yPos = (-this.player.targetTick.position.y + worldMouse.y) * 100,
  8193. yaw = game.inputPacketCreator.screenToYaw(xPos, yPos);
  8194.  
  8195. if (this.typeSpecificVariables.mouseData.yaw != yaw) {
  8196. const distance = game.inputPacketCreator.distanceToCenter(xPos, yPos) / 100;
  8197.  
  8198. this.typeSpecificVariables.mouseData.yaw = yaw;
  8199. this.typeSpecificVariables.mouseData.worldX = xPos;
  8200. this.typeSpecificVariables.mouseData.worldY = yPos;
  8201. this.typeSpecificVariables.mouseData.distance = distance;
  8202.  
  8203. if (this.typeSpecificVariables.mouseData.mouseDown) {
  8204. this.sendInput({mouseMovedWhileDown: yaw, worldX: xPos, worldY: yPos, distance});
  8205. }
  8206. if (this.typeSpecificVariables.mouseData.mouseUp) {
  8207. this.sendInput({mouseMoved: yaw, worldX: xPos, worldY: yPos, distance});
  8208. };
  8209. // game.world.entities[this.player.uid].targetTick.aimingYaw = game.world.entities[this.player.uid].fromTick.aimingYaw = yaw;
  8210. };
  8211. };
  8212. };
  8213. }
  8214. },
  8215. PACKET_ENTITY_UPDATE: function(data, parent) {
  8216. if (this.player.targetTick.dead) {
  8217. this.typeSpecificVariables.mouseData.yaw = (this.typeSpecificVariables.mouseData.yaw + 1) % 360;
  8218. this.sendInput({mouseMoved: this.typeSpecificVariables.mouseData.yaw});
  8219. }
  8220. if (game.world.localPlayer.entity.fromTick.position.x != game.world.localPlayer.entity.targetTick.position.x || game.world.localPlayer.entity.fromTick.position.y != game.world.localPlayer.entity.targetTick.position.y) {
  8221. if (this.typeSpecificVariables.autoMove == this.typeSpecificVariables.FOLLOW_TYPE.MOUSE) {
  8222. this.typeSpecificVariables.followPoint = game.renderer.screenToWorld(
  8223. this.typeSpecificVariables.mouseData.mousePos.x,
  8224. this.typeSpecificVariables.mouseData.mousePos.y
  8225. );
  8226. };
  8227. if (this.typeSpecificVariables.autoMove == this.typeSpecificVariables.FOLLOW_TYPE.PLAYER) {
  8228. this.typeSpecificVariables.followPoint = game.world.localPlayer.entity.targetTick.position;
  8229. };
  8230. };
  8231. // if (this.parent.shared.options.control.enabled) {
  8232. if (this.typeSpecificVariables.autoMove) {
  8233. const acc = this.typeSpecificVariables.FOLLOW_ACCURACY,
  8234. point = this.typeSpecificVariables.followPoint,
  8235. position = this.player.targetTick.position,
  8236. packet = {};
  8237.  
  8238. if (position.y - point.y > acc) {
  8239. packet.down = 0;
  8240. } else {
  8241. packet.down = 1;
  8242. }
  8243. if (-position.y + point.y > acc) {
  8244. packet.up = 0;
  8245. } else {
  8246. packet.up = 1;
  8247. }
  8248. if (-position.x + point.x > acc) {
  8249. packet.left = 0;
  8250. } else {
  8251. packet.left = 1;
  8252. }
  8253. if (position.x - point.x > acc) {
  8254. packet.right = 0;
  8255. } else {
  8256. packet.right = 1;
  8257. }
  8258. this.sendInput(packet);
  8259. };
  8260. // };
  8261.  
  8262. if (game.options.options.AHRC.enabled && game.options.options.AHRC.multibox) {
  8263. for (let uid in this.player.buildings) {
  8264. let obj = this.player.buildings[uid];
  8265. if (obj.type == "Harvester") {
  8266. const amount = obj.tier * 0.05 - 0.02;
  8267. const ahrcOptions = getId('ahrcOptions');
  8268. ahrcOptions.value !== "c" && this.sendRpc({name: "AddDepositToHarvester", uid: obj.uid, deposit: amount});
  8269. ahrcOptions.value !== "h" && this.sendRpc({name: "CollectHarvester", uid: obj.uid});
  8270. };
  8271. };
  8272. };
  8273. if (game.options.options.autoHeal.enabled && game.options.options.autoHeal.multibox) {
  8274. const healThreshold = getId("auto-heal-threshold").valueAsNumber;
  8275.  
  8276. if (!this.player.inventory.HealthPotion && this.player.targetTick.gold >= 100) {
  8277. this.sendRpc({name: "BuyItem", itemName: "HealthPotion", tier: 1});
  8278. }
  8279. const playerHealth = (this.player.targetTick.health / this.player.targetTick.maxHealth) * 100;
  8280. this.typeSpecificVariables.autoHeal.hasHealed = this.typeSpecificVariables.autoHeal.lastTickHealth <= playerHealth;
  8281. if (playerHealth <= healThreshold && !this.typeSpecificVariables.autoHeal.hasHealed) {
  8282. this.sendRpc({name: "EquipItem", itemName: "HealthPotion", tier: 1});
  8283. }
  8284.  
  8285. const petHealth = (this.player?.petTick?.health / this.player?.petTick?.maxHealth) * 100;
  8286. if (petHealth <= healThreshold) {
  8287. this.sendRpc({name: "BuyItem", itemName: "PetHealthPotion", tier: 1})
  8288. this.sendRpc({name: "EquipItem", itemName: "PetHealthPotion", tier: 1})
  8289. }
  8290. this.typeSpecificVariables.autoHeal.lastTickHealth = playerHealth;
  8291. }
  8292. },
  8293. },
  8294. Filler: {
  8295. PACKET_RPC: function(data, parent) {
  8296. this.sendInput({left: 1, up: 1, right: 0, down: 0});
  8297. // this.sendInput({space: 1});
  8298.  
  8299. if (this.data.name == "Dead") this.sendInput({respawn: 1});
  8300. },
  8301. },
  8302. PlayerTrick: {
  8303. init: function() {
  8304. this.typeSpecificVariables.playerTrickTimeouts = {
  8305. inull: true,
  8306. i1: true,
  8307. i2: true,
  8308. i3: true
  8309. };
  8310. this.typeSpecificVariables.dayTicker = 0;
  8311. },
  8312. getIsZombiesActive: function () {
  8313. let isZombiesActive = false;
  8314. for (let i of game.renderer.npcs.attachments) {
  8315. if (i.fromTick.model !== "NeutralTier1") {
  8316. if (i.fromTick.entityClass == "Npc") {
  8317. isZombiesActive = true;
  8318. return isZombiesActive;
  8319. }
  8320. }
  8321. }
  8322. return isZombiesActive;
  8323. },
  8324. getIsNextWaveActive: function () {
  8325. let isNextWaveActive = false;
  8326. const allComingBossWaves = [9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 121].map(wave => wave - 1);
  8327. for (let wave of allComingBossWaves) {
  8328. game.ui.playerTick.wave == wave && (isNextWaveActive = true);
  8329. }
  8330. return isNextWaveActive;
  8331. },
  8332. getIsWaveActive: function () {
  8333. let isWaveActive = false;
  8334. const allBossWaves = [9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 121];
  8335. for (let wave of allBossWaves) {
  8336. game.ui.playerTick.wave == wave && (isWaveActive = true);
  8337. }
  8338. return isWaveActive;
  8339. },
  8340. PACKET_RPC: function(data, parent) {
  8341. if (this.data.name == "DayCycle") {
  8342. this.typeSpecificVariables.tickData = this.data.response;
  8343. }
  8344. },
  8345. PACKET_ENTITY_UPDATE: function(data, parent) {
  8346. this.typeSpecificVariables.currentTick = data.tick;
  8347.  
  8348. let dayRatio = 0,
  8349. nightRatio = 0,
  8350. barWidth = 130;
  8351. if (this.typeSpecificVariables.tickData) {
  8352. if (this.typeSpecificVariables.tickData.dayEndTick) {
  8353. if (this.typeSpecificVariables.tickData.dayEndTick > 0) {
  8354. var dayLength = this.typeSpecificVariables.tickData.dayEndTick - this.typeSpecificVariables.tickData.cycleStartTick;
  8355. var dayTicksRemaining = this.typeSpecificVariables.tickData.dayEndTick - this.typeSpecificVariables.currentTick;
  8356. dayRatio = 1 - dayTicksRemaining / dayLength;
  8357. }
  8358. } else if (this.typeSpecificVariables.tickData.nightEndTick > 0) {
  8359. var nightLength = this.typeSpecificVariables.tickData.nightEndTick - this.typeSpecificVariables.tickData.cycleStartTick;
  8360. var nightTicksRemaining = this.typeSpecificVariables.tickData.nightEndTick - this.typeSpecificVariables.currentTick;
  8361. dayRatio = 1;
  8362. nightRatio = 1 - nightTicksRemaining / nightLength;
  8363. }
  8364. var currentPosition = (dayRatio * 1 / 2 + nightRatio * 1 / 2) * - barWidth;
  8365. var offsetPosition = currentPosition + barWidth / 2;
  8366. if (offsetPosition) this.typeSpecificVariables.dayTicker = Math.round(offsetPosition);
  8367. }
  8368.  
  8369. // if (game.options.options.playerTrick) {
  8370. if (parent.getIsWaveActive() && parent.getIsZombiesActive() && game.ui.playerPartyMembers.length !== 1) {
  8371. if (this.typeSpecificVariables.playerTrickTimeouts.inull) {
  8372. this.typeSpecificVariables.playerTrickTimeouts.inull = false;
  8373. this.sendRpc({name: "LeaveParty"});
  8374. setTimeout(() => { this.typeSpecificVariables.playerTrickTimeouts && (this.typeSpecificVariables.playerTrickTimeouts.inull = true); }, 250);
  8375. }
  8376. }
  8377. if (this.typeSpecificVariables.dayTicker < -18 && this.typeSpecificVariables.dayTicker >= -23 && !this.typeSpecificVariables.tickData.isDay && parent.getIsZombiesActive() && game.ui.playerPartyMembers.length !== 1) {
  8378. if (this.typeSpecificVariables.playerTrickTimeouts.i1) {
  8379. this.typeSpecificVariables.playerTrickTimeouts.i1 = false;
  8380. this.sendRpc({name: "LeaveParty"});
  8381. setTimeout(() => { this.typeSpecificVariables.playerTrickTimeouts && (this.typeSpecificVariables.playerTrickTimeouts.i1 = true); }, 250);
  8382. }
  8383. }
  8384. if (!parent.getIsZombiesActive() && game.ui.playerPartyMembers.length !== 4 && !parent.getIsNextWaveActive()) {
  8385. if (this.typeSpecificVariables.playerTrickTimeouts.i2) {
  8386. this.typeSpecificVariables.playerTrickTimeouts.i2 = false;
  8387. this.sendRpc({name: "JoinPartyByShareKey", partyShareKey: Game.currentGame.ui.getPlayerPartyShareKey() + ""});
  8388. setTimeout(() => { this.typeSpecificVariables.playerTrickTimeouts && (this.typeSpecificVariables.playerTrickTimeouts.i2 = true); }, 250);
  8389. }
  8390. }
  8391. if (this.typeSpecificVariables.dayTicker > 18 && this.typeSpecificVariables.dayTicker <= 23 && parent.getIsZombiesActive() && this.typeSpecificVariables.tickData.isDay && game.ui.playerPartyMembers.length !== 4) {
  8392. if (this.typeSpecificVariables.playerTrickTimeouts.i3) {
  8393. this.typeSpecificVariables.playerTrickTimeouts.i3 = false;
  8394. this.sendRpc({name: "LeaveParty"});
  8395. setTimeout(() => { this.typeSpecificVariables.playerTrickTimeouts && (this.typeSpecificVariables.playerTrickTimeouts.i3 = true); }, 250)
  8396. }
  8397. }
  8398. // }
  8399. },
  8400. },
  8401. AITO: {
  8402. lastSocket: {},
  8403. PACKET_ENTITY_UPDATE: function(data, parent) {
  8404. if (this.player.partyShareKey) {
  8405. if (this.player.partyShareKey != game.ui.getPlayerPartyShareKey()) {
  8406. this.sendRpc({
  8407. name: "JoinPartyByShareKey",
  8408. partyShareKey: game.ui.getPlayerPartyShareKey()
  8409. });
  8410. } else if (this.player.targetTick.gold >= 10000) {
  8411. this.sendRpc({
  8412. name: "BuyItem",
  8413. itemName: "Pause",
  8414. tier: 1
  8415. });
  8416. };
  8417. };
  8418. },
  8419. PACKET_PRE_ENTER_WORLD: function(data, parent) {
  8420. parent.lastSocket[this.identifiers.id]?.ws?.readyState === 1 && parent.lastSocket[this.identifiers.id].ws.close();
  8421. },
  8422. PACKET_RPC: function(data, parent) {
  8423. this.sendInput({left: 1, up: 1, right: 0, down: 0});
  8424. // this.sendInput({space: 1});
  8425.  
  8426. if (this.data.name == "DayCycle") {
  8427. this.typeSpecificVariables.isDay = this.data.response.isDay;
  8428. if (!this.typeSpecificVariables.isDay) {
  8429. if (this.ws.readyState === 1 && this.typeSpecificVariables.verified === true) {
  8430. parent.lastSocket[this.identifiers.id] = this;
  8431. this.parent.shared.all[this.identifiers.id] = new this.parent.Socket(
  8432. `wss://${game.network.connectionOptions.hostname}:443/`,
  8433. this.identifiers
  8434. );
  8435. }
  8436. } else this.typeSpecificVariables.verified = true;
  8437. }
  8438. if (this.data.name == "Dead") this.sendInput({respawn: 1});
  8439. },
  8440. },
  8441. },
  8442. movementCopy: {
  8443. handlers: [{type: "entityUpdate", names: "onTick"}, {type: "keybind", names: "keyup"}],
  8444. targetLastPos: null,
  8445. target: null,
  8446. onTick: function({entities}) {
  8447. if (game.options.options.movementCopy) {
  8448. if (!this.target) {
  8449. const targets = [];
  8450. for (let entity of game.renderer.npcs.attachments) {
  8451. if (entity.uid === game.world.myUid || entity.targetTick.dead == 1) continue;
  8452. const { position, uid } = entity.targetTick;
  8453. entity.entityClass === "PlayerEntity" && targets.push({position, uid});
  8454. };
  8455. if (targets.length > 0) {
  8456. const myPos = game.ui.playerTick.position;
  8457. targets.sort((a, b) => {
  8458. const distThisToA = measureDistance(myPos, a.position);
  8459. const distThisToB = measureDistance(myPos, b.position);
  8460.  
  8461. if (distThisToA < distThisToB) return -1;
  8462. else if (distThisToA > distThisToB) return 1;
  8463.  
  8464. return 0;
  8465. });
  8466. this.target = targets[0].uid;
  8467. };
  8468. };
  8469.  
  8470. const targetInCurrentTick = entities[this.target];
  8471. const targetInWorldTick = game.world.entities[this.target];
  8472. const currentTargetPosition = targetInCurrentTick?.position;
  8473. const lastTargetPosition = this.targetLastPos || targetInWorldTick.targetTick.position;
  8474.  
  8475. if (currentTargetPosition) {
  8476. const nextMove = predictDirection(lastTargetPosition, currentTargetPosition);
  8477. nextMove && game.network.sendInput(nextMove);
  8478. this.targetLastPos = currentTargetPosition;
  8479. };
  8480.  
  8481. const {position: playerPos} = game.world.entities[game.world.myUid].targetTick;
  8482. const distFromPlayerToTarget = measureDistance(playerPos, targetInWorldTick.targetTick.position);
  8483. if (distFromPlayerToTarget > 48) {
  8484. const nextMove = predictDirection(playerPos, targetInWorldTick.targetTick.position, 48);
  8485. nextMove && game.network.sendInput(nextMove);
  8486. };
  8487. };
  8488. },
  8489. keyup: function(e) {
  8490. if (e.key == "[") getId("toggle-movementCopy").click();
  8491. },
  8492. },
  8493. spectate: {
  8494. handlers: [{type: "rpc", names: ["Dead"]}, {type: "keybind", names: ["keydown", "keyup"]}],
  8495. cameraPos: {x: 0, y: 0},
  8496. navigationKeys: {
  8497. // numpad
  8498. 104: "up",
  8499. 98: "down",
  8500. 102: "right",
  8501. 100: "left",
  8502. // wasd
  8503. 87: "up",
  8504. 83: "down",
  8505. 68: "right",
  8506. 65: "left",
  8507. // keypad
  8508. 38: "up",
  8509. 40: "down",
  8510. 39: "right",
  8511. 37: "left"
  8512. },
  8513. direction: {
  8514. up: { axis: "y", value: -96 },
  8515. down: { axis: "y", value: 96 },
  8516. right: { axis: "x", value: 96 },
  8517. left: { axis: "x", value: -96 }
  8518. },
  8519. moveCameraTo: function({x, y}) {
  8520. game.renderer.follow({ getPositionX: () => x, getPositionY: () => y });
  8521. },
  8522. init: function() {
  8523. this.spectatorNote = document.createElement('p');
  8524. this.spectatorNote.innerHTML = `Press Esc to stop spectating...<br>Use arrow keys or WASD to navigate.`;
  8525. this.spectatorNote.style.display = "none";
  8526. this.spectatorNote.style.color = "white";
  8527. this.spectatorNote.style.opacity = '0.5';
  8528. this.spectatorNote.style.textAlign = "center";
  8529. getClass('hud-top-center')[0].appendChild(this.spectatorNote);
  8530.  
  8531. getId('hud-spectate-btn').onclick = () => {
  8532. game.options.options.spectate = true;
  8533. this.spectatorNote.style.display = "block";
  8534. getId("hud-respawn").style.display = "none";
  8535. };
  8536. },
  8537. Dead: function() {
  8538. this.cameraPos = game.ui.playerTick.position;
  8539. },
  8540. keyup: function(e) {
  8541. if (e.key == "Escape") {
  8542. if (game.options.options.spectate) {
  8543. game.options.options.spectate = false;
  8544. this.spectatorNote.style.display = "none";
  8545. getId("hud-respawn").style.display = "block";
  8546. game.renderer.follow(game.world.entities[game.world.myUid]);
  8547. }
  8548. }
  8549. },
  8550. keydown: function(e) {
  8551. if (!game.options.options.spectate) return;
  8552. if (e.keyCode in this.navigationKeys) {
  8553. const {axis, value} = this.direction[this.navigationKeys[e.keyCode]];
  8554. this.cameraPos[axis] += value;
  8555. this.moveCameraTo(this.cameraPos);
  8556. };
  8557. },
  8558. },
  8559. dragBox: {
  8560. handlers: [{type: "keybind", names: "keydown"}],
  8561. buildingModels: ["Wall", "Door", "SlowTrap", "ArrowTower", "CannonTower", "MeleeTower", "BombTower", "MagicTower", "GoldMine", "Harvester"],
  8562. firstDragMouse: {
  8563. pos: {x: 0, y: 0},
  8564. hasDragged: false
  8565. },
  8566. mouseDragPos: {x: 0, y: 0},
  8567. staticWorldPos: undefined,
  8568. dragBoxElem: undefined,
  8569. dragBoxMenuElem: undefined,
  8570. resetData: function() {
  8571. this.firstDragMouse = {
  8572. pos: {x: 0, y: 0},
  8573. hasDragged: false
  8574. };
  8575. this.mouseDragPos = {x: 0, y: 0};
  8576. },
  8577. isWithinSelection: function({x, y}, {pos1, pos2}) {
  8578. return (x > Math.min(pos1.x, pos2.x) && x < Math.max(pos1.x, pos2.x) && y > Math.min(pos1.y, pos2.y) && y < Math.max(pos1.y, pos2.y));
  8579. },
  8580. findStash: function({pos1, pos2}) {
  8581. return game.renderer.scenery.attachments.find((entity) => {
  8582. if (entity.fromTick.model == "GoldStash") {
  8583. const building = entity.targetTick.position;
  8584. if (this.isWithinSelection(building, {pos1, pos2})) return entity;
  8585. }
  8586. });
  8587. },
  8588. cancelDragBox: function() {
  8589. this.dragBoxMenuElem.remove();
  8590. this.dragBoxElem.remove();
  8591. this.staticWorldPos = undefined;
  8592. window.disableZoom = false;
  8593. },
  8594. init: function() {
  8595. getId("hud").addEventListener("mousedown", this.onMouseDown.bind(this));
  8596. getId("hud").addEventListener("mousemove", this.onMouseMove.bind(this));
  8597. getId("hud").addEventListener("mouseup", this.onMouseUp.bind(this));
  8598. game.renderer.on("cameraUpdate", this.onCameraUpdate.bind(this));
  8599. },
  8600. onMouseDown: function(e) {
  8601. if (this.firstDragMouse.hasDragged || !game.options.options.dragBox || !game.world.inWorld) return;
  8602. window.disableZoom = true;
  8603. this.firstDragMouse = {
  8604. pos: {x: e.clientX, y: e.clientY},
  8605. hasDragged: true
  8606. };
  8607. this.dragBoxElem = document.createElement('div');
  8608. this.dragBoxElem.classList.add('dragBox');
  8609. this.dragBoxElem.style.top = `${e.clientY}px`;
  8610. this.dragBoxElem.style.left = `${e.clientX}px`;
  8611. getId("hud").appendChild(this.dragBoxElem);
  8612. },
  8613. onMouseMove: function(e) {
  8614. if (!this.firstDragMouse.hasDragged || !game.world.inWorld) return;
  8615. // clearTimeout(this.dragTimeout);
  8616. this.mouseDragPos = {x: e.clientX, y: e.clientY};
  8617. this.dragBoxElem.style.top = `${Math.min(this.mouseDragPos.y, this.firstDragMouse.pos.y)}px`;
  8618. this.dragBoxElem.style.left = `${Math.min(this.mouseDragPos.x, this.firstDragMouse.pos.x)}px`;
  8619. this.dragBoxElem.style.width = `${Math.abs(this.mouseDragPos.x - this.firstDragMouse.pos.x)}px`;
  8620. this.dragBoxElem.style.height = `${Math.abs(this.mouseDragPos.y - this.firstDragMouse.pos.y)}px`;
  8621. // this.dragTimeout = setTimeout(function() { this.onMouseUp(e); }.bind(this), 2000);
  8622. },
  8623. onMouseUp: function(e) {
  8624. if (!this.firstDragMouse.hasDragged || !game.world.inWorld) return;
  8625. // clearTimeout(this.dragTimeout);
  8626. const lastDragPos = { x: e.clientX, y: e.clientY };
  8627. const oldPos = { x: this.firstDragMouse.pos.x, y: this.firstDragMouse.pos.y };
  8628. this.staticWorldPos = game.renderer.screenToWorld(oldPos.x, oldPos.y);
  8629. if (Math.hypot(lastDragPos.x - oldPos.x, lastDragPos.y - oldPos.y) < 50) {
  8630. this.dragBoxElem.remove();
  8631. this.resetData();
  8632. this.staticWorldPos = undefined;
  8633. return;
  8634. }
  8635. this.dragBoxMenuElem = document.createElement('div');
  8636. this.dragBoxMenuElem.classList.add('dragBoxMenu');
  8637. this.dragBoxMenuElem.style.top = `${lastDragPos.y}px`;
  8638. this.dragBoxMenuElem.style.left = `${lastDragPos.x}px`;
  8639. this.dragBoxMenuElem.innerHTML = `
  8640. <button id="saveSelection">Save Towers</button>
  8641. <button id="delWithin">Delete Selection</button>
  8642. <button id="cancelDragBox">Cancel</button>
  8643. <small style="color: red; display: none;" id="selectionErrorMessage">Cannot find any base. Please try again.</small>
  8644. `;
  8645. getId("hud").appendChild(this.dragBoxMenuElem);
  8646.  
  8647. game.options.options.dragBox = false;
  8648. this.resetData();
  8649.  
  8650. const pos1 = this.staticWorldPos;
  8651. const pos2 = game.renderer.screenToWorld(lastDragPos.x, lastDragPos.y);
  8652.  
  8653. getId("cancelDragBox").onclick = this.cancelDragBox.bind(this);
  8654. getId("delWithin").onclick = function(e) {
  8655. const roundedX = Math.round(pos1.x / 48) * 48;
  8656. const roundedY = Math.round(pos1.y / 48) * 48;
  8657.  
  8658. const deltaX = Math.round(Math.abs(pos1.x - pos2.x) / 48);
  8659. const deltaY = Math.round(Math.abs(pos1.y - pos2.y) / 48);
  8660.  
  8661. const entitiesWithin = {};
  8662.  
  8663. for (let x = roundedX; x < roundedX + (deltaX * 48); x += 48) {
  8664. for (let y = roundedY; y < roundedY + (deltaX * 48); y += 48) {
  8665. Object.assign(entitiesWithin, getEntityAtPos(x, y));
  8666. };
  8667. };
  8668.  
  8669. game.script.sell.sellAllWithUids(Object.keys(entitiesWithin));
  8670.  
  8671. this.cancelDragBox();
  8672. }.bind(this);
  8673. getId("saveSelection").onclick = function(e) {
  8674. const goldStash = this.findStash({pos1, pos2})?.fromTick?.position;
  8675. let baseStr = '';
  8676. if (!goldStash) {
  8677. getId("selectionErrorMessage").style.display = "block";
  8678. return;
  8679. };
  8680. for (let uid in game.world.entities) {
  8681. const entity = game.world.entities[uid];
  8682. if (this.buildingModels.includes(entity.fromTick.model)) {
  8683. const buildingPos = entity.targetTick.position;
  8684. if (this.isWithinSelection(buildingPos, {pos1, pos2})) {
  8685. baseStr += `${this.buildingModels.indexOf(entity.fromTick.model)},${goldStash.x - buildingPos.x},${goldStash.y - buildingPos.y},${entity.targetTick.yaw};`;
  8686. };
  8687. }
  8688. };
  8689. if (baseStr.length == 0) {
  8690. getId("selectionErrorMessage").style.display = "block";
  8691. return;
  8692. };
  8693.  
  8694. this.cancelDragBox();
  8695.  
  8696. game.ui.components.MenuSettings.isVisible() || game.ui.components.MenuSettings.show();
  8697. window.isSlotEmpty(localStorage.totalSlots) && window.createBaseSlot();
  8698. setPage('0');
  8699. getId("more-baseSaver").click();
  8700. getId("base-item-" + localStorage.totalSlots).click();
  8701. getId('target-base-design').value = baseStr;
  8702. }.bind(this);
  8703. },
  8704. onCameraUpdate: function() {
  8705. if (!this.staticWorldPos) return;
  8706. const {x: realScreenX, y: realScreenY } = game.renderer.worldToScreen(this.staticWorldPos.x, this.staticWorldPos.y);
  8707. const rect = this.dragBoxElem.getBoundingClientRect();
  8708.  
  8709. this.dragBoxElem.style.top = `${realScreenY}px`;
  8710. this.dragBoxElem.style.left = `${realScreenX}px`;
  8711. this.dragBoxMenuElem.style.top = `${rect.y + rect.height}px`;
  8712. this.dragBoxMenuElem.style.left = `${rect.x + rect.width}px`;
  8713. },
  8714. onResize: function() {
  8715.  
  8716. },
  8717. keydown: function(e) {
  8718. if (!e.repeat && e.shiftKey && e.key == "Z") {
  8719. game.options.options.dragBox = true;
  8720. };
  8721. },
  8722. },
  8723. navigator: {
  8724. handlers: [{type: "keybind", names: "keyup"}],
  8725.  
  8726. targetDisplay: null,
  8727.  
  8728. GRID_WIDTH: null,
  8729. GRID_HEIGHT: null,
  8730.  
  8731. dStar: null,
  8732.  
  8733. currentMap: null,
  8734. currentPath: null,
  8735.  
  8736. startNode: null,
  8737. goalNode: null,
  8738.  
  8739. hasRecomputed: false,
  8740. nextIndex: 0,
  8741.  
  8742. shouldMove: false,
  8743. target: null,
  8744. init() {
  8745. getId("hud-map").onclick = this.onMapClick.bind(this);
  8746. },
  8747. onMapClick: function(e) {
  8748. if (!e.shiftKey) return;
  8749. const rect = getId("hud-map").getBoundingClientRect(),
  8750. x = e.clientX - rect.left,
  8751. y = e.clientY - rect.top;
  8752. const worldX = (x / rect.width) * game.world.getWidth(),
  8753. worldY = (y / rect.height) * game.world.getHeight();
  8754.  
  8755. if (game.options.options.navigator) {
  8756. this.stop();
  8757. game.ui.components.PopupOverlay.showHint("Stopped current navigation.");
  8758. } else {
  8759. if (typeof worldX !== "number" || typeof worldY !== "number") return game.ui.components.PopupOverlay.showHint("Invalid value!");
  8760. if (worldX > 23900 || worldX < 30 || worldY > 23900 || worldY < 30) return game.ui.components.PopupOverlay.showHint("Coordinates too small / big");
  8761.  
  8762. this.targetDisplay = document.createElement("div");
  8763. this.targetDisplay.classList.add('hud-map-player');
  8764. this.targetDisplay.style.display = "block";
  8765. this.targetDisplay.style.left = x + "px";
  8766. this.targetDisplay.style.top = y + "px";
  8767. this.targetDisplay.style.background = 'var(--light-hover-btn)';
  8768. getId("hud-map").appendChild(this.targetDisplay);
  8769.  
  8770. this.start(worldX, worldY);
  8771. };
  8772. },
  8773. start: function(x, y) {
  8774. game.options.options.navigator = true;
  8775. this.shouldMove = true;
  8776. this.target = {x, y};
  8777.  
  8778. this.initMap(x, y);
  8779. this.moveToNextPath();
  8780. },
  8781. stop: function() {
  8782. this.reset();
  8783. this.shouldMove = false;
  8784. game.network.sendInput({right: 0, left: 0, up: 0, down: 0});
  8785. game.options.options.navigator = false;
  8786. },
  8787. reset: function() {
  8788. this.targetDisplay?.remove?.();
  8789.  
  8790. this.dStar = null;
  8791.  
  8792. this.currentMap = null;
  8793. this.currentPath = null;
  8794.  
  8795. this.startNode = null;
  8796. this.goalNode = null;
  8797.  
  8798. this.hasRecomputed = false;
  8799. this.nextIndex = 0;
  8800. },
  8801. initMap: function(x, y) {
  8802. console.log('initializing');
  8803. this.GRID_WIDTH = game.world.entityGrid.rows;
  8804. this.GRID_HEIGHT = game.world.entityGrid.columns;
  8805.  
  8806. this.dStar = new DStarLite(this.GRID_WIDTH, this.GRID_HEIGHT);
  8807.  
  8808. this.currentMap = structuredClone(game.world.entityGrid.entityMap);
  8809.  
  8810. console.log(this.currentMap);
  8811. const playerCellIndex = this.currentMap[game.world.myUid][0];
  8812.  
  8813. this.startNode = game.world.entityGrid.getCellCoords(playerCellIndex);
  8814. this.goalNode = game.world.entityGrid.getCellCoords(game.world.entityGrid.getCellIndexes(x, y, {width: 1, height: 1}));
  8815.  
  8816. for (let uid in this.currentMap) {
  8817. if (uid == game.world.myUid) continue;
  8818. for (let cellIndex of this.currentMap[uid]) {
  8819. const cellCoord = game.world.entityGrid.getCellCoords(cellIndex);
  8820. this.dStar.addObstacle(cellCoord.x, cellCoord.y);
  8821. };
  8822. };
  8823.  
  8824. this.dStar.initialize(this.startNode, this.goalNode);
  8825. this.dStar.computeShortestPath() && (this.currentPath = this.dStar.getPath());
  8826. console.log("initialized", this.startNode, this.goalNode);
  8827. },
  8828. updateObstacleChange: function() {
  8829. let shouldUpdateStartNode = false;
  8830. // add new obstacles
  8831. for (let uid in game.world.entityGrid.entityMap) {
  8832. if (uid == game.world.myUid) continue;
  8833. if (!(uid in this.currentMap)) {
  8834. shouldUpdateStartNode = true;
  8835. for (let cellIndex of game.world.entityGrid.entityMap[uid]) {
  8836. const cellCoord = game.world.entityGrid.getCellCoords(cellIndex);
  8837. this.dStar.updateObstacle(cellCoord.x, cellCoord.y, true);
  8838. };
  8839. };
  8840. };
  8841. // remove old obstacles
  8842. for (let uid in this.currentMap) {
  8843. if (uid == game.world.myUid) continue;
  8844. if (!(uid in game.world.entityGrid.entityMap)) {
  8845. shouldUpdateStartNode = true;
  8846. for (let cellIndex of this.currentMap[uid]) {
  8847. const cellCoord = game.world.entityGrid.getCellCoords(cellIndex);
  8848. this.dStar.updateObstacle(cellCoord.x, cellCoord.y, false);
  8849. };
  8850. };
  8851. };
  8852.  
  8853. if (shouldUpdateStartNode) {
  8854. const playerCellIndex = game.world.entityGrid.entityMap[game.world.myUid][0];
  8855. this.startNode = game.world.entityGrid.getCellCoords(playerCellIndex);
  8856. this.dStar.handleStartMoved(this.startNode);
  8857.  
  8858. const foundNewPath = this.dStar.computeShortestPath();
  8859. if (foundNewPath) {
  8860. console.log("real");
  8861. console.log(this.dStar);
  8862.  
  8863. this.currentPath = this.dStar.getPath();
  8864. this.hasRecomputed = true;
  8865. };
  8866. };
  8867.  
  8868. this.currentMap = structuredClone(game.world.entityGrid.entityMap);
  8869. },
  8870. moveToNextPath: function() {
  8871. try {
  8872. this.updateObstacleChange();
  8873. if (!this.shouldMove) return;
  8874.  
  8875. if (this.hasRecomputed) {
  8876. this.nextIndex = 1;
  8877. this.hasRecomputed = false;
  8878. };
  8879.  
  8880. this.nextIndex = ++this.nextIndex;
  8881. let nextPath = this.currentPath[this.nextIndex];
  8882. if (nextPath == undefined) nextPath = this.currentPath[this.currentPath.length - 1];
  8883. if (inRange(nextPath.x * 48, this.target.x, 50) && inRange(nextPath.y * 48, this.target.y, 50)) return this.stop();
  8884.  
  8885. console.log(this.currentPath, nextPath);
  8886.  
  8887. this.moveTowards({x: nextPath.x * 48, y: nextPath.y * 48});
  8888.  
  8889. setTimeout(this.moveToNextPath.bind(this), 50);
  8890. } catch(e) {
  8891. console.log(e);
  8892. this.stop();
  8893. };
  8894. },
  8895. moveTowards: function(point, acc = 48) {
  8896. console.log(point);
  8897. const packet = {};
  8898. const position = game.ui.playerTick.position;
  8899. if (position.y - point.y > acc) {
  8900. packet.down = 0;
  8901. } else {
  8902. packet.down = 1;
  8903. }
  8904. if (-position.y + point.y > acc) {
  8905. packet.up = 0;
  8906. } else {
  8907. packet.up = 1;
  8908. }
  8909. if (-position.x + point.x > acc) {
  8910. packet.left = 0;
  8911. } else {
  8912. packet.left = 1;
  8913. }
  8914. if (position.x - point.x > acc) {
  8915. packet.right = 0;
  8916. } else {
  8917. packet.right = 1;
  8918. }
  8919. game.network.sendInput(packet);
  8920. },
  8921. keyup: function(e) {
  8922. if (e.key == "Escape") {
  8923. if (game.options.options.navigator) {
  8924. this.stop();
  8925. game.ui.components.PopupOverlay.showHint("Stopped current navigation.");
  8926. }
  8927. };
  8928. },
  8929. },
  8930. zoom: {
  8931. dimension: 1,
  8932. zoomonscroll: false,
  8933. upd: function() {
  8934. if (window.disableZoom) return;
  8935. getClass('zoom-prop')[0].innerText = `${this.dimension.toFixed(1)}x`;
  8936.  
  8937. const renderer = Game.currentGame.renderer;
  8938. let canvasWidth = window.innerWidth * window.devicePixelRatio;
  8939. let canvasHeight = window.innerHeight * window.devicePixelRatio;
  8940. let ratio = canvasHeight / (1080 * this.dimension);
  8941. renderer.scale = ratio;
  8942. renderer.entities.setScale(ratio);
  8943. renderer.ui.setScale(ratio);
  8944. renderer.renderer.resize(canvasWidth, canvasHeight);
  8945. renderer.viewport.width = renderer.renderer.width / renderer.scale + 2 * renderer.viewportPadding;
  8946. renderer.viewport.height = renderer.renderer.height / renderer.scale + 2 * renderer.viewportPadding;
  8947.  
  8948. const event = new Event("zoom");
  8949. document.dispatchEvent(event);
  8950. },
  8951. onWindowResize: function(e) {
  8952. if (this.zoomonscroll && e.deltaY) {
  8953. if (e.deltaY > 0) this.dimension *= 1.02;
  8954. else if (e.deltaY < 0) this.dimension /= 1.02;
  8955. }
  8956. this.upd();
  8957. },
  8958. zoom: function(val) {
  8959. this.dimension = val;
  8960. this.upd();
  8961. },
  8962. toggleZoomOnScroll: function() {
  8963. this.dimension /= 1.02;
  8964. this.zoomonscroll = !this.zoomonscroll;
  8965. const zoomMode = document.querySelector("#zoom-mode");
  8966. const zoomBtns = [...document.getElementsByClassName('hud-zoom-item')];
  8967. if (!this.zoomonscroll) {
  8968. this.resetZoom();
  8969. for (let i of zoomBtns) i.classList.remove('tag-is-disabled');
  8970. zoomMode.innerText = "Button";
  8971. } else {
  8972. zoomMode.innerText = "Scroll";
  8973. for (let i of zoomBtns) i.classList.add('tag-is-disabled');
  8974. }
  8975. },
  8976. zoomOut: function() {
  8977. this.dimension *= 1.25;
  8978. this.zoom(this.dimension);
  8979. },
  8980. zoomIn: function() {
  8981. this.dimension /= 1.25;
  8982. this.zoom(this.dimension);
  8983. },
  8984. resetZoom: function() {
  8985. this.dimension = 1;
  8986. this.zoom(this.dimension);
  8987. },
  8988. init: function() {
  8989. getId('hud').insertAdjacentHTML('beforeend', `
  8990. <div class="interaction-wheel">
  8991. <a class="hud-zoom-item zoom-reset" onclick="game.script.zoom.resetZoom();"><i class="fa fa-undo fa-lg" style="font-size: 30px;"></i></a>
  8992. <a class="hud-zoom-item zoom-up" onclick="game.script.zoom.zoomOut();"><i class="fa fa-arrow-up fa-2x" style="font-size: 30px;"></i></a>
  8993. <a class="hud-zoom-item zoom-down" onclick="game.script.zoom.zoomIn();"><i class="fa fa-arrow-down fa-2x" style="font-size: 30px;"></i></a>
  8994. <a class="hud-zoom-item zoom-prop">1.0x</a>
  8995. <a id="zoom-mode">Button</a>
  8996. <a id="next-wheel" onclick="game.script.zoom.toggleZoomOnScroll();"></a>
  8997. </div>
  8998. `);
  8999. document.addEventListener('keyup', function(e) {
  9000. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  9001. if (e.code == 'KeyG') {
  9002. const wheelDisplay = getClass('interaction-wheel')[0];
  9003. wheelDisplay.style.display = (wheelDisplay.style.display === 'block') ? 'none' : 'block';
  9004. }
  9005. if (e.code == "KeyN") {
  9006. game.script.zoom.zoomIn();
  9007. }
  9008. if (e.code == "KeyM") {
  9009. game.script.zoom.zoomOut();
  9010. }
  9011. if (e.key == "Escape") {
  9012. getClass('interaction-wheel')[0].style.display = 'none';
  9013. };
  9014. };
  9015. });
  9016. window.onresize = this.onWindowResize.bind(this);
  9017. window.onwheel = this.onWindowResize.bind(this);
  9018. window.onresize();
  9019. },
  9020. },
  9021. markers: {
  9022. currentIndex: 0,
  9023. allMarkers: [],
  9024. removeMarker: function(id) {
  9025. getId(id)?.remove?.();
  9026. delete this.allMarkers[id];
  9027. },
  9028. placeMarker: function({x, y, id, timeout, shouldIndicateIndex}) {
  9029. id ||= genUUID();
  9030. shouldIndicateIndex && (this.currentIndex++);
  9031. const markerLeft = parseInt(Math.round(x / game.world.getWidth() * 100)) - 4;
  9032. const markerTop = parseInt(Math.round(y / game.world.getHeight() * 100)) - 14;
  9033.  
  9034. const markerElem = document.createElement("div");
  9035. markerElem.style.left = `${markerLeft}%`;
  9036. markerElem.style.top = `${markerTop}%`;
  9037. markerElem.style.display = "block";
  9038. markerElem.style.color = "white";
  9039. markerElem.style.position = "absolute";
  9040. markerElem.classList.add("map-display");
  9041. markerElem.id = id;
  9042. markerElem.innerHTML = `<i class='fa fa-map-marker'>${shouldIndicateIndex ? this.currentIndex : ""}</i>`;
  9043. markerElem.onclick = (e) => {
  9044. e.stopPropagation();
  9045. if (e.shiftKey) return game.script.navigator.onMapClick(e);
  9046. game.ui.components.PopupOverlay.showConfirmation("Do you want to remove this marker?", 5000, (() => { this.removeMarker(id); }).bind(this));
  9047. };
  9048. getId("hud-map").insertAdjacentElement("beforeend", markerElem);
  9049.  
  9050. this.allMarkers[id] = {x, y};
  9051. timeout && setTimeout(() => {
  9052. getId(`${id}`).remove();
  9053. }, 240000);
  9054. },
  9055. init: function() {
  9056. getId("hud-map").addEventListener("click", (e) => {
  9057. if (e.shiftKey) return;
  9058. const rect = getId("hud-map").getBoundingClientRect(),
  9059. x = e.clientX - rect.left,
  9060. y = e.clientY - rect.top;
  9061. const worldX = (x / rect.width) * game.world.getWidth(),
  9062. worldY = (y / rect.height) * game.world.getHeight();
  9063.  
  9064. this.placeMarker({x: worldX, y: worldY});
  9065. });
  9066. },
  9067. },
  9068. optimize: {
  9069. zombieSprite: true,
  9070. towerSprite: true,
  9071. projectileSprite: true,
  9072. updateAnimation: true,
  9073. background: true,
  9074. init: function() {
  9075. if (window.location.hostname !== "localhost") {
  9076. getId("shouldUseOptimization").addEventListener("change", ({target}) => {
  9077. game.script.optimize.background = !target.checked;
  9078. });
  9079.  
  9080. game.world.networkEntityPool = null;
  9081. game.world._networkEntityPool = [];
  9082.  
  9083. const bsTick = { uid: 0, entityClass: null };
  9084. const poolSize = Game.currentGame.getNetworkEntityPooling();
  9085. for (let i = 0; i < poolSize; i++) {
  9086. const entity = new game.renderer.entityType(bsTick);
  9087. entity.reset();
  9088. game.world._networkEntityPool.push(entity);
  9089. };
  9090. game.world.getPooledNetworkEntityCount = function() {
  9091. return this._networkEntityPool.length;
  9092. };
  9093. } else {
  9094. getId("shouldUseOptimization").disabled = true;
  9095. getId("optimize-div").classList.add("disabled");
  9096. };
  9097. },
  9098. },
  9099. };
  9100.  
  9101. /* @Add-ons */
  9102. game.ui.components.PlacementOverlay.update = function () {
  9103. if (this.buildingId) {
  9104. var buildingSchema = this.ui.getBuildingSchema(),
  9105. building = buildingSchema[this.buildingId],
  9106. mousePos = this.ui.getMousePosition(),
  9107. world = Game.currentGame.world,
  9108. worldMousePos = Game.currentGame.renderer.screenToWorld(mousePos.x, mousePos.y),
  9109. cells = world.entityGrid.getCellIndexes(worldMousePos.x, worldMousePos.y, {
  9110. 'width': building.gridWidth,
  9111. 'height': building.gridHeight
  9112. }),
  9113. cellSize = world.entityGrid.getCellSize(),
  9114. coord = {
  9115. 'x': 0,
  9116. 'y': 0
  9117. };
  9118. for (var cell in cells) {
  9119. if (cells[cell]) {
  9120. var cellCoord = world.entityGrid.getCellCoords(cells[cell]),
  9121. _cellCoord = {
  9122. 'x': cellCoord.x * cellSize + cellSize / 2,
  9123. 'y': cellCoord.y * cellSize + cellSize / 2
  9124. },
  9125. worldToUi = Game.currentGame.renderer.worldToUi(_cellCoord.x, _cellCoord.y),
  9126. isOccupied = this.checkIsOccupied(cells[cell], cellCoord);
  9127. this.placeholderTints[cell].setPosition(worldToUi.x, worldToUi.y);
  9128. this.placeholderTints[cell].setIsOccupied(isOccupied);
  9129. this.placeholderTints[cell].setVisible(true);
  9130. coord.x += cellCoord.x;
  9131. coord.y += cellCoord.y;
  9132. } else this.placeholderTints[cell].setVisible(false);
  9133. };
  9134. coord.x = coord.x / cells.length;
  9135. coord.y = coord.y / cells.length;
  9136. var worldPos = {
  9137. 'x': coord.x * cellSize + cellSize / 2,
  9138. 'y': coord.y * cellSize + cellSize / 2
  9139. },
  9140. uiPos = Game.currentGame.renderer.worldToUi(worldPos.x, worldPos.y);
  9141. if (!this.rangeIndicator) {
  9142. var { maxStashDistance } = game.ui.components.BuildingOverlay;
  9143. if ('GoldStash' == this.buildingId) {
  9144. this.rangeIndicator = game.assetManager.models.rangeIndicatorModel({
  9145. 'width': maxStashDistance * cellSize * 2,
  9146. 'height': maxStashDistance * cellSize * 2
  9147. }, {r: 0xff, g: 0xff, b: 0xff}, {r: 0xdd, g: 0xdd, b: 0xdd});
  9148. } else if (building.rangeTiers) {
  9149. this.rangeIndicator = game.assetManager.models.rangeIndicatorModel({
  9150. 'isCircular': true,
  9151. 'radius': building.rangeTiers[0] * 0.57071
  9152. }, {r: 0xff, g: 0xff, b: 0xff}, {r: 0xdd, g: 0xdd, b: 0xdd});
  9153. };
  9154. this.rangeIndicator && Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator);
  9155. };
  9156. this.placeholderEntity.setPosition(uiPos.x, uiPos.y);
  9157. this.placeholderText.setPosition(uiPos.x, uiPos.y - 110);
  9158. this.rangeIndicator && this.rangeIndicator.setPosition(worldPos.x, worldPos.y);
  9159. };
  9160. };
  9161. game.ui.components.PlacementOverlay.cancelPlacing = function () {
  9162. if (this.buildingId) {
  9163. Game.currentGame.renderer.ui.removeAttachment(this.placeholderEntity);
  9164. Game.currentGame.renderer.ground.removeAttachment(this.rangeIndicator);
  9165. for (let cell in this.placeholderTints) Game.currentGame.renderer.ui.removeAttachment(this.placeholderTints[cell]);
  9166. for (let cell in this.borderTints) Game.currentGame.renderer.ground.removeAttachment(this.borderTints[cell]);
  9167. this.placeholderText.setAlpha(0x0);
  9168. this.placeholderText.setPosition(-0x3e8, -0x3e8);
  9169. this.placeholderEntity = null;
  9170. this.rangeIndicator = null;
  9171. this.placeholderTints = [];
  9172. this.borderTints = [];
  9173. this.buildingId = null;
  9174. };
  9175. };
  9176.  
  9177. /* @Rebinds */
  9178. getId('hud-debug').style.color = 'var(--light-hover-btn)';
  9179. game.debug.onRendererTick = function () {
  9180. if (this.ticks++, this.visible && this.ticks % 0x14 === 0x0) {
  9181. let debugHTML = `Server: ` + Game.currentGame.network.connectionOptions.id + ` (` + Game.currentGame.network.connectionOptions.name + `)<br>`,
  9182. serverTime = Game.currentGame.world.replicator.getServerTime(),
  9183. clientTime = Game.currentGame.world.replicator.getClientTime(),
  9184. realClientTime = Game.currentGame.world.replicator.getRealClientTime(),
  9185. frameStutters = Game.currentGame.world.replicator.getFrameStutters(),
  9186. interpolating = Game.currentGame.world.replicator.getInterpolating(),
  9187. tickByteSize = Game.currentGame.world.replicator.getTickByteSize(),
  9188. tickEntities = Game.currentGame.world.replicator.getTickEntities(),
  9189. pooledNetworkEntityCount = (Game.currentGame.world.getLocalPlayer(), Game.currentGame.world.getPooledNetworkEntityCount()),
  9190. frameExtrapolated = Game.currentGame.metrics.getFramesExtrapolated(),
  9191. clientTimeResets = Game.currentGame.world.replicator.getClientTimeResets(),
  9192. maxExtrapolationTime = Game.currentGame.world.replicator.getMaxExtrapolationTime(),
  9193. playerPos = game.world.localPlayer.entity.getPosition(),
  9194. kilobytePerSec = tickByteSize / 1024 * 20,
  9195. isTickLarge = kilobytePerSec > 150;
  9196. debugHTML = debugHTML + `Ping: ` + Game.currentGame.network.getPing() + ` ms<br>`;
  9197. debugHTML = debugHTML + `Server time: ` + serverTime + '\x20ms<br>';
  9198. debugHTML = debugHTML + `Client time: ` + clientTime + ` ms<br>`;
  9199. debugHTML = debugHTML + `Real client time: ` + realClientTime + ` ms<br>`;
  9200. debugHTML = debugHTML + `Client lag: ` + (serverTime - clientTime) + '\x20ms<br>';
  9201. debugHTML = debugHTML + `Real client lag: ` + (serverTime - realClientTime) + ` ms<br>`;
  9202. debugHTML = debugHTML + 'Stutters:\x20' + frameStutters + `<br>`;
  9203. debugHTML = debugHTML + `Frames extrapolated: ` + frameExtrapolated + `<br>`;
  9204. debugHTML = debugHTML + `Max extrapolation time: ` + maxExtrapolationTime + '<br>';
  9205. debugHTML = debugHTML + `Client time resets: ` + clientTimeResets + `<br>`;
  9206. debugHTML = debugHTML + `Interpolating: ` + interpolating + `<br>`;
  9207. debugHTML = debugHTML + `Tick byte size: ` + (isTickLarge ? "<strong>" : "") + tickByteSize + '\x20(' + kilobytePerSec.toFixed(2) + 'KB/s)' + (isTickLarge ? "</strong>" : "") + '<br>';
  9208. debugHTML = debugHTML + `Tick entities: ` + tickEntities + '<br>';
  9209. debugHTML = debugHTML + 'Pooled\x20network\x20entities:\x20' + pooledNetworkEntityCount + '<br>';
  9210. debugHTML += `Pooled model entities:<br>`;
  9211. for (const modelName in Game.currentGame.getModelEntityPooling()) {
  9212. debugHTML = debugHTML + '- ' + modelName + ': ' + Game.currentGame.world.getPooledModelEntityCount(modelName) + '<br>';
  9213. }
  9214. debugHTML = debugHTML + 'Player\x20position:\x20<br>';
  9215. debugHTML = debugHTML + '-\x20X:\x20' + playerPos.x.toFixed(2) + '<br>';
  9216. debugHTML = debugHTML + '-\x20Y:\x20' + playerPos.y.toFixed(2) + '<br>';
  9217. this.debugElem.innerHTML = debugHTML;
  9218. }
  9219. }
  9220. game.renderer.tickCallbacks[8] = game.debug.onRendererTick.bind(game.debug);
  9221.  
  9222. game.ui.components.MenuParty.update = function () {
  9223. var parties = this.ui.getParties();
  9224. var playerIsLeader = this.ui.getPlayerPartyLeader();
  9225. var playerPartyData = parties[this.ui.getPlayerPartyId()];
  9226. var playerPartyMembers = this.ui.getPlayerPartyMembers();
  9227. var serverId = this.ui.getOption('serverId');
  9228. var staleElems = {};
  9229. var availableParties = 0;
  9230.  
  9231. this.clonedPartyElems ||= {};
  9232. this.closedGridElem ||= getId("privateHud2");
  9233.  
  9234. for (var partyId in this.partyElems) {
  9235. staleElems[partyId] = true;
  9236. }
  9237. for (var partyId in parties) {
  9238. var partyData = parties[partyId];
  9239. var partyElem = this.partyElems[partyId];
  9240. var partyNameSanitized = window.filterXSS(partyData.partyName);
  9241. delete staleElems[partyId];
  9242. if (!this.partyElems[partyId]) {
  9243. partyElem = this.ui.createElement("<div class=\"hud-party-link\"></div>");
  9244. this.clonedPartyElems[partyId] = this.ui.createElement("<div class=\"hud-party-link\"></div>");
  9245. this.partyElems[partyId] = partyElem;
  9246. this.gridElem.appendChild(partyElem);
  9247. this.closedGridElem.appendChild(this.clonedPartyElems[partyId]);
  9248. partyElem.addEventListener('click', this.onPartyJoinRequestHandler(partyData.partyId).bind(this));
  9249. }
  9250. if (partyData.isOpen) {
  9251. partyElem.style.display = 'block';
  9252. this.clonedPartyElems[partyId].style.display = "none";
  9253. availableParties++;
  9254. }
  9255. else {
  9256. partyElem.style.display = 'none';
  9257. this.clonedPartyElems[partyId].style.display = "block";
  9258. }
  9259. if (this.ui.getPlayerPartyId() === partyData.partyId) {
  9260. partyElem.classList.add('is-active');
  9261. partyElem.classList.remove('is-disabled');
  9262.  
  9263. this.clonedPartyElems[partyId].classList.add('is-active');
  9264. this.clonedPartyElems[partyId].classList.remove('is-disabled');
  9265. }
  9266. else if (partyData.memberCount === this.maxPartySize) {
  9267. partyElem.classList.remove('is-active');
  9268. partyElem.classList.add('is-disabled');
  9269.  
  9270. this.clonedPartyElems[partyId].classList.remove('is-active');
  9271. this.clonedPartyElems[partyId].classList.add('is-disabled');
  9272. }
  9273. else {
  9274. partyElem.classList.remove('is-active');
  9275. partyElem.classList.remove('is-disabled');
  9276.  
  9277. this.clonedPartyElems[partyId].classList.remove('is-active');
  9278. this.clonedPartyElems[partyId].classList.remove('is-disabled');
  9279. }
  9280. partyElem.innerHTML = "<strong>" + partyNameSanitized + "</strong><small>ID: " + partyData.partyId + "</small> <span>" + partyData.memberCount + "/" + this.maxPartySize + "</span><span>-</span>";
  9281. this.clonedPartyElems[partyId].innerHTML = "<strong>" + partyNameSanitized + "</strong><small>ID: " + partyData.partyId + "</small> <span>" + partyData.memberCount + "/" + this.maxPartySize + "</span>";
  9282. }
  9283. for (var partyId in staleElems) {
  9284. if (!this.partyElems[partyId]) {
  9285. continue;
  9286. }
  9287. this.partyElems[partyId].remove();
  9288. this.clonedPartyElems[partyId].remove();
  9289. delete this.partyElems[partyId];
  9290. delete this.clonedPartyElems[partyId];
  9291. }
  9292. for (var i in this.memberElems) {
  9293. this.memberElems[i].remove();
  9294. delete this.memberElems[i];
  9295. }
  9296. for (var i in playerPartyMembers) {
  9297. var playerName = window.filterXSS(playerPartyMembers[i].displayName);
  9298. var memberElem = this.ui.createElement(
  9299. "<div class=\"hud-member-link\">\n <strong>" + playerName + "</strong>\n <small>" + (playerPartyMembers[i].isLeader === 1 ? 'Leader' : 'Member') + "</small>\n <div class=\"hud-member-actions\">\n <a class=\"hud-member-can-sell btn" + (!playerIsLeader || playerPartyMembers[i].isLeader === 1 ? ' is-disabled' : '') + (playerPartyMembers[i].canSell === 1 ? ' is-active' : '') + "\"><span class=\"hud-can-sell-tick\"></span> Can sell buildings</a>\n <a class=\"hud-member-kick btn btn-red" + (!playerIsLeader || playerPartyMembers[i].isLeader === 1 ? ' is-disabled' : '') + "\">Kick</a>\n </div>\n </div>"
  9300. );
  9301. this.membersElem.appendChild(memberElem);
  9302. this.memberElems[i] = memberElem;
  9303. if (playerIsLeader && playerPartyMembers[i].isLeader === 0) {
  9304. var kickElem = memberElem.querySelector('.hud-member-kick');
  9305. var canSellElem = memberElem.querySelector('.hud-member-can-sell');
  9306. kickElem.addEventListener('click', this.onPartyMemberKick(i).bind(this));
  9307. canSellElem.addEventListener('click', this.onPartyMemberCanSellToggle(i).bind(this));
  9308. }
  9309. }
  9310. if (availableParties > 0) {
  9311. this.gridEmptyElem.style.display = 'none';
  9312. }
  9313. else {
  9314. this.gridEmptyElem.style.display = 'block';
  9315. }
  9316. if (!playerPartyData) {
  9317. this.tagInputElem.setAttribute('disabled', 'true');
  9318. this.tagInputElem.value = '';
  9319. this.shareInputElem.setAttribute('disabled', 'true');
  9320. this.shareInputElem.value = '';
  9321. this.visibilityElem.classList.add('is-disabled');
  9322. return;
  9323. }
  9324. if (document.activeElement !== this.tagInputElem) {
  9325. this.tagInputElem.value = playerPartyData.partyName;
  9326. }
  9327. if (playerIsLeader) {
  9328. this.tagInputElem.removeAttribute('disabled');
  9329. }
  9330. else {
  9331. this.tagInputElem.setAttribute('disabled', 'true');
  9332. }
  9333. this.shareInputElem.removeAttribute('disabled');
  9334. this.shareInputElem.value = 'https://zombs.io/#/' + serverId + '/' + this.ui.getPlayerPartyShareKey();
  9335. if (playerIsLeader) {
  9336. this.visibilityElem.classList.remove('is-disabled');
  9337. }
  9338. else {
  9339. this.visibilityElem.classList.add('is-disabled');
  9340. }
  9341. if (playerPartyData.isOpen) {
  9342. this.visibilityElem.classList.remove('is-private');
  9343. this.visibilityElem.innerText = 'Public';
  9344. }
  9345. else {
  9346. this.visibilityElem.classList.add('is-private');
  9347. this.visibilityElem.innerText = 'Private';
  9348. }
  9349. };
  9350. getClass("hud-party-actions")[0].insertAdjacentHTML("afterend", `
  9351. <div class="partydiv" style="text-align: center">
  9352. <button class="btn btn-red" style="width: 275.5px;margin: 10px 0 0 3px;box-shadow: none;" onclick="Game.currentGame.network.sendRpc({name: 'LeaveParty'});">Leave</button>
  9353. </div>`);
  9354.  
  9355. game.ui.components.Leaderboard.update = function () {
  9356. const currentGame = Game.currentGame;
  9357. // this.playerUidElems ||= {};
  9358. for (let leaderboardElem = 0; leaderboardElem < this.leaderboardData.length; leaderboardElem++) {
  9359. let playerData = this.leaderboardData[leaderboardElem],
  9360. playerName = this.playerNames[playerData.uid];
  9361. this.playerNames[playerData.uid] || (
  9362. playerName = window.filterXSS(playerData.name),
  9363. this.playerNames[playerData.uid] = playerName
  9364. );
  9365. leaderboardElem in this.playerElems || (
  9366. this.playerElems[leaderboardElem] = this.ui.createElement('<div\x20class=\x22hud-leaderboard-player\x22></div>'),
  9367. // this.playerUidElems[leaderboardElem] = this.ui.createElement('<span\x20class=\x22player-uid\x22>-</span>'),
  9368. this.playerRankElems[leaderboardElem] = this.ui.createElement(`<span class="player-rank">-</span>`),
  9369. this.playerNameElems[leaderboardElem] = this.ui.createElement(`<strong class="player-name">-</strong>`),
  9370. this.playerScoreElems[leaderboardElem] = this.ui.createElement(`<span class="player-score">-</span>`),
  9371. this.playerWaveElems[leaderboardElem] = this.ui.createElement('<span\x20class=\x22player-wave\x22>-</span>'),
  9372.  
  9373. this.playerElems[leaderboardElem].appendChild(this.playerRankElems[leaderboardElem]),
  9374. // this.playerElems[leaderboardElem].appendChild(this.playerUidElems[leaderboardElem]),
  9375. this.playerElems[leaderboardElem].appendChild(this.playerNameElems[leaderboardElem]),
  9376. this.playerElems[leaderboardElem].appendChild(this.playerScoreElems[leaderboardElem]),
  9377. this.playerElems[leaderboardElem].appendChild(this.playerWaveElems[leaderboardElem]),
  9378.  
  9379. this.playersElem.appendChild(this.playerElems[leaderboardElem])
  9380. );
  9381.  
  9382. game.world.myUid === playerData.uid
  9383. ? this.playerElems[leaderboardElem].classList.add('is-active')
  9384. : this.playerElems[leaderboardElem].classList.remove(`is-active`);
  9385.  
  9386. this.playerElems[leaderboardElem].style.display = `block`;
  9387. // this.playerUidElems[leaderboardElem].innerText = playerData.uid;
  9388. this.playerRankElems[leaderboardElem].innerText = '#' + (playerData.rank + 1);
  9389. this.playerNameElems[leaderboardElem].innerText = playerName;
  9390. this.playerScoreElems[leaderboardElem].innerText = playerData.score.toLocaleString();
  9391. this.playerWaveElems[leaderboardElem].innerHTML = (0 === playerData.wave) ? `<small>-</small>` : playerData.wave.toLocaleString();
  9392.  
  9393. }
  9394. if (this.leaderboardData.length < this.playerElems.length) {
  9395. for (let invalidEntries = this.leaderboardData.length; invalidEntries < this.playerElems.length; invalidEntries++) {
  9396. this.playerElems[invalidEntries].style.display = `none`;
  9397. }
  9398. }
  9399. }
  9400.  
  9401. game.ui.components.BuildingOverlay.createResourceCostString = function (schema, schemaTier, amountOfBuildings) {
  9402. void 0 === schemaTier && (schemaTier = 0x1);
  9403. void 0 === amountOfBuildings && (amountOfBuildings = 0x1);
  9404. var totalCost = [],
  9405. resources = {
  9406. 'wood': `wood`,
  9407. 'stone': `stone`,
  9408. 'gold': 'gold',
  9409. 'token': 'tokens'
  9410. },
  9411. playerTick = Game.currentGame.ui.getPlayerTick();
  9412. for (var resource in resources) {
  9413. var resourceCost = resource + `Costs`;
  9414. if (schema[resourceCost] && schema[resourceCost][schemaTier - 1]) {
  9415. var currentTotalCost = schema[resourceCost][schemaTier - 1] * amountOfBuildings,
  9416. canAfford = playerTick && playerTick[resource] >= currentTotalCost;
  9417. canAfford
  9418. ? totalCost.push('<span\x20class=\x22hud-resource-' + resources[resource] + '\x22>' + currentTotalCost.toLocaleString() + '\x20' + resources[resource] + `</span>`)
  9419. : totalCost.push(`<span class="hud-resource-` + resources[resource] + ` hud-resource-low">` + currentTotalCost.toLocaleString() + '\x20' + resources[resource] + `</span>`);
  9420. }
  9421. }
  9422. return totalCost.length > 0 ? totalCost.join(',\x20') : `<span class="hud-resource-free">Free</span>`;
  9423. }
  9424.  
  9425. game.ui.components.BuildingOverlay.createResourceRefundString = function (buildingType, buildingSchema, tier) {
  9426. void 0 === tier && (tier = 1);
  9427. var totalCost = [],
  9428. buildingsByTier = {},
  9429. buildings = Object.values(game.ui.buildings).filter(e => e.type == buildingType),
  9430. resources = {
  9431. 'wood': `wood`,
  9432. 'stone': `stone`,
  9433. 'gold': `gold`,
  9434. 'token': 'tokens'
  9435. };
  9436. for (let building of buildings) {
  9437. buildingsByTier[building.tier] ||= 0;
  9438. buildingsByTier[building.tier]++;
  9439. }
  9440. for (var resource in resources) {
  9441. var resourceCost = resource + `Costs`;
  9442. if (buildingSchema[resourceCost]) {
  9443. var totalTierCost = 0;
  9444. if (this.shouldUpgradeAll) {
  9445. for (let i = 1; i <= tier; i++) {
  9446. totalTierCost = Math.floor(
  9447. buildingSchema[resourceCost].slice(0, i)
  9448. .reduce((prev, curr) => prev + curr, 0) / 2
  9449. ) * buildingsByTier[i];
  9450. }
  9451. } else totalTierCost = Math.floor(buildingSchema[resourceCost].slice(0, tier).reduce((prev, curr) => prev + curr, 0) / 2);
  9452. totalTierCost && totalCost.push('<span\x20class=\x22hud-resource-' + resources[resource] + '\x22>' + totalTierCost.toLocaleString() + '\x20' + resources[resource] + `</span>`);
  9453. }
  9454. }
  9455. return totalCost.length > 0 ? totalCost.join(',\x20') : `<span class="hud-resource-free">None</span>`;
  9456. }
  9457.  
  9458.  
  9459. game.ui.components.BuildingOverlay.excludeBuilding = function() {
  9460. game.script.AHRC.excludedHarvesters.has(this.buildingUid) ? (
  9461. this.excludeElem.classList.add("btn-theme"),
  9462. this.excludeElem.classList.remove("btn-red"),
  9463. this.excludeElem.innerHTML = `Exclude Harvester<i class="fa fa-minus" style="position: absolute;right: 10px;top: 13px;"></i>`,
  9464. game.script.AHRC.excludedHarvesters.delete(this.buildingUid)
  9465. ) : (
  9466. this.excludeElem.classList.add("btn-red"),
  9467. this.excludeElem.classList.remove("btn-theme"),
  9468. this.excludeElem.innerHTML = `Include Harvester<i class="fa fa-plus" style="position: absolute;right: 10px;top: 13px;"></i>`,
  9469. game.script.AHRC.excludedHarvesters.add(this.buildingUid)
  9470. );
  9471. }
  9472.  
  9473. game.ui.components.BuildingOverlay.viewFromBuilding = function() {
  9474. const buildings = game.ui.getBuildings(),
  9475. building = game.world.entities[this.buildingUid];
  9476. if (!building) return;
  9477.  
  9478. this.isViewingFromBuilding = true;
  9479. this.componentElem.style.opacity = "0.1";
  9480. game.renderer.follow(building);
  9481. };
  9482.  
  9483. game.ui.components.BuildingOverlay.stopWatching = function () {
  9484. this.buildingUid && (
  9485. this.isViewingFromBuilding && game.renderer.follow(game.world.entities[game.world.myUid]),
  9486. this.rangeIndicator && (
  9487. Game.currentGame.renderer.ground.removeAttachment(this.rangeIndicator),
  9488. delete this.rangeIndicator
  9489. ),
  9490. this.componentElem.innerHTML = '',
  9491. this.componentElem.style.opacity = "1",
  9492. this.componentElem.style.left = `-1000px`,
  9493. this.componentElem.style.top = '-1000px',
  9494. this.buildingUid = null,
  9495. this.buildingId = null,
  9496. this.buildingTier = null,
  9497. this.hide()
  9498. );
  9499. }
  9500.  
  9501. game.ui.components.BuildingOverlay.startWatching = function(buildingId) {
  9502. this.buildingUid && this.stopWatching();
  9503. let buildings = this.ui.getBuildings(),
  9504. building = buildings[buildingId];
  9505. if (!building) return;
  9506. this.buildingUid = buildingId;
  9507. this.buildingId = building.type;
  9508. this.buildingTier = building.tier;
  9509. const schema = this.ui.getBuildingSchema(),
  9510. buildingSchema = schema[this.buildingId];
  9511. if ('GoldStash' == this.buildingId) {
  9512. var world = Game.currentGame.world,
  9513. cellSize = world.entityGrid.getCellSize();
  9514. this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', {
  9515. 'width': this.maxStashDistance * cellSize * 2,
  9516. 'height': this.maxStashDistance * cellSize * 2
  9517. });
  9518. Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator);
  9519. } else if (buildingSchema.rangeTiers) {
  9520. this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', {
  9521. 'isCircular': true,
  9522. 'radius': buildingSchema.rangeTiers[this.buildingTier - 1] * 0.57071
  9523. });
  9524. Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator)
  9525. };
  9526. this.componentElem.innerHTML = `<div class="hud-tooltip-building">
  9527. <h2>` + buildingSchema.name + `</h2>
  9528. <h3>Tier <span class="hud-building-tier">` + this.buildingTier + `</span> Building</h3>
  9529. <div class="hud-tooltip-health">
  9530. <span class="hud-tooltip-health-bar" style="width:100%;"></span>
  9531. </div>
  9532. <div class="hud-tooltip-body">
  9533. <div class="hud-building-stats"></div>
  9534. <p class="hud-building-actions">
  9535. <span class="hud-building-dual-btn">
  9536. <a class="btn btn-purple hud-building-deposit">Refuel</a>
  9537. <a class="btn btn-gold hud-building-collect">Collect</a>
  9538. </span>
  9539. <a class="btn btn-theme hud-building-ahrc">Exclude Harvester<i class="fa fa-minus" style="position: absolute;right: 10px;top: 13px;"></i></a>
  9540. <a class="btn btn-theme hud-building-view" style="display: none;">View From Building<i class="fas fa-eye" style="position: absolute;right: 10px;top: 13px;"></i></a>
  9541. <a class="btn btn-green hud-building-upgrade">Upgrade</a>
  9542. <a class="btn btn-red hud-building-sell">Sell</a>
  9543. </p>
  9544. </div>
  9545. </div>`;
  9546. this.tierElem = this.componentElem.querySelector(`.hud-building-tier`);
  9547. this.healthBarElem = this.componentElem.querySelector(`.hud-tooltip-health-bar`);
  9548. this.statsElem = this.componentElem.querySelector(`.hud-building-stats`);
  9549. this.actionsElem = this.componentElem.querySelector(`.hud-building-actions`);
  9550. this.depositElem = this.componentElem.querySelector(`.hud-building-deposit`);
  9551. this.dualBtnElem = this.componentElem.querySelector(`.hud-building-dual-btn`);
  9552. this.excludeElem = this.componentElem.querySelector(`.hud-building-ahrc`);
  9553. this.collectElem = this.componentElem.querySelector(`.hud-building-collect`);
  9554. this.viewElem = this.componentElem.querySelector('.hud-building-view');
  9555. this.upgradeElem = this.componentElem.querySelector('.hud-building-upgrade');
  9556. this.sellElem = this.componentElem.querySelector('.hud-building-sell');
  9557. `Harvester` !== this.buildingId && (
  9558. this.dualBtnElem.style.display = `none`,
  9559. this.excludeElem.style.display = `none`,
  9560. this.viewElem.style.display = `block`
  9561. );
  9562. game.script.AHRC.excludedHarvesters.has(this.buildingUid) ? (
  9563. this.excludeElem.classList.add("btn-red"),
  9564. this.excludeElem.classList.remove("btn-theme"),
  9565. this.excludeElem.innerHTML = `Include Harvester<i class="fa fa-plus" style="position: absolute;right: 10px;top: 13px;"></i>`
  9566. ) : (
  9567. this.excludeElem.classList.add("btn-theme"),
  9568. this.excludeElem.classList.remove("btn-red"),
  9569. this.excludeElem.innerHTML = `Exclude Harvester<i class="fa fa-minus" style="position: absolute;right: 10px;top: 13px;"></i>`
  9570. );
  9571. this.depositElem.addEventListener(`click`, this.depositIntoBuilding.bind(this));
  9572. this.collectElem.addEventListener(`click`, this.collectFromBuilding.bind(this));
  9573. this.excludeElem.addEventListener(`click`, this.excludeBuilding.bind(this));
  9574. this.viewElem.addEventListener(`click`, this.viewFromBuilding.bind(this));
  9575. this.upgradeElem.addEventListener(`click`, this.upgradeBuilding.bind(this));
  9576. this.sellElem.addEventListener(`click`, this.sellBuilding.bind(this));
  9577. this.show();
  9578. this.update();
  9579. }
  9580. game.ui.components.BuildingOverlay.update = function () {
  9581. if (this.buildingUid) {
  9582. const buildingEntity = Game.currentGame.world.getEntityByUid(this.buildingUid);
  9583. if (!buildingEntity) return void this.stopWatching();
  9584.  
  9585. let renderer = Game.currentGame.renderer,
  9586. buildingUiPosition = renderer.worldToScreen(buildingEntity.getPositionX(), buildingEntity.getPositionY()),
  9587. buildingTick = buildingEntity.getTargetTick(),
  9588. buildingsSchema = this.ui.getBuildingSchema(),
  9589. buildings = this.ui.getBuildings(),
  9590. buildingSchema = buildingsSchema[this.buildingId],
  9591. building = buildings[this.buildingUid];
  9592. if (!building) return void this.stopWatching();
  9593.  
  9594. let buildingHeight = buildingSchema.gridHeight,
  9595. buildingScale = (buildingSchema.gridWidth, buildingHeight / 2 * 48 * (renderer.getScale() / window.devicePixelRatio)),
  9596. buildingTier = building.tier,
  9597. buildingSchemaTier = 1,
  9598. isBuildingMaxed = false,
  9599. isBuildingAtMaxTier = false,
  9600. currentStats = {},
  9601. nextTierStats = {},
  9602. sameBuildings = 1,
  9603. buildingStats = {
  9604. 'health': `Health`,
  9605. 'damage': `Damage`,
  9606. 'range': 'Range',
  9607. 'gps': 'Gold/Sec',
  9608. 'harvest': `Harvest/Sec`,
  9609. 'harvestCapacity': `Capacity`,
  9610. 'msBetweenFires': `Firerate`
  9611. };
  9612.  
  9613. if (buildingSchema.tiers) {
  9614. const stashTier = this.getGoldStashTier();
  9615. building.tier < buildingSchema.tiers ? (buildingSchemaTier = building.tier + 1, isBuildingMaxed = false) : (buildingSchemaTier = building.tier, isBuildingMaxed = true);
  9616. isBuildingAtMaxTier = !isBuildingMaxed && (building.tier < stashTier || `GoldStash` === this.buildingId);
  9617. }
  9618. for (let buildingStat in buildingStats) {
  9619. let currentStat = `<small>&mdash;</small>`,
  9620. nextTierStat = '<small>&mdash;</small>';
  9621. buildingSchema[buildingStat + `Tiers`] && (
  9622. currentStat = buildingSchema[buildingStat + `Tiers`][buildingTier - 1],
  9623. buildingStat == "msBetweenFires" && (currentStat = (1000 / currentStat).toFixed(2).toLocaleString()),
  9624. isBuildingMaxed || (
  9625. nextTierStat = buildingSchema[buildingStat + 'Tiers'][buildingSchemaTier - 1],
  9626. buildingStat == "msBetweenFires" && (nextTierStat = (1000 / nextTierStat).toFixed(2).toLocaleString())
  9627. ),
  9628. currentStats[buildingStat] = '<p>' + buildingStats[buildingStat] + `: <strong class="hud-stats-current">` + currentStat + '</strong></p>',
  9629. nextTierStats[buildingStat] = `<p>` + buildingStats[buildingStat] + ':\x20<strong\x20class=\x22hud-stats-next\x22>' + nextTierStat + `</strong></p>`
  9630. );
  9631. }
  9632. if (this.shouldUpgradeAll) {
  9633. sameBuildings = 0;
  9634. for (let buildingUid in buildings) {
  9635. // parseInt(buildingUid); tf
  9636. buildings[buildingUid].type === this.buildingId && buildings[buildingUid].tier === building.tier && sameBuildings++;
  9637. }
  9638. }
  9639. let costString = this.createResourceCostString(buildingSchema, buildingSchemaTier, sameBuildings),
  9640. refundString = this.createResourceRefundString(this.buildingId, buildingSchema, building.tier),
  9641. buildingHealth = Math.round(buildingTick.health / buildingTick.maxHealth * 100);
  9642.  
  9643. buildingTick.partyId !== this.ui.getPlayerPartyId() ? this.actionsElem.style.display = `none` : this.actionsElem.style.display = 'block';
  9644. this.tierElem.innerHTML = building.tier.toString();
  9645. this.buildingTier = building.tier;
  9646. this.healthBarElem.style.width = buildingHealth + '%';
  9647. if (Object.keys(currentStats).length > 0) {
  9648. let currentStatValues = '',
  9649. nextTierStatValues = '';
  9650. for (let stat in currentStats) currentStatValues += currentStats[stat];
  9651. for (let stat in nextTierStats) nextTierStatValues += nextTierStats[stat];
  9652. this.statsElem.innerHTML = `
  9653. <div class="hud-stats-current hud-stats-values">
  9654. ` + currentStatValues + `
  9655. </div>
  9656. <div class="hud-stats-next hud-stats-values">
  9657. ` + nextTierStatValues + `
  9658. </div>
  9659. `;
  9660. } else this.statsElem.innerHTML = '';
  9661. if (`Harvester` === this.buildingId) {
  9662. let depositAmount = Math.floor(buildingTick.depositMax / 10),
  9663. isDepositPossible = buildingTick.depositMax - buildingTick.deposit < depositAmount;
  9664. isDepositPossible ? this.depositElem.classList.add('is-disabled') : this.depositElem.classList.remove(`is-disabled`);
  9665. this.shouldUpgradeAll
  9666. ? this.depositElem.innerHTML = 'Refuel\x20All\x20<small>(' + (depositAmount * sameBuildings).toLocaleString() + ` gold)</small>`
  9667. : this.depositElem.innerHTML = 'Refuel\x20<small>(' + depositAmount.toLocaleString() + ` gold)</small>`;
  9668. }
  9669. isBuildingAtMaxTier ? this.upgradeElem.classList.remove(`is-disabled`) : this.upgradeElem.classList.add('is-disabled');
  9670. this.shouldUpgradeAll ? (
  9671. this.upgradeElem.innerHTML = `Upgrade All <small>(` + costString + ')</small>',
  9672. this.sellElem.innerHTML = `Sell All <small>(` + refundString + ')</small>'
  9673. ) : (
  9674. this.upgradeElem.innerHTML = `Upgrade <small>(` + costString + `)</small>`,
  9675. this.sellElem.innerHTML = `Sell <small>(` + refundString + `)</small>`
  9676. );
  9677. `GoldStash` == this.buildingId ? (
  9678. this.sellElem.innerHTML = `Sell All Buildings`,
  9679. this.sellElem.classList.remove(`is-disabled`),
  9680. this.isSellingAll && this.sellElem.classList.add(`is-disabled`)
  9681. ) : this.ui.getPlayerPartyCanSell() ? (
  9682. this.sellElem.classList.remove(`is-disabled`)
  9683. ) : (
  9684. this.sellElem.classList.add(`is-disabled`),
  9685. this.sellElem.innerHTML = `Need Permission to Sell`
  9686. );
  9687. this.componentElem.style.left = buildingUiPosition.x - this.componentElem.offsetWidth / 0x2 + 'px';
  9688. this.componentElem.style.top = buildingUiPosition.y - buildingScale - this.componentElem.offsetHeight - 0x14 + 'px';
  9689. this.rangeIndicator && this.rangeIndicator.setPosition(buildingEntity.getPositionX(), buildingEntity.getPositionY());
  9690. }
  9691. }
  9692.  
  9693. game.ui.onBuildingSchemaUpdate = function (rawSchema) {
  9694. const schemas = JSON.parse(rawSchema.json);
  9695. for (const buildingId in schemas) {
  9696. let buildingSchema = schemas[buildingId];
  9697. for (var schema in this.buildingSchema) {
  9698. if (schema == buildingSchema.Name) {
  9699. buildingSchema.MsBetweenFires && (this.buildingSchema[schema].msBetweenFiresTiers = buildingSchema.MsBetweenFires);
  9700. buildingSchema.ProjectileAoe && (this.buildingSchema[schema].aoeTiers = buildingSchema.ProjectileAoe);
  9701. buildingSchema.ProjectileAoeRadius && (this.buildingSchema[schema].aoeRadiusTiers = buildingSchema.ProjectileAoeRadius);
  9702. buildingSchema.ProjectileLifetime && (this.buildingSchema[schema].lifetimeTiers = buildingSchema.ProjectileLifetime);
  9703. break;
  9704. }
  9705. }
  9706. }
  9707. this.emit(`buildingSchemaUpdate`, this.buildingSchema);
  9708. }
  9709. game.ui.onItemSchemaUpdate = function (rawSchema) {
  9710. var schemas = JSON.parse(rawSchema.json);
  9711. for (var item in schemas) {
  9712. var itemSchema = schemas[item];
  9713. for (var schema in this.itemSchema) {
  9714. schema == "Bow" && (this.itemSchema[schema].rangeTiers = Array(7).fill(1000));
  9715. if (schema == itemSchema.Name) {
  9716. itemSchema.MaxYawDeviation && (this.itemSchema[schema].maxYawDeviationTiers = itemSchema.MaxYawDeviation);
  9717. itemSchema.MsBetweenFires && (this.itemSchema[schema].msBetweenFiresTiers = itemSchema.MsBetweenFires);
  9718. itemSchema.ProjectileAoe && (this.itemSchema[schema].aoeTiers = itemSchema.ProjectileAoe);
  9719. itemSchema.ProjectileAoeRadius && (this.itemSchema[schema].aoeRadiusTiers = itemSchema.ProjectileAoeRadius);
  9720. itemSchema.ProjectileLifetime && (this.itemSchema[schema].lifetimeTiers = itemSchema.ProjectileLifetime);
  9721. break;
  9722. }
  9723. }
  9724. }
  9725. this.emit(`itemSchemaUpdate`, this.itemSchema);
  9726. }
  9727.  
  9728. game.network.addRpcHandler("BuildingShopPrices", game.ui.onBuildingSchemaUpdate.bind(game.ui));
  9729. game.network.addRpcHandler("ItemShopPrices", game.ui.onItemSchemaUpdate.bind(game.ui));
  9730.  
  9731. /* @CustomRenderer */
  9732. game.renderer.nodeType = class i {
  9733. constructor(e = null) {
  9734. this.attachments = [];
  9735. this.parent = null;
  9736. this.isVisible = true;
  9737. this.setNode(e || new window.PIXI.Container);
  9738. }
  9739. getNode() {
  9740. return this.node;
  9741. }
  9742. setNode(t) {
  9743. this.node = t;
  9744. }
  9745. getParent() {
  9746. return this.parent;
  9747. }
  9748. setParent(t) {
  9749. this.parent = t;
  9750. }
  9751. getAttachments() {
  9752. return this.attachments;
  9753. }
  9754. addAttachment(t, e = 0) {
  9755. t.getNode().zHack = e;
  9756. t.setParent(this);
  9757. this.node.addChild(t.getNode());
  9758. this.attachments.push(t);
  9759. this.node.children.sort(function (t, e) {
  9760. return t.zHack == e.zHack ? 0 : t.zHack < e.zHack ? -1 : 1;
  9761. });
  9762. }
  9763. removeAttachment(t) {
  9764. if (t) {
  9765. this.node.removeChild(t.getNode());
  9766. t.setParent(null);
  9767.  
  9768. var e = this.attachments.indexOf(t);
  9769. e > -1 && this.attachments.splice(e, 1);
  9770. }
  9771. }
  9772. getRotation() {
  9773. return 180 * this.node.rotation / Math.PI;
  9774. }
  9775. setRotation(t) {
  9776. this.node.rotation = t * Math.PI / 180;
  9777. }
  9778. getAlpha() {
  9779. return this.node.alpha;
  9780. }
  9781. setAlpha(t) {
  9782. this.node.alpha = t;
  9783. }
  9784. getScale() {
  9785. return this.node.scale;
  9786. }
  9787. setScale(t) {
  9788. this.node.scale.x = t;
  9789. this.node.scale.y = t;
  9790. }
  9791. getScaleX() {
  9792. return this.node.scale.x;
  9793. }
  9794. setScaleX(t) {
  9795. this.node.scale.x = t;
  9796. }
  9797. getScaleY() {
  9798. return this.node.scale.y;
  9799. }
  9800. setScaleY(t) {
  9801. this.node.scale.y = t;
  9802. }
  9803. getFilters() {
  9804. return this.node.filters;
  9805. }
  9806. setFilters(t) {
  9807. this.node.filters = t;
  9808. }
  9809. getPosition() {
  9810. return this.node.position;
  9811. }
  9812. setPosition(t, e) {
  9813. this.node.position.x = t;
  9814. this.node.position.y = e;
  9815. }
  9816. getPositionX() {
  9817. return this.getPosition().x;
  9818. }
  9819. setPositionX(t) {
  9820. this.node.position.x = t;
  9821. }
  9822. getPositionY() {
  9823. return this.getPosition().y;
  9824. }
  9825. setPositionY(t) {
  9826. this.node.position.y = t;
  9827. }
  9828. getPivotPoint() {
  9829. return this.node.pivot;
  9830. }
  9831. setPivotPoint(t, e) {
  9832. this.node.pivot.x = t;
  9833. this.node.pivot.y = e;
  9834. }
  9835. getVisible() {
  9836. return this.isVisible;
  9837. }
  9838. setVisible(t) {
  9839. this.isVisible = t;
  9840. this.node.visible = t;
  9841. }
  9842. update(t, e) {
  9843. for (let r = 0; r < this.attachments.length; r++) this.attachments[r].update(t, e);
  9844. }
  9845. };
  9846. game.renderer.spriteType = class d extends game.renderer.nodeType {
  9847. constructor(texture, tiled) {
  9848. super();
  9849. this.sprite = null;
  9850. if (typeof texture === 'string') {
  9851. texture = window.PIXI.Texture.fromImage(texture);
  9852. }
  9853. if (tiled) {
  9854. this.sprite = new window.PIXI.extras.TilingSprite(texture);
  9855. this.sprite.texture.baseTexture.scaleMode = window.PIXI.SCALE_MODES.NEAREST;
  9856. } else {
  9857. this.sprite = new window.PIXI.Sprite(texture);
  9858. }
  9859. this.sprite.anchor.x = 0.5;
  9860. this.sprite.anchor.y = 0.5;
  9861. this.setNode(this.sprite);
  9862. }
  9863. getAnchor() {
  9864. return this.sprite.anchor;
  9865. };
  9866. setAnchor(x, y) {
  9867. this.sprite.anchor.x = x;
  9868. this.sprite.anchor.y = y;
  9869. };
  9870. getTint() {
  9871. return this.node.tint;
  9872. };
  9873. setTint(tint) {
  9874. this.node.tint = tint;
  9875. };
  9876. getBlendMode() {
  9877. return this.node.tint;
  9878. };
  9879. setBlendMode(blendMode) {
  9880. this.node.blendMode = blendMode;
  9881. };
  9882. getMask() {
  9883. return this.node.mask;
  9884. };
  9885. setMask(entity) {
  9886. this.node.mask = entity.getNode();
  9887. };
  9888. setDimensions(x, y, width, height) {
  9889. this.sprite.x = x;
  9890. this.sprite.y = y;
  9891. this.sprite.width = width;
  9892. this.sprite.height = height;
  9893. };
  9894. };
  9895. game.renderer.graphicsType = class u extends game.renderer.nodeType {
  9896. constructor() {
  9897. super();
  9898. this.draw = new window.PIXI.Graphics();
  9899. this.draw.clear();
  9900. this.setNode(this.draw);
  9901. }
  9902. drawLine(thickness, xStart, yStart, xEnd, yEnd, color = 0xffffff, alpha = 1) {
  9903. this.draw.alpha = alpha;
  9904. this.draw.lineStyle(thickness, color)
  9905. .moveTo(xStart, yStart)
  9906. .lineTo(xEnd, yEnd);
  9907. }
  9908. drawTriangle(_a, _b, _c, _d, _e, _f) {
  9909. void 0x0 === _d && (_d = null);
  9910. void 0x0 === _e && (_e = null);
  9911. void 0x0 === _f && (_f = null);
  9912. _f && _f > 0x0 && this.draw.lineStyle(_f, _e.r << 0x10 | _e.g << 0x8 | _e.b, _e.a);
  9913. _d && this.draw.beginFill(_d.r << 0x10 | _d.g << 0x8 | _d.b, _d.a);
  9914. this.draw.drawPolygon([_a.x, _a.y, _b.x, _b.y, _c.x, _c.y]);
  9915. _d && this.draw.endFill();
  9916. }
  9917. drawArc(_a, _b, _c, _d, _e, _f, _g, _h, _i) {
  9918. void 0x0 === _g && (_g = null),
  9919. void 0x0 === _h && (_h = null),
  9920. void 0x0 === _i && (_i = null),
  9921. _i && _i > 0x0 && this.draw.lineStyle(_i, _h.r << 0x10 | _h.g << 0x8 | _h.b, _h.a),
  9922. _d = _d * Math.PI / 0xb4,
  9923. _e = _e * Math.PI / 0xb4,
  9924. _g && this.draw.beginFill(_g.r << 0x10 | _g.g << 0x8 | _g.b, _g.a),
  9925. this.draw.arc(_a, _b, _c, _d, _e, _f),
  9926. _g && this.draw.endFill();
  9927. };
  9928. drawCircle(_a, _b, _c, _d, _e, _f) {
  9929. void 0x0 === _d && (_d = null),
  9930. void 0x0 === _e && (_e = null),
  9931. void 0x0 === _f && (_f = null),
  9932. _f && _f > 0x0 && this.draw.lineStyle(_f, _e.r << 0x10 | _e.g << 0x8 | _e.b, _e.a),
  9933. _d && this.draw.beginFill(_d.r << 0x10 | _d.g << 0x8 | _d.b, _d.a),
  9934. this.draw.drawCircle(_a, _b, _c),
  9935. _d && this.draw.endFill();
  9936. };
  9937. drawRect(_a, _b, _c, _d, _e, _f, _g) {
  9938. void 0x0 === _e && (_e = null),
  9939. void 0x0 === _f && (_f = null),
  9940. void 0x0 === _g && (_g = null),
  9941. _g && _g > 0x0 && this.draw.lineStyle(_g, _f.r << 0x10 | _f.g << 0x8 | _f.b, _f.a),
  9942. _e && this.draw.beginFill(_e.r << 0x10 | _e.g << 0x8 | _e.b, _e.a),
  9943. this.draw.drawRect(_a, _b, _c - _a, _d - _b),
  9944. _e && this.draw.endFill();
  9945. };
  9946. drawRoundedRect(_a, _b, _c, _d, _e, _f, _g, _h) {
  9947. void 0x0 === _f && (_f = null),
  9948. void 0x0 === _g && (_g = null),
  9949. void 0x0 === _h && (_h = null),
  9950. _h && _h > 0x0 && this.draw.lineStyle(_h, _g.r << 0x10 | _g.g << 0x8 | _g.b, _g.a),
  9951. _f && this.draw.beginFill(_f.r << 0x10 | _f.g << 0x8 | _f.b, _f.a),
  9952. this.draw.drawRoundedRect(_a, _b, _c - _a, _d - _b, _e),
  9953. _f && this.draw.endFill();
  9954. };
  9955. drawEllipse(_a, _b, _c, _d, _e, _f, _g) {
  9956. void 0x0 === _e && (_e = null),
  9957. void 0x0 === _f && (_f = null),
  9958. void 0x0 === _g && (_g = null),
  9959. _g && _g > 0x0 && this.draw.lineStyle(_g, _f.r << 0x10 | _f.g << 0x8 | _f.b, _f.a),
  9960. _e && this.draw.beginFill(_e.r << 0x10 | _e.g << 0x8 | _e.b, _e.a),
  9961. this.draw.drawEllipse(_a, _b, _c, _d),
  9962. _e && this.draw.endFill();
  9963. };
  9964. getTexture() {
  9965. const renderer = Game.currentGame.renderer.getInternalRenderer();
  9966. return renderer.generateTexture(this.draw);
  9967. };
  9968. clear() {
  9969. this.draw.clear();
  9970. };
  9971. };
  9972. if (window.location.hostname !== "localhost") {
  9973. game.renderer.models = {GamePlayer:{model:"PlayerModel"},Stone:{model:"RecoilModel",gridSize:{width:3,height:3},args:{name:"/asset/image/map/map-stone.svg"}},Tree:{model:"RecoilModel",gridSize:{width:4,height:4},args:{name:"/asset/image/map/map-tree.svg"}},Wall:{model:"WallModel"},Door:{model:"DoorModel"},SlowTrap:{model:"SlowTrapModel"},ArrowTower:{model:"ArrowTowerModel",gridSize:{width:2,height:2}},CannonTower:{model:"CannonTowerModel",gridSize:{width:2,height:2}},MeleeTower:{model:"MeleeTowerModel",gridSize:{width:2,height:2}},BombTower:{model:"BombTowerModel",gridSize:{width:2,height:2}},MagicTower:{model:"MageTowerModel",gridSize:{width:2,height:2}},GoldMine:{model:"GoldMineModel",gridSize:{width:2,height:2}},Harvester:{model:"HarvesterModel",gridSize:{width:2,height:2}},GoldStash:{model:"GoldStashModel",gridSize:{width:2,height:2}},ArrowProjectile:{model:"ProjectileArrowModel"},CannonProjectile:{model:"ProjectileCannonModel"},BowProjectile:{model:"ProjectileArrowModel"},BombProjectile:{model:"ProjectileBombModel"},FireballProjectile:{model:"ProjectileMageModel"},HealTowersSpell:{model:"HealTowersSpellModel"},PetCARL:{model:"PetModel"},PetMiner:{model:"PetModel"},ZombieGreenTier1:{model:"ZombieModel"},ZombieGreenTier2:{model:"ZombieModel"},ZombieGreenTier3:{model:"ZombieModel"},ZombieGreenTier4:{model:"ZombieModel"},ZombieGreenTier5:{model:"ZombieModel"},ZombieGreenTier6:{model:"ZombieModel"},ZombieGreenTier7:{model:"ZombieModel"},ZombieGreenTier8:{model:"ZombieModel"},ZombieGreenTier9:{model:"ZombieModel"},ZombieGreenTier10:{model:"ZombieModel"},ZombieRangedGreenTier1:{model:"ZombieRangedModel"},ZombieBlueTier1:{model:"ZombieModel"},ZombieBlueTier2:{model:"ZombieModel"},ZombieBlueTier3:{model:"ZombieModel"},ZombieBlueTier4:{model:"ZombieModel"},ZombieBlueTier5:{model:"ZombieModel"},ZombieBlueTier6:{model:"ZombieModel"},ZombieBlueTier7:{model:"ZombieModel"},ZombieBlueTier8:{model:"ZombieModel"},ZombieBlueTier9:{model:"ZombieModel"},ZombieBlueTier10:{model:"ZombieModel"},ZombieRedTier1:{model:"ZombieModel"},ZombieRedTier2:{model:"ZombieModel"},ZombieRedTier3:{model:"ZombieModel"},ZombieRedTier4:{model:"ZombieModel"},ZombieRedTier5:{model:"ZombieModel"},ZombieRedTier6:{model:"ZombieModel"},ZombieRedTier7:{model:"ZombieModel"},ZombieRedTier8:{model:"ZombieModel"},ZombieRedTier9:{model:"ZombieModel"},ZombieRedTier10:{model:"ZombieModel"},ZombieYellowTier1:{model:"ZombieModel"},ZombieYellowTier2:{model:"ZombieModel"},ZombieYellowTier3:{model:"ZombieModel"},ZombieYellowTier4:{model:"ZombieModel"},ZombieYellowTier5:{model:"ZombieModel"},ZombieYellowTier6:{model:"ZombieModel"},ZombieYellowTier7:{model:"ZombieModel"},ZombieYellowTier8:{model:"ZombieModel"},ZombieYellowTier9:{model:"ZombieModel"},ZombieYellowTier10:{model:"ZombieModel"},ZombiePurpleTier1:{model:"ZombieModel"},ZombiePurpleTier2:{model:"ZombieModel"},ZombiePurpleTier3:{model:"ZombieModel"},ZombiePurpleTier4:{model:"ZombieModel"},ZombiePurpleTier5:{model:"ZombieModel"},ZombiePurpleTier6:{model:"ZombieModel"},ZombiePurpleTier7:{model:"ZombieModel"},ZombiePurpleTier8:{model:"ZombieModel"},ZombiePurpleTier9:{model:"ZombieModel"},ZombiePurpleTier10:{model:"ZombieModel"},ZombieOrangeTier1:{model:"ZombieModel"},ZombieOrangeTier2:{model:"ZombieModel"},ZombieOrangeTier3:{model:"ZombieModel"},ZombieOrangeTier4:{model:"ZombieModel"},ZombieOrangeTier5:{model:"ZombieModel"},ZombieOrangeTier6:{model:"ZombieModel"},ZombieOrangeTier7:{model:"ZombieModel"},ZombieOrangeTier8:{model:"ZombieModel"},ZombieOrangeTier9:{model:"ZombieModel"},ZombieOrangeTier10:{model:"ZombieModel"},ZombieBossTier1:{model:"ZombieBossModel"},ZombieBossTier2:{model:"ZombieBossModel"},ZombieBossTier3:{model:"ZombieBossModel"},ZombieBossTier4:{model:"ZombieBossModel"},ZombieBossTier5:{model:"ZombieBossModel"},ZombieBossTier6:{model:"ZombieBossModel"},ZombieBossTier7:{model:"ZombieBossModel"},ZombieBossTier8:{model:"ZombieBossModel"},ZombieBossTier9:{model:"ZombieBossModel"},ZombieBossTier10:{model:"ZombieBossModel"},ZombieBossTier11:{model:"ZombieBossModel"},ZombieBossTier12:{model:"ZombieBossModel"},ZombieBossTier13:{model:"ZombieBossModel"},ZombieBossTier14:{model:"ZombieBossModel"},ZombieBossTier15:{model:"ZombieBossModel"},ZombieBossTier16:{model:"ZombieBossModel"},ZombieBossTier17:{model:"ZombieBossModel"},ZombieBossTier18:{model:"ZombieBossModel"},ZombieBossTier19:{model:"ZombieBossModel"},ZombieBossTier20:{model:"ZombieBossModel"},ZombieBossTier21:{model:"ZombieBossModel"},ZombieBossTier22:{model:"ZombieBossModel"},ZombieBossTier23:{model:"ZombieBossModel"},ZombieBossTier24:{model:"ZombieBossModel"},ZombieBossTier25:{model:"ZombieBossModel"},ZombieBossTier26:{model:"ZombieBossModel"},ZombieBossTier27:{model:"ZombieBossModel"},ZombieBossTier28:{model:"ZombieBossModel"},ZombieBossTier29:{model:"ZombieBossModel"},ZombieBossTier30:{model:"ZombieBossModel"},ZombieBossTier31:{model:"ZombieBossModel"},ZombieBossTier32:{model:"ZombieBossModel"},ZombieBossTier33:{model:"ZombieBossModel"},ZombieBossTier34:{model:"ZombieBossModel"},ZombieBossTier35:{model:"ZombieBossModel"},ZombieBossTier36:{model:"ZombieBossModel"},ZombieBossTier37:{model:"ZombieBossModel"},ZombieBossTier38:{model:"ZombieBossModel"},ZombieBossTier39:{model:"ZombieBossModel"},ZombieBossTier40:{model:"ZombieBossModel"},NeutralCamp:{model:"NeutralCampModel"},NeutralTier1:{model:"NeutralModel"},PathNode:{model:"PathNodeModel"}};
  9974. game.lerp = function(t, e, r) {
  9975. return (r > 1.2 && (r = 1), t + (e - t) * r);
  9976. }
  9977. game.mod = function (_a, _b) {
  9978. return (_a % _b + _b) % _b;
  9979. }
  9980. game.interpolateYaw = function (__a, __b) {
  9981. var _game = Game.currentGame.world.getReplicator().getMsInThisTick() / Game.currentGame.world.getMsPerTick(),
  9982. delta = __a - __b;
  9983. delta = game.mod(delta + 0xb4, 0x168) - 0xb4;
  9984. delta = game.lerp(0x0, delta, _game);
  9985. var addDelta = __b + delta;
  9986. addDelta < 0x0 && (addDelta += 0x168);
  9987. addDelta >= 0x168 && (addDelta -= 0x168);
  9988. return addDelta;
  9989. }
  9990. game.renderer.entityType = class o extends game.renderer.nodeType {
  9991. constructor(t) {
  9992. super();
  9993. this.uid = t.uid;
  9994. this.setVisible(true);
  9995. this.setTargetTick(t);
  9996. }
  9997. calculateVector(t, e, r) {
  9998. return (r > 1.2 && (r = 1), t + (e - t) * r);
  9999. }
  10000. reset() {
  10001. this.uid = 0;
  10002. this.currentModel = null;
  10003. this.entityClass = null;
  10004. this.fromTick = null;
  10005. this.targetTick = null;
  10006. this.setVisible(true);
  10007. }
  10008. isLocal() {
  10009. var t = Game.currentGame.world.getLocalPlayer();
  10010. return !(!t || !t.getEntity()) && this.uid == t.getEntity().uid;
  10011. }
  10012. getTargetTick() {
  10013. return this.targetTick;
  10014. }
  10015. getFromTick() {
  10016. return this.fromTick;
  10017. }
  10018. setTargetTick(t) {
  10019. this.targetTick || (this.entityClass = t.entityClass, this.targetTick = t);
  10020. this.addMissingTickFields(t, this.targetTick);
  10021. this.fromTick = this.targetTick;
  10022. this.targetTick = t;
  10023. void 0 !== t.scale && this.setScale(t.scale);
  10024. this.fromTick.model !== this.targetTick.model && this.refreshModel(this.targetTick.model);
  10025. this.entityClass = this.targetTick.entityClass;
  10026. }
  10027. overrideFromTick(t) {
  10028. this.fromTick = t;
  10029. }
  10030. overrideTargetTick(t) {
  10031. this.targetTick = t;
  10032. }
  10033. tick(t, e) {
  10034. if (this.fromTick) {
  10035. var r = t / e;
  10036. this.isVisible || this.setVisible(true);
  10037. this.setPositionX(this.calculateVector(this.fromTick.position.x, this.targetTick.position.x, r));
  10038. this.setPositionY(this.calculateVector(this.fromTick.position.y, this.targetTick.position.y, r));
  10039. this.setRotation(((t, e) => {
  10040. let r = t - e;
  10041. r = ((r + 180) % 360 + 360) % 360 - 180;
  10042. r = this.calculateVector(0, r, Game.currentGame.world.getReplicator().getMsInThisTick() / Game.currentGame.world.getMsPerTick());
  10043.  
  10044. let i = e + r;
  10045. i < 0 && (i += 360);
  10046. i >= 360 && (i -= 360);
  10047.  
  10048. return i;
  10049. })(this.targetTick.yaw, this.fromTick.yaw));
  10050. }
  10051. }
  10052. update(t, e) {
  10053. this.fromTick && (this.fromTick.interpolatedYaw = this.getRotation());
  10054. if (this.currentModel && game.script.optimize.updateAnimation) this.currentModel.update(t, this.fromTick);
  10055. this.node.visible = this.isVisible;
  10056. }
  10057. refreshModel(t) {
  10058. const e = game.renderer.models;
  10059. if (!(t in e)) throw new Error("Attempted to create unknown model: " + t);
  10060. var r = e[t].model;
  10061.  
  10062. Game.currentGame.getModelEntityPooling(r) && (this.currentModel = Game.currentGame.world.getModelFromPool(r));
  10063. if (!this.currentModel) {
  10064. var i = {};
  10065. "args" in e[t] && (i = e[t].args);
  10066. i.modelName = t;
  10067.  
  10068. this.currentModel = Game.currentGame.assetManager.loadModel(r, i);
  10069. this.currentModel.modelName = r;
  10070. }
  10071. if (this.currentModel.modelName == 'PlayerModel') {
  10072. this.currentModel.updateSwingingWeapon = function (useThisIfUrGay, radius) {
  10073. var currentModel = this;
  10074. void 0 === radius && (radius = 100);
  10075. return function (tick, currentTick) {
  10076. var interpolatedYaw = game.interpolateYaw(currentTick.getTargetTick().aimingYaw, currentTick.getFromTick().aimingYaw);
  10077. currentModel.weapon.setRotation(interpolatedYaw - tick.interpolatedYaw);
  10078. if (tick.firingTick && (tick.firingTick !== currentModel.lastFiringTick || !currentModel.lastFiringAnimationDone)) {
  10079. currentModel.lastFiringTick = tick.firingTick;
  10080. currentModel.lastFiringAnimationDone = false;
  10081. var msSinceTick = Game.currentGame.world.replicator.getMsSinceTick(tick.firingTick),
  10082. itemSchema = game.ui.itemSchema,
  10083. _a = Math.min(msSinceTick / itemSchema[currentModel.lastWeaponName].msBetweenFiresTiers[currentModel.lastWeaponTier - 1], 1),
  10084. _b = Math.sin(_a * Math.PI) * radius // itemSchema[currentModel.lastWeaponName].maxYawDeviationTiers[currentModel.lastWeaponTier - 1];
  10085. 1 === _a && (currentModel.lastFiringAnimationDone = true);
  10086. currentModel.weapon.setRotation(interpolatedYaw - tick.interpolatedYaw - _b);
  10087. currentModel.hat && currentModel.hat.setRotation(interpolatedYaw - tick.interpolatedYaw - 0.6 * _b);
  10088. }
  10089. }
  10090. }
  10091. /*
  10092. this.currentModel.updateRotationWithLocalData = function(entity, yaw) {
  10093. if (entity.isLocal() || yaw) {
  10094. entity.getTargetTick().aimingYaw = entity.getFromTick().aimingYaw = yaw || game.inputPacketCreator.getLastAnyYaw();
  10095. }
  10096. }
  10097. */
  10098. };
  10099. this.currentModel.setParent(this);
  10100. this.setNode(this.currentModel.getNode());
  10101. }
  10102. addMissingTickFields(t, e) {
  10103. for (var r in e) {
  10104. var i = e[r];
  10105. r in t || (t[r] = i);
  10106. }
  10107. }
  10108. };
  10109. game.renderer.textSpriteType = class s extends window.PIXI.Text {
  10110. constructor() {
  10111. super();
  10112. }
  10113. renderWebGL(t) {
  10114. this.updateText(true);
  10115. this.calculateVertices();
  10116.  
  10117. t.setObjectRenderer(t.plugins[this.pluginName]);
  10118. t.plugins[this.pluginName].render(this);
  10119. }
  10120. _renderCanvas(t) {
  10121. this.updateText(true);
  10122. t.plugins[this.pluginName].render(this);
  10123. }
  10124. };
  10125. game.renderer.textType = class a extends game.renderer.nodeType {
  10126. constructor(t, e, r) {
  10127. super();
  10128. this.text = new game.renderer.textSpriteType(t, {fontFamily: e, fontSize: r, lineJoin: "round", padding: 10});
  10129. this.text.resolution = 2 * window.devicePixelRatio;
  10130. this.setNode(this.text);
  10131. }
  10132. setColor(t, e, r) {
  10133. this.text.style.fill = t << 16 | e << 8 | r;
  10134. }
  10135. setStroke(t, e, r, i) {
  10136. this.text.style.stroke = t << 16 | e << 8 | r;
  10137. this.text.style.strokeThickness = i;
  10138. }
  10139. setFontWeight(t) {
  10140. this.text.style.fontWeight = t;
  10141. }
  10142. setLetterSpacing(t) {
  10143. this.text.style.letterSpacing = t;
  10144. }
  10145. setAnchor(t, e) {
  10146. this.text.anchor.set(t, e);
  10147. }
  10148. setString(t) {
  10149. this.text.text = t;
  10150. }
  10151. }
  10152.  
  10153. Game.currentGame.world.createEntity = function(t) {
  10154. if (this.entities[t.uid]) return;
  10155.  
  10156. let e;
  10157. if (Game.currentGame.getNetworkEntityPooling() && this._networkEntityPool.length > 0) {
  10158. e = this._networkEntityPool.shift();
  10159. e.setTargetTick(t);
  10160. e.uid = t.uid;
  10161. } else {
  10162. e = new game.renderer.entityType(t);
  10163. }
  10164.  
  10165. let shouldLoadModel = true;
  10166. if (t.model.indexOf("Zombie") > -1 && !game.script.optimize.zombieSprite) shouldLoadModel = false;
  10167. if (t.model in game.ui.buildingSchema && !game.script.optimize.towerSprite) shouldLoadModel = false;
  10168. if (t.entityClass == "Projectile" && !game.script.optimize.projectileSprite) shouldLoadModel = false;
  10169. shouldLoadModel && e.refreshModel(t.model);
  10170.  
  10171. t.uid === this.myUid && (this.localPlayer.setEntity(e), this.renderer.follow(e));
  10172. this.entities[t.uid] = e;
  10173. this.renderer.add(e, t.entityClass);
  10174. this.entityGrid.updateEntity(this.entities[t.uid]);
  10175. game.script.stashIndicators.onEntityCreated(t);
  10176. };
  10177. Game.currentGame.world.removeEntity = function(t) {
  10178. if (["Tree", "Stone", "NeutralCamp"].indexOf(this.entities[t].fromTick.model) > -1) return;
  10179. game.script.showAoe.onEntityRemoved(t);
  10180. this.renderer.remove(this.entities[t]);
  10181. this.entityGrid.removeEntity(parseInt(t));
  10182. if (this.entities[t].currentModel) {
  10183. const model = this.entities[t].currentModel;
  10184. if (Game.currentGame.getModelEntityPooling(model.modelName)) {
  10185. model.reset();
  10186. this.modelEntityPool[model.modelName].push(model);
  10187. };
  10188. };
  10189. if (Game.currentGame.getNetworkEntityPooling()) {
  10190. this.entities[t].reset();
  10191. this._networkEntityPool.push(this.entities[t]);
  10192. }
  10193. delete this.entities[t];
  10194. };
  10195. Game.currentGame.renderer.add = function(t, e) {
  10196. if (t instanceof game.renderer.entityType) {
  10197. switch (e) {
  10198. case "Prop":
  10199. this.scenery.addAttachment(t);
  10200. break;
  10201. case "Projectile":
  10202. this.projectiles.addAttachment(t);
  10203. break;
  10204. case "Player":
  10205. this.players.addAttachment(t);
  10206. break;
  10207. default:
  10208. this.npcs.addAttachment(t);
  10209. }
  10210. // } else t instanceof game.renderer.textType ? this.ui.addAttachment(t) : this.ground.addAttachment(t);
  10211. } else if (!game.script.optimize.background) {
  10212. if (t instanceof game.renderer.nodeType) Game.currentGame.renderer.ground.addAttachment(t);
  10213. else {
  10214. if (!(t instanceof game.renderer.textType)) return; // throw new Error("Unhandled object: " + JSON.stringify(t));
  10215. Game.currentGame.renderer.ui.addAttachment(t);
  10216. }
  10217. } else t instanceof game.renderer.textType ? this.ui.addAttachment(t) : this.ground.addAttachment(t);
  10218. };
  10219. Game.currentGame.renderer.remove = function(t) {
  10220. if (t instanceof game.renderer.entityType) {
  10221. switch (t.entityClass) {
  10222. case "Prop":
  10223. this.scenery.removeAttachment(t);
  10224. break;
  10225. case "Projectile":
  10226. this.projectiles.removeAttachment(t);
  10227. break;
  10228. case "Player":
  10229. this.players.removeAttachment(t);
  10230. break;
  10231. default:
  10232. this.npcs.removeAttachment(t);
  10233. }
  10234. // } else t instanceof game.renderer.textType ? this.ui.removeAttachment(t) : this.ground.removeAttachment(t);
  10235. } else if (!game.script.optimize.background) {
  10236. t instanceof game.renderer.nodeType ? Game.currentGame.renderer.ground.removeAttachment(t) : t instanceof game.renderer.textType && Game.currentGame.renderer.ui.removeAttachment(t);
  10237. } else t instanceof game.renderer.textType ? this.ui.removeAttachment(t) : this.ground.removeAttachment(t);
  10238. };
  10239. Game.currentGame.renderer.tickCallbacks[7] = () => {
  10240. const t = Game.currentGame.world.replicator.getMsInThisTick();
  10241. for (const e in Game.currentGame.world.entities) {
  10242. Game.currentGame.world.entities[e].tick(t, Game.currentGame.world.replicator.msPerTick);
  10243. };
  10244. };
  10245. } else {
  10246. Game.currentGame.world._createEntity = Game.currentGame.world.createEntity;
  10247. Game.currentGame.world.createEntity = function(t) {
  10248. if (this.entities[t.uid]) return;
  10249. this._createEntity(t);
  10250. game.script.stashIndicators.onEntityCreated(t);
  10251. };
  10252. Game.currentGame.world._removeEntity = Game.currentGame.world.removeEntity;
  10253. Game.currentGame.world.removeEntity = function(t) {
  10254. if (["Tree", "Stone", "NeutralCamp"].indexOf(this.entities[t].fromTick.model) > -1) return;
  10255. game.script.showAoe.onEntityRemoved(t);
  10256. this._removeEntity(t);
  10257. };
  10258. };
  10259.  
  10260. game.assetManager.models ||= {};
  10261. game.assetManager.models.rangeIndicatorModel = function(e, innerRGB = {r: 0xc8, g: 0xa0, b: 0x0}, borderRGB = {r: 0xff, g: 0xc8, b: 0x0}, lineWidth = 8) {
  10262. const container = new game.renderer.nodeType();
  10263. container.isCircular = e.isCircular || false;
  10264. container.goldRegion = new game.renderer.graphicsType();
  10265. container.goldRegion.setAlpha(0.1);
  10266.  
  10267. if (container.isCircular) {
  10268. container.goldRegion.drawCircle(0, 0, e.radius, innerRGB, borderRGB, lineWidth);
  10269. } else {
  10270. container.goldRegion.drawRect(-e.width / 2, -e.height / 2, e.width / 2, e.height / 2, innerRGB, borderRGB, lineWidth);
  10271. };
  10272.  
  10273. container.addAttachment(container.goldRegion);
  10274. return container;
  10275. };
  10276.  
  10277. /* @Misc. */
  10278. document.getElementsByClassName('hud-party-tag')[0].setAttribute('maxlength', 49);
  10279. document.getElementsByClassName('hud-intro-name')[0].setAttribute('maxlength', 29);
  10280.  
  10281.  
  10282. /* @Bindings */
  10283. (function MapFunctionsToElem() {
  10284. for (let page in menu) {
  10285. const [optionsElem, moreElem] = document.querySelectorAll("#" + page + " > div");
  10286. for (let option in menu[page]) {
  10287. const {name, description, more, isToggle, callback, customButtonText, onCallback, offCallback} = menu[page][option];
  10288. const hasMore = !!more;
  10289. const itemElem = document.createElement("div");
  10290. itemElem.id = option + "-div";
  10291. // if option is an object
  10292. if (typeof game.options.options[option] == "object") {
  10293. itemElem.innerHTML = `
  10294. <h2>${name}</h2>
  10295. <span>${description}</span>
  10296. <button id="toggle-${option}" ${game.options.options[option].enabled ? `class="underline-red"` : ""}>
  10297. ${game.options.options[option].enabled ? "Disable" : "Enable"}
  10298. </button>
  10299. ${isToggle === false ? `<button id="${name}">${customButtonText}</button>` : ""}
  10300. ${hasMore ? `<a id="more-${option}"></a>` : ""}
  10301. <div>
  10302. <span>Multibox</span>
  10303. <input id="multibox-${option}" type="checkbox" ${game.options.options[option].multibox ? "checked" : ""} />
  10304. </div>
  10305. `;
  10306. // if option is a boolean or undefined
  10307. } else {
  10308. itemElem.innerHTML = `
  10309. <h2>${name}</h2>
  10310. <span>${description}</span>
  10311. ${game.options.options[option] === undefined ? "" : `
  10312. <button id="toggle-${option}" ${game.options.options[option] ? `class="underline-red"` : ""}>
  10313. ${game.options.options[option] ? "Disable" : "Enable"}
  10314. </button>
  10315. `}
  10316. ${isToggle === false ? `<button id="${name}">${customButtonText}</button>` : ""}
  10317. ${hasMore ? `<a id="more-${option}"></a>` : ""}
  10318. `;
  10319. };
  10320. optionsElem.appendChild(itemElem);
  10321.  
  10322. if (hasMore) {
  10323. const {html, functions, bind} = more;
  10324. const moreContainer = document.createElement("div");
  10325. moreContainer.innerHTML = html;
  10326. moreContainer.style.display = "none";
  10327. moreElem.appendChild(moreContainer);
  10328. functions?.();
  10329.  
  10330. const toggleElem = getId("more-" + option);
  10331. toggleElem.onclick = () => {
  10332. refreshMore(page);
  10333. bind?.();
  10334. moreContainer.style.display = "block";
  10335. }
  10336. }
  10337. if (!(game.options.options[option] === undefined)) {
  10338. if (typeof game.options.options[option] == "object") {
  10339. addFunctionToElem({id: 'multibox-' + option, option, isCheckBox: true});
  10340. };
  10341. addFunctionToElem({id: 'toggle-' + option, option, buttonText: '', colors: "underline-red?", isToggle, callback, onCallback, offCallback});
  10342. } else if (isToggle === false) {
  10343. addFunctionToElem({id: name, option, buttonText: '', colors: "underline-red?", isToggle, callback, onCallback, offCallback});
  10344. };
  10345. };
  10346. };
  10347. })();
  10348.  
  10349. (function MapHandlers() {
  10350. for (const functionName in game.script) game.script[functionName]?.init?.();
  10351. for (const subFunctionName in game.script.sockets) {
  10352. if (typeof game.script.sockets[subFunctionName] == "object") {} // && (game.script.sockets[subFunctionName].parent = game.script.sockets);
  10353. };
  10354. const keybindListeners = {};
  10355. for (const functionName in game.options.options) {
  10356. if (!game.script[functionName] || game.script[functionName].handlers === undefined) continue;
  10357. const usesHandlers = game.script[functionName].handlers;
  10358. for (const {type, names} of usesHandlers) {
  10359. console.log(type, functionName, names);
  10360. switch(type) {
  10361. case "rpc":
  10362. for (const name of names) {
  10363. game.network.addRpcHandler(name, game.script[functionName][name].bind(game.script[functionName]));
  10364. };
  10365. break;
  10366. case "entityUpdate":
  10367. game.network.addEntityUpdateHandler(game.script[functionName][names].bind(game.script[functionName]));
  10368. break;
  10369. case "tickUpdate":
  10370. game.ui._events[names].push(game.script[functionName][names].bind(game.script[functionName][names]));
  10371. break;
  10372. case "keybind":
  10373. if (typeof names == "object") {
  10374. for (const name of names) {
  10375. keybindListeners[name] ||= [];
  10376. keybindListeners[name].push(functionName);
  10377. };
  10378. } else {
  10379. keybindListeners[names] ||= [];
  10380. keybindListeners[names].push(functionName);
  10381. };
  10382. break;
  10383. case "packetFunc":
  10384. game.network[names[0]] = function(data) {
  10385. game.script[functionName][names[1]](data);
  10386. this.sendPacket(names[2], data);
  10387. };
  10388. break;
  10389. };
  10390. };
  10391. };
  10392. for (const name in keybindListeners) {
  10393. document.addEventListener(name, function(e) {
  10394. if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
  10395. for (const functionName of keybindListeners[name]) game.script[functionName][name](e);
  10396. };
  10397. });
  10398. };
  10399. })();