// ==UserScript==
// @name Sun:Raise - zombs.io
// @namespace http://tampermonkey.net/
// @version 1.10
// @description weeb strikes again
// @author rdm
// @match *://zombs.io/
// @icon https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Kanae%20Midsummer%20icon.webp?v=1716509941729
// @grant none
// @license GNU GPLv3
// @noframes
// ==/UserScript==
/* @Credit
* i have to give credit where credit is due,
* most of the images used in this mod, including:
* + intro background (#hud-intro::before),
* + theme-character (.hud-intro-character)
* is taken from Arcaea, this mod is themed to look
* like Arcaea's UI.
*
* visit Arcaea at https://arcaea.lowiro.com/ and
* check out the game on Google's Play Store and
* Apple's App Store.
*/
// day 1 (0.1) : intro styles done
// day 2 (0.2) : menu styles done
// day 3 (0.3) : ahrc, rb, autoup done + polishing
// day 4 (0.4) : entering unfamiliar territory with scanner
// day 5 (0.41): polishing
// day ? (0.42): beta release
// v0.5 : added resizeable wall blocks
// v0.6 : auto heal & ??????????????????
// v0.7 : unlimited slots base saver
// v0.71 : shop shortcuts
// v0.73 : shop shortcut fixes & added entity preserver
// v0.80 : raid defending tools (in Misc.) and Grouping Grid (courtesy of ABCxFF) added
// v0.90 : multi-auto-heal feature based on Trollers' idea, fix assets (again) & one minor fix
// v0.91 : websocket scanner preview
// v0.92 : map viewer (press +) backported from my personal mod
// v0.93 : i forgor that entity caching (added in v0.91? but i also forgor to note that in oops) doesnt have a reset button so now it does
// v1.00 : now with enough features! and more to come...
// v1.10 : session saver! more about it here: https://github.com/AyuBloom/zombs-session-saver
/* @Dependencies */
/*
bytebuffer.js (c) 2015 Daniel Wirtz <dcode@dcode.io>
Backing buffer: ArrayBuffer, Accessor: Uint8Array
Released under the Apache License, Version 2.0
see: https://github.com/dcodeIO/bytebuffer.js for details
*/
(function (h, l) {
if ("function" === typeof define && define.amd) define(["long"], l);
else if ("function" === typeof require && "object" === typeof module && module && module.exports) {
h = module;
try {
var t = require("long");
} catch (v) {}
l = l(t);
h.exports = l;
} else (h.dcodeIO = h.dcodeIO || {}).ByteBuffer = l(h.dcodeIO.Long);
})(this, function (h) {
function l(a) {
var b = 0;
return function () {
return b < a.length ? a.charCodeAt(b++) : null;
};
}
function t() {
var a = [],
b = [];
return function () {
if (0 === arguments.length) return b.join("") + x.apply(String, a);
1024 < a.length + arguments.length && (b.push(x.apply(String, a)), (a.length = 0));
Array.prototype.push.apply(a, arguments);
};
}
function v(a, b, c, e, k) {
var f = 8 * k - e - 1;
var d = (1 << f) - 1,
g = d >> 1,
n = -7;
k = c ? k - 1 : 0;
var h = c ? -1 : 1,
q = a[b + k];
k += h;
c = q & ((1 << -n) - 1);
q >>= -n;
for (n += f; 0 < n; c = 256 * c + a[b + k], k += h, n -= 8);
f = c & ((1 << -n) - 1);
c >>= -n;
for (n += e; 0 < n; f = 256 * f + a[b + k], k += h, n -= 8);
if (0 === c) c = 1 - g;
else {
if (c === d) return f ? NaN : Infinity * (q ? -1 : 1);
f += Math.pow(2, e);
c -= g;
}
return (q ? -1 : 1) * f * Math.pow(2, c - e);
}
function y(a, b, c, e, k, f) {
var d,
g = 8 * f - k - 1,
n = (1 << g) - 1,
h = n >> 1,
q = 23 === k ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
f = e ? 0 : f - 1;
var l = e ? 1 : -1,
m = 0 > b || (0 === b && 0 > 1 / b) ? 1 : 0;
b = Math.abs(b);
isNaN(b) || Infinity === b
? ((b = isNaN(b) ? 1 : 0), (e = n))
: ((e = Math.floor(Math.log(b) / Math.LN2)),
1 > b * (d = Math.pow(2, -e)) && (e--, (d *= 2)),
(b = 1 <= e + h ? b + q / d : b + q * Math.pow(2, 1 - h)),
2 <= b * d && (e++, (d /= 2)),
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)));
for (; 8 <= k; a[c + f] = b & 255, f += l, b /= 256, k -= 8);
e = (e << k) | b;
for (g += k; 0 < g; a[c + f] = e & 255, f += l, e /= 256, g -= 8);
a[c + f - l] |= 128 * m;
}
var g = function (a, b, c) {
"undefined" === typeof a && (a = g.DEFAULT_CAPACITY);
"undefined" === typeof b && (b = g.DEFAULT_ENDIAN);
"undefined" === typeof c && (c = g.DEFAULT_NOASSERT);
if (!c) {
a |= 0;
if (0 > a) throw RangeError("Illegal capacity");
b = !!b;
c = !!c;
}
this.buffer = 0 === a ? w : new ArrayBuffer(a);
this.view = 0 === a ? null : new Uint8Array(this.buffer);
this.offset = 0;
this.markedOffset = -1;
this.limit = a;
this.littleEndian = b;
this.noAssert = c;
};
g.VERSION = "5.0.1";
g.LITTLE_ENDIAN = !0;
g.BIG_ENDIAN = !1;
g.DEFAULT_CAPACITY = 16;
g.DEFAULT_ENDIAN = g.BIG_ENDIAN;
g.DEFAULT_NOASSERT = !1;
g.Long = h || null;
var d = g.prototype;
Object.defineProperty(d, "__isByteBuffer__", { value: !0, enumerable: !1, configurable: !1 });
var w = new ArrayBuffer(0),
x = String.fromCharCode;
g.accessor = function () {
return Uint8Array;
};
g.allocate = function (a, b, c) {
return new g(a, b, c);
};
g.concat = function (a, b, c, e) {
if ("boolean" === typeof b || "string" !== typeof b) (e = c), (c = b), (b = void 0);
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);
if (0 === k) return new g(0, c, e);
b = new g(k, c, e);
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));
b.limit = b.offset;
b.offset = 0;
return b;
};
g.isByteBuffer = function (a) {
return !0 === (a && a.__isByteBuffer__);
};
g.type = function () {
return ArrayBuffer;
};
g.wrap = function (a, b, c, e) {
"string" !== typeof b && ((e = c), (c = b), (b = void 0));
if ("string" === typeof a)
switch (("undefined" === typeof b && (b = "utf8"), b)) {
case "base64":
return g.fromBase64(a, c);
case "hex":
return g.fromHex(a, c);
case "binary":
return g.fromBinary(a, c);
case "utf8":
return g.fromUTF8(a, c);
case "debug":
return g.fromDebug(a, c);
default:
throw Error("Unsupported encoding: " + b);
}
if (null === a || "object" !== typeof a) throw TypeError("Illegal buffer");
if (g.isByteBuffer(a)) return (b = d.clone.call(a)), (b.markedOffset = -1), b;
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)));
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));
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];
else throw TypeError("Illegal buffer");
return b;
};
d.writeBitSet = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if (!(a instanceof Array)) throw TypeError("Illegal BitSet: Not an array");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
var e = b,
k = a.length,
f = k >> 3,
d = 0;
for (b += this.writeVarint32(k, b); f--; ) {
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);
this.writeByte(g, b++);
}
if (d < k) {
for (g = f = 0; d < k; ) g |= (!!a[d++] & 1) << f++;
this.writeByte(g, b++);
}
return c ? ((this.offset = b), this) : b - e;
};
d.readBitSet = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
var c = this.readVarint32(a),
e = c.value,
k = e >> 3,
f = 0,
d = [];
for (a += c.length; k--; )
(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));
if (f < e) for (k = 0, c = this.readByte(a++); f < e; ) d[f++] = !!((c >> k++) & 1);
b && (this.offset = a);
return d;
};
d.readBytes = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + a > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+" + a + ") <= " + this.buffer.byteLength);
}
b = this.slice(b, b + a);
c && (this.offset += a);
return b;
};
d.writeInt8 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a |= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 1;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
this.view[b - 1] = a;
c && (this.offset += 1);
return this;
};
d.writeByte = d.writeInt8;
d.readInt8 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
}
a = this.view[a];
128 === (a & 128) && (a = -(255 - a + 1));
b && (this.offset += 1);
return a;
};
d.readByte = d.readInt8;
d.writeUint8 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 1;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
this.view[b - 1] = a;
c && (this.offset += 1);
return this;
};
d.writeUInt8 = d.writeUint8;
d.readUint8 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
}
a = this.view[a];
b && (this.offset += 1);
return a;
};
d.readUInt8 = d.readUint8;
d.writeInt16 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a |= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 2;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= 2;
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));
c && (this.offset += 2);
return this;
};
d.writeShort = d.writeInt16;
d.readInt16 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+2) <= " + this.buffer.byteLength);
}
if (this.littleEndian) {
var c = this.view[a];
c |= this.view[a + 1] << 8;
} else (c = this.view[a] << 8), (c |= this.view[a + 1]);
32768 === (c & 32768) && (c = -(65535 - c + 1));
b && (this.offset += 2);
return c;
};
d.readShort = d.readInt16;
d.writeUint16 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 2;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= 2;
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));
c && (this.offset += 2);
return this;
};
d.writeUInt16 = d.writeUint16;
d.readUint16 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+2) <= " + this.buffer.byteLength);
}
if (this.littleEndian) {
var c = this.view[a];
c |= this.view[a + 1] << 8;
} else (c = this.view[a] << 8), (c |= this.view[a + 1]);
b && (this.offset += 2);
return c;
};
d.readUInt16 = d.readUint16;
d.writeInt32 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a |= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 4;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= 4;
this.littleEndian
? ((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))
: ((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));
c && (this.offset += 4);
return this;
};
d.writeInt = d.writeInt32;
d.readInt32 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
}
if (this.littleEndian) {
var c = this.view[a + 2] << 16;
c |= this.view[a + 1] << 8;
c |= this.view[a];
c += (this.view[a + 3] << 24) >>> 0;
} else (c = this.view[a + 1] << 16), (c |= this.view[a + 2] << 8), (c |= this.view[a + 3]), (c += (this.view[a] << 24) >>> 0);
b && (this.offset += 4);
return c | 0;
};
d.readInt = d.readInt32;
d.writeUint32 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 4;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= 4;
this.littleEndian
? ((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))
: ((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));
c && (this.offset += 4);
return this;
};
d.writeUInt32 = d.writeUint32;
d.readUint32 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
}
if (this.littleEndian) {
var c = this.view[a + 2] << 16;
c |= this.view[a + 1] << 8;
c |= this.view[a];
c += (this.view[a + 3] << 24) >>> 0;
} else (c = this.view[a + 1] << 16), (c |= this.view[a + 2] << 8), (c |= this.view[a + 3]), (c += (this.view[a] << 24) >>> 0);
b && (this.offset += 4);
return c;
};
d.readUInt32 = d.readUint32;
h &&
((d.writeInt64 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" === typeof a) a = h.fromNumber(a);
else if ("string" === typeof a) a = h.fromString(a);
else if (!(a && a instanceof h)) throw TypeError("Illegal value: " + a + " (not an integer or Long)");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
"number" === typeof a ? (a = h.fromNumber(a)) : "string" === typeof a && (a = h.fromString(a));
b += 8;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= 8;
e = a.low;
a = a.high;
this.littleEndian
? ((this.view[b + 3] = (e >>> 24) & 255),
(this.view[b + 2] = (e >>> 16) & 255),
(this.view[b + 1] = (e >>> 8) & 255),
(this.view[b] = e & 255),
(b += 4),
(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))
: ((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),
(b += 4),
(this.view[b] = (e >>> 24) & 255),
(this.view[b + 1] = (e >>> 16) & 255),
(this.view[b + 2] = (e >>> 8) & 255),
(this.view[b + 3] = e & 255));
c && (this.offset += 8);
return this;
}),
(d.writeLong = d.writeInt64),
(d.readInt64 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+8) <= " + this.buffer.byteLength);
}
if (this.littleEndian) {
var c = this.view[a + 2] << 16;
c |= this.view[a + 1] << 8;
c |= this.view[a];
c += (this.view[a + 3] << 24) >>> 0;
a += 4;
var e = this.view[a + 2] << 16;
e |= this.view[a + 1] << 8;
e |= this.view[a];
e += (this.view[a + 3] << 24) >>> 0;
} else
(e = this.view[a + 1] << 16),
(e |= this.view[a + 2] << 8),
(e |= this.view[a + 3]),
(e += (this.view[a] << 24) >>> 0),
(a += 4),
(c = this.view[a + 1] << 16),
(c |= this.view[a + 2] << 8),
(c |= this.view[a + 3]),
(c += (this.view[a] << 24) >>> 0);
a = new h(c, e, !1);
b && (this.offset += 8);
return a;
}),
(d.readLong = d.readInt64),
(d.writeUint64 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" === typeof a) a = h.fromNumber(a);
else if ("string" === typeof a) a = h.fromString(a);
else if (!(a && a instanceof h)) throw TypeError("Illegal value: " + a + " (not an integer or Long)");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
"number" === typeof a ? (a = h.fromNumber(a)) : "string" === typeof a && (a = h.fromString(a));
b += 8;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= 8;
e = a.low;
a = a.high;
this.littleEndian
? ((this.view[b + 3] = (e >>> 24) & 255),
(this.view[b + 2] = (e >>> 16) & 255),
(this.view[b + 1] = (e >>> 8) & 255),
(this.view[b] = e & 255),
(b += 4),
(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))
: ((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),
(b += 4),
(this.view[b] = (e >>> 24) & 255),
(this.view[b + 1] = (e >>> 16) & 255),
(this.view[b + 2] = (e >>> 8) & 255),
(this.view[b + 3] = e & 255));
c && (this.offset += 8);
return this;
}),
(d.writeUInt64 = d.writeUint64),
(d.readUint64 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+8) <= " + this.buffer.byteLength);
}
if (this.littleEndian) {
var c = this.view[a + 2] << 16;
c |= this.view[a + 1] << 8;
c |= this.view[a];
c += (this.view[a + 3] << 24) >>> 0;
a += 4;
var e = this.view[a + 2] << 16;
e |= this.view[a + 1] << 8;
e |= this.view[a];
e += (this.view[a + 3] << 24) >>> 0;
} else
(e = this.view[a + 1] << 16),
(e |= this.view[a + 2] << 8),
(e |= this.view[a + 3]),
(e += (this.view[a] << 24) >>> 0),
(a += 4),
(c = this.view[a + 1] << 16),
(c |= this.view[a + 2] << 8),
(c |= this.view[a + 3]),
(c += (this.view[a] << 24) >>> 0);
a = new h(c, e, !0);
b && (this.offset += 8);
return a;
}),
(d.readUInt64 = d.readUint64));
d.writeFloat32 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a) throw TypeError("Illegal value: " + a + " (not a number)");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 4;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
y(this.view, a, b - 4, this.littleEndian, 23, 4);
c && (this.offset += 4);
return this;
};
d.writeFloat = d.writeFloat32;
d.readFloat32 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
}
a = v(this.view, a, this.littleEndian, 23, 4);
b && (this.offset += 4);
return a;
};
d.readFloat = d.readFloat32;
d.writeFloat64 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a) throw TypeError("Illegal value: " + a + " (not a number)");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
b += 8;
var e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
y(this.view, a, b - 8, this.littleEndian, 52, 8);
c && (this.offset += 8);
return this;
};
d.writeDouble = d.writeFloat64;
d.readFloat64 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+8) <= " + this.buffer.byteLength);
}
a = v(this.view, a, this.littleEndian, 52, 8);
b && (this.offset += 8);
return a;
};
d.readDouble = d.readFloat64;
g.MAX_VARINT32_BYTES = 5;
g.calculateVarint32 = function (a) {
a >>>= 0;
return 128 > a ? 1 : 16384 > a ? 2 : 2097152 > a ? 3 : 268435456 > a ? 4 : 5;
};
g.zigZagEncode32 = function (a) {
return (((a |= 0) << 1) ^ (a >> 31)) >>> 0;
};
g.zigZagDecode32 = function (a) {
return ((a >>> 1) ^ -(a & 1)) | 0;
};
d.writeVarint32 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a |= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
var e = g.calculateVarint32(a);
b += e;
var k = this.buffer.byteLength;
b > k && this.resize((k *= 2) > b ? k : b);
b -= e;
for (a >>>= 0; 128 <= a; ) (k = (a & 127) | 128), (this.view[b++] = k), (a >>>= 7);
this.view[b++] = a;
return c ? ((this.offset = b), this) : e;
};
d.writeVarint32ZigZag = function (a, b) {
return this.writeVarint32(g.zigZagEncode32(a), b);
};
d.readVarint32 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
}
var c = 0,
e = 0;
do {
if (!this.noAssert && a > this.limit) throw ((a = Error("Truncated")), (a.truncated = !0), a);
var k = this.view[a++];
5 > c && (e |= (k & 127) << (7 * c));
++c;
} while (0 !== (k & 128));
e |= 0;
return b ? ((this.offset = a), e) : { value: e, length: c };
};
d.readVarint32ZigZag = function (a) {
a = this.readVarint32(a);
"object" === typeof a ? (a.value = g.zigZagDecode32(a.value)) : (a = g.zigZagDecode32(a));
return a;
};
h &&
((g.MAX_VARINT64_BYTES = 10),
(g.calculateVarint64 = function (a) {
"number" === typeof a ? (a = h.fromNumber(a)) : "string" === typeof a && (a = h.fromString(a));
var b = a.toInt() >>> 0,
c = a.shiftRightUnsigned(28).toInt() >>> 0;
a = a.shiftRightUnsigned(56).toInt() >>> 0;
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;
}),
(g.zigZagEncode64 = function (a) {
"number" === typeof a ? (a = h.fromNumber(a, !1)) : "string" === typeof a ? (a = h.fromString(a, !1)) : !1 !== a.unsigned && (a = a.toSigned());
return a.shiftLeft(1).xor(a.shiftRight(63)).toUnsigned();
}),
(g.zigZagDecode64 = function (a) {
"number" === typeof a ? (a = h.fromNumber(a, !1)) : "string" === typeof a ? (a = h.fromString(a, !1)) : !1 !== a.unsigned && (a = a.toSigned());
return a.shiftRightUnsigned(1).xor(a.and(h.ONE).toSigned().negate()).toSigned();
}),
(d.writeVarint64 = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" === typeof a) a = h.fromNumber(a);
else if ("string" === typeof a) a = h.fromString(a);
else if (!(a && a instanceof h)) throw TypeError("Illegal value: " + a + " (not an integer or Long)");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
"number" === typeof a ? (a = h.fromNumber(a, !1)) : "string" === typeof a ? (a = h.fromString(a, !1)) : !1 !== a.unsigned && (a = a.toSigned());
var e = g.calculateVarint64(a),
k = a.toInt() >>> 0,
f = a.shiftRightUnsigned(28).toInt() >>> 0;
a = a.shiftRightUnsigned(56).toInt() >>> 0;
b += e;
var d = this.buffer.byteLength;
b > d && this.resize((d *= 2) > b ? d : b);
b -= e;
switch (e) {
case 10:
this.view[b + 9] = (a >>> 7) & 1;
case 9:
this.view[b + 8] = 9 !== e ? a | 128 : a & 127;
case 8:
this.view[b + 7] = 8 !== e ? (f >>> 21) | 128 : (f >>> 21) & 127;
case 7:
this.view[b + 6] = 7 !== e ? (f >>> 14) | 128 : (f >>> 14) & 127;
case 6:
this.view[b + 5] = 6 !== e ? (f >>> 7) | 128 : (f >>> 7) & 127;
case 5:
this.view[b + 4] = 5 !== e ? f | 128 : f & 127;
case 4:
this.view[b + 3] = 4 !== e ? (k >>> 21) | 128 : (k >>> 21) & 127;
case 3:
this.view[b + 2] = 3 !== e ? (k >>> 14) | 128 : (k >>> 14) & 127;
case 2:
this.view[b + 1] = 2 !== e ? (k >>> 7) | 128 : (k >>> 7) & 127;
case 1:
this.view[b] = 1 !== e ? k | 128 : k & 127;
}
return c ? ((this.offset += e), this) : e;
}),
(d.writeVarint64ZigZag = function (a, b) {
return this.writeVarint64(g.zigZagEncode64(a), b);
}),
(d.readVarint64 = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
}
var c = a,
e = 0,
k = 0;
var d = this.view[a++];
var g = d & 127;
if (
d & 128 &&
((d = this.view[a++]), (g |= (d & 127) << 7), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (g |= (d & 127) << 14), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (g |= (d & 127) << 21), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (e = d & 127), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (e |= (d & 127) << 7), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (e |= (d & 127) << 14), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (e |= (d & 127) << 21), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (k = d & 127), d & 128 || (this.noAssert && "undefined" === typeof d)) &&
((d = this.view[a++]), (k |= (d & 127) << 7), d & 128 || (this.noAssert && "undefined" === typeof d))
)
throw Error("Buffer overrun");
g = h.fromBits(g | (e << 28), (e >>> 4) | (k << 24), !1);
return b ? ((this.offset = a), g) : { value: g, length: a - c };
}),
(d.readVarint64ZigZag = function (a) {
(a = this.readVarint64(a)) && a.value instanceof h ? (a.value = g.zigZagDecode64(a.value)) : (a = g.zigZagDecode64(a));
return a;
}));
d.writeCString = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
var e,
d = a.length;
if (!this.noAssert) {
if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
for (e = 0; e < d; ++e) if (0 === a.charCodeAt(e)) throw RangeError("Illegal str: Contains NULL-characters");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
d = m.calculateUTF16asUTF8(l(a))[1];
b += d + 1;
e = this.buffer.byteLength;
b > e && this.resize((e *= 2) > b ? e : b);
b -= d + 1;
m.encodeUTF16toUTF8(
l(a),
function (a) {
this.view[b++] = a;
}.bind(this)
);
this.view[b++] = 0;
return c ? ((this.offset = b), this) : d;
};
d.readCString = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
}
var c = a,
e,
d = -1;
m.decodeUTF8toUTF16(
function () {
if (0 === d) return null;
if (a >= this.limit) throw RangeError("Illegal range: Truncated data, " + a + " < " + this.limit);
d = this.view[a++];
return 0 === d ? null : d;
}.bind(this),
(e = t()),
!0
);
return b ? ((this.offset = a), e()) : { string: e(), length: a - c };
};
d.writeIString = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
var e = b;
var d = m.calculateUTF16asUTF8(l(a), this.noAssert)[1];
b += 4 + d;
var f = this.buffer.byteLength;
b > f && this.resize((f *= 2) > b ? f : b);
b -= 4 + d;
this.littleEndian
? ((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))
: ((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));
b += 4;
m.encodeUTF16toUTF8(
l(a),
function (a) {
this.view[b++] = a;
}.bind(this)
);
if (b !== e + 4 + d) throw RangeError("Illegal range: Truncated data, " + b + " == " + (b + 4 + d));
return c ? ((this.offset = b), this) : b - e;
};
d.readIString = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+4) <= " + this.buffer.byteLength);
}
var c = a,
e = this.readUint32(a);
e = this.readUTF8String(e, g.METRICS_BYTES, (a += 4));
a += e.length;
return b ? ((this.offset = a), e.string) : { string: e.string, length: a - c };
};
g.METRICS_CHARS = "c";
g.METRICS_BYTES = "b";
d.writeUTF8String = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
var e = b;
var d = m.calculateUTF16asUTF8(l(a))[1];
b += d;
var f = this.buffer.byteLength;
b > f && this.resize((f *= 2) > b ? f : b);
b -= d;
m.encodeUTF16toUTF8(
l(a),
function (a) {
this.view[b++] = a;
}.bind(this)
);
return c ? ((this.offset = b), this) : b - e;
};
d.writeString = d.writeUTF8String;
g.calculateUTF8Chars = function (a) {
return m.calculateUTF16asUTF8(l(a))[0];
};
g.calculateUTF8Bytes = function (a) {
return m.calculateUTF16asUTF8(l(a))[1];
};
g.calculateString = g.calculateUTF8Bytes;
d.readUTF8String = function (a, b, c) {
"number" === typeof b && ((c = b), (b = void 0));
var e = "undefined" === typeof c;
e && (c = this.offset);
"undefined" === typeof b && (b = g.METRICS_CHARS);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal length: " + a + " (not an integer)");
a |= 0;
if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
c >>>= 0;
if (0 > c || c + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+0) <= " + this.buffer.byteLength);
}
var d = 0,
f = c;
if (b === g.METRICS_CHARS) {
var p = t();
m.decodeUTF8(
function () {
return d < a && c < this.limit ? this.view[c++] : null;
}.bind(this),
function (a) {
++d;
m.UTF8toUTF16(a, p);
}
);
if (d !== a) throw RangeError("Illegal range: Truncated data, " + d + " == " + a);
return e ? ((this.offset = c), p()) : { string: p(), length: c - f };
}
if (b === g.METRICS_BYTES) {
if (!this.noAssert) {
if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
c >>>= 0;
if (0 > c || c + a > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+" + a + ") <= " + this.buffer.byteLength);
}
var h = c + a;
m.decodeUTF8toUTF16(
function () {
return c < h ? this.view[c++] : null;
}.bind(this),
(p = t()),
this.noAssert
);
if (c !== h) throw RangeError("Illegal range: Truncated data, " + c + " == " + h);
return e ? ((this.offset = c), p()) : { string: p(), length: c - f };
}
throw TypeError("Unsupported metrics: " + b);
};
d.readString = d.readUTF8String;
d.writeVString = function (a, b) {
var c = "undefined" === typeof b;
c && (b = this.offset);
if (!this.noAssert) {
if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: " + b + " (not an integer)");
b >>>= 0;
if (0 > b || b + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + b + " (+0) <= " + this.buffer.byteLength);
}
var e = b;
var d = m.calculateUTF16asUTF8(l(a), this.noAssert)[1];
var f = g.calculateVarint32(d);
b += f + d;
var p = this.buffer.byteLength;
b > p && this.resize((p *= 2) > b ? p : b);
b -= f + d;
b += this.writeVarint32(d, b);
m.encodeUTF16toUTF8(
l(a),
function (a) {
this.view[b++] = a;
}.bind(this)
);
if (b !== e + d + f) throw RangeError("Illegal range: Truncated data, " + b + " == " + (b + d + f));
return c ? ((this.offset = b), this) : b - e;
};
d.readVString = function (a) {
var b = "undefined" === typeof a;
b && (a = this.offset);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+1) <= " + this.buffer.byteLength);
}
var c = a,
e = this.readVarint32(a);
e = this.readUTF8String(e.value, g.METRICS_BYTES, (a += e.length));
a += e.length;
return b ? ((this.offset = a), e.string) : { string: e.string, length: a - c };
};
d.append = function (a, b, c) {
if ("number" === typeof b || "string" !== typeof b) (c = b), (b = void 0);
var e = "undefined" === typeof c;
e && (c = this.offset);
if (!this.noAssert) {
if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
c >>>= 0;
if (0 > c || c + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+0) <= " + this.buffer.byteLength);
}
a instanceof g || (a = g.wrap(a, b));
b = a.limit - a.offset;
if (0 >= b) return this;
c += b;
var d = this.buffer.byteLength;
c > d && this.resize((d *= 2) > c ? d : c);
c -= b;
this.view.set(a.view.subarray(a.offset, a.limit), c);
a.offset += b;
e && (this.offset += b);
return this;
};
d.appendTo = function (a, b) {
a.append(this, b);
return this;
};
d.writeBytes = d.append;
d.assert = function (a) {
this.noAssert = !a;
return this;
};
d.capacity = function () {
return this.buffer.byteLength;
};
d.clear = function () {
this.offset = 0;
this.limit = this.buffer.byteLength;
this.markedOffset = -1;
return this;
};
d.clone = function (a) {
var b = new g(0, this.littleEndian, this.noAssert);
a ? ((b.buffer = new ArrayBuffer(this.buffer.byteLength)), (b.view = new Uint8Array(b.buffer))) : ((b.buffer = this.buffer), (b.view = this.view));
b.offset = this.offset;
b.markedOffset = this.markedOffset;
b.limit = this.limit;
return b;
};
d.compact = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
b >>>= 0;
if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
}
if (0 === a && b === this.buffer.byteLength) return this;
var c = b - a;
if (0 === c) return (this.buffer = w), (this.view = null), 0 <= this.markedOffset && (this.markedOffset -= a), (this.limit = this.offset = 0), this;
var e = new ArrayBuffer(c),
d = new Uint8Array(e);
d.set(this.view.subarray(a, b));
this.buffer = e;
this.view = d;
0 <= this.markedOffset && (this.markedOffset -= a);
this.offset = 0;
this.limit = c;
return this;
};
d.copy = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
b >>>= 0;
if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
}
if (a === b) return new g(0, this.littleEndian, this.noAssert);
var c = b - a,
e = new g(c, this.littleEndian, this.noAssert);
e.offset = 0;
e.limit = c;
0 <= e.markedOffset && (e.markedOffset -= a);
this.copyTo(e, 0, a, b);
return e;
};
d.copyTo = function (a, b, c, e) {
var d, f;
if (!this.noAssert && !g.isByteBuffer(a)) throw TypeError("Illegal target: Not a ByteBuffer");
b = (f = "undefined" === typeof b) ? a.offset : b | 0;
c = (d = "undefined" === typeof c) ? this.offset : c | 0;
e = "undefined" === typeof e ? this.limit : e | 0;
if (0 > b || b > a.buffer.byteLength) throw RangeError("Illegal target range: 0 <= " + b + " <= " + a.buffer.byteLength);
if (0 > c || e > this.buffer.byteLength) throw RangeError("Illegal source range: 0 <= " + c + " <= " + this.buffer.byteLength);
var p = e - c;
if (0 === p) return a;
a.ensureCapacity(b + p);
a.view.set(this.view.subarray(c, e), b);
d && (this.offset += p);
f && (a.offset += p);
return this;
};
d.ensureCapacity = function (a) {
var b = this.buffer.byteLength;
return b < a ? this.resize((b *= 2) > a ? b : a) : this;
};
d.fill = function (a, b, c) {
var e = "undefined" === typeof b;
e && (b = this.offset);
"string" === typeof a && 0 < a.length && (a = a.charCodeAt(0));
"undefined" === typeof b && (b = this.offset);
"undefined" === typeof c && (c = this.limit);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal value: " + a + " (not an integer)");
a |= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal begin: Not an integer");
b >>>= 0;
if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal end: Not an integer");
c >>>= 0;
if (0 > b || b > c || c > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + b + " <= " + c + " <= " + this.buffer.byteLength);
}
if (b >= c) return this;
for (; b < c; ) this.view[b++] = a;
e && (this.offset = b);
return this;
};
d.flip = function () {
this.limit = this.offset;
this.offset = 0;
return this;
};
d.mark = function (a) {
a = "undefined" === typeof a ? this.offset : a;
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal offset: " + a + " (not an integer)");
a >>>= 0;
if (0 > a || a + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + a + " (+0) <= " + this.buffer.byteLength);
}
this.markedOffset = a;
return this;
};
d.order = function (a) {
if (!this.noAssert && "boolean" !== typeof a) throw TypeError("Illegal littleEndian: Not a boolean");
this.littleEndian = !!a;
return this;
};
d.LE = function (a) {
this.littleEndian = "undefined" !== typeof a ? !!a : !0;
return this;
};
d.BE = function (a) {
this.littleEndian = "undefined" !== typeof a ? !a : !1;
return this;
};
d.prepend = function (a, b, c) {
if ("number" === typeof b || "string" !== typeof b) (c = b), (b = void 0);
var e = "undefined" === typeof c;
e && (c = this.offset);
if (!this.noAssert) {
if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal offset: " + c + " (not an integer)");
c >>>= 0;
if (0 > c || c + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= " + c + " (+0) <= " + this.buffer.byteLength);
}
a instanceof g || (a = g.wrap(a, b));
b = a.limit - a.offset;
if (0 >= b) return this;
var d = b - c;
if (0 < d) {
var f = new ArrayBuffer(this.buffer.byteLength + d),
p = new Uint8Array(f);
p.set(this.view.subarray(c, this.buffer.byteLength), b);
this.buffer = f;
this.view = p;
this.offset += d;
0 <= this.markedOffset && (this.markedOffset += d);
this.limit += d;
c += d;
} else new Uint8Array(this.buffer);
this.view.set(a.view.subarray(a.offset, a.limit), c - b);
a.offset = a.limit;
e && (this.offset -= b);
return this;
};
d.prependTo = function (a, b) {
a.prepend(this, b);
return this;
};
d.printDebug = function (a) {
"function" !== typeof a && (a = console.log.bind(console));
a(this.toString() + "\n-------------------------------------------------------------------\n" + this.toDebug(!0));
};
d.remaining = function () {
return this.limit - this.offset;
};
d.reset = function () {
0 <= this.markedOffset ? ((this.offset = this.markedOffset), (this.markedOffset = -1)) : (this.offset = 0);
return this;
};
d.resize = function (a) {
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal capacity: " + a + " (not an integer)");
a |= 0;
if (0 > a) throw RangeError("Illegal capacity: 0 <= " + a);
}
if (this.buffer.byteLength < a) {
a = new ArrayBuffer(a);
var b = new Uint8Array(a);
b.set(this.view);
this.buffer = a;
this.view = b;
}
return this;
};
d.reverse = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
b >>>= 0;
if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
}
if (a === b) return this;
Array.prototype.reverse.call(this.view.subarray(a, b));
return this;
};
d.skip = function (a) {
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal length: " + a + " (not an integer)");
a |= 0;
}
var b = this.offset + a;
if (!this.noAssert && (0 > b || b > this.buffer.byteLength)) throw RangeError("Illegal length: 0 <= " + this.offset + " + " + a + " <= " + this.buffer.byteLength);
this.offset = b;
return this;
};
d.slice = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
b >>>= 0;
if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
}
var c = this.clone();
c.offset = a;
c.limit = b;
return c;
};
d.toBuffer = function (a) {
var b = this.offset,
c = this.limit;
if (!this.noAssert) {
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal offset: Not an integer");
b >>>= 0;
if ("number" !== typeof c || 0 !== c % 1) throw TypeError("Illegal limit: Not an integer");
c >>>= 0;
if (0 > b || b > c || c > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + b + " <= " + c + " <= " + this.buffer.byteLength);
}
if (!a && 0 === b && c === this.buffer.byteLength) return this.buffer;
if (b === c) return w;
a = new ArrayBuffer(c - b);
new Uint8Array(a).set(new Uint8Array(this.buffer).subarray(b, c), 0);
return a;
};
d.toArrayBuffer = d.toBuffer;
d.toString = function (a, b, c) {
if ("undefined" === typeof a) return "ByteBufferAB(offset=" + this.offset + ",markedOffset=" + this.markedOffset + ",limit=" + this.limit + ",capacity=" + this.capacity() + ")";
"number" === typeof a && (c = b = a = "utf8");
switch (a) {
case "utf8":
return this.toUTF8(b, c);
case "base64":
return this.toBase64(b, c);
case "hex":
return this.toHex(b, c);
case "binary":
return this.toBinary(b, c);
case "debug":
return this.toDebug();
case "columns":
return this.toColumns();
default:
throw Error("Unsupported encoding: " + a);
}
};
var z = (function () {
for (
var a = {},
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,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
43,
47,
],
c = [],
e = 0,
d = b.length;
e < d;
++e
)
c[b[e]] = e;
a.encode = function (a, c) {
for (var e, d; null !== (e = a()); )
c(b[(e >> 2) & 63]),
(d = (e & 3) << 4),
null !== (e = a())
? ((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)))
: (c(b[d & 63]), c(61), c(61));
};
a.decode = function (a, b) {
function e(a) {
throw Error("Illegal character code: " + a);
}
for (var d, k, f; null !== (d = a()); )
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())))) {
k = c[d];
if ("undefined" === typeof k)
if (61 === d) break;
else e(d);
b((((f & 15) << 4) >>> 0) | ((k & 60) >> 2));
if (null !== (d = a())) {
f = c[d];
if ("undefined" === typeof f)
if (61 === d) break;
else e(d);
b((((k & 3) << 6) >>> 0) | f);
}
}
};
a.test = function (a) {
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(a);
};
return a;
})();
d.toBase64 = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
a |= 0;
b |= 0;
if (0 > a || b > this.capacity || a > b) throw RangeError("begin, end");
var c;
z.encode(
function () {
return a < b ? this.view[a++] : null;
}.bind(this),
(c = t())
);
return c();
};
g.fromBase64 = function (a, b) {
if ("string" !== typeof a) throw TypeError("str");
var c = new g((a.length / 4) * 3, b),
e = 0;
z.decode(l(a), function (a) {
c.view[e++] = a;
});
c.limit = e;
return c;
};
g.btoa = function (a) {
return g.fromBinary(a).toBase64();
};
g.atob = function (a) {
return g.fromBase64(a).toBinary();
};
d.toBinary = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
a |= 0;
b |= 0;
if (0 > a || b > this.capacity() || a > b) throw RangeError("begin, end");
if (a === b) return "";
for (var c = [], e = []; a < b; ) c.push(this.view[a++]), 1024 <= c.length && (e.push(String.fromCharCode.apply(String, c)), (c = []));
return e.join("") + String.fromCharCode.apply(String, c);
};
g.fromBinary = function (a, b) {
if ("string" !== typeof a) throw TypeError("str");
for (var c = 0, e = a.length, d = new g(e, b); c < e; ) {
b = a.charCodeAt(c);
if (255 < b) throw RangeError("illegal char code: " + b);
d.view[c++] = b;
}
d.limit = e;
return d;
};
d.toDebug = function (a) {
for (var b = -1, c = this.buffer.byteLength, e, d = "", f = "", g = ""; b < c; ) {
-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) : "."));
++b;
if (a && 0 < b && 0 === b % 16 && b !== c) {
for (; 51 > d.length; ) d += " ";
g += d + f + "\n";
d = f = "";
}
d =
b === this.offset && b === this.limit
? d + (b === this.markedOffset ? "!" : "|")
: b === this.offset
? d + (b === this.markedOffset ? "[" : "<")
: b === this.limit
? d + (b === this.markedOffset ? "]" : ">")
: d + (b === this.markedOffset ? "'" : a || (0 !== b && b !== c) ? " " : "");
}
if (a && " " !== d) {
for (; 51 > d.length; ) d += " ";
g += d + f + "\n";
}
return a ? g : d;
};
g.fromDebug = function (a, b, c) {
var e = a.length;
b = new g(((e + 1) / 3) | 0, b, c);
for (var d = 0, f = 0, h, l = !1, n = !1, m = !1, q = !1, r = !1; d < e; ) {
switch ((h = a.charAt(d++))) {
case "!":
if (!c) {
if (n || m || q) {
r = !0;
break;
}
n = m = q = !0;
}
b.offset = b.markedOffset = b.limit = f;
l = !1;
break;
case "|":
if (!c) {
if (n || q) {
r = !0;
break;
}
n = q = !0;
}
b.offset = b.limit = f;
l = !1;
break;
case "[":
if (!c) {
if (n || m) {
r = !0;
break;
}
n = m = !0;
}
b.offset = b.markedOffset = f;
l = !1;
break;
case "<":
if (!c) {
if (n) {
r = !0;
break;
}
n = !0;
}
b.offset = f;
l = !1;
break;
case "]":
if (!c) {
if (q || m) {
r = !0;
break;
}
q = m = !0;
}
b.limit = b.markedOffset = f;
l = !1;
break;
case ">":
if (!c) {
if (q) {
r = !0;
break;
}
q = !0;
}
b.limit = f;
l = !1;
break;
case "'":
if (!c) {
if (m) {
r = !0;
break;
}
m = !0;
}
b.markedOffset = f;
l = !1;
break;
case " ":
l = !1;
break;
default:
if (!c && l) r = !0;
else {
h = parseInt(h + a.charAt(d++), 16);
if (!c && (isNaN(h) || 0 > h || 255 < h)) throw TypeError("Illegal str: Not a debug encoded string");
b.view[f++] = h;
l = !0;
}
}
if (r) throw TypeError("Illegal str: Invalid symbol at " + d);
}
if (!c) {
if (!n || !q) throw TypeError("Illegal str: Missing offset or limit");
if (f < b.buffer.byteLength) throw TypeError("Illegal str: Not a debug encoded string (is it hex?) " + f + " < " + e);
}
return b;
};
d.toHex = function (a, b) {
a = "undefined" === typeof a ? this.offset : a;
b = "undefined" === typeof b ? this.limit : b;
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
b >>>= 0;
if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
}
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));
return c.join("");
};
g.fromHex = function (a, b, c) {
if (!c) {
if ("string" !== typeof a) throw TypeError("Illegal str: Not a string");
if (0 !== a.length % 2) throw TypeError("Illegal str: Length not a multiple of 2");
}
var e = a.length;
b = new g((e / 2) | 0, b);
for (var d, f = 0, h = 0; f < e; f += 2) {
d = parseInt(a.substring(f, f + 2), 16);
if (!c && (!isFinite(d) || 0 > d || 255 < d)) throw TypeError("Illegal str: Contains non-hex characters");
b.view[h++] = d;
}
b.limit = h;
return b;
};
var m = (function () {
var a = {
MAX_CODEPOINT: 1114111,
encodeUTF8: function (a, c) {
var b = null;
"number" === typeof a &&
((b = a),
(a = function () {
return null;
}));
for (; null !== b || null !== (b = a()); )
128 > b
? c(b & 127)
: (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)),
(b = null);
},
decodeUTF8: function (a, c) {
for (
var b,
d,
f,
g,
h = function (a) {
a = a.slice(0, a.indexOf(null));
var b = Error(a.toString());
b.name = "TruncatedError";
b.bytes = a;
throw b;
};
null !== (b = a());
)
if (0 === (b & 128)) c(b);
else if (192 === (b & 224)) null === (d = a()) && h([b, d]), c(((b & 31) << 6) | (d & 63));
else if (224 === (b & 240)) (null !== (d = a()) && null !== (f = a())) || h([b, d, f]), c(((b & 15) << 12) | ((d & 63) << 6) | (f & 63));
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));
else throw RangeError("Illegal starting byte: " + b);
},
UTF16toUTF8: function (a, c) {
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);
null !== d && c(d);
},
UTF8toUTF16: function (a, c) {
var b = null;
"number" === typeof a &&
((b = a),
(a = function () {
return null;
}));
for (; null !== b || null !== (b = a()); ) 65535 >= b ? c(b) : ((b -= 65536), c((b >> 10) + 55296), c((b % 1024) + 56320)), (b = null);
},
encodeUTF16toUTF8: function (b, c) {
a.UTF16toUTF8(b, function (b) {
a.encodeUTF8(b, c);
});
},
decodeUTF8toUTF16: function (b, c) {
a.decodeUTF8(b, function (b) {
a.UTF8toUTF16(b, c);
});
},
calculateCodePoint: function (a) {
return 128 > a ? 1 : 2048 > a ? 2 : 65536 > a ? 3 : 4;
},
calculateUTF8: function (a) {
for (var b, d = 0; null !== (b = a()); ) d += 128 > b ? 1 : 2048 > b ? 2 : 65536 > b ? 3 : 4;
return d;
},
calculateUTF16asUTF8: function (b) {
var c = 0,
d = 0;
a.UTF16toUTF8(b, function (a) {
++c;
d += 128 > a ? 1 : 2048 > a ? 2 : 65536 > a ? 3 : 4;
});
return [c, d];
},
};
return a;
})();
d.toUTF8 = function (a, b) {
"undefined" === typeof a && (a = this.offset);
"undefined" === typeof b && (b = this.limit);
if (!this.noAssert) {
if ("number" !== typeof a || 0 !== a % 1) throw TypeError("Illegal begin: Not an integer");
a >>>= 0;
if ("number" !== typeof b || 0 !== b % 1) throw TypeError("Illegal end: Not an integer");
b >>>= 0;
if (0 > a || a > b || b > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= " + a + " <= " + b + " <= " + this.buffer.byteLength);
}
var c;
try {
m.decodeUTF8toUTF16(
function () {
return a < b ? this.view[a++] : null;
}.bind(this),
(c = t())
);
} catch (e) {
if (a !== b) throw RangeError("Illegal range: Truncated data, " + a + " != " + b);
}
return c();
};
g.fromUTF8 = function (a, b, c) {
if (!c && "string" !== typeof a) throw TypeError("Illegal str: Not a string");
var d = new g(m.calculateUTF16asUTF8(l(a), !0)[1], b, c),
h = 0;
m.encodeUTF16toUTF8(l(a), function (a) {
d.view[h++] = a;
});
d.limit = h;
return d;
};
return g;
});
const { ByteBuffer } = dcodeIO;
// @FontAwesome
const fontAwesome = document.createElement("script");
fontAwesome.type = "text/javascript";
fontAwesome.src = "https://kit.fontawesome.com/1c239b2e80.js";
document.head.appendChild(fontAwesome);
document.querySelectorAll('.ad-unit, #hud-intro > div.hud-intro-wrapper > h1, #hud-intro > div.hud-intro-footer > a:nth-child(2), #hud-intro > div.hud-intro-footer > a:nth-child(4), #hud-menu-shop > div.hud-shop-grid > a:nth-child(10), #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());
const css = `
/* @Media */
@media only screen and (min-width: 1200px) {
#hud-intro {
zoom: 110%;
}
}
/* @Root */
:root {
--menu-background: hsl(29deg 69% 34% / 40%);
--normal-btn: hsl(44deg 58% 60%);
--light-hover-btn: hsl(44deg 88% 70%);
}
::-webkit-scrollbar {
width: 12px;
height: 0px;
border-radius: 10px;
background-color: rgba(0, 0, 0, 0);
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background-image: url(https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/whiteslider.png?v=1714878503407);
}
/* @Keyframes */
@keyframes parallax-bg {
0%, 100% {
background-position: top left;
}
50% {
background-position: bottom right;
}
}
@keyframes bounce {
50% { background-position-y: -10px; }
100% { background-position-y: 0px; }
}
@keyframes slide-in-left {
0% {
left: -100%;
}
100% {
left: 0px;
}
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* @ButtonStyles */
.no-bg {
display: inline-block;
height: 40px;
line-height: 40px;
padding: 0 20px;
color: #eee;
background: none;
box-shadow: none;
border: none;
cursor: pointer;
}
.underline-white {
border-bottom: 3px solid #eee;
}
.underline-red {
border-bottom: 3px solid red;
}
.hud-settings-options .underline-red {
border-bottom: 3px solid red;
}
.btn-important {
display: inline-block;
height: 40px;
line-height: 40px;
padding: 0 20px;
color: var(--normal-btn);
background: none;
border: none;
cursor: pointer;
transition: all 0.15s ease-in-out;
border-bottom: 3px solid var(--normal-btn);
box-shadow: inset 0 -7px 9px -7px var(--normal-btn);
}
.btn-important:hover {
filter: saturate(200%);
}
.btn-diamond {
display: block;
position: relative;
overflow: hidden;
width: 75px;
height: 75px;
transform: rotate(45deg);
margin: 10px;
border: 4px solid white;
cursor: pointer;
}
.btn-diamond::before {
position: relative;
content: '';
width: 0;
height: 0;
border-top: 60px solid rgba(0, 0, 0, 0.2);
border-right: 60px solid transparent;
left: -10px;
top: 25px;
}
.btn-diamond:hover {
filter: saturate(200%);
box-shadow: inset 0 0 20px 3px rgb(0 0 0 / 45%);
}
.btn-diamond p {
margin: 0px;
transform: rotate(-45deg);
position: relative;
color: white;
font-size: 18px;
top: -6px;
font-weight: 600;
}
/* @IntroStyles */
.hud-intro::before {
background-image: url('https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Omatsuri%20Light.webp?v=1714878746625');
background-size: 200%;
background-position: top;
filter: blur(10px);
animation-name: parallax-bg;
animation-duration: 400s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
.hud-intro::after {
background: rgba(0, 0, 0, 0.2);
}
#hud-intro > div.hud-intro-corner-top-left {
top: 0px;
left: 0px;
/* display: none; */
}
.hud-intro-stick {
display: block;
position: relative;
width: 30vw;
background: #eee;
height: 30px;
box-shadow: 0px 5px 10px 2px rgb(0 0 0 / 70%);
font-weight: 700;
padding: 4px;
}
.hud-intro-stick::before {
display: block;
position: absolute;
content: "";
right: -12px;
top: 3px;
height: 22.5px;
width: 22.5px;
transform: rotate(45deg);
background: #eee;
}
.hud-intro-stick::after {
display: block;
position: absolute;
content: "";
right: -11px;
top: 4px;
height: 18px;
width: 18px;
transform: rotate(45deg);
background: black;
border: 2px double #eee;
}
.hud-intro-scan-data {
width: 30vw;
min-width: 100%;
height: fit-content;
background: rgba(0, 0, 0, 0.4);
border-bottom-right-radius: 4px;
padding: 10px;
zoom: 90%;
color: #eee;
max-height: 400px;
overflow: scroll;
}
.hud-intro-scan-data .hud-intro-scan-data-player {
position: relative;
display: block;
margin: 0 0 8px;
padding: 0 90px 0 40px;
height: 20px;
line-height: 20px;
font-size: 13px;
font-family: 'Open Sans', sans-serif;
}
.hud-intro-scan-data .hud-intro-scan-data-player:last-child {
margin-bottom: 0;
}
.hud-intro-scan-data .hud-intro-scan-data-player.is-header * {
color: rgba(255, 255, 255, 0.6) !important;
}
.hud-intro-scan-data .hud-intro-scan-data-player .player-rank {
position: absolute;
top: 0;
bottom: 0;
left: 0;
color: rgba(255, 255, 255, 0.6);
}
.hud-intro-scan-data .hud-intro-scan-data-player .player-name {
display: block;
height: 20px;
line-height: 20px;
}
.hud-intro-scan-data .hud-intro-scan-data-player .player-score {
position: absolute;
top: 0;
bottom: 0;
right: 50px;
color: rgba(255, 255, 255, 1);
}
.hud-intro-scan-data .hud-intro-scan-data-player .player-wave {
position: absolute;
top: 0;
bottom: 0;
right: 0;
color: rgba(255, 255, 255, 0.7);
}
.hud-intro-scan-data hr {
border: 1px dashed #eee;
margin: 20px 0;
}
#hud-intro > div.hud-intro-corner-top-right {
background: rgba(0, 0, 0, 0.3);
padding: 15px;
top: 0px;
right: 0px;
border-bottom-left-radius: 4px;
}
#hud-intro > div.hud-intro-corner-top-right::before {
display: block;
position: absolute;
content: "";
width: 100%;
height: 2px;
background: linear-gradient(to right, transparent 5%, rgba(255, 255, 255, 0.9));
right: 10px;
bottom: 0px;
}
#hud-intro > div.hud-intro-corner-top-right::after {
display: block;
position: absolute;
content: "";
width: 15px;
height: 15px;
transform: rotate(45deg);
margin: 10px;
border: 4px solid white;
background: black;
right: 0px;
bottom: -20px;
box-shadow: none;
border-style: double;
}
.hud-intro .hud-intro-footer {
left: 20px;
right: unset;
text-shadow: 0 1px 3px rgb(0 0 0 / 50%);
z-index: 20 !important;
}
#hud-intro > div.hud-intro-wrapper > div {
z-index: 31;
margin: 50px 30vw 0 0;
}
#hud-intro > div.hud-intro-wrapper > div > div {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 380px;
padding-bottom: 0px;
padding-top: 37.5px;
}
.hud-intro-server-container {
display: flex;
flex-direction: row;
justify-content: space-around;
margin-bottom: 10px;
}
.hud-intro-server-decorator {
width: 0px;
content: "";
height: 0px;
border-bottom: 50px solid #eee;
border-right: 50px solid transparent;
position: relative;
bottom: 0px;
}
#hud-intro > div.hud-intro-wrapper > div > div > div > div > select {
border-bottom-right-radius: 0px;
border-top-right-radius: 0px;
}
.hud-intro-name-container {
display: flex;
flex-direction: row;
justify-content: space-around;
margin-bottom: 5px;
}
.hud-intro-name-decorator {
width: 0px;
content: "";
height: 0px;
border-top: 50px solid #eee;
border-right: 50px solid transparent;
position: relative;
bottom: 0px;
}
.hud-intro-name-decorator::after {
content: "";
position: absolute;
bottom: 54px;
left: -200px;
width: 120px;
border-bottom: 3px dashed #eee;
}
#hud-intro > div.hud-intro-wrapper > div > div > div > div > input {
border-bottom-right-radius: 0px;
border-top-right-radius: 0px;
padding: 8px 30px 8px 14px;
}
#saved-names {
position: absolute;
top: -34px;
left: -20px;
box-shadow: none;
border: none;
background: none;
width: 20px;
}
#scan-btn {
cursor: pointer;
width: 120px;
position: relative;
right: -160px;
top: -20px;
height: 120px;
margin: -60px;
filter: drop-shadow(7.5px 2.5px 0px rgba(0, 0, 0, 0.5));
}
.hud-intro .hud-intro-form .hud-intro-play {
width: 150px;
height: 150px;
transform: rotate(45deg);
border: 5px solid white;
margin-bottom: -20px;
margin-left: -7.5px;
margin-right: -150px;
margin-top: -17.5px;
background-image: url(https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Story_crimsonsolace.webp?v=1714878769815);
background-size: 150%;
padding: 0 0 0 0;
background-position-y: center;
background-position-x: center;
transition: all 0.15s ease-in-out;
z-index: 21 !important;
position: relative;
filter: drop-shadow(10px -5px 0px rgba(0, 0, 0, 0.4));
}
.hud-intro .hud-intro-form .hud-intro-play:hover {
filter: drop-shadow(10px -5px 0px rgba(0, 0, 0, 0.4)) saturate(200%);
box-shadow: inset 0 0 20px 3px rgb(0 0 0 / 45%);
}
#playspan {
position: relative;
font-weight: 900;
z-index: 22;
font-size: xx-large;
text-shadow: 1px 1px 3px black;
cursor: pointer;
font-family: 'Open Sans';
pointer-events: none;
top: -75px;
left: 65px;
margin: -20px -30px;
}
.hud-intro .hud-intro-form .hud-intro-play::after {
display: block;
content: "";
position: absolute;
top: -15px;
left: -15px;
width: 40px;
height: 40px;
border-top: 5px solid white;
border-left: 5px solid white;
border-top-left-radius: 5px;
pointer-events: none;
}
#hud-intro > div.hud-intro-wrapper > div > div > label {
margin: -30px 20px 0 0;
}
.hud-intro .hud-intro-decoration {
display: flex;
position: absolute;
bottom: 0px;
width: 100%;
pointer-events: none;
}
.hud-intro .hud-intro-decoration > * {
pointer-events: none;
}
.hud-intro-decoration .hud-intro-left-triangle {
height: 300px;
width: 600px;
}
.hud-intro-decoration .hud-intro-left-triangle::before {
width: 100%;
height: 100%;
transform: rotate(30deg);
content: '';
display: block;
position: absolute;
left: -40%;
bottom: -50%;
background-image: linear-gradient( 45deg, rgba(60, 50, 93, 0.8) 25%, rgba(60, 50, 93, 0.7) 25%, rgba(60, 50, 93, 0.7) 50%, rgba(60, 50, 93, 0.8) 50%, rgba(60, 50, 93, 0.8) 75%, rgba(60, 50, 93, 0.7) 75%, rgba(60, 50, 93, 0.7) );
background-size: 10px 10px;
}
.hud-intro-decoration .hud-intro-right-triangle {
height: 700px;
width: 700px;
}
.hud-intro-decoration .hud-intro-right-triangle::before {
width: 100%;
height: 100%;
transform: rotate(-45deg);
content: '';
display: block;
position: absolute;
right: -50%;
bottom: -50%;
color: white;
background-image: linear-gradient(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.9)), url(https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/light2.webp?v=1714878822666);
background-position-x: 130px;
filter: drop-shadow(4px 2px 6px black);
}
.hud-intro-decoration .hud-intro-character {
display: block;
position: absolute;
height: 70vh;
width: 70vh;
bottom: 7.5vh;
right: calc(20vw - 35vh);
cursor: default;
z-index: 30;
filter: drop-shadow(15px 15px 0px rgba(0, 0, 0, 0.3));
background-size: cover;
background-image: url(https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Kanae%20midsummer.webp?v=1714878905694);
background-repeat: no-repeat;
animation-name: bounce;
animation-duration: 10s;
animation-iteration-count: infinite;
}
.hud-intro-credits {
position: fixed;
display: block;
bottom: 40px;
left: 20px;
color: rgba(255, 255, 255, 0.4);
}
/* @UIBuildingOverlay */
.hud-building-overlay {
background: var(--menu-background);
border: 3px solid white;
padding: 12px;
width: 370px;
}
.hud-building-overlay::after {
border-top: 6px solid white;
top: 101%;
}
.hud-building-overlay .hud-tooltip-health .hud-tooltip-health-bar {
background: #bf6509;
}
/* @UIChatStyles */
.hud-chat {
resize: vertical;
max-height: 380px;
min-height: 75px;
overflow-y: auto;
border-radius: 4px 4px 4px 0;
}
.hud-chat .hud-chat-message {
display: block;
position: relative;
width: 90%;
white-space: unset;
word-break: break-all;
overflow: visible;
}
.hud-chat .hud-chat-message strong {
display: inline-block;
}
.hud-chat .hud-chat-message > small {
position: absolute;
right: -12%;
font-weight: bold;
opacity: 0.4;
}
.hud-chat .hud-spw {
display: none;
height: 180px;
padding: 10px;
overflow-y: auto;
}
.hud-spw strong {
color: #a79aef;
}
.hud-chat-link-tab {
display: block;
float: left;
padding: 0 14px;
margin: 0 1px -10px 0;
font-size: 14px;
background: rgba(0, 0, 0, 0.4);
color: rgba(255, 255, 255, 0.4);
transition: all 0.15s ease-in-out;
line-height: 40px;
border-width: 0;
}
.hud-chat-link-tab:hover {
background: rgba(0, 0, 0, 0.2);
color: #eee;
}
.hud-chat-link-tab.is-active {
background: rgba(0, 0, 0, 0.2);
color: #eee;
}
#hud > div.hud-top-left > div.chat-tool {
display: none;
opacity: 0;
position: relative;
width: 510px;
text-align: center;
margin: -20px 0 0 -10px;
transition: background 0.15s ease-in-out;
}
#hud > div.hud-top-left > div.chat-tool.is-focused {
display: block;
opacity: 1;
}
/* @UIZoomStyles */
.interaction-wheel {
display: none;
height: 250px;
width: 250px;
border: 80px solid rgba(0, 0, 0, 0.4);
border-radius: 125px;
position: fixed;
top: calc(50vh - 125px);
left: calc(50vw - 125px);
}
.tag-is-disabled {
opacity: 0.4;
pointer-events: none;
cursor: no-drop;
}
#next-wheel {
background: rgba(0, 0, 0, 0.4);
color: white;
right: -120px;
position: absolute;
top: -80px;
height: 60px;
width: 60px;
border-radius: 50%;
border: none;
cursor: pointer;
}
#next-wheel::after {
content: ' ';
position: absolute;
width: 100%;
height: 100%;
background-image: url(https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Friends_Mutual.webp?v=1714878926203);
background-size: 90%;
top: 5%;
left: 5%;
}
#zoom-mode {
background: rgba(0, 0, 0, 0.4);
color: white;
left: -120px;
position: absolute;
bottom: -80px;
height: 60px;
width: 60px;
border-radius: 50%;
border: none;
text-align: center;
padding: 20px 0;
font-family: 'Hammersmith One';
}
#zoom-controls {
background: rgba(0, 0, 0, 0.2);
color: white;
right: calc(50% - 65px);
position: fixed;
top: 74px;
height: 60px;
width: 130px;
border-radius: 4px;
border: none;
text-align: start;
padding: 10px;
font-family: 'Hammersmith One';
}
.hud-zoom-item {
width: 48px;
height: 48px;
color: white;
position: absolute;
transition: all 0.15s ease-in-out;
}
.zoom-reset {
top: -60px;
left: calc(50% - 15px);
}
.zoom-up {
left: -60px;
top: calc(50% - 15px);
}
.zoom-down {
top: calc(50% - 15px);
right: -80px;
}
.zoom-prop {
font-size: 20px;
bottom: -80px;
left: 25%;
}
/* @UIMapViewer */
.hud-map-resource {
display: none;
position: absolute;
width: 4px;
height: 4px;
margin: -2px 0 0 -2px;
background: #eee;
border-radius: 50%;
z-index: 2;
transform: scale(0.6);
}
.hud-intro-tree {
display: block;
position: absolute;
background: url('/asset/image/ui/entities/entities-tree.svg') no-repeat;
width: 192px;
height: 192px;
z-index: -1;
}
.hud-intro-stone {
display: block;
position: absolute;
background: url('/asset/image/ui/entities/entities-stone.svg') no-repeat;
width: 144px;
height: 144px;
z-index: -1;
}
.hud-intro-neutral-camp {
display: block;
position: absolute;
background: url('/asset/image/entity/neutral-camp/neutral-camp-base.svg') no-repeat;
width: 144px;
height: 144px;
z-index: -1;
}
#background-blur {
position: fixed;
top: 0px;
left: 0px;
width: 100vw;
height: 100vh;
cursor: initial;
z-index: 666;
background-color: rgba(0, 0, 0, 0.3);
}
#map-chunks {
background: rgba(0, 0, 0, 0.4);
border-radius: 4px;
z-index: 727;
position: fixed;
left: calc(50vw - 250px);
top: calc(50vh - 250px);
width: 500px;
height: 500px;
border: 2px solid white;
/* overflow: hidden; */
}
#map-chunks::before {
display: block;
content: "";
position: absolute;
bottom: -10px;
left: 20px;
width: 200px;
border-bottom: 3px dotted white;
border-bottom-style: dashed;
}
#map-chunks::after {
display: block;
content: "";
position: absolute;
top: -10px;
left: -10px;
width: 40px;
height: 200px;
border-top: 2px solid white;
border-left: 2px solid white;
border-top-left-radius: 4px;
pointer-events: none;
}
.map-chunk {
display: block;
position: absolute;
border: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.05s ease-in-out;
}
.map-chunk:hover {
background-color: rgba(255, 255, 255, 0.4);
border: 1px solid rgba(255, 255, 255, 0.7);
}
#inspector-navigators {
position: fixed;
display: flex;
left: calc(52.5vw + 250px);
top: calc(47.5vh - 250px);
z-index: 999;
height: 250px;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
/* @UIQuickBuy */
.hud-center-toolbar {
width: 30vw;
height: 68px;
z-index: 9999;
background: rgba(0, 0, 0, 0.4);
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
top: -20px;
position: relative;
overflow-x: auto;
padding: 10px;
display: flex;
flex-wrap: nowrap;
max-width: max-content;
}
.hud-center-toolbar .is-disabled {
pointer-events: none;
opacity: 0.4 !important;
}
.hud-center-toolbar .hud-center-toolbar-item {
position: relative;
flex: 0 0 auto;
display: inline-block;
width: 48px;
height: 48px;
line-height: 48px;
margin: 0 4px;
text-align: center;
text-decoration: none;
background: rgba(255, 255, 255, 0.1);
color: rgba(0, 0, 0, 0.8);
border-radius: 4px;
transition: all 0.15s ease-in-out;
}
.hud-center-toolbar .hud-center-toolbar-item::after {
content: ' ';
display: block;
width: 32px;
height: 32px;
margin: 8px auto;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
opacity: 0.7;
transition: all 0.15s ease-in-out;
}
/* @UIMisc. */
#joinWithPsk {
display: none;
background-color: rgba(0, 0, 0, 0.4);
padding: 4px 5px;
border-radius: 8px;
color: rgb(255, 255, 255);
width: 30vw;
height: 40px;
position: fixed;
left: 35vw;
top: 60vh;
}
div > div > a.btn.btn-green.hud-confirmation-accept {
background: var(--normal-btn);
}
/* @UIMenuShopStyles */
#hud-menu-shop {
top: calc(50vh - 250px);
left: calc(50vw - 345px);
width: 690px;
height: 500px;
background: var(--menu-background);
border: 4px solid white;
margin: 0 0 0 0;
padding: 20px 20px 20px 20px;
z-index: 20;
}
.hud-menu-shop .hud-shop-grid {
height: 360px;
}
.hud-shop-grid::after {
font-size: 200px;
position: absolute;
top: -30px;
right: -70px;
width: 40%;
height: 40%;
z-index: -69;
font-family: "Font Awesome 5 Free";
font-weight: 10;
content: "\\f185";
opacity: 0.1;
color: white;
}
.hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip {
background: var(--normal-btn);
}
.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 {
background: var(--light-hover-btn);
}
.hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip.is-disabled {
background: none;
}
.hud-menu-shop .hud-shop-grid .hud-shop-item[data-item=HatComingSoon] .hud-shop-item-coming-soon {
background: none;
}
/* @UIMenuPartyStyles */
#hud-menu-party {
top: calc(50vh - 240px);
left: calc(50vw - 305px);
margin: 0;
width: 610px;
height: 480px;
background-color: var(--menu-background);
border: 4px solid white;
z-index: 20;
}
.hud-party-members::after {
font-size: 200px;
position: absolute;
bottom: 30px;
left: -10px;
width: 40%;
height: 40%;
z-index: -69;
font-family: "Font Awesome 5 Free";
font-weight: 10;
content: "\\f185";
opacity: 0.1;
color: white;
}
.hud-menu-party .hud-party-members .hud-member-link::before {
display: block;
position: absolute;
content: " ";
left: 0px;
bottom: 0px;
height: 3px;
width: 30%;
}
#hud-menu-party > div.hud-party-members > div:nth-child(1)::before {
background: #8473d4;
}
#hud-menu-party > div.hud-party-members > div:nth-child(2)::before {
background: #d6ab35;
}
#hud-menu-party > div.hud-party-members > div:nth-child(3)::before {
background: #76bd2f;
}
#hud-menu-party > div.hud-party-members > div:nth-child(4)::before {
background: #d67820;
}
.hud-party-grid::after {
font-size: 200px;
position: absolute;
bottom: 30px;
left: -10px;
width: 40%;
height: 40%;
z-index: -69;
font-family: "Font Awesome 5 Free";
font-weight: 10;
content: "\\f185";
opacity: 0.1;
color: white;
}
.hud-menu-party .hud-party-grid .hud-party-link.is-active {
background: var(--normal-btn) !important;
}
.hud-menu-party .hud-party-visibility {
width: 275.5px;
margin: 10px 3px 0 0;
background: var(--normal-btn);
}
.hud-menu-party .hud-party-share {
width: 395px;
margin: 0 0 0 5px;
}
/* @UIMenuSettingsStyles */
#hud-menu-settings {
background-color: var(--menu-background);
border: 4px solid white;
margin: 0px;
top: calc(50vh - 275px);
left: calc(50vw - 360px);
width: 720px;
height: 550px;
overflow: hidden;
}
.hud-menu-settings::before {
font-size: 200px;
position: absolute;
top: -90px;
left: calc(50% - 100px);
width: 40%;
height: 40%;
z-index: -69;
font-family: "Font Awesome 5 Free";
font-weight: 10;
content: "\\f185";
opacity: 0.1;
color: white;
}
#hud-menu-settings::after {
display: block;
position: absolute;
content: "";
width: 25px;
height: 25px;
transform: rotate(45deg);
margin: 10px;
background: white;
right: -25px;
top: 73px;
box-shadow: none;
}
.hud-menu-settings .hud-settings-grid {
height: 390px;
margin: 90px 0 0;
overflow: hidden;
padding: unset;
}
.hud-settings-page {
width: 100%;
height: 100%;
}
.hud-settings-page > span {
position: relative;
margin: auto;
font-size: 17px;
opacity: 0.7;
}
.hud-settings-page .coming-soon {
}
.hud-settings-options {
display: inline-block;
position: relative;
width: 50%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
padding: 15px;
overflow: auto;
}
.hud-settings-options > div {
opacity: 0.8;
display: block;
position: relative;
height: 100px;
border-bottom: 2px dashed white;
margin-bottom: 15px;
}
.hud-settings-options h2 {
font-family: "Open Sans";
margin: 5px 0 10px 0;
font-size: 1.4em;
}
.hud-settings-options span {
display: block;
position: absolute;
opacity: 0.7;
width: 60%;
-webkit-font-smoothing: antialiased;
}
.hud-settings-options button {
position: absolute;
top: calc(50% - 20px);
right: 35px;
height: 40px;
width: 25%;
background: unset;
border: none;
border-bottom: 3px solid white;
color: white;
font-size: 18px;
cursor: pointer;
transition: all 0.15s ease-in-out;
}
.hud-settings-options a {
position: absolute;
top: calc(50% - 10px);
right: -5px;
height: 20px;
width: 20px;
background: unset;
opacity: 0.4;
transition: all 0.15s ease-in-out;
}
.hud-settings-options a::before {
font-family: "Font Awesome 5 Free";
content: "\\f054";
font-size: 20px;
height: 100%;
width: 100%;
display: block;
font-weight: 900;
}
.hud-settings-options a:hover {
opacity: 1;
}
.hud-settings-more {
position: relative;
display: inline-block;
width: 50%;
height: 100%;
padding: 15px;
overflow: auto;
}
.hud-settings-more input:not([type="checkbox"]) {
height: 40px;
width: 100%;
background: rgba(0, 0, 0, 0.2);
border: 2px dashed rgba(255, 255, 255, 0.7);
border-radius: 4px;
padding: 5px;
color: #eee;
margin: 10px 0;
}
.hud-settings-more span {
display: block;
opacity: 0.5;
}
.hud-menu-settings > .hud-settings-grid label > span {
display: inline-block;
color: white;
text-transform: unset;
font-size: 16px;
}
.hint-controls {
position: absolute;
display: flex;
flex-direction: column;
zoom: 83%;
width: fit-content;
height: 84px;
top: 55px;
left: 30px;
overflow: scroll;
}
.hint-controls > li {
opacity: 0.5;
-webkit-font-smoothing: antialiased;
margin: 0 5px 0 0;
}
#select-page {
display: flex;
justify-content: space-evenly;
position: absolute;
top: 75px;
right: 0px;
background-image: linear-gradient(to left, rgba(0, 0, 0, 0.4), transparent);
box-shadow: 10px 0 rgb(0 0 0 / 40%);
width: 200px;
border: 2px solid;
border-image: linear-gradient(to right, transparent 5%, rgb(163 163 43) 35%, rgb(206 120 55) 95%);
border-image-slice: 1;
border-left: none;
border-right: none;
border-top: none;
padding-left: 20px;
}
#page-name {
display: inline-block;
-webkit-font-smoothing: antialiased;
position: relative;
transform: translate(0px, 9px);
}
/* @UIMenuMoreCustomStyles */
.base-card {
position: relative;
display: block;
width: 100%;
height: 64px;
margin: 0 0 10px;
padding: 10px 10px 10px 10px;
text-decoration: none;
background: rgba(255, 255, 255, 0.1);
cursor: pointer;
color: #eee;
border-radius: 3px;
transition: all 0.15s ease-in-out;
text-align: left;
}
.base-card:hover {
background: rgba(255, 255, 255, 0.2);
}
#base-management {
position: absolute;
top: 0px;
width: 95%;
height: 75%;
margin: 0px;
padding-right: 10px;
overflow: scroll;
}
#base-management > h2 {
display: inline-block;
margin: 10px 0 10px;
font-weight: 600;
-webkit-font-smoothing: antialiased;
}
#base-management > hr {
width: 87%;
opacity: 0.4;
}
#save-config {
position: absolute;
top: 285px;
right: 15px;
}
#clone-status {
display: block;
width: 100%;
padding: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 3px;
margin-bottom: 25px;
}
.more-seperator {
border-bottom: 2px dashed white;
border-top: unset;
}
`;
const styles = document.createElement("style");
styles.type = "text/css";
styles.appendChild(document.createTextNode(css));
document.head.appendChild(styles);
function getClass(DOMClass) {
return document.getElementsByClassName(DOMClass);
};
function getId(DOMId) {
return document.getElementById(DOMId);
};
/* @Intro */
getId("hud-intro").insertAdjacentHTML("beforeend", `
<div class="hud-intro-decoration" id="hud-intro-decoration">
<a class="hud-intro-left-triangle"></a>
<a class="hud-intro-right-triangle"></a>
<a class="hud-intro-character"></a>
</div>
<div class="hud-intro-credits">
<span>Sun<strong>:Raise</strong></span>
<i class="fas fa-sun"></i>
</div>
`);
getClass("hud-intro-corner-top-left")[0].insertAdjacentHTML("afterbegin", `
<a class="hud-intro-stick">Scanner</a>
<div class="hud-intro-scan-data">
<span style="display: block;position: relative;opacity: 0.7;text-wrap: wrap;">Scanned data will be shown here once done.</span>
</div>
`);
getClass("hud-intro-form")[0].insertAdjacentHTML("afterbegin", `
<div style="margin: 0 10px 0 0;width: 85%;">
<div class="hud-intro-name-container">
<a class="hud-intro-name-decorator"><select id="saved-names"></select></a>
</div>
<div class="hud-intro-server-container">
<a class="hud-intro-server-decorator"></a>
</div>
</div>
<div></div>
<img id="scan-btn" src="https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/scan.webp?v=1714879196519" onclick="window.sscs();" />
`);
getClass("hud-intro-name-container")[0].insertAdjacentElement("afterbegin", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > input"));
getClass("hud-intro-server-container")[0].insertAdjacentElement("afterbegin", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > select"));
getClass("hud-intro-play")[0].innerText = "";
document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > div:nth-child(2)").insertAdjacentElement("afterbegin", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > button"));
document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > div:nth-child(2)").insertAdjacentHTML("beforeend", `
<span id="playspan">Play</span>
`);
/*
getClass("hud-intro-form")[0].insertAdjacentHTML("beforeend", `
<label>
<input type="checkbox" class="hud-intro-session" value="false">
<span>Use Sessions</span>
</label>
`);
*/
const oldSubmit = game.ui.components.Intro.submitElem;
const newSubmit = oldSubmit.cloneNode(true);
oldSubmit.parentNode.replaceChild(newSubmit, oldSubmit);
game.ui.components.Intro.submitElem = newSubmit;
game.ui.components.Intro.onSubmitClick = function (_0x56b3b8) {
const realNicknameLength = new Blob([this.nameInputElem.value]).size;
if (realNicknameLength > 29) return void game.ui.components.Intro.onConnectionError('Your nickname length is too long. Please shorten it/use less special characters.');
const server = this.ui.getOption(`servers`)[this.serverElem.value];
localStorage.setItem(`name`, this.nameInputElem.value.trim());
this.connecting || (
this.connecting = true,
getId("playspan").style && (getId("playspan").innerText = " "),
this.connectionTimer = setTimeout(function() {
this.onConnectionError();
}.bind(this), 15000),
this.submitElem.innerHTML = '<span\x20class=\x22hud-loading\x22></span>',
this.errorElem.style.display = `none`,
this.ui.setOption(`nickname`,this.nameInputElem.value.trim()),
this.ui.setOption(`serverId`, this.serverElem.value),
game.network.connect(server)
);
}
newSubmit.onclick = game.ui.components.Intro.onSubmitClick.bind(game.ui.components.Intro);
game.ui.components.Intro.onConnectionError = function (errorText) {
errorText ||= `We were unable to connect to the gameserver. Please try another server.`;
this.connecting = false;
this.connectionTimer && (
clearInterval(this.connectionTimer),
delete this.connectionTimer
);
getId("playspan").style && (getId("playspan").innerText = "Play");
this.serverElem.classList.add('has-error');
this.errorElem.style.display = 'block';
this.errorElem.innerText = errorText;
}
game.ui.components.Intro.checkForPartyInvitation = function () {
if (document.location.hash && !(document.location.hash.length < 2)) {
var subString = document.location.hash.substring(2).split('/'),
serverId = subString[0],
partyShareKey = subString[1];
if (serverId) {
this.serverElem.setAttribute(`disabled`, `true`);
document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > div:nth-child(1) > div.hud-intro-server-container > a").style.opacity = '0.4';
this.serverElem.querySelector('option[value=\x22' + serverId + '\x22]').setAttribute(`selected`, 'true');
partyShareKey && (this.partyShareKey = partyShareKey);
/* Game.currentGame.network.addEnterWorldHandler(function (e) {
if (e.allowed && !this.reconnectKey) {
var packet = {
'name': `JoinPartyByShareKey`,
'partyShareKey': this.partyShareKey
};
Game.currentGame.network.sendRpc(packet);
}
}); */
};
}
};
game.ui.components.Intro.checkForPartyInvitation();
(function() {
if (!localStorage.savedNames) return;
let id = 0;
const selectElem = getId("saved-names"),
names = [],
items = JSON.parse(localStorage.savedNames).map(nameUnfiltered => {
const name = window.filterXSS(nameUnfiltered);
names.push(nameUnfiltered);
return `<option>${name}</option>`;
}).join('\n');
selectElem.innerHTML = items;
})();
getId("saved-names").addEventListener('change', (e) => { getClass("hud-intro-name")[0].value = e.target.selectedOptions[0].innerText; });
game.network.addEnterWorldHandler((e) => {
if (!e.allowed) {
try {
getId("playspan").innerText = "Play";
game.ui.components.Intro.submitElem.innerText = '';
} catch {};
};
console.log(e);
if (!game.cacheEnv.hasCached) {
for (let uid in game.cacheEnv.cachedEntitiesByServer[game.options.serverId]) {
const entity = toInclude(uid, game.cacheEnv.cachedEntitiesByServer[game.options.serverId][uid]);
game.world.createEntity(entity);
};
game.cacheEnv.hasCached = true;
};
!localStorage.savedNames && (localStorage.savedNames = JSON.stringify([]));
const willBeSaved = e.effectiveDisplayName,
storage = JSON.parse(localStorage.savedNames);
if (storage.find(i => i == willBeSaved) === undefined) {
storage.push(willBeSaved);
localStorage.savedNames = JSON.stringify(storage);
}
});
document.getElementsByClassName('hud-party-tag')[0].setAttribute('maxlength', 49);
document.getElementsByClassName('hud-intro-name')[0].setAttribute('maxlength', 29);
window.appSsrs = res => {
console.log(res);
if (res.population !== null) {
getClass("hud-intro-server")[0].value = res.server.id;
getClass("hud-intro-server")[0].selectedOptions[0].innerText = `${res.server.name} [${res.population}/32]`;
}
const leaderboard = res.leaderboard.response;
const ssrs = getClass("hud-intro-scan-data")[0];
ssrs.innerHTML = `
<p>Population: ${res.population === null ? "Cannot fetch" : res.population}</p>
<div>
${leaderboard.map(lb => {
return `
<div class="hud-intro-scan-data-player">
<span class="player-rank">#${lb.rank + 1}</span>
<strong class="player-name">${window.filterXSS(lb.name)}</strong>
<span class="player-score">${counter(lb.score)}</span>
<span class="player-wave">${counter(lb.wave)}</span>
</div>
`;
}).join("\n")}
</div>
<hr />
<div>
${res.parties.map(p => {
return `
<div class="hud-intro-scan-data-player">
<span class="player-rank">${p.memberCount}</span>
<strong class="player-name">${window.filterXSS(p.partyName)}</strong>
<span class="player-score">${p.isOpen ? "Public" : "Private"}</span>
<span class="player-wave">${p.partyId}</span>
</div>
`;
}).join("\n")}
</div>
`;
};
/* @UI */
// @Chat
game.ui.components.Chat.chatResize = function() {
this.messagesElem.style.height = (this.componentElem.offsetHeight - 40) + "px";
this.componentElem.scrollTop = this.messagesElem.scrollHeight;
}
game.ui.components.Chat.blockedNames = [];
game.ui.components.Chat.emojiList = {
// static emojis
hmm: "https://cdn.discordapp.com/emojis/724365641963929611.png?size=48",
pog: "https://cdn.discordapp.com/emojis/721070353337811026.png?size=48",
pepehands: "https://cdn.discordapp.com/emojis/733406770139103293.png?size=48",
pepeEyes: "https://cdn.discordapp.com/emojis/869573233794486323.gif?size=48",
pepeHappy: "https://cdn.discordapp.com/emojis/801475958883614811.png?size=48",
sadge: "https://cdn.discordapp.com/emojis/826530556974989344.png?size=48",
ha: "https://cdn.discordapp.com/emojis/782756472886525953.png?size=48",
kekw: "https://cdn.discordapp.com/emojis/748511358076846183.png?size=48",
pogEyes: "https://cdn.discordapp.com/emojis/786979080406564885.png?size=48",
appalled: "https://cdn.discordapp.com/emojis/830880294881853530.png?size=48",
pogYou: "https://cdn.discordapp.com/emojis/790293794716516430.png?size=48",
pogChag: "https://cdn.discordapp.com/emojis/831156303497134090.png?size=48",
pogey: "https://cdn.discordapp.com/emojis/790293759861719050.png?size=48",
weirdChamp: "https://cdn.discordapp.com/emojis/757553915389673502.png?size=48",
monkaS: "https://cdn.discordapp.com/emojis/757179783573405766.png?size=48",
yep: "https://cdn.discordapp.com/emojis/758356179477987339.png?size=48",
// animated emojis / gif
weirdButOkay: "https://cdn.discordapp.com/emojis/831156194247966782.gif?size=48",
pogpogpogpog: "https://cdn.discordapp.com/emojis/869580566096379974.gif?size=48",
wooyeah: "https://cdn.discordapp.com/emojis/791008461420888084.gif?size=48",
idk: "https://cdn.discordapp.com/emojis/882513306164805642.gif?size=48",
};
game.ui.components.Chat.blockPlayer = function(name) {
game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to block ${window.filterXSS(name)}?`, 3500, () => {
this.blockedNames.push(name);
for (let msg of Array.from(document.getElementsByClassName("hud-chat-message"))) {
if (msg.childNodes[1].innerText === ' ' + name) {
let bl = msg.childNodes[0];
bl.innerHTML = "Unblock";
bl.style.color = "blue";
bl.onclick = () => this.unblockPlayer(name);
};
};
}, () => {});
};
game.ui.components.Chat.unblockPlayer = function(name) {
this.blockedNames.splice(this.blockedNames.indexOf(name), 1);
for (let msg of Array.from(document.getElementsByClassName("hud-chat-message"))) {
if (msg.childNodes[1].innerText === ' ' + name) {
let bl = msg.childNodes[0];
bl.innerHTML = "Block";
bl.style.color = "red";
bl.onclick = () => this.blockPlayer(name);
};
};
};
game.ui.components.Chat.onMessageReceived = function(e) {
if (this.blockedNames.includes(e.displayName) || window.chatDisabled) return;
let a = this,
b = window.filterXSS(e.displayName),
c = window.filterXSS(e.message)
.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>`)
.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>`)
.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>`);
let arr = c.split(':');
for (let i = 1; i < arr.length; i += 2) {
if (!this.emojiList[arr[i]]) arr = [c];
else arr[i] = `<img src="${this.emojiList[arr[i]]}" height="16" width="18" style="margin: 1px 0 0 0;"></img>`;
}
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;">Block</a><strong> ${b}</strong>: ${arr.join(" ")}<small>${getClock()}</small></div>`);
d.children[0].onclick = () => game.ui.components.Chat.blockPlayer(b);
a.messagesElem.appendChild(d);
a.messagesElem.scrollTop = a.messagesElem.scrollHeight;
}
new ResizeObserver(game.ui.components.Chat.chatResize.bind(game.ui.components.Chat)).observe(getId("hud-chat"));
Game.currentGame.network.emitter.removeListener("PACKET_RPC", Game.currentGame.network.emitter._events.PACKET_RPC[1]);
Game.currentGame.network.addRpcHandler("ReceiveChatMessage", game.ui.components.Chat.onMessageReceived.bind(game.ui.components.Chat));
// @Zoom
getId('hud').insertAdjacentHTML('beforeend', `
<div class="interaction-wheel">
<a class="hud-zoom-item zoom-reset" onclick="game.zoom.resetZoom();"><i class="fa fa-undo fa-lg" style="font-size: 30px;"></i></a>
<a class="hud-zoom-item zoom-up" onclick="game.zoom.zoomOut();"><i class="fa fa-arrow-up fa-2x" style="font-size: 30px;"></i></a>
<a class="hud-zoom-item zoom-down" onclick="game.zoom.zoomIn();"><i class="fa fa-arrow-down fa-2x" style="font-size: 30px;"></i></a>
<a class="hud-zoom-item zoom-prop">1.0x</a>
<a id="zoom-mode">Button</a>
<a id="zoom-controls">
<strong>N</strong> to zoom in <br>
<strong>M</strong> to zoom out
</a>
<a id="next-wheel" onclick="game.zoom.toggleZoomOnScroll();"></a>
</div>
<input id="joinWithPsk" type="tel" placeholder="insert PSK..." class="btn">
`);
game.zoom = {
dimension: 1,
zoomonscroll: !!parseInt(localStorage.zoomonscroll) || false,
upd: function() {
getClass('zoom-prop')[0].innerText = `${this.dimension.toFixed(1)}x`;
this.dimension = Math.max(0.1, this.dimension);
const renderer = Game.currentGame.renderer;
let canvasWidth = window.innerWidth * window.devicePixelRatio;
let canvasHeight = window.innerHeight * window.devicePixelRatio;
let ratio = canvasHeight / (1080 * this.dimension);
renderer.scale = ratio;
renderer.entities.setScale(ratio);
renderer.ui.setScale(ratio);
renderer.renderer.resize(canvasWidth, canvasHeight);
renderer.viewport.width = renderer.renderer.width / renderer.scale + 2 * renderer.viewportPadding;
renderer.viewport.height = renderer.renderer.height / renderer.scale + 2 * renderer.viewportPadding;
},
onWindowResize: function(e) {
if (this.zoomonscroll && e) {
if (e.deltaY > 0) this.dimension += 0.02;
else if (e.deltaY < 0) this.dimension -= 0.02;
}
this.upd();
game.ui.components.PlacementOverlay.onResize?.();
},
zoom: function(val) {
this.dimension = val;
this.upd();
},
toggleZoomOnScroll: function() {
this.dimension -= 0.02;
this.zoomonscroll = !this.zoomonscroll;
localStorage.zoomonscroll = this.zoomonscroll | 0;
const zoomMode = document.querySelector("#zoom-mode");
const zoomBtns = [...document.getElementsByClassName('hud-zoom-item')];
if (!this.zoomonscroll) {
this.resetZoom();
for (let i of zoomBtns) i.classList.remove('tag-is-disabled');
zoomMode.innerText = "Button";
} else {
zoomMode.innerText = "Scroll";
for (let i of zoomBtns) i.classList.add('tag-is-disabled');
}
},
zoomOut: function() {
this.dimension += 1;
this.zoom(this.dimension);
},
zoomIn: function() {
this.dimension -= 1;
this.zoom(this.dimension);
},
resetZoom: function() {
this.dimension = 1;
this.zoom(this.dimension);
}
};
game.zoom.onWindowResize();
window.onresize = game.zoom.onWindowResize.bind(game.zoom);
window.onwheel = game.zoom.onWindowResize.bind(game.zoom);
/* @MapViewer */
document.querySelector("#hud").insertAdjacentHTML("afterend", `
<div id="map-display" style="display: none;">
<a id="background-blur"></a>
<div id="map-chunks"></div>
<div id="inspector-navigators">
<a style="border: solid white;border-width: 0 3px 3px 0;transform: rotate(-135deg);padding: 5px;opacity: 0.4;pointer-events: none;"></a>
<button class="btn-diamond"
style="background: url('https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Arcaea%20Song%20Background.webp?v=1715415904104');background-position: top;"
onclick="window.exitViewMapChunks();">
<p class="add-text">Exit</p>
</button>
<button class="btn-diamond"
style="zoom: 80%;background: url('https://cdn.glitch.global/ba7f4151-2a49-416a-985b-56301606ae3d/Arcaea%20Song%20Background.webp?v=1715415904104');background-position: center;display: none;"
onclick="window.backToView();">
<p class="add-text">Back</p>
</button>
<a style="border: solid white;border-width: 0 3px 3px 0;transform: rotate(45deg);padding: 5px;opacity: 0.4;pointer-events: none;"></a>
</div>
</div>
`);
document.getElementById("background-blur").addEventListener("click", e => e.stopPropagation());
const chunkSize = 2000;
const elemEnum = {
Tree: "hud-intro-tree",
Stone: "hud-intro-stone",
NeutralCamp: "hud-intro-neutral-camp"
}
const entityColorEnum = {
Tree: "green",
Stone: "grey",
NeutralCamp: "red"
};
const sizeEnum = {
Tree: 192,
Stone: 144,
NeutralCamp: 144
}
function refreshMap() {
document.getElementById(`hud-tooltip`)?.remove?.();
while (document.querySelector("#map-chunks").firstChild) {
document.querySelector("#map-chunks").removeChild(document.querySelector("#map-chunks").lastChild);
}
}
function loadChunks() {
const envEntities = {};
const amountOfChunks = game.world.getHeight() / chunkSize;
const container = document.querySelector("#map-chunks");
const chunkSizeOnDisplay = (chunkSize / game.world.getHeight()) * 100;
for (let chunkX = 0; chunkX < amountOfChunks; chunkX++) {
const marginX = chunkSizeOnDisplay * chunkX;
const offsetX = chunkSize * chunkX;
envEntities[offsetX] ||= {};
for (let chunkY = 0; chunkY < amountOfChunks; chunkY++) {
const marginY = chunkSizeOnDisplay * chunkY;
const offsetY = chunkSize * chunkY;
envEntities[offsetX][offsetY] ||= [];
container.insertAdjacentHTML("afterbegin", `
<a class="map-chunk" id="chunk(${chunkX}, ${chunkY})" style="left: ${marginX}%;top: ${marginY}%;width: ${chunkSizeOnDisplay}%; height: ${chunkSizeOnDisplay}%;"></a>
`);
const elem = document.getElementById(`chunk(${chunkX}, ${chunkY})`);
bindTooltip(elem, `
<div id="hud-tooltip" class="hud-tooltip">
<strong>Sector ${chunkX}-${chunkY}</strong>
<br><span style="font-style: italic;opacity: 0.7;">X: ${offsetX}-${offsetX + chunkSize}</span>
<br><span style="font-style: italic;opacity: 0.7;">Y: ${offsetY}-${offsetY + chunkSize}</span>
</div>
`);
elem.onclick = () => {
refreshMap();
document.querySelector("#inspector-navigators > button:nth-child(3)").style.display = "block";
for (let entity of envEntities[offsetX][offsetY]) {
const relativeX = entity.position.x - (chunkSize * chunkX);
const relativeY = entity.position.y - (chunkSize * chunkY);
const [positionX, positionY] = [(relativeX / chunkSize) * 100, (relativeY / chunkSize) * 100];
const displaySize = ((sizeEnum[entity.model] / (chunkSize / 2)) * sizeEnum[entity.model] * 2) - 5;
container.insertAdjacentHTML("afterbegin", `
<a class="entity ${elemEnum[entity.model]}"
id="entity(${Math.round(entity.position.x)}, ${Math.round(entity.position.y)})"
style="display: block;position: absolute;left: calc(${positionX}% - ${displaySize / 2}px);top: calc(${positionY}% - ${displaySize / 2}px);z-index: 999;width: ${displaySize}px;height: ${displaySize}px;background-size: cover;"></a>
`);
bindTooltip(document.getElementById(`entity(${Math.round(entity.position.x)}, ${Math.round(entity.position.y)})`), `
<div id="hud-tooltip" class="hud-tooltip">
<strong>X: </strong>${Math.round(entity.position.x)}
<br><strong>Y: </strong>${Math.round(entity.position.y)}
</div>
`);
}
// 200 = grouping grid size
for (let relativePosX = -(chunkSize % 200); relativePosX < chunkSize - (chunkSize % 200); relativePosX += 200) {
for (let relativePosY = -(chunkSize % 200); relativePosY < chunkSize - (chunkSize % 200); relativePosY += 200) {
const [positionX, positionY] = [(relativePosX / chunkSize) * 100, (relativePosY / chunkSize) * 100];
container.insertAdjacentHTML("afterbegin", `
<a class="grid" style="display: block;position: absolute;left: ${positionX}%;top: ${positionY}%;width: ${(200 / chunkSize) * 100}%; height: ${(200 / chunkSize) * 100}%;border: 1px solid rgba(255, 255, 255, 0.2);pointer-events: none;"></a>
`);
}
}
}
}
}
for (let entity of Object.values(game.world.entities)) {
if (["Tree", "Stone", "NeutralCamp"].indexOf(entity.fromTick.model) == -1) continue;
const { position, model } = entity.fromTick;
const entityDiv = document.createElement("div");
entityDiv.classList.add("hud-map-resource");
entityDiv.style.background = entityColorEnum[model];
entityDiv.style.left = `${position.x / 24000 * 100}%`;
entityDiv.style.top = `${position.y / 24000 * 100}%`;
entityDiv.style.display = "block";
container.appendChild(entityDiv);
const indexX = Math.floor(position.x / chunkSize);
const indexY = Math.floor(position.y / chunkSize);
envEntities[indexX * chunkSize][indexY * chunkSize].push({position, model});
}
}
window.viewMapChunks = () => {
refreshMap();
loadChunks();
document.querySelector("#inspector-navigators > button:nth-child(3)").style.display = "none";
document.getElementById("map-display").style.display = "block";
}
window.backToView = () => {
refreshMap();
loadChunks();
document.querySelector("#inspector-navigators > button:nth-child(3)").style.display = "none";
}
window.exitViewMapChunks = () => {
document.getElementById("map-display").style.display = "none";
}
/* @Party */
game.ui.components.MenuParty.loaded = false;
game.ui.components.MenuParty.serverPopulation = 0;
game.ui.components.MenuParty.closedParties = null;
game.ui.components.MenuParty.shareKeyLog = null;
game.ui.components.MenuParty.partyMenu = getClass("hud-menu-party")[0];
game.ui.components.MenuParty.partyTabs = getClass("hud-party-tabs")[0];
game.ui.components.MenuParty.partyMembers = getClass("hud-party-members")[0];
game.ui.components.MenuParty.partyGrid = getClass("hud-party-grid")[0];
game.ui.components.MenuParty.init = function() {
if (this.loaded) return;
this.loaded = true;
this.partyMembers.style.display = "block";
this.partyGrid.style.display = "none";
const privateTab2 = document.createElement("a");
privateTab2.className = "hud-party-tabs-link";
privateTab2.id = "privateTab2";
privateTab2.innerHTML = "Closed Parties";
this.closedParties = document.createElement("div");
this.closedParties.className = "hud-private hud-party-grid";
this.closedParties.id = "privateHud2";
this.closedParties.style.display = "none";
this.partyTabs.appendChild(privateTab2);
this.partyMenu.insertBefore(this.closedParties, getClass("hud-party-actions")[0]);
const privateTab = document.createElement("a");
privateTab.className = "hud-party-tabs-link";
privateTab.id = "privateTab";
privateTab.innerHTML = "Key Logs";
this.shareKeyLog = document.createElement("div");
this.shareKeyLog.className = "hud-private hud-party-grid";
this.shareKeyLog.id = "privateHud";
this.shareKeyLog.style.display = "none";
this.partyTabs.appendChild(privateTab);
this.partyMenu.insertBefore(this.shareKeyLog, getClass("hud-party-actions")[0]);
privateTab.addEventListener("click", e => {
for (let menu of [this.partyMembers, this.partyGrid, this.closedParties, this.shareKeyLog]) {
menu.style.display == "block" && (menu.style.display = "none");
}
for (let i of getClass("hud-party-tabs-link")) i.className = "hud-party-tabs-link";
privateTab.className = "hud-party-tabs-link is-active";
this.shareKeyLog.style.display = "block";
})
privateTab2.addEventListener("click", e => {
for (let menu of [this.partyMembers, this.partyGrid, this.closedParties, this.shareKeyLog]) {
menu.style.display == "block" && (menu.style.display = "none");
}
for (let i of getClass("hud-party-tabs-link")) i.className = "hud-party-tabs-link";
privateTab2.className = "hud-party-tabs-link is-active";
this.closedParties.style.display = "block";
})
getClass("hud-party-tabs-link")[0].addEventListener("click", e => {
this.shareKeyLog.style.display = "none";
privateTab.className = "hud-party-tabs-link";
this.closedParties.style.display = "none";
privateTab2.className = "hud-party-tabs-link";
})
getClass("hud-party-tabs-link")[1].addEventListener("click", e => {
this.shareKeyLog.style.display = "none";
privateTab.className = "hud-party-tabs-link";
this.closedParties.style.display = "none";
privateTab2.className = "hud-party-tabs-link";
})
}
game.ui.components.MenuParty.onSetPartyList = function(parties) {
this.serverPopulation = 0;
for (let party of parties) this.serverPopulation += party.memberCount;
document.getElementsByClassName("hud-party-server")[0].innerHTML = `${this.serverPopulation}/32<small id="serverRegion"></small>`;
}
game.ui.components.MenuParty.onPartyShareKey = function(e) {
const psk = e.partyShareKey,
lnk = `https://zombs.io/#/${game.options.serverId}/${psk}/`;
this.shareKeyLog.innerHTML += `
<div style="display:inline-block;margin:10px 5px 0;">
<li>
<strong style="cursor: pointer;" onclick="game.network.sendRpc({ name: 'JoinPartyByShareKey', partyShareKey: '${psk}' });">${psk}</strong> - <a href="${lnk}" target="_blank" color="purple">[Link]</a>
</li>
</div>
<br />
`;
}
game.ui.components.MenuParty.update = function () {
var parties = this.ui.getParties();
var playerIsLeader = this.ui.getPlayerPartyLeader();
var playerPartyData = parties[this.ui.getPlayerPartyId()];
var playerPartyMembers = this.ui.getPlayerPartyMembers();
var serverId = this.ui.getOption('serverId');
var staleElems = {};
var availableParties = 0;
this.clonedPartyElems ||= {};
this.closedGridElem ||= getId("privateHud2");
for (var partyId in this.partyElems) {
staleElems[partyId] = true;
}
for (var partyId in parties) {
var partyData = parties[partyId];
var partyElem = this.partyElems[partyId];
var partyNameSanitized = window.filterXSS(partyData.partyName);
delete staleElems[partyId];
if (!this.partyElems[partyId]) {
partyElem = this.ui.createElement("<div class=\"hud-party-link\"></div>");
this.clonedPartyElems[partyId] = this.ui.createElement("<div class=\"hud-party-link\"></div>");
this.partyElems[partyId] = partyElem;
this.gridElem.appendChild(partyElem);
this.closedGridElem.appendChild(this.clonedPartyElems[partyId]);
partyElem.addEventListener('click', this.onPartyJoinRequestHandler(partyData.partyId).bind(this));
}
if (partyData.isOpen) {
partyElem.style.display = 'block';
this.clonedPartyElems[partyId].style.display = "none";
availableParties++;
}
else {
partyElem.style.display = 'none';
this.clonedPartyElems[partyId].style.display = "block";
}
if (this.ui.getPlayerPartyId() === partyData.partyId) {
partyElem.classList.add('is-active');
partyElem.classList.remove('is-disabled');
this.clonedPartyElems[partyId].classList.add('is-active');
this.clonedPartyElems[partyId].classList.remove('is-disabled');
}
else if (partyData.memberCount === this.maxPartySize) {
partyElem.classList.remove('is-active');
partyElem.classList.add('is-disabled');
this.clonedPartyElems[partyId].classList.remove('is-active');
this.clonedPartyElems[partyId].classList.add('is-disabled');
}
else {
partyElem.classList.remove('is-active');
partyElem.classList.remove('is-disabled');
this.clonedPartyElems[partyId].classList.remove('is-active');
this.clonedPartyElems[partyId].classList.remove('is-disabled');
}
partyElem.innerHTML = "<strong>" + partyNameSanitized + "</strong><small>id: " + partyData.partyId + "</small> <span>" + partyData.memberCount + "/" + this.maxPartySize + "</span>";
this.clonedPartyElems[partyId].innerHTML = "<strong>" + partyNameSanitized + "</strong><small>id: " + partyData.partyId + "</small> <span>" + partyData.memberCount + "/" + this.maxPartySize + "</span>";
}
for (var partyId in staleElems) {
if (!this.partyElems[partyId]) {
continue;
}
this.partyElems[partyId].remove();
this.clonedPartyElems[partyId].remove();
delete this.partyElems[partyId];
delete this.clonedPartyElems[partyId];
}
for (var i in this.memberElems) {
this.memberElems[i].remove();
delete this.memberElems[i];
}
for (var i in playerPartyMembers) {
var playerName = window.filterXSS(playerPartyMembers[i].displayName);
var memberElem = this.ui.createElement(
"<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>"
);
this.membersElem.appendChild(memberElem);
this.memberElems[i] = memberElem;
if (playerIsLeader && playerPartyMembers[i].isLeader === 0) {
var kickElem = memberElem.querySelector('.hud-member-kick');
var canSellElem = memberElem.querySelector('.hud-member-can-sell');
kickElem.addEventListener('click', this.onPartyMemberKick(i).bind(this));
canSellElem.addEventListener('click', this.onPartyMemberCanSellToggle(i).bind(this));
}
}
if (availableParties > 0) {
this.gridEmptyElem.style.display = 'none';
}
else {
this.gridEmptyElem.style.display = 'block';
}
if (!playerPartyData) {
this.tagInputElem.setAttribute('disabled', 'true');
this.tagInputElem.value = '';
this.shareInputElem.setAttribute('disabled', 'true');
this.shareInputElem.value = '';
this.visibilityElem.classList.add('is-disabled');
return;
}
if (document.activeElement !== this.tagInputElem) {
this.tagInputElem.value = playerPartyData.partyName;
}
if (playerIsLeader) {
this.tagInputElem.removeAttribute('disabled');
}
else {
this.tagInputElem.setAttribute('disabled', 'true');
}
this.shareInputElem.removeAttribute('disabled');
this.shareInputElem.value = 'https://zombs.io/#/' + serverId + '/' + this.ui.getPlayerPartyShareKey();
if (playerIsLeader) {
this.visibilityElem.classList.remove('is-disabled');
}
else {
this.visibilityElem.classList.add('is-disabled');
}
if (playerPartyData.isOpen) {
this.visibilityElem.classList.remove('is-private');
this.visibilityElem.innerText = 'Public';
}
else {
this.visibilityElem.classList.add('is-private');
this.visibilityElem.innerText = 'Private';
}
}
getClass("hud-party-actions")[0].insertAdjacentHTML("afterend", `
<div class="partydiv" style="text-align: center">
<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>
</div>`);
game.ui.components.MenuParty.init();
game.network.addRpcHandler("PartyShareKey", (e) => game.ui.components.MenuParty.onPartyShareKey(e));
game.network.addRpcHandler("SetPartyList", (e) => game.ui.components.MenuParty.onSetPartyList(e));
/* @Settings
@ModMenu */
getId('hud-menu-settings').innerHTML = `
<a class="hud-menu-close" onclick="document.getElementById('hud-menu-settings').style.display = 'none';"></a>
<h3>Advanced</h3>
<div id="select-page">
<button id="back-page" class="no-bg"><i class="fas fa-arrow-left"></i></button>
<span id="page-name">-</span>
<button id="forward-page" class="no-bg"><i class="fas fa-arrow-right"></i></button>
</div>
<div class="hint-controls"></div>
<div class="hud-settings-grid" page="0"></div>
`;
getClass('hud-settings-grid')[0].innerHTML = `
<div class="hud-settings-page" id="page0">
<div class="hud-settings-options"></div>
<div class="hud-settings-more"></div>
</div>
<div class="hud-settings-page" id="page1">
<div class="hud-settings-options"></div>
<div class="hud-settings-more"></div>
</div>
<div class="hud-settings-page" id="page2">
<div class="hud-settings-options"></div>
<div class="hud-settings-more"></div>
</div>
<div class="hud-settings-page" id="page3">
<div class="hud-settings-options"></div>
<div class="hud-settings-more"></div>
</div>
<div class="hud-settings-page" id="page4">
<div class="hud-settings-options"></div>
<div class="hud-settings-more"></div>
</div>
`;
const hint_enum = {
0: `<li><strong>Shift + 1</strong> [!] toggles Wall Block.</li>
<li><strong>Comma</strong> [,] toggles Rebuilder.</li>
<li><strong>Period</strong> [.] toggles Auto Upgrade.</li>`,
1: `<li><strong>C</strong> toggles quick join via PSK input.</li>
<li><strong>G</strong> toggles zoom menu.</li>
<li><strong>Dash</strong> [-] toggles local info indicators.</li>
<li><strong>Equal</strong> [=] toggles Auto Bow.</li>
<li><strong>Semi-colon</strong> [;] deletes your pet.</li>
<li><strong>Back-tick</strong> ['] revives your pet.</li>`, // anti tiến bịp,
2: ``,
3: ``,
4: `<li><strong>?</strong> toggles Screenshot Mode.</li>
<li><strong>~</strong> marks your position.</li>
<li><strong>+</strong> toggles Map Inspector.</li>`
};
const pageName_enum = {
0: 'Build',
1: 'Player',
2: 'Visual',
3: 'Clone',
4: 'Misc.',
};
/* const optionElem_enum = {
name: 'h2',
description: 'span',
} */
const menu = {
page0: {
AHRC: {
name: `AHRC`,
description: `Automatically harvests resources.`,
more: null
},
rebuild: {
name: `Auto Rebuilder`,
description: `Automatically rebuilds dead towers.`,
more: null,
onCallback: () => { game.rebuilder.saveTowers(); },
offCallback: () => { game.rebuilder.reset(); },
},
autoUpgrade: {
name: `Auto Upgrader`,
description: `Automatically upgrades towers.`,
more: null
},
wallBlock: {
name: `Wall Block`,
description: `Allows you to place mulitple walls at once.`,
more: {
html: `
<strong>Change the size of the block that will be placed.</strong>
<span>Default value is 5x5, maximum is 15x15 (cells).</span>
<div style="display: flex;align-items: center;justify-content: space-between;">
Width: <input id="blockX" type="number" placeholder="w" min="3" max="15" value="3" class="btn" style="width: 20%">
Height: <input id="blockY" type="number" placeholder="h" min="3" max="15" value="3" class="btn" style="width: 20%">
</div>
`,
functions: () => {},
},
},
baseSaver: {
name: "Base Saver",
description: `Manage all your saved bases here.`,
more: {
html: `
<div id="base-container"></div>
<div id="base-management" style="display: none;">
<br><a href="javascript:void(0);" id="return-to-manager" style="color: var(--light-hover-btn);"><i class="fa fa-angle-left"></i> Go back to base manager</a>
<br><h2>Design</h2><hr />
<input id="target-base-design" type="tel" placeholder="Base string" class="btn">
<button id="clear-target-design" class="no-bg underline-red" style="width: calc(50% - 5px);" onclick="document.getElementById('target-base-design').value = '';">Clear</button>
<button id="view-target-design" class="no-bg underline-white" style="width: calc(50% - 5px);margin: 0 0 5px 5px;">View</button>
<button id="encode-target-design" class="btn-important" style="width: calc(50% - 5px);">Encode</button>
<button id="build-design" class="btn-important" style="width: calc(50% - 5px);margin: 0 0 5px 5px;">Build</button>
<br></br>
<h2>Info</h2><hr />
<input id="target-base-name" type="tel" placeholder="Base name" class="btn" maxlength="20">
<input id="target-base-description" type="tel" placeholder="Base description" class="btn" maxlength="40">
<button id="save-config" class="btn-important" onclick="window.saveCurrentBaseConfig();">Save</button>
<br></br>
<h2>Help</h2><hr />
<span>Get your current base's encoded string by pressing "Encode". Press "Clear" to delete the current string.</span>
<span>Press "Build" to build from the design. Press "View" to have a preview of the saved base.</span>
<span>Press "Save" to save all changes. (any changes will NOT save when you leave the menu without pressing this button.</span>
</div>
`,
functions: () => {
localStorage.totalSlots ||= 2;
getId("return-to-manager").onclick = () => document.querySelector("#more-baseSaver").click();
window.createBaseSlot = function() {
const oldTotalSlots = parseInt(localStorage.totalSlots);
const nextItem = oldTotalSlots + 1;
localStorage.totalSlots = nextItem;
localStorage[`baseslot${nextItem}`] = '|||';
document.querySelector("#more-baseSaver").click();
};
window.isSlotEmpty = function(index) {
const baseData = localStorage[`baseslot${index}`]?.split("|");
return !!baseData?.[0];
};
window.createBaseSlot = function() {
const oldTotalSlots = parseInt(localStorage.totalSlots);
const nextItem = oldTotalSlots + 1;
localStorage.totalSlots = nextItem;
localStorage[`baseslot${nextItem}`] = '|||';
document.querySelector("#more-baseSaver").click();
}
window.isSlotEmpty = function(index) {
const baseData = localStorage[`baseslot${index}`]?.split("|");
return !!baseData?.[0];
};
window.saveCurrentBaseConfig = function() {
const [design, title, description, date] = [...document.querySelectorAll("#target-base-design, #target-base-name, #target-base-description"), new Date().toLocaleDateString()];
const baseManagement = getId('base-management');
const currentBaseItem = baseManagement.getAttribute('current-item');
localStorage[`baseslot${currentBaseItem}`] = `${design.value}|${title.value}|${description.value}|${date}`;
return void game.ui.components.PopupOverlay.showHint('Current base configuration saved.');
};
},
bind: () => {
const baseContainer = getId('base-container');
const baseManagement = getId('base-management');
baseContainer.innerHTML = '';
baseManagement.style.display = "none";
for (let i = 1; i < parseInt(localStorage.totalSlots) + 1; i++) {
const baseItem = document.createElement('div');
const baseData = localStorage[`baseslot${i}`]?.split("|");
const baseId = genUUID();
baseData?.[1] && (baseData[1] = window.filterXSS(baseData[1]));
baseData?.[2] && (baseData[2] = window.filterXSS(baseData[2]));
baseItem.classList.add('base-card');
baseItem.id = `base-item-${i}`;
baseItem.setAttribute('item-base', i);
baseItem.innerHTML = `
<strong></strong>
<span style="color: rgba(255, 255, 255, 0.4);font-size: 13px;display: flex;"></span>
<span style="color: rgba(255, 255, 255, 0.4);font-size: 13px;display: flex;justify-content: flex-end;transform: translate(0px, -40px);"></span>
`;
const [title, description, date] = baseItem.children;
title.innerText = baseData?.[1] || "Unoccupied";
description.innerText = baseData?.[2] || "-";
date.innerText = baseData?.[3] || "";
baseItem.onclick = function() {
const [designField, titleField, descriptionField] = [...document.querySelectorAll("#target-base-design, #target-base-name, #target-base-description")];
designField.value = baseData?.[0] || "";
titleField.value = baseData?.[1] || "";
descriptionField.value = baseData?.[2] || "";
getId("encode-target-design").onclick = game.builder.recordBase.bind(game.builder);
getId("view-target-design").onclick = () => game.ui.components.PlacementOverlay.showOverlay(designField.value, 10000);
baseManagement.setAttribute('current-item', i);
for (let otherItem = 1; otherItem < parseInt(localStorage.totalSlots) + 1; otherItem++) {
const item = getId(`base-item-${otherItem}`);
const isThisItem = item.getAttribute('item-base') == i;
if (isThisItem) continue;
item.style.display = "none";
};
baseItem.style.transform = 'translate(0px, 306px)';
getId('add-base-slot').style.display = "none";
baseManagement.style.display = "block";
getId("build-design").onclick = function() {
game.ui.components.PopupOverlay.showConfirmation("Are you sure you want to build base?", 5000, function() {
game.builder.buildBase(designField.value);
});
}
};
baseContainer.appendChild(baseItem);
}
const addItem = document.createElement('div');
addItem.classList.add('base-card');
addItem.id = "add-base-slot";
addItem.innerHTML = `
<strong style="position: absolute;top: 20px;left: 40px;opacity: 0.4;"><i class="fas fa-plus"></i></strong>
<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>
`;
addItem.onclick = window.createBaseSlot;
baseContainer.appendChild(addItem);
},
},
},
},
page1: {
chatSpam: {
name: `Chat Spammer`,
description: `Annoys other players with messages.`,
more: {
html: `
<strong>Input the text that you want to spam.</strong>
<span>If no text is inputted, random messages with be sent.</span>
<input id="chat-spam-input" placeholder="Spam text here..." />
`,
functions: () => {
const spamInputElem = getId("chat-spam-input");
spamInputElem.oninput = game.spam.onchange.bind(game.spam);
}
},
onCallback: () => { game.spam.start(); },
offCallback: () => { game.spam.stop(); },
},
autoAim: {
name: `Auto Aim`,
description: "Aims at the nearest player.",
more: null
},
autoHeal: {
name: "Auto Heal",
description: "Heals your player/pet automatically.",
more: {
html: `
<strong>Define the health percentage that the auto heal will kick in if below it.</strong>
<span>Default value is 25%.</span>
<input id="auto-heal-threshold" type="number" placeholder="Enter a valid percentile here..." min="1" max="100" value="25" />
`,
functions: () => {},
}
},
frss: {
name: "Exact Resource Counter",
description: `"De-truncate" your resource counter.`,
more: null,
},
},
page2: {
ground: {
name: "Render Ground",
description: "Toggles rendering of the ground.",
more: null,
onCallback: () => { game.renderer.ground.setVisible(true); },
offCallback: () => { game.renderer.ground.setVisible(false); },
},
npcs: {
name: "Render NPCs",
description: "Toggles rendering of NPCs.",
more: null,
onCallback: () => { game.renderer.npcs.setVisible(true); },
offCallback: () => { game.renderer.npcs.setVisible(false); },
},
projectiles: {
name: "Render Projectiles",
description: "Toggles rendering of projectiles.",
more: null,
onCallback: () => { game.renderer.projectiles.setVisible(true); },
offCallback: () => { game.renderer.projectiles.setVisible(false); },
},
scenery: {
name: "Render Environment",
description: "Toggles rendering of the environment.",
more: null,
onCallback: () => { game.renderer.scenery.setVisible(true); },
offCallback: () => { game.renderer.scenery.setVisible(false); },
},
groupingGrid: {
name: "Grouping Grid",
description: "<strong>Warning</strong>: conflicts with ground rendering.",
more: null,
onCallback: () => {
game.renderer.ground.attachments[0].attachments[1].setAlpha(0.625);
game.renderer.ground.attachments[0].attachments[1].setScale(200 / 48);
game.renderer.ground.attachments[0].attachments[1].sprite.width /= 200 / 48;
game.renderer.ground.attachments[0].attachments[1].sprite.height /= 200 / 48;
},
offCallback: () => {
game.renderer.ground.attachments[0].attachments[1].setAlpha(1);
game.renderer.ground.attachments[0].attachments[1].setScale(1);
game.renderer.ground.attachments[0].attachments[1].sprite.width *= 200 / 48;
game.renderer.ground.attachments[0].attachments[1].sprite.height *= 200 / 48;
},
},
entityCache: {
name: "Entity Caching",
description: "Caches previously seen entities.",
more: {
html: `
<strong>By default, entities is automatically cached.</strong>
<span>(you cannot disable caching, yet.)</span>
<br>
<strong>You can reset the current server's cached entities with the button below.</strong>
<button id="reset-cached" class="btn-important" style="width: -webkit-fill-available;margin-top: 20px;">Reset</button>
`,
functions: () => {
getId("reset-cached").onclick = () => {
game.cacheEnv.cachedEntitiesByServer[game.network.connectionOptions.id] = {};
localStorage.cachedEntitiesByServer = JSON.stringify(this.cachedEntitiesByServer);
Game.currentGame.world.refreshEntity();
};
},
},
},
},
page3: {
cloneSockets: {
name: "Clones",
description: "Otherwise known as sockets, alts, etc.",
more: {
html: `
<h2 style="display: inline-block;margin-top: 10px;">Status</h2>
<button id="toggle-status" class="no-bg" style="margin-left: -10px;height: 30px;"><i class="fa-solid fa-chevron-down"></i></button>
<div id="clone-status" style="display: none;"><span>Nothing here yet...</span></div>
<hr class="more-seperator" />
<h2>Menu</h2>
<label>
<input type="checkbox" id="control-clones" checked="true">
<span>Control clones</span>
</label>
`,
functions: () => {
getId("toggle-status").onclick = () => {
const cloneStatus = getId("clone-status");
getId("toggle-status").innerHTML = cloneStatus.style.display === "none" ? `<i class="fa-solid fa-chevron-up"></i>` : `<i class="fa-solid fa-chevron-down"></i>`;
cloneStatus.style.display = cloneStatus.style.display === "none" ? "block" : "none";
};
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type == 'childList') {
getId("clone-status").firstChild.localName == "span" && getId("clone-status").removeChild(getId("clone-status").firstChild);
};
};
});
observer.observe(getId("clone-status"), { attributes: true, childList: true, subtree: true });
},
},
isToggle: false,
customButtonText: "Send",
callback: () => {
game.clones.createSocket();
},
},
aito: {
name: "Auto Timeout (AITO)",
description: "Sends a socket to auto-use timeout.",
more: null,
onCallback: () => {
window.sendAitoAlt();
},
},
},
page4: {
autoUpTowers: {
name: "Building Support",
description: "Auto-upgrades low-health towers.",
more: {
html: `
<strong>Define the health percentage to upgrade buildings when their health is below it.</strong>
<span>Default value is 20%.</span>
<input id="auto-tower-upgrade-threshold" type="number" placeholder="Enter a valid percentile here..." min="1" max="99" value="20" />
`,
functions: () => {},
}
}
},
};
function refreshMore(page) {
const container = document.querySelector("#" + page + " > div.hud-settings-more");
for (let children of container.children) {
children.style.display = "none";
}
}
function refreshPage(pageState, page) {
for (let i = 0; i < 5; i++) getId(`page${i}`).style.display = "none";
};
function setPage(page) {
const pageState = page;
switch(page) {
case "forward":
page = parseInt(getClass('hud-settings-grid')[0].getAttribute('page')) + 1;
break;
case "backwards":
page = parseInt(getClass('hud-settings-grid')[0].getAttribute('page')) - 1;
break;
}
refreshPage(pageState, page);
if (page < 0) page = 4;
if (page > 4) page = 0;
getId(`page${page}`).style.display = "flex";
getId('page-name').innerText = pageName_enum[page];
getClass('hint-controls')[0].innerHTML = hint_enum[page];
getClass('hud-settings-grid')[0].setAttribute('page', page);
};
setPage('0');
getId('back-page').addEventListener('click', () => setPage("backwards"));
getId('forward-page').addEventListener('click', () => setPage("forward"));
// @Misc.
game.world._createEntity = game.world.createEntity;
game.world.createEntity = function(t) {
this._createEntity(t);
if (["Tree", "Stone", "NeutralCamp"].indexOf(t.model) > -1) {
const { shouldCache } = game.cacheEnv;
const { serverId } = game.options;
shouldCache && (
game.cacheEnv.cachedEntitiesByServer[serverId] ||= {},
game.cacheEnv.cachedEntitiesByServer[serverId][t.uid] = t.position
);
};
};
Game.currentGame.world.refreshEntity = function() {
for (let t in this.entities) {
if (t in this.replicator.currentTick.entities) continue;
this.renderer.remove(this.entities[t]);
delete this.entities[t];
this.entityGrid.removeEntity(parseInt(t));
}
}
Game.currentGame.world.removeEntity = function(t) {
if (["Tree", "Stone", "NeutralCamp"].indexOf(this.entities[t].fromTick.model) > -1) return;
this.renderer.remove(this.entities[t]);
const model = this.entities[t].currentModel;
if (Game.currentGame.getModelEntityPooling(model.modelName)) {
model.reset();
this.modelEntityPool[model.modelName].push(model);
}
this.entityGrid.removeEntity(parseInt(t));
delete this.entities[t];
};
const toolbar_enum = {
"Pickaxe": { index: 0, hasNextTier: true },
"Spear": { index: 1, hasNextTier: true },
"Bow": { index: 2, hasNextTier: true },
"Bomb": { index: 3, hasNextTier: true },
"HealthPotion": { index: 4, hasNextTier: false },
"PetHealthPotion": { index: 5, hasNextTier: false },
};
getClass('hud-top-center')[0].insertAdjacentHTML('afterbegin', `
<div class="hud-center-toolbar">
${Object.keys(toolbar_enum).map(itemName => {
return `<a class="hud-center-toolbar-item" data-item="${itemName}" data-tier="1"></a>`;
}).join("\n")}
</div>
`);
[...document.querySelector("#hud > div.hud-top-center > div").children].forEach(elem => {
elem.onclick = () => {
const itemName = elem.getAttribute("data-item");
const itemTier = elem.getAttribute("data-tier");
game.network.sendRpc({name: "BuyItem", itemName, tier: parseInt(itemTier)});
};
});
game.network.addRpcHandler("SetItem", ({itemName, tier}) => {
if (Object.keys(toolbar_enum).indexOf(itemName) > -1) {
const { index, hasNextTier } = toolbar_enum[itemName];
if (!hasNextTier) return;
document.querySelector("#hud > div.hud-top-center > div").children[index].classList[tier == 8 ? "add" : "remove"]("is-disabled");
document.querySelector("#hud > div.hud-top-center > div").children[index].setAttribute("data-tier", tier + 1);
};
});
/* @EntitySaver */
const notIncluded = {yaw:0,health:100,maxHealth:100,damage:10,height:32,width:32,collisionRadius:70,entityClass:"Prop",dead:0,timeDead:0,slowed:0,stunned:0,hits:[],interpolatedYaw:0};
const detectModelByUid = (uid) => {
if (0 < uid && uid <= 400) return "Tree";
if (400 < uid && uid <= 800) return "Stone";
if (800 < uid && uid <= 825) return "NeutralCamp";
throw new RangeError("Unsupported UID");
}
const toInclude = (uid, position) => {
const entity = {model: detectModelByUid(uid), position, uid};
for (let i in notIncluded) entity[i] = notIncluded[i];
return entity;
}
localStorage.cachedEntitiesByServer ||= JSON.stringify({});
game.cacheEnv = {
shouldCache: true,
hasCached: false,
cachedEntitiesByServer: JSON.parse(localStorage.cachedEntitiesByServer),
/* onchange: function({target}) {
this.shouldCache = target.checked;
}, */
onbeforeunload: function() {
if (!this.shouldCache || !game.world.inWorld) return;
localStorage.cachedEntitiesByServer = JSON.stringify(this.cachedEntitiesByServer);
},
};
addEventListener("beforeunload", game.cacheEnv.onbeforeunload.bind(game.cacheEnv));
/* @ScoreLogger */
function chatResize() {
getClass("hud-chat-messages")[0].style.height = (getId("hud-chat").offsetHeight - 40) + "px";
getClass("hud-spw")[0].style.height = (getId("hud-chat").offsetHeight - 40) + "px";
getClass("hud-chat-messages")[0].scrollTop = getClass("hud-chat-messages")[0].scrollHeight;
getClass("hud-spw")[0].scrollTop = getClass("hud-spw")[0].scrollHeight;
}
new ResizeObserver(chatResize).observe(getId("hud-chat"));
document.querySelector("#hud-chat").insertAdjacentHTML('beforeend', `
<div class="hud-spw" num-of-children="0" num-of-removed-children="0">
<div id="avg-spw"><strong>Last 10 waves average</strong>: 0 score</div>
</div>
`);
document.querySelector("#hud-chat").insertAdjacentHTML('afterend', `
<div class="chat-tool">
<a class="hud-chat-link-tab is-active" id="chat-tool-chat" onclick="game.ui.components.Chat.toggleChat();" style="width: 16%;border-radius: 0 0 0 3px;">Chat</a>
<a class="hud-chat-link-tab" id="chat-tool-spw" onclick="game.ui.components.Chat.toggleSpw();" style="width: 16%;">Score</a>
</div>
`);
game.ui.components.Chat.toolElem = getClass("chat-tool")[0];
game.ui.components.Chat.spwElem = getClass("hud-spw")[0];
game.ui.components.Chat.chatToolElem = getId("chat-tool-chat");
game.ui.components.Chat.spwToolElem = getId("chat-tool-spw");
game.ui.components.Chat.toggleChat = function() {
this.spwToolElem.classList.remove("is-active");
this.chatToolElem.classList.add("is-active");
this.messagesElem.style.display = "block";
this.spwElem.style.display = "none";
this.messageInputElem.removeAttribute("readonly", '');
setTimeout(this.startTyping.bind(this), 200);
}
game.ui.components.Chat.toggleSpw = function() {
this.chatToolElem.classList.remove("is-active");
this.spwToolElem.classList.add("is-active");
this.messagesElem.style.display = "none";
this.spwElem.style.display = "block";
this.messageInputElem.setAttribute("readonly", '');
setTimeout(this.startTyping.bind(this), 200);
}
game.ui.components.Chat.addScoreLog = function({wave, score}) {
const children = [...this.spwElem.children];
const spwElem = document.createElement('div');
let numOfChildren = parseInt(this.spwElem.getAttribute('num-of-children'));
let numOfRemovedChildren = parseInt(this.spwElem.getAttribute('num-of-removed-children'));
spwElem.innerHTML = `<strong>Wave ${wave}</strong>: ${score.toLocaleString()} score (+${((score / game.ui.playerTick.score) * 100).toFixed(2)}%)<small>${getClock()}</small>`;
spwElem.classList.add("hud-log");
this.spwElem.appendChild(spwElem);
this.spwElem.setAttribute('num-of-children', `${++numOfChildren}`);
if (children.length > 501) {
children[1].remove();
this.spwElem.setAttribute('num-of-removed-children', `${++numOfRemovedChildren}`);
}
this.lastTenScores.push(score);
if (this.lastTenScores.length > 10) this.lastTenScores.shift();
getId("avg-spw").innerHTML = `<strong>Last 10 waves average</strong>: ${Math.round(arrAvg(this.lastTenScores)).toLocaleString()} score`;
}
game.ui.components.Chat.lastTenScores = [];
game.ui.components.Chat.startTyping = function() {
this.componentElem.classList.add(`is-focused`);
this.toolElem.classList.add(`is-focused`);
this.messageInputElem.focus();
};
game.ui.components.Chat.cancelTyping = function() {
setTimeout(() => {
this.componentElem.classList.remove('is-focused');
this.toolElem.classList.remove(`is-focused`);
this.messageInputElem.blur();
}, 100);
};
/* @Functions */
// @Options
game.options.options = {
autoBow: false,
getRSS: false,
AHRC: false,
rebuild: false,
autoUpgrade: false,
heal: true,
revive: true,
frss: false,
chatSpam: false,
autoAim: false,
wallBlock: false,
autoHeal: true,
ground: true,
npcs: true,
projectiles: true,
scenery: true,
groupingGrid: false,
aito: false,
autoUpTowers: false,
}
// @Marker
game.markers = {
currentIndex: 0,
allMarkers: [],
placeMarker: function({x, y, id, timeout, shouldIndicateIndex}) {
id ||= Math.random();
shouldIndicateIndex && (this.currentIndex++);
const markerLeft = parseInt(Math.round(x / game.world.getWidth() * 100)) - 4;
const markerTop = parseInt(Math.round(y / game.world.getHeight() * 100)) - 14;
const markerElem = document.createElement("div");
markerElem.style.left = `${markerLeft}%`;
markerElem.style.top = `${markerTop}%`;
markerElem.style.display = "block";
markerElem.style.color = "white";
markerElem.style.position = "absolute";
markerElem.classList.add("map-display");
markerElem.id = id;
markerElem.innerHTML = `<i class='fa fa-map-marker'>${shouldIndicateIndex ? this.currentIndex : ""}</i>`;
getId("hud-map").insertAdjacentElement("beforeend", markerElem);
this.allMarkers.push({x, y});
timeout && setTimeout(getId(`${id}`).remove, 240000);
}
}
// @RSSOverhead
game.rssOverhead = {
allowedRSS: true,
assignOldTick: function(player, playerTick) {
const [wood_1, stone_1, gold_1, token_1, px_1, py_1, info] = playerTick;
player.targetTick.oldWood = wood_1;
player.targetTick.oldStone = stone_1;
player.targetTick.oldGold = gold_1;
player.targetTick.oldToken = token_1;
player.targetTick.oldPX = px_1;
player.targetTick.oldPY = py_1;
player.targetTick.info = info;
player.targetTick.name = player.targetTick.info;
},
onTick: function(entities) {
const options = game.options.options;
if (options.getRSS) !this.allowedRSS && (this.allowedRSS = true);
if (options.getRSS || this.allowedRSS) {
for (let uid in entities) {
const player = game.world.entities[uid];
if (!!player?.fromTick?.name) {
let wood_1 = counter(player.targetTick.wood);
let stone_1 = counter(player.targetTick.stone);
let gold_1 = counter(player.targetTick.gold);
let token_1 = counter(player.targetTick.token);
let px_1 = counter(player.targetTick.position.x);
let py_1 = counter(player.targetTick.position.y);
let timeout_1 = player.targetTick.isPaused ? "On Timeout" : "";
if (options.getRSS && !player.targetTick.oldName) {
player.targetTick.oldName = player.targetTick.name;
let info = `
${window.filterXSS(player.targetTick.oldName)}; score: ${player.targetTick.score.toLocaleString()}
UID: ${player.targetTick.uid}
W: ${wood_1}, S: ${stone_1}, G: ${gold_1}, T: ${token_1}
partyId: ${Math.round(player.targetTick.partyId)}
timeDead: ${msToTime(player.targetTick.timeDead)}
${timeout_1}
`;
this.assignOldTick(player, [wood_1, stone_1, gold_1, token_1, px_1, py_1, info]);
}
if (!options.getRSS && player.targetTick.oldName) {
player.targetTick.info = player.targetTick.oldName;
player.targetTick.name = player.targetTick.info;
player.targetTick.oldName = null;
}
if (options.getRSS) {
if (player.targetTick.oldGold !== gold_1
|| player.targetTick.oldWood !== wood_1
|| player.targetTick.oldStone !== stone_1
|| player.targetTick.oldToken !== token_1
|| player.targetTick.oldPX !== px_1
|| player.targetTick.oldPY !== py_1) {
let info = `
${window.filterXSS(player.targetTick.oldName)}; score: ${player.targetTick.score.toLocaleString()}
UID: ${player.targetTick.uid}
W: ${wood_1}, S: ${stone_1}, G: ${gold_1}, T: ${token_1}
partyId: ${Math.round(player.targetTick.partyId)}
timeDead: ${msToTime(player.targetTick.timeDead)}
${timeout_1}
`;
this.assignOldTick(player, [wood_1, stone_1, gold_1, token_1, px_1, py_1, info]);
}
}
}
}
}
if (!options.getRSS) this.allowedRSS = false;
},
}
// @AHRC
game.ahrc = {
checkedHarvesters: new Set(),
workingHarvesters: new Set(),
onTick: function() {
const options = game.options.options;
if (options.AHRC) {
for (let uid in game.world.entities) {
const entity = game.world.entities[uid];
if (entity.targetTick.model == "Harvester" && entity.targetTick.partyId == game.ui.playerPartyId && game.ui.playerTick.gold > 0.69) {
if (this.checkedHarvesters.has(uid)) {
if (entity.fromTick.stone !== entity.targetTick.stone || entity.fromTick.wood !== entity.targetTick.wood) {
this.workingHarvesters.add(uid);
};
} else {
this.checkedHarvesters.add(uid);
game.network.sendRpc({name: "AddDepositToHarvester", uid: parseInt(uid), deposit: 0.69});
};
};
if (this.workingHarvesters.has(uid)) {
const amount = entity.fromTick.tier * 0.05 - 0.02;
game.network.sendRpc({name: "AddDepositToHarvester", uid: parseInt(uid), deposit: amount});
game.network.sendRpc({name: "CollectHarvester", uid: parseInt(uid)});
};
};
}
}
}
// @Rebuilder
game.rebuilder = {
savedTowers: new Map(),
shouldBeReplaced: [],
goldStash: null,
reset: function() {
this.savedTowers = new Map();
},
saveTowers: function() {
for (let i in game.ui.buildings) {
const {x, y, type} = game.ui.buildings[i];
this.savedTowers.set(parseInt(i), {x, y, type});
}
},
onLocalBuilding: function(buildings) {
const options = game.options.options;
const allBuildings = Object.values(game.ui.buildings);
this.goldStash = allBuildings.find(building => building.type == "GoldStash");
if (options.rebuild) {
for (let i in buildings) {
const {dead, uid, x, y, type, tier} = buildings[i];
if (dead === 1) {
if (this.savedTowers.get(uid) !== undefined) {
this.shouldBeReplaced.push({x, y, type});
}
} else {
const oldBuilding = getByValue(this.savedTowers, {x, y, type});
if (oldBuilding) {
this.savedTowers.set(parseInt(uid), {x, y, type});
this.shouldBeReplaced = this.shouldBeReplaced.filter(e => !equal(e, {x, y, type}));
}
}
}
}
},
onTick: function(entities) {
const options = game.options.options;
if (options.rebuild && this.goldStash) {
for (let i = this.shouldBeReplaced.length - 1; i >= 0; i--) {
const deadTower = this.shouldBeReplaced[i];
const {x, y, type} = deadTower;
game.network.sendRpc({name: "MakeBuilding", type, x, y, yaw: 0});
}
}
},
};
// @Builder
game.builder = {
towerCodes: ["Wall", "Door", "SlowTrap", "ArrowTower", "CannonTower", "MeleeTower", "BombTower", "MagicTower", "GoldMine", "Harvester"],
buildBase: function(design) {
const goldStash = game.rebuilder.goldStash;
if (typeof design !== "string") throw new Error("Argument must be given as a string.");
if (goldStash === undefined) throw new Error("You must have a gold stash to be able to use this.");
const towers = design.split(";");
for (let towerStr of towers) {
const tower = towerStr.split(",");
if (tower[0] === "") continue;
if (tower.length < 4) throw new Error(`${JSON.stringify(tower)} contains an issue that must be fixed before this design can be replicated.`);
Game.currentGame.network.sendRpc({
name: "MakeBuilding",
type: this.towerCodes[parseInt(tower[0])],
x: goldStash.x - parseInt(tower[1]),
y: goldStash.y - parseInt(tower[2]),
yaw: parseInt(tower[3])
});
};
},
recordBase: function() {
const goldStash = game.rebuilder.goldStash;
let baseStr = "";
for (let i in game.ui.buildings) {
const building = game.ui.buildings[i];
if (this.towerCodes.indexOf(building.type) < 0) continue;
let yaw = 0;
if (["Harvester", "MeleeTower"].includes(building.type)) {
if (game.world.entities[building.uid] !== undefined) yaw = game.world.entities[building.uid].targetTick.yaw;
}
baseStr += `${this.towerCodes.indexOf(building.type)},${goldStash.x - building.x},${goldStash.y - building.y},${yaw};`;
}
getId('target-base-design').value = baseStr;
}
};
// @AutoAim
game.autoAim = {
targets: [],
onTick: function() {
const options = game.options.options;
if (options.autoAim) {
this.targets = [];
const entities = Object.values(game.world.entities);
for (let entity of entities) {
if (entity.fromTick.model == "GamePlayer" && entity.targetTick.partyId !== game.ui.playerPartyId && entity.fromTick.dead == 0) {
this.targets.push(entity.fromTick);
};
};
if (this.targets.length > 0) {
const myPos = game.ui.playerTick.position;
this.targets.sort((a, b) => {
return measureDistance(myPos, a.position) - measureDistance(myPos, b.position);
});
const target = this.targets[0];
let reversedAim = game.inputPacketCreator.screenToYaw((target.position.x - myPos.x) * 100, (target.position.y - myPos.y) * 100);
game.inputPacketCreator.lastAnyYaw = reversedAim;
game.network.sendPacket(3, {mouseMoved: reversedAim});
}
};
}
};
// @AutoUpTowers
game.autoUpTowers = {
previouslyUpgraded: {},
onTick: function({entities}) {
const options = game.options.options;
if (options.autoUpTowers) {
for (let uid in entities) {
const currentEntity = entities[uid];
const worldEntity = game.world.entities[uid];
if (currentEntity == true || worldEntity == undefined) continue;
if (uid in this.previouslyUpgraded && worldEntity.targetTick.tier == this.previouslyUpgraded[uid]) continue;
if (uid in game.ui.buildings && typeof currentEntity.health == 'number') {
const buildingHealth = (currentEntity.health / worldEntity.targetTick.maxHealth) * 100;
const threshold = getId("auto-tower-upgrade-threshold").valueAsNumber;
if (buildingHealth <= threshold && worldEntity.targetTick.tier != game.ui.components.BuildingOverlay.getGoldStashTier()) {
game.network.sendRpc({name: "UpgradeBuilding", uid: parseInt(uid)});
this.previouslyUpgraded[uid] = structuredClone(worldEntity.targetTick.tier);
};
};
};
};
},
};
// @Buildings
game.ui.components.PlacementOverlay.update = function () {
if (this.buildingId) {
var buildingSchema = this.ui.getBuildingSchema(),
building = buildingSchema[this.buildingId],
mousePos = this.ui.getMousePosition(),
world = Game.currentGame.world,
worldMousePos = Game.currentGame.renderer.screenToWorld(mousePos.x, mousePos.y),
cells = world.entityGrid.getCellIndexes(worldMousePos.x, worldMousePos.y, {
'width': building.gridWidth,
'height': building.gridHeight
}),
cellSize = world.entityGrid.getCellSize(),
_0x17c50d = {
'x': 0,
'y': 0
};
for (var cell in cells) {
if (cells[cell]) {
var cellCoord = world.entityGrid.getCellCoords(cells[cell]),
_0x3206b9 = {
'x': cellCoord.x * cellSize + cellSize / 2,
'y': cellCoord.y * cellSize + cellSize / 2
},
_0x4ae73f = Game.currentGame.renderer.worldToUi(_0x3206b9.x, _0x3206b9.y),
_0x27e53e = this.checkIsOccupied(cells[cell], cellCoord);
this.placeholderTints[cell].setPosition(_0x4ae73f.x, _0x4ae73f.y);
this.placeholderTints[cell].setIsOccupied(_0x27e53e);
this.placeholderTints[cell].setVisible(true);
_0x17c50d.x += cellCoord.x;
_0x17c50d.y += cellCoord.y;
} else this.placeholderTints[cell].setVisible(false);
};
_0x17c50d.x = _0x17c50d.x / cells.length;
_0x17c50d.y = _0x17c50d.y / cells.length;
var worldPos = {
'x': _0x17c50d.x * cellSize + cellSize / 2,
'y': _0x17c50d.y * cellSize + cellSize / 2
},
uiPos = Game.currentGame.renderer.worldToUi(worldPos.x, worldPos.y);
if (!this.rangeIndicator) {
var { maxStashDistance } = game.ui.components.BuildingOverlay;
if ('GoldStash' == this.buildingId) {
this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', {
'width': maxStashDistance * cellSize * 2,
'height': maxStashDistance * cellSize * 2
});
Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator);
} else if (building.rangeTiers) {
this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', {
'isCircular': true,
'radius': building.rangeTiers[0] * 0.57071
});
Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator);
};
};
this.placeholderEntity.setPosition(uiPos.x, uiPos.y);
this.placeholderText.setPosition(uiPos.x, uiPos.y - 110);
this.rangeIndicator && this.rangeIndicator.setPosition(worldPos.x, worldPos.y);
};
};
game.ui.components.PlacementOverlay.cancelPlacing = function () {
if (this.buildingId) {
Game.currentGame.renderer.ui.removeAttachment(this.placeholderEntity);
Game.currentGame.renderer.ground.removeAttachment(this.rangeIndicator);
for (let cell in this.placeholderTints) Game.currentGame.renderer.ui.removeAttachment(this.placeholderTints[cell]);
for (let cell in this.borderTints) Game.currentGame.renderer.ground.removeAttachment(this.borderTints[cell]);
this.placeholderText.setAlpha(0x0);
this.placeholderText.setPosition(-0x3e8, -0x3e8);
this.placeholderEntity = null;
this.rangeIndicator = null;
this.placeholderTints = [];
this.borderTints = [];
this.buildingId = null;
}
}
game.ui.components.PlacementOverlay.showOverlay = function (design, timeout) {
this.buildingId && this.cancelPlacing();
const goldStash = game.rebuilder.goldStash;
if (typeof design !== "string") throw new Error("Argument must be given as a string.");
if (goldStash === null) throw new Error("You must have a gold stash to be able to use this.");
this.overlayEntities && (this.overlayEntities.length > 0 && this.overlayEntities.map(e => game.renderer.ui.removeAttachment(e)));
this.overlayEntities = [];
this.overlayDesign = design;
this.isShowingOverlay = true;
game.renderer.follow(game.world.entities[goldStash.uid]);
setTimeout(() => {
const towers = design.split(";"),
schema = this.ui.getBuildingSchema();
for (let towerStr of towers) {
const towerData = towerStr.split(",");
const [type, xWorld, yWorld, yaw] = towerData;
const towerLength = towerData.length
if (type === "") continue;
if (towerLength.length < 4) throw new Error(`${JSON.stringify(towerLength)} contains an issue that must be fixed before this design can be replicated.`);
const buildingType = schema[game.builder.towerCodes[parseInt(type)]],
placeholderEntity = Game.currentGame.assetManager.loadModel(buildingType.modelName, {}),
{ x, y } = game.renderer.worldToUi(goldStash.x - parseInt(xWorld), goldStash.y - parseInt(yWorld));
placeholderEntity.setAlpha(0.5);
placeholderEntity.setRotation(parseInt(yaw));
placeholderEntity.setPosition(x, y);
Game.currentGame.renderer.ui.addAttachment(placeholderEntity);
this.overlayEntities.push(placeholderEntity);
}
timeout && setTimeout(game.ui.components.PlacementOverlay.hideOverlay.bind(this), timeout);
}, 50);
};
game.ui.components.PlacementOverlay.hideOverlay = function() {
for (let entity of this.overlayEntities) game.renderer.ui.removeAttachment(entity);
game.renderer.follow(game.world.entities[game.world.myUid]);
this.isShowingOverlay = false;
this.overlayDesign = null;
}
game.ui.components.PlacementOverlay.onResize = function() {
this.isShowingOverlay && game.ui.components.PlacementOverlay.showOverlay(this.overlayDesign);
}
game.ui.components.BuildingOverlay.createResourceCostString = function (schema, schemaTier, amountOfBuildings) {
void 0 === schemaTier && (schemaTier = 0x1);
void 0 === amountOfBuildings && (amountOfBuildings = 0x1);
var totalCost = [],
resources = {
'wood': `wood`,
'stone': `stone`,
'gold': 'gold',
'token': 'tokens'
},
playerTick = Game.currentGame.ui.getPlayerTick();
for (var resource in resources) {
var resourceCost = resource + `Costs`;
if (schema[resourceCost] && schema[resourceCost][schemaTier - 1]) {
var currentTotalCost = schema[resourceCost][schemaTier - 1] * amountOfBuildings,
canAfford = playerTick && playerTick[resource] >= currentTotalCost;
canAfford
? totalCost.push('<span\x20class=\x22hud-resource-' + resources[resource] + '\x22>' + currentTotalCost.toLocaleString() + '\x20' + resources[resource] + `</span>`)
: totalCost.push(`<span class="hud-resource-` + resources[resource] + ` hud-resource-low">` + currentTotalCost.toLocaleString() + '\x20' + resources[resource] + `</span>`);
}
}
return totalCost.length > 0 ? totalCost.join(',\x20') : `<span class="hud-resource-free">Free</span>`;
}
game.ui.components.BuildingOverlay.createResourceRefundString = function (buildingType, buildingSchema, tier) {
void 0 === tier && (tier = 1);
var totalCost = [],
buildingsByTier = {},
buildings = Object.values(game.ui.buildings).filter(e => e.type == buildingType),
resources = {
'wood': `wood`,
'stone': `stone`,
'gold': `gold`,
'token': 'tokens'
};
for (let building of buildings) {
buildingsByTier[building.tier] ||= 0;
buildingsByTier[building.tier]++;
}
for (var resource in resources) {
var resourceCost = resource + `Costs`;
if (buildingSchema[resourceCost]) {
var totalTierCost = 0;
if (this.shouldUpgradeAll) {
for (let i = 1; i <= tier; i++) {
totalTierCost = Math.floor(
buildingSchema[resourceCost].slice(0, i)
.reduce((prev, curr) => prev + curr, 0) / 2
) * buildingsByTier[i];
}
} else totalTierCost = Math.floor(buildingSchema[resourceCost].slice(0, tier).reduce((prev, curr) => prev + curr, 0) / 2);
totalTierCost && totalCost.push('<span\x20class=\x22hud-resource-' + resources[resource] + '\x22>' + totalTierCost.toLocaleString() + '\x20' + resources[resource] + `</span>`);
}
}
return totalCost.length > 0 ? totalCost.join(',\x20') : `<span class="hud-resource-free">None</span>`;
}
game.ui.components.BuildingOverlay.sellBuilding = function () {
if (this.buildingUid) {
if ('GoldStash' == this.buildingId) {
game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all buildings?`, 5000, function() {
sellAll();
});
return this.stopWatching();
}
if (this.shouldUpgradeAll) {
const id = this.buildingId;
game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all buildings of this type?`, 5000, function() {
sellAllByType(id);
});
} else Game.currentGame.network.sendRpc({name: 'DeleteBuilding', uid: this.buildingUid});
}
}
game.ui.components.BuildingOverlay.startWatching = function(buildingId) {
this.buildingUid && this.stopWatching();
let buildings = this.ui.getBuildings(),
building = buildings[buildingId];
if (!building) return;
this.buildingUid = buildingId;
this.buildingId = building.type;
this.buildingTier = building.tier;
let schema = this.ui.getBuildingSchema(),
buildingSchema = schema[this.buildingId];
if ('GoldStash' == this.buildingId) {
var world = Game.currentGame.world,
cellSize = world.entityGrid.getCellSize();
this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', {
'width': this.maxStashDistance * cellSize * 2,
'height': this.maxStashDistance * cellSize * 2
});
Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator);
} else {
buildingSchema.rangeTiers && (
this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', {
'isCircular': true,
'radius': buildingSchema.rangeTiers[this.buildingTier - 1] * 0.57071
}), Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator)
);
};
this.componentElem.innerHTML = `<div class="hud-tooltip-building">
<h2>` + buildingSchema.name + `</h2>
<h3>Tier <span class="hud-building-tier">` + this.buildingTier + `</span> Building</h3>
<div class="hud-tooltip-health">
<span class="hud-tooltip-health-bar" style="width:100%;"></span>
</div>
<div class="hud-tooltip-body">
<div class="hud-building-stats"></div>
<p class="hud-building-actions">
<span class="hud-building-dual-btn">
<a class="btn btn-purple hud-building-deposit">Refuel</a>
<a class="btn btn-gold hud-building-collect">Collect</a>
</span>
<a class="btn btn-gold hud-building-upgrade">Upgrade</a>
<a class="btn btn-red hud-building-sell">Sell</a>
</p>
</div>
</div>`;
this.tierElem = this.componentElem.querySelector(`.hud-building-tier`);
this.healthBarElem = this.componentElem.querySelector(`.hud-tooltip-health-bar`);
this.statsElem = this.componentElem.querySelector(`.hud-building-stats`);
this.actionsElem = this.componentElem.querySelector(`.hud-building-actions`);
this.depositElem = this.componentElem.querySelector(`.hud-building-deposit`);
this.dualBtnElem = this.componentElem.querySelector(`.hud-building-dual-btn`);
this.collectElem = this.componentElem.querySelector(`.hud-building-collect`);
this.upgradeElem = this.componentElem.querySelector('.hud-building-upgrade');
this.sellElem = this.componentElem.querySelector('.hud-building-sell');
`Harvester` !== this.buildingId && (this.dualBtnElem.style.display = `none`);
this.depositElem.addEventListener(`click`, this.depositIntoBuilding.bind(this));
this.collectElem.addEventListener(`click`, this.collectFromBuilding.bind(this));
this.upgradeElem.addEventListener(`click`, this.upgradeBuilding.bind(this));
this.sellElem.addEventListener(`click`, this.sellBuilding.bind(this));
this.show();
this.update();
}
game.ui.components.BuildingOverlay.update = function () {
if (this.buildingUid) {
const buildingEntity = Game.currentGame.world.getEntityByUid(this.buildingUid);
if (!buildingEntity) return void this.stopWatching();
let renderer = Game.currentGame.renderer,
buildingUiPosition = renderer.worldToScreen(buildingEntity.getPositionX(), buildingEntity.getPositionY()),
buildingTick = buildingEntity.getTargetTick(),
buildingsSchema = this.ui.getBuildingSchema(),
buildings = this.ui.getBuildings(),
buildingSchema = buildingsSchema[this.buildingId],
building = buildings[this.buildingUid];
if (!building) return void this.stopWatching();
let buildingHeight = buildingSchema.gridHeight,
buildingScale = (buildingSchema.gridWidth, buildingHeight / 2 * 48 * (renderer.getScale() / window.devicePixelRatio)),
buildingTier = building.tier,
buildingSchemaTier = 1,
isBuildingMaxed = false,
isBuildingAtMaxTier = false,
currentStats = {},
nextTierStats = {},
sameBuildings = 1,
buildingStats = {
'health': `Health`,
'damage': `Damage`,
'range': 'Range',
'gps': 'Gold/Sec',
'harvest': `Harvest/Sec`,
'harvestCapacity': `Capacity`
};
if (buildingSchema.tiers) {
const stashTier = this.getGoldStashTier();
building.tier < buildingSchema.tiers ? (buildingSchemaTier = building.tier + 1, isBuildingMaxed = false) : (buildingSchemaTier = building.tier, isBuildingMaxed = true);
isBuildingAtMaxTier = !isBuildingMaxed && (building.tier < stashTier || `GoldStash` === this.buildingId);
}
for (let buildingStat in buildingStats) {
let currentStat = `<small>—</small>`,
nextTierStat = '<small>—</small>';
buildingSchema[buildingStat + `Tiers`] && (
currentStat = buildingSchema[buildingStat + `Tiers`][buildingTier - 1].toLocaleString(),
isBuildingMaxed || (
nextTierStat = buildingSchema[buildingStat + 'Tiers'][buildingSchemaTier - 1].toLocaleString()
),
currentStats[buildingStat] = '<p>' + buildingStats[buildingStat] + `: <strong class="hud-stats-current">` + currentStat + '</strong></p>',
nextTierStats[buildingStat] = `<p>` + buildingStats[buildingStat] + ':\x20<strong\x20class=\x22hud-stats-next\x22>' + nextTierStat + `</strong></p>`
);
}
if (this.shouldUpgradeAll) {
sameBuildings = 0;
for (let buildingUid in buildings) {
// parseInt(buildingUid); tf
buildings[buildingUid].type === this.buildingId && buildings[buildingUid].tier === building.tier && sameBuildings++;
}
}
let costString = this.createResourceCostString(buildingSchema, buildingSchemaTier, sameBuildings),
refundString = this.createResourceRefundString(this.buildingId, buildingSchema, building.tier),
buildingHealth = Math.round(buildingTick.health / buildingTick.maxHealth * 100);
buildingTick.partyId !== this.ui.getPlayerPartyId() ? this.actionsElem.style.display = `none` : this.actionsElem.style.display = 'block';
this.tierElem.innerHTML = building.tier.toString();
this.buildingTier = building.tier;
this.healthBarElem.style.width = buildingHealth + '%';
if (Object.keys(currentStats).length > 0) {
let currentStatValues = '',
nextTierStatValues = '';
for (let stat in currentStats) currentStatValues += currentStats[stat];
for (let stat in nextTierStats) nextTierStatValues += nextTierStats[stat];
this.statsElem.innerHTML = `
<div class="hud-stats-current hud-stats-values">
` + currentStatValues + `
</div>
<div class="hud-stats-next hud-stats-values">
` + nextTierStatValues + `
</div>
`;
} else this.statsElem.innerHTML = '';
if (`Harvester` === this.buildingId) {
let depositAmount = Math.floor(buildingTick.depositMax / 10),
isDepositPossible = buildingTick.depositMax - buildingTick.deposit < depositAmount;
isDepositPossible ? this.depositElem.classList.add('is-disabled') : this.depositElem.classList.remove(`is-disabled`);
this.shouldUpgradeAll
? this.depositElem.innerHTML = 'Refuel\x20All\x20<small>(' + (depositAmount * sameBuildings).toLocaleString() + ` gold)</small>`
: this.depositElem.innerHTML = 'Refuel\x20<small>(' + depositAmount.toLocaleString() + ` gold)</small>`;
}
isBuildingAtMaxTier ? this.upgradeElem.classList.remove(`is-disabled`) : this.upgradeElem.classList.add('is-disabled');
this.shouldUpgradeAll ? (
this.upgradeElem.innerHTML = `Upgrade All <small>(` + costString + ')</small>',
this.sellElem.innerHTML = `Sell All <small>(` + refundString + ')</small>'
) : (
this.upgradeElem.innerHTML = `Upgrade <small>(` + costString + `)</small>`,
this.sellElem.innerHTML = `Sell <small>(` + refundString + `)</small>`
);
`GoldStash` == this.buildingId ? (
this.sellElem.innerHTML = `Sell All Buildings`,
this.sellElem.classList.remove(`is-disabled`),
this.isSellingAll && this.sellElem.classList.add(`is-disabled`)
) : this.ui.getPlayerPartyCanSell() ? (
this.sellElem.classList.remove(`is-disabled`)
) : (
this.sellElem.classList.add(`is-disabled`),
this.sellElem.innerHTML = `Need Permission to Sell`
);
this.componentElem.style.left = buildingUiPosition.x - this.componentElem.offsetWidth / 0x2 + 'px';
this.componentElem.style.top = buildingUiPosition.y - buildingScale - this.componentElem.offsetHeight - 0x14 + 'px';
this.rangeIndicator && this.rangeIndicator.setPosition(buildingEntity.getPositionX(), buildingEntity.getPositionY());
}
}
// @Leaderboard
game.ui.components.Leaderboard.update = function () {
const currentGame = Game.currentGame;
for (let leaderboardElem = 0; leaderboardElem < this.leaderboardData.length; leaderboardElem++) {
let playerData = this.leaderboardData[leaderboardElem],
playerName = this.playerNames[playerData.uid];
this.playerNames[playerData.uid] || (
playerName = window.filterXSS(playerData.name),
this.playerNames[playerData.uid] = playerName
);
leaderboardElem in this.playerElems || (
this.playerElems[leaderboardElem] = this.ui.createElement('<div\x20class=\x22hud-leaderboard-player\x22></div>'),
this.playerRankElems[leaderboardElem] = this.ui.createElement(`<span class="player-rank">-</span>`),
this.playerNameElems[leaderboardElem] = this.ui.createElement(`<strong class="player-name">-</strong>`),
this.playerScoreElems[leaderboardElem] = this.ui.createElement(`<span class="player-score">-</span>`),
this.playerWaveElems[leaderboardElem] = this.ui.createElement('<span\x20class=\x22player-wave\x22>-</span>'),
this.playerElems[leaderboardElem].appendChild(this.playerRankElems[leaderboardElem]),
this.playerElems[leaderboardElem].appendChild(this.playerNameElems[leaderboardElem]),
this.playerElems[leaderboardElem].appendChild(this.playerScoreElems[leaderboardElem]),
this.playerElems[leaderboardElem].appendChild(this.playerWaveElems[leaderboardElem]),
this.playersElem.appendChild(this.playerElems[leaderboardElem])
);
this.playerElems[leaderboardElem].classList[game.world.myUid === playerData.uid ? "add" : "remove"]('is-active');
this.playerElems[leaderboardElem].style.display = `block`;
this.playerRankElems[leaderboardElem].innerText = '#' + (playerData.rank + 1);
this.playerNameElems[leaderboardElem].innerText = playerName;
this.playerScoreElems[leaderboardElem].innerText = playerData.score.toLocaleString();
this.playerWaveElems[leaderboardElem].innerHTML = (0 === playerData.wave) ? `<small>-</small>` : playerData.wave.toLocaleString();
}
if (this.leaderboardData.length < this.playerElems.length) {
for (let invalidEntries = this.leaderboardData.length; invalidEntries < this.playerElems.length; invalidEntries++) {
this.playerElems[invalidEntries].style.display = `none`;
}
}
}
// @Spammer
game.spam = {
literallyEveryUnicodeEver: null,
randomSpamText: [
// `${garbageGenerator()} BIG RAID ${garbageGenerator()}`,
`?verify`,
"hi",
"ez",
"Super Idol的笑容都没你的甜八月正午的阳光都没你耀眼热爱 105 °C的你滴滴清纯的蒸馏水",
"Zǎoshang hǎo zhōngguó xiànzài wǒ yǒu BING CHILLING 🥶🍦",
"Wǒ hěn xǐhuān BING CHILLING 🥶🍦 Dànshì sùdù yǔ jīqíng 9 bǐ BING CHILLING 🥶🍦",
],
spamInterval: null,
spamText: '',
fetchUnicode: async function() {
if (!this.literallyEveryUnicodeEver) {
this.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')
.then(response => response.text())
.then(data => { return data; });
this.randomSpamText.push(`${garbageGenerator()} BIG RAID ${garbageGenerator()}`);
}
},
onchange: function({target}) {
this.spamText = target.value;
},
start: function() {
this.spamInterval = setInterval(() => {
let text;
if (this.spamText !== '') text = `${garbageGenerator()} ${this.spamText} ${garbageGenerator()}`;
else text = getRandomItem(this.randomSpamText);
game.network.sendRpc({
name: "SendChatMessage",
channel: "Local",
message: text
});
}, 1050);
},
stop: function() {
clearInterval(this.spamInterval);
}
};
// @Clones + @SessionSaver
let PacketIds_1 = {
default: {
0: "PACKET_ENTITY_UPDATE",
1: "PACKET_PLAYER_COUNTER_UPDATE",
2: "PACKET_SET_WORLD_DIMENSIONS",
3: "PACKET_INPUT",
4: "PACKET_ENTER_WORLD",
5: "PACKET_PRE_ENTER_WORLD",
6: "PACKET_ENTER_WORLD2",
7: "PACKET_PING",
9: "PACKET_RPC",
10: "PACKET_BLEND",
PACKET_PRE_ENTER_WORLD: 5,
PACKET_ENTER_WORLD: 4,
PACKET_ENTER_WORLD2: 6,
PACKET_ENTITY_UPDATE: 0,
PACKET_INPUT: 3,
PACKET_PING: 7,
PACKET_PLAYER_COUNTER_UPDATE: 1,
PACKET_RPC: 9,
PACKET_SET_WORLD_DIMENSIONS: 2,
PACKET_BLEND: 10,
},
},
e_AttributeType = {
0: "Uninitialized",
1: "Uint32",
2: "Int32",
3: "Float",
4: "String",
5: "Vector2",
6: "EntityType",
7: "ArrayVector2",
8: "ArrayUint32",
9: "Uint16",
10: "Uint8",
11: "Int16",
12: "Int8",
13: "Uint64",
14: "Int64",
15: "Double",
Uninitialized: 0,
Uint32: 1,
Int32: 2,
Float: 3,
String: 4,
Vector2: 5,
EntityType: 6,
ArrayVector2: 7,
ArrayUint32: 8,
Uint16: 9,
Uint8: 10,
Int16: 11,
Int8: 12,
Uint64: 13,
Int64: 14,
Double: 15,
},
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 };
class BinCodec {
constructor() {
this.attributeMaps = {};
this.entityTypeNames = {};
this.rpcMaps = [];
this.rpcMapsByName = {};
this.sortedUidsByType = {};
this.removedEntities = {};
this.absentEntitiesFlags = [];
this.updatedEntityFlags = [];
}
encode(e, t, r) {
let a = new ByteBuffer(100, !0);
switch (e) {
case PacketIds_1.default.PACKET_ENTER_WORLD:
a.writeUint8(PacketIds_1.default.PACKET_ENTER_WORLD), this.encodeEnterWorld(a, t);
break;
case PacketIds_1.default.PACKET_ENTER_WORLD2:
a.writeUint8(PacketIds_1.default.PACKET_ENTER_WORLD2), this.encodeEnterWorld2(a, r);
break;
case PacketIds_1.default.PACKET_INPUT:
a.writeUint8(PacketIds_1.default.PACKET_INPUT), this.encodeInput(a, t);
break;
case PacketIds_1.default.PACKET_PING:
a.writeUint8(PacketIds_1.default.PACKET_PING), this.encodePing(a, t);
break;
case PacketIds_1.default.PACKET_RPC:
a.writeUint8(PacketIds_1.default.PACKET_RPC), this.encodeRpc(a, t);
break;
case PacketIds_1.default.PACKET_BLEND:
a.writeUint8(PacketIds_1.default.PACKET_BLEND), this.encodeBlend(a, t);
}
return a.flip(), a.compact(), a.toArrayBuffer(!1);
}
decode(e, t) {
let r = ByteBuffer.wrap(e);
r.littleEndian = !0;
let a = r.readUint8(),
n;
switch (a) {
case PacketIds_1.default.PACKET_PRE_ENTER_WORLD:
n = this.decodePreEnterWorldResponse(r, t);
break;
case PacketIds_1.default.PACKET_ENTER_WORLD:
n = this.decodeEnterWorldResponse(r);
break;
case PacketIds_1.default.PACKET_ENTITY_UPDATE:
n = this.decodeEntityUpdate(r);
break;
case PacketIds_1.default.PACKET_PING:
n = this.decodePing(r);
break;
case PacketIds_1.default.PACKET_RPC:
n = this.decodeRpc(r);
break;
case PacketIds_1.default.PACKET_BLEND:
n = this.decodeBlend(r, t);
}
return (n.opcode = a), n;
}
safeReadVString(e) {
let t = e.offset,
r = e.readVarint32(t);
try {
var a = e.readUTF8String.bind(e)(r.value, "b", (t += r.length));
return (t += a.length), (e.offset = t), a.string;
} catch (n) {
return (t += r.value), (e.offset = t), "?";
}
}
decodePreEnterWorldResponse(e, t) {
return t._MakeBlendField(255, 140), { extra: this.decodeBlendInternal(e, t) };
}
decodeEnterWorldResponse(e) {
let t = e.readUint32(),
r,
a = {
allowed: t,
uid: e.readUint32(),
startingTick: e.readUint32(),
tickRate: e.readUint32(),
effectiveTickRate: e.readUint32(),
players: e.readUint32(),
maxPlayers: e.readUint32(),
chatChannel: e.readUint32(),
effectiveDisplayName: this.safeReadVString(e),
x1: e.readInt32(),
y1: e.readInt32(),
x2: e.readInt32(),
y2: e.readInt32(),
},
n = e.readUint32();
(this.attributeMaps = {}), (this.entityTypeNames = {});
for (let i = 0; i < n; i++) {
let s = [],
d = e.readUint32(),
l = e.readVString(),
c = e.readUint32();
for (let o = 0; o < c; o++) {
let u = e.readVString(),
f = e.readUint32();
s.push({ name: u, type: f });
}
(this.attributeMaps[d] = s), (this.entityTypeNames[d] = l), (this.sortedUidsByType[d] = []);
}
let p = e.readUint32();
(this.rpcMaps = []), (this.rpcMapsByName = {});
for (let _ = 0; _ < p; _++) {
let E = e.readVString(),
m = e.readUint8(),
y = 0 != e.readUint8(),
h = [];
for (let T = 0; T < m; T++) {
let P = e.readVString(),
U = e.readUint8();
h.push({ name: P, type: U });
}
let $ = { name: E, parameters: h, isArray: y, index: this.rpcMaps.length };
this.rpcMaps.push($), (this.rpcMapsByName[E] = $);
}
return a;
}
decodeEntityUpdate(e) {
let t = e.readUint32(),
r = e.readVarint32(),
a = {};
(a.tick = t), (a.entities = new Map());
let n = Object.keys(this.removedEntities);
for (let i = 0; i < n.length; i++) delete this.removedEntities[n[i]];
for (let s = 0; s < r; s++) {
var d = e.readUint32();
this.removedEntities[d] = 1;
}
let l = e.readVarint32();
for (let c = 0; c < l; c++)
for (var o = e.readVarint32(), u = e.readUint32(), f = 0; f < o; f++) {
var p = e.readUint32();
this.sortedUidsByType[u].push(p);
}
let _ = Object.keys(this.sortedUidsByType);
for (let E = 0; E < _.length; E++) {
let m = this.sortedUidsByType[_[E]],
y = [];
for (let h = 0; h < m.length; h++) {
let T = m[h];
T in this.removedEntities || y.push(T);
}
y.sort((e, t) => e - t), (this.sortedUidsByType[_[E]] = y);
}
for (; e.remaining(); ) {
let P = e.readUint32();
if (!(P in this.attributeMaps)) throw Error("Entity type is not in attribute map: " + P);
let U = Math.floor((this.sortedUidsByType[P].length + 7) / 8);
this.absentEntitiesFlags.length = 0;
for (let $ = 0; $ < U; $++) this.absentEntitiesFlags.push(e.readUint8());
let b = this.attributeMaps[P];
for (let A = 0; A < this.sortedUidsByType[P].length; A++) {
let I = this.sortedUidsByType[P][A];
if ((this.absentEntitiesFlags[Math.floor(A / 8)] & (1 << A % 8)) != 0) {
a.entities.set(I, !0);
continue;
}
var k = { uid: I };
this.updatedEntityFlags.length = 0;
for (let g = 0; g < Math.ceil(b.length / 8); g++) this.updatedEntityFlags.push(e.readUint8());
for (let C = 0; C < b.length; C++) {
let w = b[C],
R = Math.floor(C / 8),
v = C % 8,
N,
B = [];
if (this.updatedEntityFlags[R] & (1 << v))
switch (w.type) {
case e_AttributeType.Uint32:
k[w.name] = e.readUint32();
break;
case e_AttributeType.Int32:
k[w.name] = e.readInt32();
break;
case e_AttributeType.Float:
k[w.name] = e.readInt32() / 100;
break;
case e_AttributeType.String:
k[w.name] = this.safeReadVString(e);
break;
case e_AttributeType.Vector2:
var K = e.readInt32() / 100,
S = e.readInt32() / 100;
k[w.name] = { x: K, y: S };
break;
case e_AttributeType.ArrayVector2:
(N = e.readInt32()), (B = []);
for (let D = 0; D < N; D++) {
let M = e.readInt32() / 100,
F = e.readInt32() / 100;
B.push({ x: M, y: F });
}
k[w.name] = B;
break;
case e_AttributeType.ArrayUint32:
(N = e.readInt32()), (B = []);
for (let O = 0; O < N; O++) {
let W = e.readInt32();
B.push(W);
}
k[w.name] = B;
break;
case e_AttributeType.Uint16:
k[w.name] = e.readUint16();
break;
case e_AttributeType.Uint8:
k[w.name] = e.readUint8();
break;
case e_AttributeType.Int16:
k[w.name] = e.readInt16();
break;
case e_AttributeType.Int8:
k[w.name] = e.readInt8();
break;
case e_AttributeType.Uint64:
k[w.name] = e.readUint32() + 4294967296 * e.readUint32();
break;
case e_AttributeType.Int64:
var L = e.readUint32(),
V = e.readInt32();
V < 0 && (L *= -1), (L += 4294967296 * V), (k[w.name] = L);
break;
case e_AttributeType.Double:
var x = e.readUint32(),
G = e.readInt32();
G < 0 && (x *= -1), (x += 4294967296 * G), (x /= 100), (k[w.name] = x);
break;
default:
throw Error("Unsupported attribute type: " + w.type);
}
}
a.entities.set(k.uid, k);
}
}
return (a.byteSize = e.capacity()), a;
}
decodePing() {
return {};
}
encodeRpc(e, t) {
if (!(t.name in this.rpcMapsByName)) throw Error("RPC not in map: " + t.name);
var r = this.rpcMapsByName[t.name];
e.writeUint32(r.index);
for (var a = 0; a < r.parameters.length; a++) {
var n = t[r.parameters[a].name];
switch (r.parameters[a].type) {
case e_ParameterType.Float:
e.writeInt32(Math.floor(100 * n));
break;
case e_ParameterType.Int32:
e.writeInt32(n);
break;
case e_ParameterType.String:
e.writeVString(n);
break;
case e_ParameterType.Uint32:
e.writeUint32(n);
}
}
}
decodeBlend(e, t) {
return { extra: this.decodeBlendInternal(e, t) };
}
decodeBlendInternal(e, t) {
t._MakeBlendField(24, 132);
for (let r = t._MakeBlendField(228, e.remaining()), a = 0; e.remaining(); ) (t.HEAPU8[r + a] = e.readUint8()), a++;
t._MakeBlendField(172, 36);
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];
return n;
}
decodeRpcObject(e, t) {
for (var r = {}, a = 0; a < t.length; a++)
switch (t[a].type) {
case e_ParameterType.Uint32:
r[t[a].name] = e.readUint32();
break;
case e_ParameterType.Int32:
r[t[a].name] = e.readInt32();
break;
case e_ParameterType.Float:
r[t[a].name] = e.readInt32() / 100;
break;
case e_ParameterType.String:
r[t[a].name] = this.safeReadVString(e);
break;
case e_ParameterType.Uint64:
r[t[a].name] = e.readUint32() + 4294967296 * e.readUint32();
}
return r;
}
decodeRpc(e) {
var t = e.readUint32(),
r = this.rpcMaps[t],
a = { name: r.name, response: null };
if (r.isArray) {
for (var n = [], i = e.readUint16(), s = 0; s < i; s++) n.push(this.decodeRpcObject(e, r.parameters));
a.response = n;
} else a.response = this.decodeRpcObject(e, r.parameters);
return a;
}
encodeBlend(e, t) {
for (var r = new Uint8Array(t.extra), a = 0; a < t.extra.byteLength; a++) e.writeUint8(r[a]);
}
encodeEnterWorld(e, t) {
e.writeVString(t.displayName);
for (var r = new Uint8Array(t.extra), a = 0; a < t.extra.byteLength; a++) e.writeUint8(r[a]);
}
encodeEnterWorld2(e, t) {
for (var r = t._MakeBlendField(187, 22), a = 0; a < 16; a++) e.writeUint8(t.HEAPU8[r + a]);
}
encodeInput(e, t) {
e.writeVString(JSON.stringify(t));
}
encodePing(e) {
e.writeUint8(0);
}
}
let codec = new BinCodec(),
wasmBuffers;
fetch("https://cdn.glitch.global/14f404fe-81a3-418b-bc7c-78513660ae26/zombs_wasm%20(7).wasm?v=1710679251082")
.then((e) => e.arrayBuffer().then((e) => {
wasmBuffers = e;
}));
const wasmModule = (callback, data_12, hostname) => {
function _a(e, t, r) {
for (var a = t + r, n = t; e[n] && !(n >= a); ) ++n;
if (n - t > 16 && e.subarray && _n) return _n.decode(e.subarray(t, n));
for (var i = ""; t < n; ) {
let s = e[t++];
if (128 & s) {
var d = 63 & e[t++];
if (192 != (224 & s)) {
var l = 63 & e[t++];
if ((s = 224 == (240 & s) ? ((15 & s) << 12) | (d << 6) | l : ((7 & s) << 18) | (d << 12) | (l << 6) | (63 & e[t++])) < 65536) i += String.fromCharCode(s);
else {
var c = s - 65536;
i += String.fromCharCode(55296 | (c >> 10), 56320 | (1023 & c));
}
} else i += String.fromCharCode(((31 & s) << 6) | d);
} else i += String.fromCharCode(s);
}
return i;
}
function _b(e, t) {
return e ? _a(_k, e, t) : "";
}
function _c(e, t, r, a) {
if (!(a > 0)) return 0;
for (var n = r, i = r + a - 1, s = 0; s < e.length; ++s) {
var d = e.charCodeAt(s);
if ((d >= 55296 && d <= 57343 && (d = (65536 + ((1023 & d) << 10)) | (1023 & e.charCodeAt(++s))), d <= 127)) {
if (r >= i) break;
t[r++] = d;
} else if (d <= 2047) {
if (r + 1 >= i) break;
(t[r++] = 192 | (d >> 6)), (t[r++] = 128 | (63 & d));
} else if (d <= 65535) {
if (r + 2 >= i) break;
(t[r++] = 224 | (d >> 12)), (t[r++] = 128 | ((d >> 6) & 63)), (t[r++] = 128 | (63 & d));
} else {
if (r + 3 >= i) break;
(t[r++] = 240 | (d >> 18)), (t[r++] = 128 | ((d >> 12) & 63)), (t[r++] = 128 | ((d >> 6) & 63)), (t[r++] = 128 | (63 & d));
}
}
return (t[r] = 0), r - n;
}
function _d(e, t, r) {
return _c(e, _k, t, r);
}
function _e(e) {
for (var t = 0, r = 0; r < e.length; ++r) {
var a = e.charCodeAt(r);
a >= 55296 && a <= 57343 && (a = (65536 + ((1023 & a) << 10)) | (1023 & e.charCodeAt(++r))), a <= 127 ? ++t : (t += a <= 2047 ? 2 : a <= 65535 ? 3 : 4);
}
return t;
}
function _f(e) {
(_m.HEAP8 = new Int8Array(e)),
(_m.HEAP16 = new Int16Array(e)),
(_m.HEAP32 = _l = new Int32Array(e)),
(_m.HEAPU8 = _k = new Uint8Array(e)),
(_m.HEAPU16 = new Uint16Array(e)),
(_m.HEAPU32 = new Uint32Array(e)),
(_m.HEAPF32 = new Float32Array(e)),
(_m.HEAPF64 = new Float64Array(e));
}
function _g() {
function e(e) {
(_m.asm = e.exports), _f(_m.asm.g.buffer), _o(), _j();
}
function t(t) {
e(t.instance);
}
function r(e) {
WebAssembly.instantiate(wasmBuffers, a).then((t) => {
e(t), "function" == typeof callback && callback(_m.decodeOpcode5(hostname, data_12));
});
}
var a = { a: { d() {}, e() {}, c() {}, f() {}, b: _h, a: _i } };
if (_m.instantiateWasm)
try {
return _m.instantiateWasm(a, e);
} catch (n) {
return console.log("Module.instantiateWasm callback failed with error: " + n), !1;
}
return r(t), {};
}
function _h(_hh) {
let e = _b(_hh);
if (e.includes('typeof window === "undefined" ? 1 : 0;') || e.includes("typeof process !== 'undefined' ? 1 : 0;")) return 0;
if (e.includes("Game.currentGame.network.connected ? 1 : 0")) return 1;
if (e.includes("Game.currentGame.world.myUid === null ? 0 : Game.currentGame.world.myUid;")) return 0;
if (e.includes('document.getElementById("hud").children.length;')) return 24;
if (e.includes("hostname")) return hostname;
let data;
return 0 | eval(_b(_hh));
}
function _i(e) {
var t = hostname;
if (null == t) return 0;
t = String(t);
var r = _i,
a = _e(t);
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;
}
function _j() {
(_l[1328256] = 5313008), (_l[1328257] = 0), _m._main(1, 5313024);
}
var _k,
_l,
_m = {},
_n = new TextDecoder("utf8");
_g();
var _o = (_m.___wasm_call_ctors = function () {
return (_o = _m.___wasm_call_ctors = _m.asm.h).apply(null, arguments);
}),
_p = (_m._main = function () {
return (_p = _m._main = _m.asm.i).apply(null, arguments);
}),
_q = (_m._MakeBlendField = function () {
return (_q = _m._MakeBlendField = _m.asm.j).apply(null, arguments);
}),
_r = (_m._malloc = function () {
return (_r = _m._malloc = _m.asm.l).apply(null, arguments);
}),
_s = (_m._free = function () {
return (_s = _m._free = _m.asm.m).apply(null, arguments);
});
return (
(_m.decodeOpcode5 = function (e, t) {
_m.hostname = e;
let r = codec.decode(new Uint8Array(t), _m),
a = codec.encode(6, {}, _m);
return { 5: r, 6: a, 10: _m };
}),
_m
);
};
const 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
}
];
const 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}}}'
game.sessions = {
SESSION_SECRET_KEY: 'f07cbf563d19619ba4afe3ae1e2ec95710a72b3e',
SESSION_DEFAULT_PORT: 727,
SESSION_FETCH_TIMEOUT: 7500,
allSessions: null,
sessionElem: document.createElement('optgroup'),
shouldUseSession: false,
currentSession: null,
init: async function() {
const allServerElems = document.querySelectorAll(".hud-intro-server option");
for (const serverElem of allServerElems) {
serverElem.innerText = `${serverElem.innerText} (${serverElem.value})`;
};
await this.fetchSessions();
this.sessionElem.label = "Sessions";
game.ui.components.Intro.serverElem.appendChild(this.sessionElem);
game.ui.components.Intro.serverElem.onchange = ({ target: { value } }) => {
if (value == "newSes") return game.sessions.createSession();
if (value.includes("session")) {
const sessionId = value.split("/")[1];
game.sessions.useSessions(sessionId);
} else this.shouldUseSession = false;
};
},
useSessions: function(sessionId) {
this.currentSession = sessionId;
this.shouldUseSession = true;
},
fetchSessions: async function() {
try {
let data = await fetch(
`http://localhost:${this.SESSION_DEFAULT_PORT + 1}/sessions`,
{ signal: AbortSignal.timeout(this.SESSION_FETCH_TIMEOUT) }
);
data = await data.json();
this.allSessions = data;
this.mapSessions();
} catch {
console.log("Failed to fetch available sessions...");
};
},
createSession: async function(nickname = getClass("hud-intro-name")[0].value, server = getClass("hud-intro-server")[0].value, psk = "") {
if (server == "newSes") server = prompt("Enter server ID");
if (!(server in game.options.servers)) {
if (!("v" + server in game.options.servers)) return this.createSession(nickname, "newSes");
};
psk = prompt("Enter party share key (if you don't intend to join a party after creating the session, please leave this empty)");
try {
let data = await fetch(
`http://localhost:${this.SESSION_DEFAULT_PORT + 1}/create?name=${nickname}&serverId=${server}&psk=${psk}`,
{ signal: AbortSignal.timeout(this.SESSION_FETCH_TIMEOUT) }
);
data = await data.json();
this.allSessions = data.data;
this.mapSessions();
getClass("hud-intro-server")[0].value = `session/${data.createdSession}`;
this.useSessions(data.createdSession);
} catch(e) {
console.log("Failed to create new session: " + e);
};
// await fetch(`http://localhost:${this.SESSION_DEFAULT_PORT + 1}/create?name=${nickname}&serverId=${server}`);
},
mapSessions() {
if (this.allSessions === null) return;
this.sessionElem.innerHTML = [...Object.entries(this.allSessions).map(([ key, {name, connectionOptions: { id } } ]) => {
return `
<option value="session/${key}">${window.filterXSS(name)} [${id}]</option>
`;
}), `<option value="newSes">New Session</option>`].join("\n");
},
};
game.network.establishSessionConnection = function() {
const { currentSession, allSessions } = game.sessions;
this.connectionOptions = allSessions[currentSession].connectionOptions;
this.connected = false;
this.connecting = true;
this.codec.rpcMaps = [{
"name": "SyncData",
"parameters": [{
"name": "json",
"type": 3
}],
"isArray": false,
"index": 0
}, {
"name": "VerifyUser",
"parameters": [{
"name": "secretKey",
"type": 3,
}],
"isArray": false,
"index": 1
}, {
"name": "ConnectSession",
"parameters": [{
"name": "id",
"type": 3
}],
"isArray": false,
"index": 2
}];
this.codec.rpcMapsByName = {
"SyncData": {
"name": "SyncData",
"parameters": [{
"name": "json",
"type": 3
}],
"isArray": false,
"index": 0
},
"VerifyUser": {
"name": "VerifyUser",
"parameters": [{
"name": "secretKey",
"type": 3
}],
"isArray": false,
"index": 1
},
"ConnectSession": {
"name": "ConnectSession",
"parameters": [{
"name": "id",
"type": 3
}],
"isArray": false,
"index": 2
},
};
this.socket = new WebSocket(`ws://localhost:${game.sessions.SESSION_DEFAULT_PORT}`);
this.socket.binaryType = `arraybuffer`;
this.socket.addEventListener("open", () => {
this.socket.send(this.codec.encode(9, {
name: "VerifyUser",
secretKey: game.sessions.SESSION_SECRET_KEY
}));
this.socket.send(this.codec.encode(9, {
name: "ConnectSession",
id: currentSession,
}));
});
this.bindEventListeners();
this.addRpcHandler("SyncData", (response) => {
try {
const data = JSON.parse(response.json);
this.connectionOptions = data.connectionOptions;
game.options.serverId = data.connectionOptions.id;
game.options.nickname = data.syncNeeds[0].effectiveDisplayName;
const staticCodecData = JSON.parse(codecJSON);
for (let i in staticCodecData) {
this.codec[i] = staticCodecData[i];
};
this.codec.sortedUidsByType = data.sortedUidsByType;
this.codec.removedEntities = data.removedEntities;
this.codec.absentEntitiesFlags = data.absentEntitiesFlags;
this.codec.updatedEntityFlags = data.updatedEntityFlags;
for (let i = 0; i < staticJSONs.length; i++) {
this.emitter.emit(PacketIds_1.default[staticJSONs[i].opcode], staticJSONs[i]);
};
for (let i = 0; i < data.syncNeeds.length; i++) {
this.emitter.emit(PacketIds_1.default[data.syncNeeds[i].opcode], data.syncNeeds[i]);
};
for (let i = 0; i < data.messages.length; i++) {
this.emitter.emit(PacketIds_1.default[9], {
name: "ReceiveChatMessage",
response: data.messages[i],
opcode: 9
});
};
if (data.castSpellResponse && data.castSpellResponse.cooldownStartTick && (data.tick - data.castSpellResponse.cooldownStartTick) * 50 < 240000) {
this.emitter.emit(PacketIds_1.default[9], {
name: 'CastSpellResponse',
response: data.castSpellResponse,
opcode: 9
});
};
for (let i in data.inventory) {
this.emitter.emit(PacketIds_1.default[9], {
name: "SetItem",
response: {
itemName: data.inventory[i].itemName,
tier: data.inventory[i].tier,
stacks: data.inventory[i].stacks
},
opcode: 9
});
};
this.emitter.emit(PacketIds_1.default[9], {
name: "LocalBuilding",
response: data.localBuildings,
opcode: 9
});
this.emitter.emit(PacketIds_1.default[0], {
tick: data.tick,
entities: data.entities,
byteSize: data.byteSize,
opcode: 0
});
this.emitter.once(PacketIds_1.default[0], () => {
const myPlayer = data.entities[data.syncNeeds[0].uid];
myPlayer?.dead && this.emitter.emit(PacketIds_1.default[9], {
name: "Dead",
response: {stashDied: 0},
opcode: 9
});
myPlayer?.isPaused && (
game.ui.onLocalItemUpdate({
itemName: 'Pause',
tier: 1,
stacks: 1
}),
game.ui.emit('wavePaused')
);
});
} catch(e) { console.log(e); };
});
};
game.network.connect = async function (options) {
if (!this.connecting) {
if (game.sessions.shouldUseSession) return this.establishSessionConnection();
this.connectionOptions = options;
this.connected = false;
this.connecting = true;
this.socket = new WebSocket('wss://' + options.hostname + ':' + options.port);
this.socket.binaryType = `arraybuffer`;
this.bindEventListeners();
};
};
game.sessions.init();
const loadLbPacket = (socket) => {
for (let i = 0; i < 26; i++) socket.ws.send(new Uint8Array([3, 17, 123, 34, 117, 112, 34, 58, 49, 44, 34, 100, 111, 119, 110, 34, 58, 48, 125])); // move packet
socket.ws.send(new Uint8Array([7, 0])); // ping
socket.ws.send(
new Uint8Array(
[9,6,0,0,0,126,8,0,0,108,27,0,0,146,23,0,0,82,23,0,0,8,91,11,0,8,91,11,0,0,0,0,0,32,78,0,0,76,79,0,0,172,38,0,0,120,155,0,0,
166,39,0,0,140,35,0,0,36,44,0,0,213,37,0,0,100,0,0,0,120,55,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,134,6,0,0]
)
); // metrics
};
game.clones = {
all: {},
shared: {
control: true,
},
createSocket: function() {
const socket = new CloneSocket();
this.all[socket.identifiers.id] = socket;
socket.shared = this.shared;
}
};
function decodeMessage(server, socket, msg) {
let data = {};
const m = new Uint8Array(msg.data);
data.opcode = m[0];
switch(m[0]) {
case 5:
wasmModule(e => {
socket.sendPacket(4, {displayName: socket.identifiers.name, extra: e[5].extra});
socket.ws.enterWorld2 = e[6];
socket.Module = e[10];
}, m, server.ipAddress);
break;
case 10:
socket.sendPacket(10, {extra: codec.decode(m, socket.Module).extra});
break;
default:
data = socket.network.codec.decode(msg.data);
};
if (m[0] == 4) {
data.allowed && socket.ws.send(socket.ws.enterWorld2);
delete socket.ws.enterWorld2;
};
return data;
}
class Socket {
constructor(url, identifiers, sendNow = true) {
this.url = url;
this.identifiers = identifiers;
sendNow && this.init();
};
init() {
this.ws = new WebSocket(this.url);
this.ws.binaryType = "arraybuffer";
this.ws.addEventListener("open", () => {
console.log("a", this);
this.network = new game.networkType();
this.network.emitter.removeListener("PACKET_BLEND", this.network.emitter._events.PACKET_BLEND);
});
}
sendPacket(e, t) {
const enc = this.network.codec.encode(e, t);
this.ws.readyState == 1 && this.ws.send(enc);
};
};
const status_enum = {
"Population Full": "red",
"Failed": "red",
"Closed": "red",
"Connecting": "yellow",
"Open": "green"
};
class CloneSocket extends Socket {
constructor(server = game.network.connectionOptions) {
const id = genShortUUID();
super(`wss://${server.hostname}:443/`, {
name: garbageGenerator(1), id,
});
this.timeCreation = Date.now();
this.player = {
uid: null,
partyShareKey: null,
targetTick: {},
petTick: {},
// entities: {},
inventory: {},
buildings: {},
parties: {},
hasHealed: false,
lastTickHealth: 100,
};
this.minimapDisplay = document.createElement('div');
this.statusDisplay = document.createElement("p");
// this.server = server;
this.bindControls();
this.ws.addEventListener("open", () => { this.updateStatus("Connecting"); });
this.ws.addEventListener("message", (msg) => {
this.data = decodeMessage(server, this, msg);
switch(this.data.opcode) {
case 0: this.onEntityUpdate(this.data); break;
case 4: this.onEnterWorld(this.data); break;
case 5:
this.onPreEnterWorld(this.data);
setTimeout(() => { if (this.data.opcode === 5) this.ws.close(3001); }, 5000);
break;
case 9: this.onRpc(this.data); break;
};
});
this.ws.addEventListener("close", ({code}) => { this.onClose(code); });
};
sendInput(t) { this.sendPacket(3, t); };
sendPing(t) { this.sendPacket(7, t); };
sendRpc(t) { this.sendPacket(9, t); };
onEntityUpdate(data) {
if (data.entities[this.player.uid].name) {
this.player.targetTick = data.entities[this.player.uid];
}
for (let g in this.player.targetTick) {
if (this.player.targetTick[g] !== data.entities[this.player.uid][g] && data.entities[this.player.uid][g] !== undefined) {
this.player.targetTick[g] = data.entities[this.player.uid][g];
}
}
if (this.player.targetTick.petUid) {
if (data.entities?.[this.player.targetTick.petUid]?.model) {
this.player.petTick = data.entities[this.player.targetTick.petUid];
}
for (let g in this.player.petTick) {
if (this.player.petTick[g] !== data.entities?.[this.player.targetTick.petUid][g] && data.entities?.[this.player.targetTick.petUid][g] !== undefined) {
this.player.petTick[g] = data.entities[this.player.targetTick.petUid][g];
}
}
}
for (let i in data.entities) {
/*
if (data.entities[i].name) {
this.entities.players[i] = data.entities[i];
} */
if (["Tree", "Stone", "NeutralCamp"].indexOf(data.entities[i].model) > -1) {
game.world.createEntity(data.entities[i]);
}
}
/*
for (let i in this.entities.players) {
if (!data.entities[i]) delete this.entities.players[i];
for (let g in this.entities.players[i]) {
if (this.entities.players[i][g] !== data.entities[i][g] && data.entities[i][g] !== undefined) {
this.entities.players[i][g] = data.entities[i][g];
};
};
};
*/
};
onEnterWorld(e) {
if (e.allowed) {
this.player.uid = e.uid;
this.updateStatus("Open");
console.log(`%c [SOCKET ${this.identifiers.id}]`, 'color: #54ebd9', '\n', `${e.players + 1}/32 players`);
this.sendRpc({name: "BuyItem", itemName: "PetCARL", tier: 1});
this.sendRpc({name: "BuyItem", itemName: "PetMiner", tier: 1});
this.sendInput({left: 1, up: 1});
this.sendInput({space: 1});
} else {
console.log(`%c [SOCKET ${this.identifiers.id}]`, 'color: #54ebd9', '\n', `32/32 players`);
this.updateStatus("Population Full");
};
};
onPreEnterWorld(e) {};
onRpc(e) {
this.updateStatus("Open");
switch(e.name) {
case "PartyShareKey":
this.player.partyShareKey || this.sendRpc({name: "JoinPartyByShareKey", partyShareKey: game.ui.getPlayerPartyShareKey()});
this.player.partyShareKey = e.response;
break;
case "SetItem":
this.player.inventory[e.response.itemName] = e.response;
if (!this.player.inventory[e.response.itemName].stacks) {
delete this.player.inventory[e.response.itemName];
}
break;
};
};
onClose(code) {
switch(code) {
case 3001:
this.updateStatus("Failed");
break;
default:
this.updateStatus("Closed");
};
};
bindControls() {};
updateStatus(status) {
const timeElapsedInMiliseconds = Date.now() - this.timeCreation;
const timeElapsedInSeconds = Math.floor(timeElapsedInMiliseconds / 1000);
const timeElapsedInMinutes = Math.floor(timeElapsedInSeconds / 60);
const timeElapsedInSecondsSubtracted = timeElapsedInSeconds - (timeElapsedInMinutes * 60);
this.statusDisplay.id = `alt${this.identifiers.id}`;
this.statusDisplay.innerHTML = `
Socket ${this.identifiers.id}<br>
State: <strong style="color: ${status_enum[status]};">[${status}]</strong>${["Population Full", "Failed", "Closed"].indexOf(status) == -1 ? `, elapsed: ${timeElapsedInMinutes}m ${timeElapsedInSecondsSubtracted}s` : `, created: ${getClock(new Date(this.timeCreation))}`}<br>
${status === "Open" ? `
UID: ${this.player.uid}, partyId: <strong>${this.player.targetTick.partyId || 0}</strong><br>
<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>
<a href="javascript:void(0);" style="margin: 5px 0 0 0;color: red;" onclick="game.clones.all['${this.identifiers.id}'].ws.close();">Delete</a>
<!--
<a href="javascript:void(0);"
style="margin: 5px 0 0 0;color: lightblue;"
class="elem-is-disabled"
id="respawnAlt#${this.identifiers.id}"
onclick="
game.script.cloneSockets.allSockets[${this.identifiers.id}].network.sendInput({respawn: 1});
document.getElementById('respawnAlt#${this.identifiers.id}').classList.add('elem-is-disabled');
"
>Respawn</a> -->
` : ""}
`;
status === "Connecting" && getId("clone-status").appendChild(this.statusDisplay);
};
};
window.CloneSocket = CloneSocket;
window.sendAitoAlt = () => {
let lastSocket = null;
const server = game.network.connectionOptions;
const hostname = server.hostname;
const url = `wss://${hostname}:443/`;
const aitoInterval = () => {
if (!game.options.options.aito) {
lastSocket?.ws?.close?.();
return;
};
const socket = new Socket(url, {
name: garbageGenerator(1),
});
socket.verified = false;
socket.sendInput = function(t) {
this.sendPacket(3, t);
};
socket.sendRpc = function(t) {
this.sendPacket(9, t);
};
socket.ws.onmessage = (msg) => {
socket.data = decodeMessage(server, socket, msg);
if (socket.data.opcode === 0) {
socket.identifiers.player = Object.assign(socket.identifiers.player, socket.data.entities[socket.identifiers.uid]);
if (socket.identifiers.psk) {
if (socket.identifiers.psk.response.partyShareKey != game.ui.getPlayerPartyShareKey()) {
socket.sendRpc({
name: "JoinPartyByShareKey",
partyShareKey: game.ui.getPlayerPartyShareKey()
});
} else if (socket.identifiers.player.gold >= 10000) {
socket.sendRpc({
name: "BuyItem",
itemName: "Pause",
tier: 1
});
};
};
};
if (socket.data.opcode === 4) {
socket.identifiers.uid = socket.data.uid;
socket.identifiers.player = {};
socket.sendInput({left: 1, up: 1});
};
if (socket.data.opcode === 5) {
console.log(lastSocket);
lastSocket?.ws?.close?.();
setTimeout(() => {
if (socket.data.opcode === 5) {
socket.ws.close();
aitoInterval();
};
}, 2500);
};
if (socket.data.opcode === 9) {
if (socket.data.name == "DayCycle") {
const isDay = socket.data.response.isDay;
if (!isDay) {
if (socket.ws.readyState == 1 && socket.verified) {
lastSocket = socket;
aitoInterval();
};
} else socket.verified = true;
};
if (socket.data.name == "Dead") socket.sendInput({respawn: 1});
if (socket.data.name == "Leaderboard") {
socket.sendPacket(7, {nonce: 0});
socket.sendRpc(game.metrics.metrics);
};
if (socket.data.name == "PartyShareKey") socket.identifiers.psk = socket.data;
};
};
};
aitoInterval();
};
window.sscs = (selected = getClass("hud-intro-server")[0].value) => {
const server = game.options.servers[selected];
const hostname = server.hostname;
const url = `wss://${hostname}:443/`;
let hasSentData = false;
document.querySelector("#hud-intro > div.hud-intro-corner-top-left > div").innerHTML = `
<strong class="hud-loading" style="display: block;margin: auto;"></strong>
<span style="display: block;margin: 10px 0 5px;position: relative;text-align: center;opacity: 0.7;">This may take 10-20 seconds.</span>
`;
const socket = new Socket(url, {
name: new Date().toLocaleString(),
});
socket.ws.onopen = (data) => {
socket.ws.send(new Uint8Array([7, 0]));
};
socket.ws.onmessage = msg => {
const data = decodeMessage(server, socket, msg);
if (!data) return;
switch(data.opcode) {
case 4:
if (!data.allowed) {
const lbData = {
name: "Leaderboard",
response: [{name: "Server full.", uid: 727, rank: 0, score: 0, wave: 0}],
opcode: 9
};
window.appSsrs({ population: 32, leaderboard: lbData, parties: [], server: server });
hasSentData = true;
} else {
socket.sendPacket(3, { left: 1, up: 1, mouseMovedWhileDown: 0 });
socket.sendPacket(3, {space: 0});
socket.sendPacket(3, {space: 1});
socket.pop = data.players;
loadLbPacket(socket);
}
break;
case 9:
if (data.name === "SetPartyList") {
socket.parties = data.response;
};
if (data.name === "Leaderboard") {
if (socket.b4 >= 3) return socket.ws.close();
if (socket.b4 != 0) {
if (data.response.length > 1 || socket.pop == 0) {
window.appSsrs({ population: socket.pop, leaderboard: data, parties: socket.parties, server: server });
hasSentData = true;
return socket.ws.close();
} else loadLbPacket(socket);
};
socket.b4++;
};
break;
};
};
socket.ws.onclose = () => {
if (!hasSentData) {
const lbData = {
name: "Leaderboard",
response: [{name: "Unable to access.", uid: 727, rank: 0, score: 0, wave: 0}],
opcode: 9
};
window.appSsrs({ population: null, leaderboard: lbData, parties: [], server: server });
hasSentData = true;
};
};
};
/* @Functions */
function bindTooltip(elem, innerHTML, anchor = 'top') {
elem.targetElem = elem;
elem.anchor = anchor;
elem.hide = function() { this.tooltipElem && (this.tooltipElem.remove(), delete this.tooltipElem); };
elem.targetElem.addEventListener('mouseenter', function() {
let toolTip = innerHTML;
document.body.insertAdjacentHTML(`beforeend`, toolTip);
this.tooltipElem = document.getElementById(`hud-tooltip`);
let clientRect = this.targetElem.getBoundingClientRect();
let position = {'left': 0, 'top': 0};
switch(this.anchor) {
case 'top':
position.left = clientRect.left + clientRect.width / 0x2 - this.tooltipElem.offsetWidth / 0x2;
position.top = clientRect.top - this.tooltipElem.offsetHeight - 0x14;
break;
case 'bottom':
position.left = clientRect.left + clientRect.width / 0x2 - this.tooltipElem.offsetWidth / 0x2;
position.top = clientRect.top + clientRect.height + 0x14;
break;
case 'left':
position.left = clientRect.left - this.tooltipElem.offsetWidth - 0x14;
position.top = clientRect.top + clientRect.height / 0x2 - this.tooltipElem.offsetHeight / 0x2;
break;
case 'right':
position.left = clientRect.left + clientRect.width + 0x14;
position.top = clientRect.top + clientRect.height / 0x2 - this.tooltipElem.offsetHeight / 0x2;
break;
}
this.tooltipElem.className = `hud-tooltip hud-tooltip-` + this.anchor;
this.tooltipElem.style.left = position.left + 'px';
this.tooltipElem.style.top = position.top + 'px';
this.tooltipElem.style.zIndex = "999";
});
elem.targetElem.addEventListener(`mouseleave`, elem.hide);
}
function genUUID() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(
/[018]/g, c => (
c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4
).toString(16)
);
};
function genShortUUID() {
return ([1e2] + -1e2 + -4e2 + -8e2 + -1e2).replace(
/[018]/g, c => (
c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4
).toString(16)
);
};
function getRandomItem(array) {
return array[Math.floor(Math.random() * array.length)];
};
function garbageGenerator(garbageLength = 25) {
let garbageCharacters = game.spam.literallyEveryUnicodeEver;
let garbage = "";
for (let i = 0; i < garbageLength; i++) garbage += garbageCharacters[Math.floor(Math.random() * garbageCharacters.length)];
return garbage;
}
function isEven(number) {
return number % 2 === 0;
};
function isEntityOccupied(x, y) {
const cell = game.world.entityGrid.getCellIndexes(x, y, { width: 1, height: 1 });
const entity = game.world.entityGrid.getEntitiesInCell(cell);
return Object.keys(entity).length > 0;
};
function placeWallBlock(blockWidth, blockHeight, data) {
const widthOffset = isEven(blockWidth) ? 0 : 1;
const heightOffset = isEven(blockHeight) ? 0 : 1;
for (let x = -((blockWidth - widthOffset) / 2) * 48; x <= (blockWidth - widthOffset) / 2 * 48; x += 48) {
for (let y = -((blockHeight - heightOffset) / 2) * 48; y <= (blockHeight - heightOffset) / 2 * 48; y += 48) {
const posX = data.x + x,
posY = data.y + y,
shouldPlace = !isEntityOccupied(posX, posY);
shouldPlace && game.network.sendPacket(9, {name: "MakeBuilding", type: "Wall", x: posX, y: posY, yaw: 0});
};
};
};
function sellAllByType(type) {
if (!game.ui.playerPartyCanSell) return;
let lastSoldBuilding = null;
let allBuildings = [Infinity, ...Object.values(game.ui.buildings).filter(e => e.type == type)];
let sellInterval = () => {
if (!game.ui.buildings[lastSoldBuilding?.uid]) allBuildings.shift();
if (window.sellBreak || allBuildings.length == 0) return;
const target = allBuildings[0];
if (target !== undefined && !game.ui.buildings[target]?.dead) {
lastSoldBuilding = target;
Game.currentGame.network.sendRpc({
name: "DeleteBuilding",
uid: parseInt(target.uid)
});
setTimeout(sellInterval, 50);
};
};
sellInterval();
};
function sellAll() {
game.ui.components.BuildingOverlay.isSellingAll = true;
const sellInterval = () => {
if (window.sellBreak) return;
if (Object.keys(game.ui.buildings).length > 1 && game.ui.playerPartyCanSell) {
Game.currentGame.network.sendRpc({
name: "DeleteBuilding",
uid: parseInt(Object.keys(game.ui.buildings)[1])
});
setTimeout(() => { sellInterval(); }, 100);
Object.keys(game.ui.buildings).length == 2 && (game.ui.components.BuildingOverlay.isSellingAll = false);
}
}
sellInterval();
}
const measureDistance = (obj1, obj2) => {
if (!(obj1.x && obj1.y && obj2.x && obj2.y)) return Infinity;
let xDif = obj2.x - obj1.x;
let yDif = obj2.y - obj1.y;
return Math.abs((Math.pow(xDif, 2)) + (Math.pow(yDif, 2)));
};
function getByValue(map, searchValue) {
for (let [key, value] of map.entries()) {
if (equal(value, searchValue)) return key;
}
}
function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;) {
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
}
for (i = length; i-- !== 0;) {
var key = keys[i];
if (!equal(a[key], b[key])) return false;
}
return true;
}
return a!==a && b!==b;
};
const addFunctionToElem = ({ id, option, buttonText, colors, isToggle, callback, onCallback, offCallback }) => {
const options = game.options.options;
colors ||= 'btn-red?btn-theme';
getId(id).addEventListener('click', e => {
if (isToggle === false) {
callback?.();
} else {
let toggleColor = colors.split('?');
if (options[option] === false) {
options[option] = true;
toggleColor[1] && e.target.classList.remove(toggleColor[1]);
e.target.classList.add(toggleColor[0]);
buttonText === undefined || (e.target.innerText = `Disable ${buttonText}`);
onCallback?.();
} else {
options[option] = false;
e.target.classList.remove(toggleColor[0]);
toggleColor[1] && e.target.classList.add(toggleColor[1]);
buttonText === undefined || (e.target.innerText = `Enable ${buttonText}`);
offCallback?.();
}
};
});
}
function counter(e = 0) {
if (e <= -0.99949999999999999e24) {
return Math.round(e/-1e23)/-10 + "TT";
}
if (e <= -0.99949999999999999e21) {
return Math.round(e/-1e20)/-10 + "TB";
}
if (e <= -0.99949999999999999e18) {
return Math.round(e/-1e17)/-10 + "TM";
}
if (e <= -0.99949999999999999e15) {
return Math.round(e/-1e14)/-10 + "TK";
}
if (e <= -0.99949999999999999e12) {
return Math.round(e/-1e11)/-10 + "T";
}
if (e <= -0.99949999999999999e9) {
return Math.round(e/-1e8)/-10 + "B";
}
if (e <= -0.99949999999999999e6) {
return Math.round(e/-1e5)/-10 + "M";
}
if (e <= -0.99949999999999999e3) {
return Math.round(e/-1e2)/-10 + "K";
}
if (e <= 0.99949999999999999e3) {
return Math.round(e) + "";
}
if (e <= 0.99949999999999999e6) {
return Math.round(e/1e2)/10 + "K";
}
if (e <= 0.99949999999999999e9) {
return Math.round(e/1e5)/10 + "M";
}
if (e <= 0.99949999999999999e12) {
return Math.round(e/1e8)/10 + "B";
}
if (e <= 0.99949999999999999e15) {
return Math.round(e/1e11)/10 + "T";
}
if (e <= 0.99949999999999999e18) {
return Math.round(e/1e14)/10 + "TK";
}
if (e <= 0.99949999999999999e21) {
return Math.round(e/1e17)/10 + "TM";
}
if (e <= 0.99949999999999999e24) {
return Math.round(e/1e20)/10 + "TB";
}
if (e <= 0.99949999999999999e27) {
return Math.round(e/1e+23)/10 + "TT";
}
if (e >= 0.99949999999999999e27) {
return Math.round(e/1e+23)/10 + "TT";
}
}
const getClock = (_date) => {
let date = _date || new Date(),
d = date.getDate(),
d1 = date.getDay(),
h = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds(),
session = "PM";
if (h == 2){
h = 12;
};
if (h < 13) {
session = "AM"
};
if (h > 12){
session = "PM";
h -= 12;
};
h = (h < 10) ? "0" + h : h;
m = (m < 10) ? "0" + m : m;
s = (s < 10) ? "0" + s : s;
return `${h}:${m} ${session}`;
}
function msToTime(s) {
// Pad to 2 or 3 digits, default is 2
function pad(n, z) {
z = z || 2;
return ('00' + n).slice(-z);
}
var ms = s % 1000;
s = (s - ms) / 1000;
var secs = s % 60;
s = (s - secs) / 60;
var mins = s % 60;
var hrs = (s - mins) / 60;
return pad(hrs) + ':' + pad(mins) + ':' + pad(secs) + '.' + pad(ms, 3);
}
function ssMode() {
const mba = document.querySelectorAll([".hud-bottom-right", ".hud-bottom-left", ".hud-bottom-center", ".hud-center-left", ".hud-center-right", ".hud-chat", ".hud-top-right", ".hud-center-toolbar"]);
for (let mb of mba) {
if (mb.classList[0] !== "hud-center-toolbar") mb.style.display = (mb.style.display === "none") ? "block" : "none";
else mb.style.display = (mb.style.display === "none") ? "flex" : "none";
}
document.querySelector(".hud-bottom-right").appendChild(document.querySelector("#hud-shield-bar"));
document.querySelector(".hud-bottom-right").appendChild(document.querySelector("#hud-health-bar"));
document.querySelector(".hud-bottom-right").insertAdjacentElement("afterbegin", document.querySelector("#hud-party-icons"));
document.querySelector(".hud-bottom-left").insertAdjacentElement("afterbegin", document.querySelector("#hud-day-night-ticker"));
};
// @TickUpdates
game.tickUpdate = {
playerTickUpdate: {
resourceElem: game.ui.components.Resources,
hasEquipedPotion: false,
lastTickHealth: 100,
onTick: function(player) {
const options = game.options.options;
/* const playerHealth = (player.health / player.maxHealth) * 100;
const healThreshold = getId("auto-heal-threshold").valueAsNumber || 25;
if (options.autoHeal && playerHealth <= healThreshold) this.healPlayer(); */
if (options.autoHeal) {
if (!game.ui.inventory.HealthPotion && player.gold >= 100) {
Game.currentGame.network.sendRpc({name: "BuyItem", itemName: "HealthPotion", tier: 1});
};
const playerHealth = (player.health / player.maxHealth) * 100;
this.hasEquipedPotion = (this.lastTickHealth <= playerHealth);
const healThreshold = getId("auto-heal-threshold").valueAsNumber || 15;
if (playerHealth <= healThreshold && !this.hasEquipedPotion) {
Game.currentGame.network.sendRpc({name: "EquipItem", itemName: "HealthPotion", tier: 1});
};
this.lastTickHealth = playerHealth;
};
if (!options.frss) return;
const resources = ["wood", "stone", "gold"];
for (let rs of resources) {
this.resourceElem[`${rs}Elem`].innerHTML = Math.round(player[rs]).toLocaleString();
};
this.resourceElem.tokensElem.innerHTML = Math.round(player.token).toLocaleString();
},
},
petTickUpdate: {
buyItem: (itemName, tier = 1) => Game.currentGame.network.sendRpc({name: "BuyItem", itemName, tier}),
equipItem: (itemName, tier = 1) => Game.currentGame.network.sendRpc({name: "EquipItem", itemName, tier}),
petLevelEnum: [8, 16, 24, 32, 48, 64, 96],
petTokenEnum: [100, 100, 100, 100, 200, 200, 300, Infinity],
onTick: function(pet) {
const options = game.options.options;
if (options.autoHeal) {
if (pet.health <= 0) {
this.buyItem("PetRevive");
this.equipItem("PetRevive");
}
let petHealth = (pet.health / pet.maxHealth) * 100;
const healThreshold = getId("auto-heal-threshold").valueAsNumber || 25;
if (petHealth <= healThreshold) {
this.buyItem('PetHealthPotion');
this.equipItem("PetHealthPotion");
}
};
this.petLevelEnum.indexOf(game.ui.components.MenuShop.shopItems[pet.model].level) > -1 && (
game.ui.playerTick.token >= this.petTokenEnum[pet.tier - 1] && this.buyItem(pet.model, pet.tier + 1)
)
},
},
};
/* @Handlers + Bindings */
game.network.sendRpc = function(data) {
if (data.name === "MakeBuilding" && data.type === "Wall" && game.options.options.wallBlock) {
const blockWidth = document.querySelector('#blockX').valueAsNumber;
const blockHeight = document.querySelector('#blockY').valueAsNumber;
placeWallBlock(blockWidth, blockHeight, data);
return;
};
this.sendPacket(9, data);
};
game.network.addEntityUpdateHandler((e) => {
const {entities} = e;
const options = game.options.options;
if (options.autoBow) {
game.network.sendInput({space: 0});
game.network.sendInput({space: 1});
};
if (options.autoUpgrade) {
for (let uid in game.ui.buildings) {
const building = game.ui.buildings[uid];
if (building?.type !== "GoldStash" && building?.tier >= game.rebuilder.goldStash.tier) continue;
if (building?.dead || !(uid in game.world.entities)) continue;
game.network.sendRpc({name: "UpgradeBuilding", uid: parseInt(uid)});
};
};
game.autoUpTowers.onTick(e);
game.ahrc.onTick();
game.rssOverhead.onTick(entities);
game.rebuilder.onTick(entities);
game.autoAim.onTick();
});
game.spam.fetchUnicode();
game.network.addRpcHandler("LocalBuilding", (buildings) => {
game.rebuilder.onLocalBuilding(buildings);
});
game.ui._events.playerPetTickUpdate.push(game.tickUpdate.petTickUpdate.onTick.bind(game.tickUpdate.petTickUpdate));
game.ui._events.playerTickUpdate.push(game.tickUpdate.playerTickUpdate.onTick.bind(game.tickUpdate.playerTickUpdate));
(function MapFunctionsToElem() {
for (let page in menu) {
const [optionsElem, moreElem] = document.querySelectorAll("#" + page + " > div");
for (let option in menu[page]) {
const {name, description, more, isToggle, callback, customButtonText, onCallback, offCallback} = menu[page][option];
const hasMore = !!more;
const itemElem = document.createElement("div");
itemElem.innerHTML = `
<h2>${name}</h2>
<span>${description}</span>
${game.options.options[option] === undefined ? "" : `
<button id="toggle-${option}" ${game.options.options[option] ? `class="underline-red"` : ""}>
${game.options.options[option] ? "Disable" : "Enable"}
</button>
`}
${isToggle === false ? `<button id="${name}">${customButtonText}</button>` : ""}
${hasMore ? `<a id="more-${option}"></a>` : ""}
`;
optionsElem.appendChild(itemElem);
if (hasMore) {
const {html, functions, bind} = more;
const moreContainer = document.createElement("div");
moreContainer.innerHTML = html;
moreContainer.style.display = "none";
moreElem.appendChild(moreContainer);
functions?.();
const toggleElem = getId("more-" + option);
toggleElem.onclick = () => {
refreshMore(page);
bind?.();
moreContainer.style.display = "block";
}
}
if (!(game.options.options[option] === undefined)) {
addFunctionToElem({id: 'toggle-' + option, option, buttonText: '', colors: "underline-red?", isToggle, callback, onCallback, offCallback});
} else if (isToggle === false) {
addFunctionToElem({id: name, option, buttonText: '', colors: "underline-red?", isToggle, callback, onCallback, offCallback});
};
}
}
})();
/* @Keybinds */
document.addEventListener('keydown', function(e) {
if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
if (e.key == "/") {
game.network.sendRpc({name: "EquipItem", itemName: "PetCARL", tier: game.ui.inventory?.PetCARL?.tier || 1});
}
if (e.key === "?") {
ssMode();
};
}
});
document.addEventListener('keyup', function(e) {
if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") {
if (e.key == "~") {
game.markers.placeMarker({
x: game.ui.playerTick.position.x,
y: game.ui.playerTick.position.y,
timeout: false,
shouldIndicateIndex: true,
});
}
if (e.key == '-') {
game.options.options.getRSS = !game.options.options.getRSS;
}
if (e.key == "=") {
game.world.inWorld && (
game.ui.playerTick.gold > 100 && (
game.ui.inventory.Bow || (
game.network.sendRpc({name: "BuyItem", itemName: "Bow", tier: 1}),
game.ui.inventory.Bow = {itemName: 'Bow', tier: 1, stacks: 1}
)
),
game.ui.inventory.Bow && (
game.options.options.autoBow = !game.options.options.autoBow,
game.options.options.autoBow && game.network.sendRpc({name: "EquipItem", itemName: "Bow", tier: game.ui.inventory.Bow.tier})
)
)
}
if (e.key == ",") {
getId('toggle-rebuild').click();
}
if (e.key == ".") {
getId("toggle-autoUpgrade").click();
}
if (e.key == ";") {
game.ui.getPlayerPetUid() && Game.currentGame.network.sendRpc({name: "DeleteBuilding", uid: game.ui.getPlayerPetUid()});
}
if (e.key == "'") {
game.ui.getPlayerPetUid() && (
game.network.sendRpc({name: "BuyItem", itemName: "PetRevive", tier: 1}),
game.network.sendRpc({name: "EquipItem", itemName: "PetRevive", tier: 1})
);
}
if (e.key == "+") {
window.viewMapChunks();
}
if (e.code == 'KeyG') {
const wheelDisplay = getClass('interaction-wheel')[0];
wheelDisplay.style.display = (wheelDisplay.style.display === 'block') ? 'none' : 'block';
}
if (e.code == 'KeyC' && !e.ctrlKey) {
setTimeout(() => {
document.querySelector('#joinWithPsk').style.display = 'block';
document.querySelector('#joinWithPsk').focus();
document.querySelector('#joinWithPsk').value = "";
}, 100);
}
if (e.code == "KeyN") {
game.zoom.zoomIn();
}
if (e.code == "KeyM") {
game.zoom.zoomOut();
}
if (e.key == "Escape") {
window.exitViewMapChunks();
getClass('interaction-wheel')[0].style.display = 'none';
}
if (e.key == "!") {
getId("toggle-wallBlock").click();
}
}
});
document.querySelector('#joinWithPsk').addEventListener('keyup', (e) => {
if (e.key == "Enter" || e.key == "Escape") {
e.target.style.display = 'none';
(e.key == "Enter") && game.network.sendRpc({name: "JoinPartyByShareKey", partyShareKey: e.target.value});
};
});