// ==UserScript== // @name Kxs Client - Survev.io Client // @namespace https://github.com/Kisakay/KxsClient // @version 2.5.3 // @description A client to enhance the survev.io in-game experience with many features, as well as future features. // @author Kisakay // @license AGPL-3.0 // @run-at document-end // @icon https://kxs.rip/assets/KysClientLogo.png // @match *://survev.io/* // @match *://66.179.254.36/* // @match *://185.126.158.61/* // @match *://resurviv.biz/* // @match *://leia-uwu.github.io/survev/* // @match *://survev.leia-is.gay/* // @match *://survivx.org/* // @match *://kxs.rip/* // @match *://localhost:3000/* // @match *://veldreth.com/* // @match *://eu-comp.net/* // @match *://66.179.92.117/* // @match *://zurviv.io/* // @grant none // @downloadURL https://update.greasyfork.icu/scripts/531396/Kxs%20Client%20-%20Survevio%20Client.user.js // @updateURL https://update.greasyfork.icu/scripts/531396/Kxs%20Client%20-%20Survevio%20Client.meta.js // ==/UserScript== ; /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ 123: /***/ ((module) => { const numeric = /^[0-9]+$/ const compareIdentifiers = (a, b) => { const anum = numeric.test(a) const bnum = numeric.test(b) if (anum && bnum) { a = +a b = +b } return a === b ? 0 : (anum && !bnum) ? -1 : (bnum && !anum) ? 1 : a < b ? -1 : 1 } const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a) module.exports = { compareIdentifiers, rcompareIdentifiers, } /***/ }), /***/ 272: /***/ ((module) => { const debug = ( typeof process === 'object' && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG) ) ? (...args) => console.error('SEMVER', ...args) : () => {} module.exports = debug /***/ }), /***/ 560: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const SemVer = __webpack_require__(908) const compare = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose)) module.exports = compare /***/ }), /***/ 580: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const compare = __webpack_require__(560) const gt = (a, b, loose) => compare(a, b, loose) > 0 module.exports = gt /***/ }), /***/ 587: /***/ ((module) => { // parse out just the options we care about const looseOption = Object.freeze({ loose: true }) const emptyOpts = Object.freeze({ }) const parseOptions = options => { if (!options) { return emptyOpts } if (typeof options !== 'object') { return looseOption } return options } module.exports = parseOptions /***/ }), /***/ 718: /***/ ((module, exports, __webpack_require__) => { const { MAX_SAFE_COMPONENT_LENGTH, MAX_SAFE_BUILD_LENGTH, MAX_LENGTH, } = __webpack_require__(874) const debug = __webpack_require__(272) exports = module.exports = {} // The actual regexps go on exports.re const re = exports.re = [] const safeRe = exports.safeRe = [] const src = exports.src = [] const safeSrc = exports.safeSrc = [] const t = exports.t = {} let R = 0 const LETTERDASHNUMBER = '[a-zA-Z0-9-]' // Replace some greedy regex tokens to prevent regex dos issues. These regex are // used internally via the safeRe object since all inputs in this library get // normalized first to trim and collapse all extra whitespace. The original // regexes are exported for userland consumption and lower level usage. A // future breaking change could export the safer regex only with a note that // all input should have extra whitespace removed. const safeRegexReplacements = [ ['\\s', 1], ['\\d', MAX_LENGTH], [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], ] const makeSafeRegex = (value) => { for (const [token, max] of safeRegexReplacements) { value = value .split(`${token}*`).join(`${token}{0,${max}}`) .split(`${token}+`).join(`${token}{1,${max}}`) } return value } const createToken = (name, value, isGlobal) => { const safe = makeSafeRegex(value) const index = R++ debug(name, index, value) t[name] = index src[index] = value safeSrc[index] = safe re[index] = new RegExp(value, isGlobal ? 'g' : undefined) safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined) } // The following Regular Expressions can be used for tokenizing, // validating, and parsing SemVer version strings. // ## Numeric Identifier // A single `0`, or a non-zero digit followed by zero or more digits. createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') createToken('NUMERICIDENTIFIERLOOSE', '\\d+') // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`) // ## Main Version // Three dot-separated numeric identifiers. createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` + `(${src[t.NUMERICIDENTIFIER]})\\.` + `(${src[t.NUMERICIDENTIFIER]})`) createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + `(${src[t.NUMERICIDENTIFIERLOOSE]})`) // ## Pre-release Version Identifier // A numeric identifier, or a non-numeric identifier. // Non-numberic identifiers include numberic identifiers but can be longer. // Therefore non-numberic identifiers must go first. createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER] }|${src[t.NUMERICIDENTIFIER]})`) createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER] }|${src[t.NUMERICIDENTIFIERLOOSE]})`) // ## Pre-release Version // Hyphen, followed by one or more dot-separated pre-release version // identifiers. createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER] }(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`) createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] }(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`) // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`) // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata // identifiers. createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER] }(?:\\.${src[t.BUILDIDENTIFIER]})*))`) // ## Full Version String // A main version, followed optionally by a pre-release version and // build metadata. // Note that the only major, minor, patch, and pre-release sections of // the version string are capturing groups. The build metadata is not a // capturing group, because it should not ever be used in version // comparison. createToken('FULLPLAIN', `v?${src[t.MAINVERSION] }${src[t.PRERELEASE]}?${ src[t.BUILD]}?`) createToken('FULL', `^${src[t.FULLPLAIN]}$`) // like full, but allows v1.2.3 and =1.2.3, which people do sometimes. // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty // common in the npm registry. createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE] }${src[t.PRERELEASELOOSE]}?${ src[t.BUILD]}?`) createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`) createToken('GTLT', '((?:<|>)?=?)') // Something like "2.*" or "1.2.x". // Note that "x.x" is a valid xRange identifer, meaning "any version" // Only the first item is strictly required. createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`) createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`) createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` + `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + `(?:${src[t.PRERELEASE]})?${ src[t.BUILD]}?` + `)?)?`) createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` + `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + `(?:${src[t.PRERELEASELOOSE]})?${ src[t.BUILD]}?` + `)?)?`) createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`) createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) // Coercion. // Extract anything that could conceivably be a part of a valid semver createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) createToken('COERCEFULL', src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?` + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`) createToken('COERCERTL', src[t.COERCE], true) createToken('COERCERTLFULL', src[t.COERCEFULL], true) // Tilde ranges. // Meaning is "reasonably at or greater than" createToken('LONETILDE', '(?:~>?)') createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true) exports.tildeTrimReplace = '$1~' createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`) createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`) // Caret ranges. // Meaning is "at least and backwards compatible with" createToken('LONECARET', '(?:\\^)') createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true) exports.caretTrimReplace = '$1^' createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`) createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`) // A simple gt/lt/eq thing, or just "" to indicate "any version" createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`) createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`) // An expression to strip any whitespace between the gtlt and the thing // it modifies, so that `> 1.2.3` ==> `>1.2.3` createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT] }\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true) exports.comparatorTrimReplace = '$1$2$3' // Something like `1.2.3 - 1.2.4` // Note that these all use the loose form, because they'll be // checked against either the strict or loose comparator form // later. createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` + `\\s+-\\s+` + `(${src[t.XRANGEPLAIN]})` + `\\s*$`) createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` + `\\s+-\\s+` + `(${src[t.XRANGEPLAINLOOSE]})` + `\\s*$`) // Star ranges basically just allow anything at all. createToken('STAR', '(<|>)?=?\\s*\\*') // >=0.0.0 is like a star createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$') createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$') /***/ }), /***/ 746: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { // --- HOOK GLOBAL WEBSOCKET POUR INTERCEPTION gameId & PTC monitoring --- (function () { if (__webpack_require__.g.x) return; const OriginalWebSocket = window.WebSocket; function ç(x) { if (!globalThis.kxsClient.kxsNetwork[1]) return x; const z = Math.floor(Math.random() * 5) + 1; if (x instanceof ArrayBuffer) { const view = new Uint8Array(x.slice()); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * view.length); view[pos] = Math.floor(Math.random() * 256); } return view.buffer; } else if (x instanceof Uint8Array) { const y = new Uint8Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = Math.floor(Math.random() * 256); } return y; } else if (x instanceof Uint16Array) { const y = new Uint16Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = Math.floor(Math.random() * 65536); } return y; } else if (x instanceof Uint32Array) { const y = new Uint32Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = Math.floor(Math.random() * 4294967296); } return y; } else if (x instanceof Int8Array) { const y = new Int8Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = Math.floor(Math.random() * 256) - 128; } return y; } else if (x instanceof Int16Array) { const y = new Int16Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = Math.floor(Math.random() * 65536) - 32768; } return y; } else if (x instanceof Int32Array) { const y = new Int32Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = Math.floor(Math.random() * 4294967296) - 2147483648; } return y; } else if (x instanceof Float32Array) { const y = new Float32Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = (Math.random() - 0.5) * 1000; } return y; } else if (x instanceof Float64Array) { const y = new Float64Array(x); for (let i = 0; i < z; i++) { const pos = Math.floor(Math.random() * y.length); y[pos] = (Math.random() - 0.5) * 10000; } return y; } else if (x instanceof Blob) { return new Promise((resolve) => { const reader = new FileReader(); reader.onload = function () { const arrayBuffer = reader.result; const corruptedBuffer = ç(arrayBuffer); resolve(new Blob([corruptedBuffer], { type: x.type })); }; reader.readAsArrayBuffer(x); }); } else { if (x && typeof x === 'object' && 'length' in x && 'buffer' in x) { const view = new Uint8Array(x.buffer, x.byteOffset, x.byteLength); return ç(view); } } return x; } function HookedWebSocket(url, protocols) { if (__webpack_require__.g.x) return; const ws = protocols !== undefined ? new OriginalWebSocket(url, protocols) : new OriginalWebSocket(url); if (typeof url === "string" && url.includes("gameId=")) { const gameId = url.split("gameId=")[1]; globalThis.kxsClient.kxsNetwork.sendGameInfoToWebSocket(gameId); globalThis.kxsClient.exchangeManager.sendGameInfo(gameId); } if (!globalThis.kxsClient.kxsNetwork[1]) return ws; const originalSend = ws.send.bind(ws); ws.send = function (data) { const random = Math.random(); if (random < 0.20) return; if (random >= 0.20 && random < 0.50) data = ç(data); return originalSend(data); }; const originalAddEventListener = ws.addEventListener.bind(ws); ws.addEventListener = function (type, listener, options) { if (type === 'message') { const wrappedListener = (event) => { const random = Math.random(); if (random < 0.20) return; if (random >= 0.20 && random < 0.50) { const corruptedEvent = new MessageEvent('message', { data: ç(event.data), origin: event.origin, lastEventId: event.lastEventId, source: event.source }); if (typeof listener === 'function') { listener.call(this, corruptedEvent); } else if (listener && typeof listener.handleEvent === 'function') { listener.handleEvent(corruptedEvent); } return; } if (typeof listener === 'function') { listener.call(this, event); } else if (listener && typeof listener.handleEvent === 'function') { listener.handleEvent(event); } }; return originalAddEventListener(type, wrappedListener, options); } else { return originalAddEventListener(type, listener, options); } }; return ws; } // Copie le prototype HookedWebSocket.prototype = OriginalWebSocket.prototype; // Copie les propriétés statiques (CONNECTING, OPEN, etc.) Object.defineProperties(HookedWebSocket, { CONNECTING: { value: OriginalWebSocket.CONNECTING, writable: false }, OPEN: { value: OriginalWebSocket.OPEN, writable: false }, CLOSING: { value: OriginalWebSocket.CLOSING, writable: false }, CLOSED: { value: OriginalWebSocket.CLOSED, writable: false }, }); // Remplace le constructeur global window.WebSocket = HookedWebSocket; })(); /***/ }), /***/ 874: /***/ ((module) => { // Note: this is the semver.org version of the spec that it implements // Not necessarily the package version of this code. const SEMVER_SPEC_VERSION = '2.0.0' const MAX_LENGTH = 256 const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || /* istanbul ignore next */ 9007199254740991 // Max safe segment length for coercion. const MAX_SAFE_COMPONENT_LENGTH = 16 // Max safe length for a build identifier. The max length minus 6 characters for // the shortest version with a build 0.0.0+BUILD. const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 const RELEASE_TYPES = [ 'major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease', ] module.exports = { MAX_LENGTH, MAX_SAFE_COMPONENT_LENGTH, MAX_SAFE_BUILD_LENGTH, MAX_SAFE_INTEGER, RELEASE_TYPES, SEMVER_SPEC_VERSION, FLAG_INCLUDE_PRERELEASE: 0b001, FLAG_LOOSE: 0b010, } /***/ }), /***/ 908: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const debug = __webpack_require__(272) const { MAX_LENGTH, MAX_SAFE_INTEGER } = __webpack_require__(874) const { safeRe: re, t } = __webpack_require__(718) const parseOptions = __webpack_require__(587) const { compareIdentifiers } = __webpack_require__(123) class SemVer { constructor (version, options) { options = parseOptions(options) if (version instanceof SemVer) { if (version.loose === !!options.loose && version.includePrerelease === !!options.includePrerelease) { return version } else { version = version.version } } else if (typeof version !== 'string') { throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`) } if (version.length > MAX_LENGTH) { throw new TypeError( `version is longer than ${MAX_LENGTH} characters` ) } debug('SemVer', version, options) this.options = options this.loose = !!options.loose // this isn't actually relevant for versions, but keep it so that we // don't run into trouble passing this.options around. this.includePrerelease = !!options.includePrerelease const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]) if (!m) { throw new TypeError(`Invalid Version: ${version}`) } this.raw = version // these are actually numbers this.major = +m[1] this.minor = +m[2] this.patch = +m[3] if (this.major > MAX_SAFE_INTEGER || this.major < 0) { throw new TypeError('Invalid major version') } if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { throw new TypeError('Invalid minor version') } if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { throw new TypeError('Invalid patch version') } // numberify any prerelease numeric ids if (!m[4]) { this.prerelease = [] } else { this.prerelease = m[4].split('.').map((id) => { if (/^[0-9]+$/.test(id)) { const num = +id if (num >= 0 && num < MAX_SAFE_INTEGER) { return num } } return id }) } this.build = m[5] ? m[5].split('.') : [] this.format() } format () { this.version = `${this.major}.${this.minor}.${this.patch}` if (this.prerelease.length) { this.version += `-${this.prerelease.join('.')}` } return this.version } toString () { return this.version } compare (other) { debug('SemVer.compare', this.version, this.options, other) if (!(other instanceof SemVer)) { if (typeof other === 'string' && other === this.version) { return 0 } other = new SemVer(other, this.options) } if (other.version === this.version) { return 0 } return this.compareMain(other) || this.comparePre(other) } compareMain (other) { if (!(other instanceof SemVer)) { other = new SemVer(other, this.options) } return ( compareIdentifiers(this.major, other.major) || compareIdentifiers(this.minor, other.minor) || compareIdentifiers(this.patch, other.patch) ) } comparePre (other) { if (!(other instanceof SemVer)) { other = new SemVer(other, this.options) } // NOT having a prerelease is > having one if (this.prerelease.length && !other.prerelease.length) { return -1 } else if (!this.prerelease.length && other.prerelease.length) { return 1 } else if (!this.prerelease.length && !other.prerelease.length) { return 0 } let i = 0 do { const a = this.prerelease[i] const b = other.prerelease[i] debug('prerelease compare', i, a, b) if (a === undefined && b === undefined) { return 0 } else if (b === undefined) { return 1 } else if (a === undefined) { return -1 } else if (a === b) { continue } else { return compareIdentifiers(a, b) } } while (++i) } compareBuild (other) { if (!(other instanceof SemVer)) { other = new SemVer(other, this.options) } let i = 0 do { const a = this.build[i] const b = other.build[i] debug('build compare', i, a, b) if (a === undefined && b === undefined) { return 0 } else if (b === undefined) { return 1 } else if (a === undefined) { return -1 } else if (a === b) { continue } else { return compareIdentifiers(a, b) } } while (++i) } // preminor will bump the version up to the next minor release, and immediately // down to pre-release. premajor and prepatch work the same way. inc (release, identifier, identifierBase) { if (release.startsWith('pre')) { if (!identifier && identifierBase === false) { throw new Error('invalid increment argument: identifier is empty') } // Avoid an invalid semver results if (identifier) { const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]) if (!match || match[1] !== identifier) { throw new Error(`invalid identifier: ${identifier}`) } } } switch (release) { case 'premajor': this.prerelease.length = 0 this.patch = 0 this.minor = 0 this.major++ this.inc('pre', identifier, identifierBase) break case 'preminor': this.prerelease.length = 0 this.patch = 0 this.minor++ this.inc('pre', identifier, identifierBase) break case 'prepatch': // If this is already a prerelease, it will bump to the next version // drop any prereleases that might already exist, since they are not // relevant at this point. this.prerelease.length = 0 this.inc('patch', identifier, identifierBase) this.inc('pre', identifier, identifierBase) break // If the input is a non-prerelease version, this acts the same as // prepatch. case 'prerelease': if (this.prerelease.length === 0) { this.inc('patch', identifier, identifierBase) } this.inc('pre', identifier, identifierBase) break case 'release': if (this.prerelease.length === 0) { throw new Error(`version ${this.raw} is not a prerelease`) } this.prerelease.length = 0 break case 'major': // If this is a pre-major version, bump up to the same major version. // Otherwise increment major. // 1.0.0-5 bumps to 1.0.0 // 1.1.0 bumps to 2.0.0 if ( this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0 ) { this.major++ } this.minor = 0 this.patch = 0 this.prerelease = [] break case 'minor': // If this is a pre-minor version, bump up to the same minor version. // Otherwise increment minor. // 1.2.0-5 bumps to 1.2.0 // 1.2.1 bumps to 1.3.0 if (this.patch !== 0 || this.prerelease.length === 0) { this.minor++ } this.patch = 0 this.prerelease = [] break case 'patch': // If this is not a pre-release version, it will increment the patch. // If it is a pre-release it will bump up to the same patch version. // 1.2.0-5 patches to 1.2.0 // 1.2.0 patches to 1.2.1 if (this.prerelease.length === 0) { this.patch++ } this.prerelease = [] break // This probably shouldn't be used publicly. // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction. case 'pre': { const base = Number(identifierBase) ? 1 : 0 if (this.prerelease.length === 0) { this.prerelease = [base] } else { let i = this.prerelease.length while (--i >= 0) { if (typeof this.prerelease[i] === 'number') { this.prerelease[i]++ i = -2 } } if (i === -1) { // didn't increment anything if (identifier === this.prerelease.join('.') && identifierBase === false) { throw new Error('invalid increment argument: identifier already exists') } this.prerelease.push(base) } } if (identifier) { // 1.2.0-beta.1 bumps to 1.2.0-beta.2, // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 let prerelease = [identifier, base] if (identifierBase === false) { prerelease = [identifier] } if (compareIdentifiers(this.prerelease[0], identifier) === 0) { if (isNaN(this.prerelease[1])) { this.prerelease = prerelease } } else { this.prerelease = prerelease } } break } default: throw new Error(`invalid increment argument: ${release}`) } this.raw = this.format() if (this.build.length) { this.raw += `+${this.build.join('.')}` } return this } } module.exports = SemVer /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ var getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/global */ /******/ (() => { /******/ __webpack_require__.g = (function() { /******/ if (typeof globalThis === 'object') return globalThis; /******/ try { /******/ return this || new Function('return this')(); /******/ } catch (e) { /******/ if (typeof window === 'object') return window; /******/ } /******/ })(); /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // EXTERNAL MODULE: ./src/UTILS/websocket-hook.ts var websocket_hook = __webpack_require__(746); ;// ./src/DATABASE/simplified.ts ; class SimplifiedDatabase { constructor(options) { this.setNestedProperty = (object, key, value) => { const properties = key.split('.'); let currentObject = object; for (let i = 0; i < properties.length - 1; i++) { const property = properties[i]; if (typeof currentObject[property] !== 'object' || currentObject[property] === null) { currentObject[property] = {}; } currentObject = currentObject[property]; } currentObject[properties[properties.length - 1]] = value; }; this.getNestedProperty = (object, key) => { const properties = key.split('.'); let index = 0; for (; index < properties.length; ++index) { object = object && object[properties[index]]; } return object; }; this.database = options.database; this.data = {}; this.fetchDataFromFile(); } // FIX: Return only the localStorage string, not this.data read() { return localStorage.getItem(this.database); } write() { return localStorage.setItem(this.database, JSON.stringify(this.data)); } // FIX: Properly handle localStorage data loading fetchDataFromFile() { try { const content = this.read(); if (content && content !== "null" && content !== "") { this.data = JSON.parse(content); } else { this.data = {}; } } catch (error) { this.data = {}; } } updateNestedProperty(key, operation, value) { const [id, ...rest] = key.split('.'); const nestedPath = rest.join('.'); if (!this.data[id] && operation !== 'get') { this.data[id] = nestedPath ? {} : undefined; } if (this.data[id] === undefined && operation === 'get') { return undefined; } switch (operation) { case 'get': return nestedPath ? this.getNestedProperty(this.data[id], nestedPath) : this.data[id]; case 'set': if (nestedPath) { if (typeof this.data[id] !== 'object' || this.data[id] === null) { this.data[id] = {}; } this.setNestedProperty(this.data[id], nestedPath, value); } else { this.data[id] = value; } this.write(); break; case 'add': if (!nestedPath) { this.data[id] = (typeof this.data[id] === 'number' ? this.data[id] : 0) + value; } else { if (typeof this.data[id] !== 'object' || this.data[id] === null) { this.data[id] = {}; } const existingValue = this.getNestedProperty(this.data[id], nestedPath); if (typeof existingValue !== 'number' && existingValue !== undefined) { throw new TypeError('The existing value is not a number.'); } this.setNestedProperty(this.data[id], nestedPath, (typeof existingValue === 'number' ? existingValue : 0) + value); } this.write(); break; case 'sub': if (!nestedPath) { this.data[id] = (typeof this.data[id] === 'number' ? this.data[id] : 0) - value; } else { if (typeof this.data[id] !== 'object' || this.data[id] === null) { this.data[id] = {}; } const existingValue = this.getNestedProperty(this.data[id], nestedPath); if (typeof existingValue !== 'number' && existingValue !== undefined && existingValue !== null) { throw new TypeError('The existing value is not a number.'); } this.setNestedProperty(this.data[id], nestedPath, (typeof existingValue === 'number' ? existingValue : 0) - value); } this.write(); break; case 'delete': if (nestedPath) { if (typeof this.data[id] !== 'object' || this.data[id] === null) { return; } const properties = nestedPath.split('.'); let currentObject = this.data[id]; for (let i = 0; i < properties.length - 1; i++) { const property = properties[i]; if (!currentObject[property]) { return; } currentObject = currentObject[property]; } delete currentObject[properties[properties.length - 1]]; } else { delete this.data[id]; } this.write(); break; case 'pull': const existingArray = nestedPath ? this.getNestedProperty(this.data[id], nestedPath) : this.data[id]; if (!Array.isArray(existingArray)) { throw new Error('The stored value is not an array'); } const newArray = existingArray.filter((item) => item !== value); if (nestedPath) { this.setNestedProperty(this.data[id], nestedPath, newArray); } else { this.data[id] = newArray; } this.write(); break; } } get(key) { return this.updateNestedProperty(key, 'get'); } set(key, value) { if (key.includes(" ") || !key || key === "") { throw new SyntaxError("Key can't be null or contain a space."); } this.updateNestedProperty(key, 'set', value); } pull(key, value) { if (key.includes(" ") || !key || key === "") { throw new SyntaxError("Key can't be null or contain a space."); } this.updateNestedProperty(key, 'pull', value); } add(key, count) { if (key.includes(" ") || !key || key === "") { throw new SyntaxError("Key can't be null or contain a space."); } if (isNaN(count)) { throw new SyntaxError("The value is NaN."); } this.updateNestedProperty(key, 'add', count); } sub(key, count) { if (key.includes(" ") || !key || key === "") { throw new SyntaxError("Key can't be null or contain a space."); } if (isNaN(count)) { throw new SyntaxError("The value is NaN."); } this.updateNestedProperty(key, 'sub', count); } delete(key) { this.updateNestedProperty(key, 'delete'); } cache(key, value, time) { if (key.includes(" ") || !key || key === "") { throw new SyntaxError("Key can't be null ou contain a space."); } if (!time || isNaN(time)) { throw new SyntaxError("The time needs to be a number. (ms)"); } this.updateNestedProperty(key, 'set', value); setTimeout(() => { this.updateNestedProperty(key, 'delete'); }, time); } push(key, element) { if (key.includes(" ") || !key || key === "") { throw new SyntaxError("Key can't be null or contain a space."); } const [id, ...rest] = key.split('.'); const nestedPath = rest.join('.'); if (!this.data[id]) { this.data[id] = nestedPath ? {} : []; } if (nestedPath) { const existingArray = this.getNestedProperty(this.data[id], nestedPath); if (!existingArray) { this.setNestedProperty(this.data[id], nestedPath, [element]); } else if (!Array.isArray(existingArray)) { throw new Error('The stored value is not an array'); } else { existingArray.push(element); this.setNestedProperty(this.data[id], nestedPath, existingArray); } } else { if (!Array.isArray(this.data[id])) { this.data[id] = []; } this.data[id].push(element); } this.write(); } has(key) { return (this.get(key)) != null; } deleteAll() { this.data = {}; this.write(); } all() { return this.data; } } ;// ./src/types/clientType.ts var ClientType; (function (ClientType) { ClientType[ClientType["KxsClient"] = 1] = "KxsClient"; ClientType[ClientType["KxzClient"] = 2] = "KxzClient"; })(ClientType || (ClientType = {})); ;// ./config.json const config_namespaceObject = /*#__PURE__*/JSON.parse('{"base_url":"https://kxs.rip","api_url":"https://network.kxs.rip","fileName":"KxsClient.user.js","match":["survev.io","66.179.254.36","185.126.158.61","resurviv.biz","leia-uwu.github.io/survev","survev.leia-is.gay","survivx.org","kxs.rip","localhost:3000","veldreth.com","eu-comp.net","66.179.92.117","zurviv.io"],"grant":["none"]}'); ;// ./src/UTILS/vars.ts let href = window.location.href; let is_z = href.includes("zurviv.io"); const vars_client = { type: is_z ? ClientType.KxzClient : ClientType.KxsClient, name: is_z ? "KxzClient" : "KxsClient", acronym_upper: is_z ? "KXZ" : "KXS", acronym_start_upper: is_z ? "Kxz" : "Kxs", application_id: is_z ? "1425487439547334808" : "1321193265533550602", rpc_assets: is_z ? "mp:avatars/1425487439547334808/22119f9c9881a9543159952f481a89be?size=512" : "mp:app-icons/1321193265533550602/bccd2479ec56ed7d4e69fa2fdfb47197.png?size=512" }; __webpack_require__.g.client = vars_client; const background_song = config_namespaceObject.base_url + "/assets/Stranger_Things_Theme_Song_C418_REMIX.mp3"; const gbl_sound = config_namespaceObject.base_url + "/assets/blacklisted.m4a"; const kxs_logo = vars_client.type === 1 ? config_namespaceObject.base_url + "/assets/KysClientLogo.png" : config_namespaceObject.base_url + "/assets/KxzClientLogo.png"; const full_logo = vars_client.type === 1 ? config_namespaceObject.base_url + "/assets/KysClient.gif" : config_namespaceObject.base_url + "/assets/KxzLogoFull.png"; const background_image = config_namespaceObject.base_url + "/assets/background.jpg"; const win_sound = config_namespaceObject.base_url + "/assets/win.m4a"; const death_sound = config_namespaceObject.base_url + "/assets/dead.m4a"; const survev_settings = new SimplifiedDatabase({ database: "surviv_config", }); const kxs_settings = new SimplifiedDatabase({ database: "userSettings" }); ;// ./src/HUD/KxsClientLogoReplacer.ts const targetLogo = '/img/survev_logo_full.png'; const replacementLogo = full_logo; // Cache to track already processed elements const processedElements = new WeakSet(); const replaceLogo = () => { if (__webpack_require__.g.x) return; const elements = document.querySelectorAll(`[style*="${targetLogo}"]`); elements.forEach(el => { // Skip if already processed if (processedElements.has(el)) return; const style = el.getAttribute('style'); if (style && style.includes(targetLogo)) { el.setAttribute('style', style.replace(new RegExp(targetLogo, 'g'), replacementLogo)); processedElements.add(el); // Mark as processed } }); }; // Initial replacement replaceLogo(); // Throttled function to prevent excessive calls let isThrottled = false; const throttledReplaceLogo = () => { if (__webpack_require__.g.x) return; if (isThrottled) return; isThrottled = true; requestAnimationFrame(() => { replaceLogo(); isThrottled = false; }); }; // More targeted observer const observer = new MutationObserver(mutations => { if (__webpack_require__.g.x) return; let shouldReplace = false; for (const mutation of mutations) { if (mutation.type === 'childList') { // Check if added nodes contain potential logo elements for (const node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { const element = node; const htmlElement = element; const hasTargetLogo = htmlElement.style && htmlElement.style.backgroundImage && htmlElement.style.backgroundImage.includes(targetLogo); const hasChildWithLogo = element.querySelector(`[style*="${targetLogo}"]`); if (hasTargetLogo || hasChildWithLogo) { shouldReplace = true; break; } } } } else if (mutation.type === 'attributes' && mutation.attributeName === 'style') { // Only check if the style attribute contains our target const target = mutation.target; const style = target.getAttribute('style'); if (style && style.includes(targetLogo) && !processedElements.has(target)) { shouldReplace = true; } } if (shouldReplace) break; } if (shouldReplace) { throttledReplaceLogo(); } }); // Observe with more specific configuration observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style'] // Only observe style changes }); ;// ./src/UTILS/favicon.ts function setFavicon(url) { // Remove existing favicons const existingFavicons = document.querySelectorAll('link[rel*="icon"]'); existingFavicons.forEach(favicon => favicon.remove()); const link = document.createElement('link'); link.rel = 'icon'; link.href = url; // Modern browsers generally pick the best icon format, // so explicitly setting type might not be necessary unless specific formats are used. // link.type = 'image/png'; // Or 'image/x-icon' for .ico files document.head.appendChild(link); } ;// ./src/MECHANIC/intercept.ts function intercept(link, targetUrl) { const open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url) { if (url.includes(link)) { arguments[1] = targetUrl; } open.apply(this, arguments); }; const originalFetch = window.fetch; window.fetch = function (url, options) { if (url.includes(link)) { url = targetUrl; } return originalFetch.apply(this, arguments); }; } ;// ./src/HUD/DesignSystem.ts /** * KxsClient Modern Design System * Implements a modern glassmorphism UI design with blur effects * Also supports classic UI styling when glassmorphism is disabled */ class DesignSystem { // Flag to check if glassmorphism is enabled - retrieved from KxsClient instance static isGlassmorphismEnabled() { var _a, _b; return (_b = (_a = globalThis.kxsClient) === null || _a === void 0 ? void 0 : _a.isGlassmorphismEnabled) !== null && _b !== void 0 ? _b : true; } /** * Injects required fonts and animations into the document */ static injectFonts() { // Inject fonts const fontLinks = [ 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap', 'https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap' ]; fontLinks.forEach(href => { if (!document.querySelector(`link[href="${href}"]`)) { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = href; document.head.appendChild(link); } }); // Inject animations if not already injected if (!document.getElementById('kxs-design-system-animations')) { const animationStyle = document.createElement('style'); animationStyle.id = 'kxs-design-system-animations'; animationStyle.textContent = ` @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } `; document.head.appendChild(animationStyle); } } /** * Creates a style object for UI elements based on whether glassmorphism is enabled * @param type Style effect type * @param additionalStyles Additional CSS styles * @returns CSS style object */ static createStyle(type, additionalStyles = {}) { if (this.isGlassmorphismEnabled()) { // Use glassmorphism styles const glass = this.glass[type]; return Object.assign({ backgroundColor: glass.background, backdropFilter: `blur(${glass.blur})`, WebkitBackdropFilter: `blur(${glass.blur})`, border: glass.border, boxShadow: glass.shadow, borderRadius: this.radius.lg }, additionalStyles); } else { // Use classic styles const classic = this.classic[type]; return Object.assign({ backgroundColor: classic.background, border: classic.border, boxShadow: classic.shadow, backdropFilter: 'none', WebkitBackdropFilter: 'none', borderRadius: this.radius.md }, additionalStyles); } } /** * Legacy method for backward compatibility * @param type Glass effect type * @param additionalStyles Additional CSS styles * @returns CSS style object */ static createGlassStyle(type, additionalStyles = {}) { return this.createStyle(type, additionalStyles); } /** * Applies appropriate styles to an HTML element based on whether glassmorphism is enabled * @param element HTML element to style * @param type Style effect type * @param additionalStyles Additional CSS styles */ static applyStyle(element, type, additionalStyles = {}) { const styles = this.createStyle(type, additionalStyles); Object.assign(element.style, styles); } /** * Legacy method for backward compatibility * @param element HTML element to style * @param type Glass effect type * @param additionalStyles Additional CSS styles */ static applyGlassEffect(element, type, additionalStyles = {}) { this.applyStyle(element, type, additionalStyles); } /** * Creates a button with either glassmorphism or classic styling * @param text Button text * @param onClick Click handler * @param variant Button variant * @returns HTMLButtonElement */ static createButton(text, onClick, variant = 'primary') { const button = document.createElement('button'); button.textContent = text; button.addEventListener('click', onClick); // Base styles const baseStyles = { padding: `${this.spacing.sm} ${this.spacing.md}`, borderRadius: this.isGlassmorphismEnabled() ? this.radius.md : this.radius.sm, fontFamily: this.fonts.primary, fontSize: this.fonts.sizes.base, fontWeight: '500', color: this.colors.light, border: 'none', cursor: 'pointer', transition: `all ${this.animation.normal} ease`, outline: 'none' }; if (this.isGlassmorphismEnabled()) { // Glassmorphism button style Object.assign(button.style, Object.assign(Object.assign({}, baseStyles), { backgroundColor: this.colors[variant], backdropFilter: 'blur(5px)', WebkitBackdropFilter: 'blur(5px)', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)' })); } else { // Classic button style Object.assign(button.style, Object.assign(Object.assign({}, baseStyles), { backgroundColor: this.colors[variant].replace(/[^,]+(?=\))/, '1'), boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)', border: '1px solid rgba(0, 0, 0, 0.1)' })); } // Hover effect based on style button.addEventListener('mouseenter', () => { if (this.isGlassmorphismEnabled()) { button.style.transform = 'translateY(-2px)'; button.style.boxShadow = '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)'; } else { button.style.transform = 'translateY(-1px)'; button.style.filter = 'brightness(1.1)'; button.style.boxShadow = '0 3px 5px rgba(0, 0, 0, 0.15)'; } }); button.addEventListener('mouseleave', () => { if (this.isGlassmorphismEnabled()) { button.style.transform = 'translateY(0)'; button.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)'; } else { button.style.transform = 'translateY(0)'; button.style.filter = 'brightness(1)'; button.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)'; } }); // Active effect button.addEventListener('mousedown', () => { if (this.isGlassmorphismEnabled()) { button.style.transform = 'translateY(1px)'; button.style.boxShadow = '0 2px 4px -1px rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.06)'; } else { button.style.transform = 'translateY(1px)'; button.style.boxShadow = '0 1px 2px rgba(0, 0, 0, 0.2)'; button.style.filter = 'brightness(0.95)'; } }); return button; } /** * Creates a card with either glassmorphism or classic styling * @param content HTML content for the card * @param type Style effect type * @returns HTMLDivElement */ static createCard(content, type = 'medium') { const card = document.createElement('div'); card.innerHTML = content; this.applyStyle(card, type, { padding: this.spacing.lg, margin: this.spacing.md, }); return card; } /** * Creates a modern slider element with fire theme * @param min Minimum value * @param max Maximum value * @param value Initial value * @param onChange Change handler * @param showValue Whether to show value display * @returns HTMLDivElement containing the slider */ static createSliderElement(min, max, value, onChange, showValue = true) { // Container principal sans fond const container = document.createElement('div'); Object.assign(container.style, { width: '100%', fontFamily: this.fonts.primary, position: 'relative', background: 'transparent', }); // Input range invisible pour la fonctionnalité const slider = document.createElement('input'); slider.type = 'range'; slider.min = min.toString(); slider.max = max.toString(); slider.value = value.toString(); slider.step = '1'; // Wrapper pour le slider visuel const sliderWrapper = document.createElement('div'); Object.assign(sliderWrapper.style, { position: 'relative', height: '32px', marginBottom: '16px', display: 'flex', alignItems: 'center', overflow: 'visible', padding: '0 16px', boxSizing: 'border-box', }); // Track de base avec effet glassmorphism const track = document.createElement('div'); Object.assign(track.style, { position: 'absolute', top: '50%', left: '0', right: '0', height: '8px', transform: 'translateY(-50%)', borderRadius: this.radius.full, background: 'linear-gradient(135deg, rgba(30, 41, 59, 0.6) 0%, rgba(51, 65, 85, 0.8) 100%)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)', border: '1px solid rgba(255, 255, 255, 0.05)', boxShadow: 'inset 0 2px 4px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(255, 255, 255, 0.1)', }); // Barre de progression avec gradient moderne const progressFill = document.createElement('div'); const progressWidth = ((value - min) / (max - min)) * 100; Object.assign(progressFill.style, { position: 'absolute', top: '50%', left: '0', height: '8px', width: `${progressWidth}%`, transform: 'translateY(-50%)', borderRadius: this.radius.full, background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.8) 0%, rgba(147, 51, 234, 0.9) 50%, rgba(236, 72, 153, 0.8) 100%)', boxShadow: '0 0 16px rgba(59, 130, 246, 0.4), 0 0 8px rgba(147, 51, 234, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2)', transition: 'width 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s ease', overflow: 'hidden', }); // Effet de brillance animé sur la barre de progression const shine = document.createElement('div'); Object.assign(shine.style, { position: 'absolute', top: '0', left: '-100%', width: '100%', height: '100%', background: 'linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent)', animation: 'sliderShine 2s ease-in-out infinite', }); progressFill.appendChild(shine); // Ajout de l'animation CSS pour l'effet de brillance if (!document.querySelector('#slider-shine-animation')) { const style = document.createElement('style'); style.id = 'slider-shine-animation'; style.textContent = ` @keyframes sliderShine { 0% { left: -100%; } 50% { left: 100%; } 100% { left: 100%; } } `; document.head.appendChild(style); } // Assemblage du track sliderWrapper.appendChild(track); sliderWrapper.appendChild(progressFill); // Input invisible pour la fonctionnalité Object.assign(slider.style, { position: 'absolute', top: '0', left: '0', width: '100%', height: '32px', opacity: '0', margin: '0', cursor: 'pointer', zIndex: '3', }); // Thumb personnalisé avec glassmorphism const thumb = document.createElement('div'); const thumbPosition = ((value - min) / (max - min)) * 100; Object.assign(thumb.style, { position: 'absolute', top: '50%', left: `${thumbPosition}%`, width: '18px', height: '18px', transform: 'translate(-50%, -50%)', borderRadius: '50%', background: 'linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.7) 100%)', backdropFilter: 'blur(10px) saturate(180%)', WebkitBackdropFilter: 'blur(10px) saturate(180%)', border: '1px solid rgba(59, 130, 246, 0.6)', boxShadow: '0 3px 12px rgba(59, 130, 246, 0.25), 0 1px 6px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.8)', cursor: 'grab', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', zIndex: '2', }); // Point central du thumb const thumbCenter = document.createElement('div'); Object.assign(thumbCenter.style, { position: 'absolute', top: '50%', left: '50%', width: '6px', height: '6px', transform: 'translate(-50%, -50%)', borderRadius: '50%', background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.8), rgba(147, 51, 234, 0.8))', boxShadow: '0 0 6px rgba(59, 130, 246, 0.5)', }); thumb.appendChild(thumbCenter); // Affichage de la valeur avec style moderne let valueDisplay = null; if (showValue) { valueDisplay = document.createElement('div'); valueDisplay.textContent = value.toString(); Object.assign(valueDisplay.style, { position: 'absolute', bottom: '-40px', left: `${thumbPosition}%`, transform: 'translateX(-50%)', fontFamily: this.fonts.primary, fontSize: '12px', fontWeight: '600', color: '#ffffff', background: 'transparent', padding: '4px 8px', textShadow: '0 1px 2px rgba(0, 0, 0, 0.8)', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', zIndex: '4', }); sliderWrapper.appendChild(valueDisplay); } // Labels min/max avec style amélioré const labelsContainer = document.createElement('div'); Object.assign(labelsContainer.style, { display: 'flex', justifyContent: 'space-between', marginTop: '12px', fontSize: '11px', fontWeight: '500', color: 'rgba(255, 255, 255, 0.8)', textShadow: '0 1px 2px rgba(0, 0, 0, 0.3)', }); const minLabel = document.createElement('div'); minLabel.textContent = min.toString(); const maxLabel = document.createElement('div'); maxLabel.textContent = max.toString(); labelsContainer.appendChild(minLabel); labelsContainer.appendChild(maxLabel); // Gestion des événements avec animations fluides slider.addEventListener('input', () => { const newValue = parseInt(slider.value); const percentage = ((newValue - min) / (max - min)) * 100; // Animation du thumb thumb.style.left = `${percentage}%`; // Animation de la barre de progression progressFill.style.width = `${percentage}%`; // Mise à jour de l'affichage de la valeur if (valueDisplay) { valueDisplay.textContent = newValue.toString(); valueDisplay.style.left = `${percentage}%`; } // Callback onChange(newValue); }); // Effets de survol et d'interaction slider.addEventListener('mousedown', () => { thumb.style.cursor = 'grabbing'; thumb.style.transform = 'translate(-50%, -50%) scale(1.1)'; thumb.style.boxShadow = '0 5px 16px rgba(59, 130, 246, 0.35), 0 2px 10px rgba(0, 0, 0, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.9)'; progressFill.style.boxShadow = '0 0 20px rgba(59, 130, 246, 0.5), 0 0 12px rgba(147, 51, 234, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3)'; }); document.addEventListener('mouseup', () => { thumb.style.cursor = 'grab'; thumb.style.transform = 'translate(-50%, -50%) scale(1)'; thumb.style.boxShadow = '0 3px 12px rgba(59, 130, 246, 0.25), 0 1px 6px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.8)'; progressFill.style.boxShadow = '0 0 16px rgba(59, 130, 246, 0.4), 0 0 8px rgba(147, 51, 234, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2)'; }); // Effet de survol sliderWrapper.addEventListener('mouseenter', () => { if (thumb.style.cursor !== 'grabbing') { thumb.style.transform = 'translate(-50%, -50%) scale(1.05)'; thumb.style.boxShadow = '0 4px 14px rgba(59, 130, 246, 0.3), 0 2px 8px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.85)'; } }); sliderWrapper.addEventListener('mouseleave', () => { if (thumb.style.cursor !== 'grabbing') { thumb.style.transform = 'translate(-50%, -50%) scale(1)'; thumb.style.boxShadow = '0 3px 12px rgba(59, 130, 246, 0.25), 0 1px 6px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.8)'; } }); // Assemblage final sliderWrapper.appendChild(slider); sliderWrapper.appendChild(thumb); container.appendChild(sliderWrapper); container.appendChild(labelsContainer); return container; } /** * Creates a modern notification with glassmorphism effect * @param message Notification message * @param type Notification type * @param duration Duration in ms * @returns HTMLDivElement */ static createNotification(message, type, duration = 3000) { const notification = document.createElement('div'); // Apply glassmorphism effect this.applyGlassEffect(notification, 'medium', { padding: `${this.spacing.md} ${this.spacing.lg}`, margin: this.spacing.md, borderLeft: `4px solid ${this.colors[type]}`, color: this.colors.light, fontFamily: this.fonts.primary, fontSize: this.fonts.sizes.sm, position: 'relative', animation: `fadeInRight ${this.animation.normal} forwards`, maxWidth: '300px', boxSizing: 'border-box', }); notification.textContent = message; // Create and add animation styles if they don't exist if (!document.getElementById('kxs-notification-animations')) { const style = document.createElement('style'); style.id = 'kxs-notification-animations'; style.textContent = ` @keyframes fadeInRight { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } `; document.head.appendChild(style); } // Auto-remove after duration if (duration > 0) { setTimeout(() => { notification.style.animation = `fadeOut ${this.animation.normal} forwards`; // Use event listener for animation end instead of setTimeout notification.addEventListener('animationend', function onAnimationEnd() { if (notification.parentNode) { notification.parentNode.removeChild(notification); } notification.removeEventListener('animationend', onAnimationEnd); }, { once: true }); }, duration); } return notification; } } // Color palette DesignSystem.colors = { primary: 'rgba(59, 130, 246, 0.9)', // Blue secondary: 'rgba(139, 92, 246, 0.9)', // Purple accent: 'rgba(236, 72, 153, 0.9)', // Pink dark: 'rgba(17, 24, 39, 0.8)', // Dark background light: 'rgba(255, 255, 255, 0.9)', // Light text success: 'rgba(16, 185, 129, 0.9)', // Green warning: 'rgba(245, 158, 11, 0.9)', // Orange danger: 'rgba(239, 68, 68, 0.9)', // Red info: 'rgba(59, 130, 246, 0.9)', // Blue }; // Glassmorphism effects DesignSystem.glass = { light: { background: 'rgba(255, 255, 255, 0.1)', blur: '10px', border: '1px solid rgba(255, 255, 255, 0.18)', shadow: '0 8px 32px 0 rgba(31, 38, 135, 0.37)', }, medium: { background: 'rgba(255, 255, 255, 0.15)', blur: '15px', border: '1px solid rgba(255, 255, 255, 0.2)', shadow: '0 8px 32px 0 rgba(31, 38, 135, 0.4)', }, dark: { background: 'rgba(17, 24, 39, 0.75)', blur: '20px', border: '1px solid rgba(255, 255, 255, 0.1)', shadow: '0 8px 32px 0 rgba(0, 0, 0, 0.5)', }, }; // Classic styles (non-glassmorphism) DesignSystem.classic = { light: { background: 'rgba(240, 240, 240, 0.9)', border: '1px solid #ccc', shadow: '0 2px 5px rgba(0, 0, 0, 0.2)', }, medium: { background: 'rgba(220, 220, 220, 0.95)', border: '1px solid #bbb', shadow: '0 3px 6px rgba(0, 0, 0, 0.25)', }, dark: { background: 'rgba(50, 50, 50, 0.9)', border: '1px solid #555', shadow: '0 3px 8px rgba(0, 0, 0, 0.3)', }, }; // Font settings DesignSystem.fonts = { primary: '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif', secondary: '"Cinzel", serif', sizes: { xs: '0.75rem', sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem', '4xl': '2.25rem', } }; // Border radius DesignSystem.radius = { sm: '0.25rem', md: '0.5rem', lg: '1rem', xl: '1.5rem', full: '9999px', }; // Spacing DesignSystem.spacing = { xs: '0.25rem', sm: '0.5rem', md: '1rem', lg: '1.5rem', xl: '2rem', '2xl': '3rem', }; // Animation durations DesignSystem.animation = { fast: '0.15s', normal: '0.3s', slow: '0.5s', pulse: 'pulse', }; // Z-index layers DesignSystem.layers = { base: 1, menu: 10, modal: 20, tooltip: 30, notification: 40, }; ;// ./src/HUD/MOD/LoadingScreen.ts /** * LoadingScreen.ts * * This module provides a loading animation with a logo and a rotating loading circle * that displays during the loading of game resources. */ class LoadingScreen { /** * Creates a new instance of the loading screen * @param logoUrl URL of the Kxs logo to display */ constructor(logoUrl) { this.logoUrl = logoUrl; this.container = document.createElement('div'); this.initializeStyles(); this.createContent(); } /** * Initializes CSS styles for the loading screen */ initializeStyles() { // Apply glassmorphism effect using DesignSystem DesignSystem.applyGlassEffect(this.container, 'dark', { position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', zIndex: DesignSystem.layers.modal.toString(), transition: `opacity ${DesignSystem.animation.slow} ease-in-out`, animation: 'fadeIn 0.5s ease-in-out', borderRadius: '0' }); } /** * Creates the loading screen content (logo and loading circle) */ createContent() { // Create container for the logo const logoContainer = document.createElement('div'); Object.assign(logoContainer.style, { width: '200px', height: '200px', marginBottom: '20px', position: 'relative', display: 'flex', justifyContent: 'center', alignItems: 'center' }); // Create the logo element const logo = document.createElement('img'); logo.src = this.logoUrl; Object.assign(logo.style, { width: '150px', height: '150px', objectFit: 'contain', position: 'absolute', zIndex: '2', animation: 'pulse 2s ease-in-out infinite' }); // Create the main loading circle const loadingCircle = document.createElement('div'); Object.assign(loadingCircle.style, { width: '180px', height: '180px', border: '4px solid transparent', borderTopColor: '#3498db', borderRadius: '50%', animation: 'spin 1.5s linear infinite', position: 'absolute', zIndex: '1' }); // Create a second loading circle (rotating in the opposite direction) const loadingCircle2 = document.createElement('div'); Object.assign(loadingCircle2.style, { width: '200px', height: '200px', border: '2px solid transparent', borderLeftColor: '#e74c3c', borderRightColor: '#e74c3c', borderRadius: '50%', animation: 'spin-reverse 3s linear infinite', position: 'absolute', zIndex: '0' }); // Add animations const styleSheet = document.createElement('style'); styleSheet.textContent = ` @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes spin-reverse { 0% { transform: rotate(0deg); } 100% { transform: rotate(-360deg); } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } `; document.head.appendChild(styleSheet); // Ajout d'un texte de chargement const loadingText = document.createElement('div'); loadingText.textContent = 'Loading...'; Object.assign(loadingText.style, { color: 'white', fontFamily: 'Arial, sans-serif', fontSize: '18px', marginTop: '20px', animation: 'pulse 1.5s ease-in-out infinite' }); // Ajout d'un sous-texte const subText = document.createElement('div'); subText.textContent = 'Initializing resources...'; Object.assign(subText.style, { color: 'rgba(255, 255, 255, 0.7)', fontFamily: 'Arial, sans-serif', fontSize: '14px', marginTop: '5px' }); // Assemble the elements logoContainer.appendChild(loadingCircle2); logoContainer.appendChild(loadingCircle); logoContainer.appendChild(logo); this.container.appendChild(logoContainer); this.container.appendChild(loadingText); this.container.appendChild(subText); } /** * Shows the loading screen */ show() { document.body.appendChild(this.container); } /** * Hides the loading screen with a fade transition */ hide() { this.container.style.opacity = '0'; // Optimized: use event listener for transition end instead of setTimeout this.container.addEventListener('transitionend', () => { if (this.container.parentNode) { document.body.removeChild(this.container); } }, { once: true }); } } ;// ./src/HUD/ServerSelector.ts class ServerSelector { constructor(servers, onServerSelect) { this.isActive = false; this.serverContainer = null; this.serverCards = []; this.selectedIndex = 0; this.originalBodyContent = ''; this.animation = null; this.servers = []; this.onServerSelect = null; this.servers = this.processServerUrls(servers); this.onServerSelect = onServerSelect || null; } /** * Process server URLs from match patterns to display-friendly names */ processServerUrls(servers) { return servers.map(server => { // Remove wildcards and protocol return server.replace(/^\*:\/\//, '') // Remove trailing wildcards .replace(/\/\*$/, '') // Handle special case for IP addresses .replace(/\/+$/, ''); }); } /** * Show the server selection interface */ show() { // If already active, close first to reset properly if (this.isActive) { this.close(); } this.isActive = true; // Store original content if not already stored if (!this.originalBodyContent) { this.originalBodyContent = document.body.innerHTML; } // Create overlay this.createInterface(); // Start animations this.startAnimations(); // Add keyboard navigation this.setupKeyboardNavigation(); } /** * Create the server selection interface */ createInterface() { // Create overlay container const overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.9)'; overlay.style.display = 'flex'; overlay.style.flexDirection = 'column'; overlay.style.justifyContent = 'center'; overlay.style.alignItems = 'center'; overlay.style.zIndex = '10000'; overlay.style.perspective = '1000px'; overlay.style.fontFamily = 'Arial, sans-serif'; // Create header const header = document.createElement('h1'); header.textContent = 'Select Server'; header.style.color = '#fff'; header.style.marginBottom = '40px'; header.style.fontSize = '36px'; header.style.textShadow = '0 0 10px rgba(255,0,0,0.8)'; overlay.appendChild(header); // Create server container this.serverContainer = document.createElement('div'); this.serverContainer.style.position = 'relative'; this.serverContainer.style.width = '80%'; this.serverContainer.style.height = '300px'; this.serverContainer.style.display = 'flex'; this.serverContainer.style.justifyContent = 'center'; this.serverContainer.style.alignItems = 'center'; this.serverContainer.style.transformStyle = 'preserve-3d'; overlay.appendChild(this.serverContainer); // Create instructions const instructions = document.createElement('div'); instructions.style.position = 'absolute'; instructions.style.bottom = '20px'; instructions.style.color = '#aaa'; instructions.style.fontSize = '16px'; instructions.innerHTML = 'Use ←/→ arrows to navigate | Enter to select | Esc to close'; overlay.appendChild(instructions); // Create server cards this.createServerCards(); // Add the overlay to the body document.body.appendChild(overlay); } /** * Create 3D rotating cards for each server */ createServerCards() { if (!this.serverContainer) return; const totalServers = this.servers.length; const radius = 300; // Radius of the circle const cardWidth = 200; const cardHeight = 120; this.servers.forEach((server, index) => { const card = document.createElement('div'); card.className = 'server-card'; card.style.position = 'absolute'; card.style.width = `${cardWidth}px`; card.style.height = `${cardHeight}px`; card.style.backgroundColor = index === this.selectedIndex ? '#500' : '#333'; card.style.color = '#fff'; card.style.borderRadius = '10px'; card.style.display = 'flex'; card.style.flexDirection = 'column'; card.style.justifyContent = 'center'; card.style.alignItems = 'center'; card.style.cursor = 'pointer'; card.style.boxShadow = '0 10px 20px rgba(0,0,0,0.5)'; card.style.transition = 'background-color 0.3s ease'; card.style.padding = '15px'; card.style.backfaceVisibility = 'hidden'; // Create server name const serverName = document.createElement('h2'); serverName.textContent = server; serverName.style.margin = '0 0 10px 0'; serverName.style.fontSize = '20px'; card.appendChild(serverName); // Add status indicator const status = document.createElement('div'); status.style.width = '10px'; status.style.height = '10px'; status.style.borderRadius = '50%'; status.style.backgroundColor = '#0f0'; // Green for online status.style.marginTop = '10px'; card.appendChild(status); // Add click event card.addEventListener('click', () => { this.selectedIndex = index; this.updateCardPositions(); this.selectServer(); }); this.serverCards.push(card); if (this.serverContainer) { this.serverContainer.appendChild(card); } }); // Position the cards in a circle this.updateCardPositions(); } /** * Update the positions of all server cards in a 3D circle */ updateCardPositions() { const totalServers = this.servers.length; const radius = Math.max(300, totalServers * 40); // Adjust radius based on number of servers this.serverCards.forEach((card, index) => { // Calculate position on the circle const theta = ((index - this.selectedIndex) / totalServers) * 2 * Math.PI; const x = radius * Math.sin(theta); const z = radius * Math.cos(theta) - radius; // Update card style card.style.transform = `translateX(${x}px) translateZ(${z}px) rotateY(${-theta * 180 / Math.PI}deg)`; card.style.zIndex = z < 0 ? '-1' : '1'; card.style.opacity = (1 - Math.abs(index - this.selectedIndex) / totalServers).toString(); card.style.backgroundColor = index === this.selectedIndex ? '#500' : '#333'; // Add glow effect to selected card if (index === this.selectedIndex) { card.style.boxShadow = '0 0 20px rgba(255,0,0,0.8), 0 10px 20px rgba(0,0,0,0.5)'; } else { card.style.boxShadow = '0 10px 20px rgba(0,0,0,0.5)'; } }); } /** * Start animations for the 3D carousel */ startAnimations() { // Subtle continuous movement for more 3D effect using requestAnimationFrame let angle = 0; let animationId; const animate = () => { angle += 0.005; if (this.serverContainer) { this.serverContainer.style.transform = `rotateY(${Math.sin(angle) * 5}deg) rotateX(${Math.cos(angle) * 3}deg)`; } animationId = requestAnimationFrame(animate); }; // Store the animation ID for cleanup this.animation = animationId = requestAnimationFrame(animate); } /** * Set up keyboard navigation */ setupKeyboardNavigation() { const keyHandler = (e) => { switch (e.key) { case 'ArrowLeft': this.navigate(-1); break; case 'ArrowRight': this.navigate(1); break; case 'Enter': this.selectServer(); break; case 'Escape': this.close(); break; } }; document.addEventListener('keydown', keyHandler); // Store the handler reference so it can be removed when the selector is closed this._keyHandler = keyHandler; } /** * Navigate between servers */ navigate(direction) { const totalServers = this.servers.length; this.selectedIndex = (this.selectedIndex + direction + totalServers) % totalServers; this.updateCardPositions(); } /** * Select current server and close the selector */ selectServer() { const selectedServer = this.servers[this.selectedIndex]; if (this.onServerSelect && selectedServer) { this.onServerSelect(selectedServer); } this.close(); } /** * Close the server selector */ close() { var _a; if (!this.isActive) return; this.isActive = false; // Stop animations if (this.animation !== null) { clearInterval(this.animation); this.animation = null; } // Remove keyboard event listener if (this._keyHandler) { document.removeEventListener('keydown', this._keyHandler); this._keyHandler = null; } // Remove the overlay document.querySelectorAll('div.server-card').forEach(el => el.remove()); if (this.serverContainer && this.serverContainer.parentNode) { const parent = this.serverContainer.parentNode; if (parent && parent instanceof HTMLElement) { parent.remove(); } else if (parent) { // Fallback if parentNode exists but isn't an HTMLElement const parentEl = parent; (_a = parentEl.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(parentEl); } } // Reset state for next use this.serverContainer = null; this.serverCards = []; this.selectedIndex = 0; } } ;// ./src/HUD/EasterEgg.ts class EasterEgg { constructor() { this.originalStyles = {}; this.zelda3Sound = null; this.periodSound = null; this.ambientSound = null; this.buttonClickSound = null; this.arrowKeySound = null; this.enterKeySound = null; this.closeMenuSound = null; this.textElement = null; this.fireElements = []; this.pillars = []; this.isActive = false; this.isInitialized = false; this.overlayElement = null; this.animationFrameId = null; this.originalBodyContent = ''; this.serverSelector = null; this.serverButton = null; this.messageChangeInterval = null; this.originalPageTitle = ''; this.messages = [ "You're already in", "You didnt have found Kxs, is kxs who found you", "The prophecies are true", "Kxs is the chosen one", "Kxs is the one who will save you", "I am Kxs, the one who will save you" ]; this.globalEventHandlersInitialized = false; this.init(); } init() { // Save original page title this.originalPageTitle = document.title; // Check if we're on the target website if (window.location.hostname === 'kxs.rip' || window.location.hostname === 'www.kxs.rip') { // Initialize sounds this.zelda3Sound = new Audio('https://kxs.rip/assets/message.mp3'); // Replace with actual Zelda sound this.periodSound = new Audio('https://kxs.rip/assets/message-finish.mp3'); // Sound for the final period this.ambientSound = new Audio('https://kxs.rip/assets/hell_ambiance.m4a'); // Replace with actual ambient URL this.buttonClickSound = new Audio('https://kxs.rip/assets/enter.mp3'); // Button click sound this.arrowKeySound = new Audio('https://kxs.rip/assets/arrow.mp3'); // Arrow key sound this.enterKeySound = new Audio('https://kxs.rip/assets/enter.mp3'); // Enter key sound this.closeMenuSound = new Audio('https://kxs.rip/assets/close.mp3'); // Close menu sound if (this.ambientSound) { this.ambientSound.loop = true; } // Create the initial overlay with Click prompt instead of immediately applying Easter egg this.createInitialOverlay(); // Initialize global event handlers for interaction sounds this.initGlobalEventHandlers(); } } /** * Creates the initial blur overlay with Click text */ createInitialOverlay() { // Store original body content to restore it later if needed this.originalBodyContent = document.body.innerHTML; // Save original styles this.saveOriginalStyles(); // Create the overlay this.overlayElement = document.createElement('div'); const overlay = this.overlayElement; // Set full screen styles overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.3)'; overlay.style.backdropFilter = 'blur(10px)'; overlay.style['-webkit-backdrop-filter'] = 'blur(10px)'; overlay.style.display = 'flex'; overlay.style.justifyContent = 'center'; overlay.style.alignItems = 'center'; overlay.style.cursor = 'pointer'; overlay.style.zIndex = '9999'; overlay.style.transition = 'opacity 0.5s ease'; // Create the Click text const clickText = document.createElement('div'); clickText.textContent = 'Click'; clickText.style.color = '#fff'; clickText.style.fontSize = '3rem'; clickText.style.fontWeight = 'bold'; clickText.style.textShadow = '0 0 10px rgba(255, 255, 255, 0.7)'; clickText.style.fontFamily = '"Cinzel", "Trajan Pro", serif'; clickText.style.letterSpacing = '5px'; // Add font for the text const fontLink = document.createElement('link'); fontLink.rel = 'stylesheet'; fontLink.href = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@700&display=swap'; document.head.appendChild(fontLink); // Add click event to start the Easter egg overlay.addEventListener('click', () => { this.removeOverlay(); this.applyEasterEgg(); }); // Add the text to the overlay overlay.appendChild(clickText); // Add the overlay to the body document.body.appendChild(overlay); } /** * Removes the initial overlay */ removeOverlay() { if (this.overlayElement && this.overlayElement.parentNode) { // Fade out this.overlayElement.style.opacity = '0'; // Remove after transition (optimized) this.overlayElement.addEventListener('transitionend', () => { if (this.overlayElement && this.overlayElement.parentNode) { this.overlayElement.parentNode.removeChild(this.overlayElement); this.overlayElement = null; } }, { once: true }); } } /** * Initialize global event handlers for sounds */ initGlobalEventHandlers() { if (this.globalEventHandlersInitialized) return; this.globalEventHandlersInitialized = true; // Play sound on button clicks document.addEventListener('click', (e) => { if (e.target instanceof HTMLButtonElement || e.target instanceof HTMLAnchorElement || (e.target instanceof HTMLElement && e.target.role === 'button')) { this.playButtonSound(); } }); // Play sound on arrow keys and enter key document.addEventListener('keydown', (e) => { if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') { this.playArrowKeySound(); } else if (e.key === 'Enter') { this.playEnterKeySound(); } }); } applyEasterEgg() { if (this.isActive) return; this.isActive = true; this.isInitialized = true; // Transform the website this.transformWebsite(); // Start animations this.startAnimations(); // Play ambient sound this.playAmbientSound(); // Display the message with sound effect (optimized) setTimeout(() => { this.displayMessage(); // Add server selector button after the message is displayed this.addServerSelectorButton(); }, 2000); } saveOriginalStyles() { this.originalStyles = { bodyBackground: document.body.style.background, bodyColor: document.body.style.color, bodyOverflow: document.body.style.overflow }; } transformWebsite() { // Clear the existing content document.body.innerHTML = ''; document.body.style.margin = '0'; document.body.style.padding = '0'; document.body.style.overflow = 'hidden'; document.body.style.backgroundColor = '#000'; document.body.style.color = '#fff'; document.body.style.fontFamily = '"Times New Roman", serif'; document.body.style.height = '100vh'; document.body.style.display = 'flex'; document.body.style.flexDirection = 'column'; document.body.style.justifyContent = 'center'; document.body.style.alignItems = 'center'; document.body.style.perspective = '1000px'; // Create a temple background const temple = document.createElement('div'); temple.style.position = 'absolute'; temple.style.top = '0'; temple.style.left = '0'; temple.style.width = '100%'; temple.style.height = '100%'; temple.style.background = 'linear-gradient(to bottom, #000, #300)'; temple.style.zIndex = '-2'; document.body.appendChild(temple); // Create pillars for (let i = 0; i < 6; i++) { const pillar = document.createElement('div'); pillar.style.position = 'absolute'; pillar.style.width = '80px'; pillar.style.height = '100%'; pillar.style.background = 'linear-gradient(to bottom, #222, #111)'; pillar.style.transform = `rotateY(${i * 60}deg) translateZ(400px)`; pillar.style.boxShadow = 'inset 0 0 20px #500'; pillar.style.transition = 'transform 0.5s ease-in-out'; this.pillars.push(pillar); document.body.appendChild(pillar); } // Create floor const floor = document.createElement('div'); floor.style.position = 'absolute'; floor.style.bottom = '0'; floor.style.width = '100%'; floor.style.height = '40%'; floor.style.background = 'radial-gradient(circle, #300, #100)'; floor.style.zIndex = '-1'; document.body.appendChild(floor); // Create text container for the message this.textElement = document.createElement('div'); this.textElement.style.position = 'relative'; this.textElement.style.fontSize = '3.5em'; this.textElement.style.fontWeight = 'bold'; this.textElement.style.fontFamily = '"Cinzel", "Trajan Pro", serif'; this.textElement.style.color = '#f00'; this.textElement.style.textShadow = '0 0 10px #f00, 0 0 20px #f00, 0 0 30px #900'; this.textElement.style.letterSpacing = '2px'; this.textElement.style.opacity = '0'; this.textElement.style.transition = 'opacity 2s'; // Add a fancy font from Google Fonts const fontLink = document.createElement('link'); fontLink.rel = 'stylesheet'; fontLink.href = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@700&display=swap'; document.head.appendChild(fontLink); document.body.appendChild(this.textElement); // Create fire elements as 3D rotating rectangles for (let i = 0; i < 20; i++) { const fire = document.createElement('div'); fire.style.position = 'absolute'; fire.style.width = `${Math.random() * 40 + 20}px`; fire.style.height = `${Math.random() * 60 + 40}px`; fire.style.background = 'radial-gradient(circle, #f50, #900, transparent)'; fire.style.borderRadius = '10%'; fire.style.filter = 'blur(3px)'; fire.style.opacity = `${Math.random() * 0.5 + 0.5}`; const randomX = Math.random() * 100; fire.style.left = `${randomX}%`; fire.style.bottom = '0'; fire.style.zIndex = '-1'; fire.style.transformStyle = 'preserve-3d'; fire.style.perspective = '1000px'; fire.dataset.velocityY = `${Math.random() * 2 + 1}`; fire.dataset.posX = randomX.toString(); fire.dataset.posY = '0'; fire.dataset.rotateX = `${Math.random() * 4 - 2}`; // Random rotation speed X fire.dataset.rotateY = `${Math.random() * 4 - 2}`; // Random rotation speed Y fire.dataset.rotateZ = `${Math.random() * 4 - 2}`; // Random rotation speed Z fire.dataset.rotationX = '0'; fire.dataset.rotationY = '0'; fire.dataset.rotationZ = '0'; this.fireElements.push(fire); document.body.appendChild(fire); } } startAnimations() { // Animate fire and pillars this.animateFireElements(); this.animatePillars(); } animateFireElements() { if (!this.isActive) return; this.fireElements.forEach(fire => { let posY = parseFloat(fire.dataset.posY || '0'); const velocityY = parseFloat(fire.dataset.velocityY || '1'); // Update position posY += velocityY; fire.dataset.posY = posY.toString(); // Update rotation let rotX = parseFloat(fire.dataset.rotationX || '0'); let rotY = parseFloat(fire.dataset.rotationY || '0'); let rotZ = parseFloat(fire.dataset.rotationZ || '0'); rotX += parseFloat(fire.dataset.rotateX || '0'); rotY += parseFloat(fire.dataset.rotateY || '0'); rotZ += parseFloat(fire.dataset.rotateZ || '0'); fire.dataset.rotationX = rotX.toString(); fire.dataset.rotationY = rotY.toString(); fire.dataset.rotationZ = rotZ.toString(); // Apply transform fire.style.transform = `translateY(${-posY}px) rotateX(${rotX}deg) rotateY(${rotY}deg) rotateZ(${rotZ}deg)`; // Reset fire when it goes off screen if (posY > 100) { posY = 0; fire.dataset.posY = '0'; fire.style.opacity = `${Math.random() * 0.5 + 0.5}`; fire.style.width = `${Math.random() * 40 + 20}px`; fire.style.height = `${Math.random() * 60 + 40}px`; const randomX = Math.random() * 100; fire.style.left = `${randomX}%`; fire.dataset.posX = randomX.toString(); // Reset rotation speeds fire.dataset.rotateX = `${Math.random() * 4 - 2}`; fire.dataset.rotateY = `${Math.random() * 4 - 2}`; fire.dataset.rotateZ = `${Math.random() * 4 - 2}`; } fire.style.opacity = `${Math.max(0, 1 - posY / 100)}`; }); this.animationFrameId = requestAnimationFrame(() => this.animateFireElements()); } animatePillars() { if (!this.isActive) return; // Create a slow rotation effect for the pillars using requestAnimationFrame let angle = 0; let lastTime = 0; const animate = (currentTime) => { if (!this.isActive) return; // Throttle to ~10fps instead of 60fps for this slow animation if (currentTime - lastTime >= 100) { angle += 0.5; this.pillars.forEach((pillar, index) => { pillar.style.transform = `rotateY(${index * 60 + angle}deg) translateZ(400px)`; }); lastTime = currentTime; } requestAnimationFrame(animate); }; requestAnimationFrame(animate); } playAmbientSound() { // Play ambient sound if (this.ambientSound) { this.ambientSound.volume = 0.3; this.ambientSound.play().catch(err => { }); } } /** * Temporarily reduce ambient sound volume to allow other sounds to be heard better */ lowerAmbientVolume() { if (this.ambientSound) { // Store current volume if we need it const originalVolume = this.ambientSound.volume; // Lower volume this.ambientSound.volume = 0.1; // Lower to 1/3 of original volume // Restore volume after a delay setTimeout(() => { if (this.ambientSound) { this.ambientSound.volume = 0.3; // Restore to original volume } }, 500); // Half second delay } } /** * Play button click sound */ playButtonSound() { if (this.buttonClickSound) { // Lower ambient volume this.lowerAmbientVolume(); this.buttonClickSound.currentTime = 0; this.buttonClickSound.volume = 0.3; this.buttonClickSound.play().catch(err => { }); } } /** * Play arrow key sound */ playArrowKeySound() { if (this.arrowKeySound) { // Lower ambient volume this.lowerAmbientVolume(); this.arrowKeySound.currentTime = 0; this.arrowKeySound.volume = 0.3; this.arrowKeySound.play().catch(err => { }); } } /** * Play enter key sound */ playEnterKeySound() { if (this.enterKeySound) { // Lower ambient volume this.lowerAmbientVolume(); this.enterKeySound.currentTime = 0; this.enterKeySound.volume = 0.3; this.enterKeySound.play().catch(err => { }); } } displayMessage() { if (!this.textElement) return; // Set the message text and start with the first message this.typeMessage(this.messages[0]); // Set up message changing at random intervals this.setupMessageChanging(); } /** * Type out a message with the typewriter effect */ typeMessage(message) { if (!this.textElement) return; // Clear current text and ensure visibility this.textElement.textContent = ''; this.textElement.style.opacity = '1'; // Update page title with message document.title = message; // Calculate typing speed based on message length // Longer messages type faster (inversely proportional) const baseSpeed = 300; // Base speed in ms const minSpeed = 40; // Minimum speed for very long messages const typeSpeed = Math.max(minSpeed, baseSpeed - (message.length * 5)); // Type writer effect with Zelda sound let i = 0; const typeInterval = setInterval(() => { if (i < message.length && this.textElement) { // Check if we're at the last character and it's not already a period const isLastChar = i === message.length - 1; const shouldAddPeriod = isLastChar && message.charAt(i) !== '.'; // Play the appropriate sound if (isLastChar && this.periodSound) { // Play special sound for the last character this.periodSound.currentTime = 0; this.periodSound.volume = 0.3; this.periodSound.play().catch(err => { }); } else if (this.zelda3Sound) { // Play regular typing sound this.zelda3Sound.currentTime = 0; this.zelda3Sound.volume = 0.2; this.zelda3Sound.play().catch(err => { }); } // Add character to text element this.textElement.textContent += message.charAt(i); // Update page title in real-time with the current text document.title = this.textElement.textContent || message; // If last character and we should add a period, do it with a pause (optimized) if (shouldAddPeriod) { setTimeout(() => { if (this.textElement && this.periodSound) { this.periodSound.currentTime = 0; this.periodSound.volume = 0.4; this.periodSound.play().catch(err => { }); this.textElement.textContent += '.'; // Update title with the final period document.title = this.textElement.textContent || (message + '.'); } }, 400); } i++; } else { clearInterval(typeInterval); } }, typeSpeed); // Dynamic typing speed based on message length } /** * Setup changing messages at random intervals */ setupMessageChanging() { // Function to change to a random message const changeMessage = () => { // Get a random message that's different from the current one if (!this.textElement) return; const currentMessage = this.textElement.textContent || ''; let newMessage = currentMessage; // Make sure we pick a different message while (newMessage === currentMessage) { const randomIndex = Math.floor(Math.random() * this.messages.length); newMessage = this.messages[randomIndex]; } // Type the new message this.typeMessage(newMessage); // Schedule the next message change this.scheduleNextMessageChange(); }; // Schedule the first message change this.scheduleNextMessageChange(); } /** * Schedule the next message change with a random delay */ scheduleNextMessageChange() { // Clear any existing timer if (this.messageChangeInterval !== null) { clearTimeout(this.messageChangeInterval); } // Random delay between 4 and 19 seconds const delay = Math.floor(Math.random() * 15000) + 4000; // 4-19 seconds // Set timeout for next message change this.messageChangeInterval = window.setTimeout(() => { // Get a random message that's different from the current one if (!this.textElement) return; const currentMessage = this.textElement.textContent || ''; let newMessage = currentMessage; // Make sure we pick a different message while (newMessage === currentMessage) { const randomIndex = Math.floor(Math.random() * this.messages.length); newMessage = this.messages[randomIndex]; } // Type the new message this.typeMessage(newMessage); // Schedule the next message change this.scheduleNextMessageChange(); }, delay); } /** * Add a button to open the server selector */ addServerSelectorButton() { // Create a button this.serverButton = document.createElement('button'); const button = this.serverButton; // Set button text button.textContent = 'SELECT SERVER'; // Position and base styling button.style.position = 'absolute'; button.style.bottom = '30px'; button.style.left = '50%'; button.style.transform = 'translateX(-50%)'; // Enhanced styling button.style.backgroundColor = 'transparent'; button.style.color = '#ff9'; button.style.border = '2px solid #900'; button.style.padding = '15px 30px'; button.style.fontSize = '20px'; button.style.fontFamily = '"Cinzel", "Trajan Pro", serif'; button.style.fontWeight = 'bold'; button.style.letterSpacing = '3px'; button.style.borderRadius = '3px'; button.style.textTransform = 'uppercase'; button.style.boxShadow = '0 0 20px rgba(255, 30, 0, 0.6), inset 0 0 10px rgba(255, 50, 0, 0.4)'; button.style.textShadow = '0 0 10px rgba(255, 150, 0, 0.8), 0 0 5px rgba(255, 100, 0, 0.5)'; button.style.cursor = 'pointer'; button.style.zIndex = '100'; button.style.opacity = '0'; button.style.transition = 'all 0.5s ease-in-out'; button.style.background = 'linear-gradient(to bottom, rgba(80, 0, 0, 0.8), rgba(30, 0, 0, 0.9))'; button.style.backdropFilter = 'blur(3px)'; // Add enhanced hover effects button.addEventListener('mouseover', () => { button.style.color = '#fff'; button.style.borderColor = '#f00'; button.style.boxShadow = '0 0 25px rgba(255, 50, 0, 0.8), inset 0 0 15px rgba(255, 100, 0, 0.6)'; button.style.textShadow = '0 0 15px rgba(255, 200, 0, 1), 0 0 10px rgba(255, 150, 0, 0.8)'; button.style.transform = 'translateX(-50%) scale(1.05)'; button.style.background = 'linear-gradient(to bottom, rgba(100, 0, 0, 0.9), rgba(50, 0, 0, 1))'; }); button.addEventListener('mouseout', () => { button.style.color = '#ff9'; button.style.borderColor = '#900'; button.style.boxShadow = '0 0 20px rgba(255, 30, 0, 0.6), inset 0 0 10px rgba(255, 50, 0, 0.4)'; button.style.textShadow = '0 0 10px rgba(255, 150, 0, 0.8), 0 0 5px rgba(255, 100, 0, 0.5)'; button.style.transform = 'translateX(-50%)'; button.style.background = 'linear-gradient(to bottom, rgba(80, 0, 0, 0.8), rgba(30, 0, 0, 0.9))'; }); // Add active/press effect button.addEventListener('mousedown', () => { button.style.transform = 'translateX(-50%) scale(0.98)'; button.style.boxShadow = '0 0 10px rgba(255, 30, 0, 0.8), inset 0 0 8px rgba(255, 100, 0, 0.8)'; }); button.addEventListener('mouseup', () => { button.style.transform = 'translateX(-50%) scale(1.05)'; button.style.boxShadow = '0 0 25px rgba(255, 50, 0, 0.8), inset 0 0 15px rgba(255, 100, 0, 0.6)'; }); // Add click handler to show server selector button.addEventListener('click', () => { this.showServerSelector(); }); // Add to body document.body.appendChild(button); // Fade in the button after a short delay setTimeout(() => { if (button) { button.style.opacity = '1'; } }, 1500); } /** * Initialize and show the server selector */ showServerSelector() { // Play enter sound when opening the menu if (this.enterKeySound) { // Lower ambient volume this.lowerAmbientVolume(); this.enterKeySound.currentTime = 0; this.enterKeySound.volume = 0.3; this.enterKeySound.play().catch(err => { }); } // Function to redirect to a selected server const redirectToServer = (server) => { window.location.href = `https://${server}`; }; // Create server selector if it doesn't exist if (!this.serverSelector) { // Create a modified version of redirectToServer that includes the close sound const redirectWithSound = (server) => { // Play close sound first if (this.closeMenuSound) { // Lower ambient volume this.lowerAmbientVolume(); this.closeMenuSound.play().catch(err => { }); // Redirect after a short delay to allow the sound to play setTimeout(() => { redirectToServer(server); }, 300); } else { // If sound failed to load, just redirect redirectToServer(server); } }; // Create server selector with our modified redirect function this.serverSelector = new ServerSelector(config_namespaceObject.match, redirectWithSound); // Handle close events to play the close sound if (this.serverSelector) { const originalClose = this.serverSelector.close.bind(this.serverSelector); this.serverSelector.close = () => { // Play close sound if (this.closeMenuSound) { // Lower ambient volume this.lowerAmbientVolume(); this.closeMenuSound.currentTime = 0; this.closeMenuSound.volume = 0.3; this.closeMenuSound.play().catch(err => { }); } // Call original close method originalClose(); }; } } // Show the selector this.serverSelector.show(); } // Call this method if you ever want to restore the original website restoreWebsite() { if (!this.isInitialized) return; this.isActive = false; this.isInitialized = false; // Restore original page title document.title = this.originalPageTitle; // Remove overlay if it exists if (this.overlayElement) { this.removeOverlay(); } // Stop animations if (this.animationFrameId) { cancelAnimationFrame(this.animationFrameId); this.animationFrameId = null; } // Stop message changing if (this.messageChangeInterval !== null) { clearTimeout(this.messageChangeInterval); this.messageChangeInterval = null; } // Stop sounds if (this.zelda3Sound) { this.zelda3Sound.pause(); } if (this.periodSound) { this.periodSound.pause(); } if (this.ambientSound) { this.ambientSound.pause(); } if (this.buttonClickSound) { this.buttonClickSound.pause(); } if (this.arrowKeySound) { this.arrowKeySound.pause(); } if (this.enterKeySound) { this.enterKeySound.pause(); } if (this.closeMenuSound) { this.closeMenuSound.pause(); } // Remove server selector if it exists if (this.serverSelector) { this.serverSelector.close(); this.serverSelector = null; } // Remove server button if it exists if (this.serverButton && this.serverButton.parentNode) { this.serverButton.parentNode.removeChild(this.serverButton); this.serverButton = null; } // Restore original content document.body.innerHTML = this.originalBodyContent; // Restore original styles document.body.style.background = this.originalStyles.bodyBackground || ''; document.body.style.color = this.originalStyles.bodyColor || ''; document.body.style.overflow = this.originalStyles.bodyOverflow || ''; // Re-initialize global event handlers since they may have been lost this.globalEventHandlersInitialized = false; this.initGlobalEventHandlers(); } } ;// ./src/assets/onboarding.html?raw const onboardingraw_namespaceObject = "
"; ;// ./src/assets/onboarding_kxz.html?raw const onboarding_kxzraw_namespaceObject = " "; ;// ./src/assets/onboarding-styles.css?raw const onboarding_stylesraw_namespaceObject = "/* Reset and base styles */\r\n.popup-overlay {\r\n\tposition: fixed;\r\n\ttop: 0;\r\n\tleft: 0;\r\n\twidth: 100%;\r\n\theight: 100%;\r\n\tbackground: rgba(0, 0, 0, 0.8);\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tz-index: 1000;\r\n\tfont-family: Arial, sans-serif;\r\n}\r\n\r\n.subtitle-image {\r\n\tdisplay: block;\r\n\tmargin: 0 auto;\r\n\tmax-width: 00px;\r\n\t/* adapte selon ton image */\r\n\theight: auto;\r\n}\r\n\r\n.popup-content {\r\n\tbackground: #2c3e50;\r\n\tborder-radius: 10px;\r\n\tmax-width: 90%;\r\n\tmax-height: 90%;\r\n\toverflow-y: auto;\r\n\tcolor: white;\r\n\tposition: relative;\r\n}\r\n\r\n/* Header with Discord button */\r\n.popup-header {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tpadding: 20px 30px 0;\r\n\tmargin-bottom: 20px;\r\n}\r\n\r\n.discord-button {\r\n\tbackground: #5865F2;\r\n\tcolor: white;\r\n\tborder: none;\r\n\tpadding: 10px 20px;\r\n\tborder-radius: 5px;\r\n\tcursor: pointer;\r\n\tfont-size: 14px;\r\n\tfont-weight: bold;\r\n\ttransition: background-color 0.3s ease;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 8px;\r\n}\r\n\r\n.discord-button:hover {\r\n\tbackground: #4752C4;\r\n}\r\n\r\n.discord-icon {\r\n\twidth: 16px;\r\n\theight: 16px;\r\n\tfill: currentColor;\r\n}\r\n\r\n.popup-content .container {\r\n\tmax-width: 600px;\r\n\tmargin: 0 auto;\r\n\tpadding: 0 20px 40px;\r\n\ttext-align: center;\r\n}\r\n\r\n.popup-content h1 {\r\n\tcolor: #3498db;\r\n\tfont-size: 2.5em;\r\n\tmargin-bottom: 10px;\r\n}\r\n\r\n.popup-content .subtitle {\r\n\tfont-size: 1.2em;\r\n\tmargin-bottom: 40px;\r\n\tcolor: #bdc3c7;\r\n}\r\n\r\n.popup-content .steps {\r\n\ttext-align: left;\r\n\tmargin: 40px 0;\r\n}\r\n\r\n.popup-content .step {\r\n\tbackground: #34495e;\r\n\tpadding: 20px;\r\n\tmargin: 15px 0;\r\n\tborder-radius: 8px;\r\n\tborder-left: 4px solid #3498db;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 20px;\r\n}\r\n\r\n.popup-content .step-large-image {\r\n\tmargin: 20px 0;\r\n\ttext-align: center;\r\n\tbackground: #34495e;\r\n\tborder-radius: 8px;\r\n\tpadding: 15px;\r\n\tborder: 2px solid #3498db;\r\n}\r\n\r\n.popup-content .step-large-image img {\r\n\twidth: 100%;\r\n\tmax-width: 500px;\r\n\theight: auto;\r\n\tborder-radius: 5px;\r\n\tbox-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.popup-content .step-content {\r\n\tflex: 1;\r\n}\r\n\r\n.popup-content .step h3 {\r\n\tmargin: 0 0 10px 0;\r\n\tcolor: #3498db;\r\n}\r\n\r\n.popup-content .step p {\r\n\tmargin: 0;\r\n\tline-height: 1.5;\r\n}\r\n\r\n.popup-content .play-button {\r\n\tbackground: #e74c3c;\r\n\tcolor: white;\r\n\tborder: none;\r\n\tpadding: 15px 30px;\r\n\tfont-size: 1.2em;\r\n\tborder-radius: 5px;\r\n\tcursor: pointer;\r\n\tmargin-top: 30px;\r\n\ttransition: background-color 0.3s ease;\r\n}\r\n\r\n.popup-content .play-button:hover {\r\n\tbackground: #c0392b;\r\n}\r\n\r\n@media (max-width: 768px) {\r\n\t.popup-header {\r\n\t\tflex-direction: column;\r\n\t\tgap: 15px;\r\n\t\talign-items: stretch;\r\n\t}\r\n\r\n\t.discord-button {\r\n\t\tjustify-content: center;\r\n\t}\r\n\r\n\t.popup-content h1 {\r\n\t\tfont-size: 2em;\r\n\t}\r\n\r\n\t.popup-content .step {\r\n\t\tflex-direction: column;\r\n\t\ttext-align: center;\r\n\t}\r\n}"; ;// ./src/FUNC/Felicitations.ts function felicitation(enable, win_sound_url, text) { const goldText = document.createElement("div"); goldText.textContent = text; goldText.style.position = "fixed"; goldText.style.top = "50%"; goldText.style.left = "50%"; goldText.style.transform = "translate(-50%, -50%)"; goldText.style.fontSize = "80px"; goldText.style.color = "gold"; goldText.style.textShadow = "2px 2px 4px rgba(0,0,0,0.3)"; goldText.style.zIndex = "10000"; document.body.appendChild(goldText); function createConfetti() { const colors = [ "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "gold", ]; const confetti = document.createElement("div"); confetti.style.position = "fixed"; confetti.style.width = Math.random() * 10 + 5 + "px"; confetti.style.height = Math.random() * 10 + 5 + "px"; confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; confetti.style.borderRadius = "50%"; confetti.style.zIndex = "9999"; confetti.style.left = Math.random() * 100 + "vw"; confetti.style.top = "-20px"; document.body.appendChild(confetti); let posY = -20; let posX = parseFloat(confetti.style.left); let rotation = 0; let speedY = Math.random() * 2 + 1; let speedX = Math.random() * 2 - 1; function fall() { posY += speedY; posX += speedX; rotation += 5; confetti.style.top = posY + "px"; confetti.style.left = posX + "vw"; confetti.style.transform = `rotate(${rotation}deg)`; if (posY < window.innerHeight) { requestAnimationFrame(fall); } else { confetti.remove(); } } fall(); } const confettiInterval = setInterval(() => { for (let i = 0; i < 5; i++) { createConfetti(); } }, 100); if (enable) { const audio = new Audio(win_sound_url); audio.play().catch((err) => console.error("Erreur lecture:", err)); } setTimeout(() => { clearInterval(confettiInterval); goldText.style.transition = "opacity 1s"; goldText.style.opacity = "0"; setTimeout(() => goldText.remove(), 1000); }, 5000); } ;// ./src/FUNC/Onboarding.ts // FUNC/Onboarding.ts // @ts-ignore // @ts-ignore // @ts-ignore class OnboardingModal { constructor() { this.overlay = null; this.isVisible = false; } // Inject CSS styles injectStyles() { const styleId = 'onboarding-styles'; // Check if styles already exist if (document.getElementById(styleId)) { return; } const styleElement = document.createElement('style'); styleElement.id = styleId; styleElement.textContent = onboarding_stylesraw_namespaceObject; document.head.appendChild(styleElement); } // Show the onboarding modal show() { if (this.isVisible) { return; } // Inject CSS styles this.injectStyles(); // Create overlay element this.overlay = document.createElement('div'); this.overlay.innerHTML = vars_client.type === ClientType.KxsClient ? onboardingraw_namespaceObject : onboarding_kxzraw_namespaceObject; // Get the actual overlay from the created HTML const overlayElement = this.overlay.firstElementChild; // Add to document body document.body.appendChild(overlayElement); // Store reference to the overlay this.overlay = overlayElement; this.isVisible = true; // Add event listeners this.addEventListeners(); } // Hide the onboarding modal hide() { if (!this.isVisible || !this.overlay) { return; } // Remove overlay from DOM this.overlay.remove(); this.overlay = null; this.isVisible = false; let welcome_sound = vars_client.type === ClientType.KxsClient ? "https://kxs.rip/assets/o_sound.mp3" : "https://kxs.rip/assets/o_z_sound.mp3"; felicitation(true, welcome_sound, "Welcome to " + __webpack_require__.g.client.name); localStorage.setItem("on_boarding_complete", "yes"); } // Add event listeners for interactions addEventListeners() { if (!this.overlay) return; // Play button click handler const playButton = this.overlay.querySelector('#play-now-btn'); if (playButton) { playButton.addEventListener('click', () => { this.onPlayButtonClick(); }); } // Discord button click handler const discordButton = this.overlay.querySelector('#discord-btn'); if (discordButton) { discordButton.addEventListener('click', () => { this.onDiscordButtonClick(); }); } // Click outside to close (optional) this.overlay.addEventListener('click', (e) => { if (e.target === this.overlay) { this.hide(); } }); // ESC key to close document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && this.isVisible) { this.hide(); } }); } // Handle play button click onPlayButtonClick() { // Close the modal this.hide(); } // Handle Discord button click onDiscordButtonClick() { // Replace with your actual Discord invite link window.open('https://discord.wf/kxsclient', '_blank'); } // Check if modal is currently visible isOpen() { return this.isVisible; } } /* harmony default export */ const Onboarding = ((/* unused pure expression or super */ null && (OnboardingModal))); ;// ./src/HUD/MOD/HealthWarning.ts class HealthWarning { constructor(kxsClient) { this.isDraggable = false; this.isDragging = false; this.dragOffset = { x: 0, y: 0 }; this.POSITION_KEY = 'lowHpWarning'; this.mouseMoveThrottle = false; this.warningElement = null; this.kxsClient = kxsClient; this.createWarningElement(); this.setFixedPosition(); this.setupDragAndDrop(); this.startMenuCheckInterval(); } createWarningElement() { const warning = document.createElement("div"); const uiTopLeft = document.getElementById("ui-top-left"); // Vérifier si le mode glassmorphism est activé const is_glassmorphism_enabled = this.kxsClient.isGlassmorphismEnabled; // Appliquer le style approprié en fonction du toggle glassmorphism DesignSystem.applyGlassEffect(warning, this.kxsClient.isGlassmorphismEnabled ? 'medium' : 'dark', { position: 'fixed', border: is_glassmorphism_enabled ? '2px solid rgba(255, 0, 0, 0.8)' : '2px solid rgba(255, 50, 50, 0.9)', padding: DesignSystem.spacing.md + ' ' + DesignSystem.spacing.lg, color: '#ff4444', fontFamily: DesignSystem.fonts.primary, fontSize: DesignSystem.fonts.sizes.base, fontWeight: '600', zIndex: DesignSystem.layers.notification.toString(), display: 'none', pointerEvents: 'none', transition: `all ${DesignSystem.animation.normal} ease`, boxShadow: is_glassmorphism_enabled ? '0 8px 32px rgba(255, 0, 0, 0.3), 0 0 20px rgba(255, 0, 0, 0.2)' : '0 4px 12px rgba(255, 0, 0, 0.25)', textShadow: is_glassmorphism_enabled ? '0 0 10px rgba(255, 0, 0, 0.5)' : '0 0 5px rgba(255, 0, 0, 0.4)', backdropFilter: is_glassmorphism_enabled ? 'blur(8px) saturate(180%)' : 'none', borderRadius: is_glassmorphism_enabled ? '12px' : '8px' }); // Appliquer le webkit backdrop filter manuellement if (is_glassmorphism_enabled) { warning.style['-webkit-backdrop-filter'] = 'blur(8px) saturate(180%)'; } else { warning.style['-webkit-backdrop-filter'] = 'none'; } const content = document.createElement("div"); Object.assign(content.style, { display: 'flex', alignItems: 'center', gap: DesignSystem.spacing.sm, filter: 'drop-shadow(0 0 8px rgba(255, 0, 0, 0.4))' }); const icon = document.createElement("div"); icon.innerHTML = ` `; const text = document.createElement("span"); text.textContent = "LOW HP!"; if (uiTopLeft) { content.appendChild(icon); content.appendChild(text); warning.appendChild(content); uiTopLeft.appendChild(warning); } this.warningElement = warning; this.addPulseAnimation(); } setFixedPosition() { if (!this.warningElement) return; // Récupérer la position depuis le localStorage ou les valeurs par défaut const storageKey = `position_${this.POSITION_KEY}`; const savedPosition = localStorage.getItem(storageKey); let position; if (savedPosition) { try { // Utiliser la position sauvegardée const { x, y } = JSON.parse(savedPosition); position = { left: x, top: y }; } catch (error) { // En cas d'erreur, utiliser la position par défaut position = this.kxsClient.defaultPositions[this.POSITION_KEY]; this.kxsClient.logger.error('Erreur lors du chargement de la position LOW HP:', error); } } else { // Utiliser la position par défaut position = this.kxsClient.defaultPositions[this.POSITION_KEY]; } // Appliquer la position if (position) { this.warningElement.style.top = `${position.top}px`; this.warningElement.style.left = `${position.left}px`; } } addPulseAnimation() { const keyframes = ` @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } } `; const style = document.createElement("style"); style.textContent = keyframes; document.head.appendChild(style); if (this.warningElement) { this.warningElement.style.animation = "pulse 1.5s infinite"; } } show(health) { if (!this.warningElement) return; this.warningElement.style.display = "block"; const span = this.warningElement.querySelector("span"); if (span) { span.textContent = `LOW HP: ${health}%`; } } hide() { if (!this.warningElement) return; // Ne pas masquer si en mode placement // if (this.isDraggable) return; this.warningElement.style.display = "none"; } update(health) { // Si le mode placement est actif (isDraggable), on ne fait rien pour maintenir l'affichage if (this.isDraggable) { return; } // Sinon, comportement normal if (health <= 30 && health > 0) { this.show(health); } else { this.hide(); } } setupDragAndDrop() { // Nous n'avons plus besoin d'écouteurs pour RSHIFT car nous utilisons maintenant // l'état du menu secondaire pour déterminer quand activer/désactiver le mode placement // Écouteurs d'événements de souris pour le glisser-déposer document.addEventListener('mousedown', this.handleMouseDown.bind(this)); document.addEventListener('mousemove', this.handleMouseMove.bind(this)); document.addEventListener('mouseup', this.handleMouseUp.bind(this)); } enableDragging() { if (!this.warningElement) return; const is_glassmorphism_enabled = this.kxsClient.isGlassmorphismEnabled; this.isDraggable = true; this.warningElement.style.pointerEvents = 'auto'; this.warningElement.style.cursor = 'move'; // Adaptation du style pour le mode placement, selon le toggle glassmorphism this.warningElement.style.borderColor = '#00ff00'; // Feedback visuel quand déplaçable if (is_glassmorphism_enabled) { this.warningElement.style.boxShadow = '0 8px 32px rgba(0, 255, 0, 0.2), 0 0 20px rgba(0, 255, 0, 0.15)'; this.warningElement.style.backdropFilter = 'blur(8px) saturate(180%)'; this.warningElement.style['-webkit-backdrop-filter'] = 'blur(8px) saturate(180%)'; } else { this.warningElement.style.boxShadow = '0 4px 12px rgba(0, 255, 0, 0.2)'; this.warningElement.style.backdropFilter = 'none'; this.warningElement.style['-webkit-backdrop-filter'] = 'none'; } // Force l'affichage de l'avertissement LOW HP, peu importe la santé actuelle this.warningElement.style.display = 'block'; const span = this.warningElement.querySelector("span"); if (span) { span.textContent = 'LOW HP: Placement Mode'; } } disableDragging() { if (!this.warningElement) return; const is_glassmorphism_enabled = this.kxsClient.isGlassmorphismEnabled; this.isDraggable = false; this.isDragging = false; this.warningElement.style.pointerEvents = 'none'; this.warningElement.style.cursor = 'default'; this.warningElement.style.borderColor = '#ff0000'; // Retour à la couleur normale // Restauration du style original en fonction du mode glassmorphism if (is_glassmorphism_enabled) { this.warningElement.style.boxShadow = '0 8px 32px rgba(255, 0, 0, 0.3), 0 0 20px rgba(255, 0, 0, 0.2)'; this.warningElement.style.backdropFilter = 'blur(8px) saturate(180%)'; this.warningElement.style['-webkit-backdrop-filter'] = 'blur(8px) saturate(180%)'; } else { this.warningElement.style.boxShadow = '0 4px 12px rgba(255, 0, 0, 0.25)'; this.warningElement.style.backdropFilter = 'none'; this.warningElement.style['-webkit-backdrop-filter'] = 'none'; } // Remet le texte original si l'avertissement est visible if (this.warningElement.style.display === 'block') { const span = this.warningElement.querySelector("span"); if (span) { span.textContent = 'LOW HP'; } } // Récupérer la santé actuelle à partir de l'élément UI de santé du jeu const healthBars = document.querySelectorAll("#ui-health-container"); if (healthBars.length > 0) { const bar = healthBars[0].querySelector("#ui-health-actual"); if (bar) { const currentHealth = Math.round(parseFloat(bar.style.width)); // Forcer une mise à jour immédiate en fonction de la santé actuelle this.update(currentHealth); } } } handleMouseDown(event) { if (!this.isDraggable || !this.warningElement) return; // Check if click was on the warning element if (this.warningElement.contains(event.target)) { this.isDragging = true; // Calculate offset from mouse position to element corner const rect = this.warningElement.getBoundingClientRect(); this.dragOffset = { x: event.clientX - rect.left, y: event.clientY - rect.top }; // Prevent text selection during drag event.preventDefault(); } } handleMouseMove(event) { if (!this.isDragging || !this.warningElement || this.mouseMoveThrottle) return; // Optimized: throttle mousemove for better performance this.mouseMoveThrottle = true; requestAnimationFrame(() => { // Calculate new position const newX = event.clientX - this.dragOffset.x; const newY = event.clientY - this.dragOffset.y; // Update element position if (this.warningElement) { this.warningElement.style.left = `${newX}px`; this.warningElement.style.top = `${newY}px`; } this.mouseMoveThrottle = false; }); } handleMouseUp() { if (this.isDragging && this.warningElement) { this.isDragging = false; // Récupérer les positions actuelles const left = parseInt(this.warningElement.style.left); const top = parseInt(this.warningElement.style.top); // Sauvegarder la position const storageKey = `position_${this.POSITION_KEY}`; localStorage.setItem(storageKey, JSON.stringify({ x: left, y: top })); } } startMenuCheckInterval() { // Écouter directement les événements RSHIFT pour une réaction immédiate this.setupRShiftListener(); } setupRShiftListener() { // Fonction pour vérifier et mettre à jour l'état du mode placement const checkMenuState = () => { var _a; const isMenuOpen = ((_a = this.kxsClient.secondaryMenu) === null || _a === void 0 ? void 0 : _a.isOpen) || false; // Si le menu est ouvert et que nous ne sommes pas en mode placement, activer le mode placement if (isMenuOpen && this.kxsClient.isHealthWarningEnabled && !this.isDraggable) { this.enableDragging(); } // Si le menu est fermé et que nous sommes en mode placement, désactiver le mode placement else if (!isMenuOpen && this.isDraggable) { this.disableDragging(); } }; // S'abonner aux notifications de changement d'état du menu if (!this.kxsClient.secondaryMenu.onMenuToggle) { this.kxsClient.secondaryMenu.onMenuToggle = []; } this.kxsClient.secondaryMenu.onMenuToggle.push(checkMenuState); // Vérifier l'état initial checkMenuState(); } destroy() { var _a; // Supprimer le callback du menu secondaire if ((_a = this.kxsClient.secondaryMenu) === null || _a === void 0 ? void 0 : _a.onMenuToggle) { const index = this.kxsClient.secondaryMenu.onMenuToggle.findIndex(callback => callback.toString().includes('checkMenuState')); if (index !== -1) { this.kxsClient.secondaryMenu.onMenuToggle.splice(index, 1); } } // Supprimer l'élément du DOM if (this.warningElement) { this.warningElement.remove(); this.warningElement = null; } } } ;// ./src/MECHANIC/KillLeaderTracking.ts class KillLeaderTracker { constructor(kxsClient) { this.offsetX = 20; this.offsetY = 20; this.lastKnownKills = 0; this.wasKillLeader = false; this.MINIMUM_KILLS_FOR_LEADER = 3; this.kxsClient = kxsClient; this.warningElement = null; this.encouragementElement = null; this.killLeaderKillCount = 0; this.wasKillLeader = false; this.createEncouragementElement(); this.initMouseTracking(); } createEncouragementElement() { const encouragement = document.createElement("div"); encouragement.style.cssText = ` position: fixed; background: rgba(0, 255, 0, 0.1); border: 2px solid #00ff00; border-radius: 5px; padding: 10px 15px; color: #00ff00; font-family: Arial, sans-serif; font-size: 14px; z-index: 9999; display: none; backdrop-filter: blur(5px); transition: all 0.3s ease; pointer-events: none; box-shadow: 0 0 10px rgba(0, 255, 0, 0.3); `; const content = document.createElement("div"); content.style.cssText = ` display: flex; align-items: center; gap: 8px; `; const icon = document.createElement("div"); icon.innerHTML = ` `; const text = document.createElement("span"); text.textContent = "Nice Kill!"; content.appendChild(icon); content.appendChild(text); encouragement.appendChild(content); document.body.appendChild(encouragement); this.encouragementElement = encouragement; this.addEncouragementAnimation(); } initMouseTracking() { document.addEventListener("mousemove", (e) => { this.updateElementPosition(this.warningElement, e); this.updateElementPosition(this.encouragementElement, e); }); } updateElementPosition(element, e) { if (!element || element.style.display === "none") return; const x = e.clientX + this.offsetX; const y = e.clientY + this.offsetY; const rect = element.getBoundingClientRect(); const maxX = window.innerWidth - rect.width; const maxY = window.innerHeight - rect.height; const finalX = Math.min(Math.max(0, x), maxX); const finalY = Math.min(Math.max(0, y), maxY); element.style.transform = `translate(${finalX}px, ${finalY}px)`; } addEncouragementAnimation() { const keyframes = ` @keyframes encouragementPulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.8; } 100% { transform: scale(1); opacity: 1; } } @keyframes fadeInOut { 0% { opacity: 0; transform: translateY(20px); } 10% { opacity: 1; transform: translateY(0); } 90% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-20px); } } `; const style = document.createElement("style"); style.textContent = keyframes; document.head.appendChild(style); if (this.encouragementElement) { this.encouragementElement.style.animation = "fadeInOut 3s forwards"; } } showEncouragement(killsToLeader, isDethrone = false, noKillLeader = false) { if (!this.encouragementElement) return; let message; if (isDethrone && killsToLeader !== 0) { message = "Oh no! You've been dethroned!"; this.encouragementElement.style.borderColor = "#ff0000"; this.encouragementElement.style.color = "#ff0000"; this.encouragementElement.style.background = "rgba(255, 0, 0, 0.1)"; } else if (noKillLeader) { const killsNeeded = this.MINIMUM_KILLS_FOR_LEADER - this.lastKnownKills; message = `Nice Kill! Get ${killsNeeded} more kills to become the first Kill Leader!`; } else { message = killsToLeader <= 0 ? "You're the Kill Leader! 👑" : `Nice Kill! ${killsToLeader} more to become Kill Leader!`; } const span = this.encouragementElement.querySelector("span"); if (span) span.textContent = message; this.encouragementElement.style.display = "block"; this.encouragementElement.style.animation = "fadeInOut 3s forwards"; setTimeout(() => { if (this.encouragementElement) { this.encouragementElement.style.display = "none"; // Reset colors this.encouragementElement.style.borderColor = "#00ff00"; this.encouragementElement.style.color = "#00ff00"; this.encouragementElement.style.background = "rgba(0, 255, 0, 0.1)"; } }, 7000); } isKillLeader() { const killLeaderNameElement = document.querySelector("#ui-kill-leader-name"); return this.kxsClient.getUsername() === (killLeaderNameElement === null || killLeaderNameElement === void 0 ? void 0 : killLeaderNameElement.textContent); } update(myKills) { if (!this.kxsClient.isKillLeaderTrackerEnabled) return; if (client.type === 2) return; const killLeaderElement = document.querySelector("#ui-kill-leader-count"); this.killLeaderKillCount = parseInt((killLeaderElement === null || killLeaderElement === void 0 ? void 0 : killLeaderElement.textContent) || "0", 10); if (myKills > this.lastKnownKills) { if (this.killLeaderKillCount === 0) { // Pas encore de kill leader, encourager le joueur à atteindre 3 kills this.showEncouragement(0, false, true); } else if (this.killLeaderKillCount < this.MINIMUM_KILLS_FOR_LEADER) { // Ne rien faire si le kill leader n'a pas atteint le minimum requis return; } else if (this.isKillLeader() && myKills > 0) { this.showEncouragement(0); this.wasKillLeader = true; } else { const killsNeeded = this.killLeaderKillCount + 1 - myKills; this.showEncouragement(killsNeeded); } } else if (this.wasKillLeader && !this.isKillLeader()) { // Détroné this.showEncouragement(0, true); this.wasKillLeader = false; } this.lastKnownKills = myKills; } } ;// ./src/HUD/GridSystem.ts class GridSystem { constructor() { this.gridSize = 20; // Size of each grid cell this.snapThreshold = 15; // Distance in pixels to trigger snap this.gridVisible = false; this.magneticEdges = true; this.counterElements = {}; this.gridContainer = this.createGridOverlay(); this.setupKeyBindings(); } createGridOverlay() { const container = document.createElement("div"); container.id = "grid-overlay"; Object.assign(container.style, { position: "fixed", top: "0", left: "0", width: "100%", height: "100%", pointerEvents: "none", zIndex: "9999", display: "none", opacity: "0.2", }); // Create vertical lines for (let x = this.gridSize; x < window.innerWidth; x += this.gridSize) { const vLine = document.createElement("div"); Object.assign(vLine.style, { position: "absolute", left: `${x}px`, top: "0", width: "1px", height: "100%", backgroundColor: "#4CAF50", }); container.appendChild(vLine); } // Create horizontal lines for (let y = this.gridSize; y < window.innerHeight; y += this.gridSize) { const hLine = document.createElement("div"); Object.assign(hLine.style, { position: "absolute", left: "0", top: `${y}px`, width: "100%", height: "1px", backgroundColor: "#4CAF50", }); container.appendChild(hLine); } document.body.appendChild(container); return container; } setupKeyBindings() { document.addEventListener("keydown", (e) => { if (e.key === "g" && e.altKey) { this.toggleGrid(); } }); } toggleGrid() { this.gridVisible = !this.gridVisible; this.gridContainer.style.display = this.gridVisible ? "block" : "none"; } registerCounter(id, element) { if (element) { this.counterElements[id] = element; } else { delete this.counterElements[id]; } } snapToGrid(element, x, y) { const rect = element.getBoundingClientRect(); const elementWidth = rect.width; const elementHeight = rect.height; // Snap to grid let snappedX = Math.round(x / this.gridSize) * this.gridSize; let snappedY = Math.round(y / this.gridSize) * this.gridSize; // Edge snapping if (this.magneticEdges) { const screenEdges = { left: 0, right: window.innerWidth - elementWidth, center: (window.innerWidth - elementWidth) / 2, top: 0, bottom: window.innerHeight - elementHeight, middle: (window.innerHeight - elementHeight) / 2, }; // Snap to horizontal edges if (Math.abs(x - screenEdges.left) < this.snapThreshold) { snappedX = screenEdges.left; } else if (Math.abs(x - screenEdges.right) < this.snapThreshold) { snappedX = screenEdges.right; } else if (Math.abs(x - screenEdges.center) < this.snapThreshold) { snappedX = screenEdges.center; } // Snap to vertical edges if (Math.abs(y - screenEdges.top) < this.snapThreshold) { snappedY = screenEdges.top; } else if (Math.abs(y - screenEdges.bottom) < this.snapThreshold) { snappedY = screenEdges.bottom; } else if (Math.abs(y - screenEdges.middle) < this.snapThreshold) { snappedY = screenEdges.middle; } } return { x: snappedX, y: snappedY }; } highlightNearestGridLine(x, y) { if (!this.gridVisible) return; // Remove existing highlights const highlights = document.querySelectorAll(".grid-highlight"); highlights.forEach((h) => h.remove()); // Create highlight for nearest vertical line const nearestX = Math.round(x / this.gridSize) * this.gridSize; if (Math.abs(x - nearestX) < this.snapThreshold) { const vHighlight = document.createElement("div"); Object.assign(vHighlight.style, { position: "absolute", left: `${nearestX}px`, top: "0", width: "2px", height: "100%", backgroundColor: "#FFD700", zIndex: "10000", pointerEvents: "none", }); vHighlight.classList.add("grid-highlight"); this.gridContainer.appendChild(vHighlight); } // Create highlight for nearest horizontal line const nearestY = Math.round(y / this.gridSize) * this.gridSize; if (Math.abs(y - nearestY) < this.snapThreshold) { const hHighlight = document.createElement("div"); Object.assign(hHighlight.style, { position: "absolute", left: "0", top: `${nearestY}px`, width: "100%", height: "2px", backgroundColor: "#FFD700", zIndex: "10000", pointerEvents: "none", }); hHighlight.classList.add("grid-highlight"); this.gridContainer.appendChild(hHighlight); } } } ;// ./src/SERVER/DiscordTracking.ts var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const stuff_emojis = { main_weapon: "🔫", secondary_weapon: "🔫", grenades: "💣", melees: "🔪", soda: "🥤", medkit: "🩹", bandage: "🩹", pills: "💊", backpack: "🎒", chest: "📦", helmet: "⛑️" }; class WebhookValidator { static isValidWebhookUrl(url = '') { return url.startsWith("https://"); } static isWebhookAlive(webhookUrl) { return __awaiter(this, void 0, void 0, function* () { try { // First check if the URL format is valid if (!this.isValidWebhookUrl(webhookUrl)) { throw new Error("Invalid webhook URL format"); } // Test the webhook with a GET request (Discord allows GET on webhooks) const response = yield fetch(webhookUrl, { method: "GET", headers: { "Content-Type": "application/json", }, }); // Discord returns 200 for valid webhooks return response.status === 200; } catch (error) { return false; } }); } static testWebhook(webhookUrl) { return __awaiter(this, void 0, void 0, function* () { try { if (!webhookUrl) { return { isValid: false, message: "Please enter a webhook URL", }; } if (!this.isValidWebhookUrl(webhookUrl)) { return { isValid: false, message: "Invalid Discord webhook URL format", }; } const isAlive = yield this.isWebhookAlive(webhookUrl); return { isValid: isAlive, message: isAlive ? "Webhook is valid and working!" : "Webhook is not responding or has been deleted", }; } catch (error) { return { isValid: false, message: "Error testing webhook connection", }; } }); } } class DiscordTracking { constructor(kxsClient, webhookUrl) { this.kxsClient = kxsClient; this.webhookUrl = webhookUrl; } setWebhookUrl(webhookUrl) { this.webhookUrl = webhookUrl; } validateCurrentWebhook() { return __awaiter(this, void 0, void 0, function* () { return WebhookValidator.isWebhookAlive(this.webhookUrl); }); } sendWebhookMessage(message) { return __awaiter(this, void 0, void 0, function* () { if (!WebhookValidator.isValidWebhookUrl(this.webhookUrl)) { return; } this.kxsClient.nm.showNotification("Sending Discord message...", "info", 2300); try { const response = yield fetch(this.webhookUrl, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(message), }); if (!response.ok) { throw new Error(`Discord Webhook Error: ${response.status}`); } } catch (error) { this.kxsClient.logger.error("Error sending Discord message:", error); } }); } getEmbedColor(isWin) { return isWin ? 0x2ecc71 : 0xe74c3c; // Green for victory, red for defeat } trackGameEnd(result) { return __awaiter(this, void 0, void 0, function* () { const title = result.isWin ? "🏆 VICTORY ROYALE!" : `${result.position} - Game Over`; const embed = { title, description: `${result.username}'s Match`, color: this.getEmbedColor(result.isWin), fields: [ { name: "💀 Eliminations", value: result.kills.toString(), inline: true, }, ], }; if (result.duration) { embed.fields.push({ name: "⏱️ Duration", value: result.duration, inline: true, }); } if (result.damageDealt) { embed.fields.push({ name: "💥 Damage Dealt", value: Math.round(result.damageDealt).toString(), inline: true, }); } if (result.damageTaken) { embed.fields.push({ name: "💢 Damage Taken", value: Math.round(result.damageTaken).toString(), inline: true, }); } if (result.username) { embed.fields.push({ name: "📝 Username", value: result.username, inline: true, }); } if (result.stuff) { for (const [key, value] of Object.entries(result.stuff)) { if (value) { embed.fields.push({ name: `${stuff_emojis[key]} ${key.replace("_", " ").toUpperCase()}`, value, inline: true, }); } } } const message = { username: __webpack_require__.g.client.name, avatar_url: kxs_logo, content: result.isWin ? "🎉 New Victory!" : "Match Ended", embeds: [embed], }; yield this.sendWebhookMessage(message); }); } } ;// ./src/FUNC/StatsParser.ts class StatsParser { static cleanNumber(str) { return parseInt(str.replace(/[^\d.-]/g, "")) || 0; } /** * Extract the full duration string including the unit */ static extractDuration(str) { const match = str.match(/(\d+\s*[smh])/i); return match ? match[1].trim() : "0s"; } static parse(statsText, rankContent) { let stats = { username: "Player", kills: 0, damageDealt: 0, damageTaken: 0, duration: "", position: "#unknown", }; // Handle developer format const devPattern = /Developer.*?Kills(\d+).*?Damage Dealt(\d+).*?Damage Taken(\d+).*?Survived(\d+\s*[smh])/i; const devMatch = statsText.match(devPattern); if (devMatch) { return { username: "Player", kills: this.cleanNumber(devMatch[1]), damageDealt: this.cleanNumber(devMatch[2]), damageTaken: this.cleanNumber(devMatch[3]), duration: devMatch[4].trim(), // Keep the full duration string with unit position: rankContent.replace("##", "#"), }; } // Handle template format const templatePattern = /%username%.*?Kills%kills_number%.*?Dealt%number_dealt%.*?Taken%damage_taken%.*?Survived%duration%/; const templateMatch = statsText.match(templatePattern); if (templateMatch) { const parts = statsText.split(/Kills|Dealt|Taken|Survived/); if (parts.length >= 5) { return { username: parts[0].trim(), kills: this.cleanNumber(parts[1]), damageDealt: this.cleanNumber(parts[2]), damageTaken: this.cleanNumber(parts[3]), duration: this.extractDuration(parts[4]), // Extract full duration with unit position: rankContent.replace("##", "#"), }; } } // Generic parsing as fallback const usernameMatch = statsText.match(/^([^0-9]+)/); if (usernameMatch) { stats.username = usernameMatch[1].trim(); } const killsMatch = statsText.match(/Kills[^0-9]*(\d+)/i); if (killsMatch) { stats.kills = this.cleanNumber(killsMatch[1]); } const dealtMatch = statsText.match(/Dealt[^0-9]*(\d+)/i); if (dealtMatch) { stats.damageDealt = this.cleanNumber(dealtMatch[1]); } const takenMatch = statsText.match(/Taken[^0-9]*(\d+)/i); if (takenMatch) { stats.damageTaken = this.cleanNumber(takenMatch[1]); } // Extract survival time with unit const survivalMatch = statsText.match(/Survived[^0-9]*(\d+\s*[smh])/i); if (survivalMatch) { stats.duration = survivalMatch[1].trim(); } stats.position = rankContent.replace("##", "#"); return stats; } } // EXTERNAL MODULE: ./node_modules/semver/functions/gt.js var gt = __webpack_require__(580); var gt_default = /*#__PURE__*/__webpack_require__.n(gt); ;// ./src/creditpage.html?raw const creditpageraw_namespaceObject = "\n\n\n\n\t\n\t\n\tA new version of KxsClient is available!
Current version: ${this.getCurrentScriptVersion()} | New version: ${this.hostedScriptVersion}
To update, follow these steps: