@ianlucas/cs2-lib 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/License.txt +21 -0
- package/README.md +26 -0
- package/assets/translations/items-brazilian.json +1 -0
- package/assets/translations/items-bulgarian.json +1 -0
- package/assets/translations/items-czech.json +1 -0
- package/assets/translations/items-danish.json +1 -0
- package/assets/translations/items-dutch.json +1 -0
- package/assets/translations/items-english.json +1 -0
- package/assets/translations/items-finnish.json +1 -0
- package/assets/translations/items-french.json +1 -0
- package/assets/translations/items-german.json +1 -0
- package/assets/translations/items-greek.json +1 -0
- package/assets/translations/items-hungarian.json +1 -0
- package/assets/translations/items-italian.json +1 -0
- package/assets/translations/items-japanese.json +1 -0
- package/assets/translations/items-koreana.json +1 -0
- package/assets/translations/items-latam.json +1 -0
- package/assets/translations/items-norwegian.json +1 -0
- package/assets/translations/items-polish.json +1 -0
- package/assets/translations/items-portuguese.json +1 -0
- package/assets/translations/items-romanian.json +1 -0
- package/assets/translations/items-russian.json +1 -0
- package/assets/translations/items-schinese.json +1 -0
- package/assets/translations/items-spanish.json +1 -0
- package/assets/translations/items-swedish.json +1 -0
- package/assets/translations/items-tchinese.json +1 -0
- package/assets/translations/items-thai.json +1 -0
- package/assets/translations/items-turkish.json +1 -0
- package/assets/translations/items-ukrainian.json +1 -0
- package/assets/translations/items-vietnamese.json +1 -0
- package/dist/economy-case.d.ts +17 -0
- package/dist/economy-case.js +51 -0
- package/dist/economy.d.ts +140 -0
- package/dist/economy.js +467 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +12 -0
- package/dist/inventory.d.ts +82 -0
- package/dist/inventory.js +379 -0
- package/dist/items.d.ts +2 -0
- package/dist/items.js +7 -0
- package/dist/keyvalues.d.ts +1 -0
- package/dist/keyvalues.js +93 -0
- package/dist/maps.d.ts +20 -0
- package/dist/maps.js +88 -0
- package/dist/teams.d.ts +6 -0
- package/dist/teams.js +13 -0
- package/dist/util.d.ts +5 -0
- package/dist/util.js +15 -0
- package/dist/veto.d.ts +26 -0
- package/dist/veto.js +111 -0
- package/package.json +38 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const CS_RARITY_COMMON_COLOR = "#b0c3d9";
|
|
2
|
+
export declare const CS_RARITY_UNCOMMON_COLOR = "#5e98d9";
|
|
3
|
+
export declare const CS_RARITY_RARE_COLOR = "#4b69ff";
|
|
4
|
+
export declare const CS_RARITY_MYTHICAL_COLOR = "#8847ff";
|
|
5
|
+
export declare const CS_RARITY_LEGENDARY_COLOR = "#d32ce6";
|
|
6
|
+
export declare const CS_RARITY_ANCIENT_COLOR = "#eb4b4b";
|
|
7
|
+
export declare const CS_RARITY_IMMORTAL_COLOR = "#e4ae39";
|
|
8
|
+
export declare const CS_RARITY_COLORS: Record<string, string>;
|
|
9
|
+
export declare const CS_RARITY_FOR_SOUNDS: Record<string, string>;
|
|
10
|
+
export declare const CS_RARITY_COLOR_DEFAULT = 0;
|
|
11
|
+
export declare const CS_RARITY_COLOR_ORDER: Record<string, number | undefined>;
|
|
12
|
+
export declare const CS_RARITIES: readonly ["common", "uncommon", "rare", "mythical", "legendary", "ancient", "immortal"];
|
|
13
|
+
export declare const CS_RARITY_ORDER: readonly ["common", "uncommon", "rare", "mythical", "legendary", "ancient", "immortal", "special"];
|
|
14
|
+
export declare const CS_BASE_ODD = 0.8;
|
|
15
|
+
export declare const CS_STATTRAK_ODD = 0.1;
|
|
16
|
+
export declare function CS_randomFloat(min: number, max: number): number;
|
|
17
|
+
export declare function CS_randomInt(min: number, max: number): number;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Ian Lucas. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
export const CS_RARITY_COMMON_COLOR = "#b0c3d9";
|
|
6
|
+
export const CS_RARITY_UNCOMMON_COLOR = "#5e98d9";
|
|
7
|
+
export const CS_RARITY_RARE_COLOR = "#4b69ff";
|
|
8
|
+
export const CS_RARITY_MYTHICAL_COLOR = "#8847ff";
|
|
9
|
+
export const CS_RARITY_LEGENDARY_COLOR = "#d32ce6";
|
|
10
|
+
export const CS_RARITY_ANCIENT_COLOR = "#eb4b4b";
|
|
11
|
+
export const CS_RARITY_IMMORTAL_COLOR = "#e4ae39";
|
|
12
|
+
export const CS_RARITY_COLORS = {
|
|
13
|
+
[CS_RARITY_COMMON_COLOR]: "common",
|
|
14
|
+
[CS_RARITY_UNCOMMON_COLOR]: "uncommon",
|
|
15
|
+
[CS_RARITY_RARE_COLOR]: "rare",
|
|
16
|
+
[CS_RARITY_MYTHICAL_COLOR]: "mythical",
|
|
17
|
+
[CS_RARITY_LEGENDARY_COLOR]: "legendary",
|
|
18
|
+
[CS_RARITY_ANCIENT_COLOR]: "ancient",
|
|
19
|
+
[CS_RARITY_IMMORTAL_COLOR]: "immortal"
|
|
20
|
+
};
|
|
21
|
+
export const CS_RARITY_FOR_SOUNDS = {
|
|
22
|
+
[CS_RARITY_COMMON_COLOR]: "common",
|
|
23
|
+
[CS_RARITY_UNCOMMON_COLOR]: "uncommon",
|
|
24
|
+
[CS_RARITY_RARE_COLOR]: "rare",
|
|
25
|
+
[CS_RARITY_MYTHICAL_COLOR]: "mythical",
|
|
26
|
+
[CS_RARITY_LEGENDARY_COLOR]: "legendary",
|
|
27
|
+
[CS_RARITY_ANCIENT_COLOR]: "ancient",
|
|
28
|
+
[CS_RARITY_IMMORTAL_COLOR]: "ancient" // immortal
|
|
29
|
+
};
|
|
30
|
+
export const CS_RARITY_COLOR_DEFAULT = 0;
|
|
31
|
+
export const CS_RARITY_COLOR_ORDER = {
|
|
32
|
+
[CS_RARITY_COMMON_COLOR]: 1,
|
|
33
|
+
[CS_RARITY_UNCOMMON_COLOR]: 2,
|
|
34
|
+
[CS_RARITY_RARE_COLOR]: 3,
|
|
35
|
+
[CS_RARITY_MYTHICAL_COLOR]: 4,
|
|
36
|
+
[CS_RARITY_LEGENDARY_COLOR]: 5,
|
|
37
|
+
[CS_RARITY_ANCIENT_COLOR]: 6,
|
|
38
|
+
[CS_RARITY_IMMORTAL_COLOR]: 7
|
|
39
|
+
};
|
|
40
|
+
export const CS_RARITIES = ["common", "uncommon", "rare", "mythical", "legendary", "ancient", "immortal"];
|
|
41
|
+
export const CS_RARITY_ORDER = [...CS_RARITIES, "special"];
|
|
42
|
+
export const CS_BASE_ODD = 0.8;
|
|
43
|
+
export const CS_STATTRAK_ODD = 0.1;
|
|
44
|
+
export function CS_randomFloat(min, max) {
|
|
45
|
+
return Math.random() * (max - min) + min;
|
|
46
|
+
}
|
|
47
|
+
export function CS_randomInt(min, max) {
|
|
48
|
+
min = Math.ceil(min);
|
|
49
|
+
max = Math.floor(max);
|
|
50
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
51
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { CS_Team } from "./teams.js";
|
|
2
|
+
export interface CS_Item {
|
|
3
|
+
altname?: string;
|
|
4
|
+
base?: boolean;
|
|
5
|
+
category?: string;
|
|
6
|
+
collection?: string;
|
|
7
|
+
collectiondesc?: string;
|
|
8
|
+
collectionname?: string;
|
|
9
|
+
contents?: number[];
|
|
10
|
+
def?: number;
|
|
11
|
+
free?: boolean;
|
|
12
|
+
id: number;
|
|
13
|
+
image?: string;
|
|
14
|
+
index?: number;
|
|
15
|
+
keys?: number[];
|
|
16
|
+
legacy?: boolean;
|
|
17
|
+
model?: string;
|
|
18
|
+
name: string;
|
|
19
|
+
specials?: number[];
|
|
20
|
+
specialsimage?: boolean;
|
|
21
|
+
stattrakonly?: boolean;
|
|
22
|
+
stattrakless?: boolean;
|
|
23
|
+
rarity: string;
|
|
24
|
+
teams?: CS_Team[];
|
|
25
|
+
tint?: number;
|
|
26
|
+
type: "agent" | "case" | "glove" | "graffiti" | "key" | "melee" | "musickit" | "patch" | "pin" | "sticker" | "tool" | "weapon";
|
|
27
|
+
wearmax?: number;
|
|
28
|
+
wearmin?: number;
|
|
29
|
+
}
|
|
30
|
+
export type CS_ItemTranslations = Record<string, Record<number, Record<string, string>>>;
|
|
31
|
+
export declare const CS_MIN_STATTRAK = 0;
|
|
32
|
+
export declare const CS_MAX_STATTRAK = 999999;
|
|
33
|
+
export declare const CS_WEAR_FACTOR = 0.000001;
|
|
34
|
+
export declare const CS_MIN_WEAR = 0;
|
|
35
|
+
export declare const CS_MAX_WEAR = 1;
|
|
36
|
+
export declare const CS_DEFAULT_MIN_WEAR = 0.06;
|
|
37
|
+
export declare const CS_DEFAULT_MAX_WEAR = 0.8;
|
|
38
|
+
export declare const CS_MIN_FACTORY_NEW_WEAR = 0;
|
|
39
|
+
export declare const CS_MAX_FACTORY_NEW_WEAR = 0.07;
|
|
40
|
+
export declare const CS_MIN_MINIMAL_WEAR_WEAR = 0.070001;
|
|
41
|
+
export declare const CS_MAX_MINIMAL_WEAR_WEAR = 0.15;
|
|
42
|
+
export declare const CS_MIN_FIELD_TESTED_WEAR = 0.150001;
|
|
43
|
+
export declare const CS_MAX_FIELD_TESTED_WEAR = 0.37;
|
|
44
|
+
export declare const CS_MIN_WELL_WORN_WEAR = 0.370001;
|
|
45
|
+
export declare const CS_MAX_WELL_WORN_WEAR = 0.44;
|
|
46
|
+
export declare const CS_MIN_BATTLE_SCARRED_WEAR = 0.440001;
|
|
47
|
+
export declare const CS_MAX_BATTLE_SCARRED_WEAR = 1;
|
|
48
|
+
export declare const CS_MIN_SEED = 1;
|
|
49
|
+
export declare const CS_MAX_SEED = 1000;
|
|
50
|
+
export declare const CS_WEARABLE_ITEMS: string[];
|
|
51
|
+
export declare const CS_NAMETAGGABLE_ITEMS: string[];
|
|
52
|
+
export declare const CS_SEEDABLE_ITEMS: string[];
|
|
53
|
+
export declare const CS_STATTRAKABLE_ITEMS: string[];
|
|
54
|
+
export declare const CS_STICKERABLE_ITEMS: string[];
|
|
55
|
+
export declare const CS_NAMETAG_RE: RegExp;
|
|
56
|
+
export declare const CS_STICKER_WEAR_FACTOR = 0.1;
|
|
57
|
+
export declare const CS_MIN_STICKER_WEAR = 0;
|
|
58
|
+
export declare const CS_MAX_STICKER_WEAR = 0.9;
|
|
59
|
+
export declare const CS_NAMETAG_TOOL_DEF = 1200;
|
|
60
|
+
export declare const CS_STATTRAK_SWAP_TOOL_DEF = 1324;
|
|
61
|
+
export declare const CS_STORAGE_UNIT_TOOL_DEF = 1201;
|
|
62
|
+
export declare const CS_NONE = 0;
|
|
63
|
+
type CS_EconomyPredicate = Partial<CS_Item> & {
|
|
64
|
+
team?: CS_Team;
|
|
65
|
+
};
|
|
66
|
+
export declare class CS_EconomyInstance {
|
|
67
|
+
categories: Set<string>;
|
|
68
|
+
items: Map<number, CS_Item>;
|
|
69
|
+
itemsAsArray: CS_Item[];
|
|
70
|
+
texts: Map<number, Record<string, string>>;
|
|
71
|
+
stickers: Set<CS_Item>;
|
|
72
|
+
use(items: CS_Item[]): void;
|
|
73
|
+
getById(id: number): CS_Item;
|
|
74
|
+
get(idOrItem: number | CS_Item): CS_Item;
|
|
75
|
+
applyTranslation(translation: CS_ItemTranslations[number]): void;
|
|
76
|
+
findItem(predicate: CS_EconomyPredicate): CS_Item;
|
|
77
|
+
filterItems(predicate: CS_EconomyPredicate): CS_Item[];
|
|
78
|
+
isC4(item: number | CS_Item): boolean;
|
|
79
|
+
isSticker(item: number | CS_Item): boolean;
|
|
80
|
+
isGlove(item: number | CS_Item): boolean;
|
|
81
|
+
expectSticker(item: number | CS_Item): boolean;
|
|
82
|
+
hasWear(item: CS_Item): boolean;
|
|
83
|
+
validateWear(wear?: number, item?: CS_Item): boolean;
|
|
84
|
+
safeValidateWear(wear?: number, item?: CS_Item): boolean;
|
|
85
|
+
hasSeed(item: CS_Item): boolean;
|
|
86
|
+
validateSeed(seed?: number, item?: CS_Item): boolean;
|
|
87
|
+
safeValidateSeed(seed?: number, item?: CS_Item): boolean;
|
|
88
|
+
hasStickers(item: CS_Item): boolean;
|
|
89
|
+
validateStickers(stickers?: number[], wears?: number[], item?: CS_Item): boolean;
|
|
90
|
+
hasNametag(item: CS_Item): boolean;
|
|
91
|
+
trimNametag(nametag?: string): string | undefined;
|
|
92
|
+
validateNametag(nametag?: string, item?: CS_Item): boolean;
|
|
93
|
+
safeValidateNametag(nametag?: string, item?: CS_Item): boolean;
|
|
94
|
+
requireNametag(nametag?: string, item?: CS_Item): boolean;
|
|
95
|
+
safeRequireNametag(nametag?: string, item?: CS_Item): boolean;
|
|
96
|
+
hasStatTrak(item: CS_Item): boolean;
|
|
97
|
+
validateStatTrak(stattrak?: number, item?: CS_Item): boolean;
|
|
98
|
+
safeValidateStatTrak(stattrak?: number, item?: CS_Item): boolean;
|
|
99
|
+
isStorageUnitTool(item: number | CS_Item): boolean;
|
|
100
|
+
expectStorageUnitTool(item: CS_Item): boolean;
|
|
101
|
+
isNametagTool(toolItem: number | CS_Item): boolean;
|
|
102
|
+
expectNametagTool(item: number | CS_Item): boolean;
|
|
103
|
+
isStatTrakSwapTool(item: number | CS_Item): boolean;
|
|
104
|
+
expectStatTrakSwapTool(item: CS_Item): boolean;
|
|
105
|
+
getWearLabel(wear: number): string;
|
|
106
|
+
getStickerCategories(): string[];
|
|
107
|
+
getStickers(): CS_Item[];
|
|
108
|
+
resolveItemImage(baseUrl: string, item: number | CS_Item, wear?: number): string;
|
|
109
|
+
resolveCollectionImage(baseUrl: string, item: number | CS_Item): string;
|
|
110
|
+
isCase(item: number | CS_Item): boolean;
|
|
111
|
+
isKey(item: number | CS_Item): boolean;
|
|
112
|
+
expectCase(item: number | CS_Item): boolean;
|
|
113
|
+
expectKey(item: number | CS_Item): boolean;
|
|
114
|
+
validateCaseKey(caseItem: number | CS_Item, keyItem?: number | CS_Item): void;
|
|
115
|
+
safeValidateCaseKey(caseItem: number | CS_Item, keyItem?: number | CS_Item): false | void;
|
|
116
|
+
getCaseContents(item: number | CS_Item): {
|
|
117
|
+
contents: number[];
|
|
118
|
+
specials: number[] | undefined;
|
|
119
|
+
};
|
|
120
|
+
groupCaseContents(item: number | CS_Item): Record<string, CS_Item[]>;
|
|
121
|
+
listCaseContents(item: number | CS_Item, hideSpecials?: boolean): CS_Item[];
|
|
122
|
+
/**
|
|
123
|
+
* @see https://www.csgo.com.cn/news/gamebroad/20170911/206155.shtml
|
|
124
|
+
*/
|
|
125
|
+
unlockCase(item: number | CS_Item): {
|
|
126
|
+
attributes: {
|
|
127
|
+
caseid: number;
|
|
128
|
+
seed: number | undefined;
|
|
129
|
+
stattrak: number | undefined;
|
|
130
|
+
wear: number | undefined;
|
|
131
|
+
};
|
|
132
|
+
id: number;
|
|
133
|
+
rarity: string;
|
|
134
|
+
special: boolean;
|
|
135
|
+
};
|
|
136
|
+
validateUnlockedItem(item: number | CS_Item, { id }: ReturnType<typeof this.unlockCase>): void;
|
|
137
|
+
resolveCaseSpecialsImage(baseUrl: string, item: number | CS_Item): string;
|
|
138
|
+
}
|
|
139
|
+
export declare const CS_Economy: CS_EconomyInstance;
|
|
140
|
+
export {};
|
package/dist/economy.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Ian Lucas. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { CS_BASE_ODD, CS_RARITY_COLORS, CS_RARITY_COLOR_DEFAULT, CS_RARITY_COLOR_ORDER, CS_RARITY_FOR_SOUNDS, CS_RARITY_ORDER, CS_STATTRAK_ODD, CS_randomFloat, CS_randomInt } from "./economy-case.js";
|
|
6
|
+
import { assert, compare } from "./util.js";
|
|
7
|
+
export const CS_MIN_STATTRAK = 0;
|
|
8
|
+
export const CS_MAX_STATTRAK = 999999;
|
|
9
|
+
export const CS_WEAR_FACTOR = 0.000001;
|
|
10
|
+
export const CS_MIN_WEAR = 0;
|
|
11
|
+
export const CS_MAX_WEAR = 1;
|
|
12
|
+
export const CS_DEFAULT_MIN_WEAR = 0.06;
|
|
13
|
+
export const CS_DEFAULT_MAX_WEAR = 0.8;
|
|
14
|
+
export const CS_MIN_FACTORY_NEW_WEAR = CS_MIN_WEAR;
|
|
15
|
+
export const CS_MAX_FACTORY_NEW_WEAR = 0.07;
|
|
16
|
+
export const CS_MIN_MINIMAL_WEAR_WEAR = 0.070001;
|
|
17
|
+
export const CS_MAX_MINIMAL_WEAR_WEAR = 0.15;
|
|
18
|
+
export const CS_MIN_FIELD_TESTED_WEAR = 0.150001;
|
|
19
|
+
export const CS_MAX_FIELD_TESTED_WEAR = 0.37;
|
|
20
|
+
export const CS_MIN_WELL_WORN_WEAR = 0.370001;
|
|
21
|
+
export const CS_MAX_WELL_WORN_WEAR = 0.44;
|
|
22
|
+
export const CS_MIN_BATTLE_SCARRED_WEAR = 0.440001;
|
|
23
|
+
export const CS_MAX_BATTLE_SCARRED_WEAR = CS_MAX_WEAR;
|
|
24
|
+
export const CS_MIN_SEED = 1;
|
|
25
|
+
export const CS_MAX_SEED = 1000;
|
|
26
|
+
export const CS_WEARABLE_ITEMS = ["glove", "melee", "weapon"];
|
|
27
|
+
export const CS_NAMETAGGABLE_ITEMS = ["melee", "weapon"];
|
|
28
|
+
export const CS_SEEDABLE_ITEMS = ["weapon", "melee", "glove"];
|
|
29
|
+
export const CS_STATTRAKABLE_ITEMS = ["melee", "weapon", "musickit"];
|
|
30
|
+
export const CS_STICKERABLE_ITEMS = ["weapon"];
|
|
31
|
+
export const CS_NAMETAG_RE = /^[A-Za-z0-9`!@#$%^&*-+=(){}\[\]\/\|\\,.?:;'_\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\s]{0,20}$/u;
|
|
32
|
+
export const CS_STICKER_WEAR_FACTOR = 0.1;
|
|
33
|
+
export const CS_MIN_STICKER_WEAR = 0;
|
|
34
|
+
export const CS_MAX_STICKER_WEAR = 0.9;
|
|
35
|
+
export const CS_NAMETAG_TOOL_DEF = 1200;
|
|
36
|
+
export const CS_STATTRAK_SWAP_TOOL_DEF = 1324;
|
|
37
|
+
export const CS_STORAGE_UNIT_TOOL_DEF = 1201;
|
|
38
|
+
export const CS_NONE = 0;
|
|
39
|
+
function filterItems(predicate) {
|
|
40
|
+
return function filter(item) {
|
|
41
|
+
return (compare(predicate.type, item.type) &&
|
|
42
|
+
compare(predicate.free, item.free) &&
|
|
43
|
+
compare(predicate.model, item.model) &&
|
|
44
|
+
compare(predicate.base, item.base) &&
|
|
45
|
+
compare(predicate.category, item.category) &&
|
|
46
|
+
(predicate.team === undefined || item.teams === undefined || item.teams.includes(predicate.team)));
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export class CS_EconomyInstance {
|
|
50
|
+
categories = new Set();
|
|
51
|
+
items = new Map();
|
|
52
|
+
itemsAsArray = [];
|
|
53
|
+
texts = new Map();
|
|
54
|
+
stickers = new Set();
|
|
55
|
+
use(items) {
|
|
56
|
+
this.categories.clear();
|
|
57
|
+
this.items.clear();
|
|
58
|
+
this.itemsAsArray = [];
|
|
59
|
+
this.texts.clear();
|
|
60
|
+
this.stickers.clear();
|
|
61
|
+
for (const item of items) {
|
|
62
|
+
const clone = { ...item };
|
|
63
|
+
this.itemsAsArray.push(clone);
|
|
64
|
+
this.items.set(item.id, clone);
|
|
65
|
+
this.texts.set(item.id, {
|
|
66
|
+
name: item.name,
|
|
67
|
+
category: item.category,
|
|
68
|
+
collectionname: item.collectionname,
|
|
69
|
+
collectiondesc: item.collectiondesc
|
|
70
|
+
});
|
|
71
|
+
if (this.isSticker(item)) {
|
|
72
|
+
assert(item.category, `Sticker item '${item.id}' does not have a category.`);
|
|
73
|
+
this.stickers.add(clone);
|
|
74
|
+
this.categories.add(item.category);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
getById(id) {
|
|
79
|
+
const item = this.items.get(id);
|
|
80
|
+
assert(item, `The given id '${id}' was not present in CS_Economy.items.`);
|
|
81
|
+
return item;
|
|
82
|
+
}
|
|
83
|
+
get(idOrItem) {
|
|
84
|
+
return typeof idOrItem === "number" ? this.getById(idOrItem) : idOrItem;
|
|
85
|
+
}
|
|
86
|
+
applyTranslation(translation) {
|
|
87
|
+
this.categories.clear();
|
|
88
|
+
for (const [id, fields] of this.texts.entries()) {
|
|
89
|
+
const item = this.items.get(Number(id));
|
|
90
|
+
if (item === undefined) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
Object.assign(item, fields);
|
|
94
|
+
if (fields.category !== undefined && item.type === "sticker") {
|
|
95
|
+
this.categories.add(fields.category);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const [id, fields] of Object.entries(translation)) {
|
|
99
|
+
const item = this.items.get(Number(id));
|
|
100
|
+
if (item === undefined) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
Object.assign(item, fields);
|
|
104
|
+
if (fields.category !== undefined && item.type === "sticker") {
|
|
105
|
+
this.categories.add(fields.category);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
findItem(predicate) {
|
|
110
|
+
const item = this.itemsAsArray.find(filterItems(predicate));
|
|
111
|
+
assert(item, "No items found.");
|
|
112
|
+
return item;
|
|
113
|
+
}
|
|
114
|
+
filterItems(predicate) {
|
|
115
|
+
const items = this.itemsAsArray.filter(filterItems(predicate));
|
|
116
|
+
assert(items.length > 0, "No items found.");
|
|
117
|
+
return items;
|
|
118
|
+
}
|
|
119
|
+
isC4(item) {
|
|
120
|
+
return this.get(item).category === "c4";
|
|
121
|
+
}
|
|
122
|
+
isSticker(item) {
|
|
123
|
+
return this.get(item).type === "sticker";
|
|
124
|
+
}
|
|
125
|
+
isGlove(item) {
|
|
126
|
+
return this.get(item).type === "glove";
|
|
127
|
+
}
|
|
128
|
+
expectSticker(item) {
|
|
129
|
+
assert(this.isSticker(item), `Item is not a sticker.`);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
hasWear(item) {
|
|
133
|
+
return CS_WEARABLE_ITEMS.includes(item.type) && !item.free && item.index !== 0;
|
|
134
|
+
}
|
|
135
|
+
validateWear(wear, item) {
|
|
136
|
+
if (wear === undefined) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
assert(!Number.isNaN(wear), "Wear must be a number.");
|
|
140
|
+
assert(String(wear).length <= String(CS_WEAR_FACTOR).length, "Wear value is too long.");
|
|
141
|
+
assert(wear >= CS_MIN_WEAR && wear <= CS_MAX_WEAR, "Wear value must be between CS_MIN_WEAR and CS_MAX_WEAR.");
|
|
142
|
+
if (item !== undefined) {
|
|
143
|
+
assert(this.hasWear(item), "Item does not have wear.");
|
|
144
|
+
assert(item.wearmin === undefined || wear >= item.wearmin, "Wear value is below the minimum allowed.");
|
|
145
|
+
assert(item.wearmax === undefined || wear <= item.wearmax, "Wear value is above the maximum allowed.");
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
safeValidateWear(wear, item) {
|
|
150
|
+
try {
|
|
151
|
+
return this.validateWear(wear, item);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
hasSeed(item) {
|
|
158
|
+
return CS_SEEDABLE_ITEMS.includes(item.type) && !item.free && item.index !== 0;
|
|
159
|
+
}
|
|
160
|
+
validateSeed(seed, item) {
|
|
161
|
+
if (seed === undefined) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
assert(!Number.isNaN(seed), "Seed must be a valid number.");
|
|
165
|
+
assert(item === undefined || this.hasSeed(item), "Item does not have a seed.");
|
|
166
|
+
assert(Number.isInteger(seed), "Seed must be an integer.");
|
|
167
|
+
assert(seed >= CS_MIN_SEED && seed <= CS_MAX_SEED, `Seed must be between CS_MIN_SEED and CS_MAX_SEED.`);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
safeValidateSeed(seed, item) {
|
|
171
|
+
try {
|
|
172
|
+
return this.validateSeed(seed, item);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
hasStickers(item) {
|
|
179
|
+
return CS_STICKERABLE_ITEMS.includes(item.type) && !this.isC4(item);
|
|
180
|
+
}
|
|
181
|
+
validateStickers(stickers, wears, item) {
|
|
182
|
+
if (stickers === undefined) {
|
|
183
|
+
assert(wears === undefined, "Stickers array is undefined.");
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
assert(stickers.length === 4, "Stickers array must contain exactly 4 elements.");
|
|
187
|
+
assert(wears === undefined || wears.length === 4, "Stickers wear array must contain exactly 4 elements.");
|
|
188
|
+
assert(item === undefined || this.hasStickers(item), "The provided item does not have stickers.");
|
|
189
|
+
for (const [index, stickerId] of stickers.entries()) {
|
|
190
|
+
if (stickerId === CS_NONE) {
|
|
191
|
+
assert(wears === undefined || wears[index] === CS_NONE, "Sticker wear value is invalid.");
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
assert(this.isSticker(stickerId), "The provided ID does not correspond to a sticker.");
|
|
195
|
+
if (wears !== undefined) {
|
|
196
|
+
const wear = wears[index];
|
|
197
|
+
assert(!Number.isNaN(wear), "Sticker wear value must be a valid number.");
|
|
198
|
+
assert(String(wear).length <= String(CS_STICKER_WEAR_FACTOR).length, "Sticker wear value is too long.");
|
|
199
|
+
assert(wear >= CS_MIN_STICKER_WEAR && wear <= CS_MAX_STICKER_WEAR, "Sticker wear value must be between CS_MIN_STICKER_WEAR and CS_MAX_STICKER_WEAR.");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
hasNametag(item) {
|
|
205
|
+
return CS_NAMETAGGABLE_ITEMS.includes(item.type) || this.isStorageUnitTool(item);
|
|
206
|
+
}
|
|
207
|
+
trimNametag(nametag) {
|
|
208
|
+
const trimmed = nametag?.trim();
|
|
209
|
+
return trimmed === "" ? undefined : trimmed;
|
|
210
|
+
}
|
|
211
|
+
validateNametag(nametag, item) {
|
|
212
|
+
if (nametag !== undefined) {
|
|
213
|
+
assert(item === undefined || this.hasNametag(item), "The provided item does not have a nametag.");
|
|
214
|
+
assert(nametag[0] !== " " && CS_NAMETAG_RE.test(nametag), "Invalid nametag format.");
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
safeValidateNametag(nametag, item) {
|
|
219
|
+
try {
|
|
220
|
+
return this.validateNametag(nametag, item);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
requireNametag(nametag, item) {
|
|
227
|
+
assert(nametag === undefined || nametag.trim().length > 0, "Nametag is required.");
|
|
228
|
+
return this.validateNametag(nametag, item);
|
|
229
|
+
}
|
|
230
|
+
safeRequireNametag(nametag, item) {
|
|
231
|
+
try {
|
|
232
|
+
return this.requireNametag(nametag, item);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
hasStatTrak(item) {
|
|
239
|
+
return CS_STATTRAKABLE_ITEMS.includes(item.type) && !item.free;
|
|
240
|
+
}
|
|
241
|
+
validateStatTrak(stattrak, item) {
|
|
242
|
+
if (stattrak === undefined) {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
assert(item === undefined || this.hasStatTrak(item), "The provided item does not support stattrak.");
|
|
246
|
+
assert(Number.isInteger(stattrak), "Stattrak value must be an integer.");
|
|
247
|
+
assert(stattrak >= CS_MIN_STATTRAK && stattrak <= CS_MAX_STATTRAK, "Stattrak value must be between CS_MIN_STATTRAK and CS_MAX_STATTRAK.");
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
safeValidateStatTrak(stattrak, item) {
|
|
251
|
+
try {
|
|
252
|
+
return this.validateStatTrak(stattrak, item);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
isStorageUnitTool(item) {
|
|
259
|
+
const { def, type } = this.get(item);
|
|
260
|
+
return type === "tool" && def === CS_STORAGE_UNIT_TOOL_DEF;
|
|
261
|
+
}
|
|
262
|
+
expectStorageUnitTool(item) {
|
|
263
|
+
assert(this.isStorageUnitTool(item), "Item is not a storage unit.");
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
isNametagTool(toolItem) {
|
|
267
|
+
const { def, type } = this.get(toolItem);
|
|
268
|
+
return type === "tool" && def === CS_NAMETAG_TOOL_DEF;
|
|
269
|
+
}
|
|
270
|
+
expectNametagTool(item) {
|
|
271
|
+
assert(this.isNametagTool(item), "Item is not a nametag tool");
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
isStatTrakSwapTool(item) {
|
|
275
|
+
const { def, type } = this.get(item);
|
|
276
|
+
return type === "tool" && def === CS_STATTRAK_SWAP_TOOL_DEF;
|
|
277
|
+
}
|
|
278
|
+
expectStatTrakSwapTool(item) {
|
|
279
|
+
assert(this.isStatTrakSwapTool(item), "Item is not a stattrak swap tool.");
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
getWearLabel(wear) {
|
|
283
|
+
switch (true) {
|
|
284
|
+
case wear <= CS_MAX_FACTORY_NEW_WEAR:
|
|
285
|
+
return "FN";
|
|
286
|
+
case wear <= CS_MAX_MINIMAL_WEAR_WEAR:
|
|
287
|
+
return "MW";
|
|
288
|
+
case wear <= CS_MAX_FIELD_TESTED_WEAR:
|
|
289
|
+
return "FT";
|
|
290
|
+
case wear <= CS_MAX_WELL_WORN_WEAR:
|
|
291
|
+
return "WW";
|
|
292
|
+
default:
|
|
293
|
+
return "BS";
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
getStickerCategories() {
|
|
297
|
+
return Array.from(this.categories).sort();
|
|
298
|
+
}
|
|
299
|
+
getStickers() {
|
|
300
|
+
return Array.from(this.stickers);
|
|
301
|
+
}
|
|
302
|
+
resolveItemImage(baseUrl, item, wear) {
|
|
303
|
+
item = this.get(item);
|
|
304
|
+
const { id, image } = item;
|
|
305
|
+
if (this.hasWear(item) && wear !== undefined) {
|
|
306
|
+
switch (true) {
|
|
307
|
+
case wear < 1 / 3:
|
|
308
|
+
return `${baseUrl}/${id}_light.png`;
|
|
309
|
+
case wear < 2 / 3:
|
|
310
|
+
return `${baseUrl}/${id}_medium.png`;
|
|
311
|
+
default:
|
|
312
|
+
return `${baseUrl}/${id}_heavy.png`;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (image === undefined) {
|
|
316
|
+
return `${baseUrl}/${id}.png`;
|
|
317
|
+
}
|
|
318
|
+
if (image.charAt(0) === "/") {
|
|
319
|
+
return `${baseUrl}${image}`;
|
|
320
|
+
}
|
|
321
|
+
return image;
|
|
322
|
+
}
|
|
323
|
+
resolveCollectionImage(baseUrl, item) {
|
|
324
|
+
item = this.get(item);
|
|
325
|
+
const { collection } = item;
|
|
326
|
+
assert(collection, "Item does not have a collection.");
|
|
327
|
+
return `${baseUrl}/${collection}.png`;
|
|
328
|
+
}
|
|
329
|
+
isCase(item) {
|
|
330
|
+
return this.get(item).type === "case";
|
|
331
|
+
}
|
|
332
|
+
isKey(item) {
|
|
333
|
+
return this.get(item).type === "key";
|
|
334
|
+
}
|
|
335
|
+
expectCase(item) {
|
|
336
|
+
assert(this.isCase(item), "Item is not a case.");
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
expectKey(item) {
|
|
340
|
+
assert(this.isKey(item), `Item is not a key.`);
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
validateCaseKey(caseItem, keyItem) {
|
|
344
|
+
caseItem = this.get(caseItem);
|
|
345
|
+
this.expectCase(caseItem);
|
|
346
|
+
keyItem = keyItem !== undefined ? this.get(keyItem) : undefined;
|
|
347
|
+
if (keyItem !== undefined) {
|
|
348
|
+
assert(caseItem.keys !== undefined, "Case does not require a key.");
|
|
349
|
+
assert(this.expectKey(keyItem), "Invalid key item.");
|
|
350
|
+
assert(caseItem.keys.includes(keyItem.id), "Invalid key for this case.");
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
assert(caseItem.keys === undefined, "Case requires a key.");
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
safeValidateCaseKey(caseItem, keyItem) {
|
|
357
|
+
try {
|
|
358
|
+
return this.validateCaseKey(caseItem, keyItem);
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
getCaseContents(item) {
|
|
365
|
+
item = this.get(item);
|
|
366
|
+
this.expectCase(item);
|
|
367
|
+
const { contents, specials } = item;
|
|
368
|
+
assert(contents, `Case has no contents.`);
|
|
369
|
+
return { contents, specials };
|
|
370
|
+
}
|
|
371
|
+
groupCaseContents(item) {
|
|
372
|
+
const { contents, specials } = this.getCaseContents(item);
|
|
373
|
+
const items = {};
|
|
374
|
+
for (const id of contents) {
|
|
375
|
+
const item = this.getById(id);
|
|
376
|
+
const rarity = CS_RARITY_COLORS[item.rarity];
|
|
377
|
+
if (!items[rarity]) {
|
|
378
|
+
items[rarity] = [];
|
|
379
|
+
}
|
|
380
|
+
items[rarity].push(item);
|
|
381
|
+
}
|
|
382
|
+
if (specials) {
|
|
383
|
+
for (const id of specials) {
|
|
384
|
+
const item = this.getById(id);
|
|
385
|
+
const rarity = "special";
|
|
386
|
+
if (!items[rarity]) {
|
|
387
|
+
items[rarity] = [];
|
|
388
|
+
}
|
|
389
|
+
items[rarity].push(item);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return items;
|
|
393
|
+
}
|
|
394
|
+
listCaseContents(item, hideSpecials = false) {
|
|
395
|
+
const { contents, specials } = this.getCaseContents(item);
|
|
396
|
+
const items = [...contents, ...(!hideSpecials && specials !== undefined ? specials : [])];
|
|
397
|
+
return items
|
|
398
|
+
.map((id) => this.getById(id))
|
|
399
|
+
.sort((a, b) => {
|
|
400
|
+
return ((CS_RARITY_COLOR_ORDER[a.rarity] ?? CS_RARITY_COLOR_DEFAULT) -
|
|
401
|
+
(CS_RARITY_COLOR_ORDER[b.rarity] ?? CS_RARITY_COLOR_DEFAULT));
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* @see https://www.csgo.com.cn/news/gamebroad/20170911/206155.shtml
|
|
406
|
+
*/
|
|
407
|
+
unlockCase(item) {
|
|
408
|
+
item = this.get(item);
|
|
409
|
+
const contents = this.groupCaseContents(item);
|
|
410
|
+
const keys = Object.keys(contents);
|
|
411
|
+
const rarities = CS_RARITY_ORDER.filter((rarity) => keys.includes(rarity));
|
|
412
|
+
const odds = rarities.map((_, index) => CS_BASE_ODD / Math.pow(5, index));
|
|
413
|
+
const total = odds.reduce((acc, cur) => acc + cur, 0);
|
|
414
|
+
const entries = rarities.map((rarity, index) => [rarity, odds[index] / total]);
|
|
415
|
+
const roll = Math.random();
|
|
416
|
+
let [rollRarity] = entries[0];
|
|
417
|
+
let acc = 0;
|
|
418
|
+
for (const [rarity, odd] of entries) {
|
|
419
|
+
acc += odd;
|
|
420
|
+
if (roll <= acc) {
|
|
421
|
+
rollRarity = rarity;
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const unlocked = contents[rollRarity][Math.floor(Math.random() * contents[rollRarity].length)];
|
|
426
|
+
const hasStatTrak = item.stattrakless !== true;
|
|
427
|
+
const alwaysStatTrak = item.stattrakonly === true;
|
|
428
|
+
return {
|
|
429
|
+
attributes: {
|
|
430
|
+
caseid: item.id,
|
|
431
|
+
seed: this.hasSeed(unlocked) ? CS_randomInt(CS_MIN_SEED, CS_MAX_SEED) : undefined,
|
|
432
|
+
stattrak: hasStatTrak
|
|
433
|
+
? this.hasStatTrak(unlocked)
|
|
434
|
+
? alwaysStatTrak || Math.random() <= CS_STATTRAK_ODD
|
|
435
|
+
? 0
|
|
436
|
+
: undefined
|
|
437
|
+
: undefined
|
|
438
|
+
: undefined,
|
|
439
|
+
wear: this.hasWear(unlocked)
|
|
440
|
+
? Number(CS_randomFloat(unlocked.wearmin ?? CS_MIN_WEAR, unlocked.wearmax ?? CS_MAX_WEAR)
|
|
441
|
+
.toString()
|
|
442
|
+
.substring(0, CS_WEAR_FACTOR.toString().length))
|
|
443
|
+
: undefined
|
|
444
|
+
},
|
|
445
|
+
id: unlocked.id,
|
|
446
|
+
rarity: CS_RARITY_FOR_SOUNDS[unlocked.rarity],
|
|
447
|
+
special: rollRarity === "special"
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
validateUnlockedItem(item, { id }) {
|
|
451
|
+
item = this.get(item);
|
|
452
|
+
this.expectCase(item);
|
|
453
|
+
const { contents, specials } = item;
|
|
454
|
+
assert(contents?.includes(id) || specials?.includes(id), `Unlocked item is not from this case.`);
|
|
455
|
+
}
|
|
456
|
+
resolveCaseSpecialsImage(baseUrl, item) {
|
|
457
|
+
item = this.get(item);
|
|
458
|
+
this.expectCase(item);
|
|
459
|
+
const { id, specialsimage, specials } = item;
|
|
460
|
+
assert(specials, "Case does not have special items.");
|
|
461
|
+
if (specialsimage) {
|
|
462
|
+
return `${baseUrl}/${id}_rare.png`;
|
|
463
|
+
}
|
|
464
|
+
return `${baseUrl}/default_rare_item.png`;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
export const CS_Economy = new CS_EconomyInstance();
|
package/dist/index.d.ts
ADDED