hypixel-api-reborn 11.2.0 → 11.2.1

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