Add bosses and support for leagues.

This commit is contained in:
maxswa
2020-01-04 16:59:07 -05:00
parent 8bf1f6cdbc
commit ae73fef5ed
6 changed files with 1893 additions and 1430 deletions

View File

@@ -68,15 +68,15 @@ const topPage = await getSkillPage('overall');
`getStats` will return a full player object with gamemode.
`getStatsByGameMode` will return a stats object and accepts a gamemode parameter:
| Game mode | Param |
| ---------------- | :----: |
| Regular | `main` |
| Ironman | `iron` |
| Hardcore Ironman | `hc` |
| Ultimate Ironman | `ult` |
| Deadman Mode | `dmm` |
| Seasonal Deadman | `sdmm` |
| DMM Tournament | `dmmt` |
| Game mode | Param |
| ---------------- | :-------: |
| Regular | `main` |
| Ironman | `iron` |
| Hardcore Ironman | `hc` |
| Ultimate Ironman | `ult` |
| Deadman Mode | `dmm` |
| DMM Tournament | `dmmt` |
| Leagues | `leagues` |
`getSkillPage` and `getActivityPage` require a skill/activity and optionally a gamemode and page:
@@ -109,6 +109,60 @@ Activities consist of all levels of clue scrolls as well as minigames:
| Bounty Hunter (Hunter) | `hunterbh` |
| Last Man Standing | `lms` |
### Leagues
| Name | Param |
| ------------- | :---: |
| League Points | `lp` |
### Bosses
| Boss Name | Param |
| -------------------------------- | :----------------------------: |
| Abyssal Sire | `abyssalsire` |
| Alchemical Hydra | `alchemicalhydra` |
| Barrows Chests | `barrowschests` |
| Bryophyta | `bryophyta` |
| Callisto | `callisto` |
| Cerberus | `cerberus` |
| Chambers Of Xeric | `chambersofxeric` |
| Chambers Of Xeric Challenge Mode | `chambersofxericchallengemode` |
| Chaos Elemental | `chaoselemental` |
| Chaos Fanatic | `chaosfanatic` |
| Commander Zilyana | `commanderzilyana` |
| Corporeal Beast | `corporealbeast` |
| Crazy Archaeologist | `crazyarchaeologist` |
| Dagannoth Prime | `dagannothprime` |
| Dagannoth Rex | `dagannothrex` |
| Dagannoth Supreme | `dagannothsupreme` |
| Deranged Archaeologist | `derangedarchaeologist` |
| General Graardor | `generalgraardor` |
| Giant Mole | `giantmole` |
| Grotesque Guardians | `grotesqueguardians` |
| Hespori | `hespori` |
| Kalphite Queen | `kalphitequeen` |
| King Black Dragon | `kingblackdragon` |
| Kraken | `kraken` |
| Kreearra | `kreearra` |
| K'ril Tsutsaroth | `kriltsutsaroth` |
| Mimic | `mimic` |
| Obor | `obor` |
| Sarachnis | `sarachnis` |
| Scorpia | `scorpia` |
| Skotizo | `skotizo` |
| Gauntlet | `gauntlet` |
| Corrupted Gauntlet | `corruptedgauntlet` |
| Theatre Of Blood | `theatreofblood` |
| Thermonuclear Smoke Devil | `thermonuclearsmokedevil` |
| TzKal-Zuk | `tzkalzuk` |
| TzTok-Jad | `tztokjad` |
| Venenatis | `venenatis` |
| Vetion | `vetion` |
| Vorkath | `vorkath` |
| Wintertodt | `wintertodt` |
| Zalcano | `zalcano` |
| Zulrah | `zulrah` |
## What you'll get
`getStats` returns a player object that looks like this:
@@ -129,7 +183,8 @@ Activities consist of all levels of clue scrolls as well as minigames:
},
clues: {},
bh: {},
lms: {}
lms: {},
bosses: {}
}
}
```

View File

@@ -5,8 +5,6 @@ import {
getStats,
getStatsByGamemode,
} from '../src/index';
import { PlayerSkillRow, Player, Stats } from '../src/types';
import axios, { AxiosError } from 'axios';
test('Parse CSV to json', () => {
const csv = `40258,2063,218035714
@@ -33,16 +31,58 @@ test('Parse CSV to json', () => {
53099, 80, 2008229
169127, 73, 1067670
115543, 82, 2546048
-1, -1
-1, -1
32875, 500
-1, -1
-1, -1
-1, -1
24817, 476
212728, 1
94827, 20
59099, 74
24642, 231
5206, 99
6293, 51`;
6293, 51
32875, 500
374,2780
934,3000
1936,1452
4919,23
101,4038
152,334
6153,133
4501,250
6806,603
1,17798
9160,125
1021,2802
4295,1655
959,2951
10009,1
1271,2407
378,4669
543,1567
6003,94
263,2897
4000,1277
41016,1477
617,2391
120,2981
1,109
26,323
198,1101
81,3404
5027,61
63,375
2845,6
6913,138
3999,2000
484,8
957,47
10987,223
1923,272
8484,1340
599,1694
-1,-1
3810,4583`;
expect(parseStats(csv)).toStrictEqual({
skills: {
@@ -85,238 +125,272 @@ test('Parse CSV to json', () => {
elite: { rank: 5206, score: 99 },
master: { rank: 6293, score: 51 },
},
bosses: {
abyssalsire: { rank: 374, score: 2780 },
alchemicalhydra: { rank: 934, score: 3000 },
barrowschests: { rank: 1936, score: 1452 },
bryophyta: { rank: 4919, score: 23 },
chambersofxeric: { rank: 101, score: 4038 },
chambersofxericchallengemode: { rank: 152, score: 334 },
chaoselemental: { rank: -1, score: -1 },
chaosfanatic: { rank: -1, score: -1 },
commanderzilyana: { rank: 6806, score: 603 },
corporealbeast: { rank: 1, score: 17798 },
crazyarchaeologist: { rank: 9160, score: 125 },
dagannothprime: { rank: 1021, score: 2802 },
dagannothrex: { rank: 4295, score: 1655 },
dagannothsupreme: { rank: 959, score: 2951 },
derangedarchaeologist: { rank: 10009, score: 1 },
generalgraardor: { rank: 1271, score: 2407 },
giantmole: { rank: 378, score: 4669 },
grotesqueguardians: { rank: 543, score: 1567 },
hespori: { rank: 6003, score: 94 },
kalphitequeen: { rank: 263, score: 2897 },
kingblackdragon: { rank: 4000, score: 1277 },
kraken: { rank: 41016, score: 1477 },
kreearra: { rank: 617, score: 2391 },
kriltsutsaroth: { rank: 120, score: 2981 },
mimic: { rank: 1, score: 109 },
obor: { rank: 26, score: 323 },
sarachnis: { rank: 198, score: 1101 },
scorpia: { rank: 81, score: 3404 },
skotizo: { rank: 5027, score: 61 },
gauntlet: { rank: 63, score: 375 },
corruptedgauntlet: { rank: 2845, score: 6 },
theatreofblood: { rank: 6913, score: 138 },
thermonuclearsmokedevil: { rank: 3999, score: 2000 },
tzkalzuk: { rank: 484, score: 8 },
tztokjad: { rank: 957, score: 47 },
venenatis: { rank: 10987, score: 223 },
vetion: { rank: 1923, score: 272 },
vorkath: { rank: 8484, score: 1340 },
wintertodt: { rank: 599, score: 1694 },
zalcano: { rank: -1, score: -1 },
zulrah: { rank: 3810, score: 4583 },
callisto: { rank: -1, score: -1 },
cerberus: { rank: -1, score: -1 },
},
});
});
test('Get rsn format', async done => {
const callback = (data: string) => {
expect(data).toBe('Lynx Titan');
done();
};
getRSNFormat('lYnX tiTaN').then(callback);
test('Get rsn format', async () => {
jest.setTimeout(30000);
const data = await getRSNFormat('lYnX tiTaN');
expect(data).toBe('Lynx Titan');
});
test('Get attack top page', async done => {
const callback = (data: PlayerSkillRow[]) => {
expect(data).toMatchObject([
{
rsn: expect.any(String),
rank: 1,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 2,
level: 99,
xp: 200000000,
dead: false,
},
{ rsn: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
{
rsn: expect.any(String),
rank: 4,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 5,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 6,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 7,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 8,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 9,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 10,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 11,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 12,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 13,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 14,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 15,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 16,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 17,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 18,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 19,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 20,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 21,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 22,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 23,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 24,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 25,
level: 99,
xp: 200000000,
dead: false,
},
]);
done();
};
getSkillPage('attack').then(callback);
test('Get attack top page', async () => {
jest.setTimeout(30000);
const data = await getSkillPage('attack');
expect(data).toMatchObject([
{
rsn: expect.any(String),
rank: 1,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 2,
level: 99,
xp: 200000000,
dead: false,
},
{ rsn: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
{
rsn: expect.any(String),
rank: 4,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 5,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 6,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 7,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 8,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 9,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 10,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 11,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 12,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 13,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 14,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 15,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 16,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 17,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 18,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 19,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 20,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 21,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 22,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 23,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 24,
level: 99,
xp: 200000000,
dead: false,
},
{
rsn: expect.any(String),
rank: 25,
level: 99,
xp: 200000000,
dead: false,
},
]);
});
test('Get non-existant player', async done => {
const callback = (err: AxiosError) => {
test('Get non-existant player', async () => {
jest.setTimeout(30000);
getStats('fishy').catch(err => {
if (err.response) {
expect(err.response.status).toBe(404);
}
done();
};
getStats('fishy').catch(callback);
});
});
test('Get stats by gamemode', async done => {
const callback = (stats: Stats) => {
expect(stats.skills).toStrictEqual({
overall: { rank: 1, level: 2277, xp: 4600000000 },
attack: { rank: 15, level: 99, xp: 200000000 },
defence: { rank: 27, level: 99, xp: 200000000 },
strength: { rank: 18, level: 99, xp: 200000000 },
hitpoints: { rank: 7, level: 99, xp: 200000000 },
ranged: { rank: 7, level: 99, xp: 200000000 },
prayer: { rank: 11, level: 99, xp: 200000000 },
magic: { rank: 32, level: 99, xp: 200000000 },
cooking: { rank: 158, level: 99, xp: 200000000 },
woodcutting: { rank: 15, level: 99, xp: 200000000 },
fletching: { rank: 12, level: 99, xp: 200000000 },
fishing: { rank: 9, level: 99, xp: 200000000 },
firemaking: { rank: 49, level: 99, xp: 200000000 },
crafting: { rank: 4, level: 99, xp: 200000000 },
smithing: { rank: 3, level: 99, xp: 200000000 },
mining: { rank: 25, level: 99, xp: 200000000 },
herblore: { rank: 5, level: 99, xp: 200000000 },
agility: { rank: 24, level: 99, xp: 200000000 },
thieving: { rank: 12, level: 99, xp: 200000000 },
slayer: { rank: 2, level: 99, xp: 200000000 },
farming: { rank: 19, level: 99, xp: 200000000 },
runecraft: { rank: 7, level: 99, xp: 200000000 },
hunter: { rank: 4, level: 99, xp: 200000000 },
construction: { rank: 4, level: 99, xp: 200000000 },
});
done();
};
getStatsByGamemode('Lynx Titan').then(callback);
test('Get stats by gamemode', async () => {
jest.setTimeout(30000);
const { skills } = await getStatsByGamemode('Lynx Titan');
expect(skills).toMatchObject({
overall: { rank: expect.any(Number), level: 2277, xp: 4600000000 },
attack: { rank: expect.any(Number), level: 99, xp: 200000000 },
defence: { rank: expect.any(Number), level: 99, xp: 200000000 },
strength: { rank: expect.any(Number), level: 99, xp: 200000000 },
hitpoints: { rank: expect.any(Number), level: 99, xp: 200000000 },
ranged: { rank: expect.any(Number), level: 99, xp: 200000000 },
prayer: { rank: expect.any(Number), level: 99, xp: 200000000 },
magic: { rank: expect.any(Number), level: 99, xp: 200000000 },
cooking: { rank: expect.any(Number), level: 99, xp: 200000000 },
woodcutting: { rank: expect.any(Number), level: 99, xp: 200000000 },
fletching: { rank: expect.any(Number), level: 99, xp: 200000000 },
fishing: { rank: expect.any(Number), level: 99, xp: 200000000 },
firemaking: { rank: expect.any(Number), level: 99, xp: 200000000 },
crafting: { rank: expect.any(Number), level: 99, xp: 200000000 },
smithing: { rank: expect.any(Number), level: 99, xp: 200000000 },
mining: { rank: expect.any(Number), level: 99, xp: 200000000 },
herblore: { rank: expect.any(Number), level: 99, xp: 200000000 },
agility: { rank: expect.any(Number), level: 99, xp: 200000000 },
thieving: { rank: expect.any(Number), level: 99, xp: 200000000 },
slayer: { rank: expect.any(Number), level: 99, xp: 200000000 },
farming: { rank: expect.any(Number), level: 99, xp: 200000000 },
runecraft: { rank: expect.any(Number), level: 99, xp: 200000000 },
hunter: { rank: expect.any(Number), level: 99, xp: 200000000 },
construction: { rank: expect.any(Number), level: 99, xp: 200000000 },
});
});

View File

@@ -13,6 +13,9 @@ import {
PlayerSkillRow,
ActivityName,
PlayerActivityRow,
Bosses,
LeagueStats,
Boss,
} from './types';
import {
getStatsURL,
@@ -26,6 +29,7 @@ import {
numberFromElement,
rsnFromElement,
getActivityPageURL,
BOSSES,
} from './utils';
export async function getStats(rsn: string): Promise<Player> {
@@ -95,10 +99,10 @@ export async function getStats(rsn: string): Promise<Player> {
throw Error('Player not found');
}
export async function getStatsByGamemode(
export async function getStatsByGamemode<T extends Gamemode = 'main'>(
rsn: string,
mode: Gamemode = 'main'
): Promise<Stats> {
mode: T = 'main' as T
): Promise<T extends 'leagues' ? LeagueStats : Stats> {
if (typeof rsn !== 'string') {
throw Error('RSN must be a string');
} else if (!/^[a-zA-Z0-9 _]+$/.test(rsn)) {
@@ -112,7 +116,7 @@ export async function getStatsByGamemode(
if (response.status !== 200) {
throw Error('Player not found');
}
const stats: Stats = parseStats(response.data);
const stats = parseStats(response.data, mode);
return stats;
}
@@ -209,7 +213,10 @@ export async function getRSNFormat(rsn: string): Promise<string> {
}
}
export function parseStats(csv: string): Stats {
export function parseStats<T extends Gamemode = 'main'>(
csv: string,
mode: T = 'main' as T
): T extends 'leagues' ? LeagueStats : Stats {
const splitCSV = csv
.split('\n')
.filter(entry => !!entry)
@@ -238,43 +245,69 @@ export function parseStats(csv: string): Stats {
return activity;
});
const [lp] = activityObjects.splice(0, 1);
const bhObjects = activityObjects.splice(0, BH_MODES.length);
const [lms] = activityObjects.splice(0, 1);
const clueObjects = activityObjects.splice(0, CLUES.length);
const [lms] = activityObjects.splice(0, 1);
const bossObjects = activityObjects.splice(0, BOSSES.length);
const skills: Skills = skillObjects.reduce<Skills>(
(prev, curr, index) => {
const newSkills = { ...prev };
newSkills[SKILLS[index]] = curr;
return newSkills;
},
{} as Skills
const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => {
const newSkills = { ...prev };
newSkills[SKILLS[index]] = curr;
return newSkills;
}, {} as Skills);
const bh: BH = bhObjects.reduce<BH>((prev, curr, index) => {
const newBH = { ...prev };
newBH[BH_MODES[index]] = curr;
return newBH;
}, {} as BH);
const clues: Clues = clueObjects.reduce<Clues>((prev, curr, index) => {
const newClues = { ...prev };
newClues[CLUES[index]] = curr;
return newClues;
}, {} as Clues);
// TODO Remove as soon as Jagex's API is fixed
const brokenBosses: Boss[] = ['callisto', 'cerberus'];
const TEMPBOSSES: Boss[] = BOSSES.reduce<Boss[]>(
(prev, curr) => (brokenBosses.includes(curr) ? prev : [...prev, curr]),
[]
);
const bh: BH = bhObjects.reduce<BH>(
(prev, curr, index) => {
const newBH = { ...prev };
newBH[BH_MODES[index]] = curr;
return newBH;
},
{} as BH
);
const bosses: Bosses = bossObjects.reduce<Bosses>((prev, curr, index) => {
const newBosses = { ...prev };
newBosses[TEMPBOSSES[index]] = brokenBosses.includes(BOSSES[index])
? { rank: -1, score: -1 }
: curr;
return newBosses;
}, {} as Bosses);
const clues: Clues = clueObjects.reduce<Clues>(
(prev, curr, index) => {
const newClues = { ...prev };
newClues[CLUES[index]] = curr;
return newClues;
},
{} as Clues
);
// TODO Remove as soon as Jagex's API is fixed
brokenBosses.forEach(broken => {
bosses[broken] = {
rank: -1,
score: -1,
};
});
const stats: Stats = {
skills,
bh,
lms,
clues,
bosses,
};
return stats;
const leagueStats: LeagueStats = {
skills,
lp,
clues,
bosses,
};
return (mode === 'leagues' ? leagueStats : stats) as T extends 'leagues'
? LeagueStats
: Stats;
}

View File

@@ -1,4 +1,11 @@
export type Gamemode = 'main' | 'iron' | 'hc' | 'ult' | 'dmm' | 'sdmm' | 'dmmt';
export type Gamemode =
| 'main'
| 'iron'
| 'hc'
| 'ult'
| 'dmm'
| 'dmmt'
| 'leagues';
export interface Skill {
rank: number;
@@ -54,6 +61,53 @@ export type BHType = 'rogue' | 'hunter';
export type BH = { [Type in BHType]: Activity };
export type Boss =
| 'abyssalsire'
| 'alchemicalhydra'
| 'barrowschests'
| 'bryophyta'
| 'callisto'
| 'cerberus'
| 'chambersofxeric'
| 'chambersofxericchallengemode'
| 'chaoselemental'
| 'chaosfanatic'
| 'commanderzilyana'
| 'corporealbeast'
| 'crazyarchaeologist'
| 'dagannothprime'
| 'dagannothrex'
| 'dagannothsupreme'
| 'derangedarchaeologist'
| 'generalgraardor'
| 'giantmole'
| 'grotesqueguardians'
| 'hespori'
| 'kalphitequeen'
| 'kingblackdragon'
| 'kraken'
| 'kreearra'
| 'kriltsutsaroth'
| 'mimic'
| 'obor'
| 'sarachnis'
| 'scorpia'
| 'skotizo'
| 'gauntlet'
| 'corruptedgauntlet'
| 'theatreofblood'
| 'thermonuclearsmokedevil'
| 'tzkalzuk'
| 'tztokjad'
| 'venenatis'
| 'vetion'
| 'vorkath'
| 'wintertodt'
| 'zalcano'
| 'zulrah';
export type Bosses = { [Type in Boss]: Activity };
export type ActivityName =
| 'hunterbh'
| 'roguebh'
@@ -64,13 +118,19 @@ export type ActivityName =
| 'mediumclues'
| 'hardclues'
| 'eliteclues'
| 'masterclues';
| 'masterclues'
| Boss;
export interface Stats {
skills: Skills;
clues: Clues;
bh: BH;
lms: Activity;
bosses: Bosses;
}
export interface LeagueStats extends Omit<Stats, 'bh' | 'lms'> {
lp: Activity;
}
export type Modes = { [M in Gamemode]?: Stats };

View File

@@ -1,4 +1,4 @@
import { SkillName, ClueType, BHType, Gamemode } from '../types';
import { SkillName, ClueType, BHType, Gamemode, Boss } from '../types';
export const BASE_URL = 'http://services.runescape.com/m=hiscore_oldschool';
export const STATS_URL = 'index_lite.ws?player=';
@@ -9,7 +9,7 @@ export const GAMEMODE_URL = {
hc: '_hardcore_ironman/',
iron: '_ironman/',
main: '/',
sdmm: '_seasonal/',
leagues: '_seasonal/',
ult: '_ultimate/',
};
export const SKILLS: SkillName[] = [
@@ -66,6 +66,51 @@ export const GAMEMODES: Gamemode[] = [
'hc',
'ult',
'dmm',
'sdmm',
'dmmt',
'leagues',
];
export const BOSSES: Boss[] = [
'abyssalsire',
'alchemicalhydra',
'barrowschests',
'bryophyta',
'chambersofxeric',
'chambersofxericchallengemode',
'callisto',
'cerberus',
'chaoselemental',
'chaosfanatic',
'commanderzilyana',
'corporealbeast',
'crazyarchaeologist',
'dagannothprime',
'dagannothrex',
'dagannothsupreme',
'derangedarchaeologist',
'generalgraardor',
'giantmole',
'grotesqueguardians',
'hespori',
'kalphitequeen',
'kingblackdragon',
'kraken',
'kreearra',
'kriltsutsaroth',
'mimic',
'obor',
'sarachnis',
'scorpia',
'skotizo',
'gauntlet',
'corruptedgauntlet',
'theatreofblood',
'thermonuclearsmokedevil',
'tzkalzuk',
'tztokjad',
'venenatis',
'vetion',
'vorkath',
'wintertodt',
'zalcano',
'zulrah',
];

2510
yarn.lock

File diff suppressed because it is too large Load Diff