UNPKG

hlviewer.js

Version:

View GoldSrc maps and replays in browser

1,912 lines 173 kB
var vs = Object.defineProperty; var xs = (e, t, s) => t in e ? vs(e, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : e[t] = s; var f = (e, t, s) => xs(e, typeof t != "symbol" ? t + "" : t, s); let rt = () => ({ emit(e, ...t) { for (let s = this.events[e] || [], n = 0, i = s.length; n < i; n++) s[n](...t); }, events: {}, on(e, t) { var s; return ((s = this.events)[e] || (s[e] = [])).push(t), () => { var n; this.events[e] = (n = this.events[e]) == null ? void 0 : n.filter((i) => t !== i); }; } }); const dt = performance.now.bind(performance), Tt = (e) => { const t = Math.floor(e / 60), s = Math.floor(e - t * 60), n = t < 10 ? `0${t}` : t.toString(), i = s < 10 ? `0${s}` : s.toString(); return `${n}:${i}`; }, $t = new AudioContext(); class Qt { constructor() { f(this, "context"); f(this, "channels"); f(this, "masterGain"); f(this, "preMuteVolume"); f(this, "events"); this.context = $t, this.events = rt(); const t = Number.parseFloat(localStorage.getItem("volume") || "0.3"); localStorage.setItem("volume", t.toString()), this.channels = [], this.preMuteVolume = 1, this.masterGain = this.context.createGain(), this.masterGain.gain.value = t, this.masterGain.connect(this.context.destination); for (let s = 0; s < 8; ++s) this.channels.push({ source: null, gain: this.context.createGain() }), this.channels[s].gain.connect(this.masterGain); } static getContext() { return $t; } play(t, s, n) { this.stop(s); const i = this.channels[s].gain; i.gain.value = Math.max(0, Math.min(1, n)); const o = this.context.createBufferSource(); o.buffer = t.buffer, o.connect(i), o.start(0), this.channels[s].source = o; } stop(t) { const s = this.channels[t].source; s && s.stop(0); } getVolume() { return this.masterGain.gain.value; } setVolume(t) { const s = this.masterGain.gain.value; s > 0 && t === 0 && (this.preMuteVolume = s), this.masterGain.gain.value = t, localStorage.setItem("volume", t.toString()), this.events.emit("volumeChange", t); } toggleMute() { this.getVolume() === 0 ? this.setVolume(this.preMuteVolume) : this.setVolume(0); } } class _t { constructor(t) { f(this, "index"); f(this, "name"); f(this, "buffer"); this.index = -1, this.name = "", this.buffer = t; } static create(t) { return new Promise((s, n) => { Qt.getContext().decodeAudioData( t, (i) => { s(new _t(i)); }, (i) => { n(i); } ); }); } } function Kt(e, t) { return e.slice(e.lastIndexOf("/") + 1).replace(t || "", ""); } function ws(e) { const t = e.lastIndexOf("/"), s = e.lastIndexOf("."); return t < s ? e.slice(s) : ""; } var D = /* @__PURE__ */ ((e) => (e[e.UByte = 0] = "UByte", e[e.Byte = 1] = "Byte", e[e.UShort = 2] = "UShort", e[e.Short = 3] = "Short", e[e.UInt = 4] = "UInt", e[e.Int = 5] = "Int", e[e.Float = 6] = "Float", e[e.Double = 7] = "Double", e[e.NString = 8] = "NString", e[e.String = 9] = "String", e))(D || {}); class fe { constructor(t) { f(this, "data"); f(this, "offset"); this.data = new DataView(t), this.offset = 0; } length() { return this.data.byteLength; } tell() { return this.offset; } seek(t) { this.offset = Math.max(0, t); } skip(t) { this.seek(this.tell() + t); } b() { const t = this.data.getInt8(this.offset); return this.skip(1), t; } ub() { const t = this.data.getUint8(this.offset); return this.skip(1), t; } s(t = !0) { const s = this.data.getInt16(this.offset, t); return this.skip(2), s; } us(t = !0) { const s = this.data.getUint16(this.offset, t); return this.skip(2), s; } i(t = !0) { const s = this.data.getInt32(this.tell(), t); return this.skip(4), s; } ui(t = !0) { const s = this.data.getUint32(this.tell(), t); return this.skip(4), s; } f(t = !0) { const s = this.data.getFloat32(this.tell(), t); return this.skip(4), s; } lf(t = !0) { const s = this.data.getFloat64(this.tell(), t); return this.skip(8), s; } str() { let t = this.ub(), s = ""; for (; t !== 0; ) s += String.fromCharCode(t), t = this.ub(); return s; } nstr(t) { let s = t; if (s < 0) return ""; let n = ""; for (; s > 0; ) { s -= 1; const i = this.ub(); if (i === 0) break; n += String.fromCharCode(i); } return s !== 0 && this.skip(s), n; } arr(t, s) { let n = t; s.bind(this); const i = []; for (; n-- > 0; ) i.push(s()); return i; } arrx(t, s, n = 0) { switch (s) { case 0: { const i = new Uint8Array(this.data.buffer, this.tell(), t); return this.skip(t), i; } case 1: { const i = new Int8Array(this.data.buffer, this.tell(), t); return this.skip(t), i; } case 2: { const i = new Uint16Array(this.data.buffer, this.tell(), t); return this.skip(t * 2), i; } case 3: { const i = new Int16Array(this.data.buffer, this.tell(), t); return this.skip(t * 2), i; } case 4: { const i = new Uint32Array(this.data.buffer, this.tell(), t); return this.skip(t * 4), i; } case 5: { const i = new Int32Array(this.data.buffer, this.tell(), t); return this.skip(t * 4), i; } case 6: { const i = new Float32Array(this.data.buffer, this.tell(), t); return this.skip(t * 4), i; } case 7: { const i = new Float64Array(this.data.buffer, this.tell(), t); return this.skip(t * 8), i; } case 8: { let i = t; const o = []; for (; i-- > 0; ) o.push(this.nstr(n)); return o; } case 9: { let i = t; const o = []; for (; i-- > 0; ) o.push(this.str()); return o; } } } } class Mt { constructor(t, s, n, i) { f(this, "name"); f(this, "width"); f(this, "height"); f(this, "data"); this.name = t, this.width = s, this.height = n, this.data = i; } static parse(t, s) { const n = new fe(t), i = { idLength: n.ub(), colorMapType: n.ub(), imageType: n.ub(), colorMap: { firstEntryIndex: n.us(), length: n.us(), size: n.ub() }, image: { xOrigin: n.us(), yOrigin: n.us(), width: n.us(), height: n.us(), depth: n.ub(), descriptor: n.ub() } }; if (i.idLength && n.arrx(i.idLength, D.UByte), i.colorMapType) throw new Error("Not implemented"); const o = i.image.width, a = i.image.height, r = o * a; let l = new Uint8Array(0); if (i.imageType === 2) { const c = r * i.image.depth / 8; if (l = n.arrx(c, D.UByte), i.image.depth === 24) { const u = new Uint8Array(r * 4); for (let h = 0; h < a; ++h) for (let m = 0; m < o; ++m) { const g = (a - 1 - h) * o + m; u[g * 4] = l[(h * o + m) * 3 + 2], u[g * 4 + 1] = l[(h * o + m) * 3 + 1], u[g * 4 + 2] = l[(h * o + m) * 3], u[g * 4 + 3] = 255; } l = u; } else if (i.image.depth === 32) { const u = new Uint8Array(r * 4); for (let h = 0; h < a; ++h) for (let m = 0; m < o; ++m) { const g = (a - 1 - h) * o + m; u[g * 4] = l[(h * o + m) * 4 + 2], u[g * 4 + 1] = l[(h * o + m) * 4 + 1], u[g * 4 + 2] = l[(h * o + m) * 4], u[g * 4 + 3] = 255; } l = u; } } else if (i.imageType === 10 && (l = new Uint8Array(r * 4), i.image.depth === 24)) for (let c = 0; c < a; ++c) for (let u = 0; u < o; ) { let h = n.ub(); if (h & 128) { h = (h & 127) + 1; const m = n.ub(), g = n.ub(), d = n.ub(); for (; u < o && h; ) { const p = (a - 1 - c) * o + u; l[p * 4] = d, l[p * 4 + 1] = g, l[p * 4 + 2] = m, l[p * 4 + 3] = 255, ++u, --h; } } else for (h = (h & 127) + 1; u < o && h; ) { const m = (a - 1 - c) * o + u; l[m * 4 + 2] = n.ub(), l[m * 4 + 1] = n.ub(), l[m * 4] = n.ub(), l[m * 4 + 3] = 255, ++u, --h; } } return new Mt(s, i.image.width, i.image.height, l); } } function ot(e, t) { const s = new Uint8Array(e.length * 4), n = e.length; for (let i = 0; i < n; ++i) s[i * 4] = t[e[i] * 3], s[i * 4 + 1] = t[e[i] * 3 + 1], s[i * 4 + 2] = t[e[i] * 3 + 2], s[i * 4 + 3] = 255; return s; } function Se(e, t) { const s = new Uint8Array(e.length * 4), n = e.length; for (let i = 0; i < n; ++i) e[i] === 255 ? s[i * 4 + 3] = 0 : (s[i * 4] = t[e[i] * 3], s[i * 4 + 1] = t[e[i] * 3 + 1], s[i * 4 + 2] = t[e[i] * 3 + 2], s[i * 4 + 3] = 255); return s; } function bs(e) { const t = e.nstr(16), s = e.ui(), n = e.ui(); e.skip(4 * 4); const i = s * n, o = e.arrx(i, D.UByte); e.skip(21 * (i / 64)), e.skip(2); const a = e.arrx(768, D.UByte), r = t[0] === "{" ? Se(o, a) : ot(o, a); return { type: "decal", name: t, width: s, height: n, data: r }; } const ys = (e, t) => ({ type: "cache", name: t.name }); function ks(e) { const t = e.nstr(16), s = e.ui(), n = e.ui(); e.skip(4 * 4); const i = s * n, o = e.arrx(i, D.UByte); e.skip(21 * (i / 64)), e.skip(2); const a = e.arrx(768, D.UByte), r = t[0] === "{" ? Se(o, a) : ot(o, a); return { type: "texture", name: t, width: s, height: n, data: r }; } function As(e, t) { const s = e.ui() && 256, n = e.ui(), i = e.ui(), o = e.ui(), a = []; for (let u = 0; u < 256; ++u) { const h = e.us(), m = e.us(); a.push({ x: h % s, y: Math.floor(h / s) / o * o, width: m, height: o }); } const r = s * n, l = e.arrx(r, D.UByte); e.skip(2); const c = e.arrx(256 * 3, D.UByte); return { type: "font", name: t.name, width: s, height: n, rowCount: i, rowHeight: o, glyphs: a, data: Se(l, c) }; } const Is = (e, t) => ({ type: "unknown", name: t.name, data: e.arrx(t.length, D.UByte) }); function _s(e, t) { switch (e.seek(t.offset), t.type) { case 64: return bs(e); case 66: return ys(e, t); case 67: return ks(e); case 70: return As(e, t); default: return Is(e, t); } } class Rt { constructor(t) { f(this, "entries"); this.entries = t; } static parse(t) { const s = new fe(t); if (s.nstr(4) !== "WAD3") throw new Error("Invalid WAD file format"); const i = s.ui(), o = s.ui(); s.seek(o); const a = []; for (let l = 0; l < i; ++l) { const c = { offset: s.ui(), diskLength: s.ui(), length: s.ui(), type: s.b(), isCompressed: s.b(), name: "" }; s.skip(2), c.name = s.nstr(16), a.push(c); } const r = a.map((l) => _s(s, l)); return new Rt(r); } } class mt { constructor(t) { f(this, "name"); f(this, "chunks"); f(this, "resources"); this.name = Kt(t, ".bsp"), this.chunks = [], this.resources = { sounds: [], skins: [], models: [], decals: [], custom: [], events: [] }; } setResources(t) { for (const s of t) switch (s.type) { case 0: { s.used = !1, this.resources.sounds.push(s); break; } case 1: { this.resources.skins.push(s); break; } case 2: { this.resources.models.push(s); break; } case 3: { this.resources.decals.push(s); break; } case 4: { this.resources.custom.push(s); break; } case 5: { this.resources.events.push(s); break; } } } addChunk(t) { this.chunks.push(t); } } class gt { constructor(t, s) { f(this, "state"); f(this, "startTime"); f(this, "timeLength"); f(this, "data"); f(this, "reader"); this.state = t.clone(), this.startTime = s, this.timeLength = 10, this.data = null, this.reader = null; } setData(t) { this.data = new Uint8Array(t.length); for (let s = 0; s < t.length; ++s) this.data[s] = t[s]; this.reader = new fe(this.data.buffer); } } class at { constructor(t = null) { f(this, "cameraPos"); f(this, "cameraRot"); f(this, "entities"); t ? (this.cameraPos = JSON.parse(JSON.stringify(t.cameraPos)), this.cameraRot = JSON.parse(JSON.stringify(t.cameraRot)), this.entities = JSON.parse(JSON.stringify(t.entities))) : (this.cameraPos = [0, 0, 0], this.cameraRot = [0, 0, 0], this.entities = []); } feedFrame(t) { switch (t.type) { case 0: case 1: { this.cameraPos[0] = t.camera.position[0], this.cameraPos[1] = t.camera.position[1], this.cameraPos[2] = t.camera.position[2], this.cameraRot[0] = t.camera.orientation[0], this.cameraRot[1] = t.camera.orientation[1], this.cameraRot[2] = t.camera.orientation[2]; break; } } } clone() { return new at(this); } } function pt(e) { const t = e.readBits(1), s = e.readBits(1); if (!t && !s) return 0; const n = e.readBits(1); let i = 0, o = 0; t && (i = e.readBits(12)), s && (o = e.readBits(3)); let a = i + o / 32; return n && (a = -a), a; } var U = /* @__PURE__ */ ((e) => (e[e.DT_BYTE = 1] = "DT_BYTE", e[e.DT_SHORT = 2] = "DT_SHORT", e[e.DT_FLOAT = 4] = "DT_FLOAT", e[e.DT_INTEGER = 8] = "DT_INTEGER", e[e.DT_ANGLE = 16] = "DT_ANGLE", e[e.DT_TIMEWINDOW_8 = 32] = "DT_TIMEWINDOW_8", e[e.DT_TIMEWINDOW_BIG = 64] = "DT_TIMEWINDOW_BIG", e[e.DT_STRING = 128] = "DT_STRING", e[e.DT_SIGNED = -2147483648] = "DT_SIGNED", e))(U || {}); function te(e, t) { const s = {}, n = e.readBits(3), i = []; for (let a = 0; a < n; ++a) i.push(e.readBits(8)); let o = !1; for (let a = 0; a < n; ++a) { for (let r = 0; r < 8; ++r) { const l = r + a * 8; if (l === t.length) { o = !0; break; } if (i[a] & 1 << r) if (t[l].flags & U.DT_BYTE) if (t[l].flags & U.DT_SIGNED) { const c = e.readBits(1) ? -1 : 1, u = e.readBits(t[l].bits - 1), h = t[l].divisor; s[t[l].name] = c * u / h; } else { const c = e.readBits(t[l].bits), u = t[l].divisor; s[t[l].name] = c / u; } else if (t[l].flags & U.DT_SHORT) if (t[l].flags & U.DT_SIGNED) { const c = e.readBits(1) ? -1 : 1, u = e.readBits(t[l].bits - 1), h = t[l].divisor; s[t[l].name] = c * u / h; } else { const c = e.readBits(t[l].bits), u = t[l].divisor; s[t[l].name] = c / u; } else if (t[l].flags & U.DT_INTEGER) if (t[l].flags & U.DT_SIGNED) { const c = e.readBits(1) ? -1 : 1, u = e.readBits(t[l].bits - 1), h = t[l].divisor; s[t[l].name] = c * u / h; } else { const c = e.readBits(t[l].bits), u = t[l].divisor; s[t[l].name] = c / u; } else if (t[l].flags & U.DT_FLOAT || t[l].flags & U.DT_TIMEWINDOW_8 || t[l].flags & U.DT_TIMEWINDOW_BIG) if (t[l].flags & U.DT_SIGNED) { const c = e.readBits(1) ? -1 : 1, u = e.readBits(t[l].bits - 1), h = t[l].divisor; s[t[l].name] = c * u / h; } else { const c = e.readBits(t[l].bits), u = t[l].divisor; s[t[l].name] = c / u; } else if (t[l].flags & U.DT_ANGLE) { const c = e.readBits(t[l].bits), u = 360 / (1 << t[l].bits); s[t[l].name] = c * u; } else t[l].flags & U.DT_STRING && (s[t[l].name] = e.readString()); } if (o) break; } return s; } const Ms = { delta_description_t: [ { name: "flags", bits: 32, divisor: 1, flags: U.DT_INTEGER }, { name: "name", bits: 8, divisor: 1, flags: U.DT_STRING }, { name: "offset", bits: 16, divisor: 1, flags: U.DT_INTEGER }, { name: "size", bits: 8, divisor: 1, flags: U.DT_INTEGER }, { name: "bits", bits: 8, divisor: 1, flags: U.DT_INTEGER }, { name: "divisor", bits: 32, divisor: 4e3, flags: U.DT_FLOAT }, { name: "preMultiplier", bits: 32, divisor: 4e3, flags: U.DT_FLOAT } ] }, Gt = () => ({ ...Ms }), ue = class ue { constructor(t) { f(this, "view"); this.view = new Uint8Array(t, 0, t.byteLength); } getBits(t, s, n = !1) { let i = t; const o = this.view.length * 8 - i; if (s > o) throw new Error("Bits out of bounds"); let a = 0; for (let r = 0; r < s; ) { const l = s - r, c = i & 7, u = this.view[i >> 3], h = Math.min(l, 8 - c), m = (1 << h) - 1, g = u >> c & m; a |= g << r, i += h, r += h; } return n ? (s !== 32 && a & 1 << s - 1 && (a |= -1 ^ (1 << s) - 1), a) : a >>> 0; } getInt8(t) { return this.getBits(t, 8, !0); } getUint8(t) { return this.getBits(t, 8, !1); } getInt16(t) { return this.getBits(t, 16, !0); } getUint16(t) { return this.getBits(t, 16, !1); } getInt32(t) { return this.getBits(t, 32, !0); } getUint32(t) { return this.getBits(t, 32, !1); } getFloat32(t) { return ue.scratch.setUint32(0, this.getUint32(t)), ue.scratch.getFloat32(0); } getFloat64(t) { return ue.scratch.setUint32(0, this.getUint32(t)), ue.scratch.setUint32(4, this.getUint32(t + 32)), ue.scratch.getFloat64(0); } }; f(ue, "scratch", new DataView(new ArrayBuffer(8))); let vt = ue; class Q { constructor(t) { f(this, "view"); f(this, "index"); this.view = new vt(t), this.index = 0; } readBits(t, s = !1) { const n = this.view.getBits(this.index, t, s); return this.index += t, n; } readInt8() { const t = this.view.getInt8(this.index); return this.index += 8, t; } readUint8() { const t = this.view.getUint8(this.index); return this.index += 8, t; } readInt16() { const t = this.view.getInt16(this.index); return this.index += 16, t; } readUint16() { const t = this.view.getUint16(this.index); return this.index += 16, t; } readInt32() { const t = this.view.getInt32(this.index); return this.index += 32, t; } readUint32() { const t = this.view.getUint32(this.index); return this.index += 32, t; } readFloat32() { const t = this.view.getFloat32(this.index); return this.index += 32, t; } readFloat64() { const t = this.view.getFloat64(this.index); return this.index += 64, t; } readString(t = 0, s = !1) { let n = 0; const i = []; let o = !0; for (; !t || t && n < t; ) { const r = this.readUint8(); if (r === 0 && (o = !1, !t)) break; o && i.push(r), n++; } const a = String.fromCharCode.apply(null, i); if (s) try { return decodeURIComponent(a); } catch { return a; } else return a; } } const T = { bad() { throw new Error("Invalid message type"); }, nop() { return null; }, disconnect(e) { return { reason: e.str() }; }, event(e, t) { const s = new Q(e.data.buffer); s.index = e.tell() * 8; const n = [], i = s.readBits(5); for (let o = 0; o < i; ++o) { const a = { index: s.readBits(10) }; s.readBits(1) && (a.packetIndex = s.readBits(11), s.readBits(1) && (a.delta = te(s, t.event_t))), s.readBits(1) && (a.fireTime = s.readBits(16)), n.push(a); } return s.index % 8 > 0 ? e.seek(Math.floor(s.index / 8) + 1) : e.seek(s.index / 8), { events: n }; }, version(e) { return { version: e.ui() }; }, setView(e) { return { entityIndex: e.s() }; }, sound(e) { const t = new Q(e.data.buffer); t.index = e.tell() * 8; const s = t.readBits(9); let n = 1; (s & 1) !== 0 && (n = t.readBits(8) / 255); let i = 1; (s & 2) !== 0 && (i = t.readBits(8) / 64); const o = t.readBits(3), a = t.readBits(11); let r; (s & 4) !== 0 ? r = t.readBits(16) : r = t.readBits(8); const l = t.readBits(1), c = t.readBits(1), u = t.readBits(1); let h = 0, m = 0, g = 0; l && (h = pt(t)), c && (m = pt(t)), u && (g = pt(t)); let d = 1; return (s & 8) !== 0 && (d = t.readBits(8)), t.index % 8 > 0 ? e.seek(Math.floor(t.index / 8) + 1) : e.seek(t.index / 8), { flags: s, volume: n, attenuation: i, channel: o, entityIndex: a, soundIndex: r, xPosition: h, yPosition: m, zPosition: g, pitch: d }; }, time(e) { return { time: e.f() }; }, print(e) { return { message: e.str() }; }, stuffText(e) { return { commands: e.str().split(";").map((n) => { const i = n.split(/\s*("[^"]+"|[^\s"]+)/).map((r) => r.replace(/^"(.*)"$/, "$1").trim()).filter((r) => r), o = i[0], a = i.slice(1); return { func: o, params: a }; }) }; }, setAngle(e) { return { pitch: e.s(), yaw: e.s(), roll: e.s() }; }, serverInfo(e) { const t = { protocol: e.i(), spawnCount: e.i(), // map change count mapCrc: e.i(), clientDllHash: e.arrx(16, D.UByte), maxPlayers: e.ub(), playerIndex: e.ub(), isDeathmatch: e.ub(), gameDir: e.str(), hostName: e.str(), mapFileName: e.str(), // path to map relative in mod directory mapCycle: e.str() }; return e.skip(1), t; }, lightStyle(e) { return { index: e.ub(), lightInfo: e.str() }; }, updateUserInfo(e) { return { clientIndex: e.ub(), clientUserId: e.ui(), clientUserInfo: e.str(), clientCdKeyHash: e.arrx(16, D.UByte) }; }, deltaDescription(e, t) { const s = { name: e.str(), fields: [] }, n = new Q(e.data.buffer), i = e.us(); n.index = e.tell() * 8; for (let o = 0; o < i; ++o) s.fields.push(te(n, t.delta_description_t)); return t[s.name] = s.fields, n.index % 8 > 0 ? e.seek(Math.floor(n.index / 8) + 1) : e.seek(n.index / 8), s; }, clientData(e, t) { const s = new Q(e.data.buffer); s.index = e.tell() * 8, s.readBits(1) && (s.index += 8); const i = t.clientdata_t, o = te(s, i), a = t.weapon_data_t; for (; s.readBits(1); ) s.index += 6, te(s, a); return s.index % 8 > 0 ? e.seek(Math.floor(s.index / 8) + 1) : e.seek(s.index / 8), { clientData: o }; }, stopSound(e) { return { entityIndex: e.s() }; }, pings(e) { const t = new Q(e.data.buffer); t.index = e.tell() * 8; const s = []; for (; t.readBits(1); ) s.push({ slot: t.readBits(8), ping: t.readBits(8), loss: t.readBits(8) }); return t.index % 8 > 0 ? e.seek(Math.floor(t.index / 8) + 1) : e.seek(t.index / 8), s; }, particle(e) { return { position: [e.s() / 8, e.s() / 8, e.s() / 8], direction: [e.b(), e.b(), e.b()], count: e.ub(), color: e.ub() }; }, damage() { return null; }, spawnStatic(e) { const t = { modelIndex: e.s(), sequence: e.b(), frame: e.b(), colorMap: e.s(), skin: e.b(), position: [], rotation: [] }; return t.position[0] = e.s() / 8, t.rotation[0] = e.b() * (360 / 256), t.position[1] = e.s() / 8, t.rotation[1] = e.b() * (360 / 256), t.position[2] = e.s() / 8, t.rotation[2] = e.b() * (360 / 256), t.renderMode = e.b(), t.renderMode && (t.renderAmt = e.b(), t.renderColor = [e.ub(), e.ub(), e.ub()], t.renderFx = e.b()), t; }, eventReliable(e, t) { const s = new Q(e.data.buffer); s.index = e.tell() * 8; const n = s.readBits(10), i = te(s, t.event_t), o = s.readBits(1); let a = 0; return o && (a = s.readBits(16)), s.index % 8 > 0 ? e.seek(Math.floor(s.index / 8) + 1) : e.seek(s.index / 8), { eventIndex: n, eventData: i, delayBit: o, delay: a }; }, spawnBaseLine(e, t) { const s = new Q(e.data.buffer); s.index = e.tell() * 8; const n = []; for (; ; ) { const r = s.readBits(11); if (r === 2047) break; const l = s.readBits(2); let c; l & 1 ? r > 0 && r <= 32 ? c = "entity_state_player_t" : c = "entity_state_t" : c = "custom_entity_state_t", n[r] = te(s, t[c]); } if (s.readBits(5) !== 31) throw new Error("Bad spawnbaseline"); const o = s.readBits(6), a = []; for (let r = 0; r < o; ++r) a.push(te(s, t.entity_state_t)); return s.index % 8 > 0 ? e.seek(Math.floor(s.index / 8) + 1) : e.seek(s.index / 8), { entities: n, extraData: a }; }, tempEntity(e) { const Ts = e.ub(), j = {}; switch (Ts) { case 0: { e.skip(24); break; } case 1: { e.skip(20); break; } case 2: { e.skip(6); break; } case 3: { e.skip(11); break; } case 4: { e.skip(6); break; } case 5: { e.skip(10); break; } case 6: { e.skip(12); break; } case 7: { e.skip(17); break; } case 8: { e.skip(16); break; } case 9: { e.skip(6); break; } case 10: { e.skip(6); break; } case 11: { e.skip(6); break; } case 12: { e.skip(8); break; } case 13: { e.skip(8), e.s() && e.skip(2); break; } case 14: { e.skip(9); break; } case 15: { e.skip(19); break; } case 17: { e.skip(10); break; } case 18: { e.skip(16); break; } case 19: { e.skip(24); break; } case 20: { e.skip(24); break; } case 21: { e.skip(24); break; } case 22: { e.skip(10); break; } case 23: { e.skip(11); break; } case 24: { e.skip(16); break; } case 25: { e.skip(19); break; } case 27: { e.skip(12); break; } case 28: { e.skip(16); break; } case 29: { j.channel = e.b(), j.x = e.s(), j.y = e.s(), j.effect = e.b(), j.textColor = [e.ub(), e.ub(), e.ub(), e.ub()], j.effectColor = [e.ub(), e.ub(), e.ub(), e.ub()], j.fadeInTime = e.s(), j.fadeOutTime = e.s(), j.holdTime = e.s(), j.effect && (j.effectTime = e.s()), j.message = e.str(); break; } case 30: { e.skip(17); break; } case 31: { e.skip(17); break; } case 99: { e.skip(2); break; } case 100: { e.skip(10); break; } case 101: { e.skip(14); break; } case 102: { e.skip(12); break; } case 103: { e.skip(14); break; } case 104: { e.skip(9); break; } case 105: { e.skip(5); break; } case 106: { e.skip(17); break; } case 107: { e.skip(13); break; } case 108: { e.skip(24); break; } case 109: { e.skip(9); break; } case 110: { e.skip(17); break; } case 111: { e.skip(7); break; } case 112: { e.skip(10); break; } case 113: { e.skip(19); break; } case 114: { e.skip(19); break; } case 115: { e.skip(12); break; } case 116: { e.skip(7); break; } case 117: { e.skip(7); break; } case 118: { e.skip(9); break; } case 119: { e.skip(16); break; } case 120: { e.skip(18); break; } case 121: { e.skip(5); break; } case 122: { e.skip(10); break; } case 123: { e.skip(9); break; } case 124: { e.skip(7); break; } case 125: { e.skip(1); break; } case 126: { e.skip(18); break; } case 127: { e.skip(15); break; } default: throw new Error("Unknown temp entity type"); } return j; }, setPause(e) { return { isPaused: e.b() }; }, signOnNum(e) { return { sign: e.b() }; }, centerPrint(e) { return { message: e.str() }; }, killedMonster() { return null; }, foundSecret() { return null; }, spawnStaticSound(e) { return { position: [e.s() / 8, e.s() / 8, e.s() / 8], soundIndex: e.us(), volume: e.ub() / 255, attenuation: e.ub() / 64, entityIndex: e.us(), pitch: e.ub(), flags: e.ub() }; }, intermission() { return null; }, finale(e) { return { text: e.str() }; }, cdTrack(e) { return { track: e.b(), loopTrack: e.b() }; }, restore(e) { const t = e.str(), s = e.ub(), n = []; for (let i = 0; i < s; ++i) n.push(e.str()); return { saveName: t, maps: n }; }, cutscene(e) { return { text: e.str() }; }, weaponAnim(e) { return { sequenceNumber: e.b(), weaponModelBodyGroup: e.b() }; }, decalName(e) { return { positionIndex: e.ub(), decalName: e.str() }; }, roomType(e) { return { type: e.us() }; }, addAngle(e) { return { angleToAdd: e.s() / (360 / 65536) }; }, newUserMsg(e) { return { index: e.ub(), size: e.b(), name: e.nstr(16) }; }, packetEntities(e, t) { const s = new Q(e.data.buffer); s.index = e.tell() * 8; const n = []; s.readBits(16); let i = 0; for (; s.readBits(16) !== 0; ) { s.index -= 16, s.readBits(1) ? i++ : s.readBits(1) ? i = s.readBits(11) : i += s.readBits(6); const r = s.readBits(1); s.readBits(1) && (s.index += 6); let c = "entity_state_t"; i > 0 && i <= 32 ? c = "entity_state_player_t" : r && (c = "custom_entity_state_t"), n.push(te(s, t[c])); } return s.index % 8 > 0 ? e.seek(Math.floor(s.index / 8) + 1) : e.seek(s.index / 8), { entityStates: n }; }, deltaPacketEntities(e, t) { const s = new Q(e.data.buffer); s.index = e.tell() * 8, s.readBits(16), s.index += 8; const n = []; let i = 0; for (; s.readBits(16) !== 0; ) { s.index -= 16; const a = s.readBits(1); if (s.readBits(1) ? i = s.readBits(11) : i += s.readBits(6), a) continue; const l = s.readBits(1); let c = "entity_state_t"; i > 0 && i < 32 ? c = "entity_state_player_t" : l && (c = "custom_entity_state_t"), n[i] = te(s, t[c]); } return s.index % 8 > 0 ? e.seek(Math.floor(s.index / 8) + 1) : e.seek(s.index / 8), { entityStates: n }; }, choke() { return null; }, resourceList(e) { const t = new Q(e.data.buffer); t.index = e.tell() * 8; const s = [], n = t.readBits(12); for (let i = 0; i < n; ++i) { const o = { type: t.readBits(4), name: t.readString(), index: t.readBits(12), size: t.readBits(24) }; t.readBits(3) & 4 && (t.index += 128), t.readBits(1) && (t.index += 256), s.push(o); } if (t.readBits(1)) for (; t.readBits(1); ) { const i = t.readBits(1) ? 5 : 10; t.index += i; } return t.index % 8 > 0 ? e.seek(Math.floor(t.index / 8) + 1) : e.seek(t.index / 8), s; }, newMoveVars(e) { return { gravity: e.f(), stopSpeed: e.f(), maxSpeed: e.f(), spectatorMaxSpeed: e.f(), acceleration: e.f(), airAcceleration: e.f(), waterAcceleration: e.f(), friction: e.f(), edgeFriction: e.f(), waterFriction: e.f(), entityGravity: e.f(), bounce: e.f(), stepSize: e.f(), maxVelocity: e.f(), zMax: e.f(), waveHeight: e.f(), footsteps: e.b(), rollAngle: e.f(), rollSpeed: e.f(), skyColor: [e.f(), e.f(), e.f()], skyVec: [e.f(), e.f(), e.f()], skyName: e.str() }; }, resourceRequest(e) { const t = { spawnCount: e.i() }; return e.skip(4), t; }, customization(e) { const t = e.ub(), s = e.ub(), n = e.str(), i = e.us(), o = e.ui(), a = e.ub(); let r = null; return a & 4 && (r = [e.i(), e.i(), e.i(), e.i()]), { playerIndex: t, type: s, name: n, index: i, downloadSize: o, flags: a, md5hash: r }; }, crosshairAngle(e) { return { pitch: e.b(), yaw: e.b() }; }, soundFade(e) { return { initialPercent: e.ub(), holdTime: e.ub(), fadeOutTime: e.ub(), fadeInTime: e.ub() }; }, fileTxferFailed(e) { return { filename: e.str() }; }, hltv(e) { return { mode: e.ub() }; }, director(e) { const t = e.ub(); return { flag: e.ub(), message: e.nstr(t - 1) }; }, voiceInit(e) { return { codecName: e.str(), quality: e.b() }; }, voiceData(e) { const t = e.ub(), s = e.us(), n = e.arrx(s, D.UByte); return { playerIndex: t, data: n }; }, sendExtraInfo(e) { return { fallbackDir: e.str(), canCheat: e.ub() }; }, timeScale(e) { return { timeScale: e.f() }; }, resourceLocation(e) { return { url: e.str() }; }, sendCvarValue(e) { return { name: e.str() }; }, sendCvarValue2(e) { return { requestId: e.ui(), name: e.str() }; } }, Rs = [ T.bad, // SVC_BAD 0 T.nop, // SVC_NOP 1 T.disconnect, // SVC_DISCONNECT 2 T.event, // SVC_EVENT 3 T.version, // SVC_VERSION 4 T.setView, // SVC_SETVIEW 5 T.sound, // SVC_SOUND 6 T.time, // SVC_TIME 7 T.print, // SVC_PRINT 8 T.stuffText, // SVC_STUFFTEXT 9 T.setAngle, // SVC_SETANGLE 10 T.serverInfo, // SVC_SERVERINFO 11 T.lightStyle, // SVC_LIGHTSTYLE 12 T.updateUserInfo, // SVC_UPDATEUSERINFO 13 T.deltaDescription, // SVC_DELTADESCRIPTION 14 T.clientData, // SVC_CLIENTDATA 15 T.stopSound, // SVC_STOPSOUND 16 T.pings, // SVC_PINGS 17 T.particle, // SVC_PARTICLE 18 T.damage, // SVC_DAMAGE 19 T.spawnStatic, // SVC_SPAWN 20 T.eventReliable, // SVC_EVENT_RELIABLE 21 T.spawnBaseLine, // SVC_SPAWNBASELINE 22 T.tempEntity, // SVC_TEMPENTITY 23 T.setPause, // SVC_SETPAUSE 24 T.signOnNum, // SVC_SIGNONNUM 25 T.centerPrint, // SVC_CENTERPRINT 26 T.killedMonster, // SVC_KILLEDMONSTER 27 T.foundSecret, // SVC_FOUNDSECRET 28 T.spawnStaticSound, // SVC_SPAWNSTATICSOUND 29 T.intermission, // SVC_INTERMISSION 30 T.finale, // SVC_FINALE 31 T.cdTrack, // SVC_CDTRACK 32 T.restore, // SVC_RESTORE 33 T.cutscene, // SVC_CUTSCENE 34 T.weaponAnim, // SVC_WEAPONANIM 35 T.decalName, // SVC_DECALNAME 36 T.roomType, // SVC_ROOMTYPE 37 T.addAngle, // SVC_ADDANGLE 38 T.newUserMsg, // SVC_NEWUSERMSG 39 T.packetEntities, // SVC_PACKETENTITIES 40 T.deltaPacketEntities, // SVC_DELTAPACKETENTITIES 41 T.choke, // SVC_CHOKE 42 T.resourceList, // SVC_RESOURCELIST 43 T.newMoveVars, // SVC_NEWMOVEVARS 44 T.resourceRequest, // SVC_RESOURCEREQUEST 45 T.customization, // SVC_CUSTOMIZATION 46 T.crosshairAngle, // SVC_CROSSHAIRANGLE 47 T.soundFade, // SVC_SOUNDFADE 48 T.fileTxferFailed, // SVC_FILETXFERFAILED 49 T.hltv, // SVC_HLTV 50 T.director, // SVC_DIRECTOR 51 T.voiceInit, // SVC_VOICEINIT 52 T.voiceData, // SVC_VOICEDATA 53 T.sendExtraInfo, // SVC_SENDEXTRAINFO 54 T.timeScale, // SVC_TIMESCALE 55 T.resourceLocation, // SVC_RESOURCELOCATION 56 T.sendCvarValue, // SVC_SENDCVARVALUE 57 T.sendCvarValue2 // SVC_SENDCVARVALUE2 58 ]; function es(e, t, s) { if (t === 0) return null; const n = Rs[t]; return n ? n(e, s) : null; } var le = /* @__PURE__ */ ((e) => (e[e.BAD = 0] = "BAD", e[e.NOP = 1] = "NOP", e[e.DISCONNECT = 2] = "DISCONNECT", e[e.EVENT = 3] = "EVENT", e[e.VERSION = 4] = "VERSION", e[e.SETVIEW = 5] = "SETVIEW", e[e.SOUND = 6] = "SOUND", e[e.TIME = 7] = "TIME", e[e.PRINT = 8] = "PRINT", e[e.STUFFTEXT = 9] = "STUFFTEXT", e[e.SETANGLE = 10] = "SETANGLE", e[e.SERVERINFO = 11] = "SERVERINFO", e[e.LIGHTSTYLE = 12] = "LIGHTSTYLE", e[e.UPDATEUSERINFO = 13] = "UPDATEUSERINFO", e[e.DELTADESCRIPTION = 14] = "DELTADESCRIPTION", e[e.CLIENTDATA = 15] = "CLIENTDATA", e[e.STOPSOUND = 16] = "STOPSOUND", e[e.PINGS = 17] = "PINGS", e[e.PARTICLE = 18] = "PARTICLE", e[e.DAMAGE = 19] = "DAMAGE", e[e.SPAWN = 20] = "SPAWN", e[e.EVENT_RELIABLE = 21] = "EVENT_RELIABLE", e[e.SPAWNBASELINE = 22] = "SPAWNBASELINE", e[e.TEMPENTITY = 23] = "TEMPENTITY", e[e.SETPAUSE = 24] = "SETPAUSE", e[e.SIGNONNUM = 25] = "SIGNONNUM", e[e.CENTERPRINT = 26] = "CENTERPRINT", e[e.KILLEDMONSTER = 27] = "KILLEDMONSTER", e[e.FOUNDSECRET = 28] = "FOUNDSECRET", e[e.SPAWNSTATICSOUND = 29] = "SPAWNSTATICSOUND", e[e.INTERMISSION = 30] = "INTERMISSION", e[e.FINALE = 31] = "FINALE", e[e.CDTRACK = 32] = "CDTRACK", e[e.RESTORE = 33] = "RESTORE", e[e.CUTSCENE = 34] = "CUTSCENE", e[e.WEAPONANIM = 35] = "WEAPONANIM", e[e.DECALNAME = 36] = "DECALNAME", e[e.ROOMTYPE = 37] = "ROOMTYPE", e[e.ADDANGLE = 38] = "ADDANGLE", e[e.NEWUSERMSG = 39] = "NEWUSERMSG", e[e.PACKETENTITIES = 40] = "PACKETENTITIES", e[e.DELTAPACKETENTITIES = 41] = "DELTAPACKETENTITIES", e[e.CHOKE = 42] = "CHOKE", e[e.RESOURCELIST = 43] = "RESOURCELIST", e[e.NEWMOVEVARS = 44] = "NEWMOVEVARS", e[e.RESOURCEREQUEST = 45] = "RESOURCEREQUEST", e[e.CUSTOMIZATION = 46] = "CUSTOMIZATION", e[e.CROSSHAIRANGLE = 47] = "CROSSHAIRANGLE", e[e.SOUNDFADE = 48] = "SOUNDFADE", e[e.FILETXFERFAILED = 49] = "FILETXFERFAILED", e[e.HLTV = 50] = "HLTV", e[e.DIRECTOR = 51] = "DIRECTOR", e[e.VOICEINIT = 52] = "VOICEINIT", e[e.VOICEDATA = 53] = "VOICEDATA", e[e.SENDEXTRAINFO = 54] = "SENDEXTRAINFO", e[e.TIMESCALE = 55] = "TIMESCALE", e[e.RESOURCELOCATION = 56] = "RESOURCELOCATION", e[e.SENDCVARVALUE = 57] = "SENDCVARVALUE", e[e.SENDCVARVALUE2 = 58] = "SENDCVARVALUE2", e))(le || {}); const Ls = (e) => e.nstr(8) === "HLDEMO", Xt = (e) => ({ demoProtocol: e.ui(), netProtocol: e.ui(), mapName: e.nstr(260), modName: e.nstr(260), mapCrc: e.i(), dirOffset: e.ui() }), Ht = (e, t) => { e.seek(t); const s = e.ui(), n = []; for (let i = 0; i < s; ++i) n.push({ id: e.ui(), name: e.nstr(64), flags: e.ui(), cdTrack: e.i(), time: e.f(), frames: e.ui(), offset: e.ui(), length: e.ui() }); return n; }, Ps = (e, t, s) => { const n = e.ui(), i = e.tell() + n, o = []; for (; e.tell() < i; ) { const a = e.ub(); if (a === 1) continue; if (a >= 64) { s[a] && s[a].size > -1 ? e.skip(s[a].size) : e.skip(e.ub()); continue; } const r = es(e, a, t); r ? (a === 39 && (s[r.index] = r), o.push({ type: a, data: r })) : e.seek(i); } return e.seek(i), o; }, Xe = (e, t, s) => { const n = { type: e.ub(), time: e.f(), tick: e.ui() }; switch (n.type) { case 0: case 1: { e.skip(4), n.camera = { position: [e.f(), e.f(), e.f()], orientation: [e.f(), e.f(), e.f()] }, e.skip(436), n.data = Ps(e, t, s); break; } case 2: break; case 3: { n.command = e.nstr(64); break; } case 4: { e.skip(32); break; } case 5: break; case 6: { e.skip(84); break; } case 7: { e.skip(8); break; } case 8: { n.sound = { channel: e.i(), sample: e.nstr(e.ui()), attenuation: e.f(), volume: e.f(), flags: e.ui(), pitch: e.i() }; break; } case 9: { e.skip(e.ui()); break; } default: { n.error = !0; break; } } return n; }; class be { constructor(t, s) { f(this, "header"); f(this, "mapName"); f(this, "directories"); this.header = t, this.mapName = this.header.mapName, this.directories = s; } static parseFromArrayBuffer(t) { const s = new fe(t); if (s.nstr(8) !== "HLDEMO") throw new Error("Invalid replay format"); const i = {}; i.demoProtocol = s.ui(), i.netProtocol = s.ui(), i.mapName = s.nstr(260), i.modName = s.nstr(260), i.mapCrc = s.i(), i.dirOffset = s.ui(), s.seek(i.dirOffset); const o = s.ui(), a = []; for (let r = 0; r < o; ++r) a.push({ id: s.ui(), name: s.nstr(64), flags: s.ui(), cdTrack: s.i(), time: s.f(), frames: s.ui(), offset: s.ui(), length: s.ui(), macros: [] }); for (let r = 0; r < a.length; ++r) { s.seek(a[r].offset); let l = !1; for (; !l; ) { const c = { type: s.b(), time: s.f(), frame: s.ui() }; switch (c.type) { case 0: case 1: { s.skip(4), c.camera = { position: [s.f(), s.f(), s.f()], orientation: [s.f(), s.f(), s.f()] }, s.skip(436), s.skip(s.ui()); break; } case 2: break; case 3: { c.command = s.nstr(64); break; } case 4: { s.skip(32); break; } case 5: { l = !0; break; } case 6: { s.skip(84); break; } case 7: { s.skip(8); break; } case 8: { s.skip(4), s.skip(s.ui() + 16); break; } case 9: { s.skip(s.ui()); break; } default: { const u = Number(s.tell() - 9).toString(16), h = [`Unexpected macro (${c.type})`, ` at offset = ${u}.`].join(""); throw new Error(h); } } a[r].macros.push(c); } } return new be(i, a); } static parseFullFromArrayBuffer(t) { const s = new fe(t); if (s.nstr(8) !== "HLDEMO") throw new Error("Invalid replay format"); const i = {}; i.demoProtocol = s.ui(), i.netProtocol = s.ui(), i.mapName = s.nstr(260), i.modName = s.nstr(260), i.mapCrc = s.i(), i.dirOffset = s.ui(), s.seek(i.dirOffset); const o = s.ui(), a = []; for (let c = 0; c < o; ++c) a.push({ id: s.ui(), name: s.nstr(64), flags: s.ui(), cdTrack: s.i(), time: s.f(), frames: s.ui(), offset: s.ui(), length: s.ui(), macros: [] }); const r = Gt(), l = []; for (let c = 0; c < a.length; ++c) { s.seek(a[c].offset); let u = !1; for (; !u; ) { const h = { type: s.b(), time: s.f(), frame: s.ui() }; switch (h.type) { case 0: case 1: { s.skip(4), h.camera = { position: [s.f(), s.f(), s.f()], orientation: [s.f(), s.f(), s.f()], forward: [s.f(), s.f(), s.f()], right: [s.f(), s.f(), s.f()], up: [s.f(), s.f(), s.f()] }, h.RefParams = { frametime: s.f(), time: s.f(), intermission: s.i(), paused: s.i(), spectator: s.i(), onground: s.i(), waterlevel: s.i(), velocity: [s.f(), s.f(), s.f()], origin: [s.f(), s.f(), s.f()], viewHeight: [s.f(), s.f(), s.f()], idealPitch: s.f(), viewAngles: [s.f(), s.f(), s.f()], health: s.i(), crosshairAngle: [s.f(), s.f(), s.f()], viewSize: s.f(), punchAngle: [s.f(), s.f(), s.f()], maxClients: s.i(), viewEntity: s.i(), playerCount: s.i(), maxEntities: s.i(), demoPlayback: s.i(), hardware: s.i(), smoothing: s.i(), ptr_cmd: s.i(), ptr_movevars: s.i(), viewport: [s.i(), s.i(), s.i(), s.i()], nextView: s.i(), onlyClientDraw: s.i() }, h.UserCmd = { lerp_msec: s.s(), msec: s.ub(), UNUSED1: s.ub(), viewAngles: [s.f(), s.f(), s.f()], forwardMove: s.f(), sideMove: s.f(), upMove: s.f(), lightLevel: s.b(), UNUSED2: s.ub(), buttons: s.us(), impulse: s.b(), weaponSelect: s.b(), UNUSED: s.s(), impactIndex: s.i(), impactPosition: [s.f(), s.f(), s.f()] }, h.MoveVars = { gravity: s.f(), stopSpeed: s.f(), maxSpeed: s.f(), spectatorMaxSpeed: s.f(), acceleration: s.f(), airAcceleration: s.f(), waterAcceleration: s.f(), friction: s.f(), edgeFriction: s.f(), waterFriction: s.f(), entityGravity: s.f(), bounce: s.f(), stepSize: s.f(), maxVelocity: s.f(), zMax: s.f(), waveHeight: s.f(), footsteps: s.i(), skyName: s.nstr(32), rollAngle: s.f(), rollSpeed: s.f(), skyColor: [s.f(), s.f(), s.f()], skyVec: [s.f(), s.f(), s.f()] }, h.view = [s.f(), s.f(), s.f()], h.viewModel = s.i(), h.incoming_sequence = s.i(), h.incoming_acknowledged = s.i(), h.incoming_reliable_acknowledged = s.i(), h.incoming_reliable_sequence = s.i(), h.outgoing_sequence = s.i(), h.reliable_sequence = s.i(), h.last_reliable_sequence = s.i(); const g = s.ui() + s.tell(); for (h.frameData = []; s.tell() < g; ) { const d = s.ub(); if (d === 1) continue; if (d >= 64) { l[d] && l[d].size > -1 ? s.skip(l[d].size) : s.skip(s.ub()); continue; } const p = es(s, d, r); p ? (d === 39 && (l[p.index] = p), h.frameData.push({ type: d, frameData: p })) : s.seek(g); } s.seek(g); break; } case 2: break; case 3: { h.command = s.nstr(64); break; } case 4: { h.clientData = { position: [s.f(), s.f(), s.f()], rotation: [s.f(), s.f(), s.f()], weaponFlags: s.ui(), fov: s.f() }; break; } case 5: { u = !0; break; } case 6: { h.event = { flags: s.ui(), index: s.ui(), delay: s.f(), args: { flags: s.ui(), entityIndex: s.ui(), position: [s.f(), s.f(), s.f()], rotation: [s.f(), s.f(), s.f()], velocity: [s.f(), s.f(), s.f()], ducking: s.ui(), fparam1: s.f(), fparam2: s.f(), iparam1: s.i(), iparam2: s.i(), bparam1: s.i(), bparam2: s.i() } }; break; } case 7: { h.weaponAnimation = { animation: s.i(), body: s.i() }; break; } case 8: { h.sound = { channel: s.i(), sample: s.nstr(s.ui()), attenuation: s.f(), volume: s.f(), flags: s.ui(), pitch: s.i() }; break; } case 9: { s.skip(s.ui()); break; } default: { const m = Number(s.tell() - 9).toString(16), g = `Unexpected macro (${h.type}) at offset = ${m}`; throw new Error(g); } } a[c].ma