├── .gitignore ├── API ├── config.json ├── constants │ ├── bestiary.js │ ├── calendar.js │ ├── crimson.js │ ├── farming.js │ ├── fetchur_items.js │ ├── functions.js │ ├── maro_networth │ │ ├── generators │ │ │ ├── forgeGenerator.js │ │ │ ├── itemGenerator.js │ │ │ ├── networthGenerator.js │ │ │ └── petGenerator.js │ │ ├── src │ │ │ ├── constants.js │ │ │ ├── constants │ │ │ │ ├── forge.js │ │ │ │ ├── gemstones.js │ │ │ │ ├── items.js │ │ │ │ ├── misc.js │ │ │ │ ├── pets.js │ │ │ │ ├── reforges.js │ │ │ │ └── talismans.js │ │ │ └── helper.js │ │ └── storage │ │ │ └── requestHandler.js │ ├── milestones.js │ ├── mining.js │ ├── minion_slots.js │ ├── minions.js │ ├── missing.js │ ├── mobs.js │ ├── networth │ │ ├── essence_upgrades.js │ │ ├── functions.js │ │ ├── ignored_enchantments.js │ │ ├── ignored_items.js │ │ ├── reforge_stones.js │ │ └── vanilla_items.js │ ├── pets.js │ ├── senitherWeight.js │ ├── skills.js │ ├── skins.js │ ├── symbols.js │ ├── talismans.js │ ├── trophyFishing.js │ ├── weight.js │ └── xp_tables.js ├── data │ ├── auctions.json │ ├── collections.json │ ├── prices.json │ ├── refreshAuctions.js │ ├── refreshCollections.js │ └── refreshPrices.js ├── functions │ ├── getAuctionHouse.js │ ├── getAuctions.js │ ├── getBingoProfile.js │ ├── getCalendar.js │ ├── getFetchur.js │ ├── getItems.js │ ├── getLatestProfile.js │ ├── getProfile.js │ ├── getProfileParsed.js │ ├── getProfiles.js │ └── getProfilesParsed.js ├── json │ └── items.json ├── stats │ ├── armor.js │ ├── auctions.js │ ├── bestiary.js │ ├── bingo.js │ ├── cakebag.js │ ├── collections.js │ ├── crimson.js │ ├── deaths.js │ ├── dungeons.js │ ├── enchanting.js │ ├── equipment.js │ ├── farming.js │ ├── hypixelLevel.js │ ├── items.js │ ├── kills.js │ ├── milestones.js │ ├── mining.js │ ├── minions.js │ ├── missing.js │ ├── networth.js │ ├── pets.js │ ├── rank.js │ ├── skills.js │ ├── slayer.js │ ├── talismans.js │ ├── trophyFishing.js │ └── weight.js └── utils │ ├── hypixel.js │ ├── nbt.js │ ├── request.js │ └── uuid.js ├── README.md ├── config.json ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | .env 4 | package-lock.json 5 | .prettierrc.json -------------------------------------------------------------------------------- /API/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auctionHouse": { 3 | "refreshMessage": true 4 | }, 5 | "prices": { 6 | "refreshMessage": true 7 | }, 8 | "debug": false 9 | } 10 | -------------------------------------------------------------------------------- /API/constants/calendar.js: -------------------------------------------------------------------------------- 1 | // CREDITS: https://github.com/slothpixel/core (Modified) 2 | const { nth, parseTimestamp } = require("./maro_networth/src/helper"); 3 | 4 | const months = [ 5 | "Early Spring", 6 | "Spring", 7 | "Late Spring", 8 | "Early Summer", 9 | "Summer", 10 | "Late Summer", 11 | "Early Autumn", 12 | "Autumn", 13 | "Late Autumn", 14 | "Early Winter", 15 | "Winter", 16 | "Late Winter", 17 | ]; 18 | 19 | const hourMs = 50000; 20 | const dayMs = 24 * hourMs; 21 | const monthLength = 31; 22 | const yearLength = months.length; 23 | 24 | const monthMs = monthLength * dayMs; 25 | const yearMs = yearLength * monthMs; 26 | 27 | const yearZero = 1560275700000; 28 | 29 | const zooStart = yearZero + yearMs * 66; 30 | const zooTimeLength = yearMs / 2; 31 | 32 | const pets = ["Elephant", "Giraffe", "Blue Whale", "Tiger", "Lion", "Monkey"]; 33 | 34 | function getOffset(month, day, hour = 0) { 35 | return ( 36 | months.indexOf(month) * monthLength * dayMs + 37 | (day - 1) * dayMs + 38 | hour * hourMs 39 | ); 40 | } 41 | 42 | function timeToSkyblockYear(time) { 43 | return Math.floor((time - yearZero) / yearMs) + 1; 44 | } 45 | 46 | function getZooPet(time) { 47 | const iterations = Math.floor((time - zooStart) / zooTimeLength); 48 | 49 | return pets[iterations % pets.length]; 50 | } 51 | 52 | function getJacobEventTimes() { 53 | const times = []; 54 | 55 | for (let month = 0; month < 12; month++) { 56 | let day = 2; 57 | while (day <= 31) { 58 | times.push({ 59 | start: getOffset(months[month], day), 60 | end: getOffset(months[month], day), 61 | }); 62 | 63 | if (day === 30) break; 64 | day += 3; 65 | if (day > 31) { 66 | day %= 31; 67 | month++; 68 | } 69 | } 70 | } 71 | return times; 72 | } 73 | 74 | function getDarkAuctionEventTimes() { 75 | const times = []; 76 | 77 | for (let month = 0; month < 12; month++) { 78 | let day = 1; 79 | while (day <= 31) { 80 | times.push({ 81 | start: getOffset(months[month], day), 82 | end: getOffset(months[month], day), 83 | }); 84 | 85 | if (day === 29) break; 86 | day += 3; 87 | if (day > 31) { 88 | day %= 31; 89 | month++; 90 | } 91 | } 92 | } 93 | return times; 94 | } 95 | 96 | function getFallenStarCultTimes() { 97 | const times = []; 98 | 99 | for (let month = 0; month < 12; month++) { 100 | for (let i = 1; i <= 4; i++) { 101 | times.push({ 102 | start: getOffset(months[month], i * 7), 103 | end: getOffset(months[month], i * 7, 6), 104 | }); 105 | } 106 | } 107 | return times; 108 | } 109 | 110 | function getUniqueListBy(array, key) { 111 | return [...new Map(array.map((item) => [item[key], item])).values()]; 112 | } 113 | 114 | const eventTimes = { 115 | BANK_INTEREST: { 116 | name: "Bank Interest", 117 | times: [ 118 | { 119 | start: getOffset("Early Spring", 1), 120 | end: getOffset("Early Spring", 1), 121 | }, 122 | { 123 | start: getOffset("Early Summer", 1), 124 | end: getOffset("Early Summer", 1), 125 | }, 126 | { 127 | start: getOffset("Early Autumn", 1), 128 | end: getOffset("Early Autumn", 1), 129 | }, 130 | { 131 | start: getOffset("Early Winter", 1), 132 | end: getOffset("Early Winter", 1), 133 | }, 134 | ], 135 | }, 136 | DARK_AUCTION: { 137 | name: "Dark Auction", 138 | times: getDarkAuctionEventTimes(), 139 | }, 140 | ELECTION_BOOTH_OPENS: { 141 | name: "Election Booth Opens", 142 | times: [ 143 | { 144 | start: getOffset("Late Summer", 27), 145 | end: getOffset("Late Summer", 27), 146 | }, 147 | ], 148 | }, 149 | ELECTION_OVER: { 150 | name: "Election Over", 151 | times: [ 152 | { 153 | start: getOffset("Late Spring", 27), 154 | end: getOffset("Late Spring", 27), 155 | }, 156 | ], 157 | }, 158 | FALLEN_STAR_CULT: { 159 | name: "Cult of the Fallen Star", 160 | times: getFallenStarCultTimes(), 161 | }, 162 | FEAR_MONGERER: { 163 | name: "Fear Mongerer", 164 | times: [ 165 | { 166 | start: getOffset("Autumn", 26), 167 | end: getOffset("Late Autumn", 3), 168 | }, 169 | ], 170 | }, 171 | JACOBS_CONTEST: { 172 | name: "Jacob's Farming Contest", 173 | times: getJacobEventTimes(), 174 | }, 175 | JERRYS_WORKSHOP: { 176 | name: "Jerry's Workshop", 177 | times: [ 178 | { 179 | start: getOffset("Late Winter", 1), 180 | end: getOffset("Late Winter", 31), 181 | }, 182 | ], 183 | }, 184 | NEW_YEAR_CELEBRATION: { 185 | name: "New Year Celebration", 186 | times: [ 187 | { 188 | start: getOffset("Late Winter", 29), 189 | end: getOffset("Late Winter", 31), 190 | }, 191 | ], 192 | }, 193 | SEASON_OF_JERRY: { 194 | name: "Season of Jerry", 195 | times: [ 196 | { 197 | start: getOffset("Late Winter", 24), 198 | end: getOffset("Late Winter", 26), 199 | }, 200 | ], 201 | }, 202 | SPOOKY_FESTIVAL: { 203 | name: "Spooky Festival", 204 | times: [ 205 | { 206 | start: getOffset("Autumn", 29), 207 | end: getOffset("Autumn", 31), 208 | }, 209 | ], 210 | }, 211 | TRAVELING_ZOO: { 212 | name: "Traveling Zoo", 213 | times: [ 214 | { 215 | start: getOffset("Early Summer", 1), 216 | end: getOffset("Early Summer", 3), 217 | }, 218 | { 219 | start: getOffset("Early Winter", 1), 220 | end: getOffset("Early Winter", 3), 221 | }, 222 | ], 223 | }, 224 | }; 225 | 226 | function buildSkyblockCalendar(events, from, to, years, stopAtYearEnd = true) { 227 | const now = Date.now(); 228 | let fromDate = from || now; 229 | 230 | if (typeof from === "string") fromDate = parseTimestamp(from); 231 | fromDate = Math.max(fromDate, yearZero); 232 | 233 | let toDate = to || fromDate + yearMs * years || now; 234 | if (typeof to === "string") toDate = parseTimestamp(to); 235 | 236 | if (Number.isNaN(Number(fromDate)) || Number.isNaN(Number(toDate))) { 237 | throw new TypeError("Parameters 'from' and 'to' must be integers"); 238 | } 239 | 240 | if (toDate < fromDate) 241 | throw new Error("Parameter 'to' must be greater than 'from'"); 242 | 243 | const currentYear = Math.floor((fromDate - yearZero) / yearMs); 244 | const currentOffset = (fromDate - yearZero) % yearMs; 245 | 246 | const currentMonth = Math.floor(currentOffset / monthMs); 247 | const currentMonthOffset = (currentOffset - currentMonth * monthMs) % monthMs; 248 | 249 | const currentDay = Math.floor(currentMonthOffset / dayMs); 250 | const currentDayOffset = (currentMonthOffset - currentDay * dayMs) % dayMs; 251 | 252 | let currentHour = Math.floor(currentDayOffset / hourMs); 253 | const currentMinute = Math.floor( 254 | ((currentDayOffset - currentHour * hourMs) / hourMs) * 60 255 | ); 256 | 257 | const suffix = currentHour >= 12 ? "pm" : "am"; 258 | 259 | if (currentHour > 12) currentHour -= 12; 260 | if (currentHour === 0) currentHour = 12; 261 | 262 | const formattedTime = `${currentHour}:${(Math.floor(currentMinute / 10) * 10) 263 | .toString() 264 | .padStart(2, "0")}${suffix}`; 265 | 266 | const eventList = {}; 267 | 268 | Object.keys(eventTimes).forEach((key) => { 269 | eventList[key] = { 270 | name: "", 271 | duration: 0, 272 | events: [], 273 | }; 274 | }); 275 | 276 | // convert 'to' to years for looping 277 | let toToYears = Number.isNaN(Number(years)) 278 | ? timeToSkyblockYear(toDate) - currentYear 279 | : years; 280 | 281 | toToYears = Math.min(toToYears, 10); 282 | 283 | if (toToYears <= 0) throw new Error("Parameter 'years' must be positive"); 284 | 285 | // convert string to boolean 286 | const stopBoolean = String(stopAtYearEnd).toLowerCase() === "true"; 287 | 288 | if (!stopBoolean) toToYears++; 289 | 290 | for (let i = 0; i < toToYears; i++) { 291 | for (const [event, { name, times: times_ }] of Object.entries(eventTimes)) { 292 | const duration = times_[0].end - times_[0].start + dayMs; 293 | 294 | eventList[event].name = name; 295 | eventList[event].duration = duration; 296 | 297 | for (const { start: start_, end: end_ } of times_) { 298 | const times = { 299 | start: start_ + yearMs * i, 300 | end: end_ + yearMs * i, 301 | }; 302 | 303 | /* eslint-disable-next-line no-continue */ 304 | if (stopBoolean && times.end < currentOffset) continue; 305 | 306 | const msTill = 307 | times.end < currentOffset 308 | ? yearMs - currentOffset + times.start 309 | : times.start - currentOffset; 310 | 311 | const o = { 312 | start_timestamp: 313 | (Math.round(fromDate / 1000) + Math.round(msTill / 1000)) * 1000, 314 | end_timestamp: 315 | (Math.round(fromDate / 1000) + 316 | Math.round((msTill + duration) / 1000)) * 317 | 1000, 318 | starting_in: msTill, 319 | ending_in: msTill + duration, 320 | }; 321 | 322 | if (name === "Traveling Zoo") o.pet = getZooPet(fromDate + msTill); 323 | 324 | eventList[event].events.push(o); 325 | } 326 | } 327 | } 328 | 329 | Object.keys(eventList).forEach((key) => { 330 | eventList[key].events = getUniqueListBy( 331 | eventList[key].events, 332 | "start_timestamp" 333 | ) 334 | /* eslint-disable-next-line camelcase */ 335 | .filter(({ start_timestamp }) => start_timestamp < toDate) 336 | .sort((a, b) => a.start_timestamp - b.start_timestamp); 337 | }); 338 | 339 | const eventsToFilter = events ? events.split(",") : Object.keys(eventTimes); 340 | 341 | const filteredEvents = {}; 342 | for (const event of eventsToFilter) { 343 | filteredEvents[event] = eventList[event]; 344 | } 345 | 346 | return { 347 | from: fromDate, 348 | to: fromDate + (yearMs - currentOffset), 349 | 350 | date: `${months[currentMonth]} ${nth(currentDay + 1)}, ${currentYear + 1}`, 351 | year: currentYear + 1, 352 | month: months[currentMonth], 353 | day: currentDay + 1, 354 | 355 | time: formattedTime, 356 | hour: currentHour, 357 | minute: Math.floor(currentMinute / 10) * 10, 358 | 359 | next_day_countdown: dayMs - currentDayOffset, 360 | next_month_countdown: monthMs - currentMonthOffset, 361 | next_year_countdown: yearMs - currentOffset, 362 | 363 | events: filteredEvents, 364 | }; 365 | } 366 | 367 | function buildSkyblockEvents() { 368 | const o = {}; 369 | Object.entries(eventTimes).forEach(([key, { name }]) => { 370 | o[key] = name; 371 | }); 372 | return o; 373 | } 374 | 375 | module.exports = { 376 | buildSkyblockCalendar, 377 | buildSkyblockEvents, 378 | }; 379 | -------------------------------------------------------------------------------- /API/constants/crimson.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | factions: { 3 | selected_faction: null, 4 | mages_reputation: 0, 5 | barbarians_reputation: 0, 6 | }, 7 | matriarch: { 8 | pearls_collected: 0, 9 | last_attempt: 0, 10 | }, 11 | kuudra_completed_tiers: { 12 | none: 0, 13 | hot: 0, 14 | }, 15 | dojo: { 16 | DOJO_POINTS_MOB_KB: 0, 17 | DOJO_TIME_MOB_KB: 0, 18 | DOJO_POINTS_WALL_JUMP: 0, 19 | DOJO_TIME_WALL_JUMP: 0, 20 | DOJO_POINTS_ARCHER: 0, 21 | DOJO_TIME_ARCHER: 0, 22 | DOJO_POINTS_SWORD_SWAP: 0, 23 | DOJO_TIME_SWORD_SWAP: 0, 24 | DOJO_POINTS_SNAKE: 0, 25 | DOJO_TIME_SNAKE: 0, 26 | DOJO_POINTS_FIREBALL: 0, 27 | DOJO_TIME_FIREBALL: 0, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /API/constants/farming.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | jacob_crops: { 3 | CARROT_ITEM: { 4 | name: "Carrot", 5 | }, 6 | CACTUS: { 7 | name: "Cactus", 8 | }, 9 | "INK_SACK:3": { 10 | name: "Cocoa Beans", 11 | }, 12 | MELON: { 13 | name: "Melon", 14 | }, 15 | MUSHROOM_COLLECTION: { 16 | name: "Mushroom", 17 | }, 18 | NETHER_STALK: { 19 | name: "Nether Wart", 20 | }, 21 | POTATO_ITEM: { 22 | name: "Potato", 23 | }, 24 | PUMPKIN: { 25 | name: "Pumpkin", 26 | }, 27 | SUGAR_CANE: { 28 | name: "Sugar Cane", 29 | }, 30 | WHEAT: { 31 | name: "Wheat", 32 | }, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /API/constants/fetchur_items.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 0: { 3 | name: "Red Wool", 4 | quantity: 50, 5 | text: "50x Red Wool", 6 | image: "https://sky.shiiyu.moe/item/WOOL:14", 7 | description: 8 | "This item can be purchased from the Wool Merchant at the Builder's House in the Hub", 9 | }, 10 | 1: { 11 | name: "Yellow Stained Glass", 12 | quantity: 20, 13 | text: "20x Yellow Stained Glass", 14 | image: "https://sky.shiiyu.moe/item/STAINED_GLASS:4", 15 | description: 16 | "This item can be purchased from the Builder at the Builder's House in the Hub", 17 | }, 18 | 2: { 19 | name: "Compass", 20 | quantity: 1, 21 | text: "1x Compass", 22 | image: "https://sky.shiiyu.moe/item/COMPASS", 23 | description: "This item can be crafted using 1 Redstone and 4 Iron Ingot", 24 | }, 25 | 3: { 26 | name: "Mithril", 27 | quantity: 20, 28 | text: "20x Mithril", 29 | image: "https://sky.shiiyu.moe/item/MITHRIL_ORE", 30 | description: 31 | "This item can be mined in the Dwarven Mines/Crystal Hollows or purchased from the Bazaar", 32 | }, 33 | 4: { 34 | name: "Firework Rocket", 35 | quantity: 1, 36 | text: "1x Firework Rocket", 37 | image: "https://sky.shiiyu.moe/item/FIREWORK", 38 | description: "This item can be crafted using 1 Gunpowder and 1 Paper", 39 | }, 40 | 5: { 41 | name: "Coffee", 42 | quantity: 1, 43 | text: "1x Coffee", 44 | image: "https://sky.shiiyu.moe/item/DECENT_COFFEE", 45 | description: "This item can be purchased from the Bartender in the Hub", 46 | }, 47 | 6: { 48 | name: "Door", 49 | quantity: 1, 50 | text: "1x Door", 51 | image: "https://sky.shiiyu.moe/item/WOOD_DOOR", 52 | description: "This item can be crafted using 6 Wood planks", 53 | }, 54 | 7: { 55 | name: "Rabbit's Foot", 56 | quantity: 3, 57 | text: "3x Rabbit's Feet", 58 | image: "https://sky.shiiyu.moe/item/RABBIT_FOOT", 59 | description: 60 | "This item can be dropped when killing an Rabbit or buying it from the Bazaar.", 61 | }, 62 | 8: { 63 | name: "Superboom TNT", 64 | quantity: 1, 65 | text: "1x Superboom TNT", 66 | image: "https://sky.shiiyu.moe/item/SUPERBOOM_TNT", 67 | description: 68 | "This item can be purchased from the Auction House or found in dungeons", 69 | }, 70 | 9: { 71 | name: "Pumpkin", 72 | quantity: 1, 73 | text: "1x Pumpkin", 74 | image: "https://sky.shiiyu.moe/item/PUMPKIN", 75 | description: 76 | "This item can be farmed in the Barn or purchased from the Bazaar", 77 | }, 78 | 10: { 79 | name: "Flint and Steel", 80 | quantity: 1, 81 | text: "1x Flint and Steel", 82 | image: "https://sky.shiiyu.moe/item/FLINT_AND_STEEL", 83 | description: "This item can be crafted using 1 Flint and 1 Iron Ingot", 84 | }, 85 | 11: { 86 | name: "Nether Quartz Ore", 87 | quantity: 50, 88 | text: "50x Nether Quartz Ore", 89 | image: "https://sky.shiiyu.moe/item/QUARTZ_ORE", 90 | description: 91 | "This item can be mined in the Crimson Isle using a Pickaxe enchanted with Silk Touch", 92 | }, 93 | 12: { 94 | name: "Red Wool", 95 | quantity: 50, 96 | text: "50x Red Wool", 97 | image: "https://sky.shiiyu.moe/item/WOOL:14", 98 | description: 99 | "This item can be purchased from the Wool Merchant at the Builder's House in the Hub", 100 | }, 101 | }; 102 | -------------------------------------------------------------------------------- /API/constants/functions.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | titleCase: function titleCase(str, replaceunderscore = false) { 3 | try { 4 | if (replaceunderscore) str = str.replace(/_/g, " "); 5 | let splitStr = str.toLowerCase().split(" "); 6 | for (let i = 0; i < splitStr.length; i++) { 7 | splitStr[i] = splitStr[i][0].toUpperCase() + splitStr[i].substr(1); 8 | } 9 | str = splitStr.join(" "); 10 | return str; 11 | } catch (err) { 12 | return null; 13 | } 14 | }, 15 | capitalize: function capitalize(str) { 16 | if (!str) return null; 17 | return str.charAt(0).toUpperCase() + str.slice(1); 18 | }, 19 | toFixed: function toFixed(num, fixed) { 20 | let re = new RegExp("^-?\\d+(?:.\\d{0," + (fixed || -1) + "})?"); 21 | return num.toString().match(re)[0]; 22 | }, 23 | isFormatCode: function isFormatCode(code) { 24 | return /[k-o]/.test(code); 25 | }, 26 | isColorCode: function isColorCode(code) { 27 | return /[0-9a-f]/.test(code); 28 | }, 29 | renderLore: function renderLore(text) { 30 | let output = ""; 31 | 32 | /** @type {ColorCode|null} */ 33 | let color = null; 34 | /** @type {Set} */ 35 | const formats = new Set(); 36 | 37 | // @ts-ignore - this regex always matches so we don't need to check for null 38 | for (let part of text.match(/(§[0-9a-fk-or])*[^§]*/g)) { 39 | if (part.length === 0) continue; 40 | 41 | output += ""; 42 | 43 | if (formats.size > 0) { 44 | output += `${Array.from(formats, (x) => "§" + x).join(" ")}`; 45 | } 46 | 47 | output += `${part}`; 48 | } 49 | return output; 50 | }, 51 | formatNumber: function formatNumber(number, floor, rounding = 10) { 52 | if (number < 1000) { 53 | return String(Math.floor(number)); 54 | } else if (number < 10000) { 55 | if (floor) { 56 | return ( 57 | (Math.floor((number / 1000) * rounding) / rounding).toFixed( 58 | rounding.toString().length - 1 59 | ) + "K" 60 | ); 61 | } else { 62 | return ( 63 | (Math.ceil((number / 1000) * rounding) / rounding).toFixed( 64 | rounding.toString().length - 1 65 | ) + "K" 66 | ); 67 | } 68 | } else if (number < 1000000) { 69 | if (floor) { 70 | return Math.floor(number / 1000) + "K"; 71 | } else { 72 | return Math.ceil(number / 1000) + "K"; 73 | } 74 | } else if (number < 1000000000) { 75 | if (floor) { 76 | return ( 77 | (Math.floor((number / 1000 / 1000) * rounding) / rounding).toFixed( 78 | rounding.toString().length - 1 79 | ) + "M" 80 | ); 81 | } else { 82 | return ( 83 | (Math.ceil((number / 1000 / 1000) * rounding) / rounding).toFixed( 84 | rounding.toString().length - 1 85 | ) + "M" 86 | ); 87 | } 88 | } else if (floor) { 89 | return ( 90 | ( 91 | Math.floor((number / 1000 / 1000 / 1000) * rounding * 10) / 92 | (rounding * 10) 93 | ).toFixed(rounding.toString().length) + "B" 94 | ); 95 | } else { 96 | return ( 97 | ( 98 | Math.ceil((number / 1000 / 1000 / 1000) * rounding * 10) / 99 | (rounding * 10) 100 | ).toFixed(rounding.toString().length) + "B" 101 | ); 102 | } 103 | }, 104 | floor: function floor(num, decimals = 0) { 105 | return Math.floor(Math.pow(10, decimals) * num) / Math.pow(10, decimals); 106 | }, 107 | round: function round(num, scale) { 108 | if (!("" + num).includes("e")) { 109 | return +(Math.round(num + "e+" + scale) + "e-" + scale); 110 | } else { 111 | var arr = ("" + num).split("e"); 112 | var sig = ""; 113 | if (+arr[1] + scale > 0) { 114 | sig = "+"; 115 | } 116 | return +( 117 | Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + 118 | "e-" + 119 | scale 120 | ); 121 | } 122 | }, 123 | }; 124 | -------------------------------------------------------------------------------- /API/constants/maro_networth/generators/forgeGenerator.js: -------------------------------------------------------------------------------- 1 | const constants = require("../src/constants"); 2 | const helper = require("../src/helper"); 3 | 4 | const findProfits = function (db) { 5 | const forgeItems = constants.forge_recipes; 6 | const output = {}; 7 | 8 | for (const key of Object.keys(forgeItems)) { 9 | const items = forgeItems[key]; 10 | const recipe = []; 11 | 12 | for (const item of Object.entries(items)) { 13 | const data = db[item[0]]; 14 | if (data === undefined) continue; 15 | 16 | let index = 0, 17 | count = 0; 18 | 19 | while (count < item[1]) { 20 | if (data.type == "AUCTION") { 21 | if (!data.sales[index]) index = 0; 22 | 23 | count += data.sales[index].count; 24 | recipe.push(data.sales[index].price); 25 | } 26 | 27 | if (data.type == "BAZAAR") { 28 | count += data.count ?? 1; 29 | recipe.push(data.price); 30 | } 31 | 32 | index++; 33 | } 34 | } 35 | 36 | const listedPrice = db[key]?.price; 37 | const craftPrice = recipe.reduce((a, b) => a + b, 0); 38 | 39 | if (craftPrice < listedPrice) { 40 | const difference = listedPrice - craftPrice; 41 | const nameWithoutReforge = helper.removeReforge(db[key].name); 42 | 43 | output[key] = { 44 | id: key.toUpperCase(), 45 | name: nameWithoutReforge, 46 | profit: difference, 47 | auction: listedPrice, 48 | crafting: craftPrice, 49 | }; 50 | } 51 | } 52 | 53 | const profits = Object.values(output).sort((a, b) => b.profit - a.profit, 0); 54 | 55 | return profits; 56 | }; 57 | 58 | module.exports = { findProfits }; 59 | -------------------------------------------------------------------------------- /API/constants/maro_networth/generators/networthGenerator.js: -------------------------------------------------------------------------------- 1 | const isItemRecombobulated = function (item) { 2 | let recombobulated; 3 | 4 | if (item.tag?.ExtraAttributes?.rarity_upgrades != undefined) { 5 | recombobulated = true; 6 | } 7 | 8 | return recombobulated; 9 | }; 10 | 11 | const getNetworth = async function (data, profile, bank) { 12 | const output = { categories: {} }; 13 | 14 | for (const key of Object.keys(data)) { 15 | const category = { 16 | items: [], 17 | unsoulbound_items: [], 18 | total: 0, 19 | unsoulbound_total: 0, 20 | }; 21 | 22 | for (const item of data[key].filter((i) => i.price)) { 23 | const isSoulbound = 24 | item.tag?.ExtraAttributes?.donated_museum || 25 | item.tag?.display?.Lore?.includes("§8§l* §8Co-op Soulbound §8§l*") || 26 | item.tag?.display?.Lore?.includes("§8§l* §8Soulbound §8§l*"); 27 | const items = { 28 | id: item.modified.id, 29 | name: item.modified.name, 30 | price: parseInt(item.price), 31 | recomb: isItemRecombobulated(item), 32 | heldItem: item.heldItem, 33 | soulbound: item?.tag?.ExtraAttributes?.donated_museum, 34 | winning_bid: item?.tag?.ExtraAttributes?.winning_bid, 35 | base: item?.modified?.base, 36 | calculation: item?.modified?.calculation, 37 | candyUsed: item.candyUsed, 38 | isPet: item?.modified?.isPet, 39 | count: item.Count ?? 1, 40 | }; 41 | category.total += item.price; 42 | category.items.push(items); 43 | if (!isSoulbound) { 44 | category.unsoulbound_total += item.price; 45 | category.unsoulbound_items.push(JSON.parse(JSON.stringify(items))); 46 | } 47 | } 48 | 49 | if (category.items.length > 0) { 50 | category.items = category.items 51 | .sort((a, b) => b.price - a.price) 52 | .reduce((r, a) => { 53 | const last = r[r.length - 1]; 54 | if (last && last.name === a.name && !a?.isPet) { 55 | last.price += a.price; 56 | last.count += a.count; 57 | last.recomb = last.recomb || a.recomb; 58 | last.heldItem = last.heldItem || a.heldItem; 59 | last.winning_bid = last.winning_bid || a.winning_bid; 60 | last.base = last.base || a.base; 61 | last.calculation = last.calculation || a.calculation; 62 | last.candyUsed = last.candyUsed || a.candyUsed; 63 | last.isPet = last.isPet || a.isPet; 64 | } else { 65 | r.push(a); 66 | } 67 | return r; 68 | }, []) 69 | .filter((e) => e); 70 | 71 | output.categories[key] = { 72 | total: parseInt(category.total), 73 | top_items: category.items, 74 | }; 75 | } 76 | 77 | if (category.unsoulbound_items.length > 0) { 78 | category.unsoulbound_items = category.unsoulbound_items 79 | .sort((a, b) => b.price - a.price) 80 | .reduce((r, a) => { 81 | const last = r[r.length - 1]; 82 | if (last && last.name === a.name) { 83 | last.price += a.price; 84 | last.count += a.count; 85 | last.recomb = last.recomb || a.recomb; 86 | last.heldItem = last.heldItem || a.heldItem; 87 | last.winning_bid = last.winning_bid || a.winning_bid; 88 | last.base = last.base || a.base; 89 | last.calculation = last.calculation || a.calculation; 90 | last.candyUsed = last.candyUsed || a.candyUsed; 91 | last.isPet = last.isPet || a.isPet; 92 | } else { 93 | r.push(a); 94 | } 95 | return r; 96 | }, []) 97 | .filter((e) => e); 98 | 99 | output.categories[key].unsoulbound_total = parseInt( 100 | category.unsoulbound_total 101 | ); 102 | output.categories[key].unsoulbound_items = category.unsoulbound_items; 103 | } 104 | } 105 | 106 | output.bank = bank || 0; 107 | output.personal_bank = 108 | (profile.bank_account || 0) !== (bank || 0) ? profile.bank_account || 0 : 0; 109 | output.purse = profile.coin_purse ?? 0; 110 | 111 | output.networth = 112 | Object.values(output.categories).reduce((a, b) => a + b.total, 0) + 113 | output.bank + 114 | output.personal_bank + 115 | output.purse; 116 | output.unsoulbound_networth = 117 | Object.values(output.categories).reduce( 118 | (a, b) => a + (b.unsoulbound_total || 0), 119 | 0 120 | ) + 121 | output.bank + 122 | output.personal_bank + 123 | output.purse; 124 | 125 | return output; 126 | }; 127 | 128 | module.exports = { getNetworth }; 129 | -------------------------------------------------------------------------------- /API/constants/maro_networth/generators/petGenerator.js: -------------------------------------------------------------------------------- 1 | const constants = require("../src/constants"); 2 | const helper = require("../src/helper"); 3 | 4 | const getPricesFromDb = function (pet, db) { 5 | let lvl1 = db[`lvl_1_${pet.tier}_${pet.type}`.toLowerCase()]?.price; 6 | let lvl100 = db[`lvl_100_${pet.tier}_${pet.type}`.toLowerCase()]?.price; 7 | let lvl200 = db[`lvl_200_${pet.tier}_${pet.type}`.toLowerCase()]?.price; 8 | 9 | if (pet.skin) { 10 | lvl1 = 11 | db[`lvl_1_${pet.tier}_${pet.type}_skinned_${pet.skin}`.toLowerCase()] 12 | ?.price || lvl1; 13 | lvl100 = 14 | db[`lvl_100_${pet.tier}_${pet.type}_skinned_${pet.skin}`.toLowerCase()] 15 | ?.price || lvl100; 16 | lvl200 = 17 | db[`lvl_200_${pet.tier}_${pet.type}_skinned_${pet.skin}`.toLowerCase()] 18 | ?.price || lvl200; 19 | } 20 | 21 | return { lvl1, lvl100, lvl200 }; 22 | }; 23 | 24 | const calculateSkillLevel = function (pet) { 25 | const maxLevel = pet.type == "GOLDEN_DRAGON" ? 200 : 100; 26 | const rarityOffset = constants.pet_rarity_offset[pet.tier]; 27 | const levels = constants.pet_levels.slice( 28 | rarityOffset, 29 | rarityOffset + maxLevel - 1 30 | ); 31 | 32 | let level = 1; 33 | let totalExperience = 0; 34 | 35 | for (let i = 0; i < maxLevel; i++) { 36 | totalExperience += levels[i]; 37 | 38 | if (totalExperience > pet.exp) { 39 | totalExperience -= levels[i]; 40 | break; 41 | } 42 | 43 | level++; 44 | } 45 | 46 | return { 47 | xpMax: levels.reduce((a, b) => a + b, 0), 48 | level: level > maxLevel ? maxLevel : level, 49 | }; 50 | }; 51 | 52 | const getPetPrice = function (pet, db) { 53 | const { lvl1, lvl100, lvl200 } = getPricesFromDb(pet, db); 54 | 55 | if (lvl1 == undefined || lvl100 == undefined) { 56 | return pet; 57 | } 58 | 59 | let data = calculateSkillLevel(pet); 60 | let price = lvl200 ?? lvl100; 61 | 62 | if (data.level < 100 && data.xpMax) { 63 | const baseFormula = (lvl100 - lvl1) / data.xpMax; 64 | 65 | if (baseFormula != undefined) { 66 | price = baseFormula * pet.exp + lvl1; 67 | } 68 | } 69 | 70 | if (data.level > 100 && data.level < 200) { 71 | const level = data.level.toString().slice(1); 72 | 73 | if (level != 1) { 74 | const baseFormula = (lvl200 - lvl100) / 100; 75 | 76 | price = baseFormula * level + lvl100; 77 | } 78 | } 79 | 80 | if (pet.heldItem) { 81 | const heldItemPrice = db[pet.heldItem.toLowerCase()]?.price; 82 | 83 | if (heldItemPrice != undefined) { 84 | price += heldItemPrice; 85 | } 86 | } 87 | 88 | if ( 89 | pet.candyUsed > 0 && 90 | pet.type !== "ENDER_DRAGON" && 91 | pet.type !== "GOLDEN_DRAGON" && 92 | pet.type !== "SCATHA" 93 | ) { 94 | const reducedValue = price / 1.538232; 95 | 96 | if (!isNaN(price)) { 97 | if (data.level === 100) { 98 | price = Math.max(reducedValue, price - 5000000); 99 | } else { 100 | price = Math.max(reducedValue, price - 2500000); 101 | } 102 | } 103 | } 104 | 105 | pet.price = price; 106 | pet.modified = { 107 | name: `[Lvl ${data.level}] ${helper.capitalize(`${pet.tier} ${pet.type}`)}${ 108 | pet.skin ? " ✦" : "" 109 | }`, 110 | isPet: true, 111 | }; 112 | 113 | return pet; 114 | }; 115 | 116 | module.exports = { calculateSkillLevel, getPetPrice }; 117 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/constants.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | 4 | const constants = {}; 5 | 6 | for (const file of fs.readdirSync(path.resolve(__dirname, "constants"))) { 7 | if (path.extname(file) != ".js") continue; 8 | 9 | const module = require(path.resolve(__dirname, "constants", file)); 10 | 11 | Object.assign(constants, module); 12 | } 13 | 14 | module.exports = constants; 15 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/constants/forge.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | forge_recipes: { 3 | REFINED_DIAMOND: { 4 | ENCHANTED_DIAMOND_BLOCK: 2, 5 | }, 6 | REFINED_MITHRIL: { 7 | ENCHANTED_MITHRIL: 160, 8 | }, 9 | REFINED_TITANIUM: { 10 | ENCHANTED_TITANIUM: 16, 11 | }, 12 | FUEL_TANK: { 13 | ENCHANTED_COAL_BLOCK: 2, 14 | }, 15 | BEJEWELED_HANDLE: { 16 | GLACITE_JEWEL: 3, 17 | }, 18 | DRILL_ENGINE: { 19 | ENCHANTED_IRON_BLOCK: 1, 20 | ENCHANTED_REDSTONE_BLOCK: 3, 21 | GOLDEN_PLATE: 1, 22 | TREASURITE: 10, 23 | REFINED_DIAMOND: 1, 24 | }, 25 | GOLDEN_PLATE: { 26 | ENCHANTED_GOLD_BLOCK: 2, 27 | GLACITE_JEWEL: 5, 28 | REFINED_DIAMOND: 1, 29 | }, 30 | MITHRIL_PLATE: { 31 | GOLDEN_PLATE: 1, 32 | REFINED_MITHRIL: 5, 33 | ENCHANTED_IRON_BLOCK: 1, 34 | REFINED_TITANIUM: 1, 35 | }, 36 | GEMSTONE_MIXTURE: { 37 | FINE_AMBER_GEM: 4, 38 | FINE_SAPPHIRE_GEM: 4, 39 | FINE_AMETHYST_GEM: 4, 40 | FINE_JADE_GEM: 4, 41 | SLUDGE_JUICE: 320, 42 | }, 43 | PERFECT_JASPER_GEM: { 44 | FLAWLESS_JASPER_GEM: 5, 45 | JASPER_CRYSTAL: 1, 46 | }, 47 | DIAMONITE: { 48 | REFINED_DIAMOND: 2, 49 | }, 50 | BEACON_2: { 51 | REFINED_MITHRIL: 5, 52 | BEACON_1: 1, 53 | }, 54 | MITHRIL_FUEL_TANK: { 55 | MITHRIL_PLATE: 3, 56 | FUEL_TANK: 5, 57 | }, 58 | MITHRIL_DRILL_ENGINE: { 59 | MITHRIL_PLATE: 3, 60 | DRILL_ENGINE: 2, 61 | }, 62 | BEACON_3: { 63 | REFINED_MITHRIL: 10, 64 | BEACON_2: 1, 65 | }, 66 | GEMSTONE_DRILL_1: { 67 | DRILL_ENGINE: 1, 68 | FUEL_TANK: 1, 69 | FINE_RUBY_GEM: 6, 70 | }, 71 | MITHRIL_DRILL_2: { 72 | MITHRIL_DRILL_1: 1, 73 | GOLDEN_PLATE: 10, 74 | MITHRIL_PLATE: 2, 75 | }, 76 | TITANIUM_DRILL_ENGINE: { 77 | DRILL_ENGINE: 10, 78 | PLASMA: 5, 79 | MITHRIL_PLATE: 4, 80 | REFINED_TITANIUM: 5, 81 | }, 82 | BEACON_4: { 83 | BEACON_3: 1, 84 | REFINED_MITHRIL: 20, 85 | PLASMA: 1, 86 | }, 87 | TITANIUM_ARTIFACT: { 88 | REFINED_TITANIUM: 12, 89 | TITANIUM_RING: 1, 90 | }, 91 | GOBLIN_OMELETTE_SUNNY_SIDE: { 92 | GOBLIN_EGG_YELLOW: 99, 93 | FINE_TOPAZ_GEM: 1, 94 | }, 95 | GEMSTONE_DRILL_2: { 96 | GEMSTONE_DRILL_1: 1, 97 | GEMSTONE_MIXTURE: 3, 98 | }, 99 | TITANIUM_DRILL_1: { 100 | DRILL_ENGINE: 1, 101 | FUEL_TANK: 1, 102 | GOLDEN_PLATE: 6, 103 | REFINED_TITANIUM: 10, 104 | REFINED_MITHRIL: 10, 105 | }, 106 | TITANIUM_DRILL_2: { 107 | TITANIUM_DRILL_1: 1, 108 | REFINED_DIAMOND: 10, 109 | REFINED_TITANIUM: 16, 110 | MITHRIL_PLATE: 6, 111 | }, 112 | TITANIUM_DRILL_3: { 113 | TITANIUM_DRILL_2: 1, 114 | REFINED_DIAMOND: 20, 115 | REFINED_TITANIUM: 30, 116 | ENCHANTED_IRON_BLOCK: 2, 117 | MITHRIL_PLATE: 15, 118 | PLASMA: 20, 119 | }, 120 | TITANIUM_FUEL_TANK: { 121 | REFINED_TITANIUM: 10, 122 | REFINED_DIAMOND: 20, 123 | REFINED_MITHRIL: 10, 124 | FUEL_TANK: 10, 125 | }, 126 | BEACON_5: { 127 | BEACON_4: 1, 128 | REFINED_MITHRIL: 40, 129 | PLASMA: 5, 130 | }, 131 | TITANIUM_RELIC: { 132 | REFINED_TITANIUM: 20, 133 | TITANIUM_ARTIFACT: 1, 134 | }, 135 | GOBLIN_OMELETTE_SPICY: { 136 | GOBLIN_EGG_RED: 99, 137 | FLAWLESS_RUBY_GEM: 1, 138 | }, 139 | GEMSTONE_CHAMBER: { 140 | WORM_MEMBRANE: 100, 141 | GEMSTONE_MIXTURE: 1, 142 | }, 143 | GEMSTONE_DRILL_3: { 144 | GEMSTONE_DRILL_2: 1, 145 | FLAWLESS_TOPAZ_GEM: 1, 146 | GEMSTONE_MIXTURE: 3, 147 | MAGMA_CORE: 5, 148 | }, 149 | RUBY_POLISHED_DRILL_ENGINE: { 150 | MITHRIL_DRILL_ENGINE: 1, 151 | SUPERLITE_MOTOR: 10, 152 | FINE_RUBY_GEM: 10, 153 | }, 154 | GEMSTONE_FUEL_TANK: { 155 | TITANIUM_FUEL_TANK: 1, 156 | CONTROL_SWITCH: 30, 157 | GEMSTONE_MIXTURE: 10, 158 | }, 159 | GOBLIN_OMELETTE_BLUE_CHEESE: { 160 | GOBLIN_EGG_BLUE: 99, 161 | PERFECT_SAPPHIRE_GEM: 1, 162 | }, 163 | ROCK_GEMSTONE: { 164 | ENCHANTED_COBBLESTONE: 128, 165 | TREASURITE: 64, 166 | }, 167 | TITANIUM_DRILL_4: { 168 | TITANIUM_DRILL_3: 1, 169 | CORLEONITE: 30, 170 | FLAWLESS_RUBY_GEM: 1, 171 | REFINED_DIAMOND: 5, 172 | GEMSTONE_MIXTURE: 16, 173 | REFINED_TITANIUM: 12, 174 | MITHRIL_PLATE: 5, 175 | }, 176 | GEMSTONE_DRILL_4: { 177 | GEMSTONE_DRILL_3: 1, 178 | FLAWLESS_JASPER_GEM: 1, 179 | TREASURITE: 100, 180 | }, 181 | SAPPHIRE_POLISHED_DRILL_ENGINE: { 182 | TITANIUM_DRILL_ENGINE: 1, 183 | ELECTRON_TRANSMITTER: 25, 184 | FTX_3070: 25, 185 | FINE_SAPPHIRE_GEM: 20, 186 | }, 187 | DIVAN_HELMET: { 188 | DIVAN_FRAGMENT: 5, 189 | GEMSTONE_MIXTURE: 10, 190 | FLAWLESS_RUBY_GEM: 1, 191 | }, 192 | DIVAN_CHESTPLATE: { 193 | DIVAN_FRAGMENT: 8, 194 | GEMSTONE_MIXTURE: 10, 195 | FLAWLESS_RUBY_GEM: 1, 196 | }, 197 | DIVAN_LEGGINGS: { 198 | DIVAN_FRAGMENT: 7, 199 | GEMSTONE_MIXTURE: 10, 200 | FLAWLESS_RUBY_GEM: 1, 201 | }, 202 | DIVAN_BOOTS: { 203 | DIVAN_FRAGMENT: 4, 204 | GEMSTONE_MIXTURE: 10, 205 | FLAWLESS_RUBY_GEM: 1, 206 | }, 207 | AMBER_POLISHED_DRILL_ENGINE: { 208 | RUBY_POLISHED_DRILL_ENGINE: 1, 209 | SAPPHIRE_POLISHED_DRILL_ENGINE: 1, 210 | FLAWLESS_AMBER_GEM: 1, 211 | ROBOTRON_REFLECTOR: 50, 212 | }, 213 | PERFECTLY_CUT_FUEL_TANK: { 214 | GEMSTONE_FUEL_TANK: 1, 215 | SYNTHETIC_HEART: 70, 216 | GEMSTONE_MIXTURE: 25, 217 | }, 218 | DIVAN_DRILL: { 219 | DIVAN_ALLOY: 1, 220 | TITANIUM_DRILL_4: 1, 221 | ENCHANTED_QUARTZ_BLOCK: 325, 222 | }, 223 | }, 224 | 225 | forge_items: [ 226 | "Refined Diamond", 227 | "Refined Mithril", 228 | "Refined Titanium", 229 | "Fuel Tank", 230 | "Bejeweled Handle", 231 | "Drill Engine", 232 | "Golden Plate", 233 | "Mithril Plate", 234 | "Gemstone Mixture", 235 | "Perfect Jasper Gemstone", 236 | "Mithril Pickaxe", 237 | "Beacon II", 238 | "Titanium Talisman", 239 | "Diamonite", 240 | "Mithril Drill SX-R226", 241 | "Mithril-Infused Fuel Tank", 242 | "Mithril-Plated Drill Engine", 243 | "Beacon III", 244 | "Titanium Ring", 245 | "Rock Gemstone", 246 | "Ruby Drill TX-15", 247 | "Mithril Drill SX-R326", 248 | "Titanium-Plated Drill Engine", 249 | "Goblin Omelette", 250 | "Beacon IV", 251 | "Titanium Artifact", 252 | "Sunny Side Goblin Omelette", 253 | "Gemstone Drill LT-522", 254 | "Titanium Drill DR-X355", 255 | "Titanium Drill DR-X455", 256 | "Titanium Drill DR-X555", 257 | "Titanium-Infused Fuel Tank", 258 | "Beacon V", 259 | "Titanium Relic", 260 | "Spicy Goblin Omelette", 261 | "Gemstone Chamber", 262 | "Topaz Drill KGR-12", 263 | "Ruby-polished Drill Engine", 264 | "Gemstone Fuel Tank", 265 | "Blue Cheese Goblin Omelette", 266 | "Titanium Drill DR-X655", 267 | "Jasper Drill X", 268 | "Sapphire-polished Drill Engine", 269 | "Helmet Of Divan", 270 | "Chestplate Of Divan", 271 | "Leggings Of Divan", 272 | "Boots Of Divan", 273 | "Amber-polished Drill Engine", 274 | "Perfectly-Cut Fuel Tank", 275 | "Divan's Drill", 276 | ], 277 | }; 278 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/constants/gemstones.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | gemstones: { 3 | JADE: { 4 | name: "Jade", 5 | color: "a", 6 | stats: { 7 | ROUGH: { 8 | mining_fortune: [null, 4, 6, 8, 10, 12, null], 9 | }, 10 | FLAWED: { 11 | mining_fortune: [null, 5, 7, 10, 14, 18, null], 12 | }, 13 | FINE: { 14 | mining_fortune: [null, 7, 10, 15, 20, 25, null], 15 | }, 16 | FLAWLESS: { 17 | mining_fortune: [null, 10, 15, 20, 27, 35, 44], 18 | }, 19 | PERFECT: { 20 | mining_fortune: [null, 14, 20, 30, 40, 50, 60], 21 | }, 22 | }, 23 | }, 24 | 25 | AMBER: { 26 | name: "Amber", 27 | color: "6", 28 | stats: { 29 | ROUGH: { 30 | mining_speed: [4, 8, 12, 16, 20, 24, null], 31 | }, 32 | FLAWED: { 33 | mining_speed: [6, 10, 14, 18, 24, 30, null], 34 | }, 35 | FINE: { 36 | mining_speed: [10, 14, 20, 28, 36, 45, null], 37 | }, 38 | FLAWLESS: { 39 | mining_speed: [14, 20, 30, 44, 58, 75, 92], 40 | }, 41 | PERFECT: { 42 | mining_speed: [20, 28, 40, 60, 80, 100, 120], 43 | }, 44 | }, 45 | }, 46 | 47 | TOPAZ: { 48 | name: "Topaz", 49 | color: "e", 50 | stats: { 51 | ROUGH: { 52 | pristine: [null, null, 0.4, 0.4, 0.4, 0.4, null], 53 | }, 54 | FLAWED: { 55 | pristine: [null, null, 0.8, 0.8, 0.8, 0.8, null], 56 | }, 57 | FINE: { 58 | pristine: [null, null, 1.2, 1.2, 1.2, 1.2, null], 59 | }, 60 | FLAWLESS: { 61 | pristine: [null, null, 1.6, 1.6, 1.6, 1.6, null], 62 | }, 63 | PERFECT: { 64 | pristine: [null, null, 2, 2, 2, 2, 2.2], 65 | }, 66 | }, 67 | }, 68 | 69 | SAPPHIRE: { 70 | name: "Sapphire", 71 | color: "b", 72 | stats: { 73 | ROUGH: { 74 | intelligence: [2, 2, 3, 4, 5, 6, null], 75 | }, 76 | FLAWED: { 77 | intelligence: [4, 4, 5, 6, 7, 8, null], 78 | }, 79 | FINE: { 80 | intelligence: [6, 6, 7, 8, 9, 10, null], 81 | }, 82 | FLAWLESS: { 83 | intelligence: [8, 9, 10, 12, 14, 16, null], 84 | }, 85 | PERFECT: { 86 | intelligence: [10, 12, 14, 17, 20, 25, null], 87 | }, 88 | }, 89 | }, 90 | 91 | AMETHYST: { 92 | name: "Amethyst", 93 | color: "5", 94 | stats: { 95 | ROUGH: { 96 | defense: [1, 2, 3, 4, 5, 7, null], 97 | }, 98 | FLAWED: { 99 | defense: [3, 4, 5, 6, 8, 10, null], 100 | }, 101 | FINE: { 102 | defense: [4, 5, 6, 8, 10, 14, null], 103 | }, 104 | FLAWLESS: { 105 | defense: [5, 7, 10, 14, 18, 22, null], 106 | }, 107 | PERFECT: { 108 | defense: [6, 9, 13, 18, 24, 30, null], 109 | }, 110 | }, 111 | }, 112 | 113 | JASPER: { 114 | name: "Jasper", 115 | color: "d", 116 | stats: { 117 | ROUGH: { 118 | strength: [null, null, 1, 2, 2, 3, null], 119 | }, 120 | FLAWED: { 121 | strength: [null, null, 2, 3, 3, 4, null], 122 | }, 123 | FINE: { 124 | strength: [null, null, 3, 4, 4, 5, null], 125 | }, 126 | FLAWLESS: { 127 | strength: [null, null, 5, 6, 7, 8, null], 128 | }, 129 | PERFECT: { 130 | strength: [null, null, 7, 9, 10, 12, null], 131 | }, 132 | }, 133 | }, 134 | 135 | RUBY: { 136 | name: "Ruby", 137 | color: "c", 138 | stats: { 139 | ROUGH: { 140 | health: [1, 2, 3, 4, 5, 7, null], 141 | }, 142 | FLAWED: { 143 | health: [3, 4, 5, 6, 8, 10, null], 144 | }, 145 | FINE: { 146 | health: [4, 5, 6, 8, 10, 14, null], 147 | }, 148 | FLAWLESS: { 149 | health: [5, 7, 10, 14, 18, 22, null], 150 | }, 151 | PERFECT: { 152 | health: [6, 9, 13, 18, 24, 30, null], 153 | }, 154 | }, 155 | }, 156 | 157 | OPAL: { 158 | name: "Opal", 159 | color: "f", 160 | stats: { 161 | ROUGH: { 162 | true_defense: [null, null, null, null, null, null, null], 163 | }, 164 | FLAWED: { 165 | true_defense: [null, null, null, null, null, null, null], 166 | }, 167 | FINE: { 168 | true_defense: [null, null, null, null, null, null, null], 169 | }, 170 | FLAWLESS: { 171 | true_defense: [null, null, null, null, null, null, null], 172 | }, 173 | PERFECT: { 174 | true_defense: [null, null, null, null, null, null, null], 175 | }, 176 | }, 177 | }, 178 | }, 179 | }; 180 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/constants/pets.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pet_rarity_offset: { 3 | COMMON: 0, 4 | UNCOMMON: 6, 5 | RARE: 11, 6 | EPIC: 16, 7 | LEGENDARY: 20, 8 | MYTHIC: 20, 9 | }, 10 | 11 | pet_levels: [ 12 | 100, 110, 120, 130, 145, 160, 175, 190, 210, 230, 250, 275, 300, 330, 360, 13 | 400, 440, 490, 540, 600, 660, 730, 800, 880, 960, 1050, 1150, 1260, 1380, 14 | 1510, 1650, 1800, 1960, 2130, 2310, 2500, 2700, 2920, 3160, 3420, 3700, 15 | 4000, 4350, 4750, 5200, 5700, 6300, 7000, 7800, 8700, 9700, 10800, 12000, 16 | 13300, 14700, 16200, 17800, 19500, 21300, 23200, 25200, 27400, 29800, 32400, 17 | 35200, 38200, 41400, 44800, 48400, 52200, 56200, 60400, 64800, 69400, 74200, 18 | 79200, 84700, 90700, 97200, 104200, 111700, 119700, 128200, 137200, 146700, 19 | 156700, 167700, 179700, 192700, 206700, 221700, 237700, 254700, 272700, 20 | 291700, 311700, 333700, 357700, 383700, 411700, 441700, 476700, 516700, 21 | 561700, 611700, 666700, 726700, 791700, 861700, 936700, 1016700, 1101700, 22 | 1191700, 1286700, 1386700, 1496700, 1616700, 1746700, 1886700, 0, 1, 23 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 24 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 25 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 26 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 27 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 28 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 29 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 30 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 31 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 32 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 33 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 34 | 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 1886700, 35 | 1886700, 1886700, 36 | ], 37 | }; 38 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/constants/reforges.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reforges: { 3 | perfect: "diamond_atom", 4 | spiked: "dragon_scale", 5 | fabled: "dragon_claw", 6 | renowned: "dragon_horn", 7 | cubic: "molten_cube", 8 | reinforced: "rare_diamond", 9 | magnetic: "lapis_crystal", 10 | gilded: "midas_jewel", 11 | fruitful: "onyx", 12 | precise: "optical_lens", 13 | ridiculous: "red_nose", 14 | loving: "red_scarf", 15 | spiritual: "spirit_stone", 16 | warped: "warped_stone", 17 | giant: "giant_tooth", 18 | empowered: "sadans_brooch", 19 | moil: "moil_log", 20 | dirty: "dirt_bottle", 21 | toil: "toil_log", 22 | refined: "refined_amber", 23 | blessed: "blessed_fruit", 24 | candied: "candy_corn", 25 | submerged: "deep_sea_orb", 26 | ancient: "precursor_gear", 27 | withered: "wither_blood", 28 | aote_stone: "aote_stone", 29 | ambered: "amber_material", 30 | jaded: "jaderald", 31 | auspicious: "rock_gemstone", 32 | fleet: "diamonite", 33 | waxed: "blaze_wax", 34 | strengthened: "searing_stone", 35 | glistening: "shiny_prism", 36 | chomp: "kuudra_mandible", 37 | fortified: "meteor_shard", 38 | }, 39 | all_reforges: [ 40 | "gentle", 41 | "odd", 42 | "fast", 43 | "fair", 44 | "epic", 45 | "sharp", 46 | "heroic", 47 | "spicy", 48 | "legendary", 49 | "dirty", 50 | "fabled", 51 | "suspicious", 52 | "gilded", 53 | "warped", 54 | "withered", 55 | "bulky", 56 | "jerry's", 57 | "salty", 58 | "treacherous", 59 | "stiff", 60 | "lucky", 61 | "deadly", 62 | "fine", 63 | "grand", 64 | "hasty", 65 | "neat", 66 | "rapid", 67 | "unreal", 68 | "awkward", 69 | "rich", 70 | "precise", 71 | "spiritual", 72 | "headstrong", 73 | "clean", 74 | "fierce", 75 | "heavy", 76 | "light", 77 | "mythic", 78 | "pure", 79 | "smart", 80 | "titanic", 81 | "wise", 82 | "very", 83 | "highly", 84 | "extremely", 85 | "not so", 86 | "thicc", 87 | "absolutely", 88 | "undead", 89 | "perfect", 90 | "necrotic", 91 | "ancient", 92 | "spiked", 93 | "renowned", 94 | "cubic", 95 | "warped", 96 | "reinforced", 97 | "loving", 98 | "ridiculous", 99 | "giant", 100 | "submerged", 101 | "empowered", 102 | "candied", 103 | "jaded", 104 | "bizarre", 105 | "itchy", 106 | "ominous", 107 | "pleasant", 108 | "pretty", 109 | "shiny", 110 | "simple", 111 | "strange", 112 | "vivid", 113 | "godly", 114 | "demonic", 115 | "forceful", 116 | "hurtful", 117 | "keen", 118 | "strong", 119 | "superior", 120 | "unpleasant", 121 | "zealous", 122 | "bloody", 123 | "even more", 124 | "fruitful", 125 | "magnetic", 126 | "refined", 127 | "blessed", 128 | "moil", 129 | "toil", 130 | "fleet", 131 | "stellar", 132 | "mithraic", 133 | "auspicious", 134 | "bountiful", 135 | "ambered", 136 | "double_bit", 137 | "green_thumb", 138 | "unyielding", 139 | "lumberjack", 140 | "peasant", 141 | "prospector", 142 | "great", 143 | "rugged", 144 | "lush", 145 | "robust", 146 | "zooming", 147 | "excellent", 148 | "sturdy", 149 | "fortunate", 150 | "waxed", 151 | "strengthened", 152 | "glistening", 153 | "chomp", 154 | "fortified", 155 | ], 156 | }; 157 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/constants/talismans.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | talismans: { 3 | wedding_ring_0: { rarity: "common" }, 4 | wedding_ring_2: { rarity: "uncommon" }, 5 | wedding_ring_4: { rarity: "rare" }, 6 | wedding_ring_7: { rarity: "epic" }, 7 | wedding_ring_9: { rarity: "legendary" }, 8 | 9 | campfire_talisman_1: { rarity: "common" }, 10 | campfire_talisman_4: { rarity: "uncommon" }, 11 | campfire_talisman_8: { rarity: "rare" }, 12 | campfire_talisman_13: { rarity: "epic" }, 13 | campfire_talisman_21: { rarity: "legendary" }, 14 | 15 | farming_talisman: {}, 16 | vaccine_talisman: { rarity: "common" }, 17 | wood_talisman: { rarity: "uncommon" }, 18 | skeleton_talisman: {}, 19 | coin_talisman: { rarity: "common" }, 20 | magnetic_talisman: {}, 21 | gravity_talisman: {}, 22 | village_talisman: {}, 23 | mine_talisman: {}, 24 | night_vision_charm: {}, 25 | lava_talisman: {}, 26 | scavenger_talisman: {}, 27 | fire_talisman: {}, 28 | piggy_bank: {}, 29 | cracked_piggy_bank: {}, 30 | broken_piggy_bank: {}, 31 | pigs_foot: {}, 32 | wolf_paw: {}, 33 | frozen_chicken: {}, 34 | fish_affinity_talisman: {}, 35 | farmer_orb: {}, 36 | haste_ring: {}, 37 | experience_artifact: {}, 38 | new_year_cake_bag: {}, 39 | day_crystal: { rarity: "rare" }, 40 | night_crystal: { rarity: "rare" }, 41 | feather_talisman: {}, 42 | feather_ring: {}, 43 | feather_artifact: {}, 44 | potion_affinity_talisman: {}, 45 | ring_potion_affinity: {}, 46 | artifact_potion_affinity: {}, 47 | healing_talisman: {}, 48 | healing_ring: {}, 49 | candy_talisman: {}, 50 | candy_ring: {}, 51 | candy_artifact: {}, 52 | melody_hair: { rarity: "epic" }, 53 | sea_creature_talisman: { rarity: "common" }, 54 | sea_creature_ring: {}, 55 | sea_creature_artifact: {}, 56 | intimidation_talisman: {}, 57 | intimidation_ring: {}, 58 | intimidation_artifact: {}, 59 | wolf_talisman: {}, 60 | wolf_ring: {}, 61 | bat_talisman: {}, 62 | bat_ring: {}, 63 | bat_artifact: {}, 64 | devour_ring: {}, 65 | zombie_talisman: {}, 66 | zombie_ring: {}, 67 | zombie_artifact: {}, 68 | spider_talisman: {}, 69 | spider_ring: {}, 70 | spider_artifact: {}, 71 | ender_artifact: {}, 72 | tarantula_talisman: {}, 73 | survivor_cube: {}, 74 | wither_artifact: {}, 75 | red_claw_talisman: {}, 76 | red_claw_ring: {}, 77 | red_claw_artifact: {}, 78 | bait_ring: {}, 79 | shady_ring: {}, 80 | crooked_artifact: {}, 81 | seal_of_the_family: {}, 82 | hunter_talisman: {}, 83 | hunter_ring: {}, 84 | party_hat_crab: {}, 85 | potato_talisman: {}, 86 | emerald_ring: { rarity: "uncommon" }, 87 | personal_compactor_4000: { rarity: "uncommon" }, 88 | personal_compactor_5000: { rarity: "rare" }, 89 | personal_compactor_6000: { rarity: "epic" }, 90 | personal_compactor_7000: { rarity: "legendary" }, 91 | personal_deletor_4000: { rarity: "uncommon" }, 92 | personal_deletor_5000: { rarity: "rare" }, 93 | personal_deletor_6000: { rarity: "epic" }, 94 | personal_deletor_7000: { rarity: "legendary" }, 95 | speed_talisman: { rarity: "common" }, 96 | speed_ring: { rarity: "uncommon" }, 97 | speed_artifact: { rarity: "rare" }, 98 | cat_talisman: { rarity: "uncommon" }, 99 | lynx_talisman: { rarity: "rare" }, 100 | cheetah_talisman: { rarity: "epic" }, 101 | scarf_studies: { rarity: "rare" }, 102 | scarf_thesis: { rarity: "epic" }, 103 | scarf_grimoire: { rarity: "legendary" }, 104 | treasure_talisman: { rarity: "rare" }, 105 | treasure_ring: { rarity: "epic" }, 106 | treasure_artifact: { rarity: "legendary" }, 107 | mineral_talisman: { rarity: "rare" }, 108 | beastmaster_crest_common: { rarity: "common" }, 109 | beastmaster_crest_uncommon: { rarity: "uncommon" }, 110 | beastmaster_crest_rare: { rarity: "rare" }, 111 | beastmaster_crest_epic: { rarity: "epic" }, 112 | beastmaster_crest_legendary: { rarity: "legendary" }, 113 | raggedy_shark_tooth_necklace: { rarity: "common" }, 114 | dull_shark_tooth_necklace: { rarity: "uncommon" }, 115 | honed_shark_tooth_necklace: { rarity: "rare" }, 116 | sharp_shark_tooth_necklace: { rarity: "epic" }, 117 | razor_sharp_shark_tooth_necklace: { rarity: "legendary" }, 118 | hegemony_artifact: { rarity: "legendary" }, 119 | bits_talisman: { rarity: "rare" }, 120 | bat_person_talisman: { rarity: "common" }, 121 | bat_person_ring: { rarity: "uncommon" }, 122 | bat_person_artifact: { rarity: "rare" }, 123 | candy_relic: { rarity: "legendary" }, 124 | lucky_hoof: {}, 125 | eternal_hoof: {}, 126 | wither_relic: { rarity: "legendary" }, 127 | catacombs_expert_ring: { rarity: "epic" }, 128 | auto_recombobulator: { rarity: "legendary" }, 129 | jerry_talisman_green: { rarity: "uncommon" }, 130 | jerry_talisman_blue: { rarity: "rare" }, 131 | jerry_talisman_purple: { rarity: "epic" }, 132 | jerry_talisman_golden: { rarity: "legendary" }, 133 | king_talisman: { rarity: "common" }, 134 | titanium_talisman: { rarity: "uncommon" }, 135 | titanium_ring: { rarity: "rare" }, 136 | titanium_artifact: { rarity: "epic" }, 137 | titanium_relic: { rarity: "legendary" }, 138 | reaper_orb: { rarity: "legendary" }, 139 | dante_talisman: { rarity: "common" }, 140 | spiked_atrocity: { rarity: "epic" }, 141 | blood_god_crest: { rarity: "common" }, 142 | master_skull_tier_1: { rarity: "common" }, 143 | master_skull_tier_2: { rarity: "common" }, 144 | master_skull_tier_3: { rarity: "uncommon" }, 145 | master_skull_tier_4: { rarity: "uncommon" }, 146 | master_skull_tier_5: { rarity: "rare" }, 147 | master_skull_tier_6: { rarity: "epic" }, 148 | master_skull_tier_7: { rarity: "legendary" }, 149 | soulflow_pile: { rarity: "uncommon" }, 150 | soulflow_battery: { rarity: "rare" }, 151 | soulflow_supercell: { rarity: "epic" }, 152 | pocket_espresso_machine: { rarity: "common" }, 153 | handy_blood_chalice: { rarity: "common" }, 154 | ender_relic: { rarity: "legendary" }, 155 | jungle_amulet: { rarity: "uncommon" }, 156 | power_talisman: { rarity: "common" }, 157 | power_ring: { rarity: "uncommon" }, 158 | power_artifact: { rarity: "rare" }, 159 | nether_artifact: { rarity: "epic" }, 160 | burststopper_talisman: { rarity: "rare" }, 161 | burststopper_artifact: { rarity: "epic" }, 162 | fiery_kuudra_core: { rarity: "epic" }, 163 | burning_kuudra_core: { rarity: "rare" }, 164 | infernal_kuudra_core: { rarity: "rare" }, 165 | jacobus_register: { rarity: "legendary" }, 166 | odgers_bronze_tooth: { rarity: "common" }, 167 | odgers_silver_tooth: { rarity: "uncommon" }, 168 | odgers_gold_tooth: { rarity: "rare" }, 169 | odgers_diamond_tooth: { rarity: "epic" }, 170 | pulse_ring: { rarity: "uncommon" }, 171 | blaze_talisman: { rarity: "rare" }, 172 | netherrack_looking_sunshade: { rarity: "common" }, 173 | }, 174 | }; 175 | -------------------------------------------------------------------------------- /API/constants/maro_networth/src/helper.js: -------------------------------------------------------------------------------- 1 | const constants = require("./constants"); 2 | const nbt = require("prismarine-nbt"); 3 | const moment = require("moment"); 4 | const parseNbt = require("util").promisify(nbt.parse); 5 | 6 | const slots = { 7 | normal: Object.keys(constants.gemstones), 8 | special: ["UNIVERSAL", "COMBAT", "OFFENSIVE", "DEFENSIVE", "MINING"], 9 | ignore: ["unlocked_slots"], 10 | }; 11 | 12 | const getKey = function (key) { 13 | const intKey = new Number(key); 14 | 15 | if (!isNaN(intKey)) { 16 | return intKey; 17 | } 18 | 19 | return key; 20 | }; 21 | 22 | const decodeNBT = async function (data) { 23 | const buffer = Buffer.from(data, "base64"); 24 | const item = await parseNbt(buffer); 25 | 26 | if (item === undefined) { 27 | return null; 28 | } 29 | 30 | return item.value.i.value.value[0]; 31 | }; 32 | 33 | const getPath = function (obj, ...keys) { 34 | if (obj == null) { 35 | return undefined; 36 | } 37 | 38 | let loc = obj; 39 | 40 | for (let i = 0; i < keys.length; i++) { 41 | loc = loc[getKey(keys[i])]; 42 | 43 | if (loc === undefined) { 44 | return undefined; 45 | } 46 | } 47 | 48 | return loc; 49 | }; 50 | 51 | const getRawLore = function (text) { 52 | const parts = text.split("§"); 53 | let output = ""; 54 | 55 | for (const [index, part] of parts.entries()) { 56 | output += part.substring(Math.min(index, 1)); 57 | } 58 | 59 | return output; 60 | }; 61 | 62 | const removeReforge = function (text) { 63 | const items = constants.forge_items; 64 | 65 | if (!items.includes(text)) { 66 | text = text.split(" ").slice(1).join(" "); 67 | } 68 | 69 | return text; 70 | }; 71 | 72 | const capitalize = function (str) { 73 | const words = str.replace(/_/g, " ").toLowerCase().split(" "); 74 | 75 | const upperCased = words.map((word) => { 76 | return word.charAt(0).toUpperCase() + word.substr(1); 77 | }); 78 | 79 | return upperCased.join(" "); 80 | }; 81 | 82 | const parseItemGems = function (gems) { 83 | const parsed = []; 84 | 85 | for (const [key, value] of Object.entries(gems)) { 86 | if (slots.ignore.includes(key)) continue; 87 | 88 | const slot_type = key.split("_")[0]; 89 | 90 | if (slots.special.includes(slot_type)) { 91 | if (key.includes("_gem")) { 92 | parsed.push({ 93 | type: gems[`${key}`], 94 | tier: gems[`${key.replace("_gem", "")}`], 95 | }); 96 | } else { 97 | parsed.push({ type: gems[`${key}_gem`], tier: value }); 98 | } 99 | } else if (slots.normal.includes(slot_type)) { 100 | parsed.push({ type: key.split("_")[0], tier: value }); 101 | } 102 | } 103 | 104 | return parsed; 105 | }; 106 | 107 | const getAverage = function (arr) { 108 | const average = arr.reduce((a, b) => a + b, 0) / arr.length; 109 | 110 | if (!average) { 111 | return 0; 112 | } 113 | 114 | return average; 115 | }; 116 | 117 | const getMedian = function (values) { 118 | if (!values.length) return 0; 119 | 120 | values.sort((a, b) => a - b); 121 | 122 | const half = Math.floor(values.length / 2); 123 | 124 | if (values.length % 2) { 125 | return values[half]; 126 | } 127 | 128 | return (values[half - 1] + values[half]) / 2.0; 129 | }; 130 | 131 | const getMean = function (numbers) { 132 | let total = 0; 133 | 134 | for (let i = 0; i < numbers.length; i += 1) { 135 | total += numbers[i]; 136 | } 137 | 138 | return total / numbers.length; 139 | }; 140 | 141 | const getMode = function (numbers) { 142 | numbers.sort((x, y) => x - y); 143 | 144 | let bestStreak = 1; 145 | let bestElem = numbers[0]; 146 | let currentStreak = 1; 147 | let currentElem = numbers[0]; 148 | 149 | for (let i = 1; i < numbers.length; i++) { 150 | if (numbers[i - 1] !== numbers[i]) { 151 | if (currentStreak > bestStreak) { 152 | bestStreak = currentStreak; 153 | bestElem = currentElem; 154 | } 155 | 156 | currentStreak = 0; 157 | currentElem = numbers[i]; 158 | } 159 | 160 | currentStreak++; 161 | } 162 | 163 | return currentStreak > bestStreak ? currentElem : bestElem; 164 | }; 165 | 166 | const toTimestamp = function (timestamp) { 167 | return Date.parse(timestamp) / 1000; 168 | }; 169 | 170 | const nth = function (i) { 171 | return i + ["st", "nd", "rd"][((((i + 90) % 100) - 10) % 10) - 1] || `${i}th`; 172 | }; 173 | 174 | // CREDITS: https://github.com/grafana/grafana (Modified) 175 | 176 | const units = new Set(["y", "M", "w", "d", "h", "m", "s"]); 177 | 178 | function parseDateMath(mathString, time) { 179 | const strippedMathString = mathString.replace(/\s/g, ""); 180 | const dateTime = time; 181 | let i = 0; 182 | const { length } = strippedMathString; 183 | 184 | while (i < length) { 185 | const c = strippedMathString.charAt(i); 186 | i += 1; 187 | let type; 188 | let number; 189 | 190 | if (c === "/") { 191 | type = 0; 192 | } else if (c === "+") { 193 | type = 1; 194 | } else if (c === "-") { 195 | type = 2; 196 | } else { 197 | return; 198 | } 199 | 200 | if (Number.isNaN(Number.parseInt(strippedMathString.charAt(i), 10))) { 201 | number = 1; 202 | } else if (strippedMathString.length === 2) { 203 | number = strippedMathString.charAt(i); 204 | } else { 205 | const numberFrom = i; 206 | while (!Number.isNaN(Number.parseInt(strippedMathString.charAt(i), 10))) { 207 | i += 1; 208 | if (i > 10) { 209 | return; 210 | } 211 | } 212 | number = Number.parseInt(strippedMathString.slice(numberFrom, i), 10); 213 | } 214 | 215 | if (type === 0 && number !== 1) { 216 | return; 217 | } 218 | 219 | const unit = strippedMathString.charAt(i); 220 | i += 1; 221 | 222 | if (!units.has(unit)) { 223 | return; 224 | } 225 | if (type === 0) { 226 | dateTime.startOf(unit); 227 | } else if (type === 1) { 228 | dateTime.add(number, unit); 229 | } else if (type === 2) { 230 | dateTime.subtract(number, unit); 231 | } 232 | } 233 | 234 | return dateTime; 235 | } 236 | 237 | const parseTimestamp = function (text) { 238 | if (!text) return; 239 | 240 | if (typeof text !== "string") { 241 | if (moment.isMoment(text)) { 242 | return text; 243 | } 244 | if (moment.isDate(text)) { 245 | return moment(text); 246 | } 247 | return; 248 | } 249 | 250 | let time; 251 | let mathString = ""; 252 | let index; 253 | let parseString; 254 | 255 | if (text.slice(0, 3) === "now") { 256 | time = moment.utc(); 257 | mathString = text.slice(3); 258 | } else { 259 | index = text.indexOf("||"); 260 | if (index === -1) { 261 | parseString = text; 262 | mathString = ""; 263 | } else { 264 | parseString = text.slice(0, Math.max(0, index)); 265 | mathString = text.slice(Math.max(0, index + 2)); 266 | } 267 | 268 | time = moment(parseString, moment.ISO_8601); 269 | } 270 | 271 | if (mathString.length === 0) { 272 | return time.valueOf(); 273 | } 274 | 275 | const dateMath = parseDateMath(mathString, time); 276 | return dateMath ? dateMath.valueOf() : undefined; 277 | }; 278 | 279 | module.exports = { 280 | getPath, 281 | decodeNBT, 282 | getRawLore, 283 | capitalize, 284 | parseItemGems, 285 | removeReforge, 286 | getAverage, 287 | getMedian, 288 | getMean, 289 | getMode, 290 | toTimestamp, 291 | nth, 292 | parseTimestamp, 293 | }; 294 | -------------------------------------------------------------------------------- /API/constants/maro_networth/storage/requestHandler.js: -------------------------------------------------------------------------------- 1 | const URL = require("url").URL; 2 | const axios = require("axios"); 3 | 4 | const HYPIXEL_API = "https://api.hypixel.net"; 5 | const AUCTIONS_ROUTE = HYPIXEL_API + "/skyblock/auctions"; 6 | const BAZAAR_ROUTE = HYPIXEL_API + "/skyblock/bazaar"; 7 | 8 | const getBazaar = async function () { 9 | const url = new URL(BAZAAR_ROUTE); 10 | 11 | const response = await axios(url.toString()); 12 | 13 | return response.data; 14 | }; 15 | 16 | const getAuctionPage = async function (page = 0) { 17 | const url = new URL(AUCTIONS_ROUTE); 18 | url.searchParams.append("page", page); 19 | 20 | const response = await axios(url.toString()); 21 | 22 | return response.data; 23 | }; 24 | 25 | const getActiveAuctions = async function () { 26 | const url = new URL(AUCTIONS_ROUTE); 27 | 28 | const response = await axios(url.toString()); 29 | 30 | return response.data; 31 | }; 32 | 33 | module.exports = { getBazaar, getAuctionPage }; 34 | -------------------------------------------------------------------------------- /API/constants/milestones.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dolphin: [250, 1000, 2500, 5000, 10000], 3 | rock: [2500, 7500, 20000, 100000, 250000], 4 | rarities: ["common", "uncommon", "rare", "epic", "legendary"], 5 | }; 6 | -------------------------------------------------------------------------------- /API/constants/mining.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getHotM: function getHotM(experience) { 3 | let level = 0; 4 | let maxLevel = 7; 5 | let experienceGroup = [0, 3000, 9000, 25000, 60000, 100000, 150000]; 6 | for (let toRemove of experienceGroup) { 7 | experience -= toRemove; 8 | if (experience < 0) { 9 | return Math.min(level + (1 - (experience * -1) / toRemove), maxLevel); 10 | } 11 | level++; 12 | } 13 | return Math.min(level, maxLevel); 14 | }, 15 | perks: { 16 | mining_speed_2: { 17 | name: "Mining Speed 2", 18 | id: "mining_speed_2", 19 | max: 50, 20 | type: "perk", 21 | }, 22 | powder_buff: { 23 | name: "Powder Buff", 24 | id: "powder_buff", 25 | max: 50, 26 | type: "perk", 27 | }, 28 | mining_fortune_2: { 29 | name: "Mining Fortune 2", 30 | id: "mining_fortune_2", 31 | max: 50, 32 | type: "perk", 33 | }, 34 | vein_seeker: { 35 | name: "Vein Seeker", 36 | id: "vein_seeker", 37 | max: 1, 38 | type: "ability", 39 | }, 40 | lonesome_miner: { 41 | name: "Lonesome Miner", 42 | id: "lonesome_miner", 43 | max: 45, 44 | type: "perk", 45 | }, 46 | professional: { 47 | name: "Professional", 48 | id: "professional", 49 | max: 140, 50 | type: "perk", 51 | }, 52 | mole: { name: "Mole", id: "mole", max: 190, type: "perk" }, 53 | fortunate: { name: "Fortunate", id: "fortunate", max: 20, type: "perk" }, 54 | great_explorer: { 55 | name: "Great Explorer", 56 | id: "great_explorer", 57 | max: 20, 58 | type: "perk", 59 | }, 60 | maniac_miner: { 61 | name: "Maniac Miner", 62 | id: "maniac_miner", 63 | max: 1, 64 | type: "ability", 65 | }, 66 | goblin_killer: { 67 | name: "Goblin Killer", 68 | id: "goblin_killer", 69 | max: 1, 70 | type: "perk", 71 | }, 72 | special_0: { 73 | name: "Peak of the Mountain", 74 | id: "special_0", 75 | max: 5, 76 | type: "special", 77 | }, 78 | star_powder: { 79 | name: "Star Powder", 80 | id: "star_powder", 81 | max: 1, 82 | type: "perk", 83 | }, 84 | daily_effect: { 85 | name: "Sky Mall", 86 | id: "daily_effect", 87 | max: 1, 88 | type: "perk", 89 | }, 90 | mining_madness: { 91 | name: "Mining Madness", 92 | id: "mining_madness", 93 | max: 1, 94 | type: "perk", 95 | }, 96 | mining_experience: { 97 | name: "Seasoned Mineman", 98 | id: "mining_experience", 99 | max: 100, 100 | type: "perk", 101 | }, 102 | efficient_miner: { 103 | name: "Efficient Miner", 104 | id: "efficient_miner", 105 | max: 100, 106 | type: "perk", 107 | }, 108 | experience_orbs: { 109 | name: "Orbiter", 110 | id: "experience_orbs", 111 | max: 80, 112 | type: "perk", 113 | }, 114 | front_loaded: { 115 | name: "Front Loaded", 116 | id: "front_loaded", 117 | max: 1, 118 | type: "perk", 119 | }, 120 | precision_mining: { 121 | name: "Precision Mining", 122 | id: "precision_mining", 123 | max: 1, 124 | type: "perk", 125 | }, 126 | random_event: { 127 | name: "Luck of the Cave", 128 | id: "random_event", 129 | max: 45, 130 | type: "perk", 131 | }, 132 | daily_powder: { 133 | name: "Daily Powder", 134 | id: "daily_powder", 135 | max: 100, 136 | type: "perk", 137 | }, 138 | fallen_star_bonus: { 139 | name: "Crystallized", 140 | id: "fallen_star_bonus", 141 | max: 30, 142 | type: "perk", 143 | }, 144 | mining_speed_boost: { 145 | name: "Mining Speed Boost", 146 | id: "mining_speed_boost", 147 | max: 1, 148 | type: "ability", 149 | }, 150 | titanium_insanium: { 151 | name: "Titanium Insanium", 152 | id: "titanium_insanium", 153 | max: 50, 154 | type: "perk", 155 | }, 156 | mining_fortune: { 157 | name: "Mining Fortune", 158 | id: "mining_fortune", 159 | max: 50, 160 | type: "perk", 161 | }, 162 | forge_time: { 163 | name: "Quick Forge", 164 | id: "forge_time", 165 | max: 20, 166 | type: "perk", 167 | }, 168 | pickaxe_toss: { 169 | name: "Pickobulus", 170 | id: "pickaxe_toss", 171 | max: 1, 172 | type: "ability", 173 | }, 174 | mining_speed: { 175 | name: "Mining Speed", 176 | id: "mining_speed", 177 | max: 50, 178 | type: "perk", 179 | }, 180 | }, 181 | forgeItemTimes: { 182 | //REFINE ORE 183 | REFINED_DIAMOND: { duration: 28800000, name: "Refined Diamond" }, //8h 184 | REFINED_MITHRIL: { duration: 21600000, name: "Refined Mithril" }, //6h 185 | REFINED_TITANIUM: { duration: 43200000, name: "Refined Titanium" }, //12h 186 | FUEL_TANK: { duration: 36000000, name: "Fuel Tank" }, //10h 187 | BEJEWELED_HANDLE: { duration: 1800000, name: "Bejeweled Handle" }, //30min 188 | DRILL_ENGINE: { duration: 108000000, name: "Drill Engine" }, //1d 6h 30h 189 | GOLDEN_PLATE: { duration: 21600000, name: "Golden Plate" }, //6h 190 | MITHRIL_PLATE: { duration: 64800000, name: "Mithril Plate" }, //18h 191 | GEMSTONE_MIXTURE: { duration: 14400000, name: "Gemstone Mixture" }, //4h 192 | PERFECT_JADE_GEM: { duration: 72000000, name: "Perfect Jade Gemstone" }, //20h 193 | PERFECT_AMBER_GEM: { duration: 72000000, name: "Perfect Amber Gemstone" }, //20h 194 | PERFECT_TOPAZ_GEM: { duration: 72000000, name: "Perfect Topaz Gemstone" }, //20h 195 | PERFECT_SAPPHIRE_GEM: { 196 | duration: 72000000, 197 | name: "Perfect Sapphire Gemstone", 198 | }, //20h 199 | PERFECT_AMETHYST_GEM: { 200 | duration: 72000000, 201 | name: "Perfect Amethyst Gemstone", 202 | }, //20h 203 | PERFECT_JASPER_GEM: { duration: 72000000, name: "Perfect Jasper Gemstone" }, //20h 204 | PERFECT_RUBY_GEM: { duration: 72000000, name: "Perfect Ruby Gemstone" }, //20h 205 | //ITEM CASTING 206 | MITHRIL_PICKAXE: { duration: 2700000, name: "Mithril Pickaxe" }, //45min 207 | BEACON_2: { duration: 72000000, name: "Beacon 2" }, //20h 208 | TITANIUM_TALISMAN: { duration: 50400000, name: "Titanium Talisman" }, //14h 209 | DIAMONITE: { duration: 21600000, name: "Diamonite" }, //6h 210 | POWER_CRYSTAL: { duration: 7200000, name: "Power Crystal" }, //2h 211 | REFINED_MITHRIL_PICKAXE: { 212 | duration: 79200000, 213 | name: "Refined Mithril Pickaxe", 214 | }, //22h 215 | MITHRIL_DRILL_1: { duration: 14400000, name: "Mithril Drill SX-R226" }, //4h 216 | MITHRIL_FUEL_TANK: { 217 | duration: 36000000, 218 | name: "Mithril-Infused Fuel Tank", 219 | }, //10h 220 | MITHRIL_DRILL_ENGINE: { 221 | duration: 54000000, 222 | name: "Mithril-Plated Drill Engine", 223 | }, //15h 224 | BEACON_3: { duration: 108000000, name: "Beacon 3" }, //1d 6h 30h 225 | TITANIUM_RING: { duration: 72000000, name: "Titanium Ring" }, //20h 226 | PURE_MITHRIL: { duration: 43200000, name: "Pure Mithril" }, //12h 227 | ROCK_GEMSTONE: { duration: 79200000, name: "Rock Gemstone" }, //22h 228 | PETRIFIED_STARFALL: { duration: 50400000, name: "Pertrified Starfall" }, //14h 229 | GOBLIN_OMELETTE_PESTO: { 230 | duration: 72000000, 231 | name: "Pesto Goblin Omelette", 232 | }, //20h 233 | AMMONITE: { duration: 1036800000, name: "Ammonite" }, //12d 234 | GEMSTONE_DRILL_1: { duration: 3600000, name: "Ruby Drill TX-15" }, //1h 235 | MITHRIL_DRILL_2: { duration: 30000, name: "Mithril Drill SX-R326" }, //30sec 236 | TITANIUM_DRILL_ENGINE: { 237 | duration: 108000000, 238 | name: "Titanium-Plated Drill Engine", 239 | }, //1d 6h 30h 240 | GOBLIN_OMELETTE: { duration: 64800000, name: "Goblin Omelette" }, //18h 241 | BEACON_4: { duration: 144000000, name: "Beacon 4" }, //1d 16h 40h 242 | TITANIUM_ARTIFACT: { duration: 129600000, name: "Titanium Artifact" }, //1d 12h 36h 243 | HOT_STUFF: { duration: 86400000, name: "Hot Stuff" }, //1d 244 | GOBLIN_OMELETTE_SUNNY_SIDE: { 245 | duration: 72000000, 246 | name: "Sunny Side Goblin Omelette", 247 | }, //20h 248 | GEMSTONE_DRILL_2: { duration: 30000, name: "Gemstone Drill LT-522" }, //30sec 249 | TITANIUM_DRILL_1: { duration: 230400000, name: "Titanium Drill DR-X355" }, //2d 16h 64h 250 | TITANIUM_DRILL_2: { duration: 30000, name: "Titanium Drill DR-X455" }, //30sec 251 | TITANIUM_DRILL_3: { duration: 30000, name: "Titanium Drill DR-X555" }, //30sec 252 | TITANIUM_FUEL_TANK: { 253 | duration: 90000000, 254 | name: "Titanium-Infused Fuel Tank", 255 | }, //1d 1h 25h 256 | BEACON_5: { duration: 180000000, name: "Beacon 5" }, //2d 2h 50h 257 | TITANIUM_RELIC: { duration: 259200000, name: "Titanium Relic" }, //3d 72h 258 | GOBLIN_OMELETTE_SPICY: { 259 | duration: 72000000, 260 | name: "Spicy Goblin Omelette", 261 | }, //20h 262 | GEMSTONE_CHAMBER: { duration: 14400000, name: "Gemstone Chamber" }, //4h 263 | GEMSTONE_DRILL_3: { duration: 30000, name: "Topaz Drill KGR-12" }, //30sec 264 | RUBY_POLISHED_DRILL_ENGINE: { 265 | duration: 72000000, 266 | name: "Ruby-polished Drill Engine", 267 | }, //20h 268 | GEMSTONE_FUEL_TANK: { duration: 108000000, name: "Gemstone Fuel Tank" }, //1d 6h 30h 269 | GOBLIN_OMELETTE_BLUE_CHEESE: { 270 | duration: 72000000, 271 | name: "Blue Cheese Goblin Omelette", 272 | }, //20h 273 | TITANIUM_DRILL_4: { duration: 30000, name: "Titanium Drill DR-X655" }, //30sec 274 | GEMSTONE_DRILL_4: { duration: 30000, name: "Jasper Drill 10" }, //30sec 275 | SAPPHIRE_POLISHED_DRILL_ENGINE: { 276 | duration: 108000000, 277 | name: "Sapphire-polished Drill Engine", 278 | }, //1d 6h 30h 279 | AMBER_MATERIAL: { duration: 25200000, name: "Amber Material" }, //7h 280 | DIVAN_HELMET: { duration: 82800000, name: "Helmet Of Divan" }, //23h 281 | DIVAN_CHESTPLATE: { duration: 82800000, name: "Chestplate Of Divan" }, //23h 282 | DIVAN_LEGGINGS: { duration: 82800000, name: "Leggings Of Divan" }, //23h 283 | DIVAN_BOOTS: { duration: 82800000, name: "Boots Of Divan" }, //23h 284 | AMBER_POLISHED_DRILL_ENGINE: { 285 | duration: 180000000, 286 | name: "Amber-polished Drill Engine", 287 | }, //2d 2h 50h 288 | PERFECTLY_CUT_FUEL_TANK: { 289 | duration: 180000000, 290 | name: "Perfectly-Cut Fuel Tank", 291 | }, //2d 2h 50h 292 | DIVAN_DRILL: { duration: 216000000, name: "Divan's Drill" }, //2d 12h 60h, 293 | CRYSTAL_HOLLOWS_TRAVEL_SCROLL: { 294 | duration: 36000000, 295 | name: "Travel Scroll to the Crystal Hollows", 296 | }, //10h 297 | FORGE_TRAVEL_SCROLL: { 298 | duration: 18000000, 299 | name: "Travel Scroll to the Dwarven Forge", 300 | }, //5h 301 | }, 302 | }; 303 | -------------------------------------------------------------------------------- /API/constants/minion_slots.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 0: 5, 3 | 5: 6, 4 | 15: 7, 5 | 30: 8, 6 | 50: 9, 7 | 75: 10, 8 | 100: 11, 9 | 125: 12, 10 | 150: 13, 11 | 175: 14, 12 | 200: 15, 13 | 225: 16, 14 | 250: 17, 15 | 275: 18, 16 | 300: 19, 17 | 350: 20, 18 | 400: 21, 19 | 450: 22, 20 | 500: 23, 21 | 550: 24, 22 | 600: 25, //MAX 23 | 650: 26, 24 | 700: 27, 25 | 750: 28, 26 | 800: 29, 27 | 850: 30, 28 | }; 29 | -------------------------------------------------------------------------------- /API/constants/minions.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | FLOWER: { 3 | id: "FLOWER", 4 | name: "Flower", 5 | category: "foraging", 6 | maxLevel: 11, 7 | }, 8 | TARANTULA: { 9 | id: "TARANTULA", 10 | name: "Tarantula", 11 | category: "combat", 12 | maxLevel: 11, 13 | }, 14 | GRAVEL: { 15 | id: "GRAVEL", 16 | name: "Gravel", 17 | category: "mining", 18 | maxLevel: 11, 19 | }, 20 | COCOA: { 21 | id: "COCOA", 22 | name: "Cocoa Beans", 23 | category: "farming", 24 | maxLevel: 12, 25 | }, 26 | FISHING: { 27 | id: "FISHING", 28 | name: "Raw Fish", 29 | category: "fishing", 30 | maxLevel: 11, 31 | }, 32 | ICE: { 33 | id: "ICE", 34 | name: "Ice", 35 | category: "mining", 36 | maxLevel: 11, 37 | }, 38 | SLIME: { 39 | id: "SLIME", 40 | name: "Slime", 41 | category: "combat", 42 | maxLevel: 11, 43 | }, 44 | PUMPKIN: { 45 | id: "PUMPKIN", 46 | name: "Pumpkin", 47 | category: "farming", 48 | maxLevel: 12, 49 | }, 50 | COBBLESTONE: { 51 | id: "COBBLESTONE", 52 | name: "Cobblestone", 53 | category: "mining", 54 | maxLevel: 12, 55 | }, 56 | GLOWSTONE: { 57 | id: "GLOWSTONE", 58 | name: "Glowstone", 59 | category: "mining", 60 | maxLevel: 11, 61 | }, 62 | DIAMOND: { 63 | id: "DIAMOND", 64 | name: "Diamond", 65 | category: "mining", 66 | maxLevel: 12, 67 | }, 68 | DARK_OAK: { 69 | id: "DARK_OAK", 70 | name: "Dark Oak", 71 | category: "foraging", 72 | maxLevel: 11, 73 | }, 74 | GOLD: { 75 | id: "GOLD", 76 | name: "Gold Ingot", 77 | category: "mining", 78 | maxLevel: 12, 79 | }, 80 | REVENANT: { 81 | id: "REVENANT", 82 | name: "Revenant", 83 | category: "combat", 84 | maxLevel: 12, 85 | }, 86 | CHICKEN: { 87 | id: "CHICKEN", 88 | name: "Chicken", 89 | category: "farming", 90 | maxLevel: 12, 91 | }, 92 | CAVESPIDER: { 93 | id: "CAVESPIDER", 94 | name: "Cave Spider", 95 | category: "combat", 96 | maxLevel: 11, 97 | }, 98 | BLAZE: { 99 | id: "BLAZE", 100 | name: "Blaze", 101 | category: "combat", 102 | maxLevel: 11, 103 | }, 104 | CLAY: { 105 | id: "CLAY", 106 | name: "Clay", 107 | category: "fishing", 108 | maxLevel: 11, 109 | }, 110 | CACTUS: { 111 | id: "CACTUS", 112 | name: "Cactus", 113 | category: "farming", 114 | maxLevel: 12, 115 | }, 116 | PIG: { 117 | id: "PIG", 118 | name: "Porkchop", 119 | category: "farming", 120 | maxLevel: 12, 121 | }, 122 | ENDERMAN: { 123 | id: "ENDERMAN", 124 | name: "Enderman", 125 | category: "combat", 126 | maxLevel: 11, 127 | }, 128 | COAL: { 129 | id: "COAL", 130 | name: "Coal", 131 | category: "mining", 132 | maxLevel: 12, 133 | }, 134 | WHEAT: { 135 | id: "WHEAT", 136 | name: "Wheat", 137 | category: "farming", 138 | maxLevel: 12, 139 | }, 140 | REDSTONE: { 141 | id: "REDSTONE", 142 | name: "Redstone", 143 | category: "mining", 144 | maxLevel: 12, 145 | }, 146 | JUNGLE: { 147 | id: "JUNGLE", 148 | name: "Jungle Wood", 149 | category: "foraging", 150 | maxLevel: 11, 151 | }, 152 | SKELETON: { 153 | id: "SKELETON", 154 | name: "Skeleton", 155 | category: "combat", 156 | maxLevel: 11, 157 | }, 158 | LAPIS: { 159 | id: "LAPIS", 160 | name: "Lapis Lazuli", 161 | category: "mining", 162 | maxLevel: 12, 163 | }, 164 | RABBIT: { 165 | id: "RABBIT", 166 | name: "Rabbit", 167 | category: "farming", 168 | maxLevel: 12, 169 | }, 170 | SUGAR_CANE: { 171 | id: "SUGAR_CANE", 172 | name: "Sugar Cane", 173 | category: "farming", 174 | maxLevel: 12, 175 | }, 176 | MELON: { 177 | id: "MELON", 178 | name: "Melon", 179 | category: "farming", 180 | maxLevel: 12, 181 | }, 182 | NETHER_WARTS: { 183 | id: "NETHER_WARTS", 184 | name: "Nether Wart", 185 | category: "farming", 186 | maxLevel: 12, 187 | }, 188 | QUARTZ: { 189 | id: "QUARTZ", 190 | name: "Quartz", 191 | category: "mining", 192 | maxLevel: 11, 193 | }, 194 | CREEPER: { 195 | id: "CREEPER", 196 | name: "Creeper", 197 | category: "combat", 198 | maxLevel: 11, 199 | }, 200 | OAK: { 201 | id: "OAK", 202 | name: "Oak Wood", 203 | category: "foraging", 204 | maxLevel: 11, 205 | }, 206 | MUSHROOM: { 207 | id: "MUSHROOM", 208 | name: "Mushroom", 209 | category: "farming", 210 | maxLevel: 12, 211 | }, 212 | SNOW: { 213 | id: "SNOW", 214 | name: "Snow", 215 | category: "mining", 216 | maxLevel: 11, 217 | }, 218 | POTATO: { 219 | id: "POTATO", 220 | name: "Potato", 221 | category: "farming", 222 | maxLevel: 12, 223 | }, 224 | MAGMA_CUBE: { 225 | id: "MAGMA_CUBE", 226 | name: "Magma Cube", 227 | category: "combat", 228 | maxLevel: 11, 229 | }, 230 | ZOMBIE: { 231 | id: "ZOMBIE", 232 | name: "Zombie", 233 | category: "combat", 234 | maxLevel: 11, 235 | }, 236 | SPRUCE: { 237 | id: "SPRUCE", 238 | name: "Spruce Wood", 239 | category: "foraging", 240 | maxLevel: 11, 241 | }, 242 | SAND: { 243 | id: "SAND", 244 | name: "Sand", 245 | category: "mining", 246 | maxLevel: 11, 247 | }, 248 | EMERALD: { 249 | id: "EMERALD", 250 | name: "Emerald", 251 | category: "mining", 252 | maxLevel: 12, 253 | }, 254 | CARROT: { 255 | id: "CARROT", 256 | name: "Carrot", 257 | category: "farming", 258 | maxLevel: 12, 259 | }, 260 | ENDER_STONE: { 261 | id: "ENDER_STONE", 262 | name: "Endstone", 263 | category: "mining", 264 | maxLevel: 11, 265 | }, 266 | BIRCH: { 267 | id: "BIRCH", 268 | name: "Birch Wood", 269 | category: "foragings", 270 | }, 271 | GHAST: { 272 | id: "GHAST", 273 | name: "Ghast", 274 | category: "combat", 275 | maxLevel: 11, 276 | }, 277 | SPIDER: { 278 | id: "SPIDER", 279 | name: "Spider", 280 | category: "combat", 281 | maxLevel: 11, 282 | }, 283 | IRON: { 284 | id: "IRON", 285 | name: "Iron Ingot", 286 | category: "mining", 287 | maxLevel: 12, 288 | }, 289 | SHEEP: { 290 | id: "SHEEP", 291 | name: "Mutton", 292 | category: "farming", 293 | maxLevel: 12, 294 | }, 295 | ACACIA: { 296 | id: "ACACIA", 297 | name: "Acacia Wood", 298 | category: "foraging", 299 | maxLevel: 11, 300 | }, 301 | OBSIDIAN: { 302 | id: "OBSIDIAN", 303 | name: "Obsidian", 304 | category: "mining", 305 | maxLevel: 12, 306 | }, 307 | COW: { 308 | id: "COW", 309 | name: "Cow", 310 | category: "farming", 311 | maxLevel: 12, 312 | }, 313 | MITHRIL: { 314 | id: "MITHRIL", 315 | name: "Mithril", 316 | category: "mining", 317 | maxLevel: 12, 318 | }, 319 | HARD_STONE: { 320 | id: "HARD_STONE", 321 | name: "Hard Stone", 322 | category: "mining", 323 | maxLevel: 12, 324 | }, 325 | }; 326 | -------------------------------------------------------------------------------- /API/constants/missing.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/SkyCrypt/SkyCryptWebsite 2 | const constants = require("./talismans"); 3 | 4 | module.exports = function getMissingTalismans(talismans, option = "") { 5 | let unique = Object.keys(constants.talismans); 6 | if (option === "max") unique = Object.keys(constants.max_upgrade_talismans); 7 | 8 | unique.forEach((name) => { 9 | if (name in constants.talisman_duplicates) { 10 | for (let duplicate of constants.talisman_duplicates[name]) { 11 | if (talismans.includes(duplicate)) { 12 | talismans[talismans.indexOf(duplicate)] = name; 13 | break; 14 | } 15 | } 16 | } 17 | }); 18 | 19 | let missing = unique.filter((talisman) => !talismans.includes(talisman)); 20 | missing.forEach((name) => { 21 | if (name in constants.talisman_upgrades) { 22 | //if the name is in the upgrades list 23 | for (let upgrade of constants.talisman_upgrades[name]) { 24 | if (talismans.includes(upgrade)) { 25 | //if talisman list includes the upgrade 26 | missing = missing.filter((item) => item !== name); 27 | break; 28 | } 29 | } 30 | } 31 | }); 32 | 33 | const output = []; 34 | missing.forEach(async (talisman) => { 35 | let object = { 36 | name: null, 37 | rarity: null, 38 | }; 39 | 40 | if (object.id == null) object.id = talisman; 41 | 42 | if (constants.talismans[talisman] != null) { 43 | const data = constants.talismans[talisman]; 44 | 45 | object.name = data.name || null; 46 | object.rarity = data.rarity || null; 47 | } 48 | 49 | output.push(object); 50 | }); 51 | 52 | return output; 53 | }; 54 | -------------------------------------------------------------------------------- /API/constants/mobs.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/SkyCrypt/SkyCryptWebsite 2 | module.exports = { 3 | pond_squid: "Squid", 4 | unburried_zombie: "Crypt Ghoul", 5 | zealot_enderman: "Zealot", 6 | invisible_creeper: "Sneaky Creeper", 7 | generator_ghast: "Minion Ghast", 8 | generator_magma_cube: "Minion Magma Cube", 9 | generator_slime: "Minion Slime", 10 | brood_mother_spider: "Brood Mother", 11 | obsidian_wither: "Obsidian Defender", 12 | sadan_statue: "Terracotta", 13 | diamond_guy: "Angry Archaeologist", 14 | tentaclees: "Fels", 15 | master_diamond_guy: "Master Angry Archaeologist", 16 | master_sadan_statue: "Master Terracotta", 17 | master_tentaclees: "Master Fels", 18 | maxor: "Necron", 19 | }; 20 | -------------------------------------------------------------------------------- /API/constants/networth/ignored_enchantments.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | "bane of athropods 1", 3 | "bane of athropods 2", 4 | "bane of athropods 3", 5 | "bane of athropods 4", 6 | "bane of athropods 5", 7 | "cleave 1", 8 | "cleave 2", 9 | "cleave 3", 10 | "cleave 4", 11 | "cleave 5", 12 | "critical 1", 13 | "critical 2", 14 | "critical 3", 15 | "critical 4", 16 | "critical 5", 17 | "cubism 1", 18 | "cubism 2", 19 | "cubism 3", 20 | "cubism 4", 21 | "cubism 5", 22 | "ender slayer 1", 23 | "ender slayer 2", 24 | "ender slayer 3", 25 | "ender slayer 4", 26 | "ender slayer 5", 27 | "execute 1", 28 | "execute 2", 29 | "execute 3", 30 | "execute 4", 31 | "execute 5", 32 | "experience 1", 33 | "experience 2", 34 | "experience 3", 35 | "fire aspect 1", 36 | "fire aspect 2", 37 | "first strike 1", 38 | "first strike 2", 39 | "first strike 3", 40 | "first strike 4", 41 | "giant killer 1", 42 | "giant killer 2", 43 | "giant killer 3", 44 | "giant killer 4", 45 | "giant killer 5", 46 | "impaling 1", 47 | "impaling 2", 48 | "impaling 3", 49 | "knockback 1", 50 | "knockback 2", 51 | "lethality 1", 52 | "lethality 2", 53 | "lethality 3", 54 | "lethality 4", 55 | "lethality 5", 56 | "life steal 1", 57 | "life steal 2", 58 | "life steal 3", 59 | "looting 1", 60 | "looting 2", 61 | "looting 3", 62 | "luck 1", 63 | "luck 2", 64 | "luck 3", 65 | "luck 4", 66 | "luck 5", 67 | "prosecute 1", 68 | "prosecute 2", 69 | "prosecute 3", 70 | "prosecute 4", 71 | "prosecute 5", 72 | "scavenger 1", 73 | "scavenger 2", 74 | "scavenger 3", 75 | "sharpness 1", 76 | "sharpness 2", 77 | "sharpness 3", 78 | "sharpness 4", 79 | "sharpness 5", 80 | "smite 1", 81 | "smite 2", 82 | "smite 3", 83 | "smite 4", 84 | "smite 5", 85 | "syphon 1", 86 | "syphon 2", 87 | "syphon 3", 88 | "telekinesis 1", 89 | "thunderbolt 1", 90 | "thunderbolt 2", 91 | "thunderbolt 3", 92 | "thunderbolt 4", 93 | "thunderbolt 5", 94 | "thunderlord 1", 95 | "thunderlord 2", 96 | "thunderlord 3", 97 | "thunderlord 4", 98 | "thunderlord 5", 99 | "titan killer 1", 100 | "titan killer 2", 101 | "titan killer 3", 102 | "titan killer 4", 103 | "titan killer 5", 104 | "triple-strike 1", 105 | "triple-strike 2", 106 | "triple-strike 3", 107 | "triple-strike 4", 108 | "triple-strike 5", 109 | "vampirism 1", 110 | "vampirism 2", 111 | "vampirism 3", 112 | "vampirism 4", 113 | "vampirism 5", 114 | "venomous 1", 115 | "venomous 2", 116 | "venomous 3", 117 | "venomous 4", 118 | "venomous 5", 119 | "aiming 1", 120 | "aiming 2", 121 | "aiming 3", 122 | "aiming 4", 123 | "aiming 5", 124 | "chance 1", 125 | "chance 2", 126 | "chance 3", 127 | "chance 4", 128 | "chance 5", 129 | "flame 1", 130 | "infinite quiver 1", 131 | "infinite quiver 2", 132 | "infinite quiver 3", 133 | "infinite quiver 4", 134 | "infinite quiver 5", 135 | "piercing 1", 136 | "power 1", 137 | "power 2", 138 | "power 3", 139 | "power 4", 140 | "power 5", 141 | "snipe 1", 142 | "snipe 2", 143 | "snipe 3", 144 | "punch 1", 145 | "punch 2", 146 | "aqua affinity 1", 147 | "blast protection 1", 148 | "blast protection 2", 149 | "blast protection 3", 150 | "blast protection 4", 151 | "blast protection 5", 152 | "depth strider 1", 153 | "depth strider 2", 154 | "depth strider 3", 155 | "feather falling 1", 156 | "feather falling 2", 157 | "feather falling 3", 158 | "feather falling 4", 159 | "feather falling 5", 160 | "fire protection 1", 161 | "fire protection 2", 162 | "fire protection 3", 163 | "fire protection 4", 164 | "fire protection 5", 165 | "frost walker 1", 166 | "frost walker 2", 167 | "growth 1", 168 | "growth 2", 169 | "growth 3", 170 | "growth 4", 171 | "growth 5", 172 | "projectile protection 1", 173 | "projectile protection 2", 174 | "projectile protection 3", 175 | "projectile protection 4", 176 | "projectile protection 5", 177 | "protection 1", 178 | "protection 2", 179 | "protection 3", 180 | "protection 4", 181 | "protection 5", 182 | "respiration 1", 183 | "respiration 2", 184 | "respiration 3", 185 | "thorns 1", 186 | "thorns 2", 187 | "thorns 3", 188 | "efficiency 1", 189 | "efficiency 2", 190 | "efficiency 3", 191 | "efficiency 4", 192 | "efficiency 5", 193 | "harvesting 1", 194 | "harvesting 2", 195 | "harvesting 3", 196 | "harvesting 4", 197 | "harvesting 5", 198 | "fortune 1", 199 | "fortune 2", 200 | "fortune 3", 201 | "rainbow 1", 202 | "silk touch 1", 203 | "smelting touch 1", 204 | "angler 1", 205 | "angler 2", 206 | "angler 3", 207 | "angler 4", 208 | "angler 5", 209 | "blessing 1", 210 | "blessing 2", 211 | "blessing 3", 212 | "blessing 4", 213 | "blessing 5", 214 | "caster 1", 215 | "caster 2", 216 | "caster 3", 217 | "caster 4", 218 | "caster 5", 219 | "frail 1", 220 | "frail 2", 221 | "frail 3", 222 | "frail 4", 223 | "frail 5", 224 | "luck of the sea 1", 225 | "luck of the sea 2", 226 | "luck of the sea 3", 227 | "luck of the sea 4", 228 | "luck of the sea 5", 229 | "lure 1", 230 | "lure 2", 231 | "lure 3", 232 | "lure 4", 233 | "lure 5", 234 | "magnet 1", 235 | "magnet 2", 236 | "magnet 3", 237 | "magnet 4", 238 | "magnet 5", 239 | "spiked hook 1", 240 | "spiked hook 2", 241 | "spiked hook 3", 242 | "spiked hook 4", 243 | "spiked hook 5", 244 | "luck 6", 245 | "scavenger 4", 246 | "scavenger 5", 247 | "smite 6", 248 | "syphon 4", 249 | "infinite quiver 6", 250 | "infinite quiver 7", 251 | "infinite quiver 8", 252 | "infinite quiver 9", 253 | "blast protection 6", 254 | "blast protection 7", 255 | "projectile protection 6", 256 | "projectile protection 7", 257 | "feather falling 6", 258 | "feather falling 7", 259 | "feather falling 8", 260 | "feather falling 9", 261 | "fire protection 6", 262 | "fire protection 7", 263 | "angler 6", 264 | "caster 6", 265 | "frail 6", 266 | "luck of the sea 6", 267 | "lure 6", 268 | "magnet 6", 269 | "spiked hook 6", 270 | ]; 271 | -------------------------------------------------------------------------------- /API/constants/networth/ignored_items.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | "zombie commander whip", 3 | "dreadlord sword", 4 | "silent death", 5 | "zombie knight sword", 6 | "zombie soldier cutlass", 7 | "skeleton lord helmet", 8 | "earth shard", 9 | "conjuring", 10 | "parkour start/end", 11 | "pillar quartz block", 12 | "chiseled quartz block", 13 | "plumber's sponge", 14 | "oak wood", 15 | "sludge juice", 16 | "wishing compass", 17 | "rune", 18 | "inflatable jerry", 19 | "spirit leap", 20 | "mini sandcastle", 21 | "decoy", 22 | "arachne's keeperfragment", 23 | "hypixel sandcastle", 24 | "red goblin egg", 25 | "worm membrane", 26 | "soul string", 27 | "tasty cheese", 28 | ]; 29 | -------------------------------------------------------------------------------- /API/constants/networth/reforge_stones.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Candled: { 3 | item_name: "Candy Corn", 4 | }, 5 | Submerged: { 6 | item_name: "Deep Sea Orb", 7 | }, 8 | Reinforced: { 9 | item_name: "Rare Diamond", 10 | }, 11 | Dirty: { 12 | item_name: "Dirt Bottle", 13 | }, 14 | Cubic: { 15 | item_name: "Molten Cube", 16 | }, 17 | Warped: { 18 | item_name: "Warped Stone", 19 | }, 20 | Undead: { 21 | item_name: "Premium Flesh", 22 | }, 23 | Rediculous: { 24 | item_name: "Red Nose", 25 | }, 26 | Necrotic: { 27 | item_name: "Necromancer's Brooch", 28 | }, 29 | Spiked: { 30 | item_name: "Dragon Scale", 31 | }, 32 | Loving: { 33 | item_name: "Red Scarf", 34 | }, 35 | Perfect: { 36 | item_name: "Diamond Atom", 37 | }, 38 | Fabled: { 39 | item_name: "Dragon Claw", 40 | }, 41 | Suspicious: { 42 | item_name: "Suspicious Vial", 43 | }, 44 | Renowned: { 45 | item_name: "Dragon Horn", 46 | }, 47 | Gilded: { 48 | item_name: "Midas Jewel", 49 | }, 50 | Giant: { 51 | item_name: "Giant Tooth", 52 | }, 53 | Enpowered: { 54 | item_name: "Sadan's Brooch", 55 | }, 56 | Ancient: { 57 | item_name: "Precursor Gear", 58 | }, 59 | Withered: { 60 | item_name: "Wither Blood", 61 | }, 62 | Moil: { 63 | item_name: "Moil Log", 64 | }, 65 | Blessed: { 66 | item_name: "Blessed Fruit", 67 | }, 68 | Toil: { 69 | item_name: "Toil Log", 70 | }, 71 | Precise: { 72 | item_name: "Optical Lens", 73 | }, 74 | Spiritual: { 75 | item_name: "Spirit Stone", 76 | }, 77 | Headstrong: { 78 | item_name: "Salmon Opal", 79 | }, 80 | Fruitful: { 81 | item_name: "Onyx", 82 | }, 83 | Magnetic: { 84 | item_name: "Lapis Crystal", 85 | }, 86 | Fleet: { 87 | item_name: "Diamonite", 88 | }, 89 | Mithraic: { 90 | item_name: "Pure Mithril", 91 | }, 92 | Auspicious: { 93 | item_name: "Rock Gemstone", 94 | }, 95 | Refined: { 96 | item_name: "Refined Amber", 97 | }, 98 | Stellar: { 99 | item_name: "Petrified Starfall", 100 | }, 101 | }; 102 | -------------------------------------------------------------------------------- /API/constants/networth/vanilla_items.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | "allium", 3 | "anvil", 4 | "apple", 5 | "armor stand", 6 | "arrow", 7 | "arrow of fire resistance", 8 | "arrow of healing", 9 | "arrow of invisibility", 10 | "arrow of leaping", 11 | "arrow of night vision", 12 | "arrow of poison", 13 | "arrow of regeneration", 14 | "arrow of slowness", 15 | "arrow of strength", 16 | "arrow of swiftness", 17 | "arrow of water breathing", 18 | "arrow of weakness", 19 | "awkward potion", 20 | "azure bluet", 21 | "baked potato", 22 | "beacon", 23 | "bed", 24 | "beetroot", 25 | "beetroot seeds", 26 | "beetroot soup", 27 | "blaze powder", 28 | "blaze rod", 29 | "block of redstone", 30 | "blue orchid", 31 | "boat", 32 | "bone", 33 | "bone meal", 34 | "book", 35 | "book and quill", 36 | "bottle of enchanting", 37 | "bow", 38 | "bowl", 39 | "bread", 40 | "brewing stand", 41 | "brown mushroom", 42 | "bucket", 43 | "cactus", 44 | "cactus green dye", 45 | "cake", 46 | "carrot", 47 | "carrot on a stick", 48 | "cauldron", 49 | "chainmail boots", 50 | "chainmail chestplate", 51 | "chainmail helmet", 52 | "chainmail leggings", 53 | "charcoal", 54 | "chest", 55 | "chorus fruit", 56 | "clay", 57 | "clay brick", 58 | "coal", 59 | "cocoa bean", 60 | "cocoa plant", 61 | "command block", 62 | "compass", 63 | "cooked chicken", 64 | "cooked fish", 65 | "cooked mutton", 66 | "cooked porkchop", 67 | "cooked rabbit", 68 | "cookie", 69 | "cyan dye", 70 | "dandelion", 71 | "dandelion yellow dye", 72 | "daylight sensor", 73 | "dead shrub", 74 | "diamond axe", 75 | "diamond boots", 76 | "diamond chestplate", 77 | "diamond gem", 78 | "diamond helmet", 79 | "diamond hoe", 80 | "diamond horse armor", 81 | "diamond leggings", 82 | "diamond pickaxe", 83 | "diamond shovel", 84 | "diamond sword", 85 | "dispenser", 86 | "double tallgrass", 87 | "dragon egg", 88 | "dragon's breath", 89 | "dropper", 90 | "egg", 91 | "elytra", 92 | "emerald", 93 | "empty map", 94 | "enchanted book", 95 | "enchanted golden apple", 96 | "enchantment table", 97 | "end crystal", 98 | "end gateway", 99 | "ender chest", 100 | "ender pearl", 101 | "exploration map", 102 | "eye of ender", 103 | "feather", 104 | "fermented spider eye", 105 | "fire charge", 106 | "firework rocket", 107 | "firework star", 108 | "cont.", 109 | "fishing rod", 110 | "flint", 111 | "flint and steel", 112 | "flower pot", 113 | "furnace", 114 | "ghast tear", 115 | "glass bottle", 116 | "glowstone dust", 117 | "gold axe", 118 | "gold boots", 119 | "gold chestplate", 120 | "gold helmet", 121 | "gold hoe", 122 | "gold horse armor", 123 | "gold ingot", 124 | "gold leggings", 125 | "gold nugget", 126 | "gold pickaxe", 127 | "gold shovel", 128 | "gold sword", 129 | "golden apple", 130 | "golden carrot", 131 | "gray dye", 132 | "gunpowder", 133 | "harming potion", 134 | "harming potion ii", 135 | "harming splash", 136 | "harming splash ii", 137 | "healing potion", 138 | "healing potion ii", 139 | "healing splash", 140 | "healing splash ii", 141 | "hopper", 142 | "ink sack", 143 | "iron axe", 144 | "iron boots", 145 | "iron chestplate", 146 | "iron door", 147 | "iron helmet", 148 | "iron hoe", 149 | "iron horse armor", 150 | "iron ingot", 151 | "iron leggings", 152 | "iron pickaxe", 153 | "iron shovel", 154 | "iron sword", 155 | "iron trapdoor", 156 | "item frame", 157 | "jukebox", 158 | "ladder", 159 | "lapis lazuli", 160 | "large fern", 161 | "lead", 162 | "leather", 163 | "leather boots", 164 | "leather chestplate", 165 | "leather helmet", 166 | "leather leggings", 167 | "lever", 168 | "light blue dye", 169 | "light gray dye", 170 | "lilac", 171 | "lime dye", 172 | "locked chest", 173 | "magenta dye", 174 | "magma block", 175 | "magma cream", 176 | "melon seeds", 177 | "minecart", 178 | "mundane potion", 179 | "mushroom stew", 180 | "name tag", 181 | "nether quartz", 182 | "nether star", 183 | "nether wart", 184 | "nether wart seeds", 185 | "note block", 186 | "observer", 187 | "orange dye", 188 | "orange tulip", 189 | "oxeye daisy", 190 | "painting", 191 | "paper", 192 | "peony", 193 | "pink dye", 194 | "pink tulip", 195 | "piston", 196 | "cont.", 197 | "poisonous potato", 198 | "poppy", 199 | "potato", 200 | "prismarine crystals", 201 | "prismarine shard", 202 | "pumpkin pie", 203 | "pumpkin seeds", 204 | "purple dye", 205 | "purpur stairs", 206 | "quartz stairs", 207 | "rabbit hide", 208 | "rabbit stew", 209 | "rabbit's foot", 210 | "rail", 211 | "raw beef", 212 | "raw chicken", 213 | "raw fish", 214 | "raw mutton", 215 | "raw porkchop", 216 | "raw rabbit", 217 | "red mushroom", 218 | "red tulip", 219 | "redstone comparator", 220 | "redstone dust", 221 | "redstone lamp", 222 | "redstone repeater", 223 | "redstone torch", 224 | "redstone wire", 225 | "rose bush", 226 | "rose red dye", 227 | "rotten flesh", 228 | "saddle", 229 | "sea lantern", 230 | "shears", 231 | "shield", 232 | "shulker shell", 233 | "sign", 234 | "slime ball", 235 | "snowball", 236 | "spider eye", 237 | "steak", 238 | "stick", 239 | "sticky piston", 240 | "stone axe", 241 | "stone hoe", 242 | "stone pickaxe", 243 | "stone pressure plate", 244 | "stone shovel", 245 | "stone sword", 246 | "string", 247 | "sugar", 248 | "sugar cane", 249 | "sunflower", 250 | "tnt", 251 | "tall grass", 252 | "thick potion", 253 | "torch", 254 | "totem of undying", 255 | "trapdoor", 256 | "trapped chest", 257 | "tripwire", 258 | "tripwire hook", 259 | "watch", 260 | "water bottle", 261 | "wet sponge", 262 | "wheat", 263 | "wheat seeds", 264 | "white tulip", 265 | "wooden axe", 266 | "wooden door", 267 | "wooden hoe", 268 | "wooden pickaxe", 269 | "wooden pressure plate", 270 | "wooden shovel", 271 | "wooden sword", 272 | "workbench", 273 | "written book", 274 | "air", 275 | "andesite", 276 | "barrier", 277 | "bedrock", 278 | "birch-wood slab", 279 | "black wool", 280 | "block of coal", 281 | "block of diamond", 282 | "block of emerald", 283 | "block of gold", 284 | "block of iron", 285 | "blue wool", 286 | "bone block", 287 | "bookshelf", 288 | "brick", 289 | "brick slab", 290 | "brick stairs", 291 | "brown wool", 292 | "chorus flower", 293 | "chorus plant", 294 | "clay block", 295 | "coal ore", 296 | "cobblestone", 297 | "cobblestone slab", 298 | "cobblestone stairs", 299 | "cobblestone wall", 300 | "cobweb", 301 | "cyan wool", 302 | "dark prismarine", 303 | "diamond ore", 304 | "diorite", 305 | "dirt", 306 | "emerald ore", 307 | "end portal", 308 | "end portal frame", 309 | "end stone", 310 | "end stone bricks", 311 | "end rod", 312 | "farmland", 313 | "fire", 314 | "glass", 315 | "glass pane", 316 | "glowstone", 317 | "gold ore", 318 | "granite", 319 | "grass", 320 | "cont.", 321 | "grass path", 322 | "gravel", 323 | "gray wool", 324 | "green wool", 325 | "hardened clay", 326 | "hay bale", 327 | "ice", 328 | "iron bars", 329 | "iron ore", 330 | "jack-o-lantern", 331 | "jungle-wood slab", 332 | "lapis lazuli block", 333 | "lapis lazuli ore", 334 | "lava", 335 | "light blue wool", 336 | "light gray wool", 337 | "lily pad", 338 | "lime wool", 339 | "magenta wool", 340 | "melon vine", 341 | "mob spawner", 342 | "moss stone", 343 | "mossy cobblestone wall", 344 | "mycelium", 345 | "nether brick", 346 | "nether brick fence", 347 | "nether brick slab", 348 | "nether brick stairs", 349 | "nether quartz ore", 350 | "netherrack", 351 | "oak-wood slab", 352 | "obsidian", 353 | "orange wool", 354 | "packed ice", 355 | "pink wool", 356 | "podzol", 357 | "polished andesite", 358 | "polished diorite", 359 | "polished granite", 360 | "portal", 361 | "prismarine", 362 | "cont.", 363 | "prismarine bricks", 364 | "pumpkin", 365 | "pumpkin vine", 366 | "purple wool", 367 | "purpur block", 368 | "purpur pillar", 369 | "purpur slab", 370 | "quartz block", 371 | "quartz slab", 372 | "red sandstone", 373 | "red sandstone slab", 374 | "red sandstone stairs", 375 | "red wool", 376 | "redstone ore", 377 | "sand", 378 | "sandstone", 379 | "sandstone slab", 380 | "sandstone stairs", 381 | "slime block", 382 | "snow", 383 | "snow block", 384 | "soul sand", 385 | "sponge", 386 | "spruce-wood slab", 387 | "stone", 388 | "stone brick slab", 389 | "stone brick stairs", 390 | "stone bricks", 391 | "stone slab", 392 | "structure block", 393 | "vines", 394 | "water", 395 | "wooden slab", 396 | "wool", 397 | "yellow wool", 398 | ]; 399 | -------------------------------------------------------------------------------- /API/constants/senitherWeight.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade 2 | const dungeon_weights = { 3 | catacombs: 0.0002149604615, 4 | healer: 0.0000045254834, 5 | mage: 0.0000045254834, 6 | berserk: 0.0000045254834, 7 | archer: 0.0000045254834, 8 | tank: 0.0000045254834, 9 | }; 10 | const slayer_weights = { 11 | revenant: { 12 | divider: 2208, 13 | modifier: 0.15, 14 | }, 15 | tarantula: { 16 | divider: 2118, 17 | modifier: 0.08, 18 | }, 19 | sven: { 20 | divider: 1962, 21 | modifier: 0.015, 22 | }, 23 | enderman: { 24 | divider: 1430, 25 | modifier: 0.017, 26 | }, 27 | }; 28 | const skill_weights = { 29 | mining: { 30 | exponent: 1.18207448, 31 | divider: 259634, 32 | maxLevel: 60, 33 | }, 34 | // Maxes out foraging at 850 points at level 50. 35 | foraging: { 36 | exponent: 1.232826, 37 | divider: 259634, 38 | maxLevel: 50, 39 | }, 40 | // Maxes out enchanting at 450 points at level 60. 41 | enchanting: { 42 | exponent: 0.96976583, 43 | divider: 882758, 44 | maxLevel: 60, 45 | }, 46 | // Maxes out farming at 2,200 points at level 60. 47 | farming: { 48 | exponent: 1.217848139, 49 | divider: 220689, 50 | maxLevel: 60, 51 | }, 52 | // Maxes out combat at 1,500 points at level 60. 53 | combat: { 54 | exponent: 1.15797687265, 55 | divider: 275862, 56 | maxLevel: 60, 57 | }, 58 | // Maxes out fishing at 2,500 points at level 50. 59 | fishing: { 60 | exponent: 1.406418, 61 | divider: 88274, 62 | maxLevel: 50, 63 | }, 64 | // Maxes out alchemy at 200 points at level 50. 65 | alchemy: { 66 | exponent: 1.0, 67 | divider: 1103448, 68 | maxLevel: 50, 69 | }, 70 | // Maxes out taming at 500 points at level 50. 71 | taming: { 72 | exponent: 1.14744, 73 | divider: 441379, 74 | maxLevel: 50, 75 | }, 76 | }; 77 | 78 | const calcSkill = require("./skills"); 79 | 80 | async function calculateSenitherWeight(type, level = null, experience) { 81 | const slayers = ["revenant", "tarantula", "sven", "enderman"]; 82 | const dungeons = ["catacombs", "healer", "mage", "berserk", "archer", "tank"]; 83 | const skills = [ 84 | "mining", 85 | "foraging", 86 | "enchanting", 87 | "farming", 88 | "combat", 89 | "fishing", 90 | "alchemy", 91 | "taming", 92 | ]; 93 | if (slayers.includes(type)) return calculateSlayerWeight(type, experience); 94 | else if (dungeons.includes(type)) 95 | return calculateDungeonWeight(type, level, experience); 96 | else if (skills.includes(type)) 97 | return calculateSkillWeight(type, level, experience); 98 | else return null; 99 | } 100 | 101 | async function calculateTotalSenitherWeight(profile) { 102 | const weight = { 103 | skills: { 104 | farming: await calculateSenitherWeight( 105 | "farming", 106 | calcSkill("farming", profile?.experience_skill_farming || 0) 107 | .levelWithProgress, 108 | profile?.experience_skill_farming || 0 109 | ), 110 | mining: await calculateSenitherWeight( 111 | "mining", 112 | calcSkill("mining", profile?.experience_skill_mining || 0) 113 | .levelWithProgress, 114 | profile?.experience_skill_mining || 0 115 | ), 116 | combat: await calculateSenitherWeight( 117 | "combat", 118 | calcSkill("combat", profile?.experience_skill_combat || 0) 119 | .levelWithProgress, 120 | profile?.experience_skill_combat || 0 121 | ), 122 | foraging: await calculateSenitherWeight( 123 | "foraging", 124 | calcSkill("foraging", profile?.experience_skill_foraging || 0) 125 | .levelWithProgress, 126 | profile?.experience_skill_foraging || 0 127 | ), 128 | fishing: await calculateSenitherWeight( 129 | "fishing", 130 | calcSkill("fishing", profile?.experience_skill_fishing || 0) 131 | .levelWithProgress, 132 | profile?.experience_skill_fishing || 0 133 | ), 134 | enchanting: await calculateSenitherWeight( 135 | "enchanting", 136 | calcSkill("enchanting", profile?.experience_skill_enchanting || 0) 137 | .levelWithProgress, 138 | profile?.experience_skill_enchanting || 0 139 | ), 140 | alchemy: await calculateSenitherWeight( 141 | "alchemy", 142 | calcSkill("alchemy", profile?.experience_skill_alchemy || 0) 143 | .levelWithProgress, 144 | profile?.experience_skill_alchemy || 0 145 | ), 146 | taming: await calculateSenitherWeight( 147 | "taming", 148 | calcSkill("taming", profile?.experience_skill_taming || 0) 149 | .levelWithProgress, 150 | profile?.experience_skill_taming || 0 151 | ), 152 | }, 153 | slayer: { 154 | revenant: await calculateSenitherWeight( 155 | "revenant", 156 | null, 157 | profile.slayer_bosses?.zombie?.xp || 0 158 | ), 159 | tarantula: await calculateSenitherWeight( 160 | "tarantula", 161 | null, 162 | profile.slayer_bosses?.spider?.xp || 0 163 | ), 164 | sven: await calculateSenitherWeight( 165 | "sven", 166 | null, 167 | profile.slayer_bosses?.wolf?.xp || 0 168 | ), 169 | enderman: await calculateSenitherWeight( 170 | "enderman", 171 | null, 172 | profile.slayer_bosses?.enderman?.xp || 0 173 | ), 174 | }, 175 | dungeons: { 176 | catacombs: await calculateSenitherWeight( 177 | "catacombs", 178 | calcSkill( 179 | "dungeoneering", 180 | profile.dungeons?.dungeon_types?.catacombs?.experience || 0 181 | ).levelWithProgress, 182 | profile.dungeons?.dungeon_types?.catacombs?.experience || 0 183 | ), 184 | classes: { 185 | healer: await calculateSenitherWeight( 186 | "healer", 187 | calcSkill( 188 | "dungeoneering", 189 | profile.dungeons?.player_classes?.healer?.experience || 0 190 | ).levelWithProgress, 191 | profile.dungeons?.player_classes?.healer?.experience || 0 192 | ), 193 | mage: await calculateSenitherWeight( 194 | "mage", 195 | calcSkill( 196 | "dungeoneering", 197 | profile.dungeons?.player_classes?.mage?.experience || 0 198 | ).levelWithProgress, 199 | profile.dungeons?.player_classes?.mage?.experience || 0 200 | ), 201 | berserk: await calculateSenitherWeight( 202 | "berserk", 203 | calcSkill( 204 | "dungeoneering", 205 | profile.dungeons?.player_classes?.berserk?.experience || 0 206 | ).levelWithProgress, 207 | profile.dungeons?.player_classes?.berserk?.experience || 0 208 | ), 209 | archer: await calculateSenitherWeight( 210 | "archer", 211 | calcSkill( 212 | "dungeoneering", 213 | profile.dungeons?.player_classes?.archer?.experience || 0 214 | ).levelWithProgress, 215 | profile.dungeons?.player_classes?.archer?.experience || 0 216 | ), 217 | tank: await calculateSenitherWeight( 218 | "tank", 219 | calcSkill( 220 | "dungeoneering", 221 | profile.dungeons?.player_classes?.tank?.experience || 0 222 | ).levelWithProgress, 223 | profile.dungeons?.player_classes?.tank?.experience || 0 224 | ), 225 | }, 226 | }, 227 | }; 228 | return weight; 229 | } 230 | 231 | module.exports = { calculateSenitherWeight, calculateTotalSenitherWeight }; 232 | 233 | function calculateDungeonWeight(type, level, experience) { 234 | let percentageModifier = dungeon_weights[type]; 235 | 236 | let base = Math.pow(level, 4.5) * percentageModifier; 237 | 238 | if (experience <= 569809640) { 239 | return { 240 | weight: base, 241 | weight_overflow: 0, 242 | }; 243 | } 244 | 245 | let remaining = experience - 569809640; 246 | let splitter = (4 * 569809640) / base; 247 | 248 | return { 249 | weight: Math.floor(base), 250 | weight_overflow: Math.pow(remaining / splitter, 0.968) || 0, 251 | }; 252 | } 253 | 254 | function calculateSkillWeight(type, level, experience) { 255 | const skillGroup = skill_weights[type]; 256 | if (skillGroup.exponent == undefined || skillGroup.divider == undefined) { 257 | return { 258 | weight: 0, 259 | weight_overflow: 0, 260 | }; 261 | } 262 | 263 | let maxSkillLevelXP = skillGroup.maxLevel == 60 ? 111672425 : 55172425; 264 | 265 | let base = 266 | Math.pow(level * 10, 0.5 + skillGroup.exponent + level / 100) / 1250; 267 | if (experience > maxSkillLevelXP) { 268 | base = Math.round(base); 269 | } 270 | if (experience <= maxSkillLevelXP) { 271 | return { 272 | weight: base, 273 | weight_overflow: 0, 274 | }; 275 | } 276 | 277 | return { 278 | weight: base, 279 | weight_overflow: Math.pow( 280 | (experience - maxSkillLevelXP) / skillGroup.divider, 281 | 0.968 282 | ), 283 | }; 284 | } 285 | 286 | function calculateSlayerWeight(type, experience) { 287 | const slayerWeight = slayer_weights[type]; 288 | 289 | if (experience <= 1000000) { 290 | return { 291 | weight: experience == 0 ? 0 : experience / slayerWeight.divider, 292 | weight_overflow: 0, 293 | }; 294 | } 295 | 296 | let base = 1000000 / slayerWeight.divider; 297 | let remaining = experience - 1000000; 298 | 299 | let modifier = slayerWeight.modifier; 300 | let overflow = 0; 301 | 302 | while (remaining > 0) { 303 | let left = Math.min(remaining, 1000000); 304 | 305 | overflow += Math.pow( 306 | left / (slayerWeight.divider * (1.5 + modifier)), 307 | 0.942 308 | ); 309 | modifier += slayerWeight.modifier; 310 | remaining -= left; 311 | } 312 | 313 | return { 314 | weight: base, 315 | weight_overflow: overflow, 316 | }; 317 | } 318 | -------------------------------------------------------------------------------- /API/constants/skills.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/SkyCrypt/SkyCryptWebsite (Modified) 2 | const xp_tables = require("./xp_tables"); 3 | 4 | module.exports = function calcSkill(skill, experience) { 5 | table = "normal"; 6 | if (skill === "runecrafting") table = "runecrafting"; 7 | if (skill === "social") table = "social"; 8 | if (skill === "dungeoneering") table = "catacombs"; 9 | 10 | if (experience <= 0) { 11 | return { 12 | totalXp: 0, 13 | xp: 0, 14 | level: 0, 15 | xpCurrent: 0, 16 | xpForNext: xp_tables[table][0], 17 | progress: 0, 18 | }; 19 | } 20 | let xp = 0; 21 | let level = 0; 22 | let xpForNext = 0; 23 | let progress = 0; 24 | let maxLevel = 0; 25 | 26 | if (xp_tables.max_levels[skill]) maxLevel = xp_tables.max_levels[skill]; 27 | 28 | for (let i = 1; i <= maxLevel; i++) { 29 | xp += xp_tables[table][i - 1]; 30 | 31 | if (xp > experience) { 32 | xp -= xp_tables[table][i - 1]; 33 | } else { 34 | if (i <= maxLevel) level = i; 35 | } 36 | } 37 | 38 | let xpCurrent = Math.floor(experience - xp); 39 | 40 | let totalXp = experience; 41 | 42 | if (level < maxLevel) { 43 | xpForNext = Math.ceil(xp_tables[table][level]); 44 | } 45 | progress = 46 | level >= maxLevel ? 0 : Math.max(0, Math.min(xpCurrent / xpForNext, 1)); 47 | 48 | return { 49 | totalXp, 50 | xp, 51 | level, 52 | xpCurrent, 53 | xpForNext, 54 | progress, 55 | levelWithProgress: level < maxLevel ? level + progress : level, 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /API/constants/symbols.js: -------------------------------------------------------------------------------- 1 | // CREDIT: https://github.com/SkyCryptWebsite/SkyCrypt/ (Modified) 2 | 3 | const symbols = { 4 | health: { 5 | name: "Health", 6 | nameLore: "Health", 7 | nameShort: "Health", 8 | nameTiny: "HP", 9 | symbol: "❤", 10 | suffix: "", 11 | color: "c", 12 | }, 13 | defense: { 14 | name: "Defense", 15 | nameLore: "Defense", 16 | nameShort: "Defense", 17 | nameTiny: "Def", 18 | symbol: "❈", 19 | suffix: "", 20 | color: "a", 21 | }, 22 | strength: { 23 | name: "Strength", 24 | nameLore: "Strength", 25 | nameShort: "Strength", 26 | nameTiny: "Str", 27 | symbol: "❁", 28 | suffix: "", 29 | color: "c", 30 | }, 31 | intelligence: { 32 | name: "Intelligence", 33 | nameLore: "Intelligence", 34 | nameShort: "Intelligence", 35 | nameTiny: "Int", 36 | symbol: "✎", 37 | suffix: "", 38 | color: "b", 39 | }, 40 | speed: { 41 | name: "Speed", 42 | nameLore: "Speed", 43 | nameShort: "Speed", 44 | nameTiny: "Spd", 45 | symbol: "✦", 46 | suffix: "", 47 | color: "f", 48 | }, 49 | crit_chance: { 50 | name: "Crit Chance", 51 | nameLore: "Crit Chance", 52 | nameShort: "Crit Chance", 53 | nameTiny: "CC", 54 | symbol: "☣", 55 | suffix: "%", 56 | color: "9", 57 | }, 58 | crit_damage: { 59 | name: "Crit Damage", 60 | nameLore: "Crit Damage", 61 | nameShort: "Crit Damage", 62 | nameTiny: "CD", 63 | symbol: "☠", 64 | suffix: "%", 65 | color: "9", 66 | }, 67 | bonus_attack_speed: { 68 | name: "Bonus Attack Speed", 69 | nameLore: "Bonus Attack Speed", 70 | nameShort: "Attack Speed", 71 | nameTiny: "AS", 72 | symbol: "⚔", 73 | suffix: "%", 74 | color: "e", 75 | }, 76 | ability_damage: { 77 | name: "Ability Damage", 78 | nameLore: "Ability Damage", 79 | nameShort: "Ability Damage", 80 | nameTiny: "AD", 81 | symbol: "๑", 82 | suffix: "%", 83 | color: "c", 84 | }, 85 | true_defense: { 86 | name: "True Defense", 87 | nameLore: "True Defense", 88 | nameShort: "True Defense", 89 | nameTiny: "TDef", 90 | symbol: "❂", 91 | suffix: "", 92 | color: "f", 93 | }, 94 | ferocity: { 95 | name: "Ferocity", 96 | nameLore: "Ferocity", 97 | nameShort: "Ferocity", 98 | nameTiny: "Fer", 99 | symbol: "⫽", 100 | suffix: "", 101 | color: "c", 102 | }, 103 | magic_find: { 104 | name: "Magic Find", 105 | nameLore: "Magic Find", 106 | nameShort: "Magic Find", 107 | nameTiny: "MF", 108 | symbol: "✯", 109 | suffix: "", 110 | color: "b", 111 | }, 112 | pet_luck: { 113 | name: "Pet Luck", 114 | nameLore: "Pet Luck", 115 | nameShort: "Pet Luck", 116 | nameTiny: "PL", 117 | symbol: "♣", 118 | suffix: "", 119 | color: "d", 120 | }, 121 | sea_creature_chance: { 122 | name: "Sea Creature Chance", 123 | nameLore: "Sea Creature Chance", 124 | nameShort: "SC Chance", 125 | nameTiny: "SCC", 126 | symbol: "α", 127 | suffix: "%", 128 | color: "3", 129 | }, 130 | fishing_speed: { 131 | name: "Fishing Speed", 132 | nameLore: "Fishing Speed", 133 | nameShort: "Fishing Speed", 134 | nameTiny: "FS", 135 | symbol: "☂", 136 | suffix: "", 137 | color: "b", 138 | }, 139 | mining_speed: { 140 | name: "Mining Speed", 141 | nameLore: "Mining Speed", 142 | nameShort: "Mining Speed", 143 | nameTiny: "MngSpd", 144 | symbol: "⸕", 145 | suffix: "", 146 | color: "6", 147 | }, 148 | mining_fortune: { 149 | name: "Mining Fortune", 150 | nameLore: "Mining Fortune", 151 | nameShort: "Mining Fortune", 152 | nameTiny: "MngFrt", 153 | symbol: "☘", 154 | suffix: "", 155 | color: "6", 156 | }, 157 | farming_fortune: { 158 | name: "Farming Fortune", 159 | nameLore: "Farming Fortune", 160 | nameShort: "Farming Fortune", 161 | nameTiny: "FrmFrt", 162 | symbol: "☘", 163 | suffix: "", 164 | color: "6", 165 | }, 166 | foraging_fortune: { 167 | name: "Foraging Fortune", 168 | nameLore: "Foraging Fortune", 169 | nameShort: "Foraging Fortune", 170 | nameTiny: "FrgFrt", 171 | symbol: "☘", 172 | suffix: "", 173 | color: "6", 174 | }, 175 | pristine: { 176 | name: "Pristine", 177 | nameLore: "Pristine", 178 | nameShort: "Pristine", 179 | nameTiny: "Prs", 180 | symbol: "✧", 181 | suffix: "", 182 | color: "5", 183 | }, 184 | damage: { 185 | name: "Damage", 186 | nameLore: "Damage", 187 | nameShort: "Damage", 188 | nameTiny: "Dmg", 189 | symbol: "❁", 190 | suffix: "", 191 | color: "c", 192 | }, 193 | soulflow: { 194 | name: "Soulflow", 195 | nameLore: "Soulflow", 196 | nameShort: "Soulflow", 197 | nameTiny: "Sf", 198 | symbol: "⸎", 199 | suffix: "", 200 | color: "3", 201 | }, 202 | overflow_mana: { 203 | name: "Overflow Mana", 204 | nameLore: "Overflow Mana", 205 | nameShort: "Overflow Mana", 206 | nameTiny: "OMn", 207 | symbol: "ʬ", 208 | suffix: "", 209 | color: "3", 210 | }, 211 | heat: { 212 | name: "Heat", 213 | nameLore: "Heat", 214 | nameShort: "Heat", 215 | nameTiny: "Ht", 216 | symbol: "♨", 217 | suffix: "", 218 | color: "c", 219 | }, 220 | absorption: { 221 | name: "Absorption", 222 | nameLore: "Absorption", 223 | nameShort: "Absorption", 224 | nameTiny: "Abs", 225 | symbol: "❤", 226 | suffix: "", 227 | color: "6", 228 | }, 229 | breaking_power: { 230 | name: "Breaking Power", 231 | nameLore: "Breaking Power", 232 | nameShort: "Breaking Power", 233 | nameTiny: "BP", 234 | symbol: "Ⓟ", 235 | suffix: "", 236 | color: "2", 237 | }, 238 | health_regen: { 239 | name: "Health Regen", 240 | nameLore: "Health Regen", 241 | nameShort: "Health Regen", 242 | nameTiny: "HPR", 243 | symbol: "❣", 244 | suffix: "", 245 | color: "c", 246 | }, 247 | vitality: { 248 | name: "Vitality", 249 | nameLore: "Vitality", 250 | nameShort: "Vitality", 251 | nameTiny: "Vit", 252 | symbol: "♨", 253 | suffix: "", 254 | color: "5", 255 | }, 256 | mending: { 257 | name: "Mending", 258 | nameLore: "Mending", 259 | nameShort: "Mending", 260 | nameTiny: "Mend", 261 | symbol: "☄", 262 | suffix: "", 263 | color: "a", 264 | }, 265 | wisdom: { 266 | name: "Wisdom", 267 | nameLore: "Wisdom", 268 | nameShort: "Wisdom", 269 | nameTiny: "W", 270 | symbol: "☯", 271 | suffix: "", 272 | color: "3", 273 | }, 274 | rift_time: { 275 | name: "Rift Time", 276 | nameLore: "Rift Time", 277 | nameShort: "Rift Time", 278 | nameTiny: "RT", 279 | symbol: "ф", 280 | suffix: "", 281 | color: "a", 282 | }, 283 | fear: { 284 | name: "Fear", 285 | nameLore: "Fear", 286 | nameShort: "Fear", 287 | nameTiny: "Fr", 288 | symbol: "☠", 289 | suffix: "", 290 | color: "a", 291 | }, 292 | /* 293 | name: "", 294 | nameLore: "", 295 | nameShort: "", 296 | nameTiny: "", 297 | symbol: "", 298 | suffix: "", 299 | color: "", 300 | */ 301 | }; 302 | 303 | module.exports = { symbols }; 304 | -------------------------------------------------------------------------------- /API/constants/trophyFishing.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | allTrophyFish: { 3 | BLOBFISH: 0, 4 | BLOBFISH_BRONZE: 0, 5 | BLOBFISH_SILVER: 0, 6 | BLOBFISH_GOLD: 0, 7 | BLOBFISH_DIAMOND: 0, 8 | FLYFISH: 0, 9 | FLYFISH_BRONZE: 0, 10 | FLYFISH_SILVER: 0, 11 | FLYFISH_GOLD: 0, 12 | FLYFISH_DIAMOND: 0, 13 | GOLDEN_FISH: 0, 14 | GOLDEN_FISH_BRONZE: 0, 15 | GOLDEN_FISH_SILVER: 0, 16 | GOLDEN_FISH_GOLD: 0, 17 | GOLDEN_FISH_DIAMOND: 0, 18 | GUSHER: 0, 19 | GUSHER_BRONZE: 0, 20 | GUSHER_SILVER: 0, 21 | GUSHER_GOLD: 0, 22 | GUSHER_DIAMOND: 0, 23 | KARATE_FISH: 0, 24 | KARATE_FISH_BRONZE: 0, 25 | KARATE_FISH_SILVER: 0, 26 | KARATE_FISH_GOLD: 0, 27 | KARATE_FISH_DIAMOND: 0, 28 | LAVA_HORSE: 0, 29 | LAVA_HORSE_BRONZE: 0, 30 | LAVA_HORSE_SILVER: 0, 31 | LAVA_HORSE_GOLD: 0, 32 | LAVA_HORSE_DIAMOND: 0, 33 | MANA_RAY: 0, 34 | MANA_RAY_BRONZE: 0, 35 | MANA_RAY_SILVER: 0, 36 | MANA_RAY_GOLD: 0, 37 | MANA_RAY_DIAMOND: 0, 38 | MOLDFIN: 0, 39 | MOLDFIN_BRONZE: 0, 40 | MOLDFIN_SILVER: 0, 41 | MOLDFIN_GOLD: 0, 42 | MOLDFIN_DIAMOND: 0, 43 | OBFUSCATED_FISH_1: 0, 44 | OBFUSCATED_FISH_1_BRONZE: 0, 45 | OBFUSCATED_FISH_1_SILVER: 0, 46 | OBFUSCATED_FISH_1_GOLD: 0, 47 | OBFUSCATED_FISH_1_DIAMOND: 0, 48 | OBFUSCATED_FISH_2: 0, 49 | OBFUSCATED_FISH_2_BRONZE: 0, 50 | OBFUSCATED_FISH_2_SILVER: 0, 51 | OBFUSCATED_FISH_2_GOLD: 0, 52 | OBFUSCATED_FISH_2_DIAMOND: 0, 53 | OBFUSCATED_FISH_3: 0, 54 | OBFUSCATED_FISH_3_BRONZE: 0, 55 | OBFUSCATED_FISH_3_SILVER: 0, 56 | OBFUSCATED_FISH_3_GOLD: 0, 57 | OBFUSCATED_FISH_3_DIAMOND: 0, 58 | SKELETON_FISH: 0, 59 | SKELETON_FISH_BRONZE: 0, 60 | SKELETON_FISH_SILVER: 0, 61 | SKELETON_FISH_GOLD: 0, 62 | SKELETON_FISH_DIAMOND: 0, 63 | SLUGFISH: 0, 64 | SLUGFISH_BRONZE: 0, 65 | SLUGFISH_SILVER: 0, 66 | SLUGFISH_GOLD: 0, 67 | SLUGFISH_DIAMOND: 0, 68 | SOUL_FISH: 0, 69 | SOUL_FISH_BRONZE: 0, 70 | SOUL_FISH_SILVER: 0, 71 | SOUL_FISH_GOLD: 0, 72 | SOUL_FISH_DIAMOND: 0, 73 | STEAMING_HOT_FLOUNDER: 0, 74 | STEAMING_HOT_FLOUNDER_BRONZE: 0, 75 | STEAMING_HOT_FLOUNDER_SILVER: 0, 76 | STEAMING_HOT_FLOUNDER_GOLD: 0, 77 | STEAMING_HOT_FLOUNDER_DIAMOND: 0, 78 | SULPHUR_SKITTER: 0, 79 | SULPHUR_SKITTER_BRONZE: 0, 80 | SULPHUR_SKITTER_SILVER: 0, 81 | SULPHUR_SKITTER_GOLD: 0, 82 | SULPHUR_SKITTER_DIAMOND: 0, 83 | VANILLE: 0, 84 | VANILLE_BRONZE: 0, 85 | VANILLE_SILVER: 0, 86 | VANILLE_GOLD: 0, 87 | VANILLE_DIAMOND: 0, 88 | VOLCANIC_STONEFISH: 0, 89 | VOLCANIC_STONEFISH_BRONZE: 0, 90 | VOLCANIC_STONEFISH_SILVER: 0, 91 | VOLCANIC_STONEFISH_GOLD: 0, 92 | VOLCANIC_STONEFISH_DIAMOND: 0, 93 | }, 94 | }; 95 | -------------------------------------------------------------------------------- /API/constants/weight.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade 2 | const dungeon_weights = { 3 | catacombs: 0.0002149604615, 4 | healer: 0.0000045254834, 5 | mage: 0.0000045254834, 6 | berserk: 0.0000045254834, 7 | archer: 0.0000045254834, 8 | tank: 0.0000045254834, 9 | }; 10 | const slayer_weights = { 11 | revenant: { 12 | divider: 2208, 13 | modifier: 0.15, 14 | }, 15 | tarantula: { 16 | divider: 2118, 17 | modifier: 0.08, 18 | }, 19 | sven: { 20 | divider: 1962, 21 | modifier: 0.015, 22 | }, 23 | enderman: { 24 | divider: 1430, 25 | modifier: 0.017, 26 | }, 27 | }; 28 | const skill_weights = { 29 | mining: { 30 | exponent: 1.18207448, 31 | divider: 259634, 32 | maxLevel: 60, 33 | }, 34 | // Maxes out foraging at 850 points at level 50. 35 | foraging: { 36 | exponent: 1.232826, 37 | divider: 259634, 38 | maxLevel: 50, 39 | }, 40 | // Maxes out enchanting at 450 points at level 60. 41 | enchanting: { 42 | exponent: 0.96976583, 43 | divider: 882758, 44 | maxLevel: 60, 45 | }, 46 | // Maxes out farming at 2,200 points at level 60. 47 | farming: { 48 | exponent: 1.217848139, 49 | divider: 220689, 50 | maxLevel: 60, 51 | }, 52 | // Maxes out combat at 1,500 points at level 60. 53 | combat: { 54 | exponent: 1.15797687265, 55 | divider: 275862, 56 | maxLevel: 60, 57 | }, 58 | // Maxes out fishing at 2,500 points at level 50. 59 | fishing: { 60 | exponent: 1.406418, 61 | divider: 88274, 62 | maxLevel: 50, 63 | }, 64 | // Maxes out alchemy at 200 points at level 50. 65 | alchemy: { 66 | exponent: 1.0, 67 | divider: 1103448, 68 | maxLevel: 50, 69 | }, 70 | // Maxes out taming at 500 points at level 50. 71 | taming: { 72 | exponent: 1.14744, 73 | divider: 441379, 74 | maxLevel: 50, 75 | }, 76 | }; 77 | 78 | module.exports = function calculateWeight(type, level = null, experience) { 79 | const slayers = ["revenant", "tarantula", "sven", "enderman"]; 80 | const dungeons = ["catacombs", "healer", "mage", "berserk", "archer", "tank"]; 81 | const skills = [ 82 | "mining", 83 | "foraging", 84 | "enchanting", 85 | "farming", 86 | "combat", 87 | "fishing", 88 | "alchemy", 89 | "taming", 90 | ]; 91 | if (slayers.includes(type)) return calculateSlayerWeight(type, experience); 92 | else if (dungeons.includes(type)) 93 | return calculateDungeonWeight(type, level, experience); 94 | else if (skills.includes(type)) 95 | return calculateSkillWeight(type, level, experience); 96 | else return null; 97 | }; 98 | 99 | function calculateDungeonWeight(type, level, experience) { 100 | let percentageModifier = dungeon_weights[type]; 101 | 102 | let base = Math.pow(level, 4.5) * percentageModifier; 103 | 104 | if (experience <= 569809640) { 105 | return { 106 | weight: base, 107 | weight_overflow: 0, 108 | }; 109 | } 110 | 111 | let remaining = experience - 569809640; 112 | let splitter = (4 * 569809640) / base; 113 | 114 | return { 115 | weight: Math.floor(base), 116 | weight_overflow: Math.pow(remaining / splitter, 0.968) || 0, 117 | }; 118 | } 119 | 120 | function calculateSkillWeight(type, level, experience) { 121 | const skillGroup = skill_weights[type]; 122 | if (skillGroup.exponent == undefined || skillGroup.divider == undefined) { 123 | return { 124 | weight: 0, 125 | weight_overflow: 0, 126 | }; 127 | } 128 | 129 | let maxSkillLevelXP = skillGroup.maxLevel == 60 ? 111672425 : 55172425; 130 | 131 | let base = 132 | Math.pow(level * 10, 0.5 + skillGroup.exponent + level / 100) / 1250; 133 | if (experience > maxSkillLevelXP) { 134 | base = Math.round(base); 135 | } 136 | if (experience <= maxSkillLevelXP) { 137 | return { 138 | weight: base, 139 | weight_overflow: 0, 140 | }; 141 | } 142 | 143 | return { 144 | weight: base, 145 | weight_overflow: Math.pow( 146 | (experience - maxSkillLevelXP) / skillGroup.divider, 147 | 0.968 148 | ), 149 | }; 150 | } 151 | 152 | function calculateSlayerWeight(type, experience) { 153 | const slayerWeight = slayer_weights[type]; 154 | 155 | if (experience <= 1000000) { 156 | return { 157 | weight: experience == 0 ? 0 : experience / slayerWeight.divider, 158 | weight_overflow: 0, 159 | }; 160 | } 161 | 162 | let base = 1000000 / slayerWeight.divider; 163 | let remaining = experience - 1000000; 164 | 165 | let modifier = slayerWeight.modifier; 166 | let overflow = 0; 167 | 168 | while (remaining > 0) { 169 | let left = Math.min(remaining, 1000000); 170 | 171 | overflow += Math.pow( 172 | left / (slayerWeight.divider * (1.5 + modifier)), 173 | 0.942 174 | ); 175 | modifier += slayerWeight.modifier; 176 | remaining -= left; 177 | } 178 | 179 | return { 180 | weight: base, 181 | weight_overflow: overflow, 182 | }; 183 | } 184 | -------------------------------------------------------------------------------- /API/constants/xp_tables.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | max_levels: { 3 | farming: 60, 4 | mining: 60, 5 | combat: 60, 6 | foraging: 50, 7 | fishing: 50, 8 | enchanting: 60, 9 | alchemy: 50, 10 | taming: 50, 11 | carpentry: 50, 12 | runecrafting: 25, 13 | social: 25, 14 | dungeoneering: 50, 15 | }, 16 | normal: [ 17 | 50, 125, 200, 300, 500, 750, 1000, 1500, 2000, 3500, 5000, 7500, 10000, 18 | 15000, 20000, 30000, 50000, 75000, 100000, 200000, 300000, 400000, 500000, 19 | 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000, 1400000, 20 | 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000, 21 | 2300000, 2400000, 2500000, 2600000, 2750000, 2900000, 3100000, 3400000, 22 | 3700000, 4000000, 4300000, 4600000, 4900000, 5200000, 5500000, 5800000, 23 | 6100000, 6400000, 6700000, 7000000, 24 | ], 25 | social: [ 26 | 50, 100, 150, 250, 500, 750, 1000, 1250, 1500, 2000, 2500, 3000, 3750, 4500, 27 | 6000, 8000, 10000, 12500, 15000, 20000, 25000, 30000, 35000, 40000, 50000, 28 | ], 29 | runecrafting: [ 30 | 50, 100, 125, 160, 200, 250, 315, 400, 500, 625, 785, 1000, 1250, 1600, 31 | 2000, 2465, 3125, 4000, 5000, 6200, 7800, 9800, 12200, 15300, 19050, 32 | ], 33 | catacombs: [ 34 | 50, 75, 110, 160, 230, 330, 470, 670, 950, 1340, 1890, 2665, 3760, 5260, 35 | 7380, 10300, 14400, 20000, 27600, 38000, 52500, 71500, 97000, 132000, 36 | 180000, 243000, 328000, 445000, 600000, 800000, 1065000, 1410000, 1900000, 37 | 2500000, 3300000, 4300000, 5600000, 7200000, 9200000, 12000000, 15000000, 38 | 19000000, 24000000, 30000000, 38000000, 48000000, 60000000, 75000000, 39 | 93000000, 116250000, 40 | ], 41 | slayer: { 42 | zombie: [5, 15, 200, 1000, 5000, 20000, 100000, 400000, 1000000], 43 | spider: [5, 25, 200, 1000, 5000, 20000, 100000, 400000, 1000000], 44 | wolf: [5, 30, 250, 1500, 5000, 20000, 100000, 400000, 1000000], 45 | enderman: [10, 30, 250, 1500, 5000, 20000, 100000, 400000, 1000000], 46 | blaze: [10, 30, 250, 1500, 5000, 20000, 100000, 400000, 1000000], 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /API/data/auctions.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /API/data/refreshAuctions.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const fs = require("fs"); 3 | const { toFixed } = require("../constants/functions"); 4 | const config = require("../config.json"); 5 | 6 | module.exports = async function refresAuctions() { 7 | async function updateAuctions() { 8 | let request; 9 | try { 10 | request = await axios.get("https://api.hypixel.net/skyblock/auctions"); 11 | } catch (err) { 12 | return console.log("Failed to update auctions: ", err); 13 | } 14 | 15 | if (request.status === 200) { 16 | if (config.auctionHouse.refreshMessage) 17 | console.log("[AUCTIONS] Getting auctions."); 18 | let auctions = []; 19 | for (let i = 0; i < request.data.totalPages; i++) { 20 | const data = ( 21 | await axios.get(`https://api.hypixel.net/skyblock/auctions?page=${i}`) 22 | ).data.auctions; 23 | for (const auction of data) { 24 | auctions.push(auction); 25 | } 26 | 27 | if (config.debug) 28 | console.log( 29 | `[AUCTIONS] Progress ${toFixed( 30 | (i / request.data.totalPages) * 100, 31 | 2 32 | )}%` 33 | ); 34 | } 35 | fs.writeFileSync( 36 | "API/data/auctions.json", 37 | JSON.stringify(auctions, null, 2) 38 | ); 39 | if (config.auctionHouse.refreshMessage) 40 | console.log("[AUCTIONS] Auctions updated successfully"); 41 | } else { 42 | console.log("[AUCTIONS] Failed to update Auctions: ", request.status); 43 | } 44 | } 45 | 46 | updateAuctions(); 47 | setInterval(async () => { 48 | updateAuctions(); 49 | }, 1000 * 60 * 10); // 10 minutes 50 | }; 51 | -------------------------------------------------------------------------------- /API/data/refreshCollections.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const fs = require("fs"); 3 | 4 | module.exports = async () => { 5 | async function refreshCollections() { 6 | const collections = []; 7 | 8 | const collections_res = ( 9 | await axios.get("https://api.hypixel.net/resources/skyblock/collections") 10 | ).data.collections; 11 | for (const type of Object.keys(collections_res)) { 12 | for (const collection_type of Object.keys(collections_res[type].items)) { 13 | const tiers = []; 14 | for (const tier of collections_res[type].items[collection_type].tiers) { 15 | tiers.push({ 16 | tier: tier.tier, 17 | amountRequired: tier.amountRequired, 18 | }); 19 | } 20 | 21 | collections.push({ 22 | name: collections_res[type].items[collection_type].name, 23 | id: collection_type, 24 | category: type, 25 | maxTiers: collections_res[type].items[collection_type].maxTiers, 26 | tiers, 27 | }); 28 | } 29 | } 30 | fs.writeFileSync( 31 | "API/data/collections.json", 32 | JSON.stringify(collections, null, 2), 33 | (err) => { 34 | console.log(err); 35 | } 36 | ); 37 | 38 | const items_res = ( 39 | await axios.get("https://api.hypixel.net/resources/skyblock/items") 40 | ).data.items; 41 | fs.writeFileSync("API/json/items.json", JSON.stringify(items_res, null, 2)); 42 | } 43 | 44 | await refreshCollections(); 45 | setInterval(async () => { 46 | await refreshCollections(); 47 | }, 86400000); // 1 day 48 | }; 49 | -------------------------------------------------------------------------------- /API/data/refreshPrices.js: -------------------------------------------------------------------------------- 1 | const config = require("../config.json"); 2 | const axios = require("axios"); 3 | const fs = require("fs"); 4 | 5 | module.exports = async function refreshPrices() { 6 | async function updatePrices() { 7 | let request; 8 | try { 9 | request = await axios.get( 10 | "https://raw.githubusercontent.com/SkyHelperBot/Prices/master/prices.json" 11 | ); 12 | } catch (err) { 13 | return console.log("Failed to update prices: ", err); 14 | } 15 | 16 | if (request.status === 200) { 17 | fs.writeFileSync( 18 | "API/data/prices.json", 19 | JSON.stringify(request.data, null, 2) 20 | ); 21 | if (config.prices.refreshMessage) 22 | console.log("[PRICES] Prices updated successfully"); 23 | } else { 24 | console.log("[PRICES] Failed to update prices: ", request.status); 25 | } 26 | } 27 | 28 | updatePrices(); 29 | setInterval(async () => { 30 | updatePrices(); 31 | }, 1000 * 60 * 15); // 15 minutes 32 | }; 33 | -------------------------------------------------------------------------------- /API/functions/getAuctionHouse.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const fs = require('fs'); 3 | const { isUuid } = require('../utils/uuid'); 4 | const axios = require('axios') 5 | 6 | const retrieveAuctions = async function () { 7 | try { 8 | return JSON.parse(fs.readFileSync('API/data/auctions.json')); 9 | } catch (error) { 10 | if (error.toString().includes("ENOENT: no such file or directory, open '../data/auctions.json'")){ 11 | return { status: 102, data: "Auctions haven't been updated yet. Please wait a bit" }; 12 | } else { 13 | return { status: 404, data: error.toString() }; 14 | } 15 | } 16 | }; 17 | 18 | async function getUUID(uuid) { 19 | if (!isUuid(uuid)) { 20 | const mojang_response = (await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`)); 21 | if (mojang_response?.data?.uuid) uuid = mojang_response.data.uuid.replace(/-/g, ""); 22 | } 23 | return uuid; 24 | } 25 | 26 | async function getAuctionHouse(options = {lore: null, name: null, rarity: null, category: null, bin: null, lowest_price: null, highest_price: null, user: null, }) { 27 | const auctionsRes = await retrieveAuctions() 28 | 29 | let filteredAuctions = []; 30 | const searchData = {}; 31 | 32 | searchData['lore'] = options?.lore?.toLowerCase() 33 | searchData['name'] = options?.name?.toLowerCase() 34 | searchData['rarity'] = options?.rarity?.toLowerCase() 35 | searchData['category'] = options?.category?.toLowerCase() 36 | searchData['bin'] = options?.bin?.toLowerCase() 37 | searchData['lowest_price'] = options?.lowest_price?.toLowerCase() 38 | searchData['highest_price'] = options?.highest_price?.toLowerCase() 39 | searchData['user'] = options?.user != undefined ? await getUUID(options?.user?.toLowerCase()) : null 40 | 41 | Object.keys(searchData).forEach((key) => { 42 | if (searchData[key] == null ||searchData[key] == undefined) delete searchData[key]; 43 | }); 44 | 45 | for (let auction of auctionsRes) { 46 | if (auction.end < Date.now()) continue; 47 | if (searchData.name) if (!auction.item_name.toLowerCase().includes(searchData.name)) continue; 48 | if (searchData.lore) if (!auction.item_lore.toLowerCase().includes(searchData.lore)) continue; 49 | if (searchData.rarity) if (!auction.tier.toLowerCase().includes(searchData.rarity)) continue; 50 | if (searchData.tier) if (!auction.tier.toLowerCase().includes(searchData.tier)) continue; 51 | if (searchData.category) if (!auction.category.toLowerCase().includes(searchData.category)) continue; 52 | if (searchData.bin) if (auction.bin.toString() != searchData.bin) continue; 53 | if (searchData.user) if (auction.auctioneer != searchData.user) continue; 54 | if (auction.bin) { 55 | if (searchData.lowest_price) if (!(parseInt(searchData.lowest_price) <= auction.starting_bid)) continue; 56 | if (searchData.highest_price) if (!(parseInt(searchData.highest_price) >= auction.starting_bid)) continue; 57 | } else { 58 | if (searchData.lowest_price) if (!(parseInt(searchData.lowest_price) <= auction.highest_bid_amount != 0 ?? !(parseInt(searchData.lowest_price) <= auction.starting_bid))) continue; 59 | if (searchData.highest_price) if (!(parseInt(searchData.highest_price) >= auction.highest_bid_amount != 0 ?? !(parseInt(searchData.lowest_price) <= auction.starting_bid))) continue; 60 | } 61 | auction.item_lore = auction.item_lore.split('\n') 62 | filteredAuctions.push(auction) 63 | } 64 | 65 | if (searchData?.filter) { 66 | // ? TO-DO 67 | // * Sort Auctions 68 | // const highestBid = filteredAuctions.sort((a, b) => b.highest_bid_amount - a.highest_bid_amount); 69 | } 70 | 71 | 72 | return { 73 | status: 200, 74 | found: filteredAuctions.length > 1, 75 | amount: filteredAuctions.length, 76 | filter: searchData, 77 | auctions: filteredAuctions 78 | }; 79 | } 80 | 81 | module.exports = { getAuctionHouse } -------------------------------------------------------------------------------- /API/functions/getAuctions.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const { isUuid } = require("../utils/uuid"); 3 | const getActiveAuctions = require("../stats/auctions.js"); 4 | const config = require('../../config.json'); 5 | const axios = require("axios"); 6 | 7 | async function getAuctions(uuid) { 8 | if (!isUuid(uuid)) { 9 | const mojang_response = (await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`)); 10 | if (mojang_response?.data?.uuid) { 11 | uuid = mojang_response.data.uuid.replace(/-/g, ""); 12 | } 13 | } 14 | 15 | const auctionsRes = (await axios.get(`https://api.hypixel.net/skyblock/auction?key=${config.hypixelAPIkey}&player=${uuid}`)).data; 16 | const auctions = getActiveAuctions(auctionsRes); 17 | 18 | return { status: 200, data: auctions }; 19 | } 20 | 21 | module.exports = { getAuctions }; -------------------------------------------------------------------------------- /API/functions/getBingoProfile.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const { isUuid } = require("../utils/uuid"); 3 | const { parseBingoProfile } = require("../utils/hypixel"); 4 | const config = require('../../config.json'); 5 | const axios = require("axios"); 6 | 7 | async function getBingo(uuid) { 8 | if (!isUuid(uuid)) { 9 | const mojang_response = (await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`)); 10 | if (mojang_response?.data?.uuid) { 11 | uuid = mojang_response.data.uuid.replace(/-/g, ""); 12 | } 13 | } 14 | 15 | const [profileRes, bingoRes] = await Promise.all([ 16 | await axios.get(`https://api.hypixel.net/skyblock/bingo?key=${config.hypixelAPIkey}&uuid=${uuid}`), 17 | await axios.get(`https://api.hypixel.net/resources/skyblock/bingo`) 18 | ]); 19 | 20 | if (bingoRes.data.id !== profileRes.data.events[profileRes.data.events.length - 1].key) return { status: 404, data: `Found no Bingo profiles for a user with a UUID of '${uuid}'` }; 21 | 22 | const profile = parseBingoProfile(profileRes, bingoRes, uuid); 23 | 24 | return { status: 200, data: profile }; 25 | } 26 | 27 | module.exports = { getBingo }; 28 | -------------------------------------------------------------------------------- /API/functions/getCalendar.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const { buildSkyblockCalendar } = require("../constants/calendar"); 3 | 4 | function getSkyblockCalendar() { 5 | try { 6 | const calendar = buildSkyblockCalendar( 7 | null, 8 | Date.now(), 9 | Date.now() + 10710000000, 10 | 1, 11 | false 12 | ); 13 | 14 | return { status: 200, data: calendar } 15 | 16 | } catch (error) { 17 | return ({ status: 404, reason: error }); 18 | } 19 | } 20 | 21 | module.exports = { getSkyblockCalendar }; 22 | -------------------------------------------------------------------------------- /API/functions/getFetchur.js: -------------------------------------------------------------------------------- 1 | const items = require('../constants/fetchur_items') 2 | 3 | function getFetchur() { 4 | try { 5 | let today = new Date(); 6 | today.setHours(today.getHours() - 6); 7 | let day = today.getDate(); 8 | let item; 9 | if (day <= 12) { 10 | item = items[day] 11 | } 12 | item = items[(day % 12)] 13 | return item 14 | } 15 | catch (error) { 16 | console.log(error) 17 | } 18 | } 19 | 20 | module.exports = { getFetchur } -------------------------------------------------------------------------------- /API/functions/getItems.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const { isUuid } = require("../utils/uuid"); 3 | const { parseProfileItems, parseHypixel, parseProfilesItems } = require("../utils/hypixel"); 4 | const config = require('../../config.json'); 5 | const axios = require('axios') 6 | 7 | async function getItems(uuid, profile) { 8 | let profileid 9 | if (profile != undefined) profileid = profile 10 | 11 | if (!isUuid(uuid)) { 12 | const mojang_response = (await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`)); 13 | if (mojang_response?.data?.uuid) { 14 | uuid = mojang_response.data.uuid.replace(/-/g, ""); 15 | } 16 | } 17 | 18 | const [playerRes, profileRes] = await Promise.all([ 19 | await axios.get(`https://api.hypixel.net/player?key=${config.hypixelAPIkey}&uuid=${uuid}`), 20 | await axios.get(`https://api.hypixel.net/skyblock/profiles?key=${config.hypixelAPIkey}&uuid=${uuid}`), 21 | ]); 22 | const player = parseHypixel(playerRes, uuid); 23 | 24 | 25 | if (profile) { 26 | profile = await parseProfileItems(player, profileRes, uuid, profileid); 27 | } else { 28 | profile = await parseProfilesItems(player, profileRes, uuid); 29 | } 30 | 31 | return { status: 200, data: profile }; 32 | }; 33 | 34 | module.exports = { getItems } 35 | -------------------------------------------------------------------------------- /API/functions/getLatestProfile.js: -------------------------------------------------------------------------------- 1 | const { isUuid } = require('../utils/uuid'); 2 | const config = require('../../config.json'); 3 | const { parseHypixel } = require('../utils/hypixel'); 4 | const axios = require('axios') 5 | 6 | async function getLatestProfile(uuid) { 7 | try { 8 | if (!isUuid(uuid)) { 9 | const mojang_response = await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`) 10 | if (mojang_response?.data?.uuid) uuid = mojang_response.data.uuid.replace(/-/g, ''); 11 | } 12 | 13 | 14 | const [playerRes, profileRes] = await Promise.all([ 15 | await axios.get(`https://api.hypixel.net/player?key=${config.hypixelAPIkey}&uuid=${uuid}`), 16 | await axios.get(`https://api.hypixel.net/skyblock/profiles?key=${config.hypixelAPIkey}&uuid=${uuid}`) 17 | ]); 18 | 19 | const player = parseHypixel(playerRes, uuid); 20 | 21 | if (!profileRes.data.profiles) { 22 | return { 23 | status: 404, 24 | reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'.`, 25 | }; 26 | } 27 | 28 | const profileData = profileRes.data.profiles.find((a) => a.selected); 29 | const profile = profileData.members[uuid]; 30 | 31 | return { 32 | status: 200, 33 | profile: profile, 34 | profileData: profileData, 35 | playerRes: playerRes.data, 36 | player: player, 37 | uuid: uuid, 38 | }; 39 | } catch (error) { 40 | return ({ status: 404, reason: error }); 41 | } 42 | } 43 | 44 | function isValidProfile(profileMembers, uuid) { 45 | return profileMembers.hasOwnProperty(uuid) && profileMembers[uuid].last_save != undefined; 46 | } 47 | 48 | module.exports = { getLatestProfile } 49 | -------------------------------------------------------------------------------- /API/functions/getProfile.js: -------------------------------------------------------------------------------- 1 | const { isUuid } = require('../utils/uuid'); 2 | const config = require('../../config.json'); 3 | const axios = require('axios'); 4 | 5 | async function getProfile(uuid, profileid) { 6 | try { 7 | if (!isUuid(uuid)) { 8 | const mojang_response = await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`) 9 | if (mojang_response?.data?.uuid) uuid = mojang_response.data.uuid.replace(/-/g, ''); 10 | } 11 | 12 | const profileRes = await axios.get(`https://api.hypixel.net/skyblock/profiles?key=${config.hypixelAPIkey}&uuid=${uuid}`); 13 | 14 | if (profileRes.data.hasOwnProperty('profiles') && profileRes.data.profiles == null) return ({ status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'` }); 15 | 16 | if (!isUuid(profileid)) { 17 | for (const profile of profileRes.data?.profiles || []) { 18 | if (profile.cute_name.toLowerCase() === profileid.toLowerCase()) profileid = profile.profile_id; 19 | } 20 | } 21 | 22 | const profileData = profileRes.data.profiles.find((a) => a.profile_id === profileid); 23 | 24 | if (!profileData) return ({ status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'` }); 25 | if (!isValidProfile(profileData.members, uuid)) return ({ status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'` }); 26 | 27 | const profile = profileData.members[uuid]; 28 | 29 | return { profile: profile, profileData: profileData} 30 | } catch (error) { 31 | return ({ status: 404, reason: error }); 32 | } 33 | } 34 | 35 | function isValidProfile(profileMembers, uuid) { 36 | return profileMembers.hasOwnProperty(uuid) && profileMembers[uuid].last_save != undefined; 37 | } 38 | 39 | module.exports = { getProfile } -------------------------------------------------------------------------------- /API/functions/getProfileParsed.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const { isUuid } = require('../utils/uuid'); 3 | const { parseHypixel, parseProfile } = require('../utils/hypixel'); 4 | const config = require('../../config.json'); 5 | const axios = require('axios'); 6 | 7 | async function getProfileParsed(uuid, profileid) { 8 | try { 9 | if (!isUuid(uuid)) { 10 | const mojang_response = await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`); 11 | if (mojang_response?.data?.uuid) { 12 | uuid = mojang_response.data.uuid.replace(/-/g, ''); 13 | } 14 | } 15 | 16 | const [playerRes, profileRes] = await Promise.all([ 17 | await axios.get(`https://api.hypixel.net/player?key=${config.hypixelAPIkey}&uuid=${uuid}`), 18 | await axios.get(`https://api.hypixel.net/skyblock/profiles?key=${config.hypixelAPIkey}&uuid=${uuid}`) 19 | ]); 20 | 21 | const player = parseHypixel(playerRes, uuid); 22 | const profile = await parseProfile(player, profileRes, uuid, profileid); 23 | 24 | return profile 25 | } catch (error) { 26 | return ({ status: 404, reason: error }); 27 | } 28 | } 29 | 30 | module.exports = { getProfileParsed } -------------------------------------------------------------------------------- /API/functions/getProfiles.js: -------------------------------------------------------------------------------- 1 | const { isUuid } = require('../utils/uuid'); 2 | const config = require('../../config.json'); 3 | const axios = require('axios'); 4 | 5 | async function getProfiles(uuid) { 6 | try { 7 | if (!isUuid(uuid)) { 8 | const mojang_response = await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`) 9 | if (mojang_response?.data?.uuid) uuid = mojang_response.data.uuid.replace(/-/g, ''); 10 | } 11 | 12 | const profiles = (await axios.get(`https://api.hypixel.net/skyblock/profiles?key=${config.hypixelAPIkey}&uuid=${uuid}`)).data 13 | 14 | return { status: 200, data: profiles } 15 | } catch (error) { 16 | return ({ status: 404, reason: error }); 17 | } 18 | } 19 | 20 | module.exports = { getProfiles } -------------------------------------------------------------------------------- /API/functions/getProfilesParsed.js: -------------------------------------------------------------------------------- 1 | const { isUuid } = require('../utils/uuid'); 2 | const config = require('../../config.json'); 3 | const axios = require('axios'); 4 | const { parseHypixel, parseProfiles } = require('../utils/hypixel'); 5 | 6 | async function getProfiles(uuid) { 7 | try { 8 | if (!isUuid(uuid)) { 9 | const mojang_response = await axios.get(`https://api.ashcon.app/mojang/v2/user/${uuid}`) 10 | if (mojang_response?.data?.uuid) uuid = mojang_response.data.uuid.replace(/-/g, ''); 11 | } 12 | 13 | const [playerRes, profileRes] = await Promise.all([ 14 | await axios.get(`https://api.hypixel.net/player?key=${config.hypixelAPIkey}&uuid=${uuid}`), 15 | await axios.get(`https://api.hypixel.net/skyblock/profiles?key=${config.hypixelAPIkey}&uuid=${uuid}`) 16 | ]); 17 | 18 | const player = parseHypixel(playerRes, uuid); 19 | const profiles = await parseProfiles(player, profileRes, uuid); 20 | 21 | return { status: 200, data: profiles } 22 | } catch (error) { 23 | return ({ status: 404, reason: error }); 24 | } 25 | } 26 | 27 | module.exports = { getProfiles } -------------------------------------------------------------------------------- /API/stats/armor.js: -------------------------------------------------------------------------------- 1 | const { toTimestamp } = require("../constants/maro_networth/src/helper"); 2 | const { decodeData } = require("../utils/nbt"); 3 | 4 | module.exports = async (profile) => { 5 | const armorPieces = ["helmet", "chestplate", "leggings", "boots"]; 6 | const inv_armor = { 7 | helmet: [], 8 | chestplate: [], 9 | leggings: [], 10 | boots: [], 11 | }; 12 | 13 | if (profile.inv_armor?.data) { 14 | const invArmor = ( 15 | await decodeData(Buffer.from(profile.inv_armor?.data, "base64")) 16 | ).i; 17 | for (let i = 0; i < invArmor.length; i++) { 18 | if (invArmor[i].tag?.ExtraAttributes?.rarity_upgrades) { 19 | invArmor[i].tag.ExtraAttributes.recombobulated = 20 | invArmor[i].tag.ExtraAttributes.rarity_upgrades === 1 ? true : false; 21 | delete invArmor[i].tag.ExtraAttributes.rarity_upgrades; 22 | } 23 | 24 | if (invArmor[i].tag?.ExtraAttributes?.modifier) { 25 | invArmor[i].tag.ExtraAttributes.reforge = invArmor[i].tag 26 | .ExtraAttributes.modifier 27 | ? invArmor[i].tag.ExtraAttributes.modifier 28 | : "None"; 29 | delete invArmor[i].tag.ExtraAttributes.modifier; 30 | } 31 | 32 | if (invArmor[i].tag?.ExtraAttributes?.donated_museum) { 33 | invArmor[i].tag.ExtraAttributes.soulbond = 34 | invArmor[i].tag?.ExtraAttributes.donated_museum === 1 ? true : false; 35 | delete invArmor[i].tag.ExtraAttributes.donated_museum; 36 | } 37 | 38 | if (invArmor[i].tag?.ExtraAttributes?.timestamp) { 39 | invArmor[i].tag.ExtraAttributes.timestamp = 40 | toTimestamp(invArmor[i].tag.ExtraAttributes.timestamp) | null; 41 | } 42 | 43 | inv_armor[armorPieces[i]] = invArmor[i]; 44 | } 45 | } 46 | 47 | return inv_armor; 48 | }; 49 | -------------------------------------------------------------------------------- /API/stats/auctions.js: -------------------------------------------------------------------------------- 1 | module.exports = (auctionsData) => { 2 | const auctions = { 3 | totalAuctions: 0, 4 | activeAuctions: 0, 5 | unclaimedAuctions: 0, 6 | soldAuctions: 0, 7 | coinsToClaim: 0, 8 | valueIfAllSold: 0, 9 | active: [], 10 | ended: [], 11 | }; 12 | 13 | for (const auction of auctionsData.auctions) { 14 | if (auction.end >= Date.now()) { 15 | auctions.totalAuctions++; 16 | auctions.activeAuctions++; 17 | auctions.valueIfAllSold += auction.bin 18 | ? auction.starting_bid 19 | : auction.highest_bid_amount; 20 | 21 | if (auction.item_lore.includes("\n")) 22 | auction.item_lore = auction.item_lore.split("\n"); 23 | auctions.active.push(auction); 24 | } else { 25 | if (!auction.claimed) { 26 | auctions.totalAuctions++; 27 | auctions.unclaimedAuctions++; 28 | auctions.coinsToClaim += auction.highest_bid_amount; 29 | auctions.valueIfAllSold += auction.highest_bid_amount; 30 | 31 | if (auction.item_lore.includes("\n")) 32 | auction.item_lore = auction.item_lore.split("\n"); 33 | auctions.ended.push(auction); 34 | } 35 | } 36 | } 37 | 38 | return { 39 | total: auctions.totalAuctions, 40 | activeAuctions: auctions.activeAuctions, 41 | unclaimed: auctions.unclaimedAuctions, 42 | coinsToClaim: auctions.coinsToClaim, 43 | valueIfAllSold: auctions.valueIfAllSold, 44 | active: auctions.active, 45 | ended: auctions.ended, 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /API/stats/bestiary.js: -------------------------------------------------------------------------------- 1 | const { bestiary, bestiaryKills } = require("../constants/bestiary.js"); 2 | 3 | module.exports = (profile) => { 4 | const result = { 5 | level: 0, 6 | categories: {}, 7 | }; 8 | 9 | let totalCollection = 0; 10 | const bestiaryFamilies = {}; 11 | for (const [name, value] of Object.entries(profile.bestiary || {})) { 12 | if (name.startsWith("kills_family_")) { 13 | bestiaryFamilies[name] = value; 14 | } 15 | } 16 | 17 | for (const family of Object.keys(bestiary)) { 18 | result.categories[family] = {}; 19 | for (const mob of bestiary[family].mobs) { 20 | const mobName = mob.lookup.substring(13); 21 | 22 | const boss = mob.boss ? "boss" : "regular"; 23 | 24 | let kills = bestiaryFamilies[mob.lookup] || 0; 25 | let tier = bestiaryKills[boss].filter((k) => k <= kills).length; 26 | let nextTierKills = bestiaryKills[boss][tier]; 27 | let progress = kills / bestiaryKills[boss][tier]; 28 | let levelWithProgress = tier + kills / bestiaryKills[boss][tier]; 29 | let toTier = bestiaryKills[boss][tier] - (kills || 0); 30 | 31 | if (tier >= bestiary[family].max) { 32 | tier = bestiary[family].max; 33 | // setting all data to null since bestiary family is maxed 34 | nextTierKills = null; 35 | toTier = null; 36 | progress = 0; 37 | levelWithProgress = tier; 38 | } 39 | totalCollection += tier; 40 | 41 | result.categories[family][mobName] = { 42 | tier: tier, 43 | nextTier: nextTierKills, 44 | kills: kills, 45 | killsForNext: toTier, 46 | progress: progress, 47 | levelWithProgress: levelWithProgress, 48 | }; 49 | } 50 | } 51 | 52 | result.level = totalCollection / 10; 53 | 54 | return result; 55 | }; 56 | -------------------------------------------------------------------------------- /API/stats/bingo.js: -------------------------------------------------------------------------------- 1 | module.exports = (profile, bingo) => { 2 | profile = Object.values( 3 | profile.events[Object.values(profile.events).length - 1] 4 | ); 5 | const completedGoals = profile[profile.length - 1]; 6 | const bingoGoals = bingo.goals; 7 | const player = []; 8 | const community = []; 9 | 10 | for (const quest of bingoGoals) { 11 | if (!quest.tiers) { 12 | const questData = { 13 | completed: completedGoals.includes(quest.id), 14 | id: quest.id, 15 | name: quest.name, 16 | lore: quest?.lore, 17 | requiredAmount: quest.requiredAmount, 18 | }; 19 | player.push(questData); 20 | } else { 21 | const questData = { 22 | completed: quest.progress > quest.tiers[quest.tiers.length - 1], 23 | id: quest.id, 24 | name: quest.name, 25 | tiers: quest.tiers, 26 | progress: quest.progress, 27 | }; 28 | community.push(questData); 29 | } 30 | } 31 | return { 32 | points: profile[profile.length - 2], 33 | id: bingo.id, 34 | player, 35 | community, 36 | }; 37 | }; 38 | -------------------------------------------------------------------------------- /API/stats/cakebag.js: -------------------------------------------------------------------------------- 1 | const { decodeData, decodeArrayBuffer } = require("../utils/nbt"); 2 | 3 | module.exports = async (profile) => { 4 | if (profile.talisman_bag?.data) { 5 | const cakes = []; 6 | const talisman_bag = ( 7 | await decodeData(Buffer.from(profile.talisman_bag.data, "base64")) 8 | ).i; 9 | 10 | for (const talisman of talisman_bag) { 11 | if ( 12 | talisman?.tag?.display?.Name.includes("New Year Cake Bag") && 13 | talisman?.tag?.ExtraAttributes?.new_year_cake_bag_data 14 | ) { 15 | const bag_contents = await decodeArrayBuffer( 16 | talisman.tag.ExtraAttributes.new_year_cake_bag_data 17 | ); 18 | 19 | for (const cake of bag_contents) { 20 | if (cake?.tag?.ExtraAttributes?.new_years_cake) 21 | cakes.push(cake.tag.ExtraAttributes.new_years_cake); 22 | } 23 | } 24 | } 25 | 26 | return cakes; 27 | } else { 28 | return []; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /API/stats/collections.js: -------------------------------------------------------------------------------- 1 | const collections = require("../data/collections.json"); 2 | 3 | module.exports = (profileData) => { 4 | const players_collections = []; 5 | for (const collection of collections) { 6 | players_collections.push({ 7 | name: collection.name, 8 | id: collection.id, 9 | category: collection.category, 10 | maxTiers: collection.maxTiers, 11 | tier: 0, 12 | amount: 0, 13 | contributions: [], 14 | }); 15 | } 16 | 17 | for (const member of Object.keys(profileData.members)) { 18 | if (profileData.members[member]?.collection) { 19 | for (const collection_id of Object.keys( 20 | profileData.members[member]?.collection 21 | )) { 22 | const collection = players_collections.find( 23 | (a) => a.id === collection_id 24 | ); 25 | if (collection) { 26 | collection.amount += 27 | profileData.members[member].collection[collection_id]; 28 | const contributions = collection.contributions.find( 29 | (a) => a.user === member 30 | ); 31 | if (contributions) { 32 | contributions.amount += 33 | profileData.members[member].collection[collection_id]; 34 | } else { 35 | collection.contributions.push({ 36 | user: member, 37 | amount: profileData.members[member].collection[collection_id], 38 | }); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | 45 | for (const collection of players_collections) { 46 | const found_collection = collections.find((a) => a.id === collection.id); 47 | if (found_collection) { 48 | for (const tier of found_collection.tiers) { 49 | if (tier.amountRequired < collection.amount) 50 | collection.tier = tier.tier; 51 | } 52 | } 53 | } 54 | 55 | return players_collections; 56 | }; 57 | -------------------------------------------------------------------------------- /API/stats/crimson.js: -------------------------------------------------------------------------------- 1 | const crimson = require("../constants/crimson.js"); 2 | 3 | module.exports = (profile) => { 4 | if (profile.nether_island_player_data) { 5 | const crimsonIsland = { 6 | factions: crimson.factions, 7 | matriarch: crimson.matriarch, 8 | kuudra_completed_tiers: crimson.kuudra_completed_tiers, 9 | dojo: crimson.dojo, 10 | }; 11 | 12 | crimsonIsland.factions.selected_faction = 13 | profile.nether_island_player_data.selected_faction; 14 | crimsonIsland.factions.mages_reputation = 15 | profile.nether_island_player_data.mages_reputation; 16 | crimsonIsland.factions.barbarians_reputation = 17 | profile.nether_island_player_data.barbarians_reputation; 18 | crimsonIsland.matriarch.pearls_collected = 19 | profile.nether_island_player_data.matriarch.pearls_collected; 20 | crimsonIsland.matriarch.last_attempt = 21 | profile.nether_island_player_data.matriarch.last_attempt; 22 | 23 | Object.keys( 24 | profile.nether_island_player_data.kuudra_completed_tiers 25 | ).forEach((key) => { 26 | crimsonIsland.kuudra_completed_tiers[key] = 27 | profile.nether_island_player_data.kuudra_completed_tiers[key]; 28 | }); 29 | Object.keys(profile.nether_island_player_data.dojo).forEach((key) => { 30 | crimsonIsland.dojo[key.toUpperCase()] = 31 | profile.nether_island_player_data.dojo[key]; 32 | }); 33 | 34 | return crimsonIsland; 35 | } else { 36 | return { 37 | factions: crimson.factions, 38 | matriarch: crimson.matriarch, 39 | kuudra_completed_tiers: crimson.kuudra_completed_tiers, 40 | dojo: crimson.dojo, 41 | }; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /API/stats/deaths.js: -------------------------------------------------------------------------------- 1 | const mobs = require("../constants/mobs"); 2 | const { titleCase } = require("../constants/functions"); 3 | 4 | module.exports = (profile) => { 5 | const stats = profile?.stats; 6 | if (stats) { 7 | const deaths = []; 8 | 9 | for (const mob in stats) { 10 | if (mob.startsWith("deaths_") && stats[mob] > 0) { 11 | deaths.push({ 12 | name: mob.replace("deaths_", ""), 13 | id: mob.replace("deaths_", ""), 14 | deaths: stats[mob], 15 | }); 16 | } 17 | } 18 | 19 | for (const mob of deaths) { 20 | if (mob in mobs) { 21 | mob.name = mobs[mob]; 22 | } 23 | mob.name = titleCase(mob.name.replace(/_/g, " ")); 24 | } 25 | 26 | return { 27 | totalDeaths: stats.deaths, 28 | types: deaths.sort((a, b) => b.deaths - a.deaths), 29 | }; 30 | } else { 31 | return []; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /API/stats/dungeons.js: -------------------------------------------------------------------------------- 1 | const calcSkill = require("../constants/skills"); 2 | const { titleCase } = require("../constants/functions"); 3 | 4 | module.exports = (player, profile) => { 5 | try { 6 | const dungeons = profile?.dungeons; 7 | const catacombs = dungeons?.dungeon_types.catacombs; 8 | const master_catacombs = dungeons?.dungeon_types.master_catacombs; 9 | 10 | const floors = {}; 11 | const available_floors = Object.keys( 12 | dungeons?.dungeon_types.catacombs.times_played || [] 13 | ); 14 | 15 | for (const floor in available_floors) { 16 | let floor_name = "entrance"; 17 | if (floor != 0) floor_name = `floor_${floor}`; 18 | floors[floor_name] = { 19 | times_played: catacombs?.times_played 20 | ? catacombs?.times_played[floor] || 0 21 | : 0, 22 | completions: catacombs?.tier_completions 23 | ? catacombs?.tier_completions[floor] || 0 24 | : 0, 25 | best_score: { 26 | score: catacombs?.best_score ? catacombs?.best_score[floor] || 0 : 0, 27 | name: getScoreName( 28 | catacombs?.best_score ? catacombs?.best_score[floor] || 0 : 0 29 | ), 30 | }, 31 | fastest: catacombs?.fastest_time 32 | ? catacombs?.fastest_time[floor] || 0 33 | : 0, 34 | fastest_s: catacombs?.fastest_time_s 35 | ? catacombs?.fastest_time_s[floor] || 0 36 | : 0, 37 | fastest_s_plus: catacombs?.fastest_time_s_plus 38 | ? catacombs?.fastest_time_s_plus[floor] || 0 39 | : 0, 40 | mobs_killed: catacombs?.mobs_killed 41 | ? catacombs?.mobs_killed[floor] || 0 42 | : 0, 43 | }; 44 | } 45 | 46 | const master_mode_floors = {}; 47 | 48 | for ( 49 | let i = 1; 50 | i <= dungeons?.dungeon_types.master_catacombs.highest_tier_completed; 51 | i++ 52 | ) { 53 | master_mode_floors[`floor_${i}`] = { 54 | completions: master_catacombs?.tier_completions[i] ?? 0, 55 | best_score: { 56 | score: master_catacombs?.best_score[i] ?? 0, 57 | name: getScoreName(master_catacombs?.best_score[i] ?? 0), 58 | }, 59 | fastest: master_catacombs?.fastest_time[i] ?? 0, 60 | fastest_s: master_catacombs?.fastest_time_s[i] ?? 0, 61 | fastest_s_plus: master_catacombs?.fastest_time_s_plus[i] ?? 0, 62 | mobs_killed: master_catacombs?.mobs_killed[i] ?? 0, 63 | }; 64 | } 65 | 66 | const highest_tier_completed = master_catacombs?.highest_tier_completed 67 | ? `M${master_catacombs?.highest_tier_completed}` 68 | : catacombs?.highest_tier_completed 69 | ? `F${catacombs?.highest_tier_completed}` 70 | : null; 71 | 72 | const perks = { 73 | catacombs_boss_luck: profile?.perks.catacombs_boss_luck ?? 0, 74 | catacombs_looting: profile?.perks.catacombs_looting ?? 0, 75 | catacombs_intelligence: profile?.perks.catacombs_intelligence ?? 0, 76 | catacombs_health: profile?.perks.catacombs_health ?? 0, 77 | catacombs_strength: profile?.perks.catacombs_strength ?? 0, 78 | catacombs_crit_damage: profile?.perks.catacombs_crit_damage ?? 0, 79 | catacombs_defense: profile?.perks.catacombs_defense ?? 0, 80 | permanent_speed: profile?.perks.permanent_defense ?? 0, 81 | permanent_intelligence: profile?.perks.permanent_intelligence ?? 0, 82 | permanent_health: profile?.perks.permanent_health ?? 0, 83 | permanent_defense: profile?.perks.permanent_defense ?? 0, 84 | permanent_strength: profile?.perks.permanent_strength ?? 0, 85 | forbidden_blessing: profile?.perks.forbidden_blessing ?? 0, 86 | revive_stone: profile?.perks.revive_stone ?? 0, 87 | }; 88 | 89 | return { 90 | selected_class: titleCase(dungeons?.selected_dungeon_class), 91 | secrets_found: player.dungeons.secrets, 92 | classes: { 93 | healer: calcSkill( 94 | "dungeoneering", 95 | dungeons?.player_classes.healer.experience || 0 96 | ), 97 | mage: calcSkill( 98 | "dungeoneering", 99 | dungeons?.player_classes.mage.experience || 0 100 | ), 101 | berserk: calcSkill( 102 | "dungeoneering", 103 | dungeons?.player_classes.berserk.experience || 0 104 | ), 105 | archer: calcSkill( 106 | "dungeoneering", 107 | dungeons?.player_classes.archer.experience || 0 108 | ), 109 | tank: calcSkill( 110 | "dungeoneering", 111 | dungeons?.player_classes.tank.experience || 0 112 | ), 113 | }, 114 | catacombs: { 115 | skill: calcSkill( 116 | "dungeoneering", 117 | dungeons?.dungeon_types.catacombs.experience || 0 118 | ), 119 | perks, 120 | highest_tier_completed, 121 | floors, 122 | master_mode_floors, 123 | }, 124 | }; 125 | } catch (error) { 126 | return null; 127 | } 128 | }; 129 | 130 | function getScoreName(score) { 131 | if (score >= 300) return "S+"; 132 | if (score >= 270) return "S"; 133 | if (score >= 240) return "A"; 134 | if (score >= 175) return "B"; 135 | return "C"; 136 | } 137 | -------------------------------------------------------------------------------- /API/stats/enchanting.js: -------------------------------------------------------------------------------- 1 | const getSkills = require("./skills"); 2 | 3 | module.exports = (player, profile) => { 4 | const enchanting = { 5 | simon: {}, 6 | pairings: {}, 7 | numbers: {}, 8 | claims_resets: 0, 9 | claims_resets_timestamp: "None", 10 | }; 11 | if (profile.experimentation) { 12 | enchanting.simon = profile.experimentation.simon; 13 | enchanting.pairings = profile.experimentation.pairings; 14 | enchanting.numbers = profile.experimentation.numbers; 15 | enchanting.claims_resets = profile.experimentation.claims_resets; 16 | enchanting.claims_resets_timestamp = 17 | profile.experimentation.claims_resets_timestamp; 18 | } 19 | 20 | return { 21 | enchanting: getSkills(player, profile).enchanting?.level || 0, 22 | experimentation: enchanting, 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /API/stats/equipment.js: -------------------------------------------------------------------------------- 1 | const { toTimestamp } = require("../constants/maro_networth/src/helper"); 2 | const { decodeData } = require("../utils/nbt"); 3 | 4 | module.exports = async (profile) => { 5 | const equipment_contents = { 6 | necklace: [], 7 | cloak: [], 8 | belt: [], 9 | gloves: [], 10 | }; 11 | 12 | if (profile.equippment_contents?.data) { 13 | const equipment = ( 14 | await decodeData(Buffer.from(profile.equippment_contents?.data, "base64")) 15 | ).i; 16 | const equipmentPieces = ["necklace", "cloak", "belt", "gloves"]; 17 | for (let i = 0; i < equipment.length; i++) { 18 | if (equipment[i].tag?.ExtraAttributes?.rarity_upgrades) { 19 | equipment[i].tag.ExtraAttributes.recombobulated = 20 | equipment[i].tag.ExtraAttributes.rarity_upgrades === 1 ? true : false; 21 | delete equipment[i].tag.ExtraAttributes.rarity_upgrades; 22 | } 23 | 24 | if (equipment[i].tag?.ExtraAttributes?.modifier) { 25 | equipment[i].tag.ExtraAttributes.reforge = equipment[i].tag 26 | .ExtraAttributes.modifier 27 | ? equipment[i].tag.ExtraAttributes.modifier 28 | : "None"; 29 | delete equipment[i].tag.ExtraAttributes.modifier; 30 | } 31 | 32 | if (equipment[i].tag?.ExtraAttributes?.donated_museum) { 33 | equipment[i].tag.ExtraAttributes.soulbond = 34 | equipment[i].tag?.ExtraAttributes.donated_museum === 1 ? true : false; 35 | delete equipment[i].tag.ExtraAttributes.donated_museum; 36 | } 37 | 38 | if (equipment[i].tag?.ExtraAttributes?.timestamp) { 39 | equipment[i].tag.ExtraAttributes.timestamp = 40 | toTimestamp(equipment[i].tag.ExtraAttributes.timestamp) | null; 41 | } 42 | 43 | equipment_contents[equipmentPieces[i]] = equipment[i]; 44 | } 45 | } 46 | 47 | return equipment_contents; 48 | }; 49 | -------------------------------------------------------------------------------- /API/stats/farming.js: -------------------------------------------------------------------------------- 1 | const constants = require("../constants/farming"); 2 | const getSkills = require("./skills"); 3 | 4 | module.exports = (player, profile) => { 5 | const jacob = { 6 | talked: profile.jacob2?.talked || false, 7 | }; 8 | const trapper_quest = { 9 | last_task_time: "None", 10 | pelt_count: 0, 11 | }; 12 | 13 | if (profile.trapper_quest) { 14 | trapper_quest.last_task_time = profile.trapper_quest?.last_task_time 15 | ? profile.trapper_quest?.last_task_time 16 | : "None"; 17 | trapper_quest.pelt_count = profile.trapper_quest.pelt_count ?? 0; 18 | } 19 | 20 | if (jacob.talked) { 21 | jacob.medals = { 22 | bronze: profile.jacob2.medals_inv.bronze || 0, 23 | silver: profile.jacob2.medals_inv.silver || 0, 24 | gold: profile.jacob2.medals_inv.gold || 0, 25 | }; 26 | jacob.total_badges = { 27 | bronze: 0, 28 | silver: 0, 29 | gold: 0, 30 | }; 31 | jacob.perks = { 32 | double_drops: profile.jacob2.perks?.double_drops || 0, 33 | farming_level_cap: profile.jacob2.perks?.farming_level_cap || 0, 34 | }; 35 | jacob.unique_golds = profile.jacob2.unique_golds2?.length || 0; 36 | jacob.crops = {}; 37 | 38 | for (const crop in constants.jacob_crops) { 39 | jacob.crops[crop] = constants.jacob_crops[crop]; 40 | 41 | Object.assign(jacob.crops[crop], { 42 | participated: false, 43 | unique_gold: profile.jacob2.unique_golds2?.includes(crop) || false, 44 | contests: 0, 45 | personal_best: 0, 46 | badges: { 47 | gold: 0, 48 | silver: 0, 49 | bronze: 0, 50 | }, 51 | }); 52 | } 53 | 54 | const contests = { 55 | attended_contests: 0, 56 | all_contests: [], 57 | }; 58 | 59 | for (const contest_id in profile.jacob2.contests) { 60 | const data = profile.jacob2.contests[contest_id]; 61 | const contest_name = contest_id.split(":"); 62 | const date = `${contest_name[1]}_${contest_name[0]}`; 63 | const crop = contest_name.slice(2).join(":"); 64 | 65 | jacob.crops[crop].contests++; 66 | jacob.crops[crop].participated = true; 67 | if (data.collected > jacob.crops[crop].personal_best) 68 | jacob.crops[crop].personal_best = data.collected; 69 | 70 | const contest = { 71 | date: date, 72 | crop: crop, 73 | collected: data.collected, 74 | claimed: data.claimed_rewards || false, 75 | medal: null, 76 | }; 77 | 78 | const placing = {}; 79 | if (contest.claimed) { 80 | placing.position = data.claimed_position || 0; 81 | placing.percentage = 82 | (data.claimed_position / data.claimed_participants) * 100; 83 | 84 | if (placing.percentage <= 5) { 85 | contest.medal = "gold"; 86 | jacob.total_badges.gold++; 87 | jacob.crops[crop].badges.gold++; 88 | } else if (placing.percentage <= 25) { 89 | contest.medal = "silver"; 90 | jacob.total_badges.silver++; 91 | jacob.crops[crop].badges.silver++; 92 | } else if (placing.percentage <= 60) { 93 | contest.medal = "bronze"; 94 | jacob.total_badges.bronze++; 95 | jacob.crops[crop].badges.bronze++; 96 | } 97 | } 98 | 99 | contest.placing = placing; 100 | contests.attended_contests++; 101 | contests.all_contests.push(contest); 102 | } 103 | 104 | jacob.contests = contests; 105 | } 106 | 107 | return { 108 | farming: getSkills(player, profile).farming?.level || 0, 109 | trapper_quest, 110 | jacob, 111 | }; 112 | }; 113 | -------------------------------------------------------------------------------- /API/stats/hypixelLevel.js: -------------------------------------------------------------------------------- 1 | // CREDIT: https://github.com/slothpixel/core/ (util/calculateLevel.js) 2 | module.exports = (player) => { 3 | const BASE = 10000; 4 | const GROWTH = 2500; 5 | 6 | const REVERSE_PQ_PREFIX = -(BASE - 0.5 * GROWTH) / GROWTH; 7 | const REVERSE_CONST = REVERSE_PQ_PREFIX * REVERSE_PQ_PREFIX; 8 | const GROWTH_DIVIDES_2 = 2 / GROWTH; 9 | 10 | const experience = player?.networkExp || 0; 11 | 12 | const level = 13 | experience <= 1 14 | ? 1 15 | : 1 + 16 | REVERSE_PQ_PREFIX + 17 | Math.sqrt(REVERSE_CONST + GROWTH_DIVIDES_2 * experience); 18 | return level; 19 | }; 20 | -------------------------------------------------------------------------------- /API/stats/kills.js: -------------------------------------------------------------------------------- 1 | const mobs = require("../constants/mobs"); 2 | const { titleCase } = require("../constants/functions"); 3 | 4 | module.exports = (profile) => { 5 | const stats = profile?.stats; 6 | if (stats) { 7 | const kills = []; 8 | 9 | for (const mob in stats) { 10 | if (mob.startsWith("kills_") && stats[mob] > 0) { 11 | kills.push({ 12 | name: mob.replace("kills_", ""), 13 | id: mob.replace("kills_", ""), 14 | kills: stats[mob], 15 | }); 16 | } 17 | } 18 | 19 | for (const mob of kills) { 20 | if (mob in mobs) { 21 | mob.name = mobs[mob]; 22 | } 23 | mob.name = titleCase(mob.name.replace(/_/g, " ")); 24 | } 25 | 26 | return { 27 | totalKills: stats.kills, 28 | types: kills.sort((a, b) => b.kills - a.kills), 29 | }; 30 | } else { 31 | return []; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /API/stats/milestones.js: -------------------------------------------------------------------------------- 1 | const milestones = require("../constants/milestones"); 2 | 3 | module.exports = function getMilestones(profile) { 4 | const dolphin = getCurrentPet( 5 | "dolphin", 6 | profile.stats.pet_milestone_sea_creatures_killed || 0 7 | ); 8 | const rock = getCurrentPet( 9 | "rock", 10 | profile.stats.pet_milestone_ores_mined || 0 11 | ); 12 | 13 | return { 14 | fishing: { 15 | current_pet: milestones.rarities[dolphin.level - 1], 16 | next_pet: dolphin.xpForNext, 17 | sea_creatures_killed: dolphin.stats, 18 | nextRarity: dolphin.left, 19 | progress: dolphin.progress, 20 | }, 21 | mining: { 22 | current_pet: milestones.rarities[rock.level - 1], 23 | next_pet: rock.xpForNext, 24 | ores_mined: rock.stats, 25 | nextRarity: rock.left, 26 | progress: rock.progress, 27 | }, 28 | }; 29 | }; 30 | 31 | //CREDIT: https://github.com/SkyCrypt/SkyCryptWebsite (Modified) 32 | function getCurrentPet(pet, stats) { 33 | let level = 0; 34 | let xpForNext = 0; 35 | let progress = 0; 36 | 37 | for (let i = 0; i < 5; i++) { 38 | if (milestones[pet][i] < stats) level = i + 1; 39 | } 40 | 41 | if (level < 5) { 42 | xpForNext = Math.ceil(milestones[pet][level]); 43 | } 44 | 45 | let left = xpForNext - stats > 0 ? xpForNext - stats : 0; 46 | 47 | progress = level >= 5 ? 0 : Math.max(0, Math.min(stats / xpForNext, 1)); 48 | return { 49 | stats, 50 | left, 51 | level, 52 | xpForNext, 53 | progress, 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /API/stats/mining.js: -------------------------------------------------------------------------------- 1 | const { getHotM, perks, forgeItemTimes } = require("../constants/mining"); 2 | const { toFixed, titleCase } = require("../constants/functions"); 3 | const getSkills = require("./skills"); 4 | 5 | module.exports = (player, profile) => { 6 | const mining_stats = profile?.mining_core; 7 | const player_perks = []; 8 | const disabled_perks = []; 9 | 10 | for (const perk in Object.keys(mining_stats?.nodes || {}) || []) { 11 | if (!Object.keys(mining_stats.nodes)[perk].startsWith("toggle_")) { 12 | const currentPerk = perks[Object.keys(mining_stats.nodes)[perk]]; 13 | player_perks.push({ 14 | name: currentPerk.name, 15 | id: currentPerk.id, 16 | level: Object.values(mining_stats.nodes)[perk], 17 | maxLevel: currentPerk.max, 18 | }); 19 | } else { 20 | disabled_perks.push(Object.keys(mining_stats.nodes)[perk].substring(7)); 21 | } 22 | } 23 | 24 | for (let statue of mining_stats?.biomes?.dwarven?.statues_placed || []) { 25 | statue = titleCase(statue); 26 | } 27 | 28 | for (let part of mining_stats?.biomes?.precursor?.parts_delivered || []) { 29 | part = titleCase(part, true); 30 | } 31 | 32 | //Check if player has the "Quick Forge" perk in the Heart of the Mountain and change the duration of the items in the forge accordingly 33 | if (mining_stats?.nodes?.quick_forge) { 34 | for (const item of Object.keys(forgeItemTimes)) { 35 | const lessForgingTime = 36 | miningapi.mining_core.nodes.forge_time <= 19 37 | ? 0.1 + miningapi.mining_core.nodes.forge_time * 0.005 38 | : 0.3; 39 | forgeItemTimes[item].duration = 40 | forgeItemTimes[item].duration - 41 | forgeItemTimes[item].duration * lessForgingTime; 42 | } 43 | } 44 | 45 | //Forge Display 46 | const forge_api = profile.forge?.forge_processes || []; 47 | const forge = []; 48 | 49 | for (const forge_types of Object.values(forge_api)) { 50 | for (const item of Object.values(forge_types)) { 51 | if (item?.id === "PET") item.id = "AMMONITE"; 52 | forge.push({ 53 | slot: item.slot, 54 | item: forgeItemTimes[item.id]?.name || "Unknown", 55 | id: item.id === "AMMONITE" ? "PET" : item.id, 56 | ending: Number( 57 | (item.startTime + forgeItemTimes[item.id]?.duration || 0).toFixed() 58 | ), 59 | ended: 60 | item.startTime + forgeItemTimes[item.id]?.duration || 0 < Date.now() 61 | ? true 62 | : false, 63 | }); 64 | } 65 | } 66 | 67 | return { 68 | mining: getSkills(player, profile).mining?.level || 0, 69 | mithril_powder: { 70 | current: mining_stats?.powder_mithril_total || 0, 71 | total: 72 | (mining_stats?.powder_mithril_total || 0) + 73 | (mining_stats?.powder_spent_mithril || 0), 74 | }, 75 | gemstone_powder: { 76 | current: mining_stats?.powder_gemstone_total || 0, 77 | total: 78 | (mining_stats?.powder_gemstone_total || 0) + 79 | (mining_stats?.powder_spent_gemstone || 0), 80 | }, 81 | hotM_tree: { 82 | tokens: { 83 | current: mining_stats?.tokens || 0, 84 | total: mining_stats?.tokens || 0 + mining_stats?.tokens_spent || 0, 85 | }, 86 | level: mining_stats?.experience 87 | ? Number(toFixed(getHotM(mining_stats?.experience))) 88 | : 0, 89 | perks: player_perks, 90 | disabled_perks: disabled_perks, 91 | last_reset: mining_stats?.last_reset || null, 92 | pickaxe_ability: 93 | perks[mining_stats?.selected_pickaxe_ability]?.name || null, 94 | }, 95 | crystal_hollows: { 96 | last_pass: mining_stats?.greater_mines_last_access || null, 97 | crystals: [ 98 | { 99 | name: "Jade Crystal", 100 | id: "jade_crystal", 101 | total_placed: mining_stats?.crystals?.jade_crystal?.total_placed || 0, 102 | statues_placed: mining_stats?.biomes?.dwarven?.statues_placed || [], 103 | state: titleCase( 104 | mining_stats?.crystals?.jade_crystal?.state || "Not Found", 105 | true 106 | ), 107 | }, 108 | { 109 | name: "Amber Crystal", 110 | total_placed: 111 | mining_stats?.crystals?.amber_crystal?.total_placed || 0, 112 | king_quests_completed: 113 | mining_stats?.biomes?.goblin?.king_quests_completed || 0, 114 | state: titleCase( 115 | mining_stats?.crystals?.amber_crystal?.state || "Not Found", 116 | true 117 | ), 118 | }, 119 | { 120 | name: "Sapphire Crystal", 121 | total_placed: 122 | mining_stats?.crystals?.sapphire_crystal?.total_placed || 0, 123 | parts_delivered: 124 | mining_stats?.biomes?.precursor?.parts_delivered || [], 125 | state: titleCase( 126 | mining_stats?.crystals?.sapphire_crystal?.state || "Not Found", 127 | true 128 | ), 129 | }, 130 | { 131 | name: "Amethyst Crystal", 132 | total_placed: 133 | mining_stats?.crystals?.amethyst_crystal?.total_placed || 0, 134 | state: titleCase( 135 | mining_stats?.crystals?.amethyst_crystal?.state || "Not Found", 136 | true 137 | ), 138 | }, 139 | { 140 | name: "Topaz Crystal", 141 | total_placed: 142 | mining_stats?.crystals?.topaz_crystal?.total_placed || 0, 143 | state: titleCase( 144 | mining_stats?.crystals?.topaz_crystal?.state || "Not Found", 145 | true 146 | ), 147 | }, 148 | { 149 | name: "Jasper Crystal", 150 | total_placed: 151 | mining_stats?.crystals?.jasper_crystal?.total_placed || 0, 152 | state: titleCase( 153 | mining_stats?.crystals?.jasper_crystal?.state || "Not Found", 154 | true 155 | ), 156 | }, 157 | { 158 | name: "Ruby Crystal", 159 | total_placed: mining_stats?.crystals?.ruby_crystal?.total_placed || 0, 160 | state: titleCase( 161 | mining_stats?.crystals?.ruby_crystal?.state || "Not Found", 162 | true 163 | ), 164 | }, 165 | ], 166 | }, 167 | forge, 168 | }; 169 | }; 170 | -------------------------------------------------------------------------------- /API/stats/minions.js: -------------------------------------------------------------------------------- 1 | const minion_slots = require("../constants/minion_slots"); 2 | 3 | module.exports = (profile) => { 4 | const constants = require("../constants/minions"); 5 | 6 | let unlocked_minions = {}; 7 | for (const member of Object.keys(profile.members)) { 8 | const minions = profile.members[member]?.crafted_generators; 9 | if (minions) { 10 | for (const minion of minions) { 11 | const minion_level = Number(minion.replace(/\D/g, "")); 12 | const minion_name = minion.substring( 13 | 0, 14 | minion.length - minion_level.toString().length - 1 15 | ); 16 | if ( 17 | unlocked_minions[minion_name] < minion_level || 18 | !(minion_name in unlocked_minions) || 19 | unlocked_minions[minion_name]?.tier < minion_level 20 | ) { 21 | let found_minion = constants[minion_name]; 22 | if (found_minion) { 23 | found_minion.tier = minion_level; 24 | unlocked_minions[minion_name] = found_minion; 25 | } 26 | } 27 | } 28 | } 29 | } 30 | unlocked_minions = Object.values(unlocked_minions); 31 | 32 | let uniqueMinions = 0; 33 | for (const uniques of unlocked_minions) { 34 | uniqueMinions += uniques.tier; 35 | } 36 | 37 | let slots = 5; 38 | let nextSlot = 0; 39 | for (let i = 0; i < Object.keys(minion_slots).length; i++) { 40 | if (uniqueMinions > Object.keys(minion_slots)[i]) { 41 | slots = i + 5; 42 | nextSlot = Object.keys(minion_slots)[i + 1] - uniqueMinions; 43 | } 44 | } 45 | 46 | let bonus_slots = 0; 47 | const community_upgrades = profile.community_upgrades?.upgrade_states || 0; 48 | for (let i = 0; i < community_upgrades.length; i++) { 49 | if ( 50 | community_upgrades[i].upgrade === "minion_slots" && 51 | community_upgrades[i].tier > bonus_slots 52 | ) { 53 | bonus_slots = community_upgrades[i].tier; 54 | } 55 | } 56 | 57 | return { 58 | uniqueMinions, 59 | minionSlots: slots, 60 | bonusSlots: bonus_slots, 61 | nextSlot, 62 | unlockedMinions: unlocked_minions, 63 | }; 64 | }; 65 | -------------------------------------------------------------------------------- /API/stats/missing.js: -------------------------------------------------------------------------------- 1 | const { decodeData } = require("../utils/nbt"); 2 | const getMissingTalismans = require("../constants/missing"); 3 | const prices = require("../data/prices.json"); 4 | 5 | module.exports = async (profile) => { 6 | if (profile.talisman_bag?.data && profile.inv_contents?.data) { 7 | let talismans = ( 8 | await decodeData(Buffer.from(profile.talisman_bag.data, "base64")) 9 | ).i; 10 | const inventory = ( 11 | await decodeData(Buffer.from(profile.inv_contents.data, "base64")) 12 | ).i; 13 | talismans = talismans.concat(inventory); 14 | 15 | let talisman_ids = []; 16 | for (const talisman of talismans) { 17 | if (talisman?.tag?.ExtraAttributes?.id) 18 | talisman_ids.push(talisman.tag.ExtraAttributes.id); 19 | } 20 | let missing = { 21 | talismans: getMissingTalismans(talisman_ids), 22 | maxTalismans: getMissingTalismans(talisman_ids, "max"), 23 | }; 24 | 25 | for (const talisman of missing.talismans) { 26 | talisman.price = getPrice(talisman.id) || null; 27 | } 28 | for (const talisman of missing.maxTalismans) { 29 | talisman.price = getPrice(talisman.id) || null; 30 | } 31 | missing.talismans.sort((a, b) => a.price - b.price); 32 | missing.maxTalismans.sort((a, b) => a.price - b.price); 33 | 34 | return missing; 35 | } else { 36 | return null; 37 | } 38 | }; 39 | 40 | function getPrice(name) { 41 | name = name.toLowerCase(); 42 | return prices[name]?.price || null; 43 | } 44 | -------------------------------------------------------------------------------- /API/stats/networth.js: -------------------------------------------------------------------------------- 1 | const itemGenerator = require("../constants/maro_networth/generators/itemGenerator"); 2 | const networthGenerator = require("../constants/maro_networth/generators/networthGenerator"); 3 | const config = require("../config.json"); 4 | const fs = require("fs"); 5 | 6 | let prices = {}; 7 | 8 | const retrievePrices = async function () { 9 | prices = JSON.parse(fs.readFileSync("API/data/prices.json")); 10 | if (config.prices.refreshMessage) 11 | console.log("Prices retrieved successfully"); 12 | }; 13 | 14 | retrievePrices(); 15 | setInterval(() => retrievePrices(), 60 * 10000); 16 | 17 | module.exports = async (profile, profileData) => { 18 | const bank = profileData?.banking?.balance || 0; 19 | const items = await itemGenerator.getItems(profile, prices); 20 | if (items.no_inventory) return { no_inventory: true }; 21 | 22 | const networth = await networthGenerator.getNetworth(items, profile, bank); 23 | if (Object.keys(networth.categories).length < 0) 24 | return { no_inventory: true }; 25 | 26 | return { 27 | total_networth: networth.networth, 28 | unsoulbound_networth: networth.unsoulbound_networth, 29 | purse: networth.purse, 30 | bank: networth.bank, 31 | personal_bank: networth.personal_bank, 32 | types: networth.categories, 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /API/stats/rank.js: -------------------------------------------------------------------------------- 1 | // CREDIT: https://github.com/slothpixel/core (modified) 2 | 3 | const colorToCode = { 4 | BLACK: "0", 5 | DARK_BLUE: "1", 6 | DARK_GREEN: "2", 7 | DARK_AQUA: "3", 8 | DARK_RED: "4", 9 | DARK_PURPLE: "5", 10 | GOLD: "6", 11 | GRAY: "7", 12 | DARK_GRAY: "8", 13 | BLUE: "9", 14 | GREEM: "a", 15 | AQUA: "b", 16 | RED: "c", 17 | LIGHT_PURPLE: "d", 18 | YELLOW: "e", 19 | WHITE: "f", 20 | RESET: "r", 21 | }; 22 | 23 | module.exports = (player) => { 24 | const rank = getPlayerRank( 25 | player.rank, 26 | player.packageRank, 27 | player.newPackageRank, 28 | player.monthlyPackageRank 29 | ); 30 | const plusColor = `§${colorToCode[player.rankPlusColor || "RED"]}`; 31 | const plusPlusColor = `§${colorToCode[player.monthlyRankColor || "GOLD"]}`; 32 | const prefix = player.prefix 33 | ? player.prefix.replace(/§/g, "§").replace(/§/g, "&") 34 | : null; 35 | 36 | return generateFormattedRank(rank, plusColor, plusPlusColor, prefix); 37 | }; 38 | 39 | function getPlayerRank(rank, packageRank, newPackageRank, monthlyPackageRank) { 40 | let playerRank = 41 | rank === "NORMAL" 42 | ? newPackageRank || packageRank || null 43 | : rank || newPackageRank || packageRank || null; 44 | if (playerRank === "MVP_PLUS" && monthlyPackageRank === "SUPERSTAR") 45 | playerRank = "MVP_PLUS_PLUS"; 46 | if (rank === "NONE") playerRank = null; 47 | return playerRank; 48 | } 49 | 50 | function generateFormattedRank(rank, plusColor, plusPlusColor, prefix) { 51 | if (prefix) return prefix; 52 | 53 | const ranks = { 54 | VIP: "§a[VIP]", 55 | VIP_PLUS: "§a[VIP§6+§a]", 56 | MVP: "§b[MVP]", 57 | MVP_PLUS: `§b[MVP${plusColor}+§b]`, 58 | MVP_PLUS_PLUS: `${plusPlusColor}[MVP${plusColor}++${plusPlusColor}]`, 59 | HELPER: "§9[HELPER]", 60 | MODERATOR: "§2[MOD]", 61 | GAME_MASTER: "§2[GM]", 62 | ADMIN: "§c[ADMIN]", 63 | YOUTUBER: "§c[§fYOUTUBE§c]", 64 | }; 65 | 66 | return ranks[rank] || "§7"; 67 | } 68 | -------------------------------------------------------------------------------- /API/stats/skills.js: -------------------------------------------------------------------------------- 1 | const calcSkill = require("../constants/skills"); 2 | 3 | module.exports = function getSkills(player, profile) { 4 | const skill_experience = { 5 | farming: profile?.experience_skill_farming || 0, 6 | mining: profile?.experience_skill_mining || 0, 7 | combat: profile?.experience_skill_combat || 0, 8 | foraging: profile?.experience_skill_foraging || 0, 9 | fishing: profile?.experience_skill_fishing || 0, 10 | enchanting: profile?.experience_skill_enchanting || 0, 11 | alchemy: profile?.experience_skill_alchemy || 0, 12 | carpentry: profile?.experience_skill_carpentry || 0, 13 | runecrafting: profile?.experience_skill_runecrafting || 0, 14 | social: profile?.experience_skill_social2 || 0, 15 | taming: profile?.experience_skill_taming || 0, 16 | }; 17 | 18 | return { 19 | farming: calcSkill("farming", skill_experience["farming"]), 20 | mining: calcSkill("mining", skill_experience["mining"]), 21 | combat: calcSkill("combat", skill_experience["combat"]), 22 | foraging: calcSkill("foraging", skill_experience["foraging"]), 23 | fishing: calcSkill("fishing", skill_experience["fishing"]), 24 | enchanting: calcSkill("enchanting", skill_experience["enchanting"]), 25 | alchemy: calcSkill("alchemy", skill_experience["alchemy"]), 26 | carpentry: calcSkill("carpentry", skill_experience["carpentry"]), 27 | runecrafting: calcSkill("runecrafting", skill_experience["runecrafting"]), 28 | social: calcSkill("social", skill_experience["social"]), 29 | taming: calcSkill("taming", skill_experience["taming"]), 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /API/stats/slayer.js: -------------------------------------------------------------------------------- 1 | const xp_tables = require("../constants/xp_tables"); 2 | 3 | module.exports = (profile) => { 4 | function getSlayer(slayer) { 5 | const slayers = profile?.slayer_bosses?.[slayer]; 6 | const experience = slayers?.xp || 0; 7 | if (experience <= 0) { 8 | return { 9 | xp: 0, 10 | level: 0, 11 | xpForNext: xp_tables.slayer[slayer][0], 12 | progress: 0, 13 | kills: {}, 14 | }; 15 | } 16 | 17 | let level = 0; 18 | let xpForNext = 0; 19 | let progress = 0; 20 | let maxLevel = 9; 21 | 22 | for (let i = 0; i < xp_tables.slayer[slayer].length; i++) { 23 | if (xp_tables.slayer[slayer][i] <= experience) { 24 | level = i + 1; 25 | } 26 | } 27 | 28 | if (level < maxLevel) { 29 | xpForNext = Math.ceil(xp_tables.slayer[slayer][level]); 30 | } 31 | 32 | progress = 33 | level >= maxLevel ? 0 : Math.max(0, Math.min(experience / xpForNext, 1)); 34 | 35 | const kills = {}; 36 | let total = 0; 37 | if (slayer === "zombie") kills[5] = 0; 38 | for (let i = 0; i < Object.keys(slayers).length; i++) { 39 | if (Object.keys(slayers)[i].startsWith("boss_kills_tier_")) { 40 | // This indeed looks pretty bad I know... (kills[boss tier number]) 41 | total += Object.values(slayers)[i]; 42 | kills[ 43 | Number( 44 | Object.keys(slayers)[i].charAt(Object.keys(slayers)[i].length - 1) 45 | ) + 1 46 | ] = Object.values(slayers)[i]; 47 | } 48 | } 49 | 50 | return { 51 | xp: experience, 52 | totalKills: total, 53 | level, 54 | xpForNext, 55 | progress, 56 | kills, 57 | }; 58 | } 59 | 60 | return { 61 | zombie: getSlayer("zombie"), 62 | spider: getSlayer("spider"), 63 | wolf: getSlayer("wolf"), 64 | enderman: getSlayer("enderman"), 65 | blaze: getSlayer("blaze"), 66 | }; 67 | }; 68 | -------------------------------------------------------------------------------- /API/stats/talismans.js: -------------------------------------------------------------------------------- 1 | const { decodeData } = require("../utils/nbt"); 2 | const { capitalize } = require("../constants/functions"); 3 | const { talismans: allTalismans } = require("../constants/talismans"); 4 | 5 | module.exports = async (profile) => { 6 | if (profile.talisman_bag?.data) { 7 | const talismans = { 8 | talismanBagUpgrades: 9 | profile?.accessory_bag_storage?.bag_upgrades_purchased, 10 | currentReforge: profile?.accessory_bag_storage?.selected_power, 11 | unlockedReforges: profile?.accessory_bag_storage?.unlocked_powers, 12 | tuningsSlots: 13 | profile?.accessory_bag_storage?.tuning?.highest_unlocked_slot, 14 | tunings: profile?.accessory_bag_storage?.tuning, 15 | common: [], 16 | uncommon: [], 17 | rare: [], 18 | epic: [], 19 | legendary: [], 20 | mythic: [], 21 | special: [], 22 | very: [], 23 | }; 24 | delete talismans.tunings.highest_unlocked_slot; 25 | const talisman_bag = ( 26 | await decodeData(Buffer.from(profile.talisman_bag.data, "base64")) 27 | ).i; 28 | 29 | for (const talisman of talisman_bag) { 30 | if (talisman.tag?.display.Name && talisman.tag?.ExtraAttributes) { 31 | let name = 32 | talisman.tag?.display.Name.replace(/\u00A7[0-9A-FK-OR]/gi, "") || 33 | null; 34 | const reforge = capitalize( 35 | talisman.tag?.ExtraAttributes.modifier || null 36 | ); 37 | if (reforge) name = name.substring(name.indexOf(" ") + 1); 38 | const isRecombed = 39 | talisman.tag?.ExtraAttributes.rarity_upgrades > 0 40 | ? true 41 | : false || false; 42 | let new_talisman = {}; 43 | 44 | if ( 45 | getRarity(talisman.tag?.display.Lore) != "common" && 46 | getRarity(talisman.tag?.display.Lore) != "uncommon" && 47 | getRarity(talisman.tag?.display.Lore) != "rare" && 48 | getRarity(talisman.tag?.display.Lore) != "epic" 49 | ) { 50 | new_talisman = { 51 | name: allTalismans[talisman.tag?.ExtraAttributes.id]?.name || name, 52 | id: talisman.tag?.ExtraAttributes.id || null, 53 | reforge: reforge ?? "None", 54 | rarity: getRarity(talisman.tag?.display.Lore).toUpperCase(), 55 | recombobulated: isRecombed, 56 | enrichment: 57 | talisman.tag?.ExtraAttributes?.talisman_enrichment ?? "None", 58 | }; 59 | } else { 60 | new_talisman = { 61 | name: allTalismans[talisman.tag?.ExtraAttributes.id]?.name || name, 62 | id: talisman.tag?.ExtraAttributes.id || null, 63 | reforge: reforge ?? "None", 64 | rarity: getRarity(talisman.tag?.display.Lore).toUpperCase(), 65 | recombobulated: isRecombed, 66 | }; 67 | } 68 | if (talismans[getRarity(talisman.tag?.display.Lore)]) 69 | talismans[getRarity(talisman.tag?.display.Lore)].push(new_talisman); 70 | else talismans[getRarity(talisman.tag?.display.Lore)] = new_talisman; 71 | } 72 | } 73 | return talismans; 74 | } else { 75 | return { 76 | common: [], 77 | uncommon: [], 78 | rare: [], 79 | epic: [], 80 | legendary: [], 81 | mythic: [], 82 | }; 83 | } 84 | }; 85 | 86 | function getRarity(lore) { 87 | let last_index = lore[lore.length - 1]; 88 | last_index = last_index.replace(/\u00A7[0-9A-FK-OR]/gi, "").toLowerCase(); 89 | if (last_index.startsWith("a ")) last_index = last_index.substring(2); 90 | last_index = last_index.substring(0, last_index.indexOf(" ")); 91 | return last_index; 92 | } 93 | -------------------------------------------------------------------------------- /API/stats/trophyFishing.js: -------------------------------------------------------------------------------- 1 | const { allTrophyFish } = require("../constants/trophyFishing.js"); 2 | 3 | module.exports = (profile) => { 4 | if (profile.trophy_fish) { 5 | const trophyFish = { 6 | total_caught: 0, 7 | rewards: [], 8 | fish: allTrophyFish, 9 | }; 10 | trophyFish.rewards = profile.trophy_fish.rewards; 11 | trophyFish.total_caught = profile.trophy_fish.total_caught; 12 | Object.keys(profile.trophy_fish).forEach((key) => { 13 | if (key == "rewards" || key == "total_caught") return; 14 | trophyFish.fish[key.toUpperCase()] = profile.trophy_fish[key]; 15 | }); 16 | 17 | return trophyFish; 18 | } else { 19 | return { 20 | rewards: [], 21 | total_caught: 0, 22 | fish: allTrophyFish, 23 | }; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /API/utils/hypixel.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const getRank = require("../stats/rank"); 3 | const getHypixelLevel = require("../stats/hypixelLevel"); 4 | const getSkills = require("../stats/skills"); 5 | const getMilestones = require("../stats/milestones"); 6 | const getCakebag = require("../stats/cakebag"); 7 | const getMinions = require("../stats/minions"); 8 | const getSlayer = require("../stats/slayer"); 9 | const getKills = require("../stats/kills"); 10 | const getDeaths = require("../stats/deaths"); 11 | const getPets = require("../stats/pets"); 12 | const getBingo = require("../stats/bingo"); 13 | const getEquipment = require("../stats/equipment"); 14 | const getArmor = require("../stats/armor"); 15 | const getTalismans = require("../stats/talismans"); 16 | const getCollections = require("../stats/collections"); 17 | const getEnchanting = require("../stats/enchanting"); 18 | const getFarming = require("../stats/farming"); 19 | const getMining = require("../stats/mining"); 20 | const getDungeons = require("../stats/dungeons.js"); 21 | const getTrophyFish = require("../stats/trophyFishing"); 22 | const getCrimson = require("../stats/crimson.js"); 23 | const getWeight = require("../stats/weight"); 24 | const getMissing = require("../stats/missing"); 25 | const getNetworth = require("../stats/networth"); 26 | const getBestiary = require("../stats/bestiary"); 27 | const getContent = require("../stats/items"); 28 | const { isUuid } = require("./uuid"); 29 | 30 | module.exports = { 31 | parseHypixel: function parseHypixel(playerRes, uuid) { 32 | if (playerRes.data.hasOwnProperty("player") && playerRes.data.player == null) return { status: 404, reason: `Found no Player data for a user with a UUID of '${uuid}'` } 33 | 34 | const data = playerRes.data.player; 35 | const achievements = data.achievements; 36 | 37 | return { 38 | name: data.displayname, 39 | rank: getRank(data), 40 | hypixelLevel: getHypixelLevel(data), 41 | karma: data.karma, 42 | skills: { 43 | mining: achievements?.skyblock_excavator || 0, 44 | foraging: achievements?.skyblock_gatherer || 0, 45 | enchanting: achievements?.skyblock_augmentation || 0, 46 | farming: achievements?.skyblock_harvester || 0, 47 | combat: achievements?.skyblock_combat || 0, 48 | fishing: achievements?.skyblock_angler || 0, 49 | alchemy: achievements?.skyblock_concoctor || 0, 50 | taming: achievements?.skyblock_domesticator || 0, 51 | }, 52 | dungeons: { 53 | secrets: achievements?.skyblock_treasure_hunter || 0, 54 | }, 55 | }; 56 | }, 57 | parseProfile: async function parseProfile(player, profileRes, uuid, profileid, res) { 58 | if (profileRes.data.hasOwnProperty("profiles") && profileRes.data.profiles == null) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'` } 59 | 60 | if (!isUuid(profileid)) { 61 | for (const profile of profileRes.data?.profiles || []) { 62 | if (profile.cute_name.toLowerCase() === profileid.toLowerCase()) profileid = profile.profile_id; 63 | } 64 | } 65 | 66 | const profileData = profileRes.data.profiles.find((a) => a.profile_id === profileid); 67 | 68 | if (!profileData) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'` } 69 | if (!isValidProfile(profileData.members, uuid)) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'` } 70 | 71 | const profile = profileData.members[uuid]; 72 | 73 | const [networth, weight, missing, armor, equipment, talismans, cakebag] = 74 | await Promise.all([ 75 | getNetworth(profile, profileData), 76 | getWeight(profile, uuid), 77 | getMissing(profile), 78 | getArmor(profile), 79 | getEquipment(profile), 80 | getTalismans(profile), 81 | getCakebag(profile), 82 | ]); 83 | 84 | return { 85 | username: player.name, 86 | uuid: uuid, 87 | name: profileData.cute_name, 88 | id: profileData.profile_id, 89 | rank: player.rank, 90 | hypixelLevel: player.hypixelLevel, 91 | karma: player.karma, 92 | isIronman: profileData?.game_mode === "ironman" ? true : false, 93 | gamemode: profileData?.game_mode ?? "normal", 94 | last_save: profile.last_save, 95 | first_join: profile.first_join, 96 | fairy_souls: profile.fairy_souls_collected || 0, 97 | purse: profile.coin_purse || 0, 98 | bank: profileData.banking?.balance || 0, 99 | skills: getSkills(player, profile), 100 | networth: networth, 101 | weight: weight, 102 | bestiary: getBestiary(profile), 103 | dungeons: getDungeons(player, profile), 104 | crimson: getCrimson(profile), 105 | trophy_fish: getTrophyFish(profile), 106 | enchanting: getEnchanting(player, profile), 107 | farming: getFarming(player, profile), 108 | mining: getMining(player, profile), 109 | slayer: getSlayer(profile), 110 | milestones: getMilestones(profile), 111 | missing: missing, 112 | kills: getKills(profile), 113 | deaths: getDeaths(profile), 114 | armor: armor, 115 | equipment: equipment, 116 | pets: getPets(profile), 117 | talismans: talismans, 118 | collections: getCollections(profileData), 119 | minions: getMinions(profileData), 120 | cakebag: cakebag, 121 | }; 122 | }, 123 | parseProfiles: async function parseProfile(player, profileRes, uuid, res) { 124 | if (profileRes.data.hasOwnProperty("profiles") && profileRes.data.profiles == null) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'.` }; 125 | 126 | const result = []; 127 | 128 | for (const profileData of profileRes.data.profiles) { 129 | if (!isValidProfile(profileData.members, uuid)) continue; 130 | 131 | const profile = profileData.members[uuid]; 132 | const [networth, weight, missing, armor, equipment, talismans, cakebag] = 133 | await Promise.all([ 134 | getNetworth(profile, profileData), 135 | getWeight(profile, uuid), 136 | getMissing(profile), 137 | getArmor(profile), 138 | getEquipment(profile), 139 | getTalismans(profile), 140 | getCakebag(profile), 141 | ]); 142 | 143 | result.push({ 144 | username: player.name, 145 | uuid: uuid, 146 | name: profileData.cute_name, 147 | id: profileData.profile_id, 148 | rank: player.rank, 149 | hypixelLevel: player.hypixelLevel, 150 | karma: player.karma, 151 | isIronman: profileData?.game_mode === "ironman" ? true : false, 152 | gamemode: profileData?.game_mode ?? "normal", 153 | last_save: profile.last_save, 154 | first_join: profile.first_join, 155 | fairy_souls: profile.fairy_souls_collected || 0, 156 | purse: profile.coin_purse || 0, 157 | bank: profileData.banking?.balance || 0, 158 | skills: getSkills(player, profile), 159 | networth: networth, 160 | weight: weight, 161 | bestiary: getBestiary(profile), 162 | dungeons: getDungeons(player, profile), 163 | crimson: getCrimson(profile), 164 | trophy_fish: getTrophyFish(profile), 165 | enchanting: getEnchanting(player, profile), 166 | farming: getFarming(player, profile), 167 | mining: getMining(player, profile), 168 | slayer: getSlayer(profile), 169 | milestones: getMilestones(profile), 170 | missing: missing, 171 | kills: getKills(profile), 172 | deaths: getDeaths(profile), 173 | armor: armor, 174 | equipment: equipment, 175 | pets: getPets(profile), 176 | talismans: talismans, 177 | collections: getCollections(profileData), 178 | minions: getMinions(profileData), 179 | cakebag: cakebag, 180 | }); 181 | } 182 | 183 | if (result.length == 0) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'.` }; 184 | 185 | return result.sort((a, b) => b.last_save - a.last_save); 186 | }, 187 | parseProfileItems: async function parseProfileItems(player, profileRes, uuid, profileid, res) { 188 | if (profileRes.data.hasOwnProperty("profiles") && profileRes.data.profiles == null) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'.` }; 189 | 190 | if (!isUuid(profileid)) { 191 | for (const profile of profileRes.data?.profiles || []) { 192 | if (profile.cute_name.toLowerCase() === profileid.toLowerCase()) profileid = profile.profile_id; 193 | } 194 | } 195 | 196 | const profileData = profileRes.data.profiles.find((a) => a.profile_id === profileid); 197 | if (!profileData) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'` }; 198 | 199 | if (!isValidProfile(profileData.members, uuid)) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}' and profile of '${profileid}'` }; 200 | 201 | const profile = profileData.members[uuid]; 202 | 203 | return { 204 | username: player.name, 205 | uuid: uuid, 206 | name: profileData.cute_name, 207 | id: profileData.profile_id, 208 | last_save: profile.last_save, 209 | data: await getContent(profile), 210 | }; 211 | }, 212 | 213 | parseProfilesItems: async function parseProfileItems(player, profileRes, uuid, res) { 214 | if (profileRes.data.hasOwnProperty("profiles") && profileRes.data.profiles == null) return ({ status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'.` }); 215 | 216 | const result = []; 217 | 218 | for (const profileData of profileRes.data.profiles) { 219 | if (!isValidProfile(profileData.members, uuid)) continue; 220 | 221 | const profile = profileData.members[uuid]; 222 | 223 | result.push({ 224 | username: player.name, 225 | uuid: uuid, 226 | name: profileData.cute_name, 227 | id: profileData.profile_id, 228 | last_save: profile.last_save, 229 | data: await getContent(profile), 230 | }); 231 | } 232 | if (result.length == 0) return { status: 404, reason: `Found no SkyBlock profiles for a user with a UUID of '${uuid}'.` }; 233 | 234 | return result.sort((a, b) => b.last_save - a.last_save); 235 | }, 236 | 237 | parseBingoProfile: function parseBingoProfile(profile, bingo, uuid) { 238 | return { 239 | uuid: uuid, 240 | profile: getBingo(profile.data, bingo.data), 241 | }; 242 | }, 243 | }; 244 | 245 | function isValidProfile(profileMembers, uuid) { 246 | return (profileMembers.hasOwnProperty(uuid) && profileMembers[uuid].last_save != undefined); 247 | } 248 | -------------------------------------------------------------------------------- /API/utils/nbt.js: -------------------------------------------------------------------------------- 1 | const nbt = require("prismarine-nbt"); 2 | const util = require("util"); 3 | const parseNbt = util.promisify(nbt.parse); 4 | 5 | module.exports = { 6 | decodeData: async function decodeData(buffer) { 7 | const parsedNbt = await parseNbt(buffer); 8 | return nbt.simplify(parsedNbt); 9 | }, 10 | decodeArrayBuffer: async function decodeArrayBuffer(arraybuf) { 11 | let buf = Buffer.from(arraybuf); 12 | 13 | let data = await parseNbt(buf); 14 | data = nbt.simplify(data); 15 | 16 | let items = data.i; 17 | return items; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /API/utils/request.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | const axios = require("axios"); 3 | const headers = ["RateLimit-Limit", "RateLimit-Remaining", "RateLimit-Reset"]; 4 | 5 | module.exports = { 6 | makeRequest: async function makeRequest(response, url) { 7 | const result = await axios.get(url); 8 | 9 | for (let header of headers) { 10 | if (result.headers.hasOwnProperty(header.toLowerCase())) { 11 | response.set(header, result.headers[header.toLowerCase()]); 12 | } 13 | } 14 | 15 | return result; 16 | }, 17 | wrap: function wrap(fn) { 18 | return function (req, res, next) { 19 | return fn(req, res, next).catch((err) => { 20 | next(err); 21 | }); 22 | }; 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /API/utils/uuid.js: -------------------------------------------------------------------------------- 1 | //CREDIT: https://github.com/Senither/hypixel-skyblock-facade (Modified) 2 | function isUuid(uuid) { 3 | if (!uuid) { 4 | return false; 5 | } 6 | 7 | return ( 8 | /^[0-9a-fA-F]{8}[0-9a-fA-F]{4}[0-9a-fA-F]{4}[0-9a-fA-F]{4}[0-9a-fA-F]{12}$/.test( 9 | uuid 10 | ) || 11 | /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test( 12 | uuid 13 | ) 14 | ); 15 | } 16 | 17 | function validateUuid(uuid, res) { 18 | if (uuid == undefined) { 19 | res 20 | .status(400) 21 | .json({ 22 | status: 400, 23 | reason: "Invalid UUID provided, you must provide a valid UUID", 24 | }); 25 | return; 26 | } 27 | 28 | if (!isUuid(uuid)) { 29 | res 30 | .status(400) 31 | .json({ 32 | status: 400, 33 | reason: "Invalid UUID provided, you must provide a valid UUID", 34 | }); 35 | return; 36 | } 37 | 38 | return uuid; 39 | } 40 | 41 | module.exports = { 42 | isUuid, 43 | validateUuid, 44 | }; 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QwackAPI 2 | 3 | > Huge Credits to MattTheCuber and Altpapier for letting me continue this as my own project 4 | 5 | This API was made using the [qwackAPI](https://github.com/DuckySoLucky/QwackAPI) 6 | 7 | ## What does QwackAPI have but SkyHelper doesn't? 8 | 9 | - more details about player's pets (lore, abilities, perks, skin url etc..)
10 | - `auctionHouse` Endpoint
11 | - More coming soon..
12 | 13 | # Installing 14 | 15 | ### Requirements: 16 | 17 | Node.js >= 14 18 | 19 | ### Setup: 20 | 21 | 1. Clone the repository using `git clone https://github.com/DuckySoLucky/QwackAPI` 22 | 23 | 2. Install all dependencies using NPM by going into the `QwackAPI` folder `npm install` 24 | 25 | 3. Set up the [Configuration](#Configuration) 26 | 27 | 4. Start the API using `node .` or `npm start` 28 | 29 | ### Configuration 30 | 31 | You will have to set the Hypixel API key by replacing the `HYPIXEL_API_KEY` inside of the config. 32 | 33 | # Functions: 34 | 35 | ### `getAuctionHouse(options = {lore: lore, name: name, rarity: rarity, category: category, bin: bin, lowest_price: lowest_price, highest_price: highest_price, user: user })` 36 | 37 | ### `getAuctions(user)` 38 | 39 | ### `getBingo(user)` 40 | 41 | ### `getSkyblockCalendar()` 42 | 43 | ### `getFetchur()` 44 | 45 | ### `getItems(user)` 46 | 47 | ### `getItems(user, profile)` 48 | 49 | ### `getLatestProfile(user)` 50 | 51 | ### `getProfile(user, profile)` 52 | 53 | ### `getProfileParsed(user, profile)` 54 | 55 | ### `getProfiles(user)` 56 | 57 | ### `getProfilesParsed(user)` 58 | 59 | | Parameter | Description | 60 | | ------------- | ------------------------------------------ | 61 | | user | This can be the UUID of a user or the name | 62 | | profile | This can be the users profile id or name | 63 | | name | Name of the item | 64 | | lore | Lore of the item | 65 | | rarity | Rarity of the item | 66 | | bin | Bin (true or false) | 67 | | category | Category of them item | 68 | | lowest_price | Lowest price of the item | 69 | | highest_price | Highest price of the item | 70 | 71 | # Features: 72 | 73 | | Feature | Description | Endpoint | 74 | | -------------- | ----------------------------------------------------------------------- | ---------------------- | 75 | | auctions | Get a player's active and ended auctions and information about them | auctions | 76 | | auctionhouse | Get currently active auctions and details about them | auctionhouse | 77 | | bingo | Get a player's bingo profile and progress | bingo | 78 | | calendar | Get Skyblock's calendar including all events | calendar | 79 | | items | Check what item fetchur wants today including description of the item | fetchur | 80 | | skills | Get a player's skills | profile/profiles | 81 | | networth | Get a player's networth including all information about the calculation | profile/profiles | 82 | | weight | Get a player's Senither and Lily weight | profile/profiles | 83 | | dungeons | Get a player's dungeons stats | profile/profiles | 84 | | bestiary | Get a player's bestiary | profile/profiles | 85 | | crimson | Get player's Crimson Isle data | profile/profiles | 86 | | trophy_fish | Get player's trophy fishing caches and information | profile/profiles | 87 | | enchanting | Get a player's enchanting stats including experimentations | profile/profiles | 88 | | farming | Get a player's farming stats including Jacob's contests | profile/profiles | 89 | | mining | Get a player's mining stats including HotM tree and forge | profile/profiles | 90 | | slayer | Get a player's slayer stats | profile/profiles | 91 | | milestones | Get a player's pet milestones (rock / dolphin) | profile/profiles | 92 | | missing | Get a player's missing talismans including their price | profile/profiles | 93 | | kills | Get a player's most killed mobs | profile/profiles | 94 | | deaths | Get a player's deaths | profile/profiles | 95 | | armor | Get a player's armor | profile/profiles/items | 96 | | equipment | Get a player's equipment | profile/profiles/items | 97 | | pets | Get a player's pets | profile/profiles | 98 | | talismans | Get a player's talismans | profile/profiles | 99 | | collections | Get a player's collections | profile/profiles | 100 | | minions | Get a player's minions | profile/profiles | 101 | | cakebag | Get a player's new year cake editions | profile/profiles | 102 | | backpack | Get player's backpacks | items | 103 | | quiver | Get player's quiver | items | 104 | | talisman bag | Get player's talisman bag | items | 105 | | backpack icons | Get data about player's backpacks | items | 106 | | ender chest | Get player's ender chest | items | 107 | | potion bag | Get player's potion bag | items | 108 | | fishing bag | Get player's fishing bag | items | 109 | | personal vault | Get player's personal vault | items | 110 | | inventory | Get player's inventory | items | 111 | | candy bag | Get player's candy bag | items | 112 | 113 | # Credits: 114 | 115 | - https://github.com/Altpapier 116 | 117 | - https://github.com/MattTheCuber 118 | 119 | - https://github.com/zt3h/MaroAPI 120 | 121 | - https://github.com/Senither/hypixel-skyblock-facade 122 | 123 | - https://github.com/SkyCryptWebsite/SkyCrypt 124 | 125 | - https://github.com/slothpixel/core/ 126 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "hypixelAPIkey": "HYPIXEL_API_KEY" 3 | } 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // ! ORIGINAL SRC: https://github.com/Altpapier/SkyHelperAPI 2 | // 3 | // ! MODIFIED SRC: https://github.com/DuckySoLucky/QwackAPI 4 | // 5 | // ? THIS IS MODIFIED VERSION OF OFFICIAL SKYHELPER API 6 | // * THIS VERSION USES FUNCTIONS TO GET DATA INSTEAD OF HAVING TO HOST AN API 7 | // 8 | 9 | const { getFetchur } = require('./API/functions/getFetchur'); 10 | const { getBingo } = require('./API/functions/getBingoProfile') 11 | const { getProfileParsed } = require('./API/functions/getProfileParsed'); 12 | 13 | const refreshAuctions = require('./API/data/refreshAuctions') 14 | const refreshCollections = require('./API/data/refreshCollections') 15 | const refreshPrices = require('./API/data/refreshPrices') 16 | 17 | process.on('uncaughtException', (error) => console.log(error)) 18 | process.on('unhandledRejection', (error) => console.log(error)) 19 | 20 | refreshAuctions(); 21 | refreshCollections() 22 | refreshPrices() 23 | 24 | // ? Examples 25 | 26 | console.log(getFetchur()) 27 | 28 | getProfileParsed('Refraction', 'Apple').then(console.log) 29 | 30 | getBingo('Refraction').then(console.log) 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qwackapi-function", 3 | "version": "1.0.0", 4 | "description": "Functions for Modified version of Official SkyHelperAPI", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node ." 8 | }, 9 | "keywords": [ 10 | "api", 11 | "hypixel", 12 | "skyblock" 13 | ], 14 | "author": "DuckySoLucky", 15 | "license": "MIT", 16 | "dependencies": { 17 | "moment": "^2.29.4", 18 | "axios": "^0.22.0", 19 | "chalk": "^4.1.2", 20 | "cors": "^2.8.5", 21 | "dotenv": "^10.0.0", 22 | "express": "^4.17.1", 23 | "express-rate-limit": "^6.3.0", 24 | "lilyweight": "^2.7.0", 25 | "prismarine-nbt": "^1.6.0", 26 | "util": "^0.12.4" 27 | }, 28 | "engines": { 29 | "node": "=16.7.0" 30 | } 31 | } 32 | --------------------------------------------------------------------------------