hypixel-api-reborn 11.2.0 → 11.3.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.
Files changed (101) hide show
  1. package/README.md +1 -1
  2. package/eslint.config.mjs +71 -0
  3. package/package.json +14 -20
  4. package/src/API/getAchievements.js +1 -0
  5. package/src/API/getBoosters.js +1 -0
  6. package/src/API/getChallenges.js +1 -0
  7. package/src/API/getGameCounts.js +1 -0
  8. package/src/API/getGuild.js +4 -3
  9. package/src/API/getGuildAchievements.js +1 -0
  10. package/src/API/getLeaderboards.js +1 -1
  11. package/src/API/getPlayer.js +1 -0
  12. package/src/API/getQuests.js +1 -0
  13. package/src/API/getRecentGames.js +5 -9
  14. package/src/API/getServerInfo.js +40 -37
  15. package/src/API/getStatus.js +1 -0
  16. package/src/API/getWatchdogStats.js +1 -0
  17. package/src/API/housing/getActiveHouses.js +7 -0
  18. package/src/API/housing/getHouse.js +9 -0
  19. package/src/API/housing/getPlayerHouses.js +11 -0
  20. package/src/API/index.js +6 -1
  21. package/src/API/skyblock/getAuction.js +8 -6
  22. package/src/API/skyblock/getAuctions.js +15 -12
  23. package/src/API/skyblock/getAuctionsByPlayer.js +1 -1
  24. package/src/API/skyblock/getBazaar.js +1 -3
  25. package/src/API/skyblock/getBingo.js +1 -2
  26. package/src/API/skyblock/getBingoByPlayer.js +3 -3
  27. package/src/API/skyblock/getEndedAuctions.js +1 -0
  28. package/src/API/skyblock/getFireSales.js +1 -1
  29. package/src/API/skyblock/getGarden.js +7 -0
  30. package/src/API/skyblock/getGovernment.js +1 -2
  31. package/src/API/skyblock/getMember.js +5 -2
  32. package/src/API/skyblock/getMuseum.js +1 -0
  33. package/src/API/skyblock/getNews.js +1 -0
  34. package/src/API/skyblock/getProfiles.js +5 -2
  35. package/src/Client.js +88 -16
  36. package/src/Private/rateLimit.js +7 -11
  37. package/src/Private/requests.js +12 -13
  38. package/src/Private/updater.js +2 -3
  39. package/src/Private/uuidCache.js +1 -2
  40. package/src/Private/validate.js +19 -19
  41. package/src/index.js +5 -0
  42. package/src/structures/APIIncident.js +1 -2
  43. package/src/structures/APIStatus.js +0 -1
  44. package/src/structures/Boosters/Booster.js +9 -8
  45. package/src/structures/Game.js +1 -1
  46. package/src/structures/Guild/Guild.js +19 -36
  47. package/src/structures/Guild/GuildMember.js +2 -2
  48. package/src/structures/House.js +54 -0
  49. package/src/structures/MiniGames/Arcade.js +798 -312
  50. package/src/structures/MiniGames/ArenaBrawl.js +98 -32
  51. package/src/structures/MiniGames/BedWars.js +197 -194
  52. package/src/structures/MiniGames/BlitzSurvivalGames.js +381 -129
  53. package/src/structures/MiniGames/BuildBattle.js +19 -8
  54. package/src/structures/MiniGames/CopsAndCrims.js +253 -25
  55. package/src/structures/MiniGames/Duels.js +905 -664
  56. package/src/structures/MiniGames/MegaWalls.js +390 -51
  57. package/src/structures/MiniGames/MurderMystery.js +151 -30
  58. package/src/structures/MiniGames/Paintball.js +31 -11
  59. package/src/structures/MiniGames/Pit.js +4 -5
  60. package/src/structures/MiniGames/Quakecraft.js +113 -50
  61. package/src/structures/MiniGames/SkyWars.js +528 -372
  62. package/src/structures/MiniGames/SmashHeroes.js +201 -73
  63. package/src/structures/MiniGames/SpeedUHC.js +77 -24
  64. package/src/structures/MiniGames/TNTGames.js +242 -73
  65. package/src/structures/MiniGames/TurboKartRacers.js +55 -115
  66. package/src/structures/MiniGames/UHC.js +144 -132
  67. package/src/structures/MiniGames/VampireZ.js +70 -37
  68. package/src/structures/MiniGames/Warlords.js +126 -1
  69. package/src/structures/MiniGames/WoolWars.js +60 -9
  70. package/src/structures/Pet.js +1 -1
  71. package/src/structures/Player.js +43 -128
  72. package/src/structures/PlayerCosmetics.js +5 -4
  73. package/src/structures/SkyBlock/Auctions/AuctionInfo.js +2 -1
  74. package/src/structures/SkyBlock/Auctions/BaseAuction.js +1 -1
  75. package/src/structures/SkyBlock/News/SkyblockNews.js +15 -15
  76. package/src/structures/SkyBlock/PlayerBingo.js +7 -14
  77. package/src/structures/SkyBlock/SkyblockGarden.js +146 -0
  78. package/src/structures/SkyBlock/SkyblockInventoryItem.js +4 -28
  79. package/src/structures/SkyBlock/SkyblockMember.js +90 -228
  80. package/src/structures/SkyBlock/SkyblockPet.js +3 -4
  81. package/src/structures/SkyBlock/Static/Bingo.js +10 -11
  82. package/src/structures/SkyBlock/Static/BingoData.js +1 -1
  83. package/src/structures/Static/Achievement.js +16 -15
  84. package/src/structures/Static/AchievementTier.js +2 -2
  85. package/src/structures/Static/Quest.js +2 -2
  86. package/src/utils/Constants.js +522 -520
  87. package/src/utils/{guildExp.js → Guild.js} +42 -12
  88. package/src/utils/Player.js +112 -0
  89. package/src/utils/SkyblockUtils.js +482 -192
  90. package/src/utils/arrayTools.js +1 -1
  91. package/src/utils/divide.js +1 -1
  92. package/src/utils/index.js +2 -1
  93. package/src/utils/isGuildID.js +1 -1
  94. package/src/utils/oscillation.js +4 -2
  95. package/src/utils/removeSnakeCase.js +11 -7
  96. package/src/utils/rgbToHexColor.js +1 -1
  97. package/src/utils/romanize.js +3 -3
  98. package/src/utils/toUuid.js +4 -4
  99. package/src/utils/varInt.js +2 -2
  100. package/typings/index.d.ts +1186 -967
  101. package/src/utils/toIGN.js +0 -24
