// ==UserScript==
// @name Counter-Strike 2 Script
// @namespace https://github.com/Citrinate
// @author Citrinate
// @description Manage your CS2 storage units and inspect items
// @license Apache-2.0
// @version 1.0.0.2
// @match https://steamcommunity.com/id/*/inventory*
// @match https://steamcommunity.com/profiles/*/inventory*
// @match https://steamcommunity.com/market/listings/*
// @connect localhost
// @connect 127.0.0.1
// @connect *
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @grant unsafeWindow
// @homepageURL https://github.com/Citrinate/CS2Script
// @supportURL https://github.com/Citrinate/CS2Script/issues
// ==/UserScript==
(() => {
// src/core/settings.js
var SETTING_ASF_SERVER = "SETTING_ASF_SERVER";
var SETTING_ASF_PORT = "SETTING_ASF_PORT";
var SETTING_ASF_PASSWORD = "SETTING_ASF_PASSWORD";
var SETTING_INSPECT_ITEMS = "SETTING_INSPECT_ITEMS";
var SETTING_INSPECT_CACHE_TIME_HOURS = "SETTING_INSPECT_CACHE_TIME_HOURS";
var SETTING_INTERFACE_AUTOSTOP_MINUTES = "SETTING_INTERFACE_AUTOSTOP_MINUTES";
var DEFAULT_SETTINGS = {
SETTING_ASF_SERVER: "http://localhost",
SETTING_ASF_PORT: "1242",
SETTING_ASF_PASSWORD: "",
SETTING_INSPECT_ITEMS: true,
SETTING_INSPECT_CACHE_TIME_HOURS: -1,
SETTING_INTERFACE_AUTOSTOP_MINUTES: 15
};
function GetSetting(name) {
return GM_getValue(name, DEFAULT_SETTINGS[name]);
}
function SetSetting(name, value) {
GM_setValue(name, value);
}
// src/core/asf.js
var asf_default = {
Send: async function(operation, path, http_method, bot, data) {
let payload = null;
let parameters = "";
if (data) {
if (http_method === "GET") {
parameters = "?" + new URLSearchParams(data).toString();
} else if (http_method === "POST") {
payload = JSON.stringify(data);
}
}
const xhrResponse = await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: `${GetSetting(SETTING_ASF_SERVER)}:${GetSetting(SETTING_ASF_PORT)}/Api/${operation}/${bot}/${path}${parameters}`,
method: http_method,
data: payload,
responseType: "json",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authentication": GetSetting(SETTING_ASF_PASSWORD)
},
onload: (response) => {
if (typeof response.response === "string") {
try {
response.response = JSON.parse(response.response);
} catch {
;
}
}
resolve(response);
},
onerror: (e) => {
const error = new Error(`(${e.status}) Request error from /Api/${operation}/${path}`);
error.code = e.status;
reject(error);
},
ontimeout: (e) => {
const error = new Error(`(${e.status}) Request timed out on /Api/${operation}/${path}`);
error.code = e.status;
reject(error);
}
});
});
if (xhrResponse.status === 401) {
const error = new Error(`(401) Missing or incorrect ASF IPC password. Please check your settings and verify your ASF IPC password.`);
error.code = xhrResponse.status;
error.response = xhrResponse.response;
throw error;
}
if (xhrResponse.status === 403) {
let errorMessage;
if (!GetSetting(SETTING_ASF_SERVER).includes("127.0.0.1") && !GetSetting(SETTING_ASF_SERVER).toLowerCase().includes("localhost") && !GetSetting(SETTING_ASF_PASSWORD)) {
errorMessage = "(403) You must use an ASF IPC password when connecting to ASF remotely.";
} else {
errorMessage = "(403) The ASF IPC password you entered was incorrect. Please wait or restart ASF, and then try again.";
}
const error = new Error(errorMessage);
error.code = xhrResponse.status;
error.response = xhrResponse.response;
throw error;
}
if (!xhrResponse.response || xhrResponse.status !== 200) {
let errorMessage = `(${xhrResponse.status}) ASF request error from /Api/${operation}/${path}`;
if (xhrResponse.response?.Message) {
errorMessage += `: ${xhrResponse.response?.Message}`;
} else if (xhrResponse.status >= 500) {
errorMessage += `: Please check your ASF logs for errors`;
}
const error = new Error(errorMessage);
error.code = xhrResponse.status;
error.response = xhrResponse.response;
throw error;
}
if (!xhrResponse.response.Success) {
let errorMessage = `(${xhrResponse.status}) ASF response error from /Api/${operation}/${path}`;
if (xhrResponse.response.Message) {
errorMessage += `: ${xhrResponse.response.Message}`;
}
const error = new Error(errorMessage);
error.code = xhrResponse.status;
error.response = xhrResponse.response;
throw error;
}
return xhrResponse.response.Result ?? xhrResponse.response;
},
GetBot: async function(steamID, includePluginStatus = true) {
if (steamID === false) {
return;
}
const bots = await this.Send("Bot", "", "GET", "ASF");
let pluginStatus;
if (includePluginStatus) {
pluginStatus = await this.GetPluginStatus();
}
const mergedBots = Object.fromEntries(
Object.entries(bots).map(([key, value]) => [
key,
{
ASF: value,
Plugin: pluginStatus?.[key]
}
])
);
if (steamID) {
return Object.values(mergedBots).find((bot) => bot.ASF.SteamID == steamID);
}
return mergedBots;
},
GetPluginStatus: async function(botName) {
const bots = await this.Send("CS2Interface", "Status", "GET", "ASF", { "refreshAutoStop": "true" });
if (botName) {
return bots[botName];
}
return bots;
}
};
// src/cs2/constants.js
var CS2_APPID = 730;
var INVENTORY_ITEM_LIMIT = 1e3;
var STORAGE_UNIT_ITEM_LIMIT = 1e3;
var STICKER_MAX_COUNT = 5;
var KEYCHAIN_MAX_COUNT = 1;
var SEED_RANGE = { min: 0, max: 1e5 };
var FLOAT_RANGE = { min: 0, max: 1 };
var WEARS = [
{ min: 0, max: 0.07, name: "FN", nameLong: "Factory New" },
{ min: 0.07, max: 0.15, name: "MW", nameLong: "Minimum Wear" },
{ min: 0.15, max: 0.38, name: "FT", nameLong: "Field-Tested" },
{ min: 0.38, max: 0.45, name: "WW", nameLong: "Well-Worn" },
{ min: 0.45, max: 1, name: "BS", nameLong: "Battle-Scarred" }
];
// src/utils/cache.js
var Cache = class {
static #dbName = "cs2_script";
static #storeName = "kvp";
static #version = 1;
static #initPromise = null;
static #keyName = "DB_ENCRYPTION_KEY";
static #key = null;
static async #Init() {
if (this.#initPromise) {
return this.#initPromise;
}
this.#initPromise = new Promise((resolve, reject) => {
const request = indexedDB.open(this.#dbName, this.#version);
request.onupgradeneeded = () => {
const db = request.result;
if (!db.objectStoreNames.contains(this.#storeName)) {
db.createObjectStore(this.#storeName);
}
};
request.onsuccess = async () => {
const db = request.result;
const testKey = "cache_validity_test";
const testValue = 42;
const storedKey = GM_getValue(this.#keyName, null);
if (storedKey) {
try {
const raw = Uint8Array.from(atob(storedKey), (c) => c.charCodeAt(0));
this.#key = await crypto.subtle.importKey("raw", raw, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
await this.#Encrypt({ test: true });
if (await this.#Get(db, testKey) !== testValue) {
throw new Error("Cache failed to validate");
}
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e, new Error("Clearing cache"));
this.#key = null;
}
}
if (!this.#key) {
const rawKey = crypto.getRandomValues(new Uint8Array(32));
this.#key = await crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
GM_setValue(this.#keyName, btoa(String.fromCharCode(...rawKey)));
await this.#Clear(db);
}
await this.#Set(db, testKey, testValue);
resolve(db);
};
request.onerror = () => {
reject(request.error);
};
});
return this.#initPromise;
}
static async #Encrypt(data) {
const encoded = new TextEncoder().encode(JSON.stringify(data));
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, this.#key, encoded);
const combined = new Uint8Array(iv.byteLength + ciphertext.byteLength);
combined.set(iv, 0);
combined.set(new Uint8Array(ciphertext), iv.byteLength);
return combined.buffer;
}
static async #decrypt(buffer) {
const combined = new Uint8Array(buffer);
const iv = combined.slice(0, 12);
const ciphertext = combined.slice(12);
const encoded = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, this.#key, ciphertext);
return JSON.parse(new TextDecoder().decode(encoded));
}
static async #Clear(db) {
return new Promise((resolve, reject) => {
const tx = db.transaction(this.#storeName, "readwrite");
const store = tx.objectStore(this.#storeName);
const req = store.clear();
req.onsuccess = () => {
resolve();
};
req.onerror = () => {
reject(req.error);
};
});
}
static async #Get(db, key, defaultValue = null) {
return new Promise((resolve, reject) => {
const tx = db.transaction(this.#storeName, "readonly");
const store = tx.objectStore(this.#storeName);
const req = store.get(key);
req.onsuccess = async () => {
if (!req.result) {
resolve(defaultValue);
return;
}
try {
resolve(await this.#decrypt(req.result));
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
resolve(defaultValue);
}
};
req.onerror = () => {
reject(req.error);
};
});
}
static async #Set(db, key, value) {
const encrypted = await this.#Encrypt(value);
return new Promise((resolve, reject) => {
const tx = db.transaction(this.#storeName, "readwrite");
const store = tx.objectStore(this.#storeName);
const req = store.put(encrypted, key);
req.onsuccess = () => {
resolve();
};
req.onerror = () => {
reject(req.error);
};
});
}
static async GetValue(key, defaultValue = null) {
return this.#Get(await this.#Init(), key, defaultValue);
}
static async SetValue(key, value) {
return this.#Set(await this.#Init(), key, value);
}
};
// src/utils/helpers.js
function Request(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(new Error(`Request failed with status: ${xhr.status}`));
}
};
xhr.onerror = function() {
reject(new Error("Network error occurred"));
};
xhr.ontimeout = function() {
reject(new Error("Request timed out"));
};
xhr.send();
});
}
function CreateElement(tag, options) {
const el = document.createElement(tag);
if (options) {
for (const [key, value] of Object.entries(options)) {
if (key === "class") {
el.className = value;
} else if (key === "html") {
el.innerHTML = value;
} else if (key === "text") {
el.innerText = value;
} else if (key === "hide" && value) {
el.hide();
} else if (key === "style") {
Object.assign(el.style, value);
} else if (key === "vars") {
for (const [varName, varValue] of Object.entries(value)) {
el.style.setProperty(`--${varName}`, varValue);
}
} else if (key === "dataset") {
Object.assign(el.dataset, value);
} else if (key === "disabled") {
el.disabled = value;
} else if (key === "selected") {
el.selected = value;
} else if (key.startsWith("on") && typeof value === "function") {
el.addEventListener(key.slice(2).toLowerCase(), value);
} else if (key === "htmlChildren") {
for (const child of value) {
if (!child) {
continue;
}
el.insertAdjacentHTML("beforeend", child);
}
} else if (key === "children") {
for (const child of value) {
if (!child) {
continue;
}
el.append(child instanceof Node ? child : document.createTextNode(child));
}
} else {
el.setAttribute(key, value);
}
}
}
return el;
}
function CreateCachedAsyncFunction(asyncFunction) {
let cache = null;
let inProgress = null;
const wrapped = async () => {
if (cache !== null) {
return cache;
}
if (inProgress) {
return inProgress;
}
inProgress = asyncFunction().then((result) => {
cache = result;
return result;
});
return inProgress;
};
wrapped.willReturnImmediately = () => {
return cache !== null;
};
return wrapped;
}
function BindTooltip(element, text) {
if (element.unbindTooltip) {
element.unbindTooltip();
}
const tooltip = CreateElement("div", {
class: "cs2s_tooltip",
text
});
let fadeOutAnimation = null;
element.classList.add(`cs2s_has_tooltip`);
function onMouseEnter() {
if (fadeOutAnimation) {
fadeOutAnimation.cancel();
fadeOutAnimation = null;
}
const rect = element.getBoundingClientRect();
document.body.appendChild(tooltip);
void tooltip.offsetWidth;
tooltip.style.top = `${rect.bottom + window.scrollY + 8}px`;
tooltip.style.left = `${rect.left + window.scrollX + rect.width / 2 - tooltip.offsetWidth / 2}px`;
Fade(tooltip, { from: 0, to: 1, duration: 200 });
}
function onMouseLeave() {
fadeOutAnimation = Fade(tooltip, {
from: 1,
to: 0,
duration: 200,
onfinish: () => {
tooltip.isConnected && tooltip.remove();
}
});
}
element.addEventListener("mouseenter", onMouseEnter);
element.addEventListener("mouseleave", onMouseLeave);
element.unbindTooltip = () => {
element.removeEventListener("mouseenter", onMouseEnter);
element.removeEventListener("mouseleave", onMouseLeave);
element.classList.remove(`cs2s_has_tooltip`);
element.unbindTooltip = null;
tooltip.isConnected && tooltip.remove();
};
return tooltip;
}
function Fade(element, options) {
const to = options.to ?? 1;
if (typeof options.from !== "undefined") {
element.style.opacity = options.from;
}
const animation = element.animate({
opacity: to
}, {
duration: options.duration ?? 250,
easing: "ease",
fill: "forwards"
});
if (typeof options.onfinish === "function") {
animation.onfinish = () => {
options.onfinish();
};
}
return animation;
}
function Sleep(milliseconds) {
if (milliseconds <= 0) {
return Promise.resolve();
}
return new Promise((resolve) => {
setTimeout(resolve, milliseconds);
});
}
function Random(min, max) {
return Math.random() * (max - min) + min;
}
// src/cs2/items/inventory.js
var Inventory = class _Inventory {
items;
storedItems;
loadedFromCache;
static iconURLsCacheID = "icon_urls";
static iconURLs = null;
constructor(items, loadedFromCache = false) {
this.items = items;
this.storedItems = [];
this.loadedFromCache = loadedFromCache;
}
async LoadCrateContents(progressCallback) {
_Inventory.iconURLs = await Cache.GetValue(_Inventory.iconURLsCacheID, {});
let cratesOpened = 0;
const numCrates = this.items.filter((item) => item.iteminfo.def_index === 1201).length;
progressCallback(`Loading Storage Unit Contents (${cratesOpened}/${numCrates})`, cratesOpened / numCrates);
for (const item of this.items) {
if (item.iteminfo.def_index == 1201) {
const storedItems = await this.#OpenCrate(item);
if (storedItems) {
this.storedItems = this.storedItems.concat(storedItems);
}
cratesOpened++;
progressCallback(`Loading Storage Unit Contents (${cratesOpened}/${numCrates})`, cratesOpened / numCrates);
}
if (!_Inventory.iconURLs[item.full_name]) {
const asset = unsafeWindow.g_rgAppContextData[CS2_APPID].rgContexts[2].inventory.m_rgAssets[item.iteminfo.id];
if (asset) {
_Inventory.iconURLs[item.full_name] = asset.description.icon_url;
}
}
}
Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
const itemsToGetIconsFor = /* @__PURE__ */ new Set();
const commodityItemsToGetIconsFor = /* @__PURE__ */ new Set();
for (const item of [...this.items, ...this.storedItems]) {
item.id = item.iteminfo.id;
item.name = !!item.wear_name && item.full_name.includes(item.wear_name) ? item.full_name.slice(0, -(item.wear_name.length + 3)) : item.full_name;
item.name_normalized = item.name.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
item.collection_name = item.set_name ?? item.crate_name?.replace(/( Autograph Capsule)$/, " Autographs").replace(/( Capsule)$/, "");
item.collection = item.collection_name?.replace(/^(The )/, "").replace(/( Collection)$/, "").replace(/^(Operation )/, "").replace(/( Autographs)$/, "");
item.rarity = item.collection || item.iteminfo.rarity > 1 ? item.iteminfo.rarity : void 0;
item.seed = item.attributes["set item texture seed"] ? Math.floor(item.attributes["set item texture seed"]) : item.attributes["keychain slot 0 seed"];
if (item.iteminfo.quality == 3) {
item.quality = 3 + Number(item.stattrak === true);
} else if (item.iteminfo.quality == 12) {
item.quality = 2;
} else {
item.quality = Number(item.stattrak === true) * 2;
}
if (item.casket_id) {
item.casket_name = this.items.find((x) => x.iteminfo.id == item.casket_id)?.attributes["custom name attr"] ?? item.casket_id;
}
if (item.stickers) {
for (const sticker of Object.values(item.stickers)) {
if (_Inventory.iconURLs[sticker.full_name] || _Inventory.iconURLs[sticker.full_name] === null) {
continue;
}
commodityItemsToGetIconsFor.add(sticker.full_name);
}
}
if (item.keychains) {
for (const keychain of Object.values(item.keychains)) {
if (_Inventory.iconURLs[keychain.full_name] || _Inventory.iconURLs[keychain.full_name] === null) {
continue;
}
itemsToGetIconsFor.add(keychain.full_name);
}
}
if (!item.moveable || _Inventory.iconURLs[item.full_name] || _Inventory.iconURLs[item.full_name] === null) {
continue;
}
if (item.commodity) {
commodityItemsToGetIconsFor.add(item.full_name);
} else {
itemsToGetIconsFor.add(item.full_name);
}
}
await this.#FetchCommodityIcons(commodityItemsToGetIconsFor, progressCallback);
await this.#FetchIcons(/* @__PURE__ */ new Set([...itemsToGetIconsFor, ...commodityItemsToGetIconsFor]), progressCallback);
}
async #OpenCrate(item) {
if (item.iteminfo.def_index != 1201) {
return;
}
const assetID = item.iteminfo.id;
const attributes = item.attributes;
const cache_id = `crate_${assetID}`;
const cache = await Cache.GetValue(cache_id, null);
if (cache) {
if (this.loadedFromCache || cache.attributes["modification date"] == attributes["modification date"]) {
return cache.items;
}
}
if (this.loadedFromCache) {
const error2 = new Error(`Failed to load crate ${assetID} from cache`);
error2.OPERATION_ERROR = OPERATION_ERROR.INTERFACE_NOT_CONNECTED;
throw error2;
}
for (let attempt = 0; attempt < 3; attempt++) {
try {
const storedItems = await asf_default.Send("CS2Interface", `GetCrateContents/${assetID}`, "GET", script_default.Bot.ASF.BotName);
if (!storedItems) {
break;
}
const crate = {
attributes,
items: storedItems
};
Cache.SetValue(cache_id, crate);
await Sleep(2e3);
return storedItems;
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
if (e.code === 504) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error("Timed out while opening storage unit, reconnecting to interface"));
if (!await script_default.RestartInterface({ showProgress: false, errorLevel: ERROR_LEVEL.LOW })) {
break;
}
}
}
}
const error = new Error(`Failed to open crate ${assetID}`);
error.OPERATION_ERROR = OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD;
throw error;
}
async #FetchIcons(hashes, progressCallback) {
if (hashes.size == 0) {
return;
}
const iconsToFetch = hashes.size;
let iconsFetched = 0;
progressCallback("Fetching Item Icons", 0);
for (const hash of hashes) {
let success = false;
const url = `${window.location.origin}/market/listings/${CS2_APPID}/${encodeURIComponent(hash)}`;
for (let attempt = 0; attempt < 5; attempt++) {
try {
const listingPage = await Request(url);
if (listingPage.includes("g_rgAssets = []")) {
if (!listingPage.includes("Market_LoadOrderSpread")) {
success = true;
_Inventory.iconURLs[hash] = null;
hashes.delete(hash);
Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
continue;
}
await Sleep(Random(1e3, 2e3));
continue;
}
const matches = listingPage.match(/g_rgAssets\s*=\s*({.*?});/);
if (!matches) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to find g_rgAssets at ${url}`));
console.log(listingPage);
return;
}
if (matches.length > 1) {
let assets;
try {
assets = JSON.parse(matches[1]);
} catch {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to parse g_rgAssets at ${url}`));
console.log(matches);
return;
}
const asset = Object.values(assets?.[CS2_APPID]?.[2] ?? assets?.[CS2_APPID]?.[0] ?? {})?.[0];
if (asset?.icon_url) {
success = true;
_Inventory.iconURLs[hash] = asset?.icon_url;
hashes.delete(hash);
Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
}
}
break;
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
await Sleep(Random(1e3, 2e3));
}
}
if (!success) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to get item icon at ${url}`));
}
iconsFetched++;
progressCallback(`Fetching Item Icons (${iconsFetched}/${iconsToFetch})`, iconsFetched / iconsToFetch);
}
}
async #FetchCommodityIcons(hashes, progressCallback) {
if (hashes.size == 0) {
return;
}
const itemLimit = 25;
const chunkedHashes = Array.from(
{ length: Math.ceil(hashes.size / itemLimit) },
(_, index) => [...hashes].slice(index * itemLimit, (index + 1) * itemLimit)
);
const iconsToFetch = hashes.size;
let iconsFetched = 0;
progressCallback("Fetching Commodity Item Icons", 0);
for (const chunk of chunkedHashes) {
const query = new URLSearchParams({
appid: String(CS2_APPID),
contextid: "2"
});
for (const hash of chunk) {
query.append("items[]", hash);
}
const url = `${window.location.origin}/market/multisell?${query.toString()}`;
let success = false;
for (let attempt = 0; attempt < 5; attempt++) {
try {
const multiSellPage = await Request(url);
if (multiSellPage.includes("error_ctn")) {
continue;
}
const matches = multiSellPage.match(/g_rgAssets\s*=\s*({.*?});/);
if (!matches) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to find g_rgAssets at ${url}`));
console.log(multiSellPage);
return;
}
if (matches.length > 1) {
let assets;
try {
assets = JSON.parse(matches[1]);
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, e, new Error(`Failed to parse g_rgAssets at ${url}`));
console.log(matches);
return;
}
for (const asset of Object.values(assets?.[CS2_APPID]?.[2])) {
for (const hash of chunk) {
if (asset?.description?.market_hash_name == hash && asset?.description?.icon_url) {
_Inventory.iconURLs[hash] = asset.description.icon_url;
hashes.delete(hash);
break;
}
}
}
success = true;
Cache.SetValue(_Inventory.iconURLsCacheID, _Inventory.iconURLs);
}
break;
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
await Sleep(Random(1e3, 2e3));
}
}
if (!success) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, new Error(`Failed to get item icons at ${url}`));
}
iconsFetched += chunk.length;
progressCallback(`Fetching Commodity Item Icons (${iconsFetched}/${iconsToFetch})`, iconsFetched / iconsToFetch);
}
}
async StoreItem(asset, crateAsset) {
await asf_default.Send("CS2Interface", `StoreItem/${crateAsset.iteminfo.id}/${asset.iteminfo.id}`, "GET", script_default.Bot.ASF.BotName);
}
async RetrieveItem(asset) {
await asf_default.Send("CS2Interface", `RetrieveItem/${asset.casket_id}/${asset.iteminfo.id}`, "GET", script_default.Bot.ASF.BotName);
}
};
// src/components/popup.js
var Popup = class _Popup {
static #numPopups = 0;
#popoverMode;
#onopen;
#onclose;
#fade;
#popupContainer;
#background;
#visible = false;
constructor(options) {
this.#popoverMode = options.popoverMode ?? false;
this.#onopen = options.onopen ?? false;
this.#onclose = options.onclose ?? false;
this.#fade = options.fade ?? true;
_Popup.#numPopups++;
const title = CreateElement("div", {
class: "cs2s_popup_title",
text: options.title ?? "",
children: options.titleChildren ?? []
});
const simpleMode = options.simpleMode ?? false;
const disableClose = options.disableClose ?? false;
const closeButton = !simpleMode && CreateElement("div", {
class: "cs2s_popup_close_button",
onclick: () => {
this.Hide();
}
});
const popupBody = CreateElement("div", {
class: `cs2s_popup_body`,
children: [
!disableClose && closeButton,
title,
...options.body ?? []
]
});
if (simpleMode) {
popupBody.classList.add("cs2s_popup_body_simple");
}
if (this.#popoverMode) {
popupBody.classList.add("cs2s_popup_body_popover");
}
this.#background = CreateElement("div", {
class: "cs2s_popup_background",
style: {
zIndex: 1e3 + _Popup.#numPopups
}
});
this.#popupContainer = CreateElement("div", {
class: "cs2s_popup_container",
style: {
zIndex: 1e3 + _Popup.#numPopups
},
children: [
popupBody
]
});
if (!disableClose) {
this.#popupContainer.addEventListener("dblclick", (event) => {
const box = popupBody.getBoundingClientRect();
const style = getComputedStyle(popupBody);
if (event.clientY < box.top || event.clientX < box.left || event.clientY > box.bottom + parseInt(style.marginBottom) || event.clientX > box.right) {
this.Hide();
}
});
document.addEventListener("keydown", (event) => {
if (!this.#visible) {
return;
}
if (event.key === "Escape") {
event.preventDefault();
this.Hide();
}
});
}
}
Show() {
if (this.#visible) {
return;
}
this.#visible = true;
if (typeof this.#onopen === "function") {
this.#onopen();
}
unsafeWindow.document.body.append(this.#background, this.#popupContainer);
if (!this.#popoverMode) {
if (this.#fade) {
Fade(this.#background, {
from: 0,
to: getComputedStyle(this.#background).opacity
});
}
unsafeWindow.document.body.classList.add("cs2s_popup_opened");
}
}
Hide() {
if (!this.#visible) {
return;
}
this.#visible = false;
if (typeof this.#onclose === "function") {
this.#onclose();
}
if (this.#fade) {
Fade(this.#background, {
from: getComputedStyle(this.#background).opacity,
to: 0,
onfinish: () => {
this.#background.isConnected && this.#background.remove();
}
});
} else {
this.#background.isConnected && this.#background.remove();
}
this.#popupContainer.isConnected && this.#popupContainer.remove();
if (!this.#popoverMode) {
unsafeWindow.document.body.classList.remove("cs2s_popup_opened");
}
}
};
// src/core/script.js
var OPERATION_ERROR = {
INTERFACE_NOT_CONNECTED: 0,
INVENTORY_FAILED_TO_LOAD: 1
};
var ERROR_LEVEL = {
HIGH: 0,
MEDIUM: 1,
LOW: 2
};
var Script = class {
Bot;
AccountsConnected = 0;
#inventory = null;
#statusUpdateListeners = [];
#navigationButton;
#navigationStatus;
#navigationMenu;
#errorTableBody;
constructor() {
const globalNavigation = unsafeWindow.document.getElementById(`account_dropdown`);
if (!globalNavigation) {
return;
}
this.#navigationStatus = CreateElement("span", {
class: "account_name",
text: "???"
});
this.#navigationButton = CreateElement("span", {
class: "popup_menu_item cs2s_navigation_popup_menu_item",
onmouseenter: () => {
this.#ShowNavigationMenu();
},
onmouseleave: () => {
this.#HideNavigationMenu();
},
children: [
CreateElement("span", {
html: (
/*html*/
`
<span class="cs2s_navigation_icon">
<svg
width="173.27321"
height="42.757812"
viewBox="0 0 173.27321 42.757812"
fill="currentColor"
preserveAspectRatio="xMinYMin">
<path
d="m 79.808179,0 c -6.1207,1e-7 -11.646256,3.6370293 -14.035156,9.2363278 l -1.595704,3.7402352 -1.140625,2.667969 c -2.1334,4.9951 1.555679,10.533203 7.017579,10.533203 h 2.800781 22.875 l -2.935547,6.835937 H 58.10896 c -1.5238,0 -2.898,0.901969 -3.5,2.292969 l -3.222656,7.451172 h 39.164062 c 6.105704,0 11.625494,-3.621172 14.021494,-9.201172 l 2.87109,-6.683594 c 2.147,-4.9966 -1.54372,-10.548828 -7.01172,-10.548828 H 74.780835 l 1.884766,-4.402344 -4.792969,-2.3105472 h 40.464848 c 1.528,0 2.91081,-0.906287 3.50781,-2.304687 L 118.97029,0 Z M 24.497632,0.00195 C 18.410132,4.7e-4 12.905279,3.5995237 10.495679,9.1542936 L 0.6167727,32.216794 c -2.139226,4.9966 1.5490919,10.541016 7.0136719,10.541016 H 39.798413 c 1.5267,0 2.904906,-0.905381 3.503906,-2.300781 l 3.197266,-7.441404 H 12.644116 L 21.696851,11.923828 16.780835,9.6152348 h 37.253906 c 1.5267,0 2.904907,-0.905482 3.503906,-2.300782 L 60.679273,0.0058594 Z M 127.8824,0.00976 123.79451,9.6191351 h 37.17188 l -2.85157,6.7109369 h -27.21289 c -6.0365,0 -11.49792,3.620914 -13.86914,9.197266 l -0.0742,0.175781 -7.24804,17.052735 h 49.26758 l 1.89843,-4.466797 v -0.002 l 0.0742,-0.173828 v -0.01367 c 0.88057,-2.42168 -0.94013,-5.083985 -3.54101,-5.083985 h -31.46289 l 2.90625,-6.835937 h 32.1914 0.15039 0.01 c 2.95431,-0.06268 5.61224,-1.859402 6.77539,-4.597656 l 0.0742,-0.175782 4.61328,-10.851562 C 174.77935,5.5862411 171.10481,0.0097657 165.73201,0.0097657 Z" />
</svg>
</span>
`
)
}),
"CS2Script: ",
this.#navigationStatus
]
});
globalNavigation.children[0].append(this.#navigationButton);
GM_registerMenuCommand("Set ASF IPC Password", () => {
const password = prompt("Enter ASF IPC Password", GetSetting(SETTING_ASF_PASSWORD));
if (password !== null) {
SetSetting(SETTING_ASF_PASSWORD, password);
window.location.reload();
}
});
}
async #UpdateConnectionStatus() {
try {
const status = await asf_default.GetBot();
if (this.Bot) {
const oldBot = this.Bot;
this.Bot = status[this.Bot.ASF.BotName];
for (const listener of this.#statusUpdateListeners) {
listener(this.Bot, oldBot);
}
}
const currentAccountConnected = this.Bot && status[this.Bot.ASF.BotName].Plugin?.Connected;
const numOtherAccountsConnected = Object.values(status).filter((x) => x.Plugin?.Connected).length - currentAccountConnected;
const numOtherAccounts = Object.values(status).length - Number(this.Bot !== null);
this.AccountsConnected = currentAccountConnected ? numOtherAccountsConnected + 1 : numOtherAccountsConnected;
if (!this.#navigationStatus.tooltip) {
this.#navigationStatus.tooltip = BindTooltip(this.#navigationStatus, "");
}
this.#navigationStatus.innerText = currentAccountConnected ? "1" : "0";
this.#navigationStatus.tooltip.innerHTML = "Interface status for this account: ";
if (currentAccountConnected) {
this.#navigationStatus.tooltip.innerHTML += "<strong>Connected</strong>";
} else {
this.#navigationStatus.tooltip.innerHTML += "<strong>Not Connected</strong>";
}
if (numOtherAccounts > 0) {
this.#navigationStatus.innerText += ` + ${numOtherAccountsConnected}`;
this.#navigationStatus.tooltip.innerHTML += `<br>Interface is connected on <strong>${numOtherAccountsConnected}/${numOtherAccounts}</strong> other accounts`;
}
} catch (e) {
this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
}
}
AddStatusUpdateListener(listener) {
this.#statusUpdateListeners.push(listener);
}
RemovetatusUpdateListener(listener) {
this.#statusUpdateListeners = this.#statusUpdateListeners.filter((x) => x !== listener);
}
#ShowNavigationMenu(fade = true) {
if (this.#navigationMenu && this.#navigationMenu.isConnected) {
if (this.#navigationMenu.fade) {
this.#navigationMenu.fade.cancel();
this.#navigationMenu.fade = null;
}
Fade(this.#navigationMenu, {
to: 1,
duration: 200
});
return;
}
const errorButton = CreateElement("a", {
class: "popup_menu_item",
text: "View Errors",
onclick: () => {
unsafeWindow.document.body.click();
this.ShowErrors();
}
});
if (this.#navigationButton.classList.contains("cs2s_navigation_status_error_glow")) {
errorButton.classList.add("cs2s_navigation_status_error_glow");
}
const botConnected = this.Bot?.Plugin?.Connected;
const interfaceToggleButton = CreateElement("a", {
class: "popup_menu_item",
text: !botConnected ? "Start Interface" : "Stop Interface",
onclick: () => {
unsafeWindow.document.body.click();
if (!botConnected) {
this.StartInterface();
} else {
this.StopInterface();
}
}
});
const settingsButton = CreateElement("a", {
class: "popup_menu_item",
text: "Settings",
onclick: () => {
unsafeWindow.document.body.click();
this.ShowSettings();
}
});
this.#navigationMenu = CreateElement("div", {
class: "popup_block_new",
children: [
CreateElement("div", {
class: "popup_body popup_menu",
children: [
interfaceToggleButton,
settingsButton,
this.#errorTableBody && errorButton
]
})
]
});
this.#navigationButton.append(this.#navigationMenu);
this.#navigationMenu.style.top = `${this.#navigationButton.offsetTop}px`;
this.#navigationMenu.style.left = `-${this.#navigationMenu.offsetWidth}px`;
if (fade) {
Fade(this.#navigationMenu, {
from: 0,
to: 1,
duration: 200
});
}
}
#HideNavigationMenu() {
if (!this.#navigationMenu) {
return;
}
this.#navigationMenu.fade = Fade(this.#navigationMenu, {
to: 0,
duration: 200,
onfinish: () => {
this.#navigationMenu.isConnected && this.#navigationMenu.remove();
}
});
}
async VerifyConnection() {
try {
await asf_default.GetBot(null, false);
} catch (e) {
this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e, new Error('ArchiSteamFarm is not running or cannot be reached. Please verify that ASF is running. Under "Settings", verify that your ASF server, port, and password settings are all correct.'));
return false;
}
try {
await asf_default.GetPluginStatus();
} catch (e) {
this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e, new Error("CS2 Interface plugin is not installed"));
return false;
}
try {
const bot = await asf_default.GetBot(unsafeWindow.g_steamID);
if (!bot) {
throw new Error("ASF bot for this account was not found. If ASF was recently started, please wait until your bots come online and then reload the page.");
}
this.Bot = bot;
} catch (e) {
this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return false;
}
this.#UpdateConnectionStatus();
setInterval(() => {
if (unsafeWindow.document.visibilityState === "hidden") {
return;
}
this.#UpdateConnectionStatus();
}, 1e3);
return true;
}
ShowError(options, ...errors) {
if (!this.#errorTableBody) {
this.#errorTableBody = CreateElement("tbody");
}
for (const error of errors) {
console.log(error);
this.#errorTableBody.prepend(
CreateElement("tr", {
children: [
CreateElement("td", {
text: (/* @__PURE__ */ new Date()).toLocaleString()
}),
CreateElement("td", {
text: options.level == ERROR_LEVEL.HIGH ? "High" : options.level == ERROR_LEVEL.MEDIUM ? "Medium" : "Low"
}),
CreateElement("td", {
text: error.message
})
]
})
);
}
if (this.#errorTableBody.isConnected) {
return;
}
if (options.level === ERROR_LEVEL.HIGH) {
const popup = new Popup({
title: "Counter-Strike 2 Script Error",
simpleMode: true,
popoverMode: true,
fade: false,
body: [
CreateElement("div", {
class: "cs2s_action_body",
children: [
CreateElement("div", {
class: "cs2s_action_message_tall cs2s_action_multi_message",
children: [
...errors.map(
(error) => CreateElement("div", {
class: "cs2s_action_message",
text: error.message
})
)
]
}),
CreateElement("div", {
class: "cs2s_action_buttons",
children: [
CreateElement("div", {
class: "cs2s_grey_long_button",
text: "Close",
onclick: () => {
popup.Hide();
}
})
]
})
]
})
]
});
popup.Show();
} else if (options.level === ERROR_LEVEL.MEDIUM) {
const globalNavigationButton = unsafeWindow.document.getElementById(`account_pulldown`);
this.#navigationButton.classList.add("cs2s_navigation_status_error_glow");
globalNavigationButton && globalNavigationButton.classList.add("cs2s_navigation_status_error_pulse");
}
}
ShowErrors() {
const globalNavigationButton = unsafeWindow.document.getElementById(`account_pulldown`);
this.#navigationButton.classList.remove("cs2s_navigation_status_error_glow");
globalNavigationButton && globalNavigationButton.classList.remove("cs2s_navigation_status_error_pulse");
const popup = new Popup({
title: "Counter-Strike 2 Script Errors",
body: [
CreateElement("div", {
text: "More detailed information can be found in your browser's developer console",
style: {
padding: "0px 0px 16px 16px",
fontStyle: "italic"
}
}),
CreateElement("div", {
class: "cs2s_table_container cs2s_error_table_container",
children: [
CreateElement("table", {
class: "cs2s_table",
children: [
CreateElement("thead", {
children: [
CreateElement("tr", {
children: [
CreateElement("th", {
text: "Time"
}),
CreateElement("th", {
text: "Severity"
}),
CreateElement("th", {
text: "Error"
})
]
})
]
}),
this.#errorTableBody
]
})
]
})
]
});
popup.Show();
}
ShowSettings() {
const form = CreateElement("form", {
class: "cs2s_settings_form",
html: (
/*html*/
`
<div class="cs2s_settings_form_group_title">
ASF Settings
</div>
<div class="cs2s_settings_form_group">
<div class="cs2s_settings_form_group_item">
<label for="${SETTING_ASF_SERVER}">
ASF Server
</label>
<input type="text" name="${SETTING_ASF_SERVER}" placeholder="${DEFAULT_SETTINGS[SETTING_ASF_SERVER]}" value="${GetSetting(SETTING_ASF_SERVER)}">
</div>
<div class="cs2s_settings_form_group_item">
<label for="${SETTING_ASF_PORT}">
ASF Port
</label>
<input type="number" name="${SETTING_ASF_PORT}" placeholder="${DEFAULT_SETTINGS[SETTING_ASF_PORT]}" min="0" value="${GetSetting(SETTING_ASF_PORT)}">
</div>
<div class="cs2s_settings_form_group_item">
<label>
ASF IPC Password
</label>
<div class="cs2s_settings_form_message">
This setting can be configured from your userscript manager's popup menu, found in your browser's extensions toolbar
</div>
</div>
</div>
<div class="cs2s_settings_form_group_title">
Script Features
</div>
<div class="cs2s_settings_form_group">
<div class="cs2s_settings_form_group_item cs2s_settings_form_group_item_checkbox">
<input type="checkbox" name="${SETTING_INSPECT_ITEMS}" id="${SETTING_INSPECT_ITEMS}" ${GetSetting(SETTING_INSPECT_ITEMS) ? "checked" : ""}>
<label for="${SETTING_INSPECT_ITEMS}">
Inspect Items
</label>
</div>
</div>
<div class="cs2s_settings_form_group_title">
Script Settings
</div>
<div class="cs2s_settings_form_group">
<div class="cs2s_settings_form_group_item">
<label for="${SETTING_INTERFACE_AUTOSTOP_MINUTES}">
Auto-stop interface if inactive for (minutes; 0 = never auto-stop${this.Bot?.Plugin?.Connected ? "; changes will apply on next start" : ""})
</label>
<input type="number" name="${SETTING_INTERFACE_AUTOSTOP_MINUTES}" placeholder="${DEFAULT_SETTINGS[SETTING_INTERFACE_AUTOSTOP_MINUTES]}" min="0" value="${GetSetting(SETTING_INTERFACE_AUTOSTOP_MINUTES)}">
</div>
<div class="cs2s_settings_form_group_item">
<label for="${SETTING_INSPECT_CACHE_TIME_HOURS}">
Re-inspect items after (hours; -1 = never re-inspect)
</label>
<input type="number" name="${SETTING_INSPECT_CACHE_TIME_HOURS}" placeholder="${DEFAULT_SETTINGS[SETTING_INSPECT_CACHE_TIME_HOURS]}" min="-1" value="${GetSetting(SETTING_INSPECT_CACHE_TIME_HOURS)}">
</div>
</div>
<div class="cs2s_settings_form_submit_group">
<button class="cs2s_blue_long_button" type="submit">Save</button>
<button class="cs2s_grey_long_button" id="form_cancel" type="button">Cancel</button>
</div>
`
),
onsubmit: (event) => {
event.preventDefault();
for (const element of event.target) {
if (!element.name || !element.value && !element.placeholder) {
continue;
}
const value = element.type === "checkbox" ? element.checked : element.value || element.placeholder;
SetSetting(element.name, value);
}
window.location.reload();
}
});
const popup = new Popup({
title: "Counter-Strike 2 Script Settings",
body: [form]
});
form.querySelector("#form_cancel").onclick = () => {
popup.Hide();
};
popup.Show();
}
async StartInterface(options = {}) {
const showProgress = options.showProgress ?? true;
const errorLevel = options.errorLevel ?? ERROR_LEVEL.HIGH;
if (!this.Bot) {
this.ShowError({ level: errorLevel }, new Error("Cannot start interface. Check the error log for more information."));
return false;
}
const loadingBody = CreateElement("div", {
class: "cs2s_action_body",
children: [
CreateElement("div", {
class: "cs2s_action_spinner"
})
]
});
const successButton = CreateElement("div", {
class: "cs2s_blue_long_button",
text: "OK"
});
const successBody = CreateElement("div", {
class: "cs2s_action_body",
children: [
CreateElement("div", {
class: "cs2s_action_message cs2s_action_message_tall",
text: "Interface successfully started"
}),
successButton
]
});
let interfaceStarted = false;
const popup = new Popup({
simpleMode: true,
disableClose: true,
popoverMode: options.popoverMode ?? false,
fade: false,
title: "Starting Interface",
body: [
loadingBody,
successBody
],
onopen: options.onopen,
onclose: () => {
if (typeof options.onclose === "function") {
options.onclose();
}
if (interfaceStarted) {
if (typeof options.onconnected === "function") {
options.onconnected();
return interfaceStarted;
}
window.location.reload();
}
}
});
successBody.hide();
successButton.onclick = () => {
popup.Hide();
};
if (showProgress) {
popup.Show();
}
try {
const response = await asf_default.Send("CS2Interface", `Start`, "GET", this.Bot.ASF.BotName, { autoStop: GetSetting(SETTING_INTERFACE_AUTOSTOP_MINUTES) });
if (!response || !response[this.Bot.ASF.BotName]?.Success) {
popup.Hide();
this.ShowError({ level: errorLevel }, new Error("Interface failed to start"));
return interfaceStarted;
}
let status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
while (status && status.Connected && !status.InventoryLoaded) {
await Sleep(1e3);
status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
}
if (!status || !status.Connected || !status.InventoryLoaded) {
popup.Hide();
this.ShowError({ level: errorLevel }, new Error("Interface failed to start: Interface stopped while waiting for inventory to loaded"));
return interfaceStarted;
}
} catch (e) {
popup.Hide();
this.ShowError({ level: errorLevel }, new Error(e.response?.Result?.[this.Bot.ASF.BotName]?.Message ?? e.message));
return interfaceStarted;
}
interfaceStarted = true;
if (options.autoClose) {
popup.Hide();
return interfaceStarted;
}
loadingBody.hide();
successBody.show();
return interfaceStarted;
}
async StopInterface(options = {}) {
const showProgress = options.showProgress ?? true;
const errorLevel = options.errorLevel ?? ERROR_LEVEL.HIGH;
const loadingBody = CreateElement("div", {
class: "cs2s_action_body",
children: [
CreateElement("div", {
class: "cs2s_action_spinner"
})
]
});
const successButton = CreateElement("div", {
class: "cs2s_blue_long_button",
text: "OK"
});
const successBody = CreateElement("div", {
class: "cs2s_action_body",
children: [
CreateElement("div", {
class: "cs2s_action_message cs2s_action_message_tall",
text: "Interface successfully stopped"
}),
successButton
]
});
let interfaceStopped = false;
const popup = new Popup({
simpleMode: true,
title: "Stopping Interface",
body: [
loadingBody,
successBody
],
onclose: () => {
if (interfaceStopped) {
window.location.reload();
}
}
});
successBody.hide();
successButton.onclick = () => {
popup.Hide();
};
if (showProgress) {
popup.Show();
}
try {
const response = await asf_default.Send("CS2Interface", `Stop`, "GET", this.Bot.ASF.BotName);
if (!response || !response[this.Bot.ASF.BotName]?.Success) {
popup.Hide();
this.ShowError({ level: errorLevel }, new Error("Interface failed to stop"));
return interfaceStopped;
}
} catch (e) {
popup.Hide();
this.ShowError({ level: errorLevel }, e);
return interfaceStopped;
}
interfaceStopped = true;
loadingBody.hide();
successBody.show();
return interfaceStopped;
}
async RestartInterface(options = {}) {
return await this.StopInterface(options) && await this.StartInterface(options);
}
ShowStartInterfacePrompt(options = {}) {
const popup = new Popup({
title: "Start Interface?",
simpleMode: true,
popoverMode: options.popoverMode ?? false,
onopen: options.onopen,
onclose: options.onclose,
fade: options.fade,
body: [
CreateElement("div", {
class: "cs2s_action_body",
children: [
CreateElement("div", {
class: "cs2s_action_message cs2s_action_message_tall",
text: options.message ?? "Start the interface?"
}),
CreateElement("div", {
class: "cs2s_action_buttons",
children: [
CreateElement("div", {
class: "cs2s_blue_long_button",
text: "Start Interface",
onclick: () => {
popup.Hide();
this.StartInterface(options);
}
}),
CreateElement("div", {
class: "cs2s_grey_long_button",
text: "Cancel",
onclick: () => {
popup.Hide();
}
})
]
})
]
})
]
});
popup.Show();
}
async GetInventory(options = {}) {
if (this.#inventory === null) {
const progressMessage = CreateElement("div", {
class: "cs2s_action_message"
});
const progressBar = CreateElement("div", {
class: "cs2s_action_progress_bar"
});
this.GetInventory.closeButton = CreateElement("div", {
class: "cs2s_grey_long_button",
text: "Close"
});
this.GetInventory.progressBody = CreateElement("div", {
class: "cs2s_action_body",
children: [
progressMessage,
progressBar,
this.GetInventory.closeButton
]
});
this.#inventory = CreateCachedAsyncFunction(async () => {
const cache_id = `inventory_${unsafeWindow.g_steamID}`;
const cache = await Cache.GetValue(cache_id, null);
let inventory;
if (this.Bot) {
try {
let status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
if (status && status.Connected && status.InventoryLoaded) {
if (!status.InventoryLoaded) {
do {
await Sleep(1e3);
status = await asf_default.GetPluginStatus(this.Bot.ASF.BotName);
} while (status && status.Connected && !status.InventoryLoaded);
}
if (status && status.Connected && status.InventoryLoaded) {
const itemList = await asf_default.Send("CS2Interface", "Inventory", "GET", this.Bot.ASF.BotName);
if (itemList) {
inventory = new Inventory(itemList);
Cache.SetValue(cache_id, itemList);
}
}
}
} catch (e) {
this.ShowError({ level: ERROR_LEVEL.LOW }, e);
}
}
if (!inventory) {
if (!cache) {
return OPERATION_ERROR.INTERFACE_NOT_CONNECTED;
}
inventory = new Inventory(cache, true);
}
try {
await inventory.LoadCrateContents((message, progress) => {
progressMessage.innerText = message;
progressBar.style.setProperty("--percentage", `${(progress * 100).toFixed(0)}%`);
});
return inventory;
} catch (e) {
this.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return e.OPERATION_ERROR ?? OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD;
}
});
}
let cancelled = false;
const popup = new Popup({
title: "Loading Inventory",
body: [this.GetInventory.progressBody],
simpleMode: true,
onclose: () => {
cancelled = true;
}
});
this.GetInventory.closeButton.onclick = () => {
popup.Hide();
};
const alreadyFinished = this.#inventory.willReturnImmediately();
if (options.showProgress && !alreadyFinished) {
popup.Show();
}
const success = await this.#inventory() !== void 0;
if (cancelled || !success) {
return;
}
if (options.showProgress && !alreadyFinished) {
await Sleep(500);
popup.Hide();
}
return await this.#inventory();
}
};
var instance = new Script();
var script_default = instance;
// src/utils/worker.js
var Worker = class {
#queue = [];
#activeTasks = 0;
#concurrentLimit;
#delay;
#running = false;
cancelled = false;
constructor(options = {}) {
const { concurrentLimit = 1, delay = 0 } = options;
this.#concurrentLimit = typeof concurrentLimit === "function" ? concurrentLimit : () => concurrentLimit;
this.#delay = delay;
}
Add(task, options = {}) {
if (this.cancelled) {
return;
}
if (options.priority ?? false) {
this.#queue.unshift(task);
} else {
this.#queue.push(task);
}
}
Run() {
if (this.#running) {
return;
}
this.#running = true;
(async () => {
while (this.#queue.length > 0) {
if (this.#activeTasks < this.#concurrentLimit()) {
const task = this.#queue.shift();
this.#activeTasks++;
(async () => {
try {
await task();
} finally {
this.#activeTasks--;
}
})();
} else {
await Sleep(50);
}
if (this.#queue.length > 0) {
await Sleep(this.#delay);
}
}
this.#running = false;
})();
}
async Finish() {
while (this.#activeTasks > 0 || this.#queue.length > 0) {
await Sleep(50);
}
}
async Cancel() {
this.cancelled = true;
this.#queue.length = 0;
await this.Finish();
}
};
// src/cs2/items/assets/asset.js
var Asset = class _Asset {
_assetid;
_type;
_inspectLink;
_inspectData;
_wearData;
static _inspectionWorker = new Worker({
concurrentLimit: () => {
return script_default.AccountsConnected;
}
});
static TYPE = {
WEARABLE: 0,
KEYCHAIN: 1,
STORAGE_UNIT: 2,
OTHER: 3
};
ShouldInspect() {
return this._type == _Asset.TYPE.WEARABLE && this._inspectLink != "undefined";
}
async _Inspect(options = {}) {
if (!this.ShouldInspect() || !this._assetid) {
return;
}
const cacheOnly = options.cacheOnly ?? false;
const cache_id = `item_${this._assetid}`;
const cache = await Cache.GetValue(cache_id, null);
if (cache) {
const ageHours = (+/* @__PURE__ */ new Date() - cache.created) / 36e5;
const maxAgeHours = GetSetting(SETTING_INSPECT_CACHE_TIME_HOURS);
const cacheExpired = maxAgeHours >= 0 && ageHours >= maxAgeHours;
if (!cacheExpired) {
this._inspectData = cache;
}
}
if (!this._inspectData) {
if (cacheOnly) {
return false;
}
let inspectData;
for (let attempt = 0; attempt < 3; attempt++) {
try {
inspectData = await asf_default.Send("CS2Interface", "InspectItem", "GET", "ASF", { url: this._inspectLink });
break;
} catch (e) {
if (e.code === 504) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
} else {
throw e;
}
}
}
if (!inspectData) {
throw new Error(`Failed to inspect item: ${this._inspectLink}`);
}
if (!inspectData.iteminfo) {
console.log(inspectData);
throw new Error(`Invalid inspect data, check browser logs, ${this._inspectLink}`);
}
this._inspectData = {
created: +/* @__PURE__ */ new Date()
};
if (typeof inspectData.wear !== "undefined" && typeof inspectData.wear_min !== "undefined" && typeof inspectData.wear_max !== "undefined") {
this._inspectData.wear = inspectData.wear;
this._inspectData.wearMin = inspectData.wear_min;
this._inspectData.wearMax = inspectData.wear_max;
}
if (typeof inspectData.iteminfo.paintseed !== "undefined") {
this._inspectData.seed = inspectData.iteminfo.paintseed;
}
if (typeof inspectData.iteminfo.rarity !== "undefined") {
this._inspectData.rarity = inspectData.iteminfo.rarity;
}
if (typeof inspectData.iteminfo.quality !== "undefined") {
this._inspectData.quality = inspectData.iteminfo.quality;
}
if (inspectData.stattrak === true) {
this._inspectData.stattrak = true;
}
if ((inspectData.iteminfo.stickers?.length ?? 0) > 0) {
this._inspectData.stickers = inspectData.iteminfo.stickers.map((sticker) => sticker.wear ?? 0);
}
if ((inspectData.iteminfo.keychains?.length ?? 0) > 0) {
this._inspectData.charm = inspectData.iteminfo.keychains[0].pattern;
}
Cache.SetValue(cache_id, this._inspectData);
}
if (typeof this._inspectData.wear !== "undefined") {
this._wearData = _Asset.GetWear(this._inspectData.wear);
if (!this._wearData) {
throw new Error(`Invalid item wear: ${this._inspectData.wear}, ${this._inspectLink}`);
}
}
return true;
}
static GetWear(wearValue) {
for (const wear of WEARS) {
if (wearValue >= wear.min && wearValue <= wear.max) {
return wear;
}
}
}
static GetPercentileElement(wear, wearValue, wearMin, wearMax, options = {}) {
const showTooltip = options.showTooltip ?? false;
const showRounded = options.rounded ?? true;
const exteriorWearMin = Math.max(wearMin, wear.min);
const exteriorWearMax = Math.min(wearMax, wear.max);
const percentile = (1 - (wearValue - exteriorWearMin) / (exteriorWearMax - exteriorWearMin)) * 100;
const percentileRounded = Math.min(99, Math.round(percentile));
const percentileFixed = Math.min(99.99, parseFloat(percentile.toFixed(2)));
const bestWear = _Asset.GetWear(wearMin);
const worstWear = _Asset.GetWear(wearMax);
let rank;
if (wear == bestWear) {
if (percentileFixed >= 99.9) {
rank = "gold";
} else if (percentileFixed >= 99.5) {
rank = "silver";
} else if (percentileRounded >= 99) {
rank = "bronze";
}
} else if (wear == worstWear && percentileRounded == 0) {
rank = "rust";
}
const percentileElement = CreateElement("span", {
text: showRounded ? `(${percentileRounded}%)` : `(${percentileFixed}%)`
});
if (rank) {
percentileElement.classList.add(`cs2s_asset_rank_${rank}`);
}
if (showTooltip) {
BindTooltip(percentileElement, `Better than ${percentileFixed}% of ${wear.nameLong} floats`);
}
return percentileElement;
}
static GetNumCosmetics(item) {
if (typeof item.cosmetics !== "undefined") {
return item.cosmetics;
}
let count = 0;
if (item.keychains) {
count++;
}
if (item.stickers) {
for (let slotNum = 0; slotNum < STICKER_MAX_COUNT; slotNum++) {
let stickerID = item.attributes[`sticker slot ${slotNum} id`];
if (stickerID) {
count++;
}
}
}
item.cosmetics = count;
return item.cosmetics;
}
_GetPercentileElement(options = {}) {
if (!this._inspectData || !this._wearData) {
return;
}
return _Asset.GetPercentileElement(this._wearData, this._inspectData.wear, this._inspectData.wearMin, this._inspectData.wearMax, options);
}
_GetWearRangeElement(highlightHalfwayPoint = false) {
if (!this._inspectData.wear) {
return;
}
const wearRangeElement = CreateElement("div", {
class: "descriptor cs2s_asset_wear_range"
});
for (const wear of WEARS) {
const { wearMin, wearMax, wear: actualWear } = this._inspectData;
const range = wear.max - wear.min;
const isMinWear = wearMin > 0 && wearMin >= wear.min && wearMin < wear.max;
const isMaxWear = wearMax < 1 && wearMax > wear.min && wearMax <= wear.max;
const isRollableWear = wearMax > wear.min && wearMin < wear.max;
const wearGroupElement = CreateElement("div", {
class: `cs2s_asset_wear_range_${wear.name.toLowerCase()}`
});
wearRangeElement.append(wearGroupElement);
if (isMinWear) {
const percentage = (1 - (wearMin - wear.min) / range) * 100;
wearGroupElement.classList.add("cs2s_asset_wear_range_right");
wearGroupElement.style.setProperty("--wear-percentage", `${percentage.toFixed(0)}%`);
wearGroupElement.append(
CreateElement("div", {
class: "cs2s_asset_wear_range_low",
wear_value: wearMin.toFixed(2),
vars: {
"wear-percentage": `${percentage.toFixed(0)}%`
}
})
);
}
if (isMaxWear) {
const percentage = (wearMax - wear.min) / range * 100;
wearGroupElement.classList.add("cs2s_asset_wear_range_left");
wearGroupElement.style.setProperty("--wear-percentage", `${percentage.toFixed(0)}%`);
wearGroupElement.append(
CreateElement("div", {
class: "cs2s_asset_wear_range_high",
wear_value: wearMax.toFixed(2),
vars: {
"wear-percentage": `${percentage.toFixed(0)}%`
}
})
);
}
if (isRollableWear && !isMinWear && !isMaxWear) {
wearGroupElement.classList.add("cs2s_asset_wear_range_full");
}
if (!isRollableWear) {
wearGroupElement.classList.add("cs2s_asset_wear_range_empty");
}
if (this._wearData == wear) {
let percentage;
if (highlightHalfwayPoint) {
const halfWayPoint = (Math.min(wear.max, wearMax) + Math.max(wear.min, wearMin)) / 2;
percentage = (halfWayPoint - wear.min) / range * 100;
} else {
percentage = (actualWear - wear.min) / range * 100;
}
wearGroupElement.append(
CreateElement("div", {
class: "cs2s_asset_wear_range_marker",
vars: {
"wear-percentage": `${percentage.toFixed(0)}%`
}
})
);
}
}
return wearRangeElement;
}
};
// src/components/table.js
var Table = class _Table {
#mode;
#casket;
#multiCasket;
#data;
#filteredData;
#inventory;
#selectionLimit;
#rowElements = [];
#selectedRows = /* @__PURE__ */ new Set();
#selectedRowsSaved = /* @__PURE__ */ new Set();
#lastStartRow;
#lastRowClicked = null;
#lastRowSelected = null;
#inventoryChanged = false;
#sortColumns = null;
#sortDirection = null;
#filterables = null;
#filter = null;
#searchQuery = null;
static ROW_HEIGHT = 69;
static BUFFER_ROWS = 3;
#VISIBLE_ROWS;
get #NUM_ROW_ELEMENTS() {
return this.#VISIBLE_ROWS + _Table.BUFFER_ROWS * 2;
}
#popup;
#tableContainer;
#table;
#tableBody;
#spacer;
#selectionLimitCount;
#selectionCount;
#clearSelectionButton;
#filterCount;
#actionButton;
static MODE = {
STORE: 0,
RETRIEVE: 1
};
static SORT_DIRECTION = {
ASC: 0,
DESC: 1
};
constructor(data, inventory, options) {
this.#data = data;
this.#filteredData = data;
this.#inventory = inventory;
this.#mode = options.mode;
this.#casket = options.casket ?? null;
this.#multiCasket = options.multiCasket ?? false;
this.#VISIBLE_ROWS = Math.max(1, Math.floor(unsafeWindow.innerHeight * 0.66 / _Table.ROW_HEIGHT));
this.#data.map((item) => delete item.element);
this.#tableBody = CreateElement("tbody");
this.#spacer = CreateElement("div");
this.#table = CreateElement("table", {
class: "cs2s_table",
children: [
CreateElement("thead", {
children: [
CreateElement("tr", {
children: [
CreateElement("th", {
class: "cs2s_table_image_column"
}),
CreateElement("th", {
class: "cs2s_table_name_column",
children: [
CreateElement("span", {
class: "cs2s_table_column",
text: "Name",
children: [
CreateElement("div", {
class: "cs2s_table_column_sort"
})
],
onclick: (event) => {
this.#SortRows({ event, columns: ["name", "wear"] });
}
}),
CreateElement("span", {
class: "cs2s_table_column_search cs2s_resizable_input",
children: [
CreateElement("input", {
type: "search",
placeholder: "Search",
oninput: (event) => {
event.target.style.width = "0px";
event.target.parentNode.dataset.value = event.target.value || event.target.placeholder;
event.target.style.width = `${event.target.parentNode.clientWidth}px`;
this.#searchQuery = event.currentTarget.value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
this.#FilterRows(false);
}
})
]
})
]
}),
CreateElement("th", {
class: "cs2s_table_collection_column",
children: [
CreateElement("span", {
class: "cs2s_table_column",
text: "Quality",
children: [
CreateElement("div", {
class: "cs2s_table_column_sort"
})
],
onclick: (event) => {
this.#SortRows({ event, columns: ["rarity", "quality", "collection", "name", "wear"] });
}
}),
CreateElement("span", {
class: "cs2s_table_column",
text: "Collection",
children: [
CreateElement("div", {
class: "cs2s_table_column_sort"
})
],
onclick: (event) => {
this.#SortRows({ event, columns: ["collection", "rarity", "quality", "name", "wear"] });
}
})
]
}),
CreateElement("th", {
class: "cs2s_table_float_column",
children: [
CreateElement("span", {
class: "cs2s_table_column",
text: "Float",
children: [
CreateElement("div", {
class: "cs2s_table_column_sort"
})
],
onclick: (event) => {
this.#SortRows({ event, columns: ["wear"] });
}
})
]
}),
CreateElement("th", {
class: "cs2s_table_seed_column",
children: [
CreateElement("span", {
class: "cs2s_table_column",
text: "Seed",
children: [
CreateElement("div", {
class: "cs2s_table_column_sort"
})
],
onclick: (event) => {
this.#SortRows({ event, columns: ["seed"] });
}
})
]
}),
this.#multiCasket && CreateElement("th", {
class: "cs2s_table_crate_column",
children: [
CreateElement("span", {
class: "cs2s_table_column",
text: "Storage Unit",
children: [
CreateElement("div", {
class: "cs2s_table_column_sort"
})
],
onclick: (event) => {
this.#SortRows({ event, columns: ["casket_name", "id"] });
}
})
]
})
]
})
]
}),
this.#tableBody,
this.#spacer
]
});
this.#tableContainer = CreateElement("div", {
class: "cs2s_table_container",
style: {
height: `${(this.#VISIBLE_ROWS + 1) * _Table.ROW_HEIGHT}px`
},
onscroll: () => {
this.#UpdateRows();
},
children: [this.#table]
});
if (this.#mode === _Table.MODE.RETRIEVE) {
this.#selectionLimit = INVENTORY_ITEM_LIMIT - inventory.items.length;
} else {
this.#selectionLimit = STORAGE_UNIT_ITEM_LIMIT - inventory.storedItems.filter((x) => x.casket_id == this.#casket.iteminfo.id).length;
}
const onStatusUpdate = (status) => {
if (this.#mode !== _Table.MODE.RETRIEVE || typeof status.Plugin?.InventorySize === "undefined") {
return;
}
this.#selectionLimit = INVENTORY_ITEM_LIMIT - status.Plugin.InventorySize;
this.#UpdateFooter();
};
this.#filterCount = CreateElement("span", {
class: "cs2s_table_footer_selection_count",
text: this.#data.length.toLocaleString()
});
this.#selectionLimitCount = CreateElement("span", {
class: "cs2s_table_footer_selection_count",
text: this.#selectionLimit.toLocaleString()
});
this.#selectionCount = CreateElement("span", {
class: "cs2s_table_footer_selection_count",
text: 0
});
this.#clearSelectionButton = CreateElement("a", {
class: "cs2s_table_footer_action_link",
// text: "Clear",
onclick: () => {
this.#DeselectAll();
this.#tableContainer.focus();
},
children: [
CreateElement("span", {
htmlChildren: [
/*html*/
`
<svg width="16" height="16" viewBox="0 0 32 32" aria-hidden="true" stroke="none" fill="currentColor">
<path d="m 15.5,29.5 c -7.18,0 -13,-5.82 -13,-13 0,-7.18 5.82,-13 13,-13 7.18,0 13,5.82 13,13 0,7.18 -5.82,13 -13,13 z m 6.438,-13.562 c 0,-0.552 -0.448,-1 -1,-1 h -11 c -0.553,0 -1,0.448 -1,1 v 1 c 0,0.553 0.447,1 1,1 h 11 c 0.552,0 1,-0.447 1,-1 z"></path>
</svg>
`
],
children: [
"Clear"
]
})
]
});
this.#actionButton = CreateElement("a", {
class: "cs2s_green_button cs2s_button_disabled",
html: "<span>Proceed...</span>",
onclick: () => {
if (this.#actionButton.classList.contains("cs2s_button_disabled")) {
return;
}
if (!script_default.Bot?.Plugin?.Connected) {
script_default.ShowStartInterfacePrompt({
message: this.#mode === _Table.MODE.RETRIEVE ? "Interface must running to retrieve items" : "Interface must running to store items",
autoClose: true,
popoverMode: true,
fade: false,
onclose: () => {
this.#tableContainer.focus();
},
onconnected: () => {
this.#inventoryChanged = true;
this.#ProcessSelected();
}
});
return;
}
this.#ProcessSelected();
}
});
const footerContainer = CreateElement("div", {
class: "cs2s_table_footer cs2s_popup_footer",
children: [
CreateElement("div", {
class: "cs2s_table_footer_element_left",
children: [
CreateElement("span", {
children: [
CreateElement("a", {
class: "cs2s_table_footer_action_link",
onclick: (event) => {
this.#ShowFilters(event.currentTarget);
},
children: [
CreateElement("span", {
htmlChildren: [
/*html*/
`
<svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" fill="currentColor">
<path d="m 3,5 h 18 a 1,1 0 1 1 0,2 H 3 A 1,1 0 1 1 3,5 Z m 3,6 h 12 a 1,1 0 1 1 0,2 H 6 a 1,1 0 1 1 0,-2 z m 3,6 h 6 a 1,1 0 1 1 0,2 H 9 a 1,1 0 1 1 0,-2 z"/>
</svg>
`
],
children: [
"Filter"
]
})
]
}),
this.#filterCount,
" Item(s)"
]
}),
CreateElement("span", {
children: [
CreateElement("form", {
style: {
display: "inline-block"
},
onsubmit: (event) => {
event.preventDefault();
const countInput = event.target.elements["count"];
const count = parseInt(countInput.value || countInput.placeholder);
this.#SelectFirst(count);
},
children: [
CreateElement("button", {
class: "cs2s_table_footer_action_link",
children: [
CreateElement("span", {
htmlChildren: [
/*html*/
`
<svg width="16" height="16" viewBox="0 0 32 32" aria-hidden="true" stroke="none" fill="currentColor">
<path d="M15.5 29.5c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13zM21.938 15.938c0-0.552-0.448-1-1-1h-4v-4c0-0.552-0.447-1-1-1h-1c-0.553 0-1 0.448-1 1v4h-4c-0.553 0-1 0.448-1 1v1c0 0.553 0.447 1 1 1h4v4c0 0.553 0.447 1 1 1h1c0.553 0 1-0.447 1-1v-4h4c0.552 0 1-0.447 1-1v-1z"></path>
</svg>
`
],
children: [
"Select"
]
})
]
}),
CreateElement("span", {
onclick: (event) => {
const input = event.target.querySelector("input");
input && input.focus();
},
children: [
"First ",
CreateElement("span", {
class: "cs2s_table_footer_input cs2s_resizable_input",
children: [
CreateElement("input", {
type: "number",
name: "count",
min: 0,
placeholder: 0,
style: {
width: "10px"
},
oninput: (event) => {
event.target.style.width = "0px";
event.target.parentNode.dataset.value = event.target.value || event.target.placeholder;
event.target.style.width = `${event.target.parentNode.clientWidth}px`;
}
})
]
}),
" Item(s)"
]
})
]
})
]
})
]
}),
CreateElement("div", {
class: "cs2s_table_footer_element_right",
children: [
CreateElement("span", {
children: [
this.#selectionLimitCount,
" Space(s) Available"
]
}),
CreateElement("span", {
children: [
this.#clearSelectionButton,
this.#selectionCount,
" Item(s) Selected"
]
}),
this.#actionButton
]
})
]
});
const popupTitle = this.#mode === _Table.MODE.RETRIEVE ? "Select items to retrieve from " : "Select items to move into ";
const cachedNotification = CreateElement("span", {
text: "(Cached)"
});
BindTooltip(cachedNotification, "The information below was loaded from cache and may no longer be accurate.");
const popupTitleCrateName = CreateElement("span", {
class: "cs2s_table_title_casket",
text: this.#multiCasket ? options.casketName : `"${options.casketName}"`,
children: [
this.#inventory.loadedFromCache && " ",
this.#inventory.loadedFromCache && cachedNotification
]
});
if (this.#multiCasket) {
popupTitleCrateName.classList.add("cs2s_table_title_casket_multiple");
}
script_default.AddStatusUpdateListener(onStatusUpdate);
this.#popup = new Popup({
title: popupTitle,
titleChildren: [
popupTitleCrateName
],
body: [this.#tableContainer, footerContainer],
onclose: () => {
script_default.RemovetatusUpdateListener(onStatusUpdate);
if (this.#inventoryChanged) {
window.location.reload();
}
}
});
}
Show() {
this.#popup.Show();
this.#UpdateTable();
this.#tableContainer.focus();
this.#tableContainer.style.width = `${this.#tableContainer.offsetWidth}px`;
this.#tableContainer.querySelectorAll("thead th").forEach((th) => {
th.style.width = getComputedStyle(th).width;
});
}
#GetRowElement(item, buildIfDoesntExist = true) {
if (item.element) {
return item.element;
}
if (!buildIfDoesntExist) {
return;
}
const cosmetics = CreateElement("div", {
class: "cs2s_table_image_column_cosmetics"
});
if (item.keychains) {
let keychainID = item.attributes[`keychain slot 0 id`];
if (keychainID) {
cosmetics.append(CreateElement("img", {
src: `https://community.fastly.steamstatic.com/economy/image/${Inventory.iconURLs[item.keychains[keychainID].full_name]}/25fx19f`
}));
}
}
if (item.stickers) {
for (let slotNum = 0; slotNum < STICKER_MAX_COUNT; slotNum++) {
let stickerID = item.attributes[`sticker slot ${slotNum} id`];
if (stickerID) {
cosmetics.append(CreateElement("img", {
src: `https://community.fastly.steamstatic.com/economy/image/${Inventory.iconURLs[item.stickers[stickerID].full_name]}/25fx19f`
}));
}
}
}
const imageTD = CreateElement("td", {
class: "cs2s_table_image_column",
children: [
CreateElement("img", {
src: `https://community.fastly.steamstatic.com/economy/image/${Inventory.iconURLs[item.full_name]}/93fx62f`
}),
cosmetics
]
});
const nameTD = CreateElement("td", {
class: "cs2s_table_name_column",
text: item.name,
children: [
CreateElement("a", {
href: `https://steamcommunity.com/market/listings/${CS2_APPID}/${encodeURIComponent(item.full_name)}`,
target: "_blank",
html: (
/*html*/
`
<svg viewBox="0 0 64 64" stroke-width="3" stroke="currentColor" fill="none">
<path d="M55.4,32V53.58a1.81,1.81,0,0,1-1.82,1.82H10.42A1.81,1.81,0,0,1,8.6,53.58V10.42A1.81,1.81,0,0,1,10.42,8.6H32"/>
<polyline points="40.32 8.6 55.4 8.6 55.4 24.18"/>
<line x1="19.32" y1="45.72" x2="54.61" y2="8.91"/>
</svg>
`
)
})
]
});
const collectionTD = CreateElement("td", {
class: "cs2s_table_collection_column"
});
if (item.collection) {
collectionTD.innerText = item.collection;
}
if (item.collection || item.rarity > 1) {
collectionTD.classList.add("cs2s_table_collection_column_has_rarity");
collectionTD.classList.add(`cs2s_table_collection_column_rarity_${item.rarity}`);
collectionTD.classList.add(`cs2s_table_collection_column_quality_${item.iteminfo.quality}`);
if (item.stattrak) {
collectionTD.classList.add(`cs2s_table_collection_column_stattrak`);
}
}
const floatTD = CreateElement("td", {
class: "cs2s_table_float_column"
});
if (typeof item.wear !== "undefined") {
const wearData = Asset.GetWear(item.wear);
floatTD.classList.add("cs2s_table_float_column_has_float");
floatTD.classList.add(`cs2s_table_float_column_float_${wearData.name.toLowerCase()}`);
floatTD.innerText = item.wear.toFixed(14);
floatTD.append(" ");
floatTD.append(Asset.GetPercentileElement(wearData, item.wear, item.wear_min, item.wear_max));
}
const seedTD = CreateElement("td", {
class: "cs2s_table_seed_column",
text: item.seed ?? ""
});
const casketTD = this.#multiCasket && CreateElement("td", {
class: "cs2s_table_crate_column",
text: item.casket_name
});
item.element = CreateElement("tr", {
onmousedown: (event) => {
if (event.target.nodeName === "A" || event.target.parentElement.nodeName === "A" || event.button !== 0) {
return;
}
this.#SelectItem(event, item);
},
children: [
imageTD,
nameTD,
collectionTD,
floatTD,
seedTD,
casketTD
]
});
if (this.#selectedRows.has(item.iteminfo.id)) {
item.element.classList.add("cs2s_table_row_selected");
}
return item.element;
}
#UpdateTable() {
this.#lastStartRow = Number.POSITIVE_INFINITY;
for (let i = 0; i < this.#rowElements.length; i++) {
this.#rowElements[i].remove();
}
this.#rowElements = [];
for (let i = 0; i < this.#NUM_ROW_ELEMENTS; i++) {
if (i >= this.#filteredData.length) {
break;
}
const rowElement = this.#GetRowElement(this.#filteredData[i]);
this.#rowElements.push(rowElement);
this.#tableBody.append(rowElement);
}
this.#spacer.style.height = "0px";
this.#spacer.style.height = `${this.#filteredData.length * _Table.ROW_HEIGHT - this.#table.clientHeight + 31}px`;
this.#UpdateRows();
this.#UpdateFooter();
if (this.#data.length == 0) {
this.#tableBody.append(CreateElement("tr", {
children: [
CreateElement("td", {
class: "cs2s_table_empty",
colspan: 6,
text: this.#mode == _Table.MODE.RETRIEVE ? "Storage Unit is empty" : "Inventory has no storable items"
})
]
}));
}
}
#UpdateRows() {
const startRow = Math.max(
0,
Math.min(
this.#filteredData.length - this.#NUM_ROW_ELEMENTS,
Math.floor(this.#tableContainer.scrollTop / _Table.ROW_HEIGHT) - _Table.BUFFER_ROWS
)
);
if (startRow == this.#lastStartRow) {
return;
}
const diff = Math.max(
-this.#NUM_ROW_ELEMENTS,
Math.min(
this.#NUM_ROW_ELEMENTS,
startRow - this.#lastStartRow
)
);
this.#lastStartRow = startRow;
if (diff > 0) {
for (let i = 0; i < diff; i++) {
const dataIndex = startRow + this.#NUM_ROW_ELEMENTS - diff + i;
if (dataIndex >= this.#filteredData.length || dataIndex < 0) {
continue;
}
const oldRow = this.#rowElements.shift();
oldRow.remove();
const newRow = this.#GetRowElement(this.#filteredData[dataIndex]);
this.#rowElements.push(newRow);
this.#tableBody.append(newRow);
}
} else {
for (let i = 0; i < Math.abs(diff); i++) {
const dataIndex = startRow - diff - i - 1;
if (dataIndex >= this.#filteredData.length || dataIndex < 0) {
continue;
}
const oldRow = this.#rowElements.pop();
oldRow.remove();
const newRow = this.#GetRowElement(this.#filteredData[dataIndex]);
this.#rowElements.unshift(newRow);
this.#tableBody.prepend(newRow);
}
}
this.#tableBody.style.transform = `translate3d(0, ${startRow * _Table.ROW_HEIGHT}px, 0)`;
}
#UpdateFooter() {
this.#selectionLimitCount.innerText = this.#selectionLimit.toLocaleString();
this.#selectionCount.innerText = this.#selectedRows.size.toLocaleString();
this.#filterCount.innerText = this.#filteredData.length.toLocaleString();
if (this.#selectedRows.size <= 0) {
this.#actionButton.classList.add("cs2s_button_disabled");
BindTooltip(this.#actionButton, "No items selected");
} else if (this.#selectedRows.size > this.#selectionLimit) {
this.#actionButton.classList.add("cs2s_button_disabled");
BindTooltip(this.#actionButton, "Too many items selected");
} else {
this.#actionButton.classList.remove("cs2s_button_disabled");
this.#actionButton.unbindTooltip && this.#actionButton.unbindTooltip();
}
if (this.#selectedRows.size > 0) {
this.#clearSelectionButton.show();
} else {
this.#clearSelectionButton.hide();
}
}
#SelectItem(event, item) {
if (event.shiftKey) {
if (!this.#lastRowClicked || this.#lastRowClicked == item || this.#lastRowSelected === null) {
return;
}
const start = this.#filteredData.indexOf(this.#lastRowClicked);
const end = this.#filteredData.indexOf(item);
if (start < 0 || end < 0) {
return;
}
const from = Math.min(start, end);
const to = Math.max(start, end);
for (let i = from; i <= to; i++) {
const rowItem = this.#filteredData[i];
const row = this.#GetRowElement(rowItem, false);
const assetID = rowItem.iteminfo.id;
if (!this.#lastRowSelected && this.#selectedRows.has(assetID)) {
this.#selectedRows.delete(assetID);
row && row.classList.remove("cs2s_table_row_selected");
} else if (this.#lastRowSelected) {
this.#selectedRows.add(assetID);
row && row.classList.add("cs2s_table_row_selected");
}
}
} else {
const row = this.#GetRowElement(item);
const assetID = item.iteminfo.id;
if (this.#selectedRows.has(assetID)) {
this.#lastRowSelected = false;
this.#selectedRows.delete(assetID);
row.classList.remove("cs2s_table_row_selected");
} else {
this.#lastRowSelected = true;
this.#selectedRows.add(assetID);
row.classList.add("cs2s_table_row_selected");
}
}
this.#lastRowClicked = item;
this.#UpdateFooter();
}
#SelectFirst(count) {
for (let i = 0; i < count; i++) {
if (i >= this.#filteredData.length) {
break;
}
const rowItem = this.#filteredData[i];
const row = this.#GetRowElement(rowItem, false);
const assetID = rowItem.iteminfo.id;
if (!this.#selectedRows.has(assetID)) {
this.#selectedRows.add(assetID);
row && row.classList.add("cs2s_table_row_selected");
}
}
this.#lastRowClicked = null;
this.#UpdateFooter();
}
#DeselectAll() {
for (const item of this.#data) {
const assetID = item.iteminfo.id;
if (!this.#selectedRows.has(assetID)) {
continue;
}
this.#selectedRows.delete(assetID);
const row = this.#GetRowElement(item, false);
row && row.classList.remove("cs2s_table_row_selected");
}
this.#lastRowClicked = null;
this.#UpdateFooter();
}
#SortRows(options = {}) {
if (this.#data.length == 0) {
return;
}
if (options.columns) {
if (this.#sortDirection != null && this.#sortColumns[0] != options.columns[0]) {
this.#sortDirection = null;
}
this.#sortColumns = options.columns;
}
let resetSort = false;
if (options.event) {
if (this.#sortDirection === _Table.SORT_DIRECTION.DESC) {
this.#sortColumns = ["casket_id", "id"];
this.#sortDirection = _Table.SORT_DIRECTION.DESC;
resetSort = true;
} else if (this.#sortDirection === _Table.SORT_DIRECTION.ASC) {
this.#sortDirection = _Table.SORT_DIRECTION.DESC;
}
}
if (!this.#sortColumns) {
return;
}
if (!this.#sortDirection) {
this.#sortDirection = _Table.SORT_DIRECTION.ASC;
}
const asc = this.#sortDirection === _Table.SORT_DIRECTION.ASC;
this.#filteredData.sort((a, b) => {
for (const column of this.#sortColumns) {
let valueA = a[column];
let valueB = b[column];
if (valueA === valueB) {
continue;
}
if (typeof valueA === "undefined") {
return 1;
}
if (typeof valueB === "undefined") {
return -1;
}
if (typeof valueA === "string") {
return asc ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
}
return asc ? valueA - valueB : valueB - valueA;
}
return 0;
});
if (options.event) {
document.querySelectorAll(".cs2s_table_column_sort_asc").forEach((el) => {
el.classList.remove("cs2s_table_column_sort_asc");
});
document.querySelectorAll(".cs2s_table_column_sort_desc").forEach((el) => {
el.classList.remove("cs2s_table_column_sort_desc");
});
if (!resetSort) {
if (asc) {
options.event.target.querySelector(".cs2s_table_column_sort").classList.add("cs2s_table_column_sort_asc");
} else {
options.event.target.querySelector(".cs2s_table_column_sort").classList.add("cs2s_table_column_sort_desc");
}
}
}
this.#UpdateTable();
}
#FilterRows(updateSelected = true) {
if (this.#data.length == 0) {
return;
}
const inRange = (value, { min, max }) => {
return !(typeof value === "undefined" || min != null && value < min || max != null && value > max);
};
const matches = (item) => {
if (this.#filter?.selected && !this.#selectedRowsSaved.has(item.iteminfo.id)) {
return false;
}
if (this.#filter?.float && !inRange(item.wear, this.#filter.float)) {
return false;
}
if (this.#filter?.seed && !inRange(item.seed, this.#filter.seed)) {
return false;
}
if (this.#filter?.cosmetics && !inRange(item.cosmetics, this.#filter.cosmetics)) {
return false;
}
if (this.#filter?.quality != null && item.quality !== this.#filter.quality) {
return false;
}
if (this.#filter?.rarity) {
switch (this.#filter.rarity.key) {
case "weapons":
if (typeof item.wear === "undefined" || item.type_name === "Gloves") {
return false;
}
break;
case "agents":
if (item.type_name !== "Agent") {
return false;
}
break;
case "other":
if (typeof item.wear !== "undefined" && item.type_name !== "Gloves" || item.type_name === "Agent") {
return false;
}
break;
}
if (item.iteminfo.rarity !== this.#filter.rarity.value) {
return false;
}
}
if (this.#filter?.type) {
switch (this.#filter.type.key) {
case "weapons":
if (item.weapon_name !== this.#filter.type.value) {
return false;
}
break;
case "other":
if (item.type_name !== this.#filter.type.value) {
return false;
}
break;
}
}
if (this.#filter?.collection && item.collection_name !== this.#filter.collection) {
return false;
}
if (this.#searchQuery && !item.name_normalized.includes(this.#searchQuery)) {
return false;
}
return true;
};
if (updateSelected) {
this.#selectedRowsSaved = new Set(this.#selectedRows);
}
if (!this.#searchQuery && !this.#filter) {
this.#filteredData = this.#data;
} else {
this.#filteredData = this.#data.filter(matches);
}
this.#tableContainer.scrollTop = 0;
this.#SortRows();
this.#UpdateTable();
}
#ShowFilters(button) {
if (this.#filterables == null) {
this.#filterables = {
types: {
weapons: /* @__PURE__ */ new Set(),
other: /* @__PURE__ */ new Set()
},
qualities: {},
rarities: {
weapons: {},
agents: {},
other: {}
},
float: {
min: Number.POSITIVE_INFINITY,
max: Number.NEGATIVE_INFINITY,
wears: {}
},
seed: {
min: Number.POSITIVE_INFINITY,
max: Number.NEGATIVE_INFINITY
},
cosmetics: {
min: Number.POSITIVE_INFINITY,
max: Number.NEGATIVE_INFINITY
},
collections: {
empty_exists: false,
weapons: /* @__PURE__ */ new Set(),
stickers: /* @__PURE__ */ new Set(),
charms: /* @__PURE__ */ new Set(),
agents: /* @__PURE__ */ new Set(),
patches: /* @__PURE__ */ new Set(),
graffiti: /* @__PURE__ */ new Set(),
other: /* @__PURE__ */ new Set()
}
};
for (const item of this.#data) {
if (item.type_name) {
this.#filterables.types.other.add(item.type_name);
}
if (item.weapon_name) {
this.#filterables.types.weapons.add(item.weapon_name);
}
if (item.quality_name) {
this.#filterables.qualities[item.quality_name] = item.quality;
}
if (item.rarity_name) {
if (typeof item.wear !== "undefined" && item.type_name !== "Gloves") {
this.#filterables.rarities.weapons[item.rarity_name] = item.iteminfo.rarity;
} else if (item.type_name === "Agent") {
this.#filterables.rarities.agents[item.rarity_name] = item.iteminfo.rarity;
} else {
this.#filterables.rarities.other[item.rarity_name] = item.iteminfo.rarity;
}
}
if (typeof item.wear != "undefined") {
this.#filterables.float.min = Math.min(this.#filterables.float.min, item.wear);
this.#filterables.float.max = Math.max(this.#filterables.float.max, item.wear);
this.#filterables.float.wears[Asset.GetWear(item.wear).name] = true;
}
if (typeof item.seed != "undefined") {
this.#filterables.seed.min = Math.min(this.#filterables.seed.min, item.seed);
this.#filterables.seed.max = Math.max(this.#filterables.seed.max, item.seed);
}
{
const count = Asset.GetNumCosmetics(item);
this.#filterables.cosmetics.min = Math.min(this.#filterables.cosmetics.min, count);
this.#filterables.cosmetics.max = Math.max(this.#filterables.cosmetics.max, count);
}
if (item.collection_name) {
if (typeof item.wear !== "undefined") {
this.#filterables.collections.weapons.add(item.collection_name);
} else if (item.type_name === "Sticker") {
this.#filterables.collections.stickers.add(item.collection_name);
} else if (item.type_name === "Charm") {
this.#filterables.collections.charms.add(item.collection_name);
} else if (item.type_name === "Agent") {
this.#filterables.collections.agents.add(item.collection_name);
} else if (item.type_name === "Patch") {
this.#filterables.collections.patches.add(item.collection_name);
} else if (item.type_name === "Graffiti") {
this.#filterables.collections.graffiti.add(item.collection_name);
} else {
this.#filterables.collections.other.add(item.collection_name);
}
} else {
this.#filterables.collections.empty_exists = true;
}
}
this.#filterables.float.min = Math.floor(this.#filterables.float.min * 100) / 100;
this.#filterables.float.max = Math.ceil(this.#filterables.float.max * 100) / 100;
}
const floatMinValue = FLOAT_RANGE.min;
const floatMaxValue = FLOAT_RANGE.max;
const seedMinValue = SEED_RANGE.min;
const seedMaxValue = SEED_RANGE.max;
const cosmeticsMinValue = 0;
const cosmeticsMaxValue = STICKER_MAX_COUNT + KEYCHAIN_MAX_COUNT;
const type = CreateElement("select", {
id: "type",
disabled: Object.values(this.#filterables.types).reduce((sum, set) => sum + (set.size ?? 0), 0) < 2,
children: [
CreateElement("option", {
value: ""
}),
...[
{ key: "other", label: "Base Types" },
{ key: "weapons", label: "Weapon Types" }
].filter(({ key }) => this.#filterables.types[key].size > 0).map(
({ key, label }) => CreateElement("optgroup", {
label,
children: [...this.#filterables.types[key]].sort().map(
(name) => CreateElement("option", {
text: name,
value: name,
selected: this.#filter?.type?.key === key && this.#filter?.type?.value === name,
dataset: {
key
}
})
)
})
)
]
});
if (type.disabled) {
type.selectedIndex = type.options.length - 1;
}
const quality = CreateElement("select", {
id: "quality",
disabled: Object.keys(this.#filterables.qualities).length < 2,
children: [
CreateElement("option", {
value: ""
}),
...Object.entries(this.#filterables.qualities).sort(([, v1], [, v2]) => v1 - v2).map(
([qualityName, qualityValue]) => CreateElement("option", {
text: qualityValue == 0 ? "Normal" : qualityName,
value: qualityValue,
selected: this.#filter?.quality === qualityValue,
class: `cs2s_color_quality_${qualityValue}`
})
)
]
});
if (quality.disabled) {
quality.selectedIndex = quality.options.length - 1;
}
const rarity = CreateElement("select", {
id: "rarity",
disabled: Object.values(this.#filterables.rarities).reduce((sum, obj) => sum + Object.keys(obj).length, 0) < 2,
children: [
CreateElement("option", {
value: ""
}),
...[
{ key: "weapons", label: "Weapon Qualities" },
{ key: "agents", label: "Agent Qualities" },
{ key: "other", label: "Base Qualities" }
].filter(({ key }) => Object.keys(this.#filterables.rarities[key]).length > 0).map(
({ key, label }) => CreateElement("optgroup", {
label,
children: Object.entries(this.#filterables.rarities[key]).sort(([, v1], [, v2]) => v1 - v2).map(
([rarityName, rarityValue]) => CreateElement("option", {
text: rarityName,
value: rarityValue,
selected: this.#filter?.rarity?.key === key && this.#filter?.rarity?.value === rarityValue,
class: `cs2s_color_rarity_${rarityValue}`,
dataset: {
key
}
})
)
})
)
]
});
if (rarity.disabled) {
rarity.selectedIndex = rarity.options.length - 1;
}
const collection = CreateElement("select", {
id: "collection",
disabled: Object.values(this.#filterables.collections).reduce((sum, set) => sum + (set.size ?? 0), 0) < 2 - this.#filterables.collections.empty_exists,
children: [
CreateElement("option", {
value: ""
}),
...[
{ key: "weapons", label: "Weapon Collections" },
{ key: "agents", label: "Agent Collections" },
{ key: "stickers", label: "Sticker Collections" },
{ key: "patches", label: "Patch Collections" },
{ key: "charms", label: "Charm Collections" },
{ key: "graffiti", label: "Graffiti Collections" },
{ key: "other", label: "Other Collections" }
].filter(({ key }) => this.#filterables.collections[key].size > 0).map(
({ key, label }) => CreateElement("optgroup", {
label,
children: [...this.#filterables.collections[key]].sort().map(
(name) => CreateElement("option", {
text: name,
value: name,
selected: this.#filter?.collection === name
})
)
})
)
]
});
if (collection.disabled) {
collection.selectedIndex = collection.options.length - 1;
}
const floatMin = CreateElement("input", {
id: "float_min",
type: "number",
step: 0.01,
min: floatMinValue,
max: floatMaxValue,
placeholder: this.#filterables.float.min === Number.POSITIVE_INFINITY ? "" : this.#filterables.float.min,
disabled: this.#filterables.float.min === Number.POSITIVE_INFINITY,
oninput: () => {
float.value = "custom";
const value = floatMin.value;
if (floatMin.checkValidity()) {
if (value === "") {
floatMax.min = floatMinValue;
} else {
floatMax.min = value;
}
}
}
});
const floatMax = CreateElement("input", {
id: "float_max",
type: "number",
step: 0.01,
min: floatMinValue,
max: floatMaxValue,
placeholder: this.#filterables.float.max === Number.NEGATIVE_INFINITY ? "" : this.#filterables.float.max,
disabled: this.#filterables.float.max === Number.NEGATIVE_INFINITY,
oninput: () => {
float.value = "custom";
const value = floatMax.value;
if (floatMax.checkValidity()) {
if (value === "") {
floatMin.max = floatMaxValue;
} else {
floatMin.max = value;
}
}
}
});
if (typeof this.#filter?.float?.min !== "undefined" && this.#filter.float.min !== null) {
floatMin.value = floatMax.min = this.#filter.float.min;
}
if (typeof this.#filter?.float?.max !== "undefined" && this.#filter.float.max !== null) {
floatMax.value = floatMin.max = this.#filter.float.max;
}
const float = CreateElement("select", {
id: "float",
disabled: this.#filterables.float.max === Number.NEGATIVE_INFINITY,
children: [
CreateElement("option", {
value: ""
}),
CreateElement("option", {
hidden: true,
value: "custom"
}),
...WEARS.filter((wear) => this.#filterables.float.wears[wear.name] === true).map((wear) => CreateElement("option", {
value: wear.name,
text: wear.nameLong,
selected: this.#filter?.wear === wear.name,
class: `cs2s_color_wear_${wear.name.toLowerCase()}`
}))
],
onchange: (event) => {
const value = event.target.value;
if (value === "") {
floatMin.value = "";
floatMax.value = "";
floatMin.max = floatMaxValue;
floatMax.min = floatMinValue;
return;
}
for (const wear of WEARS) {
if (wear.name === value) {
floatMin.value = wear.min;
floatMax.value = wear.max;
floatMin.max = floatMax.value;
floatMax.min = floatMin.value;
return;
}
}
}
});
const seedMin = CreateElement("input", {
id: "seed_min",
type: "number",
step: 1,
min: seedMinValue,
max: seedMaxValue,
placeholder: this.#filterables.seed.min === Number.POSITIVE_INFINITY ? "" : this.#filterables.seed.min,
disabled: this.#filterables.seed.min === Number.POSITIVE_INFINITY,
oninput: () => {
const value = seedMin.value;
if (seedMin.checkValidity()) {
if (value === "") {
seedMax.min = seedMinValue;
} else {
seedMax.min = value;
}
}
}
});
const seedMax = CreateElement("input", {
id: "seed_max",
type: "number",
step: 1,
min: seedMinValue,
max: seedMaxValue,
placeholder: this.#filterables.seed.max === Number.NEGATIVE_INFINITY ? "" : this.#filterables.seed.max,
disabled: this.#filterables.seed.max === Number.NEGATIVE_INFINITY,
oninput: () => {
const value = seedMax.value;
if (seedMax.checkValidity()) {
if (value === "") {
seedMin.max = seedMaxValue;
} else {
seedMin.max = value;
}
}
}
});
if (typeof this.#filter?.seed?.min !== "undefined" && this.#filter.seed.min !== null) {
seedMin.value = seedMax.min = this.#filter.seed.min;
}
if (typeof this.#filter?.seed?.max !== "undefined" && this.#filter.seed.max !== null) {
seedMax.value = seedMin.max = this.#filter.seed.max;
}
const cosmeticsMin = CreateElement("input", {
id: "cosmetics_min",
type: "number",
step: 1,
min: cosmeticsMinValue,
max: cosmeticsMaxValue,
placeholder: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0 ? "" : this.#filterables.cosmetics.min,
disabled: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0,
oninput: () => {
const value = cosmeticsMin.value;
if (cosmeticsMin.checkValidity()) {
if (value === "") {
cosmeticsMax.min = cosmeticsMinValue;
} else {
cosmeticsMax.min = value;
}
}
}
});
const cosmeticsMax = CreateElement("input", {
id: "cosmetics_max",
type: "number",
step: 1,
min: cosmeticsMinValue,
max: cosmeticsMaxValue,
placeholder: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0 ? "" : this.#filterables.cosmetics.max,
disabled: this.#filterables.cosmetics.max === Number.NEGATIVE_INFINITY || this.#filterables.cosmetics.max === 0,
oninput: () => {
const value = cosmeticsMax.value;
if (cosmeticsMax.checkValidity()) {
if (value === "") {
cosmeticsMin.max = cosmeticsMaxValue;
} else {
cosmeticsMin.max = value;
}
}
}
});
if (typeof this.#filter?.cosmetics?.min !== "undefined" && this.#filter.cosmetics.min !== null) {
cosmeticsMin.value = cosmeticsMax.min = this.#filter.cosmetics.min;
}
if (typeof this.#filter?.cosmetics?.max !== "undefined" && this.#filter.cosmetics.max !== null) {
cosmeticsMax.value = cosmeticsMin.max = this.#filter.cosmetics.max;
}
const selected = CreateElement("input", {
id: "selected",
type: "checkbox",
disabled: this.#selectedRows.size == 0
});
if (this.#filter?.selected && this.#selectedRows.size > 0) {
selected.checked = true;
}
const form = CreateElement("form", {
class: "cs2s_settings_form cs2s_settings_filter",
onreset: () => {
floatMin.max = floatMaxValue;
floatMax.min = floatMinValue;
seedMin.max = seedMaxValue;
seedMax.min = seedMinValue;
cosmeticsMin.max = cosmeticsMaxValue;
cosmeticsMax.min = cosmeticsMinValue;
},
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_title" + (type.disabled && quality.disabled && rarity.disabled ? " cs2s_settings_form_disabled" : ""),
text: "Base Filters"
}),
CreateElement("div", {
class: "cs2s_settings_form_group",
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_row",
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_item" + (type.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("label", {
text: "Type",
for: "type"
}),
type
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item" + (quality.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("label", {
text: "Category",
for: "quality"
}),
quality
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item" + (rarity.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("label", {
text: "Quality",
for: "rarity"
}),
rarity
]
})
]
})
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_title" + (floatMax.disabled && seedMax.disabled && cosmeticsMax.disabled ? " cs2s_settings_form_disabled" : ""),
text: "Skin Filters"
}),
CreateElement("div", {
class: "cs2s_settings_form_group",
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_row cs2s_settings_form_group_collection" + (floatMax.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Exterior",
for: "float"
}),
float
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Float Min",
for: "float_min"
}),
floatMin
]
}),
CreateElement("div", {
class: "cs2s_settings_form_separator",
text: "\u2014"
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Float Max",
for: "float_max"
}),
floatMax
]
})
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_row",
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_row cs2s_settings_form_group_collection" + (seedMax.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Seed Min",
for: "seed_min"
}),
seedMin
]
}),
CreateElement("div", {
class: "cs2s_settings_form_separator",
text: "\u2014"
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Seed Max",
for: "seed_max"
}),
seedMax
]
})
]
}),
CreateElement("div", {
class: "cs2s_settings_form_separator",
text: " "
}),
CreateElement("div", {
class: "cs2s_settings_form_group_row cs2s_settings_form_group_collection" + (cosmeticsMax.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Num Cosmetics Min",
for: "cosmetics_min"
}),
cosmeticsMin
]
}),
CreateElement("div", {
class: "cs2s_settings_form_separator",
text: "\u2014"
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item",
children: [
CreateElement("label", {
text: "Num Cosmetics Max",
for: "cosmetics_max"
}),
cosmeticsMax
]
})
]
})
]
})
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_title" + (collection.disabled && selected.disabled ? " cs2s_settings_form_disabled" : ""),
text: "Group Filters"
}),
CreateElement("div", {
class: "cs2s_settings_form_group",
children: [
CreateElement("div", {
class: "cs2s_settings_form_group_item" + (collection.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
CreateElement("label", {
text: "Collection",
for: "collection"
}),
collection
]
}),
CreateElement("div", {
class: "cs2s_settings_form_group_item cs2s_settings_form_group_item_checkbox" + (selected.disabled ? " cs2s_settings_form_disabled" : ""),
children: [
selected,
CreateElement("label", {
text: "Show only selected items",
for: "selected"
})
]
})
]
}),
CreateElement("div", {
class: "cs2s_settings_form_submit_group",
children: [
CreateElement("button", {
class: "cs2s_blue_long_button",
type: "submit",
text: "Filter"
}),
CreateElement("button", {
class: "cs2s_grey_long_button",
type: "reset",
text: "Reset"
}),
CreateElement("button", {
class: "cs2s_grey_long_button",
id: "form_cancel",
text: "Cancel"
})
]
})
]
});
const popup = new Popup({
title: "Filter Items",
body: [form],
popoverMode: true,
onclose: () => {
this.#tableContainer.focus();
}
});
form.querySelector("#form_cancel").onclick = () => {
popup.Hide();
};
form.onsubmit = (event) => {
event.preventDefault();
this.#filter = {
type: type.disabled || type.selectedIndex == 0 ? null : {
key: type.selectedOptions[0].dataset.key,
value: type.value
},
quality: quality.disabled || quality.selectedIndex == 0 ? null : parseInt(quality.value),
rarity: rarity.disabled || rarity.selectedIndex == 0 ? null : {
key: rarity.selectedOptions[0].dataset.key,
value: parseInt(rarity.value)
},
wear: float.value == "" ? null : float.value,
float: floatMin.value == "" && floatMax.value == "" ? null : {
min: floatMin.value == "" ? null : parseFloat(floatMin.value),
max: floatMax.value == "" ? null : parseFloat(floatMax.value)
},
seed: seedMin.value == "" && seedMax.value == "" ? null : {
min: seedMin.value == "" ? null : parseInt(seedMin.value),
max: seedMax.value == "" ? null : parseInt(seedMax.value)
},
cosmetics: cosmeticsMin.value == "" && cosmeticsMax.value == "" ? null : {
min: cosmeticsMin.value == "" ? null : parseInt(cosmeticsMin.value),
max: cosmeticsMax.value == "" ? null : parseInt(cosmeticsMax.value)
},
collection: collection.disabled || collection.selectedIndex == 0 ? null : collection.value,
selected: selected.checked ? true : null
};
if (Object.values(this.#filter).every((value) => value === null)) {
this.#filter = null;
}
if (this.#filter === null) {
button.classList.remove("cs2s_table_footer_action_link_active");
} else {
button.classList.add("cs2s_table_footer_action_link_active");
}
popup.Hide();
this.#FilterRows();
};
popup.Show();
}
async #ProcessSelected() {
if (this.#selectedRows.size == 0) {
return;
}
const numItemsToProcess = this.#selectedRows.size;
const itemWindow = CreateElement("div", {
class: "cs2s_action_item_window"
});
const progressMessage = CreateElement("div", {
class: "cs2s_action_message",
text: this.#mode == _Table.MODE.RETRIEVE ? "Retrieving Items" : "Storing Items"
});
const progressBar = CreateElement("div", {
class: "cs2s_action_progress_bar",
vars: {
"percentage": "0%"
}
});
const closeButton = CreateElement("div", {
class: "cs2s_grey_long_button",
text: "Cancel"
});
const popupBody = CreateElement("div", {
class: "cs2s_action_body",
children: [
itemWindow,
progressMessage,
progressBar,
closeButton
]
});
const worker = new Worker({
concurrentLimit: 6,
delay: 1e3 / 6
});
const popup = new Popup({
title: this.#mode == _Table.MODE.RETRIEVE ? "Retrieving From Storage Unit" : "Moving To Storage Unit",
body: [popupBody],
simpleMode: true,
popoverMode: true,
onclose: () => {
this.#tableContainer.focus();
worker.Cancel();
}
});
closeButton.onclick = () => {
popup.Hide();
};
popup.Show();
let numItemsProcessed = 0;
for (const assetID of this.#selectedRows) {
worker.Add(async () => {
const item = this.#data.find((item2) => item2.iteminfo.id == assetID);
const itemImage = CreateElement("div", {
class: "cs2s_action_item_window_image",
html: this.#GetRowElement(item).children[0].innerHTML
});
const maxAttempts = 3;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
if (worker.cancelled) {
return;
}
try {
if (this.#mode == _Table.MODE.RETRIEVE) {
await this.#inventory.RetrieveItem(item);
} else {
await this.#inventory.StoreItem(item, this.#casket);
}
break;
} catch (e) {
if (worker.cancelled || e.code === 504 && attempt < maxAttempts) {
script_default.ShowError({ level: ERROR_LEVEL.LOW }, e);
await Sleep(Random(1e3, 2e3));
continue;
}
worker.Cancel();
popup.Hide();
script_default.ShowError({ level: ERROR_LEVEL.HIGH }, e, new Error(`Failed to ${this.#mode == _Table.MODE.RETRIEVE ? "retrieve" : "store"} "${item.full_name}". If errors persist, reload the page and try again.`));
return;
}
}
const dataIndex = this.#data.findIndex((item2) => item2.iteminfo.id == assetID);
this.#data.splice(dataIndex, 1);
const filteredDataIndex = this.#filteredData.findIndex((item2) => item2.iteminfo.id == assetID);
filteredDataIndex != -1 && this.#filteredData.splice(filteredDataIndex, 1);
this.#selectedRows.delete(assetID);
this.#selectionLimit--;
this.#inventoryChanged = true;
this.#UpdateTable();
numItemsProcessed++;
progressMessage.innerText = (this.#mode == _Table.MODE.RETRIEVE ? "Retrieving Items" : "Storing Items") + ` (${numItemsProcessed}/${numItemsToProcess})`;
progressBar.style.setProperty("--percentage", `${(numItemsProcessed / numItemsToProcess * 100).toFixed(2)}%`);
itemWindow.append(itemImage);
const transform = getComputedStyle(itemImage).transform;
itemImage.style.transformOrigin = "50% 700%";
const rotateStart = Random(-20, -10);
const rotateEnd = Random(10, 20);
const scaleEnd = Random(0.7, 0.8);
const translateYEnd = Random(-215, -165);
const duration = Random(700, 800);
const itemAnimationIn = itemImage.animate([
{ transform: `${transform} rotate(${rotateStart}deg)`, opacity: 0.75, offset: 0 },
{ opacity: 1, filter: "brightness(1)", offset: 0.5 },
{ transform: `${transform} rotate(${rotateEnd}deg) scale(${scaleEnd}) translateY(${translateYEnd}%)`, opacity: 0.5, filter: "brightness(0.1)", offset: 1 }
], {
duration,
easing: "cubic-bezier(.15, .50, .85, .50)"
});
itemAnimationIn.onfinish = () => {
itemImage.remove();
};
});
}
worker.Run();
await worker.Finish();
await Sleep(1e3);
popup.Hide();
}
};
// src/cs2/items/assets/inventory_asset.js
var InventoryAsset = class extends Asset {
_asset;
constructor(asset) {
super();
this._assetid = asset.assetid;
this._asset = asset;
if (asset.description.market_hash_name == "Storage Unit") {
this._type = Asset.TYPE.STORAGE_UNIT;
} else {
for (const tag of asset.description.tags) {
if (tag.category == "Weapon" || tag.internal_name == "Type_Hands") {
this._type = Asset.TYPE.WEARABLE;
break;
} else if (tag.internal_name == "CSGO_Tool_Keychain") {
this._type = Asset.TYPE.KEYCHAIN;
break;
}
}
}
if (typeof this._type == "undefined") {
this._type = Asset.TYPE.OTHER;
}
if (this._type == Asset.TYPE.WEARABLE) {
for (const action of asset.description.actions) {
if (action.link.includes("steam://rungame")) {
this._inspectLink = action.link.replace("%owner_steamid%", unsafeWindow.g_ActiveUser.strSteamId).replace("%assetid%", asset.assetid);
break;
}
}
}
}
async BuildInventoryUI() {
if (this.ShouldInspect() && GetSetting(SETTING_INSPECT_ITEMS)) {
const build = () => {
if (!this._inspectData) {
return;
}
if (this._inspectData.wear && this._wearData) {
this._asset.element.append(
CreateElement("div", {
class: `cs2s_asset_wear cs2s_asset_wear_${this._wearData.name.toLowerCase()}`,
text: this._inspectData.wear.toFixed(6),
children: [
" ",
this._GetPercentileElement()
// createElement("div", {
// class: "cs2s_asset_wear_name",
// text: this._wearData.name
// })
]
})
);
}
if (this._inspectData.seed) {
this._asset.element.append(
CreateElement("div", {
class: "cs2s_asset_seed",
text: this._inspectData.seed
})
);
}
if (this._inspectData.rarity) {
const el = CreateElement("div", {
class: `cs2s_asset_rarity cs2s_asset_rarity_${this._inspectData.rarity} cs2s_asset_quality_${this._inspectData.quality}`
});
if (this._inspectData.stattrak) {
el.classList.add("cs2s_asset_stattrak");
}
this._asset.element.append(el);
}
const cosmetics = [];
for (const description of this._asset.description.descriptions) {
if (description.name == "sticker_info" || description.name == "keychain_info") {
const parser = new DOMParser();
const doc = parser.parseFromString(description.value, "text/html");
for (const img of doc.querySelectorAll("img")) {
cosmetics.push(CreateElement("img", {
src: img.src
}));
}
}
}
if (cosmetics.length > 0) {
this._asset.element.append(
CreateElement("div", {
class: "cs2s_asset_cosmetics",
children: cosmetics
})
);
}
};
let cached;
try {
cached = await this._Inspect({ cacheOnly: true });
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return;
}
if (cached) {
build();
} else {
Asset._inspectionWorker.Add(async () => {
try {
await this._Inspect();
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return;
}
build();
});
Asset._inspectionWorker.Run();
}
} else if (this._type == Asset.TYPE.KEYCHAIN && GetSetting(SETTING_INSPECT_ITEMS)) {
let template;
for (const description of this._asset.description.descriptions) {
if (description.name == "attr: keychain slot 0 seed") {
const matches = description.value.match(/\d+/);
if (matches) {
template = matches[0];
}
break;
}
}
if (template) {
this._asset.element.appendChild(
CreateElement("div", {
class: "cs2s_asset_seed",
text: template
})
);
}
} else if (this._type == Asset.TYPE.STORAGE_UNIT) {
let nameTag;
let itemCount;
for (const description of this._asset.description.descriptions) {
if (description.name == "nametag") {
const matches = description.value.match(/.*?''(.*?)''/);
if (matches) {
nameTag = matches[1];
}
} else if (description.name == "attr: items count") {
const matches = description.value.match(/\d+/);
if (matches) {
itemCount = matches[0];
}
}
}
if (nameTag) {
this._asset.element.append(
CreateElement("div", {
class: "cs2s_asset_name",
text: nameTag
})
);
}
if (itemCount) {
this._asset.element.append(
CreateElement("div", {
class: "cs2s_asset_quantity",
text: itemCount
})
);
}
}
}
async BuildSelectedUI() {
const selectedItem = unsafeWindow.iActiveSelectView;
const descriptionsElement = unsafeWindow.document.getElementById(`iteminfo${selectedItem}_item_descriptors`);
const stickerElements = descriptionsElement.getElementsBySelector("#sticker_info img");
const charmElements = descriptionsElement.getElementsBySelector("#keychain_info img");
const ownerActionsElement = unsafeWindow.document.getElementById(`iteminfo${selectedItem}_item_owner_actions`);
if (this.ShouldInspect() && GetSetting(SETTING_INSPECT_ITEMS)) {
const build = () => {
if (selectedItem != unsafeWindow.iActiveSelectView || this._asset != unsafeWindow.g_ActiveInventory.selectedItem || !this._inspectData) {
return;
}
if (this._inspectData.wear && this._inspectData.seed) {
descriptionsElement.prepend(
this._GetWearRangeElement(),
CreateElement("div", {
class: "descriptor",
text: `Float: ${this._inspectData.wear.toFixed(14)}`,
children: [
" ",
this._GetPercentileElement({ showTooltip: true, rounded: false })
]
}),
CreateElement("div", {
class: "descriptor",
text: `Seed: ${this._inspectData.seed}`
}),
CreateElement("div", {
class: "descriptor",
text: "\xA0"
})
);
}
if (this._inspectData.stickers) {
for (let i = 0; i < this._inspectData.stickers.length; i++) {
if (typeof stickerElements[i] == "undefined") {
break;
}
stickerElements[i].wrap(
CreateElement("span", {
class: "cs2s_asset_sticker_wear",
wear: Math.round(this._inspectData.stickers[i] * 100)
})
);
}
}
if (this._inspectData.charm) {
if (typeof charmElements[0] != "undefined") {
charmElements[0].wrap(
CreateElement("span", {
class: "cs2s_asset_charm_template",
template: this._inspectData.charm
})
);
}
}
};
let cached;
try {
cached = await this._Inspect({ cacheOnly: true });
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return;
}
if (cached) {
build();
} else {
Asset._inspectionWorker.Add(async () => {
try {
await this._Inspect();
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return;
}
build();
}, {
priority: true
});
Asset._inspectionWorker.Run();
}
} else if (this._type == Asset.TYPE.STORAGE_UNIT) {
ownerActionsElement.style.display = "block";
ownerActionsElement.append(
CreateElement("a", {
class: "btn_small btn_grey_white_innerfade",
html: "<span>Retrieve Items</span>",
onclick: async () => {
const inventory = await script_default.GetInventory({ showProgress: true });
if (inventory === OPERATION_ERROR.INTERFACE_NOT_CONNECTED) {
script_default.ShowStartInterfacePrompt({
message: "Interface must be running to fetch stored items",
fade: false
});
return;
}
if (inventory === OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD) {
script_default.ShowError({ level: ERROR_LEVEL.HIGH }, new Error("Inventory failed to load, check error logs and refresh the page to try again"));
return;
}
if (!(inventory instanceof Inventory)) {
return;
}
const casket = inventory.items.find((x) => x.iteminfo.id == this._assetid);
const table = new Table(inventory.storedItems.filter((x) => x.casket_id == this._assetid), inventory, {
mode: Table.MODE.RETRIEVE,
casket,
casketName: casket.attributes["custom name attr"]
});
table.Show();
}
}),
CreateElement("a", {
class: "btn_small btn_grey_white_innerfade",
html: "<span>Deposit Items</span>",
onclick: async () => {
const inventory = await script_default.GetInventory({ showProgress: true });
if (inventory === OPERATION_ERROR.INTERFACE_NOT_CONNECTED) {
script_default.ShowStartInterfacePrompt({
message: "Interface must be running to fetch inventory items"
});
return;
}
if (inventory === OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD) {
script_default.ShowError({ level: ERROR_LEVEL.HIGH }, new Error("Inventory failed to load, check error logs and refresh the page to try again"));
return;
}
if (!(inventory instanceof Inventory)) {
return;
}
const casket = inventory.items.find((x) => x.iteminfo.id == this._assetid);
const table = new Table(inventory.items.filter((x) => x.moveable), inventory, {
mode: Table.MODE.STORE,
casket,
casketName: casket.attributes["custom name attr"]
});
table.Show();
}
})
);
}
}
};
// src/cs2/items/assets/market_asset.js
var MarketAsset = class _MarketAsset extends Asset {
_listingid;
static #builtItemPageUI = false;
constructor(asset, listing) {
super();
this._assetid = asset.id;
this._listingid = listing?.listingid;
for (const description of asset.descriptions) {
if (description.name == "exterior_wear") {
this._type = Asset.TYPE.WEARABLE;
break;
}
}
if (typeof this._type == "undefined") {
this._type = Asset.TYPE.OTHER;
}
if (this._type == Asset.TYPE.WEARABLE) {
for (const action of asset.market_actions) {
if (action.link.includes("steam://rungame")) {
this._inspectLink = action.link.replace("%assetid%", this._assetid);
break;
}
}
}
}
async BuildListingUI() {
if (this.ShouldInspect() && GetSetting(SETTING_INSPECT_ITEMS)) {
const build = () => {
if (!this._inspectData) {
return;
}
const listingDetailsElement = unsafeWindow.document.getElementById(`listing_${this._listingid}_details`);
if (!listingDetailsElement) {
return;
}
if (listingDetailsElement.getElementsBySelector(".cs2s_listing_info").length != 0) {
return;
}
const stickerElements = listingDetailsElement.getElementsBySelector("#sticker_info img");
const charmElements = listingDetailsElement.getElementsBySelector("#keychain_info img");
if (this._inspectData.wear && this._inspectData.seed) {
if (!_MarketAsset.#builtItemPageUI) {
_MarketAsset.#builtItemPageUI = true;
this.#BuiltItemPageUI();
}
listingDetailsElement.prepend(
CreateElement("div", {
class: "cs2s_listing_info",
children: [
CreateElement("div", {
text: `Float: ${this._inspectData.wear.toFixed(14)}`,
children: [
" ",
this._GetPercentileElement({ showTooltip: true, rounded: false })
]
}),
CreateElement("div", {
text: `Seed: ${this._inspectData.seed}`
})
]
})
);
}
if (this._inspectData.stickers) {
for (let i = 0; i < this._inspectData.stickers.length; i++) {
if (typeof stickerElements[i] == "undefined") {
break;
}
stickerElements[i].wrap(
CreateElement("span", {
class: "cs2s_asset_sticker_wear cs2s_asset_cosmetic_small",
wear: Math.round(this._inspectData.stickers[i] * 100)
})
);
}
}
if (this._inspectData.charm) {
if (typeof charmElements[0] != "undefined") {
charmElements[0].wrap(
CreateElement("span", {
class: "cs2s_asset_charm_template cs2s_asset_cosmetic_small",
template: this._inspectData.charm
})
);
}
}
};
let cached;
try {
cached = await this._Inspect({ cacheOnly: true });
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return;
}
if (cached) {
build();
} else {
Asset._inspectionWorker.Add(async () => {
const listingDetailsElement = unsafeWindow.document.getElementById(`listing_${this._listingid}_details`);
if (!listingDetailsElement) {
return;
}
try {
await this._Inspect();
} catch (e) {
script_default.ShowError({ level: ERROR_LEVEL.MEDIUM }, e);
return;
}
build();
});
Asset._inspectionWorker.Run();
}
}
}
#BuiltItemPageUI() {
if (this._inspectData.wear && this._inspectData.seed) {
const descriptionsElement = unsafeWindow.document.getElementById(`largeiteminfo_item_descriptors`);
if (descriptionsElement) {
descriptionsElement.prepend(this._GetWearRangeElement(true));
}
}
}
};
// src/css/style.css
var style_default = `:root {
--cs2s-wear-fn-color: #35cdff;
--cs2s-wear-mw-color: #0bb52f;
--cs2s-wear-ft-color: #e8c805;
--cs2s-wear-ww-color: #e86f24;
--cs2s-wear-bs-color: #ea2828;
--cs2s-stattrak-color: #cf6a32;
--cs2s-quality-3-color: #8650ac;
--cs2s-quality-12-color: #ffd700;
--cs2s-rarity-7-color: #e4ae33;
--cs2s-rarity-6-color: #eb4b4b;
--cs2s-rarity-5-color: #d32ce6;
--cs2s-rarity-4-color: #8847ff;
--cs2s-rarity-3-color: #4b69ff;
--cs2s-rarity-2-color: #5e98d9;
--cs2s-rarity-1-color: #b0c3d9;
}
.cs2s_color_wear_fn { color: var(--cs2s-wear-fn-color) !important; }
.cs2s_color_wear_mw { color: var(--cs2s-wear-mw-color) !important; }
.cs2s_color_wear_ft { color: var(--cs2s-wear-ft-color) !important; }
.cs2s_color_wear_ww { color: var(--cs2s-wear-ww-color) !important; }
.cs2s_color_wear_bs { color: var(--cs2s-wear-bs-color) !important; }
.cs2s_color_rarity_7 { color: var(--cs2s-rarity-7-color) !important; }
.cs2s_color_rarity_6 { color: var(--cs2s-rarity-6-color) !important; }
.cs2s_color_rarity_5 { color: var(--cs2s-rarity-5-color) !important; }
.cs2s_color_rarity_4 { color: var(--cs2s-rarity-4-color) !important; }
.cs2s_color_rarity_3 { color: var(--cs2s-rarity-3-color) !important; }
.cs2s_color_rarity_2 { color: var(--cs2s-rarity-2-color) !important; }
.cs2s_color_rarity_1 { color: var(--cs2s-rarity-1-color) !important; }
.cs2s_color_quality_1 { color: var(--cs2s-stattrak-color) !important; }
.cs2s_color_quality_2 { color: var(--cs2s-quality-12-color) !important; }
.cs2s_color_quality_3 { color: var(--cs2s-quality-3-color) !important; }
.cs2s_color_quality_4 { color: var(--cs2s-quality-3-color) !important; }
.cs2s_asset_wear {
position: absolute;
bottom: 0px;
right: 0px;
left: 0px;
padding-right: 4px;
text-align: right;
text-overflow: ellipsis;
font-size: 8pt;
max-width: 100%;
color: #b7becd;
&::after {
content: "";
position: absolute;
top: 0;
right: 2px;
left: 2px;
height: 4px;
border-radius: 4px;
opacity: 85%;
}
.cs2s_asset_wear_name {
position: absolute;
z-index: 1;
bottom: 12px;
right: 6px;
font-size: 8pt;
font-weight: 800;
opacity: 95%;
text-shadow: 0px 2px 4px #000000bf;
&::before {
content: '';
position: absolute;
top: 4px;
left: -6px;
width: 0;
height: 0;
border: 8px solid transparent;
border-radius: 100%;
transform: rotate(315deg);
}
}
&.cs2s_asset_wear_fn {
color: color-mix(in srgb, var(--cs2s-wear-fn-color), #cdcdcd 66%);
text-shadow: -3px -1px 10px var(--cs2s-wear-fn-color);
background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 85%) 2px);
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 40%), transparent);
}
.cs2s_asset_wear_name {
color: var(--cs2s-wear-fn-color);
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 40%);
border-right-color: color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 65%);
}
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-fn-color), transparent 40%), transparent);
}
}
}
&.cs2s_asset_wear_mw {
color: color-mix(in srgb, var(--cs2s-wear-mw-color), #cdcdcd 66%);
text-shadow: -3px -1px 10px var(--cs2s-wear-mw-color);
background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 85%) 2px);
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 40%), transparent);
}
.cs2s_asset_wear_name {
color: var(--cs2s-wear-mw-color);
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 40%);
border-right-color: color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 65%);
}
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-mw-color), transparent 40%), transparent);
}
}
}
&.cs2s_asset_wear_ft {
color: color-mix(in srgb, var(--cs2s-wear-ft-color), #cdcdcd 66%);
text-shadow: -3px -1px 10px var(--cs2s-wear-ft-color);
background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 85%) 2px);
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 40%), transparent);
}
.cs2s_asset_wear_name {
color: var(--cs2s-wear-ft-color);
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 40%);
border-right-color: color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 65%);
}
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ft-color), transparent 40%), transparent);
}
}
}
&.cs2s_asset_wear_ww {
color: color-mix(in srgb, var(--cs2s-wear-ww-color), #cdcdcd 66%);
text-shadow: -3px -1px 10px var(--cs2s-wear-ww-color);
background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 85%) 2px);
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 40%), transparent);
}
.cs2s_asset_wear_name {
color: var(--cs2s-wear-ww-color);
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 40%);
border-right-color: color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 65%);
}
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-ww-color), transparent 40%), transparent);
}
}
}
&.cs2s_asset_wear_bs {
color: color-mix(in srgb, var(--cs2s-wear-bs-color), #cdcdcd 66%);
text-shadow: -3px -1px 10px var(--cs2s-wear-bs-color);
background: repeating-linear-gradient(transparent, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 85%) 2px, transparent, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 85%) 2px);
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 40%), transparent);
}
.cs2s_asset_wear_name {
color: var(--cs2s-wear-bs-color);
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 40%);
border-right-color: color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 65%);
}
&::after {
background: linear-gradient(180deg, color-mix(in srgb, var(--cs2s-wear-bs-color), transparent 40%), transparent);
}
}
}
}
.cs2s_asset_seed {
position: absolute;
top: 0px;
right: 0px;
padding-right: 4px;
font-size: 8pt;
max-width: 100%;
}
.cs2s_asset_rarity {
position: absolute;
top: 0px;
left: 0px;
bottom: 11px;
right: 6px;
&::before {
content: '';
position: absolute;
top: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 15px 20px 0 0;
border-color: transparent;
}
&::after {
position: absolute;
left: 1px;
top: 0;
padding: 0px 0px 1px 3px;
font-size: 8pt;
font-weight: 500;
text-shadow: 0px 2px 4px #000000bf;
}
&.cs2s_asset_stattrak {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-stattrak-color), transparent 65%) !important;
}
&::after {
color: var(--cs2s-stattrak-color) !important;
}
}
&.cs2s_asset_quality_3 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-quality-3-color), transparent 65%) !important;
}
&::after {
content: '\u2605' !important;
color: var(--cs2s-quality-3-color) !important;
}
}
&.cs2s_asset_quality_12 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-quality-12-color), transparent 65%) !important;
}
&::after {
color: var(--cs2s-quality-12-color) !important;
}
}
&.cs2s_asset_rarity_7 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-7-color), transparent 65%);
}
&::after {
content: '7';
color: var(--cs2s-rarity-7-color);
}
}
&.cs2s_asset_rarity_6 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-6-color), transparent 65%);
}
&::after {
content: '6';
color: var(--cs2s-rarity-6-color);
}
}
&.cs2s_asset_rarity_5 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-5-color), transparent 65%);
}
&::after {
content: '5';
color: var(--cs2s-rarity-5-color);
}
}
&.cs2s_asset_rarity_4 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-4-color), transparent 65%);
}
&::after {
content: '4';
color: var(--cs2s-rarity-4-color);
}
}
&.cs2s_asset_rarity_3 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-3-color), transparent 65%);
}
&::after {
content: '3';
color: var(--cs2s-rarity-3-color);
}
}
&.cs2s_asset_rarity_2 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-2-color), transparent 65%);
}
&::after {
content: '2';
color: var(--cs2s-rarity-2-color);
}
}
&.cs2s_asset_rarity_1 {
&::before {
border-top-color: color-mix(in srgb, var(--cs2s-rarity-1-color), transparent 65%);
}
&::after {
content: '1';
color: var(--cs2s-rarity-1-color);
}
}
}
.cs2s_asset_quantity {
position: absolute;
top: 0px;
left: 0px;
padding-left: 4px;
font-size: 8pt;
max-width: 100%;
}
.cs2s_asset_name {
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
padding: 1px 4px 0px 4px;
overflow: hidden;
margin: 4px;
border-radius: 2px;
border-bottom: 2px solid #5f6a76;
font-size: 9pt;
max-width: 100%;
color: #b7becd;
text-shadow: 0px 2px 4px #000000bf;
text-overflow: ellipsis;
text-align: center;
background: #505050bf;
background-image: radial-gradient( #b7becd0d 1px, transparent 0);
background-size: 4px 4px;
background-position: -4px -3px;
}
.cs2s_asset_cosmetics {
position: absolute;
bottom: 14px;
left: 0px;
img {
height: 19px;
width: 25px !important;
filter: drop-shadow(0px 0px 0px #1c1c23);
}
&:has(> :nth-child(2)):has(> :nth-child(-n+5):last-child) img:nth-child(n+2) {
margin-left: -8px;
}
&:has(> :nth-child(6)) img:nth-child(n+2) {
margin-left: -12px;
}
}
.cs2s_asset_sticker_wear, .cs2s_asset_charm_template {
position: relative;
display: inline-block;
padding-bottom: 16px;
&::before {
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
}
&.cs2s_asset_cosmetic_small {
padding-bottom: 0px;
top: -6px;
&::before {
bottom: -12px;
font-size: 11px;
text-align: center;
}
}
}
.cs2s_asset_sticker_wear::before {
content: attr(wear) '%';
}
.cs2s_asset_charm_template::before {
content: attr(template);
}
.cs2s_asset_wear_range {
margin: 0px 0px 8px 4px;
& > div {
width: 50px;
height: 4px;
display: inline-block;
position: relative;
background: linear-gradient(360deg, rgb(50 50 50 / 40%), transparent);
&:not(:last-child) {
border-right: 1px solid #1d1d1dbf;
}
&.cs2s_asset_wear_range_left, &.cs2s_asset_wear_range_right, &.cs2s_asset_wear_range_empty {
background-color: #91919180 !important;
}
&.cs2s_asset_wear_range_left::before, &.cs2s_asset_wear_range_right::before {
content: "";
width: var(--wear-percentage);
height: 100%;
display: block;
position: absolute;
background: linear-gradient(360deg, rgb(50 50 50 / 40%), transparent);
}
&.cs2s_asset_wear_range_left::before {
left: 0px;
}
&.cs2s_asset_wear_range_right::before {
right: 0px;
}
&.cs2s_asset_wear_range_fn {
border-radius: 4px 0px 0px 4px;
background-color: var(--cs2s-wear-fn-color);
&::before {
background-color: var(--cs2s-wear-fn-color);
}
& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
background-color: var(--cs2s-wear-fn-color);
}
}
&.cs2s_asset_wear_range_mw {
background-color: var(--cs2s-wear-mw-color);
&::before {
background-color: var(--cs2s-wear-mw-color);
}
& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
background-color: var(--cs2s-wear-mw-color);
}
}
&.cs2s_asset_wear_range_ft {
background-color: var(--cs2s-wear-ft-color);
&::before {
background-color: var(--cs2s-wear-ft-color);
}
& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
background-color: var(--cs2s-wear-ft-color);
}
}
&.cs2s_asset_wear_range_ww {
background-color: var(--cs2s-wear-ww-color);
&::before {
background-color: var(--cs2s-wear-ww-color);
}
& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
background-color: var(--cs2s-wear-ww-color);
}
}
&.cs2s_asset_wear_range_bs {
border-radius: 0px 4px 4px 0px;
background-color: var(--cs2s-wear-bs-color);
&::before {
background-color: var(--cs2s-wear-bs-color);
}
& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
background-color: var(--cs2s-wear-bs-color);
}
}
}
& .cs2s_asset_wear_range_low, .cs2s_asset_wear_range_high {
position: absolute;
top: -2px;
bottom: -2px;
width: 2px;
&::before {
content: attr(wear_value);
position: absolute;
bottom: 6px;
left: -2px;
font-size: 8pt;
}
}
& .cs2s_asset_wear_range_low {
right: var(--wear-percentage);
transform: translate(50%, 0%);
}
& .cs2s_asset_wear_range_high {
left: var(--wear-percentage);
transform: translate(-50%, 0%);
}
& .cs2s_asset_wear_range_marker {
position: absolute;
top: 3px;
left: var(--wear-percentage);
transform: translate(-50%, 0%);
width: 0;
height: 0;
border-style: solid;
border-width: 0px 5px 5px 5px;
border-color: transparent;
border-bottom-color: white;
}
}
.cs2s_asset_rank_gold {
background: linear-gradient( #ffe34b 50%, #ff8f00);
background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 1px 1px 10px #ffe34b40, 1px 1px 10px #ff8f0040;
border-color: #ffe34b;
}
.cs2s_asset_rank_silver {
background: linear-gradient( #ffffff 50%, #fdfdfd40);
background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 1px 1px 10px #ffffff40, 1px 1px 10px #fdfdfd40;
border-color: #ffffff;
}
.cs2s_asset_rank_bronze {
background: linear-gradient( #e7913d 50%, #bb2f0f);
background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 1px 1px 10px #e7913d40, 1px 1px 10px #bb2f0f40;
border-color: #e7913d;
}
.cs2s_asset_rank_rust {
background: linear-gradient( #ff5716 50%, #daddb2);
background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 1px 1px 10px #ff57161a, 1px 1px 10px #daddb21a, #9d242480 -1px -1px 0px;
border-color: #ff5716;
}
.cs2s_listing_info {
width: 250px;
padding: 10px 8px 0px 0px;
font-size: 14px;
& + br + div {
border-left: 1px solid #404040;
padding-left: 16px !important;
}
}
.cs2s_has_tooltip {
border-bottom-width: 1px;
border-bottom-style: dashed;
}
.cs2s_tooltip {
position: absolute;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
z-index: 9999;
background: #c2c2c2;
color: #3d3d3f;
font-size: 11px;
border-radius: 3px;
padding: 5px;
max-width: 300px;
white-space: normal;
box-shadow: 0 0 3px #000000;
}
.cs2s_popup_opened {
overflow: hidden;
}
.cs2s_popup_background {
position: fixed;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: #000000;
opacity: 80%;
}
.cs2s_popup_container {
position: fixed;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
display: flex;
justify-content: center;
align-items: center;
}
.cs2s_popup_body {
position: fixed;
background: radial-gradient(circle at top left, rgba(74, 81, 92, 0.4) 0%, rgba(75, 81, 92, 0) 60%), #25282e;
&:not(.cs2s_popup_body_simple) {
padding-top: 3px;
&::after {
content: "";
position: absolute;
top: 0px;
left: 0px;
right: 0px;
height: 1px;
background: linear-gradient(to right, #00ccff, #3366ff);
}
.cs2s_popup_title {
padding: 24px;
font-size: 22px;
font-weight: 700;
color: #ffffff;
}
}
&.cs2s_popup_body_simple .cs2s_popup_title {
min-width: 400px;
padding: 16px;
font-size: 20px;
font-weight: 500;
text-align: center;
color: #fff;
background: #1b1b2280;
}
&.cs2s_popup_body_popover {
box-shadow: 0px 0px 16px 8px #00000060;
}
&:has(.cs2s_popup_footer) {
border-radius: 0px 0px 10px 10px;
margin-bottom: 64px;
}
}
.cs2s_popup_close_button {
float: right;
height: 16px;
width: 16px;
margin-top: 9px;
margin-right: 9px;
cursor: pointer;
opacity: 70%;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVBREZBRDlBNzdCNzExRTI5ODAzRUE3MDU0Mzk5MjM5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVBREZBRDlCNzdCNzExRTI5ODAzRUE3MDU0Mzk5MjM5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NUFERkFEOTg3N0I3MTFFMjk4MDNFQTcwNTQzOTkyMzkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NUFERkFEOTk3N0I3MTFFMjk4MDNFQTcwNTQzOTkyMzkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4iulRzAAABPElEQVR42mI8cuQIAyWABUqbAXEylH0fiDtwqI8FYhsoewEQH4cZcBaI64DYG8p/AVWADDyAeD4QMwPxJiA+BRJkgkr+BeJoIL4D5U8DYi0kzepAvAKq+TJU7V9kA0DgIxD7Q2lOIF4NpfmBeAuUfg3EPkD8BaaJCc2Z14A4EcoGuWAC1NkqQPwLqvkRsgYmLAG1HoiboOw0IA6EshNh/iZkAAjUA/FBJP5KIF6GTSEuAwygUQsDflAxogwQAuJ10AAExcpNKHsjEIsSMoAZGl2K0EALBeIIKFsOKSpxGtACxK5Qdi4QX4DiAqiYExB34TIgBIgrkAJtFpLcdKgYCBQBcRRMghGamUBxfhKIeaB+NkFOLFAAkjsDTZXfgdgK5DpYXvBGiqYpWDQzQMVAYZKDlDcuMFKanQECDAAqw0LA+GRiqAAAAABJRU5ErkJggg==);
&:hover {
opacity: 100%;
}
}
.cs2s_table_title_casket {
color: #919191;
&::before {
content: "";
background: url(https://community.fastly.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxqAhWSVieFOX71szWCgwsdlZRsuz0L1M1iqrOIGUauNiyzdmKxKWsMrnXkjlQsIthhO5eh9dfdg/66x45);
width: 66px;
height: 45px;
display: inline-block;
vertical-align: middle;
filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
}
&.cs2s_table_title_casket_multiple {
position: relative;
margin-left: 16px;
&::before {
margin-right: 12px;
}
&::after {
content: "";
background: url(https://community.fastly.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxqAhWSVieFOX71szWCgwsdlZRsuz0L1M1iqrOIGUauNiyzdmKxKWsMrnXkjlQsIthhO5eh9dfdg/45x31);
width: 82px;
height: 31px;
display: inline-block;
vertical-align: middle;
filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
position: absolute;
left: -14px;
top: -1px;
z-index: -1;
opacity: 85%;
}
}
}
.cs2s_table_container {
outline: 0;
overflow-y: scroll;
border-radius: 0px 0px 10px 10px;
}
.cs2s_table {
user-select: none;
width: 100%;
border-spacing: 0px;
.cs2s_table_image_column {
width: 93px;
}
.cs2s_table_name_column {
width: 350px;
}
.cs2s_table_collection_column {
width: 250px;
}
.cs2s_table_float_column {
width: 275px;
}
.cs2s_table_seed_column {
width: 150px;
}
.cs2s_table_crate_column {
width: 230px;
padding-right: 20px;
white-space: nowrap;
}
td {
border-bottom: 1px solid #1c1c23;
&:nth-child(n+2) {
padding-left: 8px;
}
}
thead {
tr {
height: 30px;
}
th {
position: sticky;
top: 1px;
background: #1c1c23;
z-index: 2;
text-align: left;
&:nth-child(n+2) {
padding-left: 8px;
border-left: 1px solid #3d3d3d;
}
&:before {
content: "";
position: absolute;
top: -1px;
left: -1px;
right: 0px;
height: 1px;
background: #1c1c23;
border-left: 1px solid #3d3d3d;
}
}
}
tbody {
will-change: transform;
}
tbody tr {
height: 69px;
color: #bdbdbd;
user-select: none;
&.cs2s_table_row_selected {
background: #a3cbe3;
color: #3c3f44;
td {
border-color: #badbdb
}
}
.cs2s_table_image_column {
position: relative;
padding-left: 4px;
img {
height: 62px;
width: 93px;
display: block;
}
.cs2s_table_image_column_cosmetics {
position: absolute;
bottom: -2px;
left: 2px;
white-space: nowrap;
img {
width: 25px;
height: 19px;
display: inline-block;
}
&:has(> :nth-child(2)):has(> :nth-child(-n+5):last-child) img:nth-child(n+2) {
margin-left: -8px;
}
&:has(> :nth-child(6)) img:nth-child(n+2) {
margin-left: -12px;
}
}
}
&:not(.cs2s_table_row_selected) .cs2s_table_image_column {
& > img {
filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
clip-path: rect(0px 100px 66px 0px);
}
.cs2s_table_image_column_cosmetics img {
filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(4px 0px 4px #1c1c23);
}
}
.cs2s_table_name_column {
a {
position: relative;
top: 1px;
left: 2px;
opacity: 75%;
color: #ffffff;
svg {
height: 12px;
width: 12px;
}
}
}
&.cs2s_table_row_selected .cs2s_table_name_column a {
color: #000000;
}
.cs2s_table_collection_column {
padding-left: 30px !important;
&.cs2s_table_collection_column_has_rarity {
position: relative;
&::after{
position: absolute;
font-size: 8pt;
font-weight: 800;
left: 5px;
top: 50%;
width: 21px;
text-align: center;
transform: translate(0%, -50%);
}
&.cs2s_table_collection_column_rarity_7::after {
content: "7";
color: var(--cs2s-rarity-7-color);
}
&.cs2s_table_collection_column_rarity_6::after {
content: "6";
color: var(--cs2s-rarity-6-color);
}
&.cs2s_table_collection_column_rarity_5::after {
content: "5";
color: var(--cs2s-rarity-5-color);
}
&.cs2s_table_collection_column_rarity_4::after {
content: "4";
color: var(--cs2s-rarity-4-color);
}
&.cs2s_table_collection_column_rarity_3::after {
content: "3";
color: var(--cs2s-rarity-3-color);
}
&.cs2s_table_collection_column_rarity_2::after {
content: "2";
color: var(--cs2s-rarity-2-color);
}
&.cs2s_table_collection_column_rarity_1::after {
content: "1";
color: var(--cs2s-rarity-1-color);
}
&.cs2s_table_collection_column_stattrak::after {
color: var(--cs2s-stattrak-color);
}
&.cs2s_table_collection_column_quality_3::after {
content: "\u2605";
color: var(--cs2s-quality-3-color);
}
&.cs2s_table_collection_column_quality_12::after {
color: var(--cs2s-quality-12-color);
}
}
}
&.cs2s_table_row_selected .cs2s_table_collection_column_has_rarity::after {
color: #3c3f44 !important;
}
&:not(.cs2s_table_row_selected) .cs2s_table_collection_column_has_rarity::after {
text-shadow: 2px 4px 6px #1c1c23;
}
.cs2s_table_float_column {
padding-left: 36px !important;
font-variant-numeric: tabular-nums;
&.cs2s_table_float_column_has_float {
position: relative;
&::after{
position: absolute;
font-size: 8pt;
font-weight: 800;
top: 50%;
left: 8px;
width: 22px;
text-align: center;
transform: translate(0%, -50%);
}
&.cs2s_table_float_column_float_fn::after {
content: "FN";
color: var(--cs2s-wear-fn-color);
}
&.cs2s_table_float_column_float_mw::after {
content: "MW";
color: var(--cs2s-wear-mw-color);
}
&.cs2s_table_float_column_float_ft::after {
content: "FT";
color: var(--cs2s-wear-ft-color);
}
&.cs2s_table_float_column_float_ww::after {
content: "WW";
color: var(--cs2s-wear-ww-color);
}
&.cs2s_table_float_column_float_bs::after {
content: "BS";
color: var(--cs2s-wear-bs-color);
}
}
}
&.cs2s_table_row_selected .cs2s_table_float_column_has_float::after {
color: #3c3f44 !important;
}
&:not(.cs2s_table_row_selected) .cs2s_table_float_column_has_float::after {
text-shadow: 2px 4px 6px #1c1c23;
}
.cs2s_table_empty {
height: 150px;
font-size: 20px;
font-weight: 500;
text-align: center;
border-bottom-width: 0px;
}
}
.cs2s_table_column {
cursor: pointer;
user-select: none;
&:hover {
color: #ffffff;
}
&:has(.cs2s_table_column_sort_asc), &:has(.cs2s_table_column_sort_desc) {
color: #3a8dde;
&:hover {
color: #4aa6ff;
}
}
}
.cs2s_table_column_sort {
position: relative;
display: inline-block;
height: 15px;
width: 15px;
vertical-align: text-bottom;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23595959' width='800px' height='800px' viewBox='0 0 36.678 36.678' %3E%3Cg%3E%3Cpath d='M29.696,20.076c0.088,0.16,0.08,0.354-0.021,0.51L19.395,36.449c-0.091,0.139-0.241,0.224-0.407,0.229 c-0.004,0-0.008,0-0.015,0c-0.157,0-0.31-0.076-0.403-0.205L6.998,20.609c-0.11-0.15-0.127-0.354-0.041-0.521 c0.085-0.168,0.257-0.272,0.444-0.272h21.855C29.443,19.814,29.609,19.914,29.696,20.076z M7.401,16.865h21.855 c0.008,0,0.017,0,0.021,0c0.275,0,0.5-0.225,0.5-0.5c0-0.156-0.07-0.295-0.184-0.388L18.086,0.205 C17.989,0.072,17.821,0.002,17.668,0c-0.165,0.005-0.315,0.09-0.406,0.229L6.982,16.094c-0.101,0.152-0.105,0.35-0.021,0.512 C7.05,16.765,7.218,16.865,7.401,16.865z'/%3E%3C/g%3E%3C/svg%3E");
background-size: 15px 15px;
margin: 0px 4px;
pointer-events: none;
&.cs2s_table_column_sort_asc::before, &.cs2s_table_column_sort_desc::before {
content: "";
position: absolute;
inset: 0;
display: block;
height: 7px;
width: 15px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%233a8dde' width='800px' height='800px' viewBox='0 0 36.678 36.678' %3E%3Cg%3E%3Cpath d='M29.696,20.076c0.088,0.16,0.08,0.354-0.021,0.51L19.395,36.449c-0.091,0.139-0.241,0.224-0.407,0.229 c-0.004,0-0.008,0-0.015,0c-0.157,0-0.31-0.076-0.403-0.205L6.998,20.609c-0.11-0.15-0.127-0.354-0.041-0.521 c0.085-0.168,0.257-0.272,0.444-0.272h21.855C29.443,19.814,29.609,19.914,29.696,20.076z M7.401,16.865h21.855 c0.008,0,0.017,0,0.021,0c0.275,0,0.5-0.225,0.5-0.5c0-0.156-0.07-0.295-0.184-0.388L18.086,0.205 C17.989,0.072,17.821,0.002,17.668,0c-0.165,0.005-0.315,0.09-0.406,0.229L6.982,16.094c-0.101,0.152-0.105,0.35-0.021,0.512 C7.05,16.765,7.218,16.865,7.401,16.865z'/%3E%3C/g%3E%3C/svg%3E");
background-size: 15px 15px;
}
&.cs2s_table_column_sort_desc::before {
top: 8px;
background-position-y: 7px;
}
}
.cs2s_table_column_search {
position: relative;
margin-left: 2px;
font-weight: normal;
font-size: 13px;
max-width: 275px;
&::before {
content: "";
display: inline-block;
position: absolute;
top: 4px;
left: 4px;
height: 13px;
width: 13px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%2396969696' width='800px' height='800px' viewBox='0 0 24 24'%3E%3Cpath d='M23.46,20.38l-5.73-5.73a9.52,9.52,0,1,0-2.83,2.83l5.73,5.73a1,1,0,0,0,1.41,0l1.41-1.41A1,1,0,0,0,23.46,20.38ZM9.75,15a5.5,5.5,0,1,1,5.5-5.5A5.51,5.51,0,0,1,9.75,15Z'/%3E%3C/svg%3E");
background-size: 13px;
pointer-events: none;
}
&::after {
padding-left: 42px;
}
input {
background: transparent;
border: none;
outline: none;
color: #969696;
border-bottom: 1px dashed #96969696;
padding-left: 22px;
font-family: inherit;
width: 100px;
min-width: 100px;
&::-webkit-search-cancel-button {
-webkit-appearance: none;
position: relative;
top: 1px;
height: 8px;
width: 8px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M1 1L11 11M11 1L1 11' stroke='%233a8dde' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
cursor: pointer;
}
}
&:has(input:not(:placeholder-shown)) {
&::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%233a8dde' width='800px' height='800px' viewBox='0 0 24 24'%3E%3Cpath d='M23.46,20.38l-5.73-5.73a9.52,9.52,0,1,0-2.83,2.83l5.73,5.73a1,1,0,0,0,1.41,0l1.41-1.41A1,1,0,0,0,23.46,20.38ZM9.75,15a5.5,5.5,0,1,1,5.5-5.5A5.51,5.51,0,0,1,9.75,15Z'/%3E%3C/svg%3E");
}
input {
color: #3a8dde;
border-color: #3a8dde;
}
}
}
}
.cs2s_table_footer {
height: 64px;
position: absolute;
top: 100%;
left: 0px;
right: 0px;
color: #bdbdbd;
display: flex;
justify-content: space-between;
align-items: center;
&::before {
content: "";
position: absolute;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
background: radial-gradient(ellipse at 68% 40%, #1c1c2380 -24%, #05080b80 66%);
backdrop-filter: blur(10px);
z-index: -1;
mask: linear-gradient(180deg, rgba(0, 0, 0, 0.9) 40%, transparent);
}
a, button {
border-radius: 20px;
& > span {
border-radius: 20px;
}
}
}
.cs2s_table_footer_element_left > * {
margin-right: 16px;
}
.cs2s_table_footer_element_right > * {
margin-left: 16px;
}
.cs2s_table_footer_selection_count {
font-weight: bold;
}
.cs2s_table_footer_action_link {
display: inline-block;
padding: 0px 18px 0px 12px;
margin-right: 8px;
border: 0px;
line-height: 28px;
background: #d7d7d7;
color: #272727;
font-size: 14px;
font-weight: bold;
text-shadow: none;
opacity: 95%;
cursor: pointer;
user-select: none;
&.cs2s_table_footer_action_link_active {
background: #3a8dde;
color: #fff;
&:hover {
background: #43a2ff;
}
}
&:hover {
background: #fff;
}
span {
display: inline-block;
svg {
height: 21px;
width: 21px;
display: inline-block;
vertical-align: top;
margin-right: 2px;
margin-top: 3px;
}
}
}
.cs2s_table_footer_input {
font-weight: bold;
input {
outline: none;
padding: 0px;
border-bottom: 1px dashed !important;
color: inherit !important;
&::-webkit-outer-spin-button, &::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
}
.cs2s_resizable_input {
display: inline-grid;
input {
font-size: inherit;
font-weight: inherit;
font-family: inherit;
grid-area: 1 / 2;
appearance: textfield;
}
&:after {
content: attr(data-value);
visibility: hidden;
grid-area: 1 / 2;
white-space: nowrap;
}
}
.cs2s_error_table_container {
max-height: 80vh;
width: 1250px;
user-select: auto;
table, tbody, tr, th, td {
user-select: auto !important;
}
th:first-child, td:first-child {
width: 250px;
padding-left: 16px;
white-space: nowrap;
}
th:nth-child(2), td:nth-child(2) {
width: 150px;
}
}
.cs2s_action_body {
padding: 16px;
display: flex;
flex-direction: column;
gap: 16px;
& > div {
margin: 0px auto;
}
}
.cs2s_action_item_window {
height: 120px;
width: 120px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
position: relative;
border-radius: 100%;
overflow: hidden;
background: #1b1b2280;
}
.cs2s_action_item_window_image {
display: inline-flex;
position: absolute;
left: 0px;
transform: translate(13px, 0px);
& > img {
filter: drop-shadow(0px 0px 0px #bdbdbd) drop-shadow(2px 4px 6px #1c1c23);
}
.cs2s_table_image_column_cosmetics {
position: absolute;
bottom: -5px;
left: -2px;
white-space: nowrap;
img {
width: 25px;
height: 19px;
display: inline-block;
}
&:has(> :nth-child(2)):has(> :nth-child(-n+5):last-child) img:nth-child(n+2) {
margin-left: -8px;
}
&:has(> :nth-child(6)) img:nth-child(n+2) {
margin-left: -12px;
}
}
}
.cs2s_action_message {
color: #969696;
font-size: 16px;
}
.cs2s_action_message_tall {
padding-top: 8px;
padding-bottom:12px;
}
.cs2s_action_multi_message {
max-width: 500px;
padding-left: 16px;
padding-right: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
.cs2s_action_buttons {
div:not(:first-child) {
margin-left: 16px;
}
}
.cs2s_action_progress_bar {
background: #1b1b2280;
padding: 6px;
border-radius: 12px;
width: 300px;
height: 25px;
&::before {
content: "";
display: block;
height: 100%;
width: var(--percentage);
min-width: 1px;
border-radius: 6px;
background: linear-gradient(to right, #47bfff 0%, #1a44c2 60%);
background-position: 25%;
background-size: 330% 100%;
transition: width 0.3s ease-in-out;
}
}
.cs2s_action_spinner {
width: 50px;
height: 50px;
border: 5px solid #a6a6ad80;
border-top-color: transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.cs2s_settings_form {
overflow: scroll;
padding: 0px 24px 24px 24px;
width: 900px;
max-height: 85vh;
}
.cs2s_settings_filter {
input::placeholder {
opacity: .75;
}
input[type=text]:not(:placeholder-shown), input[type=number]:not(:placeholder-shown), select:has(option:checked:not([value=""]):not([value="custom"])) {
outline: 1px solid #3a8dde;
}
}
.cs2s_settings_form_group_title {
padding: 0px 0px 6px 10px;
border-bottom: 2px solid rgba(228, 228, 228, .1);
font-size: 16px;
line-height: 28px;
text-transform: uppercase;
letter-spacing: 0;
color: #e4e4e4;
}
.cs2s_settings_form_group {
flex: 1;
padding: 24px 20px;
align-items: center;
}
.cs2s_settings_form_group_row {
display: flex;
justify-content: space-between;
flex-direction: row;
gap: 32px;
.cs2s_settings_form_group_item {
flex: 1;
}
}
.cs2s_settings_form_group_half_row {
display: flex;
justify-content: flex-start;
flex-direction: row;
gap: 32px;
}
.cs2s_settings_form_group_collection {
flex: 1;
position: relative;
margin: 8px 0px 10px;
&::before {
content: "";
position: absolute;
z-index: -1;
top: -4px;
bottom: 12px;
left: -12px;
right: -12px;
background-color: #2e3137;
}
}
.cs2s_settings_form_submit_group {
display: flex;
flex-direction: row-reverse;
button {
margin: 2px 0 2px 12px;
}
}
.cs2s_settings_form_group_item {
display: flex;
flex-direction: column;
margin-bottom: 22px;
label {
display: block;
margin-bottom: 4px;
font-size: 13px;
font-weight: 300;
line-height: 19px;
color: #acb2b8;
text-transform: uppercase;
letter-spacing: initial;
user-select: none;
}
&.cs2s_settings_form_group_item_checkbox {
flex-direction: row;
label {
flex: 1;
margin: 0;
padding: 4px 0px;
cursor: pointer;
white-space: nowrap;
}
}
input[type=text], input[type=number] {
display: block;
padding: 10px;
font-size: 14px;
line-height: 22px;
color: #909090;
background-color: rgba(0, 0, 0, .25);
border: none;
box-shadow: inset 1px 1px 0px #000a;
outline: 0;
&:disabled {
appearance: textfield;
}
}
input[type=checkbox] {
float: left;
width: 22px;
height: 22px;
margin-right: 8px;
padding: 0;
border-radius: 2px;
appearance: none;
background-color: #0004;
box-shadow: inset 1px .5px 3px rgba(1, 1, 1, .4);
cursor: pointer;
&:not(:disabled):hover {
background-color: #090909;
}
&:checked {
background-image: url('data:image/svg+xml,<svg version="1.1" id="base" xmlns="http://www.w3.org/2000/svg" class="SVGIcon_Button SVGIcon_DialogCheck" x="0px" y="0px" width="18px" height="18px" viewBox="0 0 256 256"><defs><linearGradient id="svgid_0" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="%2300ccff"></stop><stop offset="100%" stop-color="%232d73ff"></stop></linearGradient><filter id="svgid_1" x="0" y="0" width="200%" height="200%"><feOffset result="offOut" in="SourceAlpha" dx="20" dy="20"></feOffset><feGaussianBlur result="blurOut" in="offOut" stdDeviation="10"></feGaussianBlur><feBlend in="SourceGraphic" in2="blurOut" mode="normal"></feBlend></filter></defs><path fill="none" stroke="url(%23svgid_0)" stroke-width="24" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="10" d="M206.5,45.25L95,210.75l-45.5-63" stroke-dasharray="365.19 365.19" stroke-dashoffset="0.00"></path><path fill="none" opacity=".2" filter="url(%23svgid_1)" stroke="url(%23svgid_0)" stroke-width="24" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="10" d="M206.5,45.25L95,210.75l-45.5-63" stroke-dasharray="365.19 365.19" stroke-dashoffset="0.00"></path></svg>');
background-repeat: no-repeat;
background-position: 50% 50%;
}
}
select {
display: block;
padding: 10px;
font-size: 14px;
height: 42px;
color: #909090;
background-color: rgba(0, 0, 0, .25);
border: none;
border-right: 4px solid transparent;
box-shadow: inset 1px 1px 0px #000a;
outline: 0;
option, optgroup {
color: #909090;
background-color: #262931;
}
}
}
.cs2s_settings_form_message {
font-style: italic;
color: #909090;
}
.cs2s_settings_form_separator {
align-content: center;
font-weight: 800;
opacity: 0.5;
user-select: none;
}
.cs2s_settings_form_disabled {
opacity: 0.5;
input, select, label {
cursor: default !important;
outline: 0 !important;
}
}
.popup_menu_item {
display: block;
}
.cs2s_navigation_icon {
display: inline-block;
vertical-align: text-top;
height: 16px;
width: 47px;
svg {
height: 11px;
width: 50px;
}
}
.cs2s_navigation_status_error_glow {
animation: cs2s_glow 2s infinite ease-in-out;
}
@keyframes cs2s_glow {
0%, 100% {
box-shadow: 0 0 5px rgba(102, 192, 244, 0.4);
}
20% {
box-shadow: 0 0 10px rgba(102, 192, 244, 0.6);
}
40% {
box-shadow: 0 0 20px rgba(102, 192, 244, 0.9);
}
60% {
box-shadow: 0 0 5px rgba(102, 192, 244, 0.3);
}
80% {
box-shadow: 0 0 15px rgba(102, 192, 244, 0.8);
}
}
.cs2s_navigation_status_error_pulse {
animation: cs2s_pulse 2s infinite ease-in-out;
}
@keyframes cs2s_pulse {
0% {
transform: scale(1);
opacity: 0.75;
box-shadow: 0 0 0 0 rgba(102, 192, 244, 0.75);
}
50% {
transform: scale(1.1);
opacity: 1;
box-shadow: 0 0 10px 10px rgba(102, 192, 244, 0.3);
color: #66c0f4
}
100% {
transform: scale(1);
opacity: 0.75;
box-shadow: 0 0 0 0 rgba(102, 192, 244, 0);
}
}
.cs2s_grey_long_button {
display: inline-block;
width: 200px;
padding: 0;
line-height: 32px;
text-align: center;
font-size: 14px;
color: #dfe3e6;
background-color: #3d4450;
border: 0;
border-radius: 2px;
cursor: pointer;
&:hover {
color: #ffffff;
background-color: #464d58;
}
}
.cs2s_blue_long_button {
display: inline-block;
width: 200px;
padding: 0;
line-height: 32px;
text-align: center;
font-size: 14px;
color: #dfe3e6;
background: linear-gradient(to right, #47bfff 0%, #1a44c2 60%);
background-position: 25%;
background-size: 330% 100%;
border: 0;
border-radius: 2px;
cursor: pointer;
&:hover {
background: linear-gradient(to right, #47bfff 0%, #1a44c2 60%);
background-position: 0%;
background-size: 330% 100%;
}
}
.cs2s_green_button {
padding: 1px;
display: inline-block;
cursor: pointer;
color: #D2E885;
background: linear-gradient(to bottom, #07d03f 5%, #04692f 95%);
border-bottom-width: 0px;
span {
display: block;
padding: 0 24px;
font-size: 15px;
line-height: 30px;
background: linear-gradient(to bottom, #059917 5%, #04693b 95%);
}
&:not(.cs2s_button_disabled) {
&:hover {
color: #ffffff;
background: linear-gradient(to bottom, #08d92b 5%, #06a030 95%);
span {
background: linear-gradient(to bottom, #07bf2b 5%, #06a05e 95%);
}
}
}
&.cs2s_button_disabled {
opacity: 45%;
cursor: default;
}
}
`;
// src/main.js
{
const HAS_GM = typeof GM !== "undefined";
const NEW_GM = ((scope, GM2) => {
if (GM_info.scriptHandler !== "Tampermonkey" || compareVersions(GM_info.version, "5.3.2") < 0) return;
const GM_xmlhttpRequestOrig = GM_xmlhttpRequest;
const GM_xmlHttpRequestOrig = GM2.xmlHttpRequest;
function compareVersions(v1, v2) {
const parts1 = v1.split(".").map(Number);
const parts2 = v2.split(".").map(Number);
const length = Math.max(parts1.length, parts2.length);
for (let i = 0; i < length; i++) {
const num1 = parts1[i] || 0;
const num2 = parts2[i] || 0;
if (num1 > num2) return 1;
if (num1 < num2) return -1;
}
return 0;
}
function GM_xmlhttpRequestWrapper(odetails) {
if (odetails.redirect !== void 0) {
return GM_xmlhttpRequestOrig(odetails);
}
if (odetails.onprogress || odetails.fetch === false) {
console.warn("Fetch mode does not support onprogress in the background.");
}
const {
onload,
onloadend,
onerror,
onabort,
ontimeout,
...details
} = odetails;
const handleRedirects = (initialDetails) => {
const request = GM_xmlhttpRequestOrig({
...initialDetails,
redirect: "manual",
onload: function(response) {
if (response.status >= 300 && response.status < 400) {
const m = response.responseHeaders.match(/Location:\s*(\S+)/i);
const redirectUrl = m && m[1];
if (redirectUrl) {
const absoluteUrl = new URL(redirectUrl, initialDetails.url).href;
handleRedirects({ ...initialDetails, url: absoluteUrl });
return;
}
}
if (onload) onload.call(this, response);
if (onloadend) onloadend.call(this, response);
},
onerror: function(response) {
if (onerror) onerror.call(this, response);
if (onloadend) onloadend.call(this, response);
},
onabort: function(response) {
if (onabort) onabort.call(this, response);
if (onloadend) onloadend.call(this, response);
},
ontimeout: function(response) {
if (ontimeout) ontimeout.call(this, response);
if (onloadend) onloadend.call(this, response);
}
});
return request;
};
return handleRedirects(details);
}
function GM_xmlHttpRequestWrapper(odetails) {
let abort;
const p = new Promise((resolve, reject) => {
const { onload, ontimeout, onerror, ...send } = odetails;
send.onerror = function(r) {
if (onerror) {
resolve(r);
onerror.call(this, r);
} else {
reject(r);
}
};
send.ontimeout = function(r) {
if (ontimeout) {
resolve(r);
ontimeout.call(this, r);
} else {
reject(r);
}
};
send.onload = function(r) {
resolve(r);
if (onload) onload.call(this, r);
};
const a = GM_xmlhttpRequestWrapper(send).abort;
if (abort === true) {
a();
} else {
abort = a;
}
});
p.abort = () => {
if (typeof abort === "function") {
abort();
} else {
abort = true;
}
};
return p;
}
GM_xmlhttpRequest = GM_xmlhttpRequestWrapper;
scope.GM_xmlhttpRequestOrig = GM_xmlhttpRequestOrig;
const gopd = Object.getOwnPropertyDescriptor(GM2, "xmlHttpRequest");
if (gopd && gopd.configurable === false) {
return {
__proto__: GM2,
xmlHttpRequest: GM_xmlHttpRequestWrapper,
xmlHttpRequestOrig: GM_xmlHttpRequestOrig
};
} else {
GM2.xmlHttpRequest = GM_xmlHttpRequestWrapper;
GM2.xmlHttpRequestOrig = GM_xmlHttpRequestOrig;
}
})(window, HAS_GM ? GM : {});
if (HAS_GM && NEW_GM) GM = NEW_GM;
}
(async function() {
GM_addStyle(style_default);
await script_default.VerifyConnection();
const PAGE_INVENTORY = 0;
const PAGE_MARKET_LISTING = 1;
let currentPage = null;
if (window.location.href.includes("/market/listings")) {
currentPage = PAGE_MARKET_LISTING;
} else if (window.location.href.includes("/inventory")) {
currentPage = PAGE_INVENTORY;
}
if (currentPage == PAGE_INVENTORY) {
const IS_OWN_INVENTORY = unsafeWindow.g_ActiveUser.strSteamId == unsafeWindow.g_steamID;
if (IS_OWN_INVENTORY) {
const initInventory = () => {
if (initInventory.initialized) {
return;
}
initInventory.initialized = true;
script_default.GetInventory();
};
const allCratesButton = CreateElement("a", {
class: "btn_darkblue_white_innerfade btn_medium",
style: {
marginRight: "12px"
},
html: "<span>Retrieve All Stored Items</span>",
onclick: async () => {
const inventory = await script_default.GetInventory({ showProgress: true });
if (inventory === OPERATION_ERROR.INTERFACE_NOT_CONNECTED) {
script_default.ShowStartInterfacePrompt({
message: "Interface must be running to fetch stored items",
fade: false
});
return;
}
if (inventory === OPERATION_ERROR.INVENTORY_FAILED_TO_LOAD) {
script_default.ShowError({ level: ERROR_LEVEL.HIGH }, new Error("Inventory failed to load, check error logs and refresh the page to try again"));
return;
}
if (!(inventory instanceof Inventory)) {
return;
}
const table = new Table(inventory.storedItems.slice(), inventory, {
mode: Table.MODE.RETRIEVE,
casketName: "All Storage Units",
multiCasket: true
});
table.Show();
}
});
const originalShowItemInventory = unsafeWindow.ShowItemInventory;
unsafeWindow.ShowItemInventory = function(appid) {
const result = originalShowItemInventory.call(this, ...arguments);
if (appid == CS2_APPID) {
initInventory();
!allCratesButton.isConnected && unsafeWindow.document.getElementsByClassName("inventory_rightnav")[0].prepend(allCratesButton);
} else {
allCratesButton.isConnected && allCratesButton.remove();
}
return result;
};
if (unsafeWindow.g_ActiveInventory.appid == CS2_APPID) {
initInventory();
unsafeWindow.document.getElementsByClassName("inventory_rightnav")[0].prepend(allCratesButton);
}
}
{
const handleInventoryAssets = () => {
if (!handleInventoryAssets.handledAssetIDs) {
handleInventoryAssets.handledAssetIDs = /* @__PURE__ */ new Set();
}
if (!unsafeWindow.g_rgAppContextData[CS2_APPID].rgContexts[2].inventory?.m_rgAssets) {
return;
}
for (const element of unsafeWindow.g_rgAppContextData[CS2_APPID].rgContexts[2].inventory.m_rgItemElements) {
const asset = element?.[0]?.rgItem;
if (!asset) {
continue;
}
const assetid = asset.assetid;
if (handleInventoryAssets.handledAssetIDs.has(assetid)) {
continue;
}
handleInventoryAssets.handledAssetIDs.add(assetid);
const inventoryAsset = new InventoryAsset(asset);
inventoryAsset.BuildInventoryUI();
}
};
const originalAddInventoryData = unsafeWindow.CInventory.prototype.AddInventoryData;
unsafeWindow.CInventory.prototype.AddInventoryData = function(data) {
const result = originalAddInventoryData.call(this, ...arguments);
if (data?.assets?.[0]?.appid == CS2_APPID) {
handleInventoryAssets();
}
return result;
};
handleInventoryAssets();
}
{
const handleSelectedAsset = (asset) => {
const inventoryAsset = new InventoryAsset(asset);
inventoryAsset.BuildSelectedUI();
};
const originalSelectItem = unsafeWindow.CInventory.prototype.SelectItem;
unsafeWindow.CInventory.prototype.SelectItem = function(a, b, asset) {
const result = originalSelectItem.call(this, ...arguments);
if (asset.appid == CS2_APPID) {
handleSelectedAsset(asset);
}
return result;
};
if (unsafeWindow.g_ActiveInventory.selectedItem?.appid == CS2_APPID) {
handleSelectedAsset(unsafeWindow.g_ActiveInventory.selectedItem);
}
}
} else if (currentPage == PAGE_MARKET_LISTING) {
const IS_CS2_ITEM = !!unsafeWindow.g_rgAppContextData?.[CS2_APPID];
const HAS_INDIVIDUAL_LISTINGS = Object.values(unsafeWindow.g_rgAssets?.[CS2_APPID]?.[2])[0]?.commodity == 0;
if (!IS_CS2_ITEM || !HAS_INDIVIDUAL_LISTINGS) {
return;
}
{
const handleMarketAssets = () => {
if (!unsafeWindow.g_rgAssets?.[CS2_APPID]?.[2] || !unsafeWindow.g_rgListingInfo) {
return;
}
for (const listing of Object.values(unsafeWindow.g_rgListingInfo)) {
const asset = unsafeWindow.g_rgAssets[CS2_APPID][2][listing.asset?.id];
if (!asset) {
continue;
}
const marketAsset = new MarketAsset(asset, listing);
marketAsset.BuildListingUI();
}
};
const originalOnResponseRenderResults = unsafeWindow.CAjaxPagingControls.prototype.OnResponseRenderResults;
unsafeWindow.CAjaxPagingControls.prototype.OnResponseRenderResults = function() {
const result = originalOnResponseRenderResults.call(this, ...arguments);
handleMarketAssets();
return result;
};
handleMarketAssets();
}
}
})();
})();