// ==UserScript==
// @name Kxs Client - Survev.io Client
// @namespace https://github.com/Kisakay/KxsClient
// @version 1.2.2
// @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 ://zurviv.io/
// @match ://expandedwater.online/
// @match ://localhost:3000/
// @match ://surviv.wf/
// @match ://resurviv.biz/
// @match ://82.67.125.203/
// @match ://leia-uwu.github.io/survev/
// @match ://50v50.online/
// @match ://eu-comp.net/
// @match ://survev.leia-is.gay/
// @grant GM_xmlhttpRequest
// @grant GM_info
// @grant GM.getValue
// @grant GM.setValue
// @downloadURL none
// ==/UserScript==
;
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 908:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const debug = __webpack_require__(272)
const { MAX_LENGTH, MAX_SAFE_INTEGER } = __webpack_require__(874)
const { safeRe: re, safeSrc: src, 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 r = new RegExp(`^${this.options.loose ? src[t.PRERELEASELOOSE] : src[t.PRERELEASE]}$`)
const match = `-${identifier}`.match(r)
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
/***/ }),
/***/ 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
/***/ }),
/***/ 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,
}
/***/ }),
/***/ 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
/***/ }),
/***/ 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,
}
/***/ }),
/***/ 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.
createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER]
}|${src[t.NONNUMERICIDENTIFIER]})`)
createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE]
}|${src[t.NONNUMERICIDENTIFIER]})`)
// ## 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*$')
/***/ }),
/***/ 891:
/***/ ((module) => {
"use strict";
module.exports = /*#__PURE__*/JSON.parse('{"base_url":"https://kxs.rip","fileName":"KxsClient.user.js","match":["://survev.io/*","*://66.179.254.36/","://zurviv.io/","://expandedwater.online/","://localhost:3000/","://surviv.wf/","://resurviv.biz/","://82.67.125.203/","://leia-uwu.github.io/survev/","://50v50.online/","://eu-comp.net/","://survev.leia-is.gay/"],"grant":["GM_xmlhttpRequest","GM_info","GM.getValue","GM.setValue"]}');
/***/ }),
/***/ 330:
/***/ ((module) => {
"use strict";
module.exports = /*#__PURE__*/JSON.parse('{"name":"kxsclient","version":"1.2.2","main":"index.js","namespace":"https://github.com/Kisakay/KxsClient","icon":"https://kxs.rip/assets/KysClientLogo.png","placeholder":"Kxs Client - Survev.io Client","scripts":{"test":"echo \\"Error: no test specified\\" && exit 1","commits":"oco --yes; npm version patch; git push;"},"keywords":[],"author":"Kisakay","license":"AGPL-3.0","description":"A client to enhance the survev.io in-game experience with many features, as well as future features.","devDependencies":{"@types/semver":"^7.7.0","@types/tampermonkey":"^5.0.4","ts-loader":"^9.5.1","typescript":"^5.7.2","webpack":"^5.97.1","webpack-cli":"^5.1.4"},"dependencies":{"semver":"^7.7.1"}}');
/***/ })
/******/ });
/************************************************************************/
/******/ // 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/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
(() => {
"use strict";
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
h3: () => (/* binding */ background_image),
fW: () => (/* binding */ kxs_logo)
});
// UNUSED EXPORTS: background_song
;// ./src/ButtonManager.ts
class MenuButton {
constructor(params) {
var _a;
this.isEnabled = (_a = params.initialState) !== null && _a !== void 0 ? _a : false;
this.button = this.createButton(params);
}
createButton(params) {
const button = document.createElement("button");
// Set initial text
this.updateButtonText(button, params.text);
// Set styles
Object.assign(button.style, {
backgroundColor: this.getBackgroundColor(params.color),
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
// Set click handler
button.onclick = () => {
this.isEnabled = !this.isEnabled;
params.onClick();
if (params.updateText !== false) {
this.updateButtonText(button, params.text);
this.updateButtonColor(button, params.color);
}
};
return button;
}
updateButtonText(button, baseText) {
button.textContent = `${baseText} ${this.isEnabled ? "✅" : "❌"}`;
}
getBackgroundColor(color) {
if (color)
return color;
return this.isEnabled ? "#4CAF50" : "#FF0000";
}
updateButtonColor(button, color) {
button.style.backgroundColor = this.getBackgroundColor(color);
}
getElement() {
return this.button;
}
setState(enabled) {
this.isEnabled = enabled;
this.updateButtonColor(this.button);
}
}
class MenuManager {
constructor(menu) {
this.buttons = {};
this.menu = menu;
}
addToggleButton(params) {
const button = new MenuButton({
text: params.text,
initialState: params.initialState,
color: params.color,
onClick: params.onClick,
updateText: params.updateText,
});
this.buttons[params.id] = button;
this.menu.appendChild(button.getElement());
return button;
}
addButton(params) {
var _a;
const button = document.createElement("button");
// Set initial text
button.textContent = params.text;
// Set styles
Object.assign(button.style, {
backgroundColor: (_a = params.color) !== null && _a !== void 0 ? _a : "#007BFF", // Default color
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
// Set click handler
button.onclick = params.onClick;
this.menu.appendChild(button);
}
getButton(id) {
return this.buttons[id];
}
}
;// ./src/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 this.DISCORD_WEBHOOK_REGEX.test(url);
}
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) {
console.error("Error validating webhook:", 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",
};
}
});
}
}
WebhookValidator.DISCORD_WEBHOOK_REGEX = /^https:\/\/discord\.com\/api\/webhooks\/\d+\/[\w-]+$/;
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) {
console.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: result.username,
content: result.isWin ? "🎉 New Victory!" : "Match Ended",
embeds: [embed],
};
yield this.sendWebhookMessage(message);
});
}
}
;// ./src/ClientMainMenu.ts
var ClientMainMenu_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 KxsMainClientMenu {
constructor(kxsClient) {
this.kxsClient = kxsClient;
// this.setupKeyListeners();
// this.initMenu();
}
initMenu() {
this.menu = document.createElement("div");
this.menu.id = "kxsMenu";
Object.assign(this.menu.style, {
backgroundColor: "rgba(0, 0, 0, 0.8)",
padding: "15px",
marginLeft: "15px",
borderRadius: "10px",
boxShadow: "0 4px 10px rgba(0, 0, 0, 0.6)",
zIndex: "10001",
width: "250px",
fontFamily: "Arial, sans-serif",
color: "#fff",
maxHeight: "400px",
overflowY: "auto",
});
const title = document.createElement("h2");
title.textContent = "Kxs Client";
title.style.margin = "0 0 10px";
title.style.textAlign = "center";
title.style.fontSize = "18px";
title.style.color = "#FFAE00";
this.menu.appendChild(title);
window.onload = () => {
const savedBackground = localStorage.getItem("backgroundImage");
if (savedBackground) {
const backgroundElement = document.getElementById("background");
if (backgroundElement) {
backgroundElement.style.backgroundImage = `url(${savedBackground})`;
}
}
};
const startRowTop = document.getElementById("start-row-top");
if (startRowTop) {
startRowTop.appendChild(this.menu);
}
this.menuManager = new MenuManager(this.menu);
this.menuManager.addToggleButton({
id: "fps",
text: "Show FPS",
initialState: this.kxsClient.isFpsVisible,
onClick: () => {
this.kxsClient.isFpsVisible = !this.kxsClient.isFpsVisible;
this.kxsClient.updateFpsVisibility();
this.kxsClient.updateLocalStorage();
},
});
this.menuManager.addToggleButton({
id: "ping",
text: `Show Ping`,
initialState: this.kxsClient.isPingVisible,
onClick: () => {
this.kxsClient.isPingVisible = !this.kxsClient.isPingVisible;
this.kxsClient.updatePingVisibility();
this.kxsClient.updateLocalStorage();
},
});
this.menuManager.addToggleButton({
id: "kills",
text: `Show Kills`,
initialState: this.kxsClient.isKillsVisible,
onClick: () => {
this.kxsClient.isKillsVisible = !this.kxsClient.isKillsVisible;
this.kxsClient.updateKillsVisibility();
this.kxsClient.updateLocalStorage();
},
});
this.menuManager.addToggleButton({
id: "uncapFps",
text: `Uncap FPS`,
initialState: this.kxsClient.isFpsUncapped,
onClick: () => {
this.kxsClient.updateLocalStorage();
this.kxsClient.toggleFpsUncap();
},
});
this.menuManager.addButton({
id: "hideShow",
text: "👀 Hide/Show Menu [P]",
color: "#6F42C1",
onClick: () => this.toggleMenuVisibility(),
});
this.menuManager.addButton({
id: "background",
text: `🎨 Change Background`,
color: "#007BFF",
onClick: () => {
const backgroundElement = document.getElementById("background");
if (!backgroundElement) {
alert("Element with id 'background' not found.");
return;
}
const choice = prompt("Enter '1' to provide a URL or '2' to upload a local image:");
if (choice === "1") {
const newBackgroundUrl = prompt("Enter the URL of the new background image:");
if (newBackgroundUrl) {
backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
this.kxsClient.saveBackgroundToLocalStorage(newBackgroundUrl);
alert("Background updated successfully!");
}
}
else if (choice === "2") {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "image/*";
fileInput.onchange = (event) => {
var _a, _b;
const file = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
backgroundElement.style.backgroundImage = `url(${reader.result})`;
this.kxsClient.saveBackgroundToLocalStorage(file);
alert("Background updated successfully!");
};
reader.readAsDataURL(file);
}
};
fileInput.click();
}
},
});
this.menuManager.addButton({
id: "webhook",
text: `🕸️ Change Discord Webhook`,
color: "#007BFF",
onClick: () => ClientMainMenu_awaiter(this, void 0, void 0, function* () {
const choice = prompt("enter the new discord webhook url:");
if (choice) {
const result = yield WebhookValidator.testWebhook(choice);
if (result.isValid) {
this.kxsClient.discordWebhookUrl = choice;
this.kxsClient.discordTracker.setWebhookUrl(choice);
this.kxsClient.updateLocalStorage();
alert(result.message);
}
else {
alert(result.message);
}
}
}),
});
}
setupKeyListeners() {
document.addEventListener("keydown", (event) => {
if (event.key.toLowerCase() === "p") {
this.toggleMenuVisibility();
}
});
}
toggleMenuVisibility() {
var _a;
const isVisible = ((_a = this.menu) === null || _a === void 0 ? void 0 : _a.style.display) !== "none";
this.menu.style.display = isVisible ? "none" : "block";
}
}
;// ./src/Ping.ts
class PingTest {
constructor(selectedServer) {
this.ptcDataBuf = new ArrayBuffer(1);
this.test = {
region: selectedServer.region,
url: selectedServer.url.startsWith("ws://") || selectedServer.url.startsWith("wss://")
? selectedServer.url
: `https://${selectedServer.url}`, // Store the base URL without /ping for HTTP
ping: 0, // Initialize to 0 instead of 9999
ws: null,
sendTime: 0,
retryCount: 0,
isConnecting: false,
isWebSocket: selectedServer.url.startsWith("ws://") || selectedServer.url.startsWith("wss://"),
};
}
//check to see if urls match
getMatchingGameUrl() {
const gameUrls = [
"*://survev.io/*",
"*://66.179.254.36/*",
"*://zurviv.io/*",
"*://expandedwater.online/*",
"*://localhost:3000/*",
"*://surviv.wf/*",
"*://resurviv.biz/*",
"*://82.67.125.203/*",
"*://leia-uwu.github.io/survev/*",
"*://50v50.online/*",
"*://eu-comp.net/*",
"*://survev.leia-is.gay/*"
];
const currentDomain = window.location.hostname;
for (let i = 0; i < gameUrls.length; i++) {
const url = new URL(gameUrls[i].replace('*://', 'http://'));
if (currentDomain === url.hostname) {
return gameUrls[i];
}
}
console.warn("No matching game URL found for the current domain");
return null;
}
startPingTest() {
if (this.test.isConnecting)
return;
this.test.isConnecting = true;
// We don't need to replace the URL with a matching game URL
// because we want to test the ping to the specific server selected
// The URL was already properly set in the constructor
if (this.test.isWebSocket) {
try {
const ws = new WebSocket(this.test.url);
ws.binaryType = "arraybuffer";
ws.onopen = () => {
this.test.ws = ws;
this.test.isConnecting = false;
this.test.retryCount = 0;
this.sendPing();
};
ws.onmessage = (event) => {
if (this.test.sendTime === 0)
return;
const elapsed = Date.now() - this.test.sendTime;
this.test.ping = Math.min(Math.round(elapsed), 999);
setTimeout(() => this.sendPing(), 250);
};
ws.onerror = (error) => {
console.error("WebSocket error:", error);
this.handleConnectionError();
};
ws.onclose = () => {
this.test.ws = null;
this.test.isConnecting = false;
if (this.test.retryCount < 3) {
setTimeout(() => this.startPingTest(), 1000);
}
};
}
catch (error) {
console.error("Failed to create WebSocket:", error);
this.handleConnectionError();
}
}
else {
this.sendHttpPing();
}
}
sendHttpPing() {
// Use image loading technique to avoid CORS issues
this.test.sendTime = Date.now();
// Create a new image element
const img = new Image();
// Set up load and error handlers
img.onload = () => {
const elapsed = Date.now() - this.test.sendTime;
this.test.ping = Math.min(Math.round(elapsed), 999);
setTimeout(() => this.sendHttpPing(), 250);
};
img.onerror = () => {
// Even if the image fails to load, we can still measure the time it took to fail
// This gives us an approximate ping time
const elapsed = Date.now() - this.test.sendTime;
this.test.ping = Math.min(Math.round(elapsed), 999);
setTimeout(() => this.sendHttpPing(), 250);
};
// Add a cache-busting parameter to prevent caching
const cacheBuster = Date.now();
const baseUrl = this.test.url.replace('/ping', '');
img.src = `${baseUrl}/favicon.ico?cb=${cacheBuster}`;
}
handleConnectionError() {
this.test.ping = 0;
this.test.isConnecting = false;
this.test.retryCount++;
if (this.test.ws) {
this.test.ws.close();
this.test.ws = null;
}
if (this.test.retryCount < 3) {
setTimeout(() => this.startPingTest(), 1000);
}
}
sendPing() {
if (this.test.isWebSocket) {
if (!this.test.ws || this.test.ws.readyState !== WebSocket.OPEN) {
this.handleConnectionError();
return;
}
try {
this.test.sendTime = Date.now();
this.test.ws.send(this.ptcDataBuf);
}
catch (error) {
console.error("Failed to send ping:", error);
this.handleConnectionError();
}
}
}
getPingResult() {
return {
region: this.test.region,
ping: this.test.ping || 0,
};
}
}
class PingManager {
constructor() {
this.currentServer = null;
this.pingTest = null;
}
startPingTest() {
const currentUrl = window.location.href;
const isSpecialUrl = /\/#\w+/.test(currentUrl);
const teamSelectElement = document.getElementById("team-server-select");
const mainSelectElement = document.getElementById("server-select-main");
const region = isSpecialUrl && teamSelectElement
? teamSelectElement.value
: mainSelectElement
? mainSelectElement.value
: null;
if (!region || region === this.currentServer)
return;
this.currentServer = region;
this.resetPing();
const servers = [
{ region: "NA", url: "usr.mathsiscoolfun.com:8001" },
{ region: "EU", url: "eur.mathsiscoolfun.com:8001" },
{ region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
{ region: "SA", url: "sa.mathsiscoolfun.com:8001" },
];
const selectedServer = servers.find((server) => region.toUpperCase() === server.region.toUpperCase());
if (selectedServer) {
this.pingTest = new PingTest(selectedServer);
this.pingTest.startPingTest();
}
}
resetPing() {
var _a;
if ((_a = this.pingTest) === null || _a === void 0 ? void 0 : _a.test.ws) {
this.pingTest.test.ws.close();
this.pingTest.test.ws = null;
}
this.pingTest = null;
}
getPingResult() {
var _a;
return ((_a = this.pingTest) === null || _a === void 0 ? void 0 : _a.getPingResult()) || { region: "", ping: 0 };
}
}
;// ./src/ClientHUD.ts
class KxsClientHUD {
constructor(kxsClient) {
this.healthAnimations = [];
this.lastHealthValue = 100;
this.kxsClient = kxsClient;
this.frameCount = 0;
this.fps = 0;
this.kills = 0;
this.isMenuVisible = true;
this.pingManager = new PingManager();
if (this.kxsClient.isPingVisible) {
this.initCounter("ping", "Ping", "45ms");
}
if (this.kxsClient.isFpsVisible) {
this.initCounter("fps", "FPS", "60");
}
if (this.kxsClient.isKillsVisible) {
this.initCounter("kills", "Kills", "0");
}
this.setupWeaponBorderHandler();
this.startUpdateLoop();
this.escapeMenu();
this.initFriendDetector();
if (this.kxsClient.isKillFeedBlint) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', this.initKillFeed);
}
else {
this.initKillFeed();
}
}
}
initFriendDetector() {
// Initialize friends list
let all_friends = this.kxsClient.all_friends.split(',') || [];
if (all_friends.length >= 1) {
// Create a cache for detected friends
// Structure will be: { "friendName": timestamp }
const friendsCache = {};
// Cache duration in milliseconds (4 minutes = 240000 ms)
const cacheDuration = 4 * 60 * 1000;
// Select the element containing kill feeds
const killfeedContents = document.querySelector('#ui-killfeed-contents');
if (killfeedContents) {
// Keep track of last seen content for each div
const lastSeenContent = {
"ui-killfeed-0": "",
"ui-killfeed-1": "",
"ui-killfeed-2": "",
"ui-killfeed-3": "",
"ui-killfeed-4": "",
"ui-killfeed-5": ""
};
// Function to check if a friend is in the text with cache management
const checkForFriends = (text, divId) => {
// If the text is identical to the last seen, ignore
// @ts-ignore
if (text === lastSeenContent[divId])
return;
// Update the last seen content
// @ts-ignore
lastSeenContent[divId] = text;
// Ignore empty messages
if (!text.trim())
return;
// Current timestamp
const currentTime = Date.now();
// Check if a friend is mentioned
for (let friend of all_friends) {
if (friend !== "" && text.includes(friend)) {
// Check if the friend is in the cache and if the cache is still valid
// @ts-ignore
const lastSeen = friendsCache[friend];
if (!lastSeen || (currentTime - lastSeen > cacheDuration)) {
// Update the cache
// @ts-ignore
friendsCache[friend] = currentTime;
// Display notification
this.kxsClient.nm.showNotification(`[FriendDetector] ${friend} is in this game`, "info", 2300);
}
break;
}
}
};
// Function to check all kill feeds
const checkAllKillfeeds = () => {
all_friends = this.kxsClient.all_friends.split(',') || [];
for (let i = 0; i <= 5; i++) {
const divId = `ui-killfeed-${i}`;
const killDiv = document.getElementById(divId);
if (killDiv) {
const textElement = killDiv.querySelector('.killfeed-text');
if (textElement && textElement.textContent) {
checkForFriends(textElement.textContent, divId);
}
}
}
};
// Observe style or text changes in the entire container
const observer = new MutationObserver(() => {
checkAllKillfeeds();
});
// Start observing with a configuration that detects all changes
observer.observe(killfeedContents, {
childList: true, // Observe changes to child elements
subtree: true, // Observe the entire tree
characterData: true, // Observe text changes
attributes: true // Observe attribute changes (like style/opacity)
});
// Check current content immediately
checkAllKillfeeds();
console.log("Friend detector initialized with 4-minute cache");
}
else {
console.warn("Killfeed-contents element not found");
}
}
}
initKillFeed() {
this.applyCustomStyles();
this.setupObserver();
}
escapeMenu() {
const customStyles = `
.ui-game-menu-desktop {
background: linear-gradient(135deg, rgba(25, 25, 35, 0.95) 0%, rgba(15, 15, 25, 0.98) 100%) !important;
border: 1px solid rgba(255, 255, 255, 0.1) !important;
border-radius: 12px !important;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
padding: 20px !important;
backdrop-filter: blur(10px) !important;
max-width: 350px !important;
/* max-height: 80vh !important; */ /* Optional: Limit the maximum height */
margin: auto !important;
box-sizing: border-box !important;
overflow-y: auto !important; /* Allow vertical scrolling if necessary */
}
.ui-game-menu-desktop::-webkit-scrollbar {
width: 8px !important;
}
.ui-game-menu-desktop::-webkit-scrollbar-track {
background: rgba(25, 25, 35, 0.5) !important;
border-radius: 10px !important;
}
.ui-game-menu-desktop::-webkit-scrollbar-thumb {
background-color: #4287f5 !important;
border-radius: 10px !important;
border: 2px solid rgba(25, 25, 35, 0.5) !important;
}
.ui-game-menu-desktop::-webkit-scrollbar-thumb:hover {
background-color: #5a9eff !important;
}
.ui-game-menu-desktop {
scrollbar-width: thin !important;
scrollbar-color: #4287f5 rgba(25, 25, 35, 0.5) !important;
}
.kxs-header {
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 20px;
padding: 10px;
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
}
.kxs-logo {
width: 30px;
height: 30px;
margin-right: 10px;
border-radius: 6px;
}
.kxs-title {
font-size: 20px;
font-weight: 700;
color: #ffffff;
text-transform: uppercase;
text-shadow: 0 0 10px rgba(66, 135, 245, 0.5);
font-family: 'Arial', sans-serif;
letter-spacing: 2px;
}
.kxs-title span {
color: #4287f5;
}
.btn-game-menu {
background: linear-gradient(135deg, rgba(66, 135, 245, 0.1) 0%, rgba(66, 135, 245, 0.2) 100%) !important;
border: 1px solid rgba(66, 135, 245, 0.3) !important;
border-radius: 8px !important;
color: #ffffff !important;
transition: all 0.3s ease !important;
margin: 5px 0 !important;
padding: 12px !important;
font-weight: 600 !important;
width: 100% !important;
text-align: center !important;
display: block !important;
box-sizing: border-box !important;
}
.btn-game-menu:hover {
background: linear-gradient(135deg, rgba(66, 135, 245, 0.2) 0%, rgba(66, 135, 245, 0.3) 100%) !important;
transform: translateY(-2px) !important;
box-shadow: 0 4px 12px rgba(66, 135, 245, 0.2) !important;
}
.slider-container {
background: rgba(66, 135, 245, 0.1) !important;
border-radius: 8px !important;
padding: 10px 15px !important;
margin: 10px 0 !important;
width: 100% !important;
box-sizing: border-box !important;
}
.slider-text {
color: #ffffff !important;
font-size: 14px !important;
margin-bottom: 8px !important;
text-align: center !important;
}
.slider {
-webkit-appearance: none !important;
width: 100% !important;
height: 6px !important;
border-radius: 3px !important;
background: rgba(66, 135, 245, 0.3) !important;
outline: none !important;
margin: 10px 0 !important;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none !important;
width: 16px !important;
height: 16px !important;
border-radius: 50% !important;
background: #4287f5 !important;
cursor: pointer !important;
transition: all 0.3s ease !important;
}
.slider::-webkit-slider-thumb:hover {
transform: scale(1.2) !important;
box-shadow: 0 0 10px rgba(66, 135, 245, 0.5) !important;
}
.btns-game-double-row {
display: flex !important;
justify-content: center !important;
gap: 10px !important;
margin-bottom: 10px !important;
width: 100% !important;
}
.btn-game-container {
flex: 1 !important;
}
`;
const addCustomStyles = () => {
const styleElement = document.createElement('style');
styleElement.textContent = customStyles;
document.head.appendChild(styleElement);
};
const addKxsHeader = () => {
const menuContainer = document.querySelector('#ui-game-menu');
if (!menuContainer)
return;
const header = document.createElement('div');
header.className = 'kxs-header';
const title = document.createElement('span');
title.className = 'kxs-title';
title.innerHTML = 'Kxs CLIENT';
header.appendChild(title);
menuContainer.insertBefore(header, menuContainer.firstChild);
};
if (document.querySelector('#ui-game-menu')) {
addCustomStyles();
addKxsHeader();
}
}
handleMessage(element) {
if (element instanceof HTMLElement && element.classList.contains('killfeed-div')) {
const killfeedText = element.querySelector('.killfeed-text');
if (killfeedText instanceof HTMLElement) {
if (killfeedText.textContent && killfeedText.textContent.trim() !== '') {
if (!killfeedText.hasAttribute('data-glint')) {
killfeedText.setAttribute('data-glint', 'true');
element.style.opacity = '1';
setTimeout(() => {
element.style.opacity = '0';
}, 5000);
}
}
else {
element.style.opacity = '0';
}
}
}
}
setupObserver() {
const killfeedContents = document.getElementById('ui-killfeed-contents');
if (killfeedContents) {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.target instanceof HTMLElement &&
mutation.target.classList.contains('killfeed-text')) {
const parentDiv = mutation.target.closest('.killfeed-div');
if (parentDiv) {
this.handleMessage(parentDiv);
}
}
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLElement) {
this.handleMessage(node);
}
});
});
});
observer.observe(killfeedContents, {
childList: true,
subtree: true,
characterData: true,
attributes: true,
attributeFilter: ['style', 'class']
});
killfeedContents.querySelectorAll('.killfeed-div').forEach(this.handleMessage);
}
}
applyCustomStyles() {
const customStyles = document.createElement('style');
if (this.kxsClient.isKillFeedBlint) {
customStyles.innerHTML = `
@import url('https://fonts.googleapis.com/css2?family=Oxanium:wght@600&display=swap');
.killfeed-div {
position: absolute !important;
padding: 5px 10px !important;
background: rgba(0, 0, 0, 0.7) !important;
border-radius: 5px !important;
transition: opacity 0.5s ease-out !important;
}
.killfeed-text {
font-family: 'Oxanium', sans-serif !important;
font-weight: bold !important;
font-size: 16px !important;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) !important;
background: linear-gradient(90deg,
rgb(255, 0, 0),
rgb(255, 127, 0),
rgb(255, 255, 0),
rgb(0, 255, 0),
rgb(0, 0, 255),
rgb(75, 0, 130),
rgb(148, 0, 211),
rgb(255, 0, 0));
background-size: 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: glint 3s linear infinite;
}
@keyframes glint {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
.killfeed-div .killfeed-text:empty {
display: none !important;
}
`;
}
else {
customStyles.innerHTML = `
.killfeed-div {
position: absolute;
padding: 5px 10px;
background: rgba(0, 0, 0, 0.7);
border-radius: 5px;
transition: opacity 0.5s ease-out;
}
.killfeed-text {
font-family: inherit;
font-weight: normal;
font-size: inherit;
color: inherit;
text-shadow: none;
background: none;
}
.killfeed-div .killfeed-text:empty {
display: none;
}
`;
}
document.head.appendChild(customStyles);
}
handleResize() {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
for (const name of ['fps', 'kills', 'ping']) {
const counterContainer = document.getElementById(`${name}CounterContainer`);
if (!counterContainer)
continue;
const counter = this.kxsClient.counters[name];
if (!counter)
continue;
const rect = counterContainer.getBoundingClientRect();
const savedPosition = this.getSavedPosition(name);
let newPosition = this.calculateSafePosition(savedPosition, rect.width, rect.height, viewportWidth, viewportHeight);
this.applyPosition(counterContainer, newPosition);
this.savePosition(name, newPosition);
}
}
calculateSafePosition(currentPosition, elementWidth, elementHeight, viewportWidth, viewportHeight) {
let { left, top } = currentPosition;
if (left + elementWidth > viewportWidth) {
left = viewportWidth - elementWidth;
}
if (left < 0) {
left = 0;
}
if (top + elementHeight > viewportHeight) {
top = viewportHeight - elementHeight;
}
if (top < 0) {
top = 0;
}
return { left, top };
}
getSavedPosition(name) {
const savedPosition = localStorage.getItem(`${name}CounterPosition`);
if (savedPosition) {
try {
return JSON.parse(savedPosition);
}
catch (_a) {
return this.kxsClient.defaultPositions[name];
}
}
return this.kxsClient.defaultPositions[name];
}
applyPosition(element, position) {
element.style.left = `${position.left}px`;
element.style.top = `${position.top}px`;
}
savePosition(name, position) {
localStorage.setItem(`${name}CounterPosition`, JSON.stringify(position));
}
startUpdateLoop() {
var _a;
const now = performance.now();
const delta = now - this.kxsClient.lastFrameTime;
this.frameCount++;
if (delta >= 1000) {
this.fps = Math.round((this.frameCount * 1000) / delta);
this.frameCount = 0;
this.kxsClient.lastFrameTime = now;
this.kills = this.kxsClient.getKills();
if (this.kxsClient.isFpsVisible && this.kxsClient.counters.fps) {
this.kxsClient.counters.fps.textContent = `FPS: ${this.fps}`;
}
if (this.kxsClient.isKillsVisible && this.kxsClient.counters.kills) {
this.kxsClient.counters.kills.textContent = `Kills: ${this.kills}`;
}
if (this.kxsClient.isPingVisible &&
this.kxsClient.counters.ping &&
this.pingManager) {
const result = this.pingManager.getPingResult();
this.kxsClient.counters.ping.textContent = `PING: ${result.ping} ms`;
}
}
this.pingManager.startPingTest();
if (this.kxsClient.animationFrameCallback) {
this.kxsClient.animationFrameCallback(() => this.startUpdateLoop());
}
this.updateUiElements();
this.updateBoostBars();
this.updateHealthBars();
(_a = this.kxsClient.kill_leader) === null || _a === void 0 ? void 0 : _a.update(this.kills);
}
initCounter(name, label, initialText) {
const counter = document.createElement("div");
counter.id = `${name}Counter`;
const counterContainer = document.createElement("div");
counterContainer.id = `${name}CounterContainer`;
Object.assign(counterContainer.style, {
position: "absolute",
left: `${this.kxsClient.defaultPositions[name].left}px`,
top: `${this.kxsClient.defaultPositions[name].top}px`,
zIndex: "10000",
});
Object.assign(counter.style, {
color: "white",
backgroundColor: "rgba(0, 0, 0, 0.2)",
borderRadius: "5px",
fontFamily: "Arial, sans-serif",
padding: "5px 10px",
pointerEvents: "none",
cursor: "default",
width: `${this.kxsClient.defaultSizes[name].width}px`,
height: `${this.kxsClient.defaultSizes[name].height}px`,
display: "flex",
alignItems: "center",
justifyContent: "center",
textAlign: "center",
resize: "both",
overflow: "hidden",
});
counter.textContent = `${label}: ${initialText}`;
counterContainer.appendChild(counter);
const uiTopLeft = document.getElementById("ui-top-left");
if (uiTopLeft) {
uiTopLeft.appendChild(counterContainer);
}
const adjustFontSize = () => {
const { width, height } = counter.getBoundingClientRect();
const size = Math.min(width, height) * 0.4;
counter.style.fontSize = `${size}px`;
};
new ResizeObserver(adjustFontSize).observe(counter);
counter.addEventListener("mousedown", (event) => {
if (event.button === 1) {
this.resetCounter(name, label, initialText);
event.preventDefault();
}
});
this.kxsClient.makeDraggable(counterContainer, `${name}CounterPosition`);
this.kxsClient.counters[name] = counter;
}
resetCounter(name, label, initialText) {
const counter = this.kxsClient.counters[name];
const container = document.getElementById(`${name}CounterContainer`);
if (!counter || !container)
return;
// Reset only this counter's position and size
Object.assign(container.style, {
left: `${this.kxsClient.defaultPositions[name].left}px`,
top: `${this.kxsClient.defaultPositions[name].top}px`,
});
Object.assign(counter.style, {
width: `${this.kxsClient.defaultSizes[name].width}px`,
height: `${this.kxsClient.defaultSizes[name].height}px`,
fontSize: "18px",
});
counter.textContent = `${label}: ${initialText}`;
// Clear the saved position for this counter only
localStorage.removeItem(`${name}CounterPosition`);
}
updateBoostBars() {
const boostCounter = document.querySelector("#ui-boost-counter");
if (boostCounter) {
const boostBars = boostCounter.querySelectorAll(".ui-boost-base .ui-bar-inner");
let totalBoost = 0;
const weights = [25, 25, 40, 10];
boostBars.forEach((bar, index) => {
const width = parseFloat(bar.style.width);
if (!isNaN(width)) {
totalBoost += width * (weights[index] / 100);
}
});
const averageBoost = Math.round(totalBoost);
let boostDisplay = boostCounter.querySelector(".boost-display");
if (!boostDisplay) {
boostDisplay = document.createElement("div");
boostDisplay.classList.add("boost-display");
Object.assign(boostDisplay.style, {
position: "absolute",
bottom: "75px",
right: "335px",
color: "#FF901A",
backgroundColor: "rgba(0, 0, 0, 0.4)",
padding: "5px 10px",
borderRadius: "5px",
fontFamily: "Arial, sans-serif",
fontSize: "14px",
zIndex: "10",
textAlign: "center",
});
boostCounter.appendChild(boostDisplay);
}
boostDisplay.textContent = `AD: ${averageBoost}%`;
}
}
setupWeaponBorderHandler() {
const weaponContainers = Array.from(document.getElementsByClassName("ui-weapon-switch"));
weaponContainers.forEach((container) => {
if (container.id === "ui-weapon-id-4") {
container.style.border = "3px solid #2f4032";
}
else {
container.style.border = "3px solid #FFFFFF";
}
});
const weaponNames = Array.from(document.getElementsByClassName("ui-weapon-name"));
const WEAPON_COLORS = {
ORANGE: '#FFAE00',
BLUE: '#007FFF',
GREEN: '#0f690d',
RED: '#FF0000',
BLACK: '#000000',
OLIVE: '#808000',
ORANGE_RED: '#FF4500',
PURPLE: '#800080',
TEAL: '#008080',
BROWN: '#A52A2A',
PINK: '#FFC0CB',
DEFAULT: '#FFFFFF'
};
const WEAPON_COLOR_MAPPING = {
ORANGE: ['CZ-3A1', 'G18C', 'M9', 'M93R', 'MAC-10', 'MP5', 'P30L', 'DUAL P30L', 'UMP9', 'VECTOR', 'VSS', 'FLAMETHROWER'],
BLUE: ['AK-47', 'OT-38', 'OTS-38', 'M39 EMR', 'DP-28', 'MOSIN-NAGANT', 'SCAR-H', 'SV-98', 'M1 GARAND', 'PKP PECHENEG', 'AN-94', 'BAR M1918', 'BLR 81', 'SVD-63', 'M134', 'WATER GUN', 'GROZA', 'GROZA-S'],
GREEN: ['FAMAS', 'M416', 'M249', 'QBB-97', 'MK 12 SPR', 'M4A1-S', 'SCOUT ELITE', 'L86A2'],
RED: ['M870', 'MP220', 'SAIGA-12', 'SPAS-12', 'USAS-12', 'SUPER 90', 'LASR GUN', 'M1100'],
BLACK: ['DEAGLE 50', 'RAINBOW BLASTER'],
OLIVE: ['AWM-S', 'MK 20 SSR'],
ORANGE_RED: ['FLARE GUN'],
PURPLE: ['MODEL 94', 'PEACEMAKER', 'VECTOR (.45 ACP)', 'M1911', 'M1A1', 'MK45G'],
TEAL: ['M79'],
BROWN: ['POTATO CANNON', 'SPUD GUN'],
PINK: ['HEART CANNON'],
DEFAULT: []
};
weaponNames.forEach((weaponNameElement) => {
const weaponContainer = weaponNameElement.closest(".ui-weapon-switch");
const observer = new MutationObserver(() => {
var _a, _b, _c;
const weaponName = ((_b = (_a = weaponNameElement.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === null || _b === void 0 ? void 0 : _b.toUpperCase()) || '';
const colorKey = (((_c = Object.entries(WEAPON_COLOR_MAPPING)
.find(([_, weapons]) => weapons.includes(weaponName))) === null || _c === void 0 ? void 0 : _c[0]) || 'DEFAULT');
if (weaponContainer && weaponContainer.id !== "ui-weapon-id-4") {
weaponContainer.style.border = `3px solid ${WEAPON_COLORS[colorKey]}`;
}
});
observer.observe(weaponNameElement, { childList: true, characterData: true, subtree: true });
});
}
updateUiElements() {
const currentUrl = window.location.href;
const isSpecialUrl = /\/#\w+/.test(currentUrl);
const playerOptions = document.getElementById("player-options");
const teamMenuContents = document.getElementById("team-menu-contents");
const startMenuContainer = document.querySelector("#start-menu .play-button-container");
// Update counters draggable state based on LSHIFT menu visibility
this.updateCountersDraggableState();
if (!playerOptions)
return;
if (isSpecialUrl &&
teamMenuContents &&
playerOptions.parentNode !== teamMenuContents) {
teamMenuContents.appendChild(playerOptions);
}
else if (!isSpecialUrl &&
startMenuContainer &&
playerOptions.parentNode !== startMenuContainer) {
const firstChild = startMenuContainer.firstChild;
startMenuContainer.insertBefore(playerOptions, firstChild);
}
const teamMenu = document.getElementById("team-menu");
if (teamMenu) {
teamMenu.style.height = "355px";
}
const menuBlocks = document.querySelectorAll(".menu-block");
menuBlocks.forEach((block) => {
block.style.maxHeight = "355px";
});
//scalable?
}
updateMenuButtonText() {
const hideButton = document.getElementById("hideMenuButton");
hideButton.textContent = this.isMenuVisible
? "Hide Menu [P]"
: "Show Menu [P]";
}
updateHealthBars() {
const healthBars = document.querySelectorAll("#ui-health-container");
healthBars.forEach((container) => {
var _a, _b;
const bar = container.querySelector("#ui-health-actual");
if (bar) {
const currentHealth = Math.round(parseFloat(bar.style.width));
let percentageText = container.querySelector(".health-text");
// Create or update percentage text
if (!percentageText) {
percentageText = document.createElement("span");
percentageText.classList.add("health-text");
Object.assign(percentageText.style, {
width: "100%",
textAlign: "center",
marginTop: "5px",
color: "#333",
fontSize: "20px",
fontWeight: "bold",
position: "absolute",
zIndex: "10",
});
container.appendChild(percentageText);
}
// Check for health change
if (currentHealth !== this.lastHealthValue) {
const healthChange = currentHealth - this.lastHealthValue;
if (healthChange !== 0) {
this.showHealthChangeAnimation(container, healthChange);
}
this.lastHealthValue = currentHealth;
}
if (this.kxsClient.isHealthWarningEnabled) {
(_a = this.kxsClient.healWarning) === null || _a === void 0 ? void 0 : _a.update(currentHealth);
}
else {
(_b = this.kxsClient.healWarning) === null || _b === void 0 ? void 0 : _b.hide();
}
percentageText.textContent = `${currentHealth}%`;
// Update animations
this.updateHealthAnimations();
}
});
}
showHealthChangeAnimation(container, change) {
const animation = document.createElement("div");
const isPositive = change > 0;
Object.assign(animation.style, {
position: "absolute",
color: isPositive ? "#2ecc71" : "#e74c3c",
fontSize: "24px",
fontWeight: "bold",
fontFamily: "Arial, sans-serif",
textShadow: "2px 2px 4px rgba(0,0,0,0.3)",
pointerEvents: "none",
zIndex: "100",
opacity: "1",
top: "50%",
right: "-80px", // Position à droite de la barre de vie
transform: "translateY(-50%)", // Centre verticalement
whiteSpace: "nowrap", // Empêche le retour à la ligne
});
// Check if change is a valid number before displaying it
if (!isNaN(change)) {
animation.textContent = `${isPositive ? "+" : ""}${change} HP`;
}
else {
// Skip showing animation if change is NaN
return;
}
container.appendChild(animation);
this.healthAnimations.push({
element: animation,
startTime: performance.now(),
duration: 1500, // Animation duration in milliseconds
value: change,
});
}
updateCountersDraggableState() {
var _a;
const isMenuOpen = ((_a = this.kxsClient.secondaryMenu) === null || _a === void 0 ? void 0 : _a.getMenuVisibility()) || false;
const counters = ['fps', 'kills', 'ping'];
counters.forEach(name => {
const counter = document.getElementById(`${name}Counter`);
if (counter) {
// Mise à jour des propriétés de draggabilité
counter.style.pointerEvents = isMenuOpen ? 'auto' : 'none';
counter.style.cursor = isMenuOpen ? 'move' : 'default';
// Mise à jour de la possibilité de redimensionnement
counter.style.resize = isMenuOpen ? 'both' : 'none';
}
});
}
updateHealthAnimations() {
const currentTime = performance.now();
this.healthAnimations = this.healthAnimations.filter(animation => {
const elapsed = currentTime - animation.startTime;
const progress = Math.min(elapsed / animation.duration, 1);
if (progress < 1) {
// Update animation position and opacity
// Maintenant l'animation se déplace horizontalement vers la droite
const translateX = progress * 20; // Déplacement horizontal
Object.assign(animation.element.style, {
transform: `translateY(-50%) translateX(${translateX}px)`,
opacity: String(1 - progress),
});
return true;
}
else {
// Remove completed animation
animation.element.remove();
return false;
}
});
}
}
;// ./src/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/HealthWarning.ts
class HealthWarning {
constructor(kxsClient) {
this.warningElement = null;
this.kxsClient = kxsClient;
this.createWarningElement();
this.setFixedPosition();
}
createWarningElement() {
const warning = document.createElement("div");
const uiTopLeft = document.getElementById("ui-top-left");
warning.style.cssText = `
position: fixed;
background: rgba(0, 0, 0, 0.8);
border: 2px solid #ff0000;
border-radius: 5px;
padding: 10px 15px;
color: #ff0000;
font-family: Arial, sans-serif;
font-size: 14px;
z-index: 9999;
display: none;
backdrop-filter: blur(5px);
pointer-events: none;
`;
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 = "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;
// Example
this.warningElement.style.top = "742px";
this.warningElement.style.left = "285px";
//OR use transform use somethin like, this.warningElement.style.transform = `translate(20px, 20px)`;
}
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;
this.warningElement.style.display = "none";
}
update(health) {
if (health <= 30 && health > 0) {
this.show(health);
}
else {
this.hide();
}
}
}
;// ./src/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) {
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.getPlayerName() === (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()) {
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/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.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";
}
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/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/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());
});
};
const packageInfo = __webpack_require__(330);
const config = __webpack_require__(891);
class UpdateChecker {
constructor(kxsClient) {
this.remoteScriptUrl = config.base_url + "/download/latest-dev.js";
this.kxsClient = kxsClient;
if (this.kxsClient.isAutoUpdateEnabled) {
this.checkForUpdate();
}
}
downloadScript() {
return UpdateChecker_awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
GM.xmlHttpRequest({
method: "GET",
url: this.remoteScriptUrl,
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": "0"
},
nocache: true,
responseType: "blob",
onload: (response) => {
if (response.status === 200) {
const blob = new Blob([response.response], { type: 'application/javascript' });
const downloadUrl = window.URL.createObjectURL(blob);
const downloadLink = document.createElement('a');
downloadLink.href = downloadUrl;
downloadLink.download = 'KxsClient.user.js';
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
window.URL.revokeObjectURL(downloadUrl);
resolve();
}
else {
reject(new Error("Error downloading script: " + response.statusText));
}
},
onerror: (error) => {
reject(new Error("Error during script download: " + error));
}
});
});
});
}
getNewScriptVersion() {
return UpdateChecker_awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
GM.xmlHttpRequest({
method: "GET",
url: this.remoteScriptUrl,
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": "0"
},
nocache: true,
onload: (response) => {
if (response.status === 200) {
const scriptContent = response.responseText;
const versionMatch = scriptContent.match(/\/\/\s*@version\s+([\d.]+)/);
if (versionMatch && versionMatch[1]) {
resolve(versionMatch[1]);
}
else {
reject(new Error("Script version was not found in the file."));
}
}
else {
reject(new Error("Error retrieving remote script: " + response.statusText));
}
},
onerror: (error) => {
reject(new Error("Error during remote script request: " + 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 = "400px";
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)";
const header = document.createElement("div");
header.style.display = "flex";
header.style.alignItems = "center";
header.style.marginBottom = "15px";
const title = document.createElement("h3");
title.textContent = "Download Update";
title.style.margin = "0";
title.style.fontSize = "16px";
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 = "20px";
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!
Locale: ${this.getCurrentScriptVersion()} | On web: ${this.hostedScriptVersion}
Click the button below to update now.`;
content.style.marginBottom = "20px";
content.style.color = "rgb(75, 85, 99)";
const updateButton = document.createElement("button");
updateButton.textContent = "Update Now";
updateButton.style.backgroundColor = "rgb(59, 130, 246)";
updateButton.style.color = "white";
updateButton.style.padding = "8px 16px";
updateButton.style.borderRadius = "6px";
updateButton.style.border = "none";
updateButton.style.cursor = "pointer";
updateButton.style.width = "100%";
updateButton.onclick = () => UpdateChecker_awaiter(this, void 0, void 0, function* () {
try {
yield this.downloadScript();
this.kxsClient.nm.showNotification("Download started", "success", 2300);
modal.remove();
}
catch (error) {
this.kxsClient.nm.showNotification("Download failed: " + error.message, "info", 5000);
}
});
modal.appendChild(header);
modal.appendChild(content);
modal.appendChild(updateButton);
document.body.appendChild(modal);
}
getCurrentScriptVersion() {
return packageInfo.version;
}
}
;// ./src/DiscordRichPresence.ts
const DiscordRichPresence_packageInfo = __webpack_require__(330);
class DiscordWebSocket {
constructor(kxsClient, token) {
this.ws = null;
this.heartbeatInterval = 0;
this.sequence = null;
this.isAuthenticated = false;
this.kxsClient = kxsClient;
}
connect() {
if (this.kxsClient.discordToken === ""
|| this.kxsClient.discordToken === null
|| this.kxsClient.discordToken === undefined) {
return;
}
this.ws = new WebSocket('wss://gateway.discord.gg/?v=9&encoding=json');
this.ws.onopen = () => {
console.log('WebSocket connection established');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleMessage(data);
};
this.ws.onerror = (error) => {
this.kxsClient.nm.showNotification('WebSocket error: ' + error.type, 'error', 5000);
};
this.ws.onclose = () => {
this.kxsClient.nm.showNotification('Disconnected from Discord gateway', 'info', 5000);
clearInterval(this.heartbeatInterval);
this.isAuthenticated = false;
};
}
identify() {
const payload = {
op: 2,
d: {
token: this.kxsClient.discordToken,
properties: {
$os: 'linux',
$browser: 'chrome',
$device: 'chrome'
},
presence: {
activities: [{
name: "KxsClient",
type: 0,
application_id: "1321193265533550602",
assets: {
large_image: "mp:app-assets/1321193265533550602/1322173537326338058.png?size=512",
large_text: "KxsClient v" + DiscordRichPresence_packageInfo.version,
}
}],
status: 'online',
afk: false
}
}
};
this.send(payload);
}
handleMessage(data) {
switch (data.op) {
case 10: // Hello
const { heartbeat_interval } = data.d;
this.startHeartbeat(heartbeat_interval);
this.identify();
this.kxsClient.nm.showNotification('Started Discord RPC', 'success', 3000);
break;
case 11: // Heartbeat ACK
console.log('Heartbeat acknowledged');
break;
case 0: // Dispatch
this.sequence = data.s;
if (data.t === 'READY') {
this.isAuthenticated = true;
this.kxsClient.nm.showNotification('Connected to Discord gateway', 'success', 2500);
}
break;
}
}
startHeartbeat(interval) {
this.heartbeatInterval = setInterval(() => {
this.send({
op: 1,
d: this.sequence
});
}, interval);
}
send(data) {
var _a;
if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
disconnect() {
if (this.ws) {
clearInterval(this.heartbeatInterval);
this.ws.close();
}
}
}
;// ./src/NotificationManager.ts
class NotificationManager {
constructor() {
this.notifications = [];
this.NOTIFICATION_HEIGHT = 65; // Height + margin
this.NOTIFICATION_MARGIN = 10;
this.addGlobalStyles();
}
static getInstance() {
if (!NotificationManager.instance) {
NotificationManager.instance = new NotificationManager();
}
return NotificationManager.instance;
}
addGlobalStyles() {
const styleSheet = document.createElement("style");
styleSheet.textContent = `
@keyframes slideIn {
0% { transform: translateX(-120%); opacity: 0; }
50% { transform: translateX(10px); opacity: 0.8; }
100% { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
0% { transform: translateX(0); opacity: 1; }
50% { transform: translateX(10px); opacity: 0.8; }
100% { transform: translateX(-120%); opacity: 0; }
}
@keyframes slideLeft {
from { transform-origin: right; transform: scaleX(1); }
to { transform-origin: right; transform: scaleX(0); }
}
@keyframes bounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
`;
document.head.appendChild(styleSheet);
}
updateNotificationPositions() {
this.notifications.forEach((notification, index) => {
const topPosition = 20 + (index * this.NOTIFICATION_HEIGHT);
notification.style.top = `${topPosition}px`;
});
}
removeNotification(notification) {
const index = this.notifications.indexOf(notification);
if (index > -1) {
this.notifications.splice(index, 1);
this.updateNotificationPositions();
}
}
getIconConfig(type) {
const configs = {
success: {
color: '#4CAF50',
svg: ``
},
error: {
color: '#F44336',
svg: ``
},
info: {
color: '#FFD700',
svg: ``
}
};
return configs[type];
}
showNotification(message, type, duration = 5000) {
const notification = document.createElement("div");
// Base styles
Object.assign(notification.style, {
position: "fixed",
top: "20px",
left: "20px",
padding: "12px 20px",
backgroundColor: "#333333",
color: "white",
zIndex: "9999",
minWidth: "200px",
borderRadius: "4px",
display: "flex",
alignItems: "center",
gap: "10px",
transform: "translateX(-120%)",
opacity: "0",
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
});
// Create icon
const icon = document.createElement("div");
Object.assign(icon.style, {
width: "20px",
height: "20px",
display: "flex",
alignItems: "center",
justifyContent: "center",
animation: "bounce 0.5s ease-in-out"
});
const iconConfig = this.getIconConfig(type);
icon.style.color = iconConfig.color;
icon.innerHTML = iconConfig.svg;
// Create message
const messageDiv = document.createElement("div");
messageDiv.textContent = message;
messageDiv.style.flex = "1";
// Create progress bar
const progressBar = document.createElement("div");
Object.assign(progressBar.style, {
height: "4px",
backgroundColor: "#e6f3ff",
width: "100%",
position: "absolute",
bottom: "0",
left: "0",
animation: `slideLeft ${duration}ms linear forwards`
});
// Assemble notification
notification.appendChild(icon);
notification.appendChild(messageDiv);
notification.appendChild(progressBar);
document.body.appendChild(notification);
// Add to stack and update positions
this.notifications.push(notification);
this.updateNotificationPositions();
// Entrance animation
requestAnimationFrame(() => {
notification.style.transition = "all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55)";
notification.style.animation = "slideIn 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards";
});
// Exit animation and cleanup
setTimeout(() => {
notification.style.animation = "slideOut 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards";
setTimeout(() => {
this.removeNotification(notification);
notification.remove();
}, 500);
}, duration);
}
}
;// ./src/ClientSecondaryMenu.ts
class KxsLegacyClientSecondaryMenu {
constructor(kxsClient) {
this.kxsClient = kxsClient;
this.isClientMenuVisible = false;
this.isDragging = false;
this.dragOffset = { x: 0, y: 0 };
this.sections = [];
this.menu = document.createElement("div");
this.boundShiftListener = this.handleShiftPress.bind(this);
this.boundMouseDownListener = this.handleMouseDown.bind(this);
this.boundMouseMoveListener = this.handleMouseMove.bind(this);
this.boundMouseUpListener = this.handleMouseUp.bind(this);
this.initMenu();
this.addShiftListener();
this.addDragListeners();
}
handleShiftPress(event) {
if (event.key === "Shift" && event.location == 2) {
this.clearMenu();
this.toggleMenuVisibility();
this.loadOption();
}
}
handleMouseDown(e) {
if (e.target instanceof HTMLElement && !e.target.matches("input, select, button")) {
this.isDragging = true;
const rect = this.menu.getBoundingClientRect();
this.dragOffset = {
x: e.clientX - rect.left,
y: e.clientY - rect.top,
};
this.menu.style.cursor = "grabbing";
}
}
handleMouseMove(e) {
if (!this.isDragging)
return;
e.preventDefault();
const newX = e.clientX - this.dragOffset.x;
const newY = e.clientY - this.dragOffset.y;
const maxX = window.innerWidth - this.menu.offsetWidth;
const maxY = window.innerHeight - this.menu.offsetHeight;
this.menu.style.left = `${Math.max(0, Math.min(newX, maxX))}px`;
this.menu.style.top = `${Math.max(0, Math.min(newY, maxY))}px`;
}
handleMouseUp() {
this.isDragging = false;
this.menu.style.cursor = "move";
}
initMenu() {
this.menu.id = "kxsMenuIG";
this.applyMenuStyles();
this.createHeader();
document.body.appendChild(this.menu);
}
loadOption() {
let HUD = this.addSection("HUD");
this.addOption(HUD, {
label: "Use Legacy Menu",
value: this.kxsClient.isLegaySecondaryMenu,
type: "toggle",
onChange: (value) => {
this.kxsClient.isLegaySecondaryMenu = !this.kxsClient.isLegaySecondaryMenu;
this.kxsClient.updateLocalStorage();
this.kxsClient.secondaryMenu = new KxsClientSecondaryMenu(this.kxsClient);
this.destroy();
},
});
this.addOption(HUD, {
label: "Clean Main Menu",
value: this.kxsClient.isMainMenuCleaned,
type: "toggle",
onChange: (value) => {
this.kxsClient.isMainMenuCleaned = !this.kxsClient.isMainMenuCleaned;
this.kxsClient.MainMenuCleaning();
this.kxsClient.updateLocalStorage();
},
});
this.addOption(HUD, {
label: "Show Ping",
value: this.kxsClient.isPingVisible,
type: "toggle",
onChange: (value) => {
this.kxsClient.isPingVisible = !this.kxsClient.isPingVisible;
this.kxsClient.updatePingVisibility();
this.kxsClient.updateLocalStorage();
},
});
this.addOption(HUD, {
label: "Show FPS",
value: this.kxsClient.isFpsVisible,
type: "toggle",
onChange: (value) => {
this.kxsClient.isFpsVisible = !this.kxsClient.isFpsVisible;
this.kxsClient.updateFpsVisibility();
this.kxsClient.updateLocalStorage();
},
});
this.addOption(HUD, {
label: "Show Kills",
value: this.kxsClient.isKillsVisible,
type: "toggle",
onChange: (value) => {
this.kxsClient.isKillsVisible = !this.kxsClient.isKillsVisible;
this.kxsClient.updateKillsVisibility();
this.kxsClient.updateLocalStorage();
},
});
this.addOption(HUD, {
label: "Kill Feed Blint Text",
value: this.kxsClient.isKillFeedBlint,
type: "toggle",
onChange: (value) => {
this.kxsClient.isKillFeedBlint = !this.kxsClient.isKillFeedBlint;
this.kxsClient.updateLocalStorage();
},
});
let musicSection = this.addSection("Music");
this.addOption(musicSection, {
label: "Death sound",
value: this.kxsClient.isDeathSoundEnabled,
type: "toggle",
onChange: (value) => {
this.kxsClient.isDeathSoundEnabled = !this.kxsClient.isDeathSoundEnabled;
this.kxsClient.updateLocalStorage();
},
});
this.addOption(musicSection, {
label: "Win sound",
value: this.kxsClient.isWinSoundEnabled,
type: "toggle",
onChange: (value) => {
this.kxsClient.isWinSoundEnabled = !this.kxsClient.isWinSoundEnabled;
this.kxsClient.updateLocalStorage();
},
});
let pluginsSection = this.addSection("Plugins");
this.addOption(pluginsSection, {
label: "Webhook URL",
value: this.kxsClient.discordWebhookUrl || "",
type: "input",
onChange: (value) => {
value = value.toString().trim();
this.kxsClient.discordWebhookUrl = value;
this.kxsClient.discordTracker.setWebhookUrl(value);
this.kxsClient.updateLocalStorage();
},
});
this.addOption(pluginsSection, {
label: "Heal Warning",
value: this.kxsClient.isHealthWarningEnabled,
type: "toggle",
onChange: (value) => {
this.kxsClient.isHealthWarningEnabled = !this.kxsClient.isHealthWarningEnabled;
this.kxsClient.updateLocalStorage();
},
});
this.addOption(pluginsSection, {
label: "Update Checker",
value: this.kxsClient.isAutoUpdateEnabled,
type: "toggle",
onChange: (value) => {
this.kxsClient.isAutoUpdateEnabled = !this.kxsClient.isAutoUpdateEnabled;
this.kxsClient.updateLocalStorage();
},
});
this.addOption(HUD, {
label: `Spotify Player`,
value: this.kxsClient.isSpotifyPlayerEnabled,
type: "toggle",
onChange: () => {
this.kxsClient.isSpotifyPlayerEnabled = !this.kxsClient.isSpotifyPlayerEnabled;
this.kxsClient.updateLocalStorage();
this.kxsClient.toggleSpotifyMenu();
},
});
this.addOption(pluginsSection, {
label: `Uncap FPS`,
value: this.kxsClient.isFpsUncapped,
type: "toggle",
onChange: () => {
this.kxsClient.isFpsUncapped = !this.kxsClient.isFpsUncapped;
this.kxsClient.toggleFpsUncap();
this.kxsClient.updateLocalStorage();
},
});
this.addOption(pluginsSection, {
label: `Winning Animation`,
value: this.kxsClient.isWinningAnimationEnabled,
type: "toggle",
onChange: () => {
this.kxsClient.isWinningAnimationEnabled = !this.kxsClient.isWinningAnimationEnabled;
this.kxsClient.updateLocalStorage();
},
});
this.addOption(pluginsSection, {
label: `Rich Presence (Account token required)`,
value: this.kxsClient.discordToken || "",
type: "input",
onChange: (value) => {
value = value.toString().trim();
this.kxsClient.discordToken = this.kxsClient.parseToken(value);
this.kxsClient.discordRPC.disconnect();
this.kxsClient.discordRPC.connect();
this.kxsClient.updateLocalStorage();
},
});
this.addOption(pluginsSection, {
label: `Kill Leader Tracking`,
value: this.kxsClient.isKillLeaderTrackerEnabled,
type: "toggle",
onChange: (value) => {
this.kxsClient.isKillLeaderTrackerEnabled = !this.kxsClient.isKillLeaderTrackerEnabled;
this.kxsClient.updateLocalStorage();
},
});
this.addOption(pluginsSection, {
label: `Friends Detector (separe with ',')`,
value: this.kxsClient.all_friends,
type: "input",
onChange: (value) => {
this.kxsClient.all_friends = value;
this.kxsClient.updateLocalStorage();
},
});
this.addOption(HUD, {
label: `Change Background`,
value: true,
type: "click",
onChange: () => {
const backgroundElement = document.getElementById("background");
if (!backgroundElement) {
alert("Element with id 'background' not found.");
return;
}
const choice = prompt("Enter '0' to default Kxs background, '1' to provide a URL or '2' to upload a local image:");
if (choice === "0") {
localStorage.removeItem("lastBackgroundUrl");
localStorage.removeItem("lastBackgroundFile");
localStorage.removeItem("lastBackgroundType");
localStorage.removeItem("lastBackgroundValue");
}
else if (choice === "1") {
const newBackgroundUrl = prompt("Enter the URL of the new background image:");
if (newBackgroundUrl) {
backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
this.kxsClient.saveBackgroundToLocalStorage(newBackgroundUrl);
alert("Background updated successfully!");
}
}
else if (choice === "2") {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "image/*";
fileInput.onchange = (event) => {
var _a, _b;
const file = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
backgroundElement.style.backgroundImage = `url(${reader.result})`;
this.kxsClient.saveBackgroundToLocalStorage(file);
alert("Background updated successfully!");
};
reader.readAsDataURL(file);
}
};
fileInput.click();
}
},
});
}
clearMenu() {
this.sections.forEach((section) => {
if (section.element) {
section.element.remove();
}
});
this.sections = [];
}
applyMenuStyles() {
Object.assign(this.menu.style, {
backgroundColor: "rgba(30, 30, 30, 0.95)",
padding: "15px",
borderRadius: "10px",
boxShadow: "0 4px 15px rgba(0, 0, 0, 0.7)",
zIndex: "10001",
width: "300px",
fontFamily: "Arial, sans-serif",
color: "#fff",
maxHeight: "500px",
overflowY: "auto",
position: "fixed",
top: "15%",
left: "10%",
cursor: "move",
display: "none",
});
}
createHeader() {
const title = document.createElement("h2");
title.textContent = "KxsClient alpha";
Object.assign(title.style, {
margin: "0 0 10px",
textAlign: "center",
fontSize: "18px",
color: "#FFAE00",
});
const subtitle = document.createElement("p");
subtitle.textContent = "reset with tab";
Object.assign(subtitle.style, {
margin: "0 0 10px",
textAlign: "center",
fontSize: "12px",
color: "#ccc",
});
this.menu.appendChild(title);
this.menu.appendChild(subtitle);
}
addSection(title) {
const section = {
title,
options: [],
};
const sectionElement = document.createElement("div");
sectionElement.className = "menu-section";
const sectionTitle = document.createElement("h3");
sectionTitle.textContent = title;
Object.assign(sectionTitle.style, {
margin: "15px 0 10px",
fontSize: "16px",
color: "#4CAF50",
});
sectionElement.appendChild(sectionTitle);
this.menu.appendChild(sectionElement);
// Stocker la référence à l'élément DOM
section.element = sectionElement;
this.sections.push(section);
return section;
}
addOption(section, option) {
section.options.push(option);
const optionDiv = document.createElement("div");
Object.assign(optionDiv.style, {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "8px",
padding: "4px",
borderRadius: "4px",
backgroundColor: "rgba(255, 255, 255, 0.1)",
});
const label = document.createElement("span");
label.textContent = option.label;
label.style.color = "#fff";
let valueElement = null;
switch (option.type) {
case "toggle":
valueElement = this.createToggleElement(option);
break;
case "input":
valueElement = this.createInputElement(option);
break;
case "click":
valueElement = this.createClickElement(option);
break;
}
optionDiv.appendChild(label);
optionDiv.appendChild(valueElement);
// Utiliser la référence stockée à l'élément de section
if (section.element) {
section.element.appendChild(optionDiv);
}
}
createToggleElement(option) {
const toggle = document.createElement("div");
toggle.style.cursor = "pointer";
toggle.style.color = option.value ? "#4CAF50" : "#ff4444";
toggle.textContent = String(option.value);
toggle.addEventListener("click", () => {
var _a;
const newValue = !option.value;
option.value = newValue;
toggle.textContent = String(newValue);
toggle.style.color = newValue ? "#4CAF50" : "#ff4444";
(_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, newValue);
});
return toggle;
}
createClickElement(option) {
const button = document.createElement("button");
button.textContent = option.label;
button.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
button.style.border = "none";
button.style.borderRadius = "3px";
button.style.color = "#FFAE00";
button.style.padding = "2px 5px";
button.style.cursor = "pointer";
button.style.fontSize = "12px";
button.addEventListener("click", () => {
var _a;
(_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, true);
});
return button;
}
createInputElement(option) {
const input = document.createElement("input");
input.type = "text";
input.value = String(option.value);
Object.assign(input.style, {
backgroundColor: "rgba(255, 255, 255, 0.1)",
border: "none",
borderRadius: "3px",
color: "#FFAE00",
padding: "2px 5px",
width: "60px",
textAlign: "right",
});
input.addEventListener("change", () => {
var _a;
option.value = input.value;
(_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, input.value);
});
return input;
}
addShiftListener() {
window.addEventListener("keydown", this.boundShiftListener);
}
addDragListeners() {
this.menu.addEventListener("mousedown", this.boundMouseDownListener);
window.addEventListener("mousemove", this.boundMouseMoveListener);
window.addEventListener("mouseup", this.boundMouseUpListener);
}
toggleMenuVisibility() {
this.isClientMenuVisible = !this.isClientMenuVisible;
this.kxsClient.nm.showNotification(this.isClientMenuVisible ? "Opening menu..." : "Closing menu...", "info", 1400);
this.menu.style.display = this.isClientMenuVisible ? "block" : "none";
}
destroy() {
// Remove event listeners
window.removeEventListener("keydown", this.boundShiftListener);
this.menu.removeEventListener("mousedown", this.boundMouseDownListener);
window.removeEventListener("mousemove", this.boundMouseMoveListener);
window.removeEventListener("mouseup", this.boundMouseUpListener);
// Remove all section elements and clear sections array
this.sections.forEach(section => {
if (section.element) {
// Remove all option elements within the section
const optionElements = section.element.querySelectorAll("div");
optionElements.forEach(element => {
// Remove event listeners from toggle and input elements
const interactive = element.querySelector("div, input");
if (interactive) {
interactive.replaceWith(interactive.cloneNode(true));
}
element.remove();
});
section.element.remove();
}
});
this.sections = [];
// Remove the menu from DOM
this.menu.remove();
// Reset instance variables
this.isClientMenuVisible = false;
this.isDragging = false;
this.dragOffset = { x: 0, y: 0 };
this.menu = null;
// Clear references
this.kxsClient = null;
this.boundShiftListener = null;
this.boundMouseDownListener = null;
this.boundMouseMoveListener = null;
this.boundMouseUpListener = null;
}
getMenuVisibility() {
return this.isClientMenuVisible;
}
}
;// ./src/ClientSecondaryMenuRework.ts
class KxsClientSecondaryMenu {
constructor(kxsClient) {
this.searchTerm = '';
this.shiftListener = (event) => {
if (event.key === "Shift" && event.location == 2) {
this.clearMenu();
this.toggleMenuVisibility();
this.loadOption();
// Ensure options are displayed after loading
this.filterOptions();
}
};
this.mouseMoveListener = (e) => {
if (this.isDragging) {
const x = e.clientX - this.dragOffset.x;
const y = e.clientY - this.dragOffset.y;
this.menu.style.transform = 'none';
this.menu.style.left = `${x}px`;
this.menu.style.top = `${y}px`;
}
};
this.mouseUpListener = () => {
this.isDragging = false;
this.menu.style.cursor = "grab";
};
this.kxsClient = kxsClient;
this.isClientMenuVisible = false;
this.isDragging = false;
this.dragOffset = { x: 0, y: 0 };
this.sections = [];
this.allOptions = [];
this.activeCategory = "ALL";
this.menu = document.createElement("div");
this.initMenu();
this.addShiftListener();
this.addDragListeners();
}
initMenu() {
this.menu.id = "kxsMenuIG";
this.applyMenuStyles();
this.createHeader();
this.createGridContainer();
document.body.appendChild(this.menu);
}
applyMenuStyles() {
Object.assign(this.menu.style, {
backgroundColor: "rgba(17, 24, 39, 0.95)",
padding: "20px",
borderRadius: "12px",
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.8)",
zIndex: "10001",
width: "800px",
fontFamily: "'Segoe UI', Arial, sans-serif",
color: "#fff",
maxHeight: "80vh",
overflowY: "auto",
overflowX: "hidden", // Prevent horizontal scrolling
position: "fixed",
top: "10%",
left: "50%",
transform: "translateX(-50%)",
display: "none",
boxSizing: "border-box", // Include padding in width calculation
});
}
createHeader() {
const header = document.createElement("div");
header.style.marginBottom = "20px";
header.innerHTML = `