@@ -1,213 +1,503 @@
1
- /* eslint-disable camelcase */
1
+ /* eslint-disable jsdoc/require-jsdoc */
2
2
  const constants = require('./Constants');
3
- module.exports = {
4
- async decode(base64, isBuffer = false) {
5
- const nbt = require('prismarine-nbt');
6
- const parseNbt = require('util').promisify(nbt.parse);
7
- const buffer = isBuffer ? base64 : Buffer.from(base64, 'base64');
8
- let data = await parseNbt(buffer);
9
- data = nbt.simplify(data);
10
- const newdata = [];
11
- for (let i = 0; i < data.i.length; i++) {
12
- newdata.push(data.i[i]);
13
- }
14
- return newdata;
15
- },
16
- getLevelByXp(xp, type, levelCap) {
17
- let xpTable;
18
- switch (type) {
19
- case 'runecrafting':
20
- xpTable = constants.runecrafting_xp;
21
- break;
22
- case 'dungeons':
23
- xpTable = constants.dungeon_xp;
24
- break;
25
- case 'hotm':
26
- xpTable = constants.hotm_xp;
27
- break;
28
- case 'social':
29
- xpTable = constants.social_xp;
30
- break;
31
- default:
32
- xpTable = constants.leveling_xp;
33
- }
34
- let maxLevel = Math.max(...Object.keys(xpTable));
35
- if ((constants.skills_cap[type] ?? maxLevel) > maxLevel) {
36
- xpTable = Object.assign(constants.xp_past_50, xpTable);
37
- maxLevel = typeof levelCap === 'number' ? maxLevel + levelCap : Math.max(...Object.keys(xpTable));
38
- }
39
- if (isNaN(xp)) {
40
- return {
41
- xp: 0,
42
- level: 0,
43
- maxLevel,
44
- xpCurrent: 0,
45
- xpForNext: xpTable[1],
46
- progress: 0,
47
- cosmetic: type === 'runecrafting' || type === 'social' ? true : false
48
- };
49
- }
50
- let xpTotal = 0;
51
- let level = 0;
52
- let xpForNext = 0;
53
- for (let x = 1; x <= maxLevel; x++) {
54
- if (!xpTable[x]) continue;
55
- xpTotal += xpTable[x];
56
- if (xpTotal > xp) {
57
- xpTotal -= xpTable[x];
58
- break;
59
- } else {
60
- level = x;
61
- }
62
- }
63
- const xpCurrent = Math.floor(xp - xpTotal);
64
- if (level < maxLevel) xpForNext = Math.ceil(xpTable[level + 1]);
65
- const progress = Math.floor(Math.max(0, Math.min(xpCurrent / xpForNext, 1)) * 100 * 10) / 10;
66
3
 
4
+ async function decode(base64, isBuffer = false) {
5
+ const nbt = require('prismarine-nbt');
6
+ const parseNbt = require('util').promisify(nbt.parse);
7
+ const buffer = isBuffer ? base64 : Buffer.from(base64, 'base64');
8
+ let data = await parseNbt(buffer);
9
+ data = nbt.simplify(data);
10
+ const newdata = [];
11
+ for (let i = 0; i < data.i.length; i++) {
12
+ newdata.push(data.i[i]);
13
+ }
14
+ return newdata;
15
+ }
16
+
17
+ function getLevelByXp(xp, type, levelCap) {
18
+ let xpTable;
19
+ switch (type) {
20
+ case 'runecrafting':
21
+ xpTable = constants.runecraftingXp;
22
+ break;
23
+ case 'dungeons':
24
+ xpTable = constants.dungeonXp;
25
+ break;
26
+ case 'hotm':
27
+ xpTable = constants.hotmXp;
28
+ break;
29
+ case 'social':
30
+ xpTable = constants.socialXp;
31
+ break;
32
+ case 'garden':
33
+ xpTable = constants.garden;
34
+ break;
35
+ case 'wheat':
36
+ xpTable = constants.wheat;
37
+ break;
38
+ case 'carrot':
39
+ xpTable = constants.carrot;
40
+ break;
41
+ case 'potato':
42
+ xpTable = constants.potato;
43
+ break;
44
+ case 'melon':
45
+ xpTable = constants.melon;
46
+ break;
47
+ case 'pumpkin':
48
+ xpTable = constants.pumpkin;
49
+ break;
50
+ case 'sugarCane':
51
+ xpTable = constants.sugarCane;
52
+ break;
53
+ case 'cocoaBeans':
54
+ xpTable = constants.cocoaBeans;
55
+ break;
56
+ case 'cactus':
57
+ xpTable = constants.cactus;
58
+ break;
59
+ case 'mushroom':
60
+ xpTable = constants.mushroom;
61
+ break;
62
+ case 'netherWart':
63
+ xpTable = constants.netherWart;
64
+ break;
65
+ default:
66
+ xpTable = constants.levelingXp;
67
+ }
68
+ let maxLevel = Math.max(...Object.keys(xpTable));
69
+ if ((constants.skillsCap[type] ?? maxLevel) > maxLevel) {
70
+ xpTable = Object.assign(constants.xpPast50, xpTable);
71
+ maxLevel = 'number' === typeof levelCap ? maxLevel + levelCap : Math.max(...Object.keys(xpTable));
72
+ }
73
+ if (isNaN(xp)) {
67
74
  return {
68
- xp: xp,
69
- level: level,
70
- maxLevel: maxLevel,
71
- xpCurrent: xpCurrent,
72
- xpForNext: xpForNext,
73
- progress: progress,
74
- cosmetic: type === 'runecrafting' || type === 'social' ? true : false
75
- };
76
- },
77
- getLevelByAchievement(achievementLevel, type) {
78
- let xpTable = constants.leveling_xp;
79
- let maxLevel = Math.max(...Object.keys(xpTable));
80
- if (constants.skills_cap[type] > maxLevel && type in constants.skills_achievements) {
81
- xpTable = Object.assign(constants.xp_past_50, xpTable);
82
- maxLevel = Math.max(...Object.keys(xpTable));
83
- }
84
- if (isNaN(achievementLevel)) {
85
- return {
86
- xp: 0,
87
- level: 0,
88
- maxLevel,
89
- xpCurrent: 0,
90
- xpForNext: xpTable[1],
91
- progress: 0
92
- };
93
- }
94
- let xpTotal = 0;
95
- let xpForNext = 0;
96
- for (let x = 1; x <= achievementLevel; x++) {
97
- xpTotal += xpTable[x];
98
- }
99
- if (achievementLevel < maxLevel) xpForNext = Math.ceil(xpTable[achievementLevel + 1]);
100
- return {
101
- xp: xpTotal,
102
- level: achievementLevel,
75
+ xp: 0,
76
+ level: 0,
103
77
  maxLevel,
104
78
  xpCurrent: 0,
105
- xpForNext,
106
- progress: 0
79
+ xpForNext: xpTable[1],
80
+ progress: 0,
81
+ cosmetic: Boolean('runecrafting' === type || 'social' === type)
107
82
  };
108
- },
109
- getSlayerLevel(slayer) {
110
- if (!slayer) {
111
- return {
112
- xp: 0,
113
- tier1: 0,
114
- tier2: 0,
115
- tier3: 0,
116
- tier4: 0,
117
- tier5: 0,
118
- level: 0
119
- };
120
- }
121
- const { claimed_levels } = slayer;
122
- let level = 0;
123
- for (const level_name in claimed_levels) {
124
- if (Object.prototype.hasOwnProperty.call(claimed_levels, level_name)) {
125
- const _level = parseInt(level_name.replace('_special', '').split('_').pop(), 10);
126
- if (_level > level) {
127
- level = _level;
128
- }
129
- }
83
+ }
84
+ let xpTotal = 0;
85
+ let level = 0;
86
+ let xpForNext = 0;
87
+ for (let x = 1; x <= maxLevel; x++) {
88
+ if (!xpTable[x]) continue;
89
+ xpTotal += xpTable[x];
90
+ if (xpTotal > xp) {
91
+ xpTotal -= xpTable[x];
92
+ break;
93
+ } else {
94
+ level = x;
130
95
  }
96
+ }
97
+ const xpCurrent = Math.floor(xp - xpTotal);
98
+ if (level < maxLevel) xpForNext = Math.ceil(xpTable[level + 1]);
99
+ const progress = Math.floor(Math.max(0, Math.min(xpCurrent / xpForNext, 1)) * 100 * 10) / 10;
100
+
101
+ return {
102
+ xp: xp,
103
+ level: level,
104
+ maxLevel: maxLevel,
105
+ xpCurrent: xpCurrent,
106
+ xpForNext: xpForNext,
107
+ progress: progress,
108
+ cosmetic: Boolean('runecrafting' === type || 'social' === type)
109
+ };
110
+ }
111
+
112
+ function getSlayerLevel(slayer) {
113
+ if (!slayer) {
131
114
  return {
132
- xp: slayer.xp || 0,
133
- tier1: slayer.boss_kills_tier_0 || 0,
134
- tier2: slayer.boss_kills_tier_1 || 0,
135
- tier3: slayer.boss_kills_tier_2 || 0,
136
- tier4: slayer.boss_kills_tier_3 || 0,
137
- tier5: slayer.boss_kills_tier_4 || 0,
138
- level
115
+ xp: 0,
116
+ tier1: 0,
117
+ tier2: 0,
118
+ tier3: 0,
119
+ tier4: 0,
120
+ tier5: 0,
121
+ level: 0
139
122
  };
140
- },
141
- getSlayerLevelByXp(xp) {
142
- const { slayer_xp } = constants;
143
- const maxLevel = Math.max(...Object.keys(slayer_xp));
144
- let level = 0;
145
- for (let x = 1; x <= maxLevel && slayer_xp[x] <= xp; x++) {
146
- level = x;
123
+ }
124
+
125
+ // eslint-disable-next-line camelcase
126
+ const { claimed_levels } = slayer;
127
+ let level = 0;
128
+
129
+ // eslint-disable-next-line camelcase
130
+ for (const levelName in claimed_levels) {
131
+ if (Object.prototype.hasOwnProperty.call(claimed_levels, levelName)) {
132
+ const newLevel = parseInt(levelName.replace('_special', '').split('_').pop(), 10);
133
+ if (newLevel > level) {
134
+ level = newLevel;
135
+ }
147
136
  }
148
- return level;
149
- },
150
- getBonusStat(level, skill, max, incremention) {
151
- const skill_stats = constants.bonus_stats[skill];
152
- const steps = Object.keys(skill_stats)
153
- .sort((a, b) => Number(a) - Number(b))
154
- .map((a) => Number(a));
155
- const bonus = Object.assign({}, constants.stat_template);
156
- for (let x = steps[0]; x <= max; x += incremention) {
157
- if (level < x) {
158
- break;
137
+ }
138
+ return {
139
+ xp: slayer.xp || 0,
140
+ tier1: slayer.boss_kills_tier_0 || 0,
141
+ tier2: slayer.boss_kills_tier_1 || 0,
142
+ tier3: slayer.boss_kills_tier_2 || 0,
143
+ tier4: slayer.boss_kills_tier_3 || 0,
144
+ tier5: slayer.boss_kills_tier_4 || 0,
145
+ level
146
+ };
147
+ }
148
+
149
+ function getMemberStats(obj) {
150
+ return Object.keys(obj).reduce(
151
+ (result, currentKey) => {
152
+ const key = currentKey.replace(/_[a-z]/gi, (match) => match[1].toUpperCase());
153
+
154
+ if (currentKey.startsWith('kills') || currentKey.startsWith('deaths')) {
155
+ const category = currentKey.startsWith('kills') ? 'kills' : 'deaths';
156
+ const subKey = key === category ? 'total' : key;
157
+
158
+ result[category][
159
+ subKey.replace(category, (sub, _, key) => {
160
+ return key[sub.length].toLowerCase() + key.slice(sub.length + 1);
161
+ })
162
+ ] = obj[currentKey];
163
+ } else {
164
+ result[key] = obj[currentKey];
159
165
  }
160
- const skill_step = steps
161
- .slice()
162
- .reverse()
163
- .find((a) => a <= x);
164
- const skill_bonus = skill_stats[skill_step];
165
- for (const skill in skill_bonus) {
166
- if (Object.prototype.hasOwnProperty.call(skill_bonus, skill)) {
167
- bonus[skill] += skill_bonus[skill];
166
+
167
+ return result;
168
+ },
169
+ { kills: {}, deaths: {} }
170
+ );
171
+ }
172
+
173
+ function getTrophyFishRank(level) {
174
+ if (1 === level) {
175
+ return 'Bronze';
176
+ } else if (2 === level) {
177
+ return 'Silver';
178
+ } else if (3 === level) {
179
+ return 'Gold';
180
+ } else if (4 === level) {
181
+ return 'Diamond';
182
+ }
183
+ return 'Bronze';
184
+ }
185
+
186
+ function getSkills(data) {
187
+ const skillsObject = {};
188
+ skillsObject.combat = getLevelByXp(data?.player_data?.experience?.SKILL_COMBAT ?? 0, 'combat');
189
+ skillsObject.farming = getLevelByXp(
190
+ data?.player_data?.experience?.SKILL_FARMING ?? 0,
191
+ 'farming',
192
+ data?.m?.jacobs_contest?.perks?.farming_level_cap ?? 0 + 50
193
+ );
194
+ skillsObject.fishing = getLevelByXp(data?.player_data?.experience?.SKILL_FISHING ?? 0, 'fishing');
195
+ skillsObject.mining = getLevelByXp(data?.player_data?.experience?.SKILL_MINING ?? 0, 'mining');
196
+ skillsObject.foraging = getLevelByXp(data?.player_data?.experience?.SKILL_FORAGING ?? 0, 'foraging');
197
+ skillsObject.enchanting = getLevelByXp(data?.player_data?.experience?.SKILL_ENCHANTING ?? 0, 'enchanting');
198
+ skillsObject.alchemy = getLevelByXp(data?.player_data?.experience?.SKILL_ALCHEMY ?? 0, 'alchemy');
199
+ skillsObject.carpentry = getLevelByXp(data?.player_data?.experience?.SKILL_CARPENTRY ?? 0, 'carpentry');
200
+ skillsObject.runecrafting = getLevelByXp(data?.player_data?.experience?.SKILL_RUNECRAFTING ?? 0, 'runecrafting');
201
+ skillsObject.taming = getLevelByXp(data?.player_data?.experience?.SKILL_TAMING ?? 0, 'taming');
202
+ skillsObject.social = getLevelByXp(data?.player_data?.experience?.SKILL_SOCIAL ?? 0, 'social');
203
+ const levels = Object.values(skillsObject)
204
+ .filter((skill) => true !== skill.cosmetic)
205
+ .map((skill) => skill.level);
206
+ skillsObject.average = levels.reduce((a, b) => a + b, 0) / levels.length;
207
+ return skillsObject;
208
+ }
209
+
210
+ function formatBestiaryMobs(userProfile, mobs) {
211
+ const output = [];
212
+ for (const mob of mobs) {
213
+ const mobBracket = constants.bestiaryBrackets[mob.bracket];
214
+
215
+ const totalKills = mob.mobs.reduce((acc, cur) => {
216
+ return acc + (userProfile.bestiary.kills[cur] ?? 0);
217
+ }, 0);
218
+
219
+ const maxKills = mob.cap;
220
+ const nextTierKills = mobBracket.find((tier) => totalKills < tier && tier <= maxKills);
221
+ const tier = nextTierKills ? mobBracket.indexOf(nextTierKills) : mobBracket.indexOf(maxKills) + 1;
222
+
223
+ output.push({
224
+ tier: tier
225
+ });
226
+ }
227
+
228
+ return output;
229
+ }
230
+
231
+ function getBestiaryLevel(userProfile) {
232
+ try {
233
+ if (userProfile.bestiary?.kills === undefined) {
234
+ return null;
235
+ }
236
+
237
+ const output = {};
238
+ let tiersUnlocked = 0;
239
+ for (const [category, data] of Object.entries(constants.bestiary)) {
240
+ const { mobs } = data;
241
+ output[category] = {};
242
+
243
+ if ('fishing' === category) {
244
+ for (const [key, value] of Object.entries(data)) {
245
+ output[category][key] = {
246
+ mobs: formatBestiaryMobs(userProfile, value.mobs)
247
+ };
248
+ tiersUnlocked += output[category][key].mobs.reduce((acc, cur) => acc + cur.tier, 0);
168
249
  }
250
+ } else {
251
+ output[category].mobs = formatBestiaryMobs(userProfile, mobs);
252
+ tiersUnlocked += output[category].mobs.reduce((acc, cur) => acc + cur.tier, 0);
169
253
  }
170
254
  }
171
- return bonus;
172
- },
173
- getEffectiveHealth(health, defense) {
174
- if (defense <= 0) return health;
175
- return Math.round(health * (1 + defense / 100));
176
- },
177
- getMemberStats(obj) {
178
- return Object.keys(obj).reduce(
179
- (result, currentKey) => {
180
- const key = currentKey.replace(/_[a-z]/gi, (match) => match[1].toUpperCase());
181
-
182
- if (currentKey.startsWith('kills') || currentKey.startsWith('deaths')) {
183
- const category = currentKey.startsWith('kills') ? 'kills' : 'deaths';
184
- const subKey = key === category ? 'total' : key;
185
-
186
- result[category][
187
- subKey.replace(category, (sub, _, key) => {
188
- return key[sub.length].toLowerCase() + key.slice(sub.length + 1);
189
- })
190
- ] = obj[currentKey];
191
- } else {
192
- result[key] = obj[currentKey];
255
+
256
+ return tiersUnlocked / 10;
257
+ } catch (error) {
258
+ // eslint-disable-next-line no-console
259
+ console.log(error);
260
+ return null;
261
+ }
262
+ }
263
+
264
+ function getSlayer(data) {
265
+ if (!data?.slayer?.slayer_bosses) return;
266
+ return {
267
+ zombie: getSlayerLevel(data?.slayer?.slayer_bosses?.zombie),
268
+ spider: getSlayerLevel(data?.slayer?.slayer_bosses?.spider),
269
+ wolf: getSlayerLevel(data?.slayer?.slayer_bosses?.wolf),
270
+ enderman: getSlayerLevel(data?.slayer?.slayer_bosses?.enderman),
271
+ blaze: getSlayerLevel(data?.slayer?.slayer_bosses?.blaze),
272
+ vampire: getSlayerLevel(data?.slayer?.slayer_bosses?.vampire)
273
+ };
274
+ }
275
+
276
+ function getDungeons(data) {
277
+ return {
278
+ types: {
279
+ catacombs: getLevelByXp(
280
+ data.dungeons?.dungeon_types?.catacombs ? data.dungeons.dungeon_types.catacombs.experience : null,
281
+ 'dungeons'
282
+ )
283
+ },
284
+ classes: {
285
+ healer: getLevelByXp(
286
+ data.dungeons?.player_classes?.healer ? data.dungeons.player_classes.healer.experience : null,
287
+ 'dungeons'
288
+ ),
289
+ mage: getLevelByXp(
290
+ data.dungeons?.player_classes?.mage ? data.dungeons.player_classes.mage.experience : null,
291
+ 'dungeons'
292
+ ),
293
+ berserk: getLevelByXp(
294
+ data.dungeons?.player_classes?.berserk ? data.dungeons.player_classes.berserk.experience : null,
295
+ 'dungeons'
296
+ ),
297
+ archer: getLevelByXp(
298
+ data.dungeons?.player_classes?.archer ? data.dungeons.player_classes.archer.experience : null,
299
+ 'dungeons'
300
+ ),
301
+ tank: getLevelByXp(
302
+ data.dungeons?.player_classes?.tank ? data.dungeons.player_classes.tank.experience : null,
303
+ 'dungeons'
304
+ )
305
+ }
306
+ };
307
+ }
308
+
309
+ function getJacobData(data) {
310
+ if (!data.jacobs_contest) {
311
+ return {
312
+ medals: {
313
+ bronze: 0,
314
+ silver: 0,
315
+ gold: 0
316
+ },
317
+ perks: {
318
+ doubleDrops: 0,
319
+ farmingLevelCap: 0,
320
+ personalBests: false
321
+ },
322
+ contests: {}
323
+ };
324
+ }
325
+ return {
326
+ medals: data.jacobs_contest.medals_inv
327
+ ? {
328
+ bronze: data.jacobs_contest.medals_inv.bronze || 0,
329
+ silver: data.jacobs_contest.medals_inv.silver || 0,
330
+ gold: data.jacobs_contest.medals_inv.gold || 0
331
+ }
332
+ : { bronze: 0, silver: 0, gold: 0 },
333
+ perks: data.jacobs_contest.perks
334
+ ? {
335
+ doubleDrops: data.jacobs_contest.perks.double_drops || 0,
336
+ farmingLevelCap: data.jacobs_contest.perks.farming_level_cap || 0,
337
+ personalBests: data.jacobs_contest.perks.personal_bests || false
193
338
  }
339
+ : { doubleDrops: 0, farmingLevelCap: 0, personalBests: false },
340
+ contests: data.jacobs_contest.contests || {}
341
+ };
342
+ }
194
343
 
195
- return result;
344
+ function getChocolateFactory(data) {
345
+ if (!data?.events?.easter) {
346
+ return {
347
+ employees: {
348
+ bro: 0,
349
+ cousin: 0,
350
+ sis: 0,
351
+ father: 0,
352
+ grandma: 0,
353
+ dog: 0,
354
+ uncle: 0
355
+ },
356
+ chocolate: {
357
+ current: 0,
358
+ total: 0,
359
+ sincePrestige: 0
360
+ },
361
+ timeTower: {
362
+ charges: 0,
363
+ level: 0
364
+ },
365
+ upgrades: {
366
+ click: 0,
367
+ multiplier: 0,
368
+ rabbitRarity: 0
369
+ },
370
+ goldenClick: {
371
+ amount: 0,
372
+ year: 0
196
373
  },
197
- { kills: {}, deaths: {} }
198
- );
199
- },
200
- getTrophyFishRank(level) {
201
- if (level === 1) {
202
- return 'Bronze';
203
- } else if (level === 2) {
204
- return 'Silver';
205
- } else if (level === 3) {
206
- return 'Gold';
207
- } else if (level === 4) {
208
- return 'Diamond';
374
+ barnCapacity: 0,
375
+ prestige: 0
376
+ };
377
+ }
378
+ return {
379
+ employees: {
380
+ bro: data?.events?.easter?.employees?.rabbit_bro || 0,
381
+ cousin: data?.events?.easter?.employees?.rabbit_cousin || 0,
382
+ sis: data?.events?.easter?.employees?.rabbit_sis || 0,
383
+ father: data?.events?.easter?.employees?.rabbit_father || 0,
384
+ grandma: data?.events?.easter?.employees?.rabbit_grandma || 0,
385
+ dog: data?.events?.easter?.employees?.rabbit_dog || 0,
386
+ uncle: data?.events?.easter?.employees?.rabbit_uncle || 0
387
+ },
388
+ chocolate: {
389
+ current: data?.events?.easter?.chocolate || 0,
390
+ total: data?.events?.easter?.total_chocolate || 0,
391
+ sincePrestige: data?.events?.easter?.chocolate_since_prestige || 0
392
+ },
393
+ timeTower: {
394
+ charges: data?.events?.easter?.time_tower?.charges || 0,
395
+ level: data?.events?.easter?.time_tower?.level || 0
396
+ },
397
+ upgrades: {
398
+ click: data?.events?.easter?.click_upgrades || 0,
399
+ multiplier: data?.events?.easter?.chocolate_multiplier_upgrades || 0,
400
+ rabbitRarity: data?.events?.easter?.rabbit_rarity_upgrades || 0
401
+ },
402
+ goldenClick: {
403
+ amount: data?.events?.easter?.golden_click_amount || 0,
404
+ year: data?.events?.easter?.golden_click_year || 0
405
+ },
406
+ barnCapacity: data?.events?.easter?.rabbit_barn_capacity_level || 0,
407
+ prestige: data?.events?.easter?.chocolate_level || 0
408
+ };
409
+ }
410
+
411
+ function getPetLevel(petExp, offsetRarity, maxLevel) {
412
+ const rarityOffset = constants.petRarityOffset[offsetRarity];
413
+ const levels = constants.petLevels.slice(rarityOffset, rarityOffset + maxLevel - 1);
414
+
415
+ const xpMaxLevel = levels.reduce((a, b) => a + b, 0);
416
+ let xpTotal = 0;
417
+ let level = 1;
418
+
419
+ let xpForNext;
420
+
421
+ for (let i = 0; i < maxLevel; i++) {
422
+ xpTotal += levels[i];
423
+
424
+ if (xpTotal > petExp) {
425
+ xpTotal -= levels[i];
426
+ break;
209
427
  } else {
210
- return 'Bronze';
428
+ level++;
211
429
  }
212
430
  }
431
+
432
+ let xpCurrent = Math.floor(petExp - xpTotal);
433
+ let progress;
434
+
435
+ if (level < maxLevel) {
436
+ xpForNext = Math.ceil(levels[level - 1]);
437
+ progress = Math.max(0, Math.min(xpCurrent / xpForNext, 1));
438
+ } else {
439
+ level = maxLevel;
440
+ xpCurrent = petExp - levels[maxLevel - 1];
441
+ xpForNext = 0;
442
+ progress = 1;
443
+ }
444
+
445
+ return {
446
+ level,
447
+ xpCurrent,
448
+ xpForNext,
449
+ progress,
450
+ xpMaxLevel
451
+ };
452
+ }
453
+
454
+ function parseRarity(stringContainingRarity) {
455
+ const rarityArray = [
456
+ 'COMMON',
457
+ 'UNCOMMON',
458
+ 'RARE',
459
+ 'EPIC',
460
+ 'LEGENDARY',
461
+ 'MYTHIC',
462
+ 'DIVINE',
463
+ 'SPECIAL',
464
+ 'VERY SPECIAL'
465
+ ];
466
+ for (const rarity of rarityArray) {
467
+ if (stringContainingRarity.includes(rarity)) return rarity;
468
+ }
469
+ }
470
+
471
+ function parseGearScore(lore) {
472
+ for (const line of lore) {
473
+ if (line.match(/Gear Score: §[0-9a-f](\d+)/)) return Number(line.match(/Gear Score: §d(\d+)/)[1]);
474
+ }
475
+ }
476
+
477
+ function populateGoals(achieved, all) {
478
+ const populatedAchieved = [];
479
+ const unachieved = [];
480
+ for (const goal of all) {
481
+ if (achieved.find((str) => str === goal.name)) populatedAchieved.push(goal);
482
+ else unachieved.push(goal);
483
+ }
484
+ populatedAchieved.unachievedGoals = unachieved;
485
+ return populatedAchieved;
486
+ }
487
+
488
+ module.exports = {
489
+ decode,
490
+ getLevelByXp,
491
+ getMemberStats,
492
+ getTrophyFishRank,
493
+ getSkills,
494
+ getBestiaryLevel,
495
+ getSlayer,
496
+ getDungeons,
497
+ getJacobData,
498
+ getChocolateFactory,
499
+ getPetLevel,
500
+ parseRarity,
501
+ parseGearScore,
502
+ populateGoals
213
503
  };
@@ -1,4 +1,4 @@
1
1
  module.exports = {
2
- isStrArray: (input) => Array.isArray(input) || typeof input === 'string',
2
+ isStrArray: (input) => Array.isArray(input) || 'string' === typeof input,
3
3
  strToArray: (input) => [input].flat()
4
4
  };