data-of-loathing 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/dist/entityTypes/effects.js +39 -0
- package/dist/entityTypes/effects.test.js +31 -0
- package/dist/entityTypes/familiars.js +79 -0
- package/dist/entityTypes/familiars.test.js +37 -0
- package/dist/entityTypes/items.js +83 -0
- package/dist/entityTypes/items.test.js +35 -0
- package/dist/entityTypes/outfits.js +41 -0
- package/dist/entityTypes/outfits.test.js +36 -0
- package/dist/entityTypes/skills.js +170 -0
- package/dist/entityTypes/skills.test.js +31 -0
- package/dist/index.js +31 -0
- package/dist/testUtils.js +16 -0
- package/dist/utils.js +42 -0
- package/package.json +27 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadEffects = exports.EffectQuality = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
var EffectQuality;
|
|
15
|
+
(function (EffectQuality) {
|
|
16
|
+
EffectQuality["Good"] = "good";
|
|
17
|
+
EffectQuality["Neutral"] = "neutral";
|
|
18
|
+
EffectQuality["Bad"] = "bad";
|
|
19
|
+
})(EffectQuality || (exports.EffectQuality = EffectQuality = {}));
|
|
20
|
+
const isValidQuality = (0, utils_1.isMemberOfEnum)(EffectQuality);
|
|
21
|
+
const parseEffect = (parts) => ({
|
|
22
|
+
id: Number(parts[0]),
|
|
23
|
+
name: parts[1],
|
|
24
|
+
image: parts[2],
|
|
25
|
+
descid: parts[3],
|
|
26
|
+
quality: isValidQuality(parts[4]) ? parts[4] : EffectQuality.Neutral,
|
|
27
|
+
attributes: parts[5]
|
|
28
|
+
.split(",")
|
|
29
|
+
.map((p) => p.trim())
|
|
30
|
+
.filter((p) => p !== "none"),
|
|
31
|
+
actions: parts[6].split("|"),
|
|
32
|
+
});
|
|
33
|
+
const loadEffects = (lastKnownSize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
+
const raw = yield (0, utils_1.loadMafiaData)("statuseffects", lastKnownSize);
|
|
35
|
+
if (raw === null)
|
|
36
|
+
return null;
|
|
37
|
+
return Object.assign(Object.assign({}, raw), { data: raw.data.filter((p) => p.length > 2).map(parseEffect) });
|
|
38
|
+
});
|
|
39
|
+
exports.loadEffects = loadEffects;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const vitest_1 = require("vitest");
|
|
13
|
+
const effects_1 = require("./effects");
|
|
14
|
+
const testUtils_1 = require("../testUtils");
|
|
15
|
+
global.fetch = vitest_1.vi.fn();
|
|
16
|
+
(0, vitest_1.test)("Can read effects", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
vitest_1.vi.mocked(fetch).mockResolvedValue((0, testUtils_1.createFetchResponse)("1\n5\tFar Out\tfarout.gif\t5ad503e9df2df73bfbbb5377b622c8c4\tgood\tnone\tuse 1 patchouli incense stick"));
|
|
18
|
+
const effects = yield (0, effects_1.loadEffects)();
|
|
19
|
+
(0, testUtils_1.expectNotNull)(effects);
|
|
20
|
+
(0, vitest_1.expect)(effects.data.length).toBe(1);
|
|
21
|
+
const effect = effects.data[0];
|
|
22
|
+
(0, vitest_1.expect)(effect).toMatchObject({
|
|
23
|
+
id: 5,
|
|
24
|
+
name: "Far Out",
|
|
25
|
+
image: "farout.gif",
|
|
26
|
+
descid: "5ad503e9df2df73bfbbb5377b622c8c4",
|
|
27
|
+
attributes: [],
|
|
28
|
+
quality: "good",
|
|
29
|
+
actions: ["use 1 patchouli incense stick"],
|
|
30
|
+
});
|
|
31
|
+
}));
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadFamiliars = exports.isOwnable = exports.FamiliarType = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
var FamiliarType;
|
|
15
|
+
(function (FamiliarType) {
|
|
16
|
+
FamiliarType["Stat0"] = "stat0";
|
|
17
|
+
FamiliarType["Stat1"] = "stat1";
|
|
18
|
+
FamiliarType["Item0"] = "item0";
|
|
19
|
+
FamiliarType["Item1"] = "item1";
|
|
20
|
+
FamiliarType["Item2"] = "item2";
|
|
21
|
+
FamiliarType["Item3"] = "item3";
|
|
22
|
+
FamiliarType["Meat0"] = "meat0";
|
|
23
|
+
FamiliarType["Combat0"] = "combat0";
|
|
24
|
+
FamiliarType["Combat1"] = "combat1";
|
|
25
|
+
FamiliarType["Drop"] = "drop";
|
|
26
|
+
FamiliarType["Block"] = "block";
|
|
27
|
+
FamiliarType["Delevel"] = "delevel";
|
|
28
|
+
FamiliarType["Hp0"] = "hp0";
|
|
29
|
+
FamiliarType["Mp0"] = "mp0";
|
|
30
|
+
FamiliarType["Meat1"] = "meat1";
|
|
31
|
+
FamiliarType["Stat2"] = "stat2";
|
|
32
|
+
FamiliarType["Other0"] = "other0";
|
|
33
|
+
FamiliarType["Hp1"] = "hp1";
|
|
34
|
+
FamiliarType["Mp1"] = "mp1";
|
|
35
|
+
FamiliarType["Stat3"] = "stat3";
|
|
36
|
+
FamiliarType["Other1"] = "other1";
|
|
37
|
+
FamiliarType["Passive"] = "passive";
|
|
38
|
+
FamiliarType["Underwater"] = "underwater";
|
|
39
|
+
FamiliarType["Variable"] = "variable";
|
|
40
|
+
})(FamiliarType || (exports.FamiliarType = FamiliarType = {}));
|
|
41
|
+
const isValidType = (0, utils_1.isMemberOfEnum)(FamiliarType);
|
|
42
|
+
const isOwnable = ({ id }) => {
|
|
43
|
+
// April Fools familiars
|
|
44
|
+
if (id >= 125 && id < 134)
|
|
45
|
+
return false;
|
|
46
|
+
// Pokefams
|
|
47
|
+
if (id >= 215 && id < 260)
|
|
48
|
+
return false;
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
51
|
+
exports.isOwnable = isOwnable;
|
|
52
|
+
const parseFamiliar = (parts) => {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
return ({
|
|
55
|
+
id: Number(parts[0]),
|
|
56
|
+
name: parts[1],
|
|
57
|
+
image: parts[2],
|
|
58
|
+
types: parts[3]
|
|
59
|
+
.split(",")
|
|
60
|
+
.map((p) => p.trim())
|
|
61
|
+
.filter(isValidType),
|
|
62
|
+
larva: parts[4],
|
|
63
|
+
equipment: parts[5] || null,
|
|
64
|
+
arenaStats: {
|
|
65
|
+
cageMatch: Number(parts[6]),
|
|
66
|
+
scavengerHunt: Number(parts[7]),
|
|
67
|
+
obstacleCourse: Number(parts[8]),
|
|
68
|
+
hideAndSeek: Number(parts[9]),
|
|
69
|
+
},
|
|
70
|
+
attributes: (_b = (_a = parts[10]) === null || _a === void 0 ? void 0 : _a.split(",")) !== null && _b !== void 0 ? _b : [],
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
const loadFamiliars = (lastKnownSize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
const raw = yield (0, utils_1.loadMafiaData)("familiars", lastKnownSize);
|
|
75
|
+
if (raw === null)
|
|
76
|
+
return null;
|
|
77
|
+
return Object.assign(Object.assign({}, raw), { data: raw.data.filter((p) => p.length > 2).map(parseFamiliar) });
|
|
78
|
+
});
|
|
79
|
+
exports.loadFamiliars = loadFamiliars;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const vitest_1 = require("vitest");
|
|
13
|
+
const testUtils_1 = require("../testUtils");
|
|
14
|
+
const familiars_1 = require("./familiars");
|
|
15
|
+
global.fetch = vitest_1.vi.fn();
|
|
16
|
+
(0, vitest_1.test)("Can read familiars", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
vitest_1.vi.mocked(fetch).mockResolvedValue((0, testUtils_1.createFetchResponse)("1\n7\tSpooky Pirate Skeleton\tfamiliar7.gif\tcombat1,delevel\tspooky pirate skeleton\tblundarrrbus\t2\t3\t1\t0\thashands,haseyes,undead,cantalk"));
|
|
18
|
+
const familiars = yield (0, familiars_1.loadFamiliars)();
|
|
19
|
+
(0, testUtils_1.expectNotNull)(familiars);
|
|
20
|
+
(0, vitest_1.expect)(familiars.data.length).toBe(1);
|
|
21
|
+
const familiar = familiars.data[0];
|
|
22
|
+
(0, vitest_1.expect)(familiar).toMatchObject({
|
|
23
|
+
id: 7,
|
|
24
|
+
name: "Spooky Pirate Skeleton",
|
|
25
|
+
image: "familiar7.gif",
|
|
26
|
+
types: [familiars_1.FamiliarType.Combat1, familiars_1.FamiliarType.Delevel],
|
|
27
|
+
larva: "spooky pirate skeleton",
|
|
28
|
+
equipment: "blundarrrbus",
|
|
29
|
+
arenaStats: {
|
|
30
|
+
cageMatch: 2,
|
|
31
|
+
hideAndSeek: 0,
|
|
32
|
+
obstacleCourse: 1,
|
|
33
|
+
scavengerHunt: 3,
|
|
34
|
+
},
|
|
35
|
+
attributes: ["hashands", "haseyes", "undead", "cantalk"],
|
|
36
|
+
});
|
|
37
|
+
}));
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadItems = exports.ItemUse = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
var ItemUse;
|
|
15
|
+
(function (ItemUse) {
|
|
16
|
+
// Primary
|
|
17
|
+
ItemUse["Food"] = "food";
|
|
18
|
+
ItemUse["Drink"] = "drink";
|
|
19
|
+
ItemUse["Spleen"] = "spleen";
|
|
20
|
+
ItemUse["Potion"] = "potion";
|
|
21
|
+
ItemUse["Avatar"] = "avatar";
|
|
22
|
+
ItemUse["Usable"] = "usable";
|
|
23
|
+
ItemUse["Multiple"] = "multiple";
|
|
24
|
+
ItemUse["Reusable"] = "reusable";
|
|
25
|
+
ItemUse["Message"] = "message";
|
|
26
|
+
ItemUse["Grow"] = "grow";
|
|
27
|
+
ItemUse["PokePill"] = "pokepill";
|
|
28
|
+
ItemUse["Hat"] = "hat";
|
|
29
|
+
ItemUse["Weapon"] = "weapon";
|
|
30
|
+
ItemUse["Sixgun"] = "sixgun";
|
|
31
|
+
ItemUse["Offhand"] = "offhand";
|
|
32
|
+
ItemUse["Container"] = "container";
|
|
33
|
+
ItemUse["Shirt"] = "shirt";
|
|
34
|
+
ItemUse["Pants"] = "pants";
|
|
35
|
+
ItemUse["Accessory"] = "accessory";
|
|
36
|
+
ItemUse["Familiar"] = "familiar";
|
|
37
|
+
ItemUse["Sticker"] = "sticker";
|
|
38
|
+
ItemUse["Card"] = "card";
|
|
39
|
+
ItemUse["Folder"] = "folder";
|
|
40
|
+
ItemUse["Bootspur"] = "bootspur";
|
|
41
|
+
ItemUse["Bootskin"] = "bootskin";
|
|
42
|
+
ItemUse["FoodHelper"] = "food helper";
|
|
43
|
+
ItemUse["DrinkHelper"] = "drink helper";
|
|
44
|
+
ItemUse["Zap"] = "zap";
|
|
45
|
+
ItemUse["Sphere"] = "sphere";
|
|
46
|
+
ItemUse["Guardian"] = "guardian";
|
|
47
|
+
// Secondary
|
|
48
|
+
ItemUse["Combat"] = "combat";
|
|
49
|
+
ItemUse["CombatReusable"] = "combat reusable";
|
|
50
|
+
ItemUse["Single"] = "single";
|
|
51
|
+
ItemUse["Solo"] = "solo";
|
|
52
|
+
ItemUse["Curse"] = "curse";
|
|
53
|
+
ItemUse["Bounty"] = "bounty";
|
|
54
|
+
ItemUse["Package"] = "package";
|
|
55
|
+
ItemUse["Candy"] = "candy";
|
|
56
|
+
ItemUse["Candy1"] = "candy1";
|
|
57
|
+
ItemUse["Candy2"] = "candy2";
|
|
58
|
+
ItemUse["Chocolate"] = "chocolate";
|
|
59
|
+
ItemUse["Fancy"] = "fancy";
|
|
60
|
+
ItemUse["Paste"] = "paste";
|
|
61
|
+
ItemUse["Smith"] = "smith";
|
|
62
|
+
ItemUse["Cook"] = "cook";
|
|
63
|
+
ItemUse["Mix"] = "mix";
|
|
64
|
+
ItemUse["Matchable"] = "matchable";
|
|
65
|
+
})(ItemUse || (exports.ItemUse = ItemUse = {}));
|
|
66
|
+
const isValidItemUse = (0, utils_1.isMemberOfEnum)(ItemUse);
|
|
67
|
+
const parseAccess = (accessString) => {
|
|
68
|
+
const access = accessString.split(",").map((p) => p.trim());
|
|
69
|
+
return {
|
|
70
|
+
quest: access.includes("q"),
|
|
71
|
+
gift: access.includes("g"),
|
|
72
|
+
tradeable: access.includes("t"),
|
|
73
|
+
discardable: access.includes("d"),
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
const parseItem = (parts) => (Object.assign(Object.assign({ id: Number(parts[0]), name: parts[1], descid: parts[2], image: parts[3], uses: parts[4].split(", ").filter(isValidItemUse) }, parseAccess(parts[5])), { autosell: Number(parts[6]), plural: parts[7] }));
|
|
77
|
+
const loadItems = (lastKnownSize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
78
|
+
const raw = yield (0, utils_1.loadMafiaData)("items", lastKnownSize);
|
|
79
|
+
if (raw === null)
|
|
80
|
+
return null;
|
|
81
|
+
return Object.assign(Object.assign({}, raw), { data: raw.data.filter((p) => p.length > 2).map(parseItem) });
|
|
82
|
+
});
|
|
83
|
+
exports.loadItems = loadItems;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const vitest_1 = require("vitest");
|
|
13
|
+
const testUtils_1 = require("../testUtils");
|
|
14
|
+
const items_1 = require("./items");
|
|
15
|
+
global.fetch = vitest_1.vi.fn();
|
|
16
|
+
(0, vitest_1.test)("Can read items", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
vitest_1.vi.mocked(fetch).mockResolvedValue((0, testUtils_1.createFetchResponse)("1\n87\tmeat from yesterday\t653772183\tmeat.gif\tnone, paste\tt,d\t5\tmeats from yesterday"));
|
|
18
|
+
const items = yield (0, items_1.loadItems)();
|
|
19
|
+
(0, testUtils_1.expectNotNull)(items);
|
|
20
|
+
(0, vitest_1.expect)(items.data.length).toBe(1);
|
|
21
|
+
const item = items.data[0];
|
|
22
|
+
(0, vitest_1.expect)(item).toMatchObject({
|
|
23
|
+
id: 87,
|
|
24
|
+
name: "meat from yesterday",
|
|
25
|
+
descid: "653772183",
|
|
26
|
+
image: "meat.gif",
|
|
27
|
+
uses: [items_1.ItemUse.Paste],
|
|
28
|
+
quest: false,
|
|
29
|
+
gift: false,
|
|
30
|
+
tradeable: true,
|
|
31
|
+
discardable: true,
|
|
32
|
+
autosell: 5,
|
|
33
|
+
plural: "meats from yesterday",
|
|
34
|
+
});
|
|
35
|
+
}));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadOutfits = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
const parseEquipment = (equipmentList = "") => equipmentList.trim().split(", ");
|
|
15
|
+
const parseTreats = (treatList = "") => treatList
|
|
16
|
+
.trim()
|
|
17
|
+
.split(", ")
|
|
18
|
+
.filter((t) => t !== "none")
|
|
19
|
+
.map((treat) => {
|
|
20
|
+
const m = treat.match(/^(.*?) \((\d*\.?\d+)\)$/);
|
|
21
|
+
if (!m)
|
|
22
|
+
return { item: treat, chance: 1 };
|
|
23
|
+
return { item: m[1], chance: Number(m[2]) };
|
|
24
|
+
});
|
|
25
|
+
const parseOutfit = (parts) => {
|
|
26
|
+
var _a, _b;
|
|
27
|
+
return ({
|
|
28
|
+
id: Number(parts[0]),
|
|
29
|
+
name: parts[1],
|
|
30
|
+
image: parts[2],
|
|
31
|
+
equipment: parseEquipment((_a = parts[3]) !== null && _a !== void 0 ? _a : ""),
|
|
32
|
+
treats: parseTreats(parts[0] === "80" ? "double-ice gum" : (_b = parts[4]) !== null && _b !== void 0 ? _b : ""),
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const loadOutfits = (lastKnownSize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
+
const raw = yield (0, utils_1.loadMafiaData)("outfits", lastKnownSize);
|
|
37
|
+
if (raw === null)
|
|
38
|
+
return null;
|
|
39
|
+
return Object.assign(Object.assign({}, raw), { data: raw.data.filter((p) => p.length > 2).map(parseOutfit) });
|
|
40
|
+
});
|
|
41
|
+
exports.loadOutfits = loadOutfits;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const vitest_1 = require("vitest");
|
|
13
|
+
const testUtils_1 = require("../testUtils");
|
|
14
|
+
const outfits_1 = require("./outfits");
|
|
15
|
+
global.fetch = vitest_1.vi.fn();
|
|
16
|
+
(0, vitest_1.test)("Can read items", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
vitest_1.vi.mocked(fetch).mockResolvedValue((0, testUtils_1.createFetchResponse)("1\n35\tBlack Armaments\tblacktat.gif\tblack helmet, black sword, black shield, black greaves\tblack pudding (0.16), Blackfly Chardonnay (0.16), black & tan (0.16), black pepper (0.16), black forest cake (0.16), black forest ham (0.16)"));
|
|
18
|
+
const outfits = yield (0, outfits_1.loadOutfits)();
|
|
19
|
+
(0, testUtils_1.expectNotNull)(outfits);
|
|
20
|
+
(0, vitest_1.expect)(outfits.data.length).toBe(1);
|
|
21
|
+
const outfit = outfits.data[0];
|
|
22
|
+
(0, vitest_1.expect)(outfit).toMatchObject({
|
|
23
|
+
id: 35,
|
|
24
|
+
name: "Black Armaments",
|
|
25
|
+
image: "blacktat.gif",
|
|
26
|
+
equipment: ["black helmet", "black sword", "black shield", "black greaves"],
|
|
27
|
+
treats: [
|
|
28
|
+
{ item: "black pudding", chance: 0.16 },
|
|
29
|
+
{ item: "Blackfly Chardonnay", chance: 0.16 },
|
|
30
|
+
{ item: "black & tan", chance: 0.16 },
|
|
31
|
+
{ item: "black pepper", chance: 0.16 },
|
|
32
|
+
{ item: "black forest cake", chance: 0.16 },
|
|
33
|
+
{ item: "black forest ham", chance: 0.16 },
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
}));
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadSkills = exports.isPermable = exports.getMaxLevel = exports.SkillType = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
var SkillType;
|
|
15
|
+
(function (SkillType) {
|
|
16
|
+
SkillType[SkillType["Passive"] = 0] = "Passive";
|
|
17
|
+
SkillType[SkillType["NoncombatItemSummon"] = 1] = "NoncombatItemSummon";
|
|
18
|
+
SkillType[SkillType["NoncombatHealing"] = 2] = "NoncombatHealing";
|
|
19
|
+
SkillType[SkillType["NoncombatNonShruggableEffect"] = 3] = "NoncombatNonShruggableEffect";
|
|
20
|
+
SkillType[SkillType["NoncombatShruggableEffect"] = 4] = "NoncombatShruggableEffect";
|
|
21
|
+
SkillType[SkillType["Combat"] = 5] = "Combat";
|
|
22
|
+
SkillType[SkillType["OneAtATimeNoncombatSong"] = 6] = "OneAtATimeNoncombatSong";
|
|
23
|
+
SkillType[SkillType["CombatNoncombatHealing"] = 7] = "CombatNoncombatHealing";
|
|
24
|
+
SkillType[SkillType["CombatPassive"] = 8] = "CombatPassive";
|
|
25
|
+
SkillType[SkillType["OneAtATimeNoncombatExpression"] = 9] = "OneAtATimeNoncombatExpression";
|
|
26
|
+
SkillType[SkillType["OneAtATimeNoncombatWalk"] = 10] = "OneAtATimeNoncombatWalk";
|
|
27
|
+
SkillType[SkillType["NoncombatHealingPassive"] = 11] = "NoncombatHealingPassive";
|
|
28
|
+
})(SkillType || (exports.SkillType = SkillType = {}));
|
|
29
|
+
const isValidType = (0, utils_1.isMemberOfEnum)(SkillType);
|
|
30
|
+
const getMaxLevel = ({ id }) => {
|
|
31
|
+
switch (id) {
|
|
32
|
+
// Will probably be this way forever
|
|
33
|
+
// Slimy Sinews
|
|
34
|
+
case 46:
|
|
35
|
+
return 10;
|
|
36
|
+
// Slimy Synapes
|
|
37
|
+
case 47:
|
|
38
|
+
return 10;
|
|
39
|
+
// Slimy Shoulders
|
|
40
|
+
case 48:
|
|
41
|
+
return 10;
|
|
42
|
+
// Summon Annoyance
|
|
43
|
+
case 107:
|
|
44
|
+
return 9;
|
|
45
|
+
// Belch The Rainbow
|
|
46
|
+
case 117:
|
|
47
|
+
return 11;
|
|
48
|
+
// Implode Universe
|
|
49
|
+
case 188:
|
|
50
|
+
return 13;
|
|
51
|
+
// Will change in future
|
|
52
|
+
// Pirate Bellow
|
|
53
|
+
case 118:
|
|
54
|
+
return 7;
|
|
55
|
+
// Summon Holiday Fun
|
|
56
|
+
case 121:
|
|
57
|
+
return 6;
|
|
58
|
+
// Summon Carrot
|
|
59
|
+
case 128:
|
|
60
|
+
return 6;
|
|
61
|
+
// Bear Essence
|
|
62
|
+
case 134:
|
|
63
|
+
return 6;
|
|
64
|
+
// Summon Kokomo Resort Pass
|
|
65
|
+
case 135:
|
|
66
|
+
return 2;
|
|
67
|
+
// Calculate the Universe
|
|
68
|
+
case 144:
|
|
69
|
+
return 5;
|
|
70
|
+
// Experience Safari
|
|
71
|
+
case 180:
|
|
72
|
+
return 4;
|
|
73
|
+
// Toggle Optimality
|
|
74
|
+
case 7254:
|
|
75
|
+
return 3;
|
|
76
|
+
default:
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
exports.getMaxLevel = getMaxLevel;
|
|
81
|
+
const isPermable = ({ id }) => {
|
|
82
|
+
// Random old skills
|
|
83
|
+
if (id < 10)
|
|
84
|
+
return false;
|
|
85
|
+
// Bad Moon
|
|
86
|
+
if (id > 20 && id <= 27)
|
|
87
|
+
return false;
|
|
88
|
+
// Way of the Surprising Fist skills
|
|
89
|
+
if (id > 63 && id <= 73)
|
|
90
|
+
return false;
|
|
91
|
+
// Spirit derived skills
|
|
92
|
+
if (id > 7175 && id < 7181)
|
|
93
|
+
return false;
|
|
94
|
+
switch (id) {
|
|
95
|
+
// VIP lounge skills
|
|
96
|
+
case 91: // Dog Tired
|
|
97
|
+
case 116: // Hollow Leg
|
|
98
|
+
return false;
|
|
99
|
+
// Nemesis skills
|
|
100
|
+
case 49: // Gothy Handwave
|
|
101
|
+
case 50: // Break It On Down
|
|
102
|
+
case 51: // Pop and Lock
|
|
103
|
+
case 52: // Run Like the Wind
|
|
104
|
+
case 3024: // Carboloading
|
|
105
|
+
return false;
|
|
106
|
+
case 6019: // Gemlli's March of Testery
|
|
107
|
+
return false;
|
|
108
|
+
// Other skills from this class are not permable
|
|
109
|
+
case 17047: // Mild Curs
|
|
110
|
+
return true;
|
|
111
|
+
// Avatar of West of Loathing skills
|
|
112
|
+
case 156: // Shoot
|
|
113
|
+
return false;
|
|
114
|
+
// Not permable but granted every ascension
|
|
115
|
+
case 174: // Incrdible Self-Estem
|
|
116
|
+
return false;
|
|
117
|
+
// S.I.T. Course certificate skills
|
|
118
|
+
case 218: // Cryptobotanist
|
|
119
|
+
case 219: // Insectologist
|
|
120
|
+
case 220: // Psychogeologist
|
|
121
|
+
return false;
|
|
122
|
+
// Replica skills
|
|
123
|
+
case 222: // Replica Emotionally Chipped
|
|
124
|
+
return false;
|
|
125
|
+
// Permable from PvP
|
|
126
|
+
case 7254: // Toggle Optimality
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
switch (Math.floor(id / 1000)) {
|
|
130
|
+
case 7: // Skills granted by items
|
|
131
|
+
case 8: // Mystical Bookshelf Skills
|
|
132
|
+
case 11: // Avatar of Boris skills
|
|
133
|
+
case 12: // Zombie Slayer skills
|
|
134
|
+
case 14: // Avatar of Jarlsberg skills
|
|
135
|
+
case 15: // Avatar of Sneaky Pete skills
|
|
136
|
+
case 16: // Heavy Rains skills
|
|
137
|
+
case 17: // Ed skills
|
|
138
|
+
case 18: // Cow Puncher skills
|
|
139
|
+
case 19: // Bean Slinger skills
|
|
140
|
+
case 20: // Snake Oiler skills
|
|
141
|
+
case 21: // The Source skills
|
|
142
|
+
case 22: // Nuclear Autumn skills
|
|
143
|
+
case 23: // Gelatinous Noob skills
|
|
144
|
+
case 24: // Vampyre skills
|
|
145
|
+
case 25: // Plumber skills
|
|
146
|
+
case 27: // Grey Goo skills
|
|
147
|
+
case 28: // AoSOL; Pig Skinner skills
|
|
148
|
+
case 29: // AoSOL; Cheese Wizard skills
|
|
149
|
+
case 30: // AoSOL; Jazz Agent skills
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
};
|
|
154
|
+
exports.isPermable = isPermable;
|
|
155
|
+
const parseSkill = (parts) => ({
|
|
156
|
+
id: Number(parts[0]),
|
|
157
|
+
name: parts[1],
|
|
158
|
+
image: parts[2],
|
|
159
|
+
type: isValidType(Number(parts[3])) ? Number(parts[3]) : SkillType.Passive,
|
|
160
|
+
mpCost: Number(parts[4]),
|
|
161
|
+
duration: Number(parts[5]),
|
|
162
|
+
level: parts[6] ? Number(parts[6]) : 0,
|
|
163
|
+
});
|
|
164
|
+
const loadSkills = (lastKnownSize) => __awaiter(void 0, void 0, void 0, function* () {
|
|
165
|
+
const raw = yield (0, utils_1.loadMafiaData)("classskills", lastKnownSize);
|
|
166
|
+
if (raw === null)
|
|
167
|
+
return null;
|
|
168
|
+
return Object.assign(Object.assign({}, raw), { data: raw.data.filter((p) => p.length > 2).map(parseSkill) });
|
|
169
|
+
});
|
|
170
|
+
exports.loadSkills = loadSkills;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const vitest_1 = require("vitest");
|
|
13
|
+
const testUtils_1 = require("../testUtils");
|
|
14
|
+
const skills_1 = require("./skills");
|
|
15
|
+
global.fetch = vitest_1.vi.fn();
|
|
16
|
+
(0, vitest_1.test)("Can read items", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
vitest_1.vi.mocked(fetch).mockResolvedValue((0, testUtils_1.createFetchResponse)("1\n3035\tBind Penne Dreadful\tt_dreadful.gif\t3\t150\t0\t11"));
|
|
18
|
+
const skills = yield (0, skills_1.loadSkills)();
|
|
19
|
+
(0, testUtils_1.expectNotNull)(skills);
|
|
20
|
+
(0, vitest_1.expect)(skills.data.length).toBe(1);
|
|
21
|
+
const skill = skills.data[0];
|
|
22
|
+
(0, vitest_1.expect)(skill).toMatchObject({
|
|
23
|
+
id: 3035,
|
|
24
|
+
name: "Bind Penne Dreadful",
|
|
25
|
+
image: "t_dreadful.gif",
|
|
26
|
+
type: skills_1.SkillType.NoncombatNonShruggableEffect,
|
|
27
|
+
mpCost: 150,
|
|
28
|
+
duration: 0,
|
|
29
|
+
level: 11,
|
|
30
|
+
});
|
|
31
|
+
}));
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Skill = exports.Outfit = exports.Item = exports.Familiar = exports.Effect = void 0;
|
|
27
|
+
exports.Effect = __importStar(require("./entityTypes/effects"));
|
|
28
|
+
exports.Familiar = __importStar(require("./entityTypes/familiars"));
|
|
29
|
+
exports.Item = __importStar(require("./entityTypes/items"));
|
|
30
|
+
exports.Outfit = __importStar(require("./entityTypes/outfits"));
|
|
31
|
+
exports.Skill = __importStar(require("./entityTypes/skills"));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expectNotNull = exports.createFetchResponse = void 0;
|
|
4
|
+
const vitest_1 = require("vitest");
|
|
5
|
+
function createFetchResponse(data) {
|
|
6
|
+
return {
|
|
7
|
+
json: () => new Promise((resolve) => resolve(JSON.parse(data))),
|
|
8
|
+
text: () => new Promise((resolve) => resolve(data)),
|
|
9
|
+
headers: new Headers({ "Content-Length": String(data.length) }),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
exports.createFetchResponse = createFetchResponse;
|
|
13
|
+
function expectNotNull(val) {
|
|
14
|
+
(0, vitest_1.expect)(val).toBeDefined();
|
|
15
|
+
}
|
|
16
|
+
exports.expectNotNull = expectNotNull;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.isMemberOfEnum = exports.arrayOf = exports.tuple = exports.loadMafiaData = void 0;
|
|
13
|
+
const MAFIA_DATA_BASE = "https://raw.githubusercontent.com/kolmafia/kolmafia/main/src/data";
|
|
14
|
+
function loadMafiaData(fileName, lastKnownSize = 0) {
|
|
15
|
+
var _a;
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const url = `${MAFIA_DATA_BASE}/${fileName}.txt`;
|
|
18
|
+
if (lastKnownSize > 0) {
|
|
19
|
+
const sizeCheck = yield fetch(url, { method: "HEAD" });
|
|
20
|
+
const newSize = Number((_a = sizeCheck.headers.get("Content-Length")) !== null && _a !== void 0 ? _a : 1);
|
|
21
|
+
if (newSize === lastKnownSize)
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const request = yield fetch(url);
|
|
25
|
+
const raw = yield request.text();
|
|
26
|
+
return {
|
|
27
|
+
data: raw
|
|
28
|
+
.split("\n")
|
|
29
|
+
.slice(1)
|
|
30
|
+
.filter((r) => r !== "" && !r.startsWith("#"))
|
|
31
|
+
.map((r) => r.split("\t")),
|
|
32
|
+
size: Number(request.headers.get("Content-Length")),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
exports.loadMafiaData = loadMafiaData;
|
|
37
|
+
const tuple = (args) => args;
|
|
38
|
+
exports.tuple = tuple;
|
|
39
|
+
const arrayOf = (items) => Array.isArray(items) ? items : [items];
|
|
40
|
+
exports.arrayOf = arrayOf;
|
|
41
|
+
const isMemberOfEnum = (e) => (token) => Object.values(e).includes(token);
|
|
42
|
+
exports.isMemberOfEnum = isMemberOfEnum;
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "data-of-loathing",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"author": "Sam Gaus <sam@gaus.co.uk>",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@types/node": "^20.8.7",
|
|
12
|
+
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
|
13
|
+
"@typescript-eslint/parser": "^6.8.0",
|
|
14
|
+
"eslint": "^8.52.0",
|
|
15
|
+
"eslint-config-prettier": "^9.0.0",
|
|
16
|
+
"prettier": "^3.0.3",
|
|
17
|
+
"typescript": "^5.2.2",
|
|
18
|
+
"vitest": "^0.34.6"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"format": "prettier --write .",
|
|
23
|
+
"prepack": "yarn run build",
|
|
24
|
+
"test": "vitest"
|
|
25
|
+
},
|
|
26
|
+
"packageManager": "yarn@4.0.0"
|
|
27
|
+
}
|