// ==UserScript== // @name Kxs Client - Survev.io Client // @namespace https://github.com/Kisakay/KxsClient // @version 2.2.14 // @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 *://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/* // @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, } /***/ }), /***/ 222: /***/ ((__unused_webpack_module, exports) => { var __webpack_unused_export__; __webpack_unused_export__ = ({ value: true }); exports.W = void 0; ; class BrowserSteganoDB { data; currentTable; options; database; constructor(options) { this.currentTable = options?.tableName || "json"; this.database = options.database || "stegano.db"; this.data = { [this.currentTable]: [] }; this.fetchDataFromFile(); } read() { return localStorage.getItem(this.database) || this.data; } write() { return localStorage.setItem(this.database, JSON.stringify(this.data)); } 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; }; getNestedProperty = (object, key) => { const properties = key.split('.'); let index = 0; for (; index < properties.length; ++index) { object = object && object[properties[index]]; } return object; }; fetchDataFromFile() { try { const content = this.read(); this.data = JSON.parse(content); } catch (error) { this.data = { [this.currentTable]: [] }; } } updateNestedProperty(key, operation, value) { const [id, ...rest] = key.split('.'); const nestedPath = rest.join('.'); let currentValue = this.data[this.currentTable].find((entry) => entry.id === id); if (!currentValue && operation !== 'get') { currentValue = { id, value: {} }; this.data[this.currentTable].push(currentValue); } if (!currentValue && operation === 'get') { return undefined; } switch (operation) { case 'get': return nestedPath ? this.getNestedProperty(currentValue.value, nestedPath) : currentValue.value; case 'set': if (nestedPath) { this.setNestedProperty(currentValue.value, nestedPath, value); } else { currentValue.value = value; } this.write(); break; case 'add': if (!nestedPath) { currentValue.value = (typeof currentValue.value === 'number' ? currentValue.value : 0) + value; } else { const existingValue = this.getNestedProperty(currentValue.value, nestedPath); if (typeof existingValue !== 'number' && existingValue !== undefined) { throw new TypeError('The existing value is not a number.'); } this.setNestedProperty(currentValue.value, nestedPath, (typeof existingValue === 'number' ? existingValue : 0) + value); } this.write(); break; case 'sub': if (!nestedPath) { currentValue.value = (typeof currentValue.value === 'number' ? currentValue.value : 0) - value; } else { const existingValue = this.getNestedProperty(currentValue.value, nestedPath); if (typeof existingValue !== 'number' && existingValue !== undefined && existingValue !== null) { throw new TypeError('The existing value is not a number.'); } this.setNestedProperty(currentValue.value, nestedPath, (typeof existingValue === 'number' ? existingValue : 0) - value); } this.write(); break; case 'delete': if (nestedPath) { const properties = nestedPath.split('.'); let currentObject = currentValue.value; 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 { const index = this.data[this.currentTable].findIndex((entry) => entry.id === id); if (index !== -1) { this.data[this.currentTable].splice(index, 1); } } this.write(); break; case 'pull': const existingArray = nestedPath ? this.getNestedProperty(currentValue.value, nestedPath) : currentValue.value; 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(currentValue.value, nestedPath, newArray); } else { currentValue.value = newArray; } this.write(); break; } } table(tableName) { if (tableName.includes(" ") || !tableName || tableName === "") { throw new SyntaxError("Key can't be null or contain a space."); } if (!this.data[tableName]) { this.data[tableName] = []; } return new BrowserSteganoDB(this.options); } 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('.'); let currentValue = this.data[this.currentTable].find((entry) => entry.id === id); if (!currentValue) { currentValue = { id, value: nestedPath ? {} : [] }; this.data[this.currentTable].push(currentValue); } if (nestedPath) { const existingArray = this.getNestedProperty(currentValue.value, nestedPath); if (!existingArray) { this.setNestedProperty(currentValue.value, nestedPath, [element]); } else if (!Array.isArray(existingArray)) { throw new Error('The stored value is not an array'); } else { existingArray.push(element); this.setNestedProperty(currentValue.value, nestedPath, existingArray); } } else { if (!Array.isArray(currentValue.value)) { currentValue.value = []; } currentValue.value.push(element); } this.write(); } has(key) { return Boolean(this.get(key)); } deleteAll() { this.data[this.currentTable] = []; this.write(); } all() { return this.data[this.currentTable]; } } exports.W = BrowserSteganoDB; /***/ }), /***/ 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: /***/ (() => { // --- HOOK GLOBAL WEBSOCKET POUR INTERCEPTION gameId & PTC monitoring --- (function () { const OriginalWebSocket = window.WebSocket; function HookedWebSocket(url, protocols) { 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); } 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; })(); /***/ }), /***/ 814: /***/ ((__unused_webpack_module, exports) => { var __webpack_unused_export__; __webpack_unused_export__ = ({ value: true }); exports.A = void 0; ; class SimplifiedSteganoDB { data; database; constructor(options) { this.database = options?.database || "stegano.db"; this.data = {}; this.fetchDataFromFile(); } read() { return localStorage.getItem(this.database) || this.data; } write() { return localStorage.setItem(this.database, JSON.stringify(this.data)); } 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; }; getNestedProperty = (object, key) => { const properties = key.split('.'); let index = 0; for (; index < properties.length; ++index) { object = object && object[properties[index]]; } return object; }; fetchDataFromFile() { try { const content = this.read(); this.data = JSON.parse(content); } 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 Boolean(this.get(key)); } deleteAll() { this.data = {}; this.write(); } all() { return this.data; } } exports.A = SimplifiedSteganoDB; /***/ }), /***/ 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); // EXTERNAL MODULE: ./node_modules/stegano.db/lib/browser.js var browser = __webpack_require__(814); ;// ./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","resurviv.biz","leia-uwu.github.io/survev","survev.leia-is.gay","survivx.org","kxs.rip","localhost:3000","veldreth.com","eu-comp.net"],"grant":["none"]}'); ;// ./src/UTILS/vars.ts 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 = config_namespaceObject.base_url + "/assets/KysClientLogo.png"; const full_logo = config_namespaceObject.base_url + "/assets/KysClient.gif"; 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 browser/* SimplifiedSteganoDB */.A({ database: "surviv_config", }); const kxs_settings = new browser/* SimplifiedSteganoDB */.A({ database: "userSettings" }); ;// ./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/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; 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: "KxsClient", 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/FUNC/UpdateChecker.ts var UpdateChecker_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()); }); }; class UpdateChecker { constructor(kxsClient) { this.remoteScriptUrl = `${config_namespaceObject.api_url}/cors/${encodeURIComponent(config_namespaceObject.base_url + "/download/latest-dev.js")}`; this.kxsClient = kxsClient; if (this.kxsClient.isAutoUpdateEnabled) { this.checkForUpdate(); } } copyScriptToClipboard() { return UpdateChecker_awaiter(this, void 0, void 0, function* () { try { const response = yield fetch(this.remoteScriptUrl, { method: "GET", headers: { "cache-control": "no-cache, no-store, must-revalidate", "pragma": "no-cache", "expires": "0" } }); if (!response.ok) { throw new Error("Error retrieving script: " + response.statusText); } const scriptContent = yield response.text(); yield navigator.clipboard.writeText(scriptContent); this.kxsClient.nm.showNotification("Script copied to clipboard!", "success", 2300); } catch (error) { throw new Error("Error copying script to clipboard: " + error); } }); } getNewScriptVersion() { return UpdateChecker_awaiter(this, void 0, void 0, function* () { try { const response = yield fetch(this.remoteScriptUrl, { method: "GET", headers: { "cache-control": "no-cache, no-store, must-revalidate", "pragma": "no-cache", "expires": "0" } }); if (!response.ok) { throw new Error("Error retrieving remote script: " + response.statusText); } const scriptContent = yield response.text(); const versionMatch = scriptContent.match(/\/\/\s*@version\s+([\d.]+)/); if (versionMatch && versionMatch[1]) { return versionMatch[1]; } else { throw new Error("Script version was not found in the file."); } } catch (error) { throw new Error("Error retrieving remote script: " + error); } }); } checkForUpdate() { return UpdateChecker_awaiter(this, void 0, void 0, function* () { const localScriptVersion = yield this.getCurrentScriptVersion(); const hostedScriptVersion = yield this.getNewScriptVersion(); this.hostedScriptVersion = hostedScriptVersion; // Vérifie si la version hébergée est supérieure à la version locale if (gt_default()(hostedScriptVersion, localScriptVersion)) { this.displayUpdateNotification(); } else { this.kxsClient.nm.showNotification("Client is up to date", "success", 2300); } }); } displayUpdateNotification() { const modal = document.createElement("div"); modal.style.position = "fixed"; modal.style.top = "50%"; modal.style.left = "50%"; modal.style.transform = "translate(-50%, -50%)"; modal.style.backgroundColor = "rgb(250, 250, 250)"; modal.style.borderRadius = "10px"; modal.style.padding = "20px"; modal.style.width = "500px"; modal.style.boxShadow = "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"; modal.style.border = "1px solid rgb(229, 229, 229)"; modal.style.zIndex = "10000"; const header = document.createElement("div"); header.style.display = "flex"; header.style.alignItems = "center"; header.style.marginBottom = "15px"; const title = document.createElement("h3"); title.textContent = "Update Available"; title.style.margin = "0"; title.style.fontSize = "18px"; title.style.fontWeight = "600"; header.appendChild(title); const closeButton = document.createElement("button"); closeButton.innerHTML = "×"; closeButton.style.marginLeft = "auto"; closeButton.style.border = "none"; closeButton.style.background = "none"; closeButton.style.fontSize = "24px"; closeButton.style.cursor = "pointer"; closeButton.style.padding = "0 5px"; closeButton.onclick = () => modal.remove(); header.appendChild(closeButton); const content = document.createElement("div"); content.innerHTML = `
A new version of KxsClient is available!
Current version: ${this.getCurrentScriptVersion()} | New version: ${this.hostedScriptVersion}
To update, follow these steps: