From b49ffef98e38ac19dc9490194b5c6686b8f067d9 Mon Sep 17 00:00:00 2001 From: Kath Date: Sun, 28 Jul 2024 11:29:43 +0800 Subject: [PATCH] Convert src/structures into typescript --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/SECURITY.md | 2 +- .github/labels.yml | 2 +- package.json | 3 +- pnpm-lock.yaml | 136 +++-- renovate.json | 2 +- src/Private/defaultCache.ts | 2 +- src/index.ts | 114 ++-- src/structures/APIIncident.ts | 34 ++ src/structures/APIStatus.ts | 24 + src/structures/Boosters/Booster.ts | 43 ++ src/structures/Color.ts | 4 - src/structures/Game.ts | 10 +- src/structures/GameCounts.ts | 28 + src/structures/Guild/Guild.ts | 2 +- src/structures/House.ts | 27 + src/structures/ItemBytes.ts | 20 + src/structures/Leaderboard.ts | 17 + src/structures/MiniGames/Arcade.ts | 511 ++++++++++++++++++ src/structures/MiniGames/ArenaBrawl.ts | 90 +++ src/structures/MiniGames/BedWars.ts | 322 +++++++++++ .../MiniGames/BlitzSurvivalGames.ts | 176 ++++++ src/structures/MiniGames/BuildBattle.ts | 32 ++ src/structures/MiniGames/CopsAndCrims.ts | 139 +++++ src/structures/MiniGames/Duels.ts | 475 ++++++++++++++++ src/structures/MiniGames/MegaWalls.ts | 199 +++++++ src/structures/MiniGames/MurderMystery.ts | 93 ++++ src/structures/MiniGames/Paintball.ts | 39 ++ src/structures/MiniGames/Pit.ts | 138 +++++ src/structures/MiniGames/PitInventoryItem.ts | 21 + src/structures/MiniGames/Quakecraft.ts | 73 +++ src/structures/MiniGames/SkyWars.ts | 298 ++++++++++ src/structures/MiniGames/SmashHeroes.ts | 117 ++++ src/structures/MiniGames/SpeedUHC.ts | 74 +++ src/structures/MiniGames/TNTGames.ts | 126 +++++ src/structures/MiniGames/TurboKartRacers.ts | 62 +++ src/structures/MiniGames/UHC.ts | 186 +++++++ src/structures/MiniGames/VampireZ.ts | 44 ++ src/structures/MiniGames/Walls.ts | 26 + src/structures/MiniGames/Warlords.ts | 82 +++ src/structures/MiniGames/WoolWars.ts | 151 ++++++ src/structures/Pet.ts | 41 ++ src/structures/Pets.ts | 17 + src/structures/Player.ts | 156 ++++++ src/structures/PlayerCosmetics.ts | 155 ++++++ src/structures/RecentGame.ts | 27 + src/structures/ServerInfo.ts | 35 ++ src/structures/SkyBlock/Auctions/Auction.ts | 46 ++ .../SkyBlock/Auctions/AuctionInfo.ts | 31 ++ .../SkyBlock/Auctions/BaseAuction.ts | 25 + src/structures/SkyBlock/Auctions/Bid.ts | 25 + .../SkyBlock/Auctions/PartialAuction.ts | 13 + src/structures/SkyBlock/Bazzar/Order.ts | 21 + src/structures/SkyBlock/Bazzar/Product.ts | 33 ++ src/structures/SkyBlock/News/SkyblockNews.ts | 37 ++ src/structures/SkyBlock/PlayerBingo.ts | 27 + src/structures/SkyBlock/SkyblockGarden.ts | 74 +++ .../SkyBlock/SkyblockInventoryItem.ts | 84 +++ src/structures/SkyBlock/SkyblockMember.ts | 253 +++++++++ src/structures/SkyBlock/SkyblockMuseum.ts | 49 ++ src/structures/SkyBlock/SkyblockMuseumItem.ts | 31 ++ src/structures/SkyBlock/SkyblockPet.ts | 29 + src/structures/SkyBlock/SkyblockProfile.ts | 47 ++ src/structures/SkyBlock/Static/Bingo.ts | 56 ++ src/structures/SkyBlock/Static/BingoData.ts | 24 + src/structures/SkyBlock/Static/Candidate.ts | 21 + src/structures/SkyBlock/Static/FireSale.ts | 27 + src/structures/SkyBlock/Static/Government.ts | 45 ++ src/structures/SkyBlock/Static/Perk.ts | 13 + src/structures/Static/Achievement.ts | 52 ++ src/structures/Static/AchievementTier.ts | 24 + src/structures/Static/Achievements.ts | 23 + src/structures/Static/Challenges.ts | 23 + src/structures/Static/GameAchievements.ts | 22 + src/structures/Static/GameChallenges.ts | 25 + src/structures/Static/GameQuests.ts | 16 + src/structures/Static/GuildAchievements.ts | 22 + src/structures/Static/Quest.ts | 30 + src/structures/Static/Quests.ts | 23 + src/structures/Status.ts | 19 + src/structures/Watchdog/Stats.ts | 19 + src/typings/index.d.ts | 426 +++++++++++++++ src/utils/Constants.ts | 3 +- src/utils/Player.ts | 20 +- src/utils/SkyblockUtils.ts | 131 ++--- src/utils/removeSnakeCase.ts | 6 +- tsconfig.json | 2 +- 87 files changed, 6069 insertions(+), 205 deletions(-) create mode 100644 src/structures/APIIncident.ts create mode 100644 src/structures/APIStatus.ts create mode 100644 src/structures/Boosters/Booster.ts create mode 100644 src/structures/GameCounts.ts create mode 100644 src/structures/House.ts create mode 100644 src/structures/ItemBytes.ts create mode 100644 src/structures/Leaderboard.ts create mode 100644 src/structures/MiniGames/Arcade.ts create mode 100644 src/structures/MiniGames/ArenaBrawl.ts create mode 100644 src/structures/MiniGames/BedWars.ts create mode 100644 src/structures/MiniGames/BlitzSurvivalGames.ts create mode 100644 src/structures/MiniGames/BuildBattle.ts create mode 100644 src/structures/MiniGames/CopsAndCrims.ts create mode 100644 src/structures/MiniGames/Duels.ts create mode 100644 src/structures/MiniGames/MegaWalls.ts create mode 100644 src/structures/MiniGames/MurderMystery.ts create mode 100644 src/structures/MiniGames/Paintball.ts create mode 100644 src/structures/MiniGames/Pit.ts create mode 100644 src/structures/MiniGames/PitInventoryItem.ts create mode 100644 src/structures/MiniGames/Quakecraft.ts create mode 100644 src/structures/MiniGames/SkyWars.ts create mode 100644 src/structures/MiniGames/SmashHeroes.ts create mode 100644 src/structures/MiniGames/SpeedUHC.ts create mode 100644 src/structures/MiniGames/TNTGames.ts create mode 100644 src/structures/MiniGames/TurboKartRacers.ts create mode 100644 src/structures/MiniGames/UHC.ts create mode 100644 src/structures/MiniGames/VampireZ.ts create mode 100644 src/structures/MiniGames/Walls.ts create mode 100644 src/structures/MiniGames/Warlords.ts create mode 100644 src/structures/MiniGames/WoolWars.ts create mode 100644 src/structures/Pet.ts create mode 100644 src/structures/Pets.ts create mode 100644 src/structures/Player.ts create mode 100644 src/structures/PlayerCosmetics.ts create mode 100644 src/structures/RecentGame.ts create mode 100644 src/structures/ServerInfo.ts create mode 100644 src/structures/SkyBlock/Auctions/Auction.ts create mode 100644 src/structures/SkyBlock/Auctions/AuctionInfo.ts create mode 100644 src/structures/SkyBlock/Auctions/BaseAuction.ts create mode 100644 src/structures/SkyBlock/Auctions/Bid.ts create mode 100644 src/structures/SkyBlock/Auctions/PartialAuction.ts create mode 100644 src/structures/SkyBlock/Bazzar/Order.ts create mode 100644 src/structures/SkyBlock/Bazzar/Product.ts create mode 100644 src/structures/SkyBlock/News/SkyblockNews.ts create mode 100644 src/structures/SkyBlock/PlayerBingo.ts create mode 100644 src/structures/SkyBlock/SkyblockGarden.ts create mode 100644 src/structures/SkyBlock/SkyblockInventoryItem.ts create mode 100644 src/structures/SkyBlock/SkyblockMember.ts create mode 100644 src/structures/SkyBlock/SkyblockMuseum.ts create mode 100644 src/structures/SkyBlock/SkyblockMuseumItem.ts create mode 100644 src/structures/SkyBlock/SkyblockPet.ts create mode 100644 src/structures/SkyBlock/SkyblockProfile.ts create mode 100644 src/structures/SkyBlock/Static/Bingo.ts create mode 100644 src/structures/SkyBlock/Static/BingoData.ts create mode 100644 src/structures/SkyBlock/Static/Candidate.ts create mode 100644 src/structures/SkyBlock/Static/FireSale.ts create mode 100644 src/structures/SkyBlock/Static/Government.ts create mode 100644 src/structures/SkyBlock/Static/Perk.ts create mode 100644 src/structures/Static/Achievement.ts create mode 100644 src/structures/Static/AchievementTier.ts create mode 100644 src/structures/Static/Achievements.ts create mode 100644 src/structures/Static/Challenges.ts create mode 100644 src/structures/Static/GameAchievements.ts create mode 100644 src/structures/Static/GameChallenges.ts create mode 100644 src/structures/Static/GameQuests.ts create mode 100644 src/structures/Static/GuildAchievements.ts create mode 100644 src/structures/Static/Quest.ts create mode 100644 src/structures/Static/Quests.ts create mode 100644 src/structures/Status.ts create mode 100644 src/structures/Watchdog/Stats.ts diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8ed08cbb..b81bce49 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -22,4 +22,4 @@ - [ ] I've check for issues. (`npm run eslint`) - [ ] I've fixed my formatting. (`npm run prettier`) - \ No newline at end of file + diff --git a/.github/SECURITY.md b/.github/SECURITY.md index cf96818c..eafeff54 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -18,4 +18,4 @@ To report a vulnerability you can do so in the [Discord Server](https://discord. or you can contact the primary contributor of this repository using the following contact methods: - @kathund. on Discord -- @kathundd on Telegram \ No newline at end of file +- @kathundd on Telegram diff --git a/.github/labels.yml b/.github/labels.yml index a9cb4866..01931a6d 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -21,4 +21,4 @@ XL: XXL: name: size/XXL lines: 5000 - color: E50009 \ No newline at end of file + color: E50009 diff --git a/package.json b/package.json index b2175a44..8a88f8e0 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "dependencies": { "axios": "^1.7.2", "node-cache": "^5.1.2", - "prismarine-nbt": "^2.5.0" + "prismarine-nbt": "^2.5.0", + "skyhelper-networth": "^1.21.0" }, "license": "MIT", "readme": "https://github.com/Hypixel-API-Reborn/hypixel-api-reborn?tab=readme-ov-file#hypixel-api--reborn", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5cb7d84c..e3a37dc8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,6 @@ settings: excludeLinksFromLockfile: false importers: - .: dependencies: axios: @@ -17,6 +16,9 @@ importers: prismarine-nbt: specifier: ^2.5.0 version: 2.5.0 + skyhelper-networth: + specifier: ^1.21.0 + version: 1.21.0 devDependencies: '@types/node': specifier: ^20.14.12 @@ -29,40 +31,49 @@ importers: version: 5.5.4 packages: - '@types/node@20.14.12': - resolution: {integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==} + resolution: + { integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ== } ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + resolution: + { integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== } asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + resolution: + { integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== } axios@1.7.2: - resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==} + resolution: + { integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== } clone@2.1.2: - resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} - engines: {node: '>=0.8'} + resolution: + { integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== } + engines: { node: '>=0.8' } combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + resolution: + { integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== } + engines: { node: '>= 0.8' } delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} + resolution: + { integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== } + engines: { node: '>=0.4.0' } fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + resolution: + { integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== } fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + resolution: + { integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== } follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} + resolution: + { integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== } + engines: { node: '>=4.0' } peerDependencies: debug: '*' peerDependenciesMeta: @@ -70,82 +81,106 @@ packages: optional: true form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} + resolution: + { integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== } + engines: { node: '>= 6' } inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + resolution: + { integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== } json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + resolution: + { integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== } lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + resolution: + { integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== } lodash.reduce@4.6.0: - resolution: {integrity: sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==} + resolution: + { integrity: sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw== } mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} + resolution: + { integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== } + engines: { node: '>= 0.6' } mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + resolution: + { integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== } + engines: { node: '>= 0.6' } node-cache@5.1.2: - resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} - engines: {node: '>= 8.0.0'} + resolution: + { integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== } + engines: { node: '>= 8.0.0' } prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} - engines: {node: '>=14'} + resolution: + { integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== } + engines: { node: '>=14' } hasBin: true prismarine-nbt@2.5.0: - resolution: {integrity: sha512-F0/8UAa9SDDnAGrBYqZc4nG8h2zj5cE2eAJU5xlDR/IsQQ3moVxkOjE3h3nMv6SbvZrvAcgX7waA/nd9LLHYdA==} + resolution: + { integrity: sha512-F0/8UAa9SDDnAGrBYqZc4nG8h2zj5cE2eAJU5xlDR/IsQQ3moVxkOjE3h3nMv6SbvZrvAcgX7waA/nd9LLHYdA== } protodef-validator@1.3.1: - resolution: {integrity: sha512-lZ5FWKZYR9xOjpMw1+EfZRfCjzNRQWPq+Dk+jki47Sikl2EeWEPnTfnJERwnU/EwFq6us+0zqHHzSsmLeYX+Lg==} + resolution: + { integrity: sha512-lZ5FWKZYR9xOjpMw1+EfZRfCjzNRQWPq+Dk+jki47Sikl2EeWEPnTfnJERwnU/EwFq6us+0zqHHzSsmLeYX+Lg== } hasBin: true protodef@1.15.0: - resolution: {integrity: sha512-bZ2Omw8dT+DACjJHLrBWZlqN4MlT9g9oSpJDdkUAJOStUzgJp+Zn42FJfPUdwutUxjaxA0PftN0PDlNa2XbneA==} - engines: {node: '>=14'} + resolution: + { integrity: sha512-bZ2Omw8dT+DACjJHLrBWZlqN4MlT9g9oSpJDdkUAJOStUzgJp+Zn42FJfPUdwutUxjaxA0PftN0PDlNa2XbneA== } + engines: { node: '>=14' } proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + resolution: + { integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== } punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + resolution: + { integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== } + engines: { node: '>=6' } readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + resolution: + { integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== } + engines: { node: '>= 6' } safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + resolution: + { integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== } + + skyhelper-networth@1.21.0: + resolution: + { integrity: sha512-AB7Jz1zZYOaoVZ6s95fjjXZOCglWT9y7U8SXFintm+Ln0FmXAr33y4BHqhGj7DFJzpiywybH5ga2Q0NQyZZOVA== } string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + resolution: + { integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== } typescript@5.5.4: - resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} - engines: {node: '>=14.17'} + resolution: + { integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== } + engines: { node: '>=14.17' } hasBin: true undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + resolution: + { integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== } uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + resolution: + { integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== } util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + resolution: + { integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== } snapshots: - '@types/node@20.14.12': dependencies: undici-types: 5.26.5 @@ -234,6 +269,13 @@ snapshots: safe-buffer@5.2.1: {} + skyhelper-networth@1.21.0: + dependencies: + axios: 1.7.2 + prismarine-nbt: 2.5.0 + transitivePeerDependencies: + - debug + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 diff --git a/renovate.json b/renovate.json index f81053fa..c0854cf5 100644 --- a/renovate.json +++ b/renovate.json @@ -15,4 +15,4 @@ } ] } -} \ No newline at end of file +} diff --git a/src/Private/defaultCache.ts b/src/Private/defaultCache.ts index dd9a7d7a..20adee2f 100644 --- a/src/Private/defaultCache.ts +++ b/src/Private/defaultCache.ts @@ -35,4 +35,4 @@ class Cache implements CacheHandler { } } -module.exports = Cache; +export default Cache; diff --git a/src/index.ts b/src/index.ts index 626fad89..9e1ff275 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,64 +1,62 @@ -import Client from './Client.ts'; -import Errors from './Errors.ts'; +import Client from './Client'; +import Errors from './Errors'; -export const version = require('../package.json').version; -import APIStatus from './structures/APIStatus.ts'; -import APIIncident from './structures/APIIncident.ts'; -import Player from './structures/Player.ts'; -import Game from './structures/Game.ts'; -import Status from './structures/Status.ts'; -import Color from './structures/Color.ts'; +import APIStatus from './structures/APIStatus'; +import APIIncident from './structures/APIIncident'; +import Player from './structures/Player'; +import Game from './structures/Game'; +import Status from './structures/Status'; +import Color from './structures/Color'; import Pet from './structures/Pet'; import Pets from './structures/Pets'; import PlayerCosmetics from './structures/PlayerCosmetics'; -import Challenges from './structures/Static/Challenges.ts'; -import GameChallenges from './structures/Static/GameChallenges.ts'; -import WatchdogStats from './structures/Watchdog/Stats.ts'; -import Guild from './structures/Guild/GuildMember.js'; -import GuildMember from './structures/Guild/GuildMember.ts'; -import GuildRank from './structures/Guild/GuildRank.ts'; -import SkyblockProfile from './structures/SkyBlock/SkyblockProfile.ts'; -import SkyblockMember from './structures/SkyBlock/SkyblockMember.ts'; -import SkyblockGarden from './structures/SkyBlock/SkyblockGarden.ts'; -import SkyblockInventoryItem from './structures/SkyBlock/SkyblockInventoryItem.ts'; +import Challenges from './structures/Static/Challenges'; +import GameChallenges from './structures/Static/GameChallenges'; +import WatchdogStats from './structures/Watchdog/Stats'; +import Guild from './structures/Guild/GuildMember'; +import GuildMember from './structures/Guild/GuildMember'; +import GuildRank from './structures/Guild/GuildRank'; +import SkyblockProfile from './structures/SkyBlock/SkyblockProfile'; +import SkyblockMember from './structures/SkyBlock/SkyblockMember'; +import SkyblockGarden from './structures/SkyBlock/SkyblockGarden'; +import SkyblockInventoryItem from './structures/SkyBlock/SkyblockInventoryItem'; import SkyblockPet from './structures/SkyBlock/SkyblockPet'; -import GovernmentData from './structures/SkyBlock/Static/Government.ts'; -import Candidate from './structures/SkyBlock/Static/Candidate.ts'; -import BingoData from './structures/SkyBlock/Static/BingoData.ts'; -import Bingo from './structures/SkyBlock/Static/Bingo.ts'; -import BaseAuction from './structures/SkyBlock/Auctions/BaseAuction.ts'; -import PartialAuction from './structures/SkyBlock/Auctions/PartialAuction.ts'; -import Auction from './structures/SkyBlock/Auctions/Auction.ts'; -import AuctionInfo from './structures/SkyBlock/Auctions/AuctionInfo.ts'; -import Bid from './structures/SkyBlock/Auctions/Bid.ts'; -import FireSale from './structures/SkyBlock/Static/FireSale.ts'; -import Product from './structures/SkyBlock/Bazzar/Product.ts'; -import Order from './structures/SkyBlock/Bazzar/Order.ts'; +import GovernmentData from './structures/SkyBlock/Static/Government'; +import Candidate from './structures/SkyBlock/Static/Candidate'; +import BingoData from './structures/SkyBlock/Static/BingoData'; +import Bingo from './structures/SkyBlock/Static/Bingo'; +import BaseAuction from './structures/SkyBlock/Auctions/BaseAuction'; +import PartialAuction from './structures/SkyBlock/Auctions/PartialAuction'; +import Auction from './structures/SkyBlock/Auctions/Auction'; +import AuctionInfo from './structures/SkyBlock/Auctions/AuctionInfo'; +import Bid from './structures/SkyBlock/Auctions/Bid'; +import FireSale from './structures/SkyBlock/Static/FireSale'; +import Product from './structures/SkyBlock/Bazzar/Product'; +import Order from './structures/SkyBlock/Bazzar/Order'; import SkyblockNews from './structures/SkyBlock/News/SkyblockNews'; -import Booster from './structures/Boosters/Booster.ts'; -import House from './structures/House.ts'; -import Arcade from './structures/MiniGames/Arcade.ts'; -import ArenaBrawl from './structures/MiniGames/ArenaBrawl.ts'; -import BedWars from './structures/MiniGames/BedWars.ts'; -import BlitzSurvivalGames from './structures/MiniGames/BlitzSurvivalGames.ts'; -import BuildBattle from './structures/MiniGames/BuildBattle.ts'; -import CopsAndCrims from './structures/MiniGames/CopsAndCrims.ts'; -import Duels from './structures/MiniGames/Duels.ts'; -import MegaWalls from './structures/MiniGames/MegaWalls.ts'; -import MurderMystery from './structures/MiniGames/MurderMystery.ts'; -import Paintball from './structures/MiniGames/Paintball.ts'; -import Pit from './structures/MiniGames/Pit.ts'; -import Quakecraft from './structures/MiniGames/Quakecraft.ts'; -import SkyWars from './structures/MiniGames/SkyWars.ts'; -import SmashHeroes from './structures/MiniGames/SmashHeroes.ts'; -import SpeedUHC from './structures/MiniGames/SpeedUHC.ts'; -import TNTGames from './structures/MiniGames/TNTGames.ts'; -import TurboKartRacers from './structures/MiniGames/TurboKartRacers.ts'; -import UHC from './structures/MiniGames/UHC.ts'; -import VampireZ from './structures/MiniGames/VampireZ.ts'; -import Walls from './structures/MiniGames/Walls.ts'; -import Warlords from './structures/MiniGames/Warlords.ts'; -import WoolWars from './structures/MiniGames/WoolWars.ts'; -import Leaderboard from './structures/Leaderboard.ts'; -import ServerInfo from './structures/ServerInfo.ts'; -import Utils from './utils'; +import Booster from './structures/Boosters/Booster'; +import House from './structures/House'; +import Arcade from './structures/MiniGames/Arcade'; +import ArenaBrawl from './structures/MiniGames/ArenaBrawl'; +import BedWars from './structures/MiniGames/BedWars'; +import BlitzSurvivalGames from './structures/MiniGames/BlitzSurvivalGames'; +import BuildBattle from './structures/MiniGames/BuildBattle'; +import CopsAndCrims from './structures/MiniGames/CopsAndCrims'; +import Duels from './structures/MiniGames/Duels'; +import MegaWalls from './structures/MiniGames/MegaWalls'; +import MurderMystery from './structures/MiniGames/MurderMystery'; +import Paintball from './structures/MiniGames/Paintball'; +import Pit from './structures/MiniGames/Pit'; +import Quakecraft from './structures/MiniGames/Quakecraft'; +import SkyWars from './structures/MiniGames/SkyWars'; +import SmashHeroes from './structures/MiniGames/SmashHeroes'; +import SpeedUHC from './structures/MiniGames/SpeedUHC'; +import TNTGames from './structures/MiniGames/TNTGames'; +import TurboKartRacers from './structures/MiniGames/TurboKartRacers'; +import UHC from './structures/MiniGames/UHC'; +import VampireZ from './structures/MiniGames/VampireZ'; +import Walls from './structures/MiniGames/Walls'; +import Warlords from './structures/MiniGames/Warlords'; +import WoolWars from './structures/MiniGames/WoolWars'; +import Leaderboard from './structures/Leaderboard'; +import ServerInfo from './structures/ServerInfo'; diff --git a/src/structures/APIIncident.ts b/src/structures/APIIncident.ts new file mode 100644 index 00000000..fe7a8f77 --- /dev/null +++ b/src/structures/APIIncident.ts @@ -0,0 +1,34 @@ +const regex = /https:\/\/status.hypixel.net\/incidents\/([a-z0-9]+)/; +/** + * API incident class + */ +class APIIncident { + link: string | null; + start: Date | null; + startFormatted: string | null; + startTimestamp: number | null; + author: string | null; + HTMLContent: string; + snippet: string | null; + guid: string | null; + categories: string[]; + isResolved: boolean; + constructor(data: Record) { + this.link = data.link || null; + this.start = data.pubDate ? new Date(data.pubDate) : null; + this.startFormatted = data.pubDate || null; + this.startTimestamp = new Date(data.pubDate).getTime() || null; + this.author = data.creator || null; + this.HTMLContent = data.content; + this.snippet = data.contentSnippet || null; + const match = data.guid ? regex.exec(data.guid) : null; + this.guid = match ? match[1] : null; + this.categories = data.categories || []; + this.isResolved = this.HTMLContent.includes('Resolved -') || this.HTMLContent.includes('Completed -'); + } + toString(): string { + return this.HTMLContent; + } +} + +export default APIIncident; diff --git a/src/structures/APIStatus.ts b/src/structures/APIStatus.ts new file mode 100644 index 00000000..780bca6a --- /dev/null +++ b/src/structures/APIStatus.ts @@ -0,0 +1,24 @@ +import APIIncident from './APIIncident'; +/** + * API status class + */ +class APIStatus { + sourceUrl: string | null; + title: string | null; + description: string | null; + incidents: APIIncident[]; + currentIncidents: APIIncident[]; + constructor(data: Record) { + this.sourceUrl = data.feedUrl || null; + this.title = data.title || null; + this.description = data.description || null; + this.incidents = data.items.map((x: any) => new APIIncident(x)); + this.currentIncidents = this.incidents.filter((i) => !i.isResolved); + } + + toString(): string | null { + return this.title; + } +} + +export default APIStatus; diff --git a/src/structures/Boosters/Booster.ts b/src/structures/Boosters/Booster.ts new file mode 100644 index 00000000..1daeb53c --- /dev/null +++ b/src/structures/Boosters/Booster.ts @@ -0,0 +1,43 @@ +import Game from '../Game'; + +function parseType(data: Record): 'STACKED' | 'QUEUED' | 'ACTIVE' { + if (true === data.stacked) return 'STACKED'; + if (!data.stacked) return 'QUEUED'; + return 'ACTIVE'; +} + +/** + * Booster class + */ +class Booster { + purchaser: string; + amount: number; + originalLength: number; + remaining: number; + activatedTimestamp: number; + activated: Date; + game: Game | null; + isActive: boolean; + type: 'STACKED' | 'QUEUED' | 'ACTIVE'; + stackers: string[]; + expired: boolean; + constructor(data: Record) { + this.purchaser = data.purchaserUuid; + this.amount = data.amount; + this.originalLength = data.originalLength; + this.remaining = data.length; + this.activatedTimestamp = data.dateActivated; + this.activated = new Date(data.dateActivated); + this.game = data.gameType ? new Game(data.gameType) : null; + this.isActive = Array.isArray(data.stacked); + this.type = parseType(data); + this.stackers = Array.isArray(data.stacked) ? Array.from(data.stacked) : []; + this.expired = 0 > data.length; + } + + toString(): string { + return `${this.purchaser}'s booster in ${this.game}`; + } +} + +export default Booster; diff --git a/src/structures/Color.ts b/src/structures/Color.ts index 8f80e88b..b1483066 100644 --- a/src/structures/Color.ts +++ b/src/structures/Color.ts @@ -61,10 +61,6 @@ class Color { this.color = color; } - /** - * Returns regular color name - * @return {ColorString} - */ toString(): string { return ColorStrings[this.color]; } diff --git a/src/structures/Game.ts b/src/structures/Game.ts index 26f97ce4..52f9f198 100644 --- a/src/structures/Game.ts +++ b/src/structures/Game.ts @@ -1,5 +1,5 @@ import { GameCode, GameID, GameString } from '../typings'; -import { games } from '../utils/Constants'; +import Constants from '../utils/Constants'; /** * Game class @@ -13,7 +13,7 @@ class Game { constructor(game: GameID | GameCode) { this.game = game; - const result = games.find( + const result = Constants.games.find( (g) => g.code.toLowerCase() === this.game || g.id.toString() === this.game || g.name.toLowerCase() === this.game ) as any; this.id = result ? result.id : null; @@ -26,15 +26,15 @@ class Game { return this.name; } static get IDS(): GameID[] { - return games.map((x) => x.id as GameID); + return Constants.games.map((x) => x.id as GameID); } static get CODES(): GameCode[] { - return games.map((x) => x.code) as GameCode[]; + return Constants.games.map((x) => x.code) as GameCode[]; } static get NAMES(): GameString[] { - return games.map((x) => x.name) as GameString[]; + return Constants.games.map((x) => x.name) as GameString[]; } } diff --git a/src/structures/GameCounts.ts b/src/structures/GameCounts.ts new file mode 100644 index 00000000..92b9ba77 --- /dev/null +++ b/src/structures/GameCounts.ts @@ -0,0 +1,28 @@ +import { recursive, removeSnakeCaseString } from '../utils/removeSnakeCase'; +import Constants from '../utils/Constants'; + +/** + * GameCounts class + */ +class GameCounts { + [x: string]: object | number; + constructor(data: Record) { + this.playerCount = data.playerCount; + for (const game in data.games) { + if (Object.prototype.hasOwnProperty.call(Constants.MiniGamesString, game)) { + const objectName = (Constants.MiniGamesString as { [key: string]: string })[game] + .toUpperCase() + .replace(/ +/g, '_'); + this[removeSnakeCaseString(objectName)] = recursive(data.games[game], true); + } else { + this[removeSnakeCaseString(game)] = recursive(data.games[game], true); + } + } + } + + toString(): number { + return this.playerCount as number; + } +} + +export default GameCounts; diff --git a/src/structures/Guild/Guild.ts b/src/structures/Guild/Guild.ts index 54c0f979..adf2e1be 100644 --- a/src/structures/Guild/Guild.ts +++ b/src/structures/Guild/Guild.ts @@ -65,4 +65,4 @@ class Guild { } } -module.exports = Guild; +export default Guild; diff --git a/src/structures/House.ts b/src/structures/House.ts new file mode 100644 index 00000000..a48bfa10 --- /dev/null +++ b/src/structures/House.ts @@ -0,0 +1,27 @@ +/** + * House class + */ +class House { + name: string; + uuid: string; + owner: string; + createdAtTimestamp: number; + createdAt: Date; + players: number; + cookies: number; + constructor(data: Record) { + this.name = data.name || ''; + this.uuid = data.uuid || ''; + this.owner = data.owner || ''; + this.createdAtTimestamp = data.createdAt || 0; + this.createdAt = new Date(this.createdAtTimestamp); + this.players = data.players || 0; + this.cookies = data.cookies?.current || 0; + } + + toString(): string { + return this.name; + } +} + +export default House; diff --git a/src/structures/ItemBytes.ts b/src/structures/ItemBytes.ts new file mode 100644 index 00000000..997b4f47 --- /dev/null +++ b/src/structures/ItemBytes.ts @@ -0,0 +1,20 @@ +import { decode } from '../utils/SkyblockUtils'; + +/** + * Item Bytes class + */ +class ItemBytes { + bytesBuffer: Buffer; + constructor(data: Record) { + this.bytesBuffer = Buffer.from(JSON.stringify(data), 'base64'); + } + + base64(): string { + return this.bytesBuffer.toString('base64'); + } + + async readNBT(): Promise { + return await decode(this.bytesBuffer, true); + } +} +export default ItemBytes; diff --git a/src/structures/Leaderboard.ts b/src/structures/Leaderboard.ts new file mode 100644 index 00000000..e9744b7c --- /dev/null +++ b/src/structures/Leaderboard.ts @@ -0,0 +1,17 @@ +/** + * Leaderboard class + */ +class Leaderboard { + name: string | null; + title: string; + playerCount: string; + leaders: string[]; + constructor(data: Record) { + this.name = data.prefix || null; + this.title = data.title || null; + this.playerCount = data.count || 0; + this.leaders = data.leaders || []; + } +} + +export default Leaderboard; diff --git a/src/structures/MiniGames/Arcade.ts b/src/structures/MiniGames/Arcade.ts new file mode 100644 index 00000000..ebd85b93 --- /dev/null +++ b/src/structures/MiniGames/Arcade.ts @@ -0,0 +1,511 @@ +// IMPORTANT : a lot of the properties from the API seem to be nonsense + +import { removeSnakeCaseString } from '../../utils/removeSnakeCase'; +import { weekAB, monthAB } from '../../utils/oscillation'; +import divide from '../../utils/divide'; + +function parseZombiesKills(data: Record): Record { + const matches = Array.from(Object.keys(data)) + .map((x) => x.match(/^([A-Za-z]+)_zombie_kills_zombies$/)) + .filter((x) => x); + // From entries might be broken + return Object.fromEntries(matches.map((x) => [removeSnakeCaseString(x[1]), data[x[0]] || 0])); +} +/** + * Zombies - Stats by Map + Difficulty + */ +class ZombiesStats { + bestRound: number; + deaths: number; + doorsOpened: number; + fastestRound10: number; + fastestRound20: number; + fastestRound30: number; + playersRevived: number; + timesKnockedDown: number; + roundsSurvived: number; + windowsRepaired: number; + wins: number; + zombieKills: number; + constructor(data: Record, type: string = '') { + if (type) type = `_${type}`; + this.bestRound = data[`best_round_zombies${type}`] || 0; + this.deaths = data[`deaths_zombies${type}`] || 0; + this.doorsOpened = data[`doors_opened_zombies${type}`] || 0; + this.fastestRound10 = data[`fastest_time_10_zombies${type}_normal`] || 0; + this.fastestRound20 = data[`fastest_time_20_zombies${type}_normal`] || 0; + this.fastestRound30 = data[`fastest_time_30_zombies${type}_normal`] || 0; + this.playersRevived = data[`players_revived_zombies${type}`] || 0; + this.timesKnockedDown = data[`times_knocked_down_zombies${type}`] || 0; + this.roundsSurvived = data[`total_rounds_survived_zombies${type}`] || 0; + this.windowsRepaired = data[`windows_repaired_zombies${type}`] || 0; + this.wins = data[`wins_zombies${type}`] || 0; + this.zombieKills = data[`zombie_kills_zombies${type}`] || 0; + } +} + +/** + * Zombies - Overall stats + */ +class Zombies { + overall: ZombiesStats; + deadEnd: ZombiesStats; + badBlood: ZombiesStats; + alienArcadium: ZombiesStats; + prison: ZombiesStats; + killsByZombie: Record; + bulletsHit: number; + bulletsShot: number; + gunAccuracy: number; + headshots: number; + headshotAccuracy: number; + constructor(data: Record) { + this.overall = new ZombiesStats(data); + this.deadEnd = new ZombiesStats(data, 'deadend'); + this.badBlood = new ZombiesStats(data, 'badblood'); + this.alienArcadium = new ZombiesStats(data, 'alienarcadium'); + this.prison = new ZombiesStats(data, 'prison'); + this.killsByZombie = parseZombiesKills(data); + this.bulletsHit = data.bullets_hit_zombies || 0; + this.bulletsShot = data.bullets_shot_zombies || 0; + this.gunAccuracy = divide(this.bulletsHit, this.bulletsShot); + this.headshots = data.headshots_zombies || 0; + this.headshotAccuracy = divide(this.headshots, this.bulletsShot); + } +} + +/** + * Dropper stats by map + */ +class DropperMap { + bestTime: number; + completions: number; + constructor(data: Record, mapName: string) { + this.bestTime = data?.[mapName]?.best_time ?? 0; + this.completions = data?.[mapName]?.completions ?? 0; + } +} + +/** + * Blocking Dead class + */ +class BlockingDead { + wins: number; + kills: number; + headshots: number; + constructor(data: Record) { + this.wins = data.wins_dayone || 0; + this.kills = data.kills_dayone || 0; + this.headshots = data.headshots_dayone || 0; + } +} +/** + * Bounty Hunters class + */ +class BountyHunters { + wins: number; + kills: number; + deaths: number; + KDRatio: number; + bountyKills: number; + bowKills: number; + swordKills: number; + constructor(data: Record) { + this.wins = data.wins_oneinthequiver || 0; + this.kills = data.kills_oneinthequiver || 0; + this.deaths = data.deaths_oneinthequiver || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.bountyKills = data.bounty_kills_oneinthequiver || 0; + this.bowKills = data.bow_kills_oneinthequiver || 0; + this.swordKills = data.sword_kills_oneinthequiver || 0; + } +} +/** + * Capture The Wool class + */ +class CaptureTheWool { + wins: number; + losses: number; + WLRatio: number; + draws: number; + kills: number; + deaths: number; + KDRatio: number; + assists: number; + woolPickedUp: number; + woolCaptured: number; + fastestWin: number; + longestGame: number; + constructor(data: Record) { + this.wins = data.woolhunt_participated_wins || 0; + this.losses = data.woolhunt_participated_losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.draws = data.woolhunt_participated_draws || 0; + this.kills = data.woolhunt_kills || 0; + this.deaths = data.woolhunt_deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.assists = data.woolhunt_assists || 0; + this.woolPickedUp = data.woolhunt_wools_stolen || 0; + this.woolCaptured = data.woolhunt_wools_captured || 0; + this.fastestWin = data.woolhunt_fastest_win || 0; + this.longestGame = data.woolhunt_longest_game || 0; + } +} +/** + * Dragon Wars class + */ +class DragonWars { + wins: number; + kills: number; + constructor(data: Record) { + this.wins = data.wins_dragonwars2 || 0; + this.kills = data.kills_dragonwars2 || 0; + } +} +/** + * Dropper class + */ +class Dropper { + wins: number; + fails: number; + fastestGame: number; + flawlessGames: number; + gamesPlayed: number; + mapsCompleted: number; + gamesFinished: number; + maps: Record; + constructor(data: Record) { + this.wins = data?.wins ?? 0; + this.fails = data?.fails ?? 0; + this.fastestGame = data?.fastest_game ?? 0; + this.flawlessGames = data?.flawless_games ?? 0; + this.gamesPlayed = data?.games_played ?? 0; + this.mapsCompleted = data?.maps_completed ?? 0; + this.gamesFinished = data?.games_finished ?? 0; + this.maps = {}; + Object.keys(data?.map_stats ?? {}).forEach((map) => { + this.maps[map] = new DropperMap(data?.map_stats, map); + }); + } +} +/** + * Ender Spleef class + */ +class EnderSpleef { + wins: number; + kills: number; + trail: string; + blocksDestroyed: number; + bigShotActivations: number; + tripleShotActivations: number; + totalPowerUpActivations: number; + constructor(data: Record) { + this.wins = data.wins_ender || 0; + this.kills = data.kills_dragonwars2 || 0; + this.trail = data.enderspleef_trail || ''; + this.blocksDestroyed = data.blocks_destroyed_ender || 0; + this.bigShotActivations = data.bigshot_powerup_activations_ender || 0; + this.tripleShotActivations = data.tripleshot_powerup_activations_ender || 0; + this.totalPowerUpActivations = this.bigShotActivations + this.tripleShotActivations; + } +} +/** + * Farm Hunt class + */ +class FarmHunt { + wins: number; + winsAsAnimal: number; + winsAsHunter: number; + kills: number; + killsAsAnimal: number; + killsAsHunter: number; + tauntsUsed: number; + riskyTauntsUsed: number; + safeTauntsUsed: number; + dangerousTauntsUsed: number; + fireworkTauntsUsed: number; + poop: number; + constructor(data: Record) { + this.wins = data.wins_farm_hunt || 0; + this.winsAsAnimal = data.animal_wins_farm_hunt || 0; + this.winsAsHunter = data.hunter_wins_farm_hunt || 0; + this.kills = data.kills_farm_hunt || 0; + this.killsAsAnimal = data.animal_kills_farm_hunt || 0; + this.killsAsHunter = data.hunter_kills_farm_hunt || 0; + this.tauntsUsed = data.taunts_used_farm_hunt || 0; + this.riskyTauntsUsed = data.risky_taunts_used_farm_hunt || 0; + this.safeTauntsUsed = data.safe_taunts_used_farm_hunt || 0; + this.dangerousTauntsUsed = data.dangerous_taunts_used_farm_hunt || 0; + this.fireworkTauntsUsed = data.firework_taunts_used_farm_hunt || 0; + this.poop = (data.poop_collected_farm_hunt || 0) + (data.poop_collected || 0); + } +} +/** + * Football class + */ +class Football { + wins: number; + goals: number; + kicks: number; + powerKicks: number; + constructor(data: Record) { + this.wins = data.wins_soccer || 0; + this.goals = data.goals_soccer || 0; + this.kicks = data.kicks_soccer || 0; + this.powerKicks = data.powerkicks_soccer || 0; + } +} +/** + * Galxy Wars + */ +class GalaxyWars { + wins: number; + kills: number; + deaths: number; + shotsFired: number; + weeklyKills: number; + monthlyKills: number; + attackerKills: number; + defenderKills: number; + constructor(data: Record) { + this.wins = data.sw_game_wins || 0; + this.kills = data.sw_kills || 0; + this.deaths = data.sw_deaths || 0; + this.shotsFired = data.sw_shots_fired || 0; + this.weeklyKills = parseInt(data[`weekly_kills_${weekAB()}`] || 0, 10); + this.monthlyKills = parseInt(data[`monthly_kills_${monthAB()}`] || 0, 10); + this.attackerKills = data.sw_rebel_kills || 0; + this.defenderKills = data.sw_empire_kills || 0; + } +} +/** + * Party Popper Stats (Sub gamemode of Hide and Seek) + */ +class PartyPopper { + winsAsSeeker: number; + winsAsHider: number; + wins: number; + constructor(data: Record) { + this.winsAsSeeker = data.party_pooper_seeker_wins_hide_and_seek || 0; + this.winsAsHider = data.party_pooper_hider_wins_hide_and_seek || 0; + this.wins = this.winsAsSeeker + this.winsAsHider; + } +} +/** + * Prop Hunt Stats (Sub gamemode of Hide and Seek) + */ +class PropHunt { + winsAsSeeker: number; + winsAsHider: number; + wins: number; + constructor(data: Record) { + this.winsAsSeeker = data.prop_hunt_seeker_wins_hide_and_seek || 0; + this.winsAsHider = data.prop_hunt_hider_wins_hide_and_seek || 0; + this.wins = this.winsAsSeeker + this.winsAsHider; + } +} +/** + * Hide And Seek Stats + */ +class HideAndSeek { + partyPopper: PartyPopper; + propHunt: PropHunt; + winsAsSeeker: number; + winsAsHider: number; + constructor(data: Record) { + this.partyPopper = new PartyPopper(data); + this.propHunt = new PropHunt(data); + this.winsAsSeeker = data.seeker_wins_hide_and_seek || 0; + this.winsAsHider = data.hider_wins_hide_and_seek || 0; + } +} +/** + * Hide And Seek Stats + */ +class HoleInTheWall { + wins: number; + rounds: number; + scoreRecordFinals: number; + scoreRecordNormal: number; + scoreRecordOverall: number; + constructor(data: Record) { + this.wins = data.wins_hole_in_the_wall || 0; + this.rounds = data.rounds_hole_in_the_wall || 0; + this.scoreRecordFinals = data.hitw_record_f || 0; + this.scoreRecordNormal = data.hitw_record_q || 0; + this.scoreRecordOverall = this.scoreRecordFinals + this.scoreRecordNormal; + } +} +/** + * Hypixel Says Stats + */ +class HypixelSays { + wins: number; + rounds: number; + roundWins: number; + topScore: number; + constructor(data: Record) { + this.wins = data.wins_simon_says || 0; + this.rounds = data.rounds_simon_says || 0; + this.roundWins = data.round_wins_simon_says || 0; + this.topScore = data.top_score_simon_says || 0; + } +} +/** + * Mini Walls class + */ +class MiniWalls { + kit: string; + wins: number; + kills: number; + deaths: number; + KDRatio: number; + finalKills: number; + witherKills: number; + witherDamage: number; + arrowsShot: number; + arrowsHit: number; + bowAccuracy: number; + constructor(data: Record) { + this.kit = data.miniWalls_activeKit || ''; + this.wins = data.wins_mini_walls || 0; + this.kills = data.kills_mini_walls || 0; + this.deaths = data.deaths_mini_walls || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.finalKills = data.final_kills_mini_walls || 0; + this.witherKills = data.wither_kills_mini_walls || 0; + this.witherDamage = data.wither_damage_mini_walls || 0; + this.arrowsShot = data.arrows_shot_mini_walls || 0; + this.arrowsHit = data.arrows_hit_mini_walls || 0; + this.bowAccuracy = divide(this.arrowsHit, this.arrowsShot); + } +} +/** + * Party Games class + */ +class PartyGames { + wins: number; + roundWins: number; + stars: number; + constructor(data: Record) { + this.wins = data.wins_party || 0; + this.roundWins = data.round_wins_party || 0; + this.stars = data.total_stars_party || 0; + } +} +/** + * Pixel Party Game Mode + */ +class PixelPartyGameMode { + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + roundsPlayed: number; + powerUpsCollected: number; + constructor(data: Record, modeName: string) { + this.wins = data?.[`wins_${modeName}`] || 0; + this.gamesPlayed = data?.[`games_played_${modeName}`] || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.roundsPlayed = data?.[`rounds_completed_${modeName}`] || 0; + this.powerUpsCollected = data?.[`power_ups_collected_${modeName}`] || 0; + } +} +/** + * Party Games class + */ +class PixelParty { + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + roundsPlayed: number; + powerUpsCollected: number; + normal: PixelPartyGameMode; + hyper: PixelPartyGameMode; + highestRound: number; + musicVolume: number; + colorBlind: object; + constructor(data: Record) { + this.wins = data?.pixel_party?.wins || 0; + this.gamesPlayed = data?.pixel_party?.games_played || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.roundsPlayed = data?.pixel_party?.rounds_completed || 0; + this.powerUpsCollected = data?.pixel_party?.power_ups_collected || 0; + this.normal = new PixelPartyGameMode(data.pixel_party, 'normal'); + this.hyper = new PixelPartyGameMode(data.pixel_party, 'hyper'); + this.highestRound = data?.pixel_party?.highest_round || 0; + this.musicVolume = data.pixel_party_music_volume || 0; + this.colorBlind = data.pixelparty || {}; + } +} +/** + * Throw Out class + */ +class ThrowOut { + wins: number; + kills: number; + deaths: number; + KDRatio: number; + constructor(data: Record) { + this.wins = data.wins_throw_out || 0; + this.kills = data.kills_throw_out || 0; + this.deaths = data.deaths_throw_out || 0; + this.KDRatio = divide(this.kills, this.deaths); + } +} +/** + * Arcade class + */ +class Arcade { + coins: number; + weeklyCoins: number; + monthlyCoins: number; + hintsDisabled: boolean; + flashDisabled: boolean; + blockingDead: BlockingDead; + bountyHunters: BountyHunters; + captureTheWool: CaptureTheWool; + dragonWars: DragonWars; + dropper: Dropper; + enderSpleef: EnderSpleef; + farmHunt: FarmHunt; + football: Football; + galaxyWars: GalaxyWars; + hideAndSeek: HideAndSeek; + holeInTheWall: HoleInTheWall; + hypixelSays: HypixelSays; + miniWalls: MiniWalls; + partyGames: PartyGames; + pixelParty: PixelParty; + throwOut: ThrowOut; + zombies: Zombies; + constructor(data: Record = {}) { + this.coins = data.coins || 0; + this.weeklyCoins = parseInt(data[`weekly_coins_${weekAB()}`] || 0, 10); + this.monthlyCoins = parseInt(data[`monthly_coins_${monthAB()}`] || 0, 10); + this.hintsDisabled = !data.hints; + this.flashDisabled = !data.flash; + this.blockingDead = new BlockingDead(data); + this.bountyHunters = new BountyHunters(data); + this.captureTheWool = new CaptureTheWool(data); + this.dragonWars = new DragonWars(data); + this.dropper = new Dropper(data.dropper); + this.enderSpleef = new EnderSpleef(data); + this.farmHunt = new FarmHunt(data); + this.football = new Football(data); + this.galaxyWars = new GalaxyWars(data); + this.hideAndSeek = new HideAndSeek(data); + this.holeInTheWall = new HoleInTheWall(data); + this.hypixelSays = new HypixelSays(data); + this.miniWalls = new MiniWalls(data); + this.partyGames = new PartyGames(data); + this.pixelParty = new PixelParty(data); + this.throwOut = new ThrowOut(data); + this.zombies = new Zombies(data); + } +} + +export default Arcade; diff --git a/src/structures/MiniGames/ArenaBrawl.ts b/src/structures/MiniGames/ArenaBrawl.ts new file mode 100644 index 00000000..6032be30 --- /dev/null +++ b/src/structures/MiniGames/ArenaBrawl.ts @@ -0,0 +1,90 @@ +import divide from '../../utils/divide'; + +class ArenaBrawlMode { + damage: number; + kills: number; + deaths: number; + KDRatio: number; + healed: number; + wins: number; + losses: number; + WLRatio: number; + games: number; + winstreak: number; + constructor(data: Record, mode: string) { + this.damage = data[`damage_${mode}`]; + this.kills = data[`kills_${mode}`]; + this.deaths = data[`deaths_${mode}`]; + this.KDRatio = divide(this.kills, this.deaths); + this.healed = data[`healed_${mode}`]; + this.wins = data[`wins_${mode}`]; + this.losses = data[`losses_${mode}`]; + this.WLRatio = divide(this.wins, this.losses); + this.games = data[`games_${mode}`]; + this.winstreak = data[`win_streaks_${mode}`]; + } +} + +/** + * ArenaBrawl class + */ +class ArenaBrawl { + coins: number; + coinsSpent: number; + wins: number; + keys: number; + chests: number; + rune: string; + '1v1': ArenaBrawlMode; + '2v2': ArenaBrawlMode; + '4v4': ArenaBrawlMode; + constructor(data: Record) { + /** + * Coins + * @type {number} + */ + this.coins = data.coins || 0; + /** + * Coins Spent + * @type {number} + */ + this.coinsSpent = data.coins_spent || 0; + /** + * Wins + * @type {number} + */ + this.wins = data.wins || 0; + /** + * Keys + * @type {number} + */ + this.keys = data.keys || 0; + /** + * Chests + * @type {number} + */ + this.chests = data.magical_chest || 0; + /** + * Rune + * @type {string} + */ + this.rune = data.active_rune || ''; + /** + * ArenaBrawl mode stats + * @type {ArenaBrawlMode} + */ + this['1v1'] = new ArenaBrawlMode(data, '1v1'); + /** + * ArenaBrawl mode stats + * @type {ArenaBrawlMode} + */ + this['2v2'] = new ArenaBrawlMode(data, '2v2'); + /** + * ArenaBrawl mode stats + * @type {ArenaBrawlMode} + */ + this['4v4'] = new ArenaBrawlMode(data, '4v4'); + } +} + +export default ArenaBrawl; diff --git a/src/structures/MiniGames/BedWars.ts b/src/structures/MiniGames/BedWars.ts new file mode 100644 index 00000000..c5ab6e9a --- /dev/null +++ b/src/structures/MiniGames/BedWars.ts @@ -0,0 +1,322 @@ +import { + BedWarsCollectedItems, + BedWarsPracticeStats, + BedwarsDreamStats, + BedWarsModeStats, + BedWarsPrestige, + BedWarsBeds, + BedWarsAvg +} from '../../typings'; +import divide from '../../utils/divide'; + +function generateStatsForMode(data: Record, mode: string): BedWarsModeStats { + return { + winstreak: data[`${mode}_winstreak`] || 0, + playedGames: data[`${mode}_games_played_bedwars`] || 0, + + kills: data[`${mode}_kills_bedwars`] || 0, + deaths: data[`${mode}_deaths_bedwars`] || 0, + + wins: data[`${mode}_wins_bedwars`] || 0, + losses: data[`${mode}_losses_bedwars`] || 0, + + finalKills: data[`${mode}_final_kills_bedwars`] || 0, + finalDeaths: data[`${mode}_final_deaths_bedwars`] || 0, + + beds: { + broken: data[`${mode}_beds_broken_bedwars`] || 0, + lost: data[`${mode}_beds_lost_bedwars`] || 0, + BLRatio: divide(data[`${mode}_beds_broken_bedwars`], data[`${mode}_beds_lost_bedwars`]) + }, + + avg: { + kills: divide(data[`${mode}_kills_bedwars`], data[`${mode}_games_played_bedwars`]), + finalKills: divide(data[`${mode}_final_kills_bedwars`], data[`${mode}_games_played_bedwars`]), + bedsBroken: divide(data[`${mode}_beds_broken_bedwars`], data[`${mode}_games_played_bedwars`]) + }, + + KDRatio: divide(data[`${mode}_kills_bedwars`], data[`${mode}_deaths_bedwars`]), + WLRatio: divide(data[`${mode}_wins_bedwars`], data[`${mode}_losses_bedwars`]), + finalKDRatio: divide(data[`${mode}_final_kills_bedwars`], data[`${mode}_final_deaths_bedwars`]) + }; +} + +function getBedWarsPrestige(level: number): BedWarsPrestige | string { + if (5000 <= level) return 'Eternal'; + return ( + [ + 'Stone', + 'Iron', + 'Gold', + 'Diamond', + 'Emerald', + 'Sapphire', + 'Ruby', + 'Crystal', + 'Opal', + 'Amethyst', + 'Rainbow', + 'Iron Prime', + 'Gold Prime', + 'Diamond Prime', + 'Emerald Prime', + 'Sapphire Prime', + 'Ruby Prime', + 'Crystal Prime', + 'Opal Prime', + 'Amethyst Prime', + 'Mirror', + 'Light', + 'Dawn', + 'Dusk', + 'Air', + 'Wind', + 'Nebula', + 'Thunder', + 'Earth', + 'Water', + 'Fire', + 'Sunrise', + 'Eclipse', + 'Gamma', + 'Majestic', + 'Andesine', + 'Marine', + 'Element', + 'Galaxy', + 'Atomic', + 'Sunset', + 'Time', + 'Winter', + 'Obsidian', + 'Spring', + 'Ice', + 'Summer', + 'Spinel', + 'Autumn', + 'Mystic', + 'Eternal' + ][Math.floor(level / 100)] || 'Eternal' + ); +} +const EASY_LEVELS = 4; +const EASY_LEVELS_XP = 7000; +const XP_PER_PRESTIGE = 96 * 5000 + EASY_LEVELS_XP; +const LEVELS_PER_PRESTIGE = 100; +const HIGHEST_PRESTIGE = 10; + +function getLevelRespectingPrestige(level: number) { + if (level > HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE) { + return level - HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE; + } + return level % LEVELS_PER_PRESTIGE; +} + +function getExpForLevel(level: number) { + if (0 === level) return 0; + const respectedLevel = getLevelRespectingPrestige(level); + if (respectedLevel > EASY_LEVELS) return 5000; + switch (respectedLevel) { + case 1: + return 500; + case 2: + return 1000; + case 3: + return 2000; + case 4: + return 3500; + default: { + return 5000; + } + } +} + +function getLevelForExp(exp: number) { + const prestiges = Math.floor(exp / XP_PER_PRESTIGE); + let level = prestiges * LEVELS_PER_PRESTIGE; + let expWithoutPrestiges = exp - prestiges * XP_PER_PRESTIGE; + + for (let i = 1; i <= EASY_LEVELS; ++i) { + const expForEasyLevel = getExpForLevel(i); + if (expWithoutPrestiges < expForEasyLevel) { + break; + } + level++; + expWithoutPrestiges -= expForEasyLevel; + } + return level + Math.floor(expWithoutPrestiges / 5000); +} + +function generateStatsForPractice(data: Record): BedWarsPracticeStats { + return { + selected: data?.practice?.selected || 'NONE', + bridging: { + blocksPlaced: data?.practice?.bridging?.blocks_placed ?? 0, + attempts: { + failed: data?.practice?.bridging?.failed_attempts ?? 0, + successful: data?.practice?.bridging?.successful_attempts ?? 0, + total: data?.practice?.bridging?.failed_attempts + data?.practice?.bridging?.successful_attempts + }, + records: { + blocks30: { + elevation: { + none: { + straight: data?.practice?.records?.['bridging_distance_30:elevation_NONE:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_30:elevation_NONE:angle_DIAGONAL:'] ?? 0 + }, + slight: { + straight: data?.practice?.records?.['bridging_distance_30:elevation_SLIGHT:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_30:elevation_SLIGHT:angle_DIAGONAL:'] ?? 0 + }, + staircase: { + straight: data?.practice?.records?.['bridging_distance_30:elevation_STAIRCASE:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_30:elevation_STAIRCASE:angle_DIAGONAL:'] ?? 0 + } + } + }, + blocks50: { + elevation: { + none: { + straight: data?.practice?.records?.['bridging_distance_50:elevation_NONE:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_50:elevation_NONE:angle_DIAGONAL:'] ?? 0 + }, + slight: { + straight: data?.practice?.records?.['bridging_distance_50:elevation_SLIGHT:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_50:elevation_SLIGHT:angle_DIAGONAL:'] ?? 0 + }, + staircase: { + straight: data?.practice?.records?.['bridging_distance_50:elevation_STAIRCASE:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_50:elevation_STAIRCASE:angle_DIAGONAL:'] ?? 0 + } + } + }, + blocks100: { + elevation: { + none: { + straight: data?.practice?.records?.['bridging_distance_100:elevation_NONE:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_100:elevation_NONE:angle_DIAGONAL:'] ?? 0 + }, + slight: { + straight: data?.practice?.records?.['bridging_distance_100:elevation_SLIGHT:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_100:elevation_SLIGHT:angle_DIAGONAL:'] ?? 0 + }, + staircase: { + straight: data?.practice?.records?.['bridging_distance_100:elevation_STAIRCASE:angle_STRAIGHT:'] ?? 0, + diagonal: data?.practice?.records?.['bridging_distance_100:elevation_STAIRCASE:angle_DIAGONAL:'] ?? 0 + } + } + } + } + }, + fireballJumping: { + blocksPlaced: data?.practice?.fireball_jumping?.blocks_placed ?? 0, + attempts: { + failed: data?.practice?.fireball_jumping?.failed_attempts ?? 0, + successful: data?.practice?.fireball_jumping?.successful_attempts ?? 0, + total: data?.practice?.fireball_jumping?.failed_attempts + data?.practice?.fireball_jumping?.successful_attempts + } + }, + pearlClutching: { + attempts: { + failed: data?.practice?.pearl_clutching?.failed_attempts ?? 0, + successful: data?.practice?.pearl_clutching?.successful_attempts ?? 0, + total: data?.practice?.pearl_clutching?.failed_attempts + data?.practice?.pearl_clutching?.successful_attempts + } + }, + mlg: { + blocksPlaced: data?.practice?.mlg?.blocks_placed ?? 0, + attempts: { + failed: data?.practice?.mlg?.failed_attempts ?? 0, + successful: data?.practice?.mlg?.successful_attempts ?? 0, + total: data?.practice?.mlg?.failed_attempts + data?.practice?.mlg?.successful_attempts + } + } + }; +} +/** + * BedWars class + */ +class BedWars { + tokens: number; + level: number; + experience: number; + prestige: BedWarsPrestige | string; + playedGames: number; + wins: number; + winstreak: number; + kills: number; + finalKills: number; + losses: number; + deaths: number; + finalDeaths: number; + collectedItemsTotal: BedWarsCollectedItems; + beds: BedWarsBeds; + avg: BedWarsAvg; + KDRatio: number; + finalKDRatio: number; + WLRatio: number; + solo: BedWarsModeStats; + doubles: BedWarsModeStats; + threes: BedWarsModeStats; + fours: BedWarsModeStats; + '4v4': BedWarsModeStats; + dream: BedwarsDreamStats | {}; + castle: BedWarsModeStats; + practice: BedWarsPracticeStats; + slumberTickets: number; + totalSlumberTicket: number; + constructor(data: Record) { + this.tokens = data.coins || 0; + this.level = data.Experience ? getLevelForExp(data.Experience) : 0; + this.experience = data.Experience || 0; + this.prestige = getBedWarsPrestige(getLevelForExp(data.Experience)); + this.playedGames = data.games_played_bedwars || 0; + this.wins = data.wins_bedwars || 0; + this.winstreak = data.winstreak || 0; + this.kills = data.kills_bedwars || 0; + this.finalKills = data.final_kills_bedwars || 0; + this.losses = data.losses_bedwars || 0; + this.deaths = data.deaths_bedwars || 0; + this.finalDeaths = data.final_deaths_bedwars || 0; + this.collectedItemsTotal = { + iron: data.iron_resources_collected_bedwars || 0, + gold: data.gold_resources_collected_bedwars || 0, + diamond: data.diamond_resources_collected_bedwars || 0, + emerald: data.emerald_resources_collected_bedwars || 0 + }; + this.beds = { + lost: data.beds_lost_bedwars || 0, + broken: data.beds_broken_bedwars || 0, + BLRatio: divide(data.beds_broken_bedwars, data.beds_lost_bedwars) + }; + this.avg = { + kills: divide(this.kills, this.playedGames), + finalKills: divide(this.finalKills, this.playedGames), + bedsBroken: divide(this.beds.broken, this.playedGames) + }; + this.KDRatio = divide(this.kills, this.deaths); + this.finalKDRatio = divide(this.finalKills, this.finalDeaths); + this.WLRatio = divide(this.wins, this.losses); + this.solo = generateStatsForMode(data, 'eight_one'); + this.doubles = generateStatsForMode(data, 'eight_two'); + this.threes = generateStatsForMode(data, 'four_three'); + this.fours = generateStatsForMode(data, 'four_four'); + this['4v4'] = generateStatsForMode(data, 'two_four'); + this.dream = ['ultimate', 'rush', 'armed', 'lucky', 'voidless'].reduce( + (ac, mode) => ({ + [mode]: { + doubles: generateStatsForMode(data, `eight_two_${mode}`), + fours: generateStatsForMode(data, `four_four_${mode}`) + }, + ...ac + }), + {} + ); + this.castle = generateStatsForMode(data, 'castle'); + this.practice = generateStatsForPractice(data); + this.slumberTickets = data.slumber?.tickets ?? 0; + this.totalSlumberTicket = data.slumber?.total_tickets ?? 0; + } +} + +export default BedWars; diff --git a/src/structures/MiniGames/BlitzSurvivalGames.ts b/src/structures/MiniGames/BlitzSurvivalGames.ts new file mode 100644 index 00000000..96da098a --- /dev/null +++ b/src/structures/MiniGames/BlitzSurvivalGames.ts @@ -0,0 +1,176 @@ +import divide from '../../utils/divide'; + +class BlitzSGKit { + level: number; + exp: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + arrowsShot: number; + arrowsHit: number; + bowAccuracy: number; + damage: number; + damageTaken: number; + potionsDrunk: number; + potionsThrown: number; + playTime: number; + mobsSpawned: number; + chestsOpened: number; + constructor(data: Record, kitName: string) { + this.level = data[kitName] || 0; + this.exp = data[`exp_${kitName}`] || 0; + this.kills = data[`kills_${kitName}`] || 0; + this.deaths = data[`deaths_${kitName}`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`wins_${kitName}`] || 0; + this.gamesPlayed = data[`games_played_${kitName}`] || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.arrowsShot = data[`arrows_fired_${kitName}`] || 0; + this.arrowsHit = data[`arrows_hit_${kitName}`] || 0; + this.bowAccuracy = divide(this.arrowsHit, this.arrowsShot); + this.damage = data[`damage_${kitName}`] || 0; + this.damageTaken = data[`damage_taken_${kitName}`] || 0; + this.potionsDrunk = data[`potions_drunk_${kitName}`] || 0; + this.potionsThrown = data[`potions_thrown_${kitName}`] || 0; + this.playTime = data[`time_played_${kitName}`] || 0; + this.mobsSpawned = data[`mobs_spawned_${kitName}`] || 0; + this.chestsOpened = data[`chests_opened_${kitName}`] || 0; + } +} + +/** + * Blitz SG class + */ +class BlitzSurvivalGames { + coins: number; + kills: number; + kit: string; + killsSolo: number; + killsTeams: number; + deaths: number; + KDRatio: number; + wins: number; + winsSolo: number; + winsTeam: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + arrowsShot: number; + arrowsHit: number; + bowAccuracy: number; + damage: number; + damageTaken: number; + potionsDrunk: number; + potionsThrown: number; + mobsSpawned: number; + playTime: number; + blitzUses: number; + chestsOpened: number; + archer: BlitzSGKit; + meatmaster: BlitzSGKit; + speleologist: BlitzSGKit; + baker: BlitzSGKit; + knight: BlitzSGKit; + guardian: BlitzSGKit; + scout: BlitzSGKit; + hunter: BlitzSGKit; + hypeTrain: BlitzSGKit; + fisherman: BlitzSGKit; + armorer: BlitzSGKit; + horsetamer: BlitzSGKit; + astronaut: BlitzSGKit; + troll: BlitzSGKit; + reaper: BlitzSGKit; + shark: BlitzSGKit; + reddragon: BlitzSGKit; + toxicologist: BlitzSGKit; + rogue: BlitzSGKit; + warlock: BlitzSGKit; + slimeyslime: BlitzSGKit; + jockey: BlitzSGKit; + golem: BlitzSGKit; + viking: BlitzSGKit; + shadowKnight: BlitzSGKit; + pigman: BlitzSGKit; + paladin: BlitzSGKit; + necromancer: BlitzSGKit; + florist: BlitzSGKit; + diver: BlitzSGKit; + arachnologist: BlitzSGKit; + blaze: BlitzSGKit; + wolftamer: BlitzSGKit; + tim: BlitzSGKit; + farmer: BlitzSGKit; + creepertamer: BlitzSGKit; + snowman: BlitzSGKit; + constructor(data: Record) { + this.coins = data.coins || 0; + this.kills = data.kills || 0; + this.kit = data.defaultkit || ''; + this.killsSolo = data.kills_solo_normal || 0; + this.killsTeams = data.kills_teams_normal || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.winsSolo = data.wins_solo_normal || 0; + this.winsTeam = data.wins_teams || 0; + this.gamesPlayed = data.games_played || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.arrowsShot = data.arrows_fired || 0; + this.arrowsHit = data.arrows_hit || 0; + this.bowAccuracy = divide(this.arrowsHit, this.arrowsShot); + this.damage = data.damage || 0; + this.damageTaken = data.damage_taken || 0; + this.potionsDrunk = data.potions_drunk || 0; + this.potionsThrown = data.potions_thrown || 0; + this.mobsSpawned = data.mobs_spawned || 0; + this.playTime = data.time_played || 0; + this.blitzUses = data.blitz_uses || 0; + this.chestsOpened = data.chests_opened || 0; + this.archer = new BlitzSGKit(data, 'archer'); + this.meatmaster = new BlitzSGKit(data, 'meatmaster'); + this.speleologist = new BlitzSGKit(data, 'speleologist'); + this.baker = new BlitzSGKit(data, 'baker'); + this.knight = new BlitzSGKit(data, 'knight'); + this.guardian = new BlitzSGKit(data, 'guardian'); + this.scout = new BlitzSGKit(data, 'scout'); + this.hunter = new BlitzSGKit(data, 'hunter'); + this.hypeTrain = new BlitzSGKit(data, 'hype train'); + this.fisherman = new BlitzSGKit(data, 'fisherman'); + this.armorer = new BlitzSGKit(data, 'armorer'); + this.horsetamer = new BlitzSGKit(data, 'horsetamer'); + this.astronaut = new BlitzSGKit(data, 'astronaut'); + this.troll = new BlitzSGKit(data, 'troll'); + this.reaper = new BlitzSGKit(data, 'reaper'); + this.shark = new BlitzSGKit(data, 'shark'); + this.reddragon = new BlitzSGKit(data, 'reddragon'); + this.toxicologist = new BlitzSGKit(data, 'toxicologist'); + this.rogue = new BlitzSGKit(data, 'rogue'); + this.warlock = new BlitzSGKit(data, 'warlock'); + this.slimeyslime = new BlitzSGKit(data, 'slimeyslime'); + this.jockey = new BlitzSGKit(data, 'jockey'); + this.golem = new BlitzSGKit(data, 'golem'); + this.viking = new BlitzSGKit(data, 'viking'); + this.shadowKnight = new BlitzSGKit(data, 'shadow knight'); + this.pigman = new BlitzSGKit(data, 'pigman'); + this.paladin = new BlitzSGKit(data, 'paladin'); + this.necromancer = new BlitzSGKit(data, 'necromancer'); + this.florist = new BlitzSGKit(data, 'florist'); + this.diver = new BlitzSGKit(data, 'diver'); + this.arachnologist = new BlitzSGKit(data, 'arachnologist'); + this.blaze = new BlitzSGKit(data, 'blaze'); + this.wolftamer = new BlitzSGKit(data, 'wolftamer'); + this.tim = new BlitzSGKit(data, 'tim'); + this.farmer = new BlitzSGKit(data, 'farmer'); + this.creepertamer = new BlitzSGKit(data, 'creepertamer'); + this.snowman = new BlitzSGKit(data, 'snowman'); + } +} + +export default BlitzSurvivalGames; diff --git a/src/structures/MiniGames/BuildBattle.ts b/src/structures/MiniGames/BuildBattle.ts new file mode 100644 index 00000000..4c6ef231 --- /dev/null +++ b/src/structures/MiniGames/BuildBattle.ts @@ -0,0 +1,32 @@ +import { BuildBattleWins } from '../../typings'; +import divide from '../../utils/divide'; +/** + * BuildBattle class + */ +class BuildBattle { + score: number; + totalWins: number; + games: number; + WLRatio: number; + superVotes: number; + coins: number; + totalVotes: number; + wins: BuildBattleWins; + constructor(data: Record) { + this.score = data.score || 0; + this.totalWins = data.wins || 0; + this.games = data.games_played || 0; + this.WLRatio = divide(this.totalWins, this.games); + this.superVotes = data.super_votes || 0; + this.coins = data.coins || 0; + this.totalVotes = data.total_votes || 0; + this.wins = { + solo: data.wins_solo_normal || 0, + teams: data.wins_teams_normal || 0, + pro: data.wins_solo_pro || 0, + gtb: data.wins_guess_the_build || 0 + }; + } +} + +export default BuildBattle; diff --git a/src/structures/MiniGames/CopsAndCrims.ts b/src/structures/MiniGames/CopsAndCrims.ts new file mode 100644 index 00000000..106199e4 --- /dev/null +++ b/src/structures/MiniGames/CopsAndCrims.ts @@ -0,0 +1,139 @@ +import divide from '../../utils/divide'; +/** + * Cops and crims Defusal class + */ +class CopsAndCrimsDefusal { + kills: number; + headshotKills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + roundWins: number; + shotsFired: number; + bombsDefused: number; + bombsPlanted: number; + killsAsCrim: number; + killsAsCop: number; + constructor(data: Record) { + this.kills = data.kills || 0; + this.headshotKills = data.headshot_kills || 0; + this.assists = data.assists || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.game_wins || 0; + this.gamesPlayed = data.game_plays || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.roundWins = data.round_wins || 0; + this.shotsFired = data.shots_fired || 0; + this.bombsDefused = data.bombs_defused || 0; + this.bombsPlanted = data.bombs_planted || 0; + this.killsAsCrim = data.criminal_kills || 0; + this.killsAsCop = data.cop_kills || 0; + } +} +/** + * Cops and crims Deathmatch class + */ +class CopsAndCrimsDeathmatch { + kills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + killsAsCrim: number; + killsAsCop: number; + constructor(data: Record) { + this.kills = data.kills_deathmatch || 0; + this.assists = data.assists_deathmatch || 0; + this.deaths = data.deaths_deathmatch || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.game_wins_deathmatch || 0; + this.gamesPlayed = data.game_plays_deathmatch || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.killsAsCrim = data.criminal_kills_deathmatch || 0; + this.killsAsCop = data.cop_kills_deathmatch || 0; + } +} +/** + * Cops and crims Gun Game class + */ +class CopsAndCrimsGunGame { + kills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + killsAsCrim: number; + killsAsCop: number; + fastestWin: number; + constructor(data: Record) { + this.kills = data.kills_gungame || 0; + this.assists = data.assists_gungame || 0; + this.deaths = data.deaths_gungame || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.game_wins_gungame || 0; + this.gamesPlayed = data.game_plays_gungame || 0; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.killsAsCrim = data.criminal_kills_gungame || 0; + this.killsAsCop = data.cop_kills_gungame || 0; + this.fastestWin = data.fastest_win_gungame || 0; + } +} +/** + * Cops and crims class + */ +class CopsAndCrims { + defusal: CopsAndCrimsDefusal; + deathmath: CopsAndCrimsDeathmatch; + gunGame: CopsAndCrimsGunGame; + coins: number; + kills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + gamesPlayed: number; + losses: number; + WLRatio: number; + killsAsCrim: number; + killsAsCop: number; + prefixColor: string; + showPrefix: boolean; + selectedPrefix: string; + killsInPrefix: boolean; + constructor(data: Record) { + this.defusal = new CopsAndCrimsDefusal(data); + this.deathmath = new CopsAndCrimsDeathmatch(data); + this.gunGame = new CopsAndCrimsGunGame(data); + this.coins = data.coins || 0; + this.kills = this.defusal.kills + this.deathmath.kills + this.gunGame.kills; + this.assists = this.defusal.assists + this.deathmath.assists + this.gunGame.assists; + this.deaths = this.defusal.deaths + this.deathmath.deaths + this.gunGame.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = this.defusal.wins + this.deathmath.wins + this.gunGame.wins; + this.gamesPlayed = this.defusal.gamesPlayed + this.deathmath.gamesPlayed + this.gunGame.gamesPlayed; + this.losses = this.gamesPlayed - this.wins; + this.WLRatio = divide(this.wins, this.losses); + this.killsAsCrim = this.defusal.killsAsCrim + this.deathmath.killsAsCrim + this.gunGame.killsAsCrim; + this.killsAsCop = this.defusal.killsAsCop + this.deathmath.killsAsCop + this.gunGame.killsAsCop; + this.prefixColor = data.lobbyPrefixColor || ''; + this.showPrefix = data.show_lobby_prefix || false; + this.selectedPrefix = data.selected_lobby_prefix || ''; + this.killsInPrefix = data.show_kills_in_prefix || false; + } +} + +export default CopsAndCrims; diff --git a/src/structures/MiniGames/Duels.ts b/src/structures/MiniGames/Duels.ts new file mode 100644 index 00000000..17f01a2f --- /dev/null +++ b/src/structures/MiniGames/Duels.ts @@ -0,0 +1,475 @@ +import Constants from '../../utils/Constants'; +import romanize from '../../utils/romanize'; +import divide from '../../utils/divide'; + +function getTitle(data: Record, mode: string | null = null): string { + for (const div of Constants.duelsDivisions.slice().reverse()) { + const prestige = data[`${mode ? mode : 'all_modes'}_${div.key}_title_prestige`]; + if (prestige) { + return `${div.name} ${romanize(prestige)}`; + } + } + return ''; +} + +class DuelsGamemode { + title: string; + winstreak: number; + bestWinstreak: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + blocksPlaced: number; + healthRegenerated: number; + goldenApplesEatan: number; + constructor(data: Record, mode: string, title: string = '') { + this.title = title; + this.winstreak = data[`current_winstreak_mode_${mode}`] || 0; + this.bestWinstreak = data[`best_winstreak_mode_${mode}`] || 0; + this.kills = data[`${mode}_kills`] || 0; + this.deaths = data[`${mode}_deaths`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`${mode}_wins`] || 0; + this.losses = data[`${mode}_losses`] || 0; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = data[`${mode}_rounds_played`] || 0; + this.swings = data[`${mode}_melee_swings`] || 0; + this.hits = data[`${mode}_melee_hits`] || 0; + this.meleeAccuracy = divide(this.swings, this.hits); + this.bowShots = data[`${mode}_bow_shots`] || 0; + this.bowHits = data[`${mode}_bow_hits`] || 0; + this.bowAccuracy = divide(this.bowShots, this.bowHits); + this.blocksPlaced = data[`${mode}_blocks_placed`] || 0; + this.healthRegenerated = data[`${mode}_health_regenerated`] || 0; + this.goldenApplesEatan = data[`${mode}_golden_apples_eaten`] || 0; + } +} + +class DuelsUHC { + title: string; + winstreak: number; + bestWinstreak: number; + solo: DuelsGamemode; + doubles: DuelsGamemode; + fours: DuelsGamemode; + deathmatch: DuelsGamemode; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + blocksPlaced: number; + healthRegenerated: number; + goldenApplesEatan: number; + constructor(data: Record) { + this.title = getTitle(data, 'uhc'); + this.winstreak = data.current_uhc_winstreak || 0; + this.bestWinstreak = data.best_uhc_winstreak || 0; + this.solo = new DuelsGamemode(data, 'uhc_duel', this.title); + this.doubles = new DuelsGamemode(data, 'uhc_doubles', this.title); + this.fours = new DuelsGamemode(data, 'uhc_four', this.title); + this.deathmatch = new DuelsGamemode(data, 'uhc_meetup', this.title); + this.kills = this.solo.kills + this.doubles.kills + this.fours.kills + this.deathmatch.kills; + this.deaths = this.solo.deaths + this.doubles.deaths + this.fours.deaths + this.deathmatch.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = this.solo.wins + this.doubles.wins + this.fours.wins + this.deathmatch.wins; + this.losses = this.solo.losses + this.doubles.losses + this.fours.losses + this.deathmatch.losses; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = + this.solo.playedGames + this.doubles.playedGames + this.fours.playedGames + this.deathmatch.playedGames; + this.swings = this.solo.swings + this.doubles.swings + this.fours.swings + this.deathmatch.swings; + this.hits = this.solo.hits + this.doubles.hits + this.fours.hits + this.deathmatch.hits; + this.meleeAccuracy = divide(this.hits, this.swings); + this.bowShots = this.solo.bowShots + this.doubles.bowShots + this.fours.bowShots + this.deathmatch.bowShots; + this.bowHits = this.solo.bowHits + this.doubles.bowHits + this.fours.bowHits + this.deathmatch.bowHits; + this.bowAccuracy = divide(this.bowHits, this.bowShots); + this.blocksPlaced = + this.solo.blocksPlaced + this.doubles.blocksPlaced + this.fours.blocksPlaced + this.deathmatch.blocksPlaced; + this.healthRegenerated = + this.solo.healthRegenerated + + this.doubles.healthRegenerated + + this.fours.healthRegenerated + + this.deathmatch.healthRegenerated; + this.goldenApplesEatan = + this.solo.goldenApplesEatan + + this.doubles.goldenApplesEatan + + this.fours.goldenApplesEatan + + this.deathmatch.goldenApplesEatan; + } +} +class DuelsSkyWars { + title: string; + winstreak: number; + bestWinstreak: number; + solo: DuelsGamemode; + doubles: DuelsGamemode; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + blocksPlaced: number; + healthRegenerated: number; + goldenApplesEatan: number; + constructor(data: Record) { + this.title = getTitle(data, 'sw'); + this.winstreak = data.current_sw_winstreak || 0; + this.bestWinstreak = data.best_sw_winstreak || 0; + this.solo = new DuelsGamemode(data, 'sw_duel', this.title); + this.doubles = new DuelsGamemode(data, 'sw_doubles', this.title); + this.kills = this.solo.kills + this.doubles.kills; + this.deaths = this.solo.deaths + this.doubles.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = this.solo.wins + this.doubles.wins; + this.losses = this.solo.losses + this.doubles.losses; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = this.solo.playedGames + this.doubles.playedGames; + this.swings = this.solo.swings + this.doubles.swings; + this.hits = this.solo.hits + this.doubles.hits; + this.meleeAccuracy = divide(this.hits, this.swings); + this.bowShots = this.solo.bowShots + this.doubles.bowShots; + this.bowHits = this.solo.bowHits + this.doubles.bowHits; + this.bowAccuracy = divide(this.bowHits, this.bowShots); + this.blocksPlaced = this.solo.blocksPlaced + this.doubles.blocksPlaced; + this.healthRegenerated = this.solo.healthRegenerated + this.doubles.healthRegenerated; + this.goldenApplesEatan = this.solo.goldenApplesEatan + this.doubles.goldenApplesEatan; + } +} +class DuelsMegaWalls { + title: string; + winstreak: number; + bestWinstreak: number; + solo: DuelsGamemode; + doubles: DuelsGamemode; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + blocksPlaced: number; + healthRegenerated: number; + goldenApplesEatan: number; + constructor(data: Record) { + this.title = getTitle(data, 'mega_walls'); + this.winstreak = data.current_mega_walls_winstreak || 0; + this.bestWinstreak = data.best_mega_walls_winstreak || 0; + this.solo = new DuelsGamemode(data, 'mw_duel', this.title); + this.doubles = new DuelsGamemode(data, 'mw_doubles', this.title); + this.kills = this.solo.kills + this.doubles.kills; + this.deaths = this.solo.deaths + this.doubles.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = this.solo.wins + this.doubles.wins; + this.losses = this.solo.losses + this.doubles.losses; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = this.solo.playedGames + this.doubles.playedGames; + this.swings = this.solo.swings + this.doubles.swings; + this.hits = this.solo.hits + this.doubles.hits; + this.meleeAccuracy = divide(this.hits, this.swings); + this.bowShots = this.solo.bowShots + this.doubles.bowShots; + this.bowHits = this.solo.bowHits + this.doubles.bowHits; + this.bowAccuracy = divide(this.bowHits, this.bowShots); + this.blocksPlaced = this.solo.blocksPlaced + this.doubles.blocksPlaced; + this.healthRegenerated = this.solo.healthRegenerated + this.doubles.healthRegenerated; + this.goldenApplesEatan = this.solo.goldenApplesEatan + this.doubles.goldenApplesEatan; + } +} +class DuelsOP { + title: string; + winstreak: number; + bestWinstreak: number; + solo: DuelsGamemode; + doubles: DuelsGamemode; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + blocksPlaced: number; + healthRegenerated: number; + goldenApplesEatan: number; + constructor(data: Record) { + this.title = getTitle(data, 'op'); + this.winstreak = data.current_op_winstreak || 0; + this.bestWinstreak = data.best_op_winstreak || 0; + this.solo = new DuelsGamemode(data, 'op_duel', this.title); + this.doubles = new DuelsGamemode(data, 'op_doubles', this.title); + this.kills = this.solo.kills + this.doubles.kills; + this.deaths = this.solo.deaths + this.doubles.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = this.solo.wins + this.doubles.wins; + this.losses = this.solo.losses + this.doubles.losses; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = this.solo.playedGames + this.doubles.playedGames; + this.swings = this.solo.swings + this.doubles.swings; + this.hits = this.solo.hits + this.doubles.hits; + this.meleeAccuracy = divide(this.hits, this.swings); + this.bowShots = this.solo.bowShots + this.doubles.bowShots; + this.bowHits = this.solo.bowHits + this.doubles.bowHits; + this.bowAccuracy = divide(this.bowHits, this.bowShots); + this.blocksPlaced = this.solo.blocksPlaced + this.doubles.blocksPlaced; + this.healthRegenerated = this.solo.healthRegenerated + this.doubles.healthRegenerated; + this.goldenApplesEatan = this.solo.goldenApplesEatan + this.doubles.goldenApplesEatan; + } +} +class DuelsBridge { + title: string; + winstreak: number; + bestWinstreak: number; + solo: DuelsGamemode; + doubles: DuelsGamemode; + threes: DuelsGamemode; + fours: DuelsGamemode; + '2v2v2v2': DuelsGamemode; + '3v3v3v3': DuelsGamemode; + ctf: DuelsGamemode; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + blocksPlaced: number; + healthRegenerated: number; + goldenApplesEatan: number; + constructor(data: Record) { + this.title = getTitle(data, 'bridge'); + this.winstreak = data.current_bridge_winstreak || 0; + this.bestWinstreak = data.best_bridge_winstreak || 0; + this.solo = new DuelsGamemode(data, 'bridge_duel', this.title); + this.doubles = new DuelsGamemode(data, 'bridge_doubles', this.title); + this.threes = new DuelsGamemode(data, 'bridge_threes', this.title); + this.fours = new DuelsGamemode(data, 'bridge_fours', this.title); + this['2v2v2v2'] = new DuelsGamemode(data, '2v2v2v2', this.title); + this['3v3v3v3'] = new DuelsGamemode(data, '3v3v3v3', this.title); + this.ctf = new DuelsGamemode(data, 'capture_threes', this.title); + this.kills = + this.solo.kills + + this.doubles.kills + + this.threes.kills + + this.fours.kills + + this['2v2v2v2'].kills + + this['3v3v3v3'].kills + + this.ctf.kills; + this.deaths = + this.solo.deaths + + this.doubles.deaths + + this.threes.deaths + + this.fours.deaths + + this['2v2v2v2'].deaths + + this['3v3v3v3'].deaths + + this.ctf.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = + this.solo.wins + + this.doubles.wins + + this.threes.wins + + this.fours.wins + + this['2v2v2v2'].wins + + this['3v3v3v3'].wins + + this.ctf.wins; + this.losses = + this.solo.losses + + this.doubles.losses + + this.threes.losses + + this.fours.losses + + this['2v2v2v2'].losses + + this['3v3v3v3'].losses + + this.ctf.losses; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = + this.solo.playedGames + + this.doubles.playedGames + + this.threes.playedGames + + this.fours.playedGames + + this['2v2v2v2'].playedGames + + this['3v3v3v3'].playedGames + + this.ctf.playedGames; + this.swings = + this.solo.swings + + this.doubles.swings + + this.threes.swings + + this.fours.swings + + this['2v2v2v2'].swings + + this['3v3v3v3'].swings + + this.ctf.swings; + this.hits = + this.solo.hits + + this.doubles.hits + + this.threes.hits + + this.fours.hits + + this['2v2v2v2'].hits + + this['3v3v3v3'].hits + + this.ctf.hits; + this.meleeAccuracy = divide(this.hits, this.swings); + this.bowShots = + this.solo.bowShots + + this.doubles.bowShots + + this.threes.bowShots + + this.fours.bowShots + + this['2v2v2v2'].bowShots + + this['3v3v3v3'].bowShots + + this.ctf.bowShots; + this.bowHits = + this.solo.bowHits + + this.doubles.bowHits + + this.threes.bowHits + + this.fours.bowHits + + this['2v2v2v2'].bowHits + + this['3v3v3v3'].bowHits + + this.ctf.bowHits; + this.bowAccuracy = divide(this.bowHits, this.bowShots); + this.blocksPlaced = + this.solo.blocksPlaced + + this.doubles.blocksPlaced + + this.threes.blocksPlaced + + this.fours.blocksPlaced + + this['2v2v2v2'].blocksPlaced + + this['3v3v3v3'].blocksPlaced + + this.ctf.blocksPlaced; + this.healthRegenerated = + this.solo.healthRegenerated + + this.doubles.healthRegenerated + + this.threes.healthRegenerated + + this.fours.healthRegenerated + + this['2v2v2v2'].healthRegenerated + + this['3v3v3v3'].healthRegenerated + + this.ctf.healthRegenerated; + this.goldenApplesEatan = + this.solo.goldenApplesEatan + + this.doubles.goldenApplesEatan + + this.threes.goldenApplesEatan + + this.fours.goldenApplesEatan + + this['2v2v2v2'].goldenApplesEatan + + this['3v3v3v3'].goldenApplesEatan + + this.ctf.goldenApplesEatan; + } +} + +/** + * Duels class + */ +class Duels { + tokens: number; + title: string | null; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + winstreak: number; + bestWinstreak: number; + ping: number; + blocksPlaced: number; + swings: number; + hits: number; + meleeAccuracy: number; + bowShots: number; + bowHits: number; + bowAccuracy: number; + healthRegenerated: number; + goldenApplesEatan: number; + uhc: DuelsUHC; + skywars: DuelsSkyWars; + megawalls: DuelsMegaWalls; + blitz: DuelsGamemode; + op: DuelsOP; + classic: DuelsGamemode; + bow: DuelsGamemode; + noDebuff: DuelsGamemode; + combo: DuelsGamemode; + bowSpleef: DuelsGamemode; + sumo: DuelsGamemode; + bridge: DuelsBridge; + parkour: DuelsGamemode; + arena: DuelsGamemode; + constructor(data: Record) { + this.tokens = data.coins || 0; + this.title = getTitle(data); + this.kills = data.kills || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = data.games_played_duels || 0; + this.winstreak = data.current_winstreak || 0; + this.bestWinstreak = data.best_overall_winstreak || 0; + this.ping = data.pingPreference || 0; + this.blocksPlaced = data.blocks_placed || 0; + this.swings = data.melee_swings || 0; + this.hits = data.melee_hits || 0; + this.meleeAccuracy = divide(this.hits, this.swings); + this.bowShots = data.bow_shots || 0; + this.bowHits = data.bow_hits || 0; + this.bowAccuracy = divide(this.bowHits, this.bowShots); + this.healthRegenerated = data.health_regenerated || 0; + this.goldenApplesEatan = data.golden_apples_eaten || 0; + this.uhc = new DuelsUHC(data); + this.skywars = new DuelsSkyWars(data); + this.megawalls = new DuelsMegaWalls(data); + this.blitz = new DuelsGamemode(data, 'blitz_duel', getTitle(data, 'blitz')); + this.op = new DuelsOP(data); + this.classic = new DuelsGamemode(data, 'classic_duel', getTitle(data, 'classic')); + this.bow = new DuelsGamemode(data, 'bow_duel', getTitle(data, 'bow')); + this.noDebuff = new DuelsGamemode(data, 'potion_duel', getTitle(data, 'no_debuff')); + this.combo = new DuelsGamemode(data, 'combo_duel', getTitle(data, 'combo')); + this.bowSpleef = new DuelsGamemode(data, 'bowspleef_duel', getTitle(data, 'tnt_games')); + this.sumo = new DuelsGamemode(data, 'sumo_duel', getTitle(data, 'sumo')); + this.bridge = new DuelsBridge(data); + this.parkour = new DuelsGamemode(data, 'parkour_eight', getTitle(data, 'parkour')); + this.arena = new DuelsGamemode(data, 'duel_arena'); + } +} + +export default Duels; diff --git a/src/structures/MiniGames/MegaWalls.ts b/src/structures/MiniGames/MegaWalls.ts new file mode 100644 index 00000000..ed2c13c9 --- /dev/null +++ b/src/structures/MiniGames/MegaWalls.ts @@ -0,0 +1,199 @@ +import divide from '../../utils/divide'; + +class MegaWallsModeStats { + kills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + finalKills: number; + finalAssists: number; + finalDeaths: number; + finalKDRatio: number; + playedGames: number; + witherDamage: number; + defenderKills: number; + walked: number; + blocksPlaced: number; + blocksBroken: number; + meleeKills: number; + damageDealt: number; + constructor(data: Record, mode: string, kit?: string) { + if (kit) kit = `${kit}_`; + this.kills = data[`${kit}kills_${mode}`] || 0; + this.assists = data[`${kit}assists_${mode}`] || 0; + this.deaths = data[`${kit}deaths_${mode}`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`${kit}wins_${mode}`] || 0; + this.losses = data[`${kit}losses_${mode}`] || 0; + this.WLRatio = divide(this.wins, this.losses); + this.finalKills = data[`${kit}final_kills_${mode}`] || 0; + this.finalAssists = data[`${kit}final_assists_${mode}`] || 0; + this.finalDeaths = data[`${kit}final_deaths_${mode}`] || 0; + this.finalKDRatio = divide(this.finalKills, this.finalDeaths); + this.playedGames = data[`${kit}games_played_${mode}`] || 0; + this.witherDamage = data[`${kit}wither_damage_${mode}`] || 0; + this.defenderKills = data[`${kit}defender_kills_${mode}`] || 0; + this.walked = data[`${kit}meters_walked_${mode}`] || 0; + this.blocksPlaced = data[`${kit}blocks_placed_${mode}`] || 0; + this.blocksBroken = data[`${kit}blocks_broken_${mode}`] || 0; + this.meleeKills = data[`${kit}kills_melee_${mode}`] || 0; + this.damageDealt = data[`${kit}damage_dealt_${mode}`] || 0; + } +} +class MegaWallsKitStats { + kills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + finalKills: number; + finalAssists: number; + finalDeaths: number; + finalKDRatio: number; + playedGames: number; + witherDamage: number; + defenderKills: number; + walked: number; + blocksPlaced: number; + blocksBroken: number; + meleeKills: number; + damageDealt: number; + faceOff: MegaWallsModeStats; + casualBrawl: MegaWallsModeStats; + constructor(data: Record, kit: string) { + this.kills = data[`${kit}_kills`] || 0; + this.assists = data[`${kit}_assists`] || 0; + this.deaths = data[`${kit}_deaths`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`${kit}_wins`] || 0; + this.losses = data[`${kit}_losses`] || 0; + this.WLRatio = divide(this.wins, this.losses); + this.finalKills = data[`${kit}_final_kills`] || 0; + this.finalAssists = data[`${kit}_final_assists`] || 0; + this.finalDeaths = data[`${kit}_final_deaths`] || 0; + this.finalKDRatio = divide(this.finalKills, this.finalDeaths); + this.playedGames = data[`${kit}_games_played`] || 0; + this.witherDamage = data[`${kit}_wither_damage`] || 0; + this.defenderKills = data[`${kit}_defender_kills`] || 0; + this.walked = data[`${kit}_meters_walked`] || 0; + this.blocksPlaced = data[`${kit}_blocks_placed`] || 0; + this.blocksBroken = data[`${kit}_blocks_broken`] || 0; + this.meleeKills = data[`${kit}_kills_melee`] || 0; + this.damageDealt = data[`${kit}_damage_dealt`] || 0; + this.faceOff = new MegaWallsModeStats(data, 'face_off', kit); + this.casualBrawl = new MegaWallsModeStats(data, 'gvg', kit); + } +} + +/** + * MegaWalls class + */ +class MegaWalls { + selectedClass: string | null; + coins: number; + kills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + finalKills: number; + finalAssists: number; + finalDeaths: number; + finalKDRatio: number; + playedGames: number; + witherDamage: number; + defenderKills: number; + walked: number; + blocksPlaced: number; + blocksBroken: number; + meleeKills: number; + damageDealt: number; + faceOff: MegaWallsModeStats; + casualBrawl: MegaWallsModeStats; + cow: MegaWallsKitStats; + hunter: MegaWallsKitStats; + shark: MegaWallsKitStats; + arcanist: MegaWallsKitStats; + deadlord: MegaWallsKitStats; + golem: MegaWallsKitStats; + herobrine: MegaWallsKitStats; + pigman: MegaWallsKitStats; + zombie: MegaWallsKitStats; + blaze: MegaWallsKitStats; + enderman: MegaWallsKitStats; + shaman: MegaWallsKitStats; + squid: MegaWallsKitStats; + creeper: MegaWallsKitStats; + pirate: MegaWallsKitStats; + sheep: MegaWallsKitStats; + skeleton: MegaWallsKitStats; + spider: MegaWallsKitStats; + werewolf: MegaWallsKitStats; + angel: MegaWallsKitStats; + assassin: MegaWallsKitStats; + automaton: MegaWallsKitStats; + moleman: MegaWallsKitStats; + phoenix: MegaWallsKitStats; + renegade: MegaWallsKitStats; + snowman: MegaWallsKitStats; + constructor(data: Record) { + this.selectedClass = data.chosen_class || null; + this.coins = data.coins || 0; + this.kills = data.kills || 0; + this.assists = data.assists || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.finalKills = (data.final_kills || 0) + (data.finalkills || 0); + this.finalAssists = (data.final_assists || 0) + (data.finalassists || 0); + this.finalDeaths = (data.final_deaths || 0) + (data.finalDeaths || 0); + this.finalKDRatio = divide(this.finalKills, this.finalDeaths); + this.playedGames = data.games_played || 0; + this.witherDamage = (data.wither_damage || 0) + (data.witherDamager || 0); + this.defenderKills = data.defender_kills || 0; + this.walked = data.meters_walked || 0; + this.blocksPlaced = data.blocks_placed || 0; + this.blocksBroken = data.blocks_broken || 0; + this.meleeKills = data.kills_melee || 0; + this.damageDealt = data.damage_dealt || 0; + this.faceOff = new MegaWallsModeStats(data, 'face_off'); + this.casualBrawl = new MegaWallsModeStats(data, 'gvg'); + this.cow = new MegaWallsKitStats(data, 'cow'); + this.hunter = new MegaWallsKitStats(data, 'hunter'); + this.shark = new MegaWallsKitStats(data, 'shark'); + this.arcanist = new MegaWallsKitStats(data, 'arcanist'); + this.deadlord = new MegaWallsKitStats(data, 'deadlord'); + this.golem = new MegaWallsKitStats(data, 'golem'); + this.herobrine = new MegaWallsKitStats(data, 'herobrine'); + this.pigman = new MegaWallsKitStats(data, 'pigman'); + this.zombie = new MegaWallsKitStats(data, 'zombie'); + this.blaze = new MegaWallsKitStats(data, 'blaze'); + this.enderman = new MegaWallsKitStats(data, 'enderman'); + this.shaman = new MegaWallsKitStats(data, 'shaman'); + this.squid = new MegaWallsKitStats(data, 'squid'); + this.creeper = new MegaWallsKitStats(data, 'creeper'); + this.pirate = new MegaWallsKitStats(data, 'pirate'); + this.sheep = new MegaWallsKitStats(data, 'sheep'); + this.skeleton = new MegaWallsKitStats(data, 'skeleton'); + this.spider = new MegaWallsKitStats(data, 'spider'); + this.werewolf = new MegaWallsKitStats(data, 'werewolf'); + this.angel = new MegaWallsKitStats(data, 'angel'); + this.assassin = new MegaWallsKitStats(data, 'assassin'); + this.automaton = new MegaWallsKitStats(data, 'automaton'); + this.moleman = new MegaWallsKitStats(data, 'moleman'); + this.phoenix = new MegaWallsKitStats(data, 'phoenix'); + this.renegade = new MegaWallsKitStats(data, 'renegade'); + this.snowman = new MegaWallsKitStats(data, 'snowman'); + } +} + +export default MegaWalls; diff --git a/src/structures/MiniGames/MurderMystery.ts b/src/structures/MiniGames/MurderMystery.ts new file mode 100644 index 00000000..5de106ef --- /dev/null +++ b/src/structures/MiniGames/MurderMystery.ts @@ -0,0 +1,93 @@ +import divide from '../../utils/divide'; + +/** + * MurderMystery stats by gamemode + */ +class MurderMysteryModeStats { + goldPickedUp: number; + kills: number; + thrownKnifeKills: number; + knifeKills: number; + bowKills: number; + trapKills: number; + deaths: number; + suicides: number; + KDRatio: number; + wins: number; + winsAsDetective: number; + winsAsMurderer: number; + winsAsHero: number; + playedGames: number; + constructor(data: Record, gamemode: string) { + this.goldPickedUp = data[`coins_pickedup_${gamemode}`] || 0; + this.kills = data[`kills_${gamemode}`] || 0; + this.thrownKnifeKills = data[`thrown_knife_kills_${gamemode}`] || 0; + this.knifeKills = data[`knife_kills_${gamemode}`] || 0; + this.bowKills = data[`bow_kills_${gamemode}`] || 0; + this.trapKills = data[`trap_kills_${gamemode}`] || 0; + this.deaths = data[`deaths_${gamemode}`] || 0; + this.suicides = data[`suicides_${gamemode}`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`wins_${gamemode}`] || 0; + this.winsAsDetective = data[`detective_wins_${gamemode}`] || 0; + this.winsAsMurderer = data[`murderer_wins_${gamemode}`] || 0; + this.winsAsHero = data[`was_hero_${gamemode}`] || 0; + this.playedGames = data[`games_${gamemode}`] || 0; + } +} + +/** + * MurderMystery class + */ +class MurderMystery { + tokens: number; + goldPickedUp: number; + playedGames: number; + kills: number; + thrownKnifeKills: number; + knifeKills: number; + trapKills: number; + bowKills: number; + killsAsMurderer: number; + deaths: number; + KDRatio: number; + winsAsMurderer: number; + winsAsDetective: number; + winsAsHero: number; + fastestWinAsMurderer: number; + fastestWinAsDetective: number; + totalTimeSurvived: number; + wins: number; + suicides: number; + classic: MurderMysteryModeStats; + assassins: MurderMysteryModeStats; + doubleUp: MurderMysteryModeStats; + infection: MurderMysteryModeStats; + constructor(data: Record) { + this.tokens = data.coins || 0; + this.goldPickedUp = data.coins_pickedup || 0; + this.playedGames = data.games || 0; + this.kills = data.kills || 0; + this.thrownKnifeKills = data.thrown_knife_kills || 0; + this.knifeKills = data.knife_kills || 0; + this.trapKills = data.trap_kills || 0; + this.bowKills = data.bow_kills || 0; + this.killsAsMurderer = data.kills_as_murderer || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.winsAsMurderer = data.murderer_wins || 0; + this.winsAsDetective = data.detective_wins || 0; + this.winsAsHero = data.was_hero || 0; + this.fastestWinAsMurderer = data.quickest_murderer_win_time_seconds || 0; + this.fastestWinAsDetective = data.quickest_detective_win_time_seconds || 0; + this.totalTimeSurvived = data.total_time_survived_seconds || 0; + this.wins = data.wins || 0; + this.suicides = data.suicides || 0; + this.classic = new MurderMysteryModeStats(data, 'MURDER_CLASSIC'); + this.assassins = new MurderMysteryModeStats(data, 'MURDER_ASSASSINS'); + this.doubleUp = new MurderMysteryModeStats(data, 'MURDER_DOUBLE_UP'); + this.infection = new MurderMysteryModeStats(data, 'MURDER_INFECTION'); + } +} + +export default MurderMystery; diff --git a/src/structures/MiniGames/Paintball.ts b/src/structures/MiniGames/Paintball.ts new file mode 100644 index 00000000..c174c198 --- /dev/null +++ b/src/structures/MiniGames/Paintball.ts @@ -0,0 +1,39 @@ +import divide from '../../utils/divide'; +/** + * Paintball class + */ +class Paintball { + coins: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + shotsFired: number; + killstreaks: number; + forceFieldTime: number; + hat: string; + adrenaline: number; + endurance: number; + fortune: number; + godfather: number; + superluck: number; + transfusion: number; + constructor(data: Record) { + this.coins = data.coins || 0; + this.kills = data.kills || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.shotsFired = data.shots_fired || 0; + this.killstreaks = data.killstreaks || 0; + this.forceFieldTime = data.forcefieldTime || 0; + this.hat = data.hat || 'None'; + this.adrenaline = data.adrenaline || 0; + this.endurance = data.endurance || 0; + this.fortune = data.fortune || 0; + this.godfather = data.godfather || 0; + this.superluck = data.superluck || 0; + this.transfusion = data.transfusion || 0; + } +} +export default Paintball; diff --git a/src/structures/MiniGames/Pit.ts b/src/structures/MiniGames/Pit.ts new file mode 100644 index 00000000..9f409850 --- /dev/null +++ b/src/structures/MiniGames/Pit.ts @@ -0,0 +1,138 @@ +import { decode } from '../../utils/SkyblockUtils'; +import PitInventoryItem from './PitInventoryItem'; +import Constants from '../../utils/Constants'; +import { PitArmor } from '../../typings'; +import divide from '../../utils/divide'; + +/** + * Pit Class + */ +class Pit { + prestige: number; + xp: number; + level: number; + kills: number; + deaths: number; + KDRatio: number; + assists: number; + maxKillStreak: number; + playtime: number; + joins: number; + damageReceived: number; + damageDealt: number; + damageRatio: number; + meleeDamageReceived: number; + meleeDamageDealt: number; + swordHits: number; + leftClicks: number; + meleeAccuracy: number; + meleeDamageRatio: number; + bowDamageReceived: number; + bowDamageDealt: number; + arrowsHit: number; + arrowsFired: number; + bowAccuracy: number; + bowDamageRatio: number; + goldenHeadsEaten: number; + getInventory: () => Promise; + getEnterChest: () => Promise; + getArmor: () => Promise; + constructor(data: Record) { + this.prestige = data.profile?.prestiges?.[data.profile?.prestiges?.length - 1].index || 0; + this.xp = data.profile?.xp || 0; + this.level = + Pit.calcLevel( + this.prestige, + 0 < this.prestige ? this.xp - Constants.pit.Prestiges[this.prestige - 1].SumXp : this.xp + ) ?? 0; + this.kills = data.pit_stats_ptl?.kills || 0; + this.deaths = data.pit_stats_ptl?.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.assists = data.pit_stats_ptl?.assists || 0; + this.maxKillStreak = data.pit_stats_ptl?.max_streak || 0; + this.playtime = (data.pit_stats_ptl?.playtime_minutes || 0) * 60; + this.joins = data.pit_stats_ptl?.joins || 0; + this.damageReceived = data.pit_stats_ptl?.damage_received || 0; + this.damageDealt = data.pit_stats_ptl?.damage_dealt || 0; + this.damageRatio = divide(this.damageDealt, this.damageReceived); + this.meleeDamageReceived = data.pit_stats_ptl?.melee_damage_received || 0; + this.meleeDamageDealt = data.pit_stats_ptl?.melee_damage_dealt || 0; + this.swordHits = data.pit_stats_ptl?.sword_hits || 0; + this.leftClicks = data.pit_stats_ptl?.left_clicks || 0; + this.meleeAccuracy = divide(this.swordHits, this.leftClicks); + this.meleeDamageRatio = divide(this.meleeDamageDealt, this.meleeDamageReceived); + this.bowDamageReceived = data.pit_stats_ptl?.bow_damage_received || 0; + this.bowDamageDealt = data.pit_stats_ptl?.bow_damage_dealt || 0; + this.arrowsHit = data.pit_stats_ptl?.arrow_hits || 0; + this.arrowsFired = data.pit_stats_ptl?.arrows_fired || 0; + this.bowAccuracy = divide(this.arrowsHit, this.arrowsFired); + this.bowDamageRatio = divide(this.bowDamageDealt, this.bowDamageReceived); + this.goldenHeadsEaten = data.pit_stats_ptl?.ghead_eaten || 0; + this.getInventory = async (): Promise => { + let inventory = data.profile.inv_contents; + if (!inventory) return []; + + try { + inventory = await decode(inventory.data); + const edited = []; + for (let i = 1; i < inventory.length; i++) { + if (!inventory[i].id) { + continue; + } + edited.push(new PitInventoryItem(inventory[i])); + } + return edited; + } catch { + return []; + } + }; + this.getEnterChest = async () => { + let chest = data.profile.inv_enderchest; + if (!chest) return []; + + try { + chest = await decode(chest.data); + const edited = []; + for (let i = 1; i < chest.length; i++) { + if (!chest[i].id) { + continue; + } + edited.push(new PitInventoryItem(chest[i])); + } + return edited; + } catch { + return []; + } + }; + this.getArmor = async () => { + const base64 = data.profile.inv_armor; + const decoded = await decode(base64.data); + const armor = { + helmet: decoded[3].id ? new PitInventoryItem(decoded[3]) : null, + chestplate: decoded[2].id ? new PitInventoryItem(decoded[2]) : null, + leggings: decoded[1].id ? new PitInventoryItem(decoded[1]) : null, + boots: decoded[0].id ? new PitInventoryItem(decoded[0]) : null + }; + return armor; + }; + } + // Credit https://github.com/PitPanda/PitPandaProduction/blob/b1971f56ea1aa8c829b722cbb33247c96591c0cb/structures/Pit.js + static calcLevel(prestige: number, xp: number): number { + const multiplier = Constants.pit.Prestiges[prestige].Multiplier; + let level = 0; + while (0 < xp && 120 > level) { + const levelXp = Constants.pit.Levels[Math.floor(level / 10)].Xp * multiplier; + if (xp >= levelXp * 10) { + xp -= levelXp * 10; + level += 10; + } else { + const gain = Math.floor(xp / levelXp); + level += gain; + xp = 0; + } + } + return level; + } +} + +export default Pit; diff --git a/src/structures/MiniGames/PitInventoryItem.ts b/src/structures/MiniGames/PitInventoryItem.ts new file mode 100644 index 00000000..dba00b76 --- /dev/null +++ b/src/structures/MiniGames/PitInventoryItem.ts @@ -0,0 +1,21 @@ +/** + * PitItem class + */ +class PitInventoryItem { + itemId: number; + count: number; + name: string | null; + lore: string | null; + loreArray: string[]; + extraAttributes: object | null; + constructor(data: Record) { + this.itemId = data.id || 0; + this.count = data.Count || 0; + this.name = data?.tag?.display?.Name ? data.tag.display.Name.toString().replace(/§([1-9]|[a-f])|§/gm, '') : null; + this.lore = data?.tag?.display?.Lore ? data.tag.display.Lore.join('\n') : null; + this.loreArray = data?.tag?.display?.Lore ?? []; + this.extraAttributes = data?.tag?.ExtraAttributes ?? null; + } +} + +export default PitInventoryItem; diff --git a/src/structures/MiniGames/Quakecraft.ts b/src/structures/MiniGames/Quakecraft.ts new file mode 100644 index 00000000..4ec8ddf4 --- /dev/null +++ b/src/structures/MiniGames/Quakecraft.ts @@ -0,0 +1,73 @@ +import divide from '../../utils/divide'; + +class QuakecraftMode { + wins: number; + kills: number; + deaths: number; + KDRatio: number; + killstreaks: number; + distanceTravelled: number; + shotsFired: number; + headshots: number; + constructor(data: Record, gamemode?: string) { + if (gamemode) gamemode = `_${gamemode}`; + this.wins = data[`wins${gamemode}`] || 0; + this.kills = data[`kills${gamemode}`] || 0; + this.deaths = data[`deaths${gamemode}`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.killstreaks = data[`killstreaks${gamemode}`] || 0; + this.distanceTravelled = data[`distance_travelled${gamemode}`] || 0; + this.shotsFired = data[`shots_fired${gamemode}`] || 0; + this.headshots = data[`headshots${gamemode}`] || 0; + } +} + +/** + * Quakecraft class + */ +class Quakecraft { + coins: number; + solo: QuakecraftMode; + teams: QuakecraftMode; + wins: number; + kills: number; + deaths: number; + KDRatio: number; + killstreaks: number; + distanceTravelled: number; + shotsFired: number; + headshots: number; + instantRespawn: boolean; + killPrefixColor: string; + showPrefix: boolean; + killSound: string; + barrel: string; + case: string; + muzzle: string; + sight: string; + trigger: string; + constructor(data: Record) { + this.coins = data.coins || 0; + this.solo = new QuakecraftMode(data); + this.teams = new QuakecraftMode(data, 'teams'); + this.wins = this.solo.wins + this.teams.wins; + this.kills = this.solo.kills + this.teams.kills; + this.deaths = this.solo.deaths + this.teams.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.killstreaks = this.solo.killstreaks + this.teams.killstreaks; + this.distanceTravelled = this.solo.distanceTravelled + this.teams.distanceTravelled; + this.shotsFired = this.solo.shotsFired + this.teams.shotsFired; + this.headshots = this.solo.headshots + this.teams.headshots; + this.instantRespawn = data.instantRespawn || false; + this.killPrefixColor = data.selectedKillPrefix || ''; + this.showPrefix = data.showKillPrefix || false; + this.killSound = data.killsound || ''; + this.barrel = data.barrel || ''; + this.case = data.case || ''; + this.muzzle = data.muzzle || ''; + this.sight = data.sight || ''; + this.trigger = data.trigger || ''; + } +} + +export default Quakecraft; diff --git a/src/structures/MiniGames/SkyWars.ts b/src/structures/MiniGames/SkyWars.ts new file mode 100644 index 00000000..44b6af65 --- /dev/null +++ b/src/structures/MiniGames/SkyWars.ts @@ -0,0 +1,298 @@ +import { removeSnakeCaseString } from '../../utils/removeSnakeCase'; +import { SkyWarsPrestige } from '../../typings'; +import divide from '../../utils/divide'; + +function getSkyWarsPrestige(level: number): SkyWarsPrestige { + if (60 <= level) return 'Mythic'; + return (['Iron', 'Iron', 'Gold', 'Diamond', 'Emerald', 'Sapphire', 'Ruby', 'Crystal', 'Opal', 'Amethyst', 'Rainbow'][ + Math.floor(level / 5) + ] || 'Iron') as SkyWarsPrestige; +} + +function getSkyWarsLevel(xp: number): number { + const totalXp = [0, 2, 7, 15, 25, 50, 100, 200, 350, 600, 1000, 1500]; + if (15000 <= xp) return Math.floor((xp - 15000) / 10000 + 12); + const level = totalXp.findIndex((x) => 0 < x * 10 - xp); + return level; +} + +function getSkyWarsLevelProgress(xp: number) { + const totalXp = [0, 2, 7, 15, 25, 50, 100, 200, 350, 600, 1000, 1500]; + const xpToNextLvl = [0, 2, 5, 8, 10, 25, 50, 100, 150, 250, 400, 500]; + let percent; + let xpToNextLevel; + let currentLevelXp = xp; + if (15000 <= xp) { + currentLevelXp -= 15000; + if (0 === currentLevelXp) return { currentLevelXp: 0, xpToNextLevel: 10000, percent: 0, xpNextLevel: 10000 }; + if (10000 < currentLevelXp) { + do { + currentLevelXp -= 10000; + } while (10000 <= currentLevelXp); + } + xpToNextLevel = 10000 - currentLevelXp; + percent = Math.round(currentLevelXp) / 100; + const percentRemaining = Math.round((100 - percent) * 100) / 100; + return { + currentLevelXp, + xpToNextLevel, + percent, + xpNextLevel: 10000, + percentRemaining + }; + } + const totalXptoNextLevel = xpToNextLvl[totalXp.findIndex((x) => 0 < x * 10 - xp)] * 10; + for (let i = 0; i < xpToNextLvl.length; i++) { + if (0 > currentLevelXp - xpToNextLvl[i] * 10) break; + currentLevelXp -= xpToNextLvl[i] * 10; + } + xpToNextLevel = totalXptoNextLevel - currentLevelXp; + percent = Math.round((currentLevelXp / totalXptoNextLevel) * 10000) / 100; + return { + currentLevelXp, + xpToNextLevel, + percent, + xpNextLevel: totalXptoNextLevel + }; +} + +class SkywarsMode { + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + constructor(data: Record, gamemode: string) { + this.kills = data[`kills_${gamemode}`] || 0; + this.deaths = data[`deaths_${gamemode}`] || 0; + this.KDRatio = divide(data.kills, data.deaths); + this.wins = data[`wins_${gamemode}`] || 0; + this.losses = data[`losses_${gamemode}`] || 0; + this.WLRatio = divide(data.wins, data.losses); + } +} +class SkywarsModeStats { + activeKit: string; + killstreak: number; + kills: number; + voidKills: number; + meleeKills: number; + bowKills: number; + mobKills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + gamesPlayed: number; + survivedPlayers: number; + chestsOpened: number; + timePlayed: number; + shard: number; + longestBowShot: number; + arrowsShot: number; + arrowsHit: number; + bowAccuracy: number; + fastestWin: number; + heads: number; + constructor(data: Record, gamemode: string) { + this.activeKit = data[`activeKit_${gamemode.toUpperCase()}`] || ''; + this.killstreak = data[`killstreak_${gamemode}`] || 0; + this.kills = data[`kills_${gamemode}`] || 0; + this.voidKills = data[`void_kills_${gamemode}`] || 0; + this.meleeKills = data[`melee_kills_${gamemode}`] || 0; + this.bowKills = data[`bow_kills_${gamemode}`] || 0; + this.mobKills = data[`mob_kills_${gamemode}`] || 0; + this.assists = data[`assists_${gamemode}`] || 0; + this.deaths = data[`deaths_${gamemode}`] || 0; + this.KDRatio = divide(data.kills, data.deaths); + this.wins = data[`wins_${gamemode}`] || 0; + this.losses = data[`losses_${gamemode}`] || 0; + this.WLRatio = divide(data.wins, data.losses); + this.gamesPlayed = data[`games_${gamemode}`] || 0; + this.survivedPlayers = data[`survived_players_${gamemode}`] || 0; + this.chestsOpened = data[`chests_opened_${gamemode}`] || 0; + this.timePlayed = data[`time_played_${gamemode}`] || 0; + this.shard = data[`shard_${gamemode}`] || 0; + this.longestBowShot = data[`longest_bow_shot_${gamemode}`] || 0; + this.arrowsShot = data[`arrows_shot_${gamemode}`] || 0; + this.arrowsHit = data[`arrows_hit_${gamemode}`] || 0; + this.bowAccuracy = divide(this.arrowsHit, this.arrowsShot); + this.fastestWin = data[`fastest_win_${gamemode}`] || 0; + this.heads = data[`heads_${gamemode}`] || 0; + } +} + +/** + * Parses SkyWars Kit + */ +class SkywarsKit { + kitData: string[] | null; + isKit: boolean; + gameMode: string; + kitType: string; + kitName: string; + constructor(kit: Record) { + this.kitData = kit.match(/^kit_([a-z]+)_([a-z]+)_([a-z]+)$/); + this.isKit = Boolean(this.kitData); + this.gameMode = this.kitData ? this.kitData[2] : ''; + this.kitType = this.kitData ? this.kitData[1] : ''; + this.kitName = removeSnakeCaseString(this.kitData ? this.kitData[3] : ''); + } +} + +/** + * Parses SkyWars Kits + */ +class SkywarsKits { + kits: SkywarsKit[]; + constructor(kits: Record) { + this.kits = kits.map((kit: any) => new SkywarsKit(kit)).filter((kit: SkywarsKit) => kit.isKit); + } + + get(gameMode: string = '', type: string = ''): SkywarsKit[] { + return this.kits.filter((kit) => kit.gameMode.startsWith(gameMode) && kit.kitType.startsWith(type)); + } +} +/** + * Skywars Packages - parses every package player has + */ +class SkywarsPackages { + rawPackages: Record; + cages: any; + kits: SkywarsKits; + achievements: any; + constructor(data: Record) { + // TODO : a lot more + this.rawPackages = data; + this.cages = this.parseCages(); + this.kits = new SkywarsKits(data); + this.achievements = this.rawPackages + .map((pkg: string) => pkg.match(/^([A-Za-z]+)_?achievement([0-9]?)$/)) + .filter((x: any) => x) + .map((x: any[]) => x.slice(1).join('')); + } + + parseCages(): string[] { + return this.rawPackages + .map((pkg: string) => pkg.match(/^cage_([A-Za-z]+)-cage$/)) + .filter((x: any) => x) + .map((x: string[]) => x[1].replace(/-[a-z]/g, (x) => x[1].toUpperCase())); + } +} +/** + * SkyWars class + */ +class SkyWars { + coins: number; + souls: number; + tokens: number; + experience: number; + level: number; + levelProgress: any; + levelFormatted: string; + prestige: SkyWarsPrestige; + opals: number; + avarice: number; + tenacity: number; + shards: number; + angelOfDeathLevel: number; + killstreak: number; + kills: number; + voidKills: number; + meleeKills: number; + bowKills: number; + mobKills: number; + assists: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + gamesPlayed: number; + survivedPlayers: number; + chestsOpened: number; + timePlayed: number; + shard: number; + longestBowShot: number; + arrowsShot: number; + arrowsHit: number; + bowAccuracy: number; + fastestWin: number; + heads: number; + blocksPlaced: number; + blocksBroken: number; + eggThrown: number; + enderpearlsThrown: number; + solo: SkywarsModeStats; + soloNormal: SkywarsMode; + soloInsane: SkywarsMode; + team: SkywarsModeStats; + teamNormal: SkywarsMode; + teamInsane: SkywarsMode; + mega: SkywarsMode; + megaDoubles: SkywarsMode; + lab: SkywarsMode; + packages: SkywarsPackages; + constructor(data: Record) { + this.coins = data.coins || 0; + this.souls = data.souls || 0; + this.tokens = data.cosmetic_tokens || 0; + this.experience = data.skywars_experience || 0; + this.level = getSkyWarsLevel(data.skywars_experience); + this.levelProgress = getSkyWarsLevelProgress(data.skywars_experience); + this.levelFormatted = data.levelFormatted + ? data.levelFormatted + .replace(/§l/gm, '**') + .replace(/§([a-f]|[1-9])/gm, '') + .replace(/§r/gm, '') + : null; + this.prestige = getSkyWarsPrestige(this.level); + this.opals = data.opals || 0; + this.avarice = data.avarice || 0; + this.tenacity = data.tenacity || 0; + this.shards = data.shard || 0; + this.angelOfDeathLevel = data.angel_of_death_level || 0; + this.killstreak = data.killstreak || 0; + this.kills = data.kills || 0; + this.voidKills = data.void_kills || 0; + this.meleeKills = data.melee_kills || 0; + this.bowKills = data.bow_kills || 0; + this.mobKills = data.mob_kills || 0; + this.assists = data.assists || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(data.kills, data.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(data.wins, data.losses); + this.gamesPlayed = data.games || 0; + this.survivedPlayers = data.survived_players || 0; + this.chestsOpened = data.chests_opened || 0; + this.timePlayed = data.time_played || 0; + this.shard = data.shard || 0; + this.longestBowShot = data.longest_bow_shot || 0; + this.arrowsShot = data.arrows_shot || 0; + this.arrowsHit = data.arrows_hit || 0; + this.bowAccuracy = divide(this.arrowsHit, this.arrowsShot); + this.fastestWin = data.fastest_win || 0; + this.heads = data.heads || 0; + this.blocksPlaced = data.blocks_placed || 0; + this.blocksBroken = data.blocks_broken || 0; + this.eggThrown = data.egg_thrown || 0; + this.enderpearlsThrown = data.enderpearls_thrown || 0; + this.solo = new SkywarsModeStats(data, 'solo'); + this.soloNormal = new SkywarsMode(data, 'solo_normal'); + this.soloInsane = new SkywarsMode(data, 'solo_insane'); + this.team = new SkywarsModeStats(data, 'team'); + this.teamNormal = new SkywarsMode(data, 'team_normal'); + this.teamInsane = new SkywarsMode(data, 'team_insane'); + this.mega = new SkywarsMode(data, 'mega'); + this.megaDoubles = new SkywarsMode(data, 'mega_doubles'); + this.lab = new SkywarsMode(data, 'lab'); + this.packages = new SkywarsPackages(data.packages || []); + } +} + +export default SkyWars; diff --git a/src/structures/MiniGames/SmashHeroes.ts b/src/structures/MiniGames/SmashHeroes.ts new file mode 100644 index 00000000..3d0d9bba --- /dev/null +++ b/src/structures/MiniGames/SmashHeroes.ts @@ -0,0 +1,117 @@ +import divide from '../../utils/divide'; + +class SmashHeroesMode { + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + constructor(data: Record, mode: string) { + this.kills = data[`kills_${mode}`] || 0; + this.deaths = data[`deaths_${mode}`] || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`wins_${mode}`] || 0; + this.losses = data[`losses_${mode}`] || 0; + this.WLRatio = divide(this.wins, this.losses); + } +} + +class SmashHeoresHero { + name: string; + level: number; + xp: number; + prestige: number; + playedGames: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + constructor(data: Record, hero: string) { + this.name = hero; + this.level = data[`lastLevel_${hero}`] || 0; + this.xp = data[`xp_${hero}`] || 0; + this.prestige = data[`pg_${hero}`] || 0; + this.playedGames = data.class_stats?.[hero]?.games || 0; + this.kills = data.class_stats?.[hero]?.kills || 0; + this.deaths = data.class_stats?.[hero]?.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.class_stats?.[hero]?.wins || 0; + this.losses = data.class_stats?.[hero]?.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + } +} + +/** + * SmashHeroes class + */ +class SmashHeroes { + coins: number; + level: number; + winstreak: number; + playedGames: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + smashed: number; + '1v1v1v1': SmashHeroesMode; + '2v2': SmashHeroesMode; + '2v2v2': SmashHeroesMode; + activeClass: string; + theBulk: SmashHeoresHero; + cakeMonster: SmashHeoresHero; + generalCluck: SmashHeoresHero; + botmun: SmashHeoresHero; + marauder: SmashHeoresHero; + pug: SmashHeoresHero; + tinman: SmashHeoresHero; + spoderman: SmashHeoresHero; + frosty: SmashHeoresHero; + sergeantShield: SmashHeoresHero; + skullfire: SmashHeoresHero; + goku: SmashHeoresHero; + sanic: SmashHeoresHero; + duskCrawler: SmashHeoresHero; + shoopDaWhoop: SmashHeoresHero; + greenHood: SmashHeoresHero; + constructor(data: Record) { + this.coins = data.coins || 0; + this.level = data.smash_level_total || 0; + this.winstreak = data.win_streak || 0; + this.playedGames = data.games || 0; + this.kills = data.kills || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.smashed = data.smashed || 0; + this['1v1v1v1'] = new SmashHeroesMode(data, 'normal'); + this['2v2'] = new SmashHeroesMode(data, '2v2'); + this['2v2v2'] = new SmashHeroesMode(data, 'teams'); + this.activeClass = data.active_class || null; + this.theBulk = new SmashHeoresHero(data, 'THE_BULK'); + this.cakeMonster = new SmashHeoresHero(data, 'CAKE_MONSTER'); + this.generalCluck = new SmashHeoresHero(data, 'GENERAL_CLUCK'); + this.botmun = new SmashHeoresHero(data, 'BOTMUN'); + this.marauder = new SmashHeoresHero(data, 'MARAUDER'); + this.pug = new SmashHeoresHero(data, 'PUG'); + this.tinman = new SmashHeoresHero(data, 'TINMAN'); + this.spoderman = new SmashHeoresHero(data, 'SPODERMAN'); + this.frosty = new SmashHeoresHero(data, 'FROSTY'); + this.sergeantShield = new SmashHeoresHero(data, 'SERGEANT_SHIELD'); + this.skullfire = new SmashHeoresHero(data, 'SKULLFIRE'); + this.goku = new SmashHeoresHero(data, 'GOKU'); + this.sanic = new SmashHeoresHero(data, 'SANIC'); + this.duskCrawler = new SmashHeoresHero(data, 'DUSK_CRAWLER'); + this.shoopDaWhoop = new SmashHeoresHero(data, 'SHOOP_DA_WHOOP'); + this.greenHood = new SmashHeoresHero(data, 'GREEN_HOOD'); + } +} + +export default SmashHeroes; diff --git a/src/structures/MiniGames/SpeedUHC.ts b/src/structures/MiniGames/SpeedUHC.ts new file mode 100644 index 00000000..fee40f2d --- /dev/null +++ b/src/structures/MiniGames/SpeedUHC.ts @@ -0,0 +1,74 @@ +import divide from '../../utils/divide'; + +class SpeedUHCMode { + kills: number; + deaths: number; + wins: number; + losses: number; + playedGames: number; + winstreak: number; + killStreak: number; + assists: number; + constructor(data: Record, mode: string) { + this.kills = data[`kills_${mode}`] || 0; + this.deaths = data[`deaths_${mode}`] || 0; + this.wins = data[`wins_${mode}`] || 0; + this.losses = data[`losses_${mode}`] || 0; + this.playedGames = data[`games_${mode}`] || 0; + this.winstreak = data[`win_streak_${mode}`] || 0; + this.killStreak = data[`killstreak_${mode}`] || 0; + this.assists = data[`assists_${mode}`] || 0; + } +} + +/** + * Speed UHC class + */ +class SpeedUHC { + coins: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + playedGames: number; + winstreak: number; + killstreak: number; + blocksBroken: number; + blocksPlaced: number; + quits: number; + itemsEnchanted: number; + assists: number; + solo: SpeedUHCMode; + soloNormal: SpeedUHCMode; + soloInsane: SpeedUHCMode; + team: SpeedUHCMode; + teamNormal: SpeedUHCMode; + teamInsane: SpeedUHCMode; + constructor(data: Record) { + this.coins = data.coins || 0; + this.kills = data.kills || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.playedGames = data.games || 0; + this.winstreak = data.win_streak || 0; + this.killstreak = data.killstreak || 0; + this.blocksBroken = data.blocks_broken || 0; + this.blocksPlaced = data.blocks_placed || 0; + this.quits = data.quits || 0; + this.itemsEnchanted = data.items_enchanted || 0; + this.assists = data.assists || 0; + this.solo = new SpeedUHCMode(data, 'solo'); + this.soloNormal = new SpeedUHCMode(data, 'solo_normal'); + this.soloInsane = new SpeedUHCMode(data, 'solo_insane'); + this.team = new SpeedUHCMode(data, 'team'); + this.teamNormal = new SpeedUHCMode(data, 'team_normal'); + this.teamInsane = new SpeedUHCMode(data, 'team_insane'); + } +} + +export default SpeedUHC; diff --git a/src/structures/MiniGames/TNTGames.ts b/src/structures/MiniGames/TNTGames.ts new file mode 100644 index 00000000..226c94f6 --- /dev/null +++ b/src/structures/MiniGames/TNTGames.ts @@ -0,0 +1,126 @@ +import divide from '../../utils/divide'; + +class TNTRun { + wins: number; + bestTime: number; + deaths: number; + slownessPotions: number; + speedPotions: number; + doubleJumps: number; + prefix: string; + constructor(data: Record) { + this.wins = data.wins_tntrun || 0; + this.bestTime = data.record_tntrun || 0; + this.deaths = data.deaths_tntrun || 0; + this.slownessPotions = data.new_tntrun_slowness_potions || 0; + this.speedPotions = data.new_tntrun_speed_potions || 0; + this.doubleJumps = data.new_tntrun_double_jumps || 0; + this.prefix = data.prefix_tntrun || ''; + } +} +class PVPRun { + wins: number; + bestTime: number; + kills: number; + deaths: number; + KDRatio: number; + regeneration: number; + notoriety: number; + fortitude: number; + doubleJumps: number; + prefix: string; + constructor(data: Record) { + this.wins = data.wins_pvprun || 0; + this.bestTime = data.record_pvprun || 0; + this.kills = data.kills_pvprun || 0; + this.deaths = data.deaths_pvprun || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.regeneration = data.new_pvprun_regeneration || 0; + this.notoriety = data.new_pvprun_notoriety || 0; + this.fortitude = data.new_pvprun_fortitude || 0; + this.doubleJumps = data.new_pvprun_double_jumps || 0; + this.prefix = data.prefix_pvprun || ''; + } +} +class BowSpleef { + wins: number; + tags: number; + deaths: number; + prefix: string; + constructor(data: Record) { + this.wins = data.wins_bowspleef || 0; + this.tags = data.tags_bowspleef || 0; + this.deaths = data.deaths_bowspleef || 0; + this.prefix = data.prefix_bowspleef || ''; + } +} +class TNTTag { + wins: number; + kills: number; + deaths: number; + KDRatio: number; + speed: number; + blastProtection: number; + speedItUp: number; + slowItDown: number; + prefix: string; + constructor(data: Record) { + this.wins = data.wins_tntag || 0; + this.kills = data.kills_tntag || 0; + this.deaths = data.deaths_tntag || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.speed = data.new_tntag_speedy || 0; + this.blastProtection = data.tag_blastprotection || 0; + this.speedItUp = data.tag_speeditup || 0; + this.slowItDown = data.tag_slowitdown || 0; + this.prefix = data.prefix_tntag || ''; + } +} +class TNTWizards { + wins: number; + kills: number; + assists: number; + deaths: number; + KDRatio: number; + points: number; + kineticHealing: number; + airTime: number; + prefix: string; + constructor(data: Record) { + this.wins = data.wins_capture || 0; + this.kills = data.kills_capture || 0; + this.assists = data.assists_capture || 0; + this.deaths = data.deaths_capture || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.points = data.points_capture || 0; + this.kineticHealing = data.kinetic_healing_capture || 0; + this.airTime = data.air_time_capture || 0; + this.prefix = data.prefix_capture || ''; + } +} + +/** + * The TNT Games class + */ +class TNTGames { + coins: number; + winstreak: number; + wins: number; + tntrun: TNTRun; + pvpRun: PVPRun; + bowSpleef: BowSpleef; + tnttag: TNTTag; + wizards: TNTWizards; + constructor(data: Record) { + this.coins = data.coins || 0; + this.winstreak = data.winstreak || 0; + this.wins = data.wins || 0; + this.tntrun = new TNTRun(data); + this.pvpRun = new PVPRun(data); + this.bowSpleef = new BowSpleef(data); + this.tnttag = new TNTTag(data); + this.wizards = new TNTWizards(data); + } +} + +export default TNTGames; diff --git a/src/structures/MiniGames/TurboKartRacers.ts b/src/structures/MiniGames/TurboKartRacers.ts new file mode 100644 index 00000000..cc099e6d --- /dev/null +++ b/src/structures/MiniGames/TurboKartRacers.ts @@ -0,0 +1,62 @@ +class TurboKartRacersMap { + map: string; + plays: number; + boxPickups: number; + bronzeTrophies: number; + silverTrophies: number; + goldTrophies: number; + constructor(data: Record, mapName: string) { + this.map = mapName; + this.plays = data[`${mapName}_plays`] || 0; + this.boxPickups = data[`box_pickups_${mapName}`] || 0; + this.bronzeTrophies = data[`bronze_trophy_${mapName}`] || 0; + this.silverTrophies = data[`silver_trophy_${mapName}`] || 0; + this.goldTrophies = data[`gold_trophy_${mapName}`] || 0; + } +} + +/** + * TurboKartRacers class + */ +class TurboKartRacers { + coins: number; + wins: number; + completedLaps: number; + bronzeTrophies: number; + silverTrophies: number; + goldTrophies: number; + boxPickups: number; + horn: 'DEFAULT' | 'SHY' | 'ALIEN' | 'TAXI' | 'KLAXON' | 'TRICYCLE' | 'ALARM' | 'KLOON' | 'TEDDY' | 'TRUCK' | 'JERRY'; + retro: TurboKartRacersMap; + hypixelgp: TurboKartRacersMap; + olympus: TurboKartRacersMap; + junglerush: TurboKartRacersMap; + canyon: TurboKartRacersMap; + bananaHitsReceived: number; + bananaHitsSent: number; + blueTorpedoHit: number; + grandPrix: boolean; + grandPrixTokens: number; + constructor(data: Record) { + this.coins = data.coins || 0; + this.wins = data.wins || 0; + this.completedLaps = data.laps_completed || 0; + this.bronzeTrophies = data.bronze_trophy || 0; + this.silverTrophies = data.silver_trophy || 0; + this.goldTrophies = data.gold_trophy || 0; + this.boxPickups = data.box_pickups || 0; + this.horn = data.horn || 'DEFAULT'; + this.retro = new TurboKartRacersMap(data, 'retro'); + this.hypixelgp = new TurboKartRacersMap(data, 'hypixelgp'); + this.olympus = new TurboKartRacersMap(data, 'olympus'); + this.junglerush = new TurboKartRacersMap(data, 'junglerush'); + this.canyon = new TurboKartRacersMap(data, 'canyon'); + this.bananaHitsReceived = data.banana_hits_received || 0; + this.bananaHitsSent = data.banana_hits_sent || 0; + this.blueTorpedoHit = data.blue_torpedo_hit || 0; + this.grandPrix = data.grand_prix || 'false'; + this.grandPrixTokens = data.grand_prix_tokens || 0; + } +} + +export default TurboKartRacers; diff --git a/src/structures/MiniGames/UHC.ts b/src/structures/MiniGames/UHC.ts new file mode 100644 index 00000000..cf6e49ec --- /dev/null +++ b/src/structures/MiniGames/UHC.ts @@ -0,0 +1,186 @@ +import divide from '../../utils/divide'; + +function getStarLevel(kills: number, wins: number) { + const sum = Number(kills) + wins * 10; + let starLevel = 1; + const sums = [0, 1, 6, 21, 46, 96, 171, 271, 521, 1021, 1321, 1621, 1921, 2221, 2521, Infinity]; + starLevel += sums.map((x) => x * 10 - sum).findIndex((x) => 0 < x) - 1; + return starLevel; +} + +class UHCGamemode { + kills: number; + deaths: number; + wins: number; + headsEaten: number; + ultimatesCrafted: number; + extraUltimatesCrafted: number; + constructor(data: Record, mode?: string) { + if (mode) mode = `_${mode}`; + /** + * @type {kills:number} + */ + this.kills = data[`kills${mode}`] || 0; + /** + * @type {deaths:number} + */ + this.deaths = data[`deaths${mode}`] || 0; + /** + * @type {wins:number} + */ + this.wins = data[`wins${mode}`] || 0; + /** + * @type {headsEaten:number} + */ + this.headsEaten = data[`heads_eaten${mode}`] || 0; + /** + * @type {ultimatesCrafted:number} + */ + this.ultimatesCrafted = data[`ultimates_crafted${mode}`] || 0; + /** + * @type {extraUltimatesCrafted:number} + */ + this.extraUltimatesCrafted = data[`extra_ultimates_crafted${mode}`] || 0; + } +} + +/** + * UHC class + */ +class UHC { + coins: number; + score: number; + kit: string; + solo: UHCGamemode; + team: UHCGamemode; + redVsBlue: UHCGamemode; + noDiamond: UHCGamemode; + brawl: UHCGamemode; + soloBrawl: UHCGamemode; + duoBrawl: UHCGamemode; + wins: number; + kills: number; + deaths: number; + KDRatio: number; + headsEaten: number; + ultimatesCrafted: number; + extraUltimatesCrafted: number; + starLevel: number; + constructor(data: Record) { + /** + * @type {coins:number} + */ + this.coins = data.coins || 0; + /** + * @type {score:number} + */ + this.score = data.score || 0; + /** + * @type {kit:string} + */ + this.kit = data.equippedKit || ''; + /** + * @type {solo:UHCGamemode} + */ + this.solo = new UHCGamemode(data, 'solo'); + /** + * @type {team:UHCGamemode} + */ + this.team = new UHCGamemode(data); + /** + * @type {redVsBlue:UHCGamemode} + */ + this.redVsBlue = new UHCGamemode(data, 'red_vs_blue'); + /** + * @type {noDiamond:UHCGamemode} + */ + this.noDiamond = new UHCGamemode(data, 'no_diamonds'); + /** + * @type {brawl:UHCGamemode} + */ + this.brawl = new UHCGamemode(data, 'brawl'); + /** + * @type {soloBrawl:UHCGamemode} + */ + this.soloBrawl = new UHCGamemode(data, 'solo_brawl'); + /** + * @type {duoBrawl:UHCGamemode} + */ + this.duoBrawl = new UHCGamemode(data, 'duo_brawl'); + /** + * @type {wins:number} + */ + this.wins = + this.solo.wins + + this.team.wins + + this.redVsBlue.wins + + this.noDiamond.wins + + this.brawl.wins + + this.soloBrawl.wins + + this.duoBrawl.wins; + /** + * @type {kills:number} + */ + this.kills = + this.solo.kills + + this.team.kills + + this.redVsBlue.kills + + this.noDiamond.kills + + this.brawl.kills + + this.soloBrawl.kills + + this.duoBrawl.kills; + /** + * @type {deaths:number} + */ + this.deaths = + this.solo.deaths + + this.team.deaths + + this.redVsBlue.deaths + + this.noDiamond.deaths + + this.brawl.deaths + + this.soloBrawl.deaths + + this.duoBrawl.deaths; + /** + * @type {KDRatio:number} + */ + this.KDRatio = divide(this.kills, this.deaths); + /** + * @type {headsEaten:number} + */ + this.headsEaten = + this.solo.headsEaten + + this.team.headsEaten + + this.redVsBlue.headsEaten + + this.noDiamond.headsEaten + + this.brawl.headsEaten + + this.soloBrawl.headsEaten + + this.duoBrawl.headsEaten; + /** + * @type {ultimatesCrafted:number} + */ + this.ultimatesCrafted = + this.solo.ultimatesCrafted + + this.team.ultimatesCrafted + + this.redVsBlue.ultimatesCrafted + + this.noDiamond.ultimatesCrafted + + this.brawl.ultimatesCrafted + + this.soloBrawl.ultimatesCrafted + + this.duoBrawl.ultimatesCrafted; + /** + * @type {extraUltimatesCrafted:number} + */ + this.extraUltimatesCrafted = + this.solo.extraUltimatesCrafted + + this.team.extraUltimatesCrafted + + this.redVsBlue.extraUltimatesCrafted + + this.noDiamond.extraUltimatesCrafted + + this.brawl.extraUltimatesCrafted + + this.soloBrawl.extraUltimatesCrafted + + this.duoBrawl.extraUltimatesCrafted; + /** + * @type {starLevel:number} + */ + this.starLevel = getStarLevel(this.kills, this.wins); + } +} +export default UHC; diff --git a/src/structures/MiniGames/VampireZ.ts b/src/structures/MiniGames/VampireZ.ts new file mode 100644 index 00000000..afc6473e --- /dev/null +++ b/src/structures/MiniGames/VampireZ.ts @@ -0,0 +1,44 @@ +import divide from '../../utils/divide'; + +class VampireZRole { + kills: number; + deaths: number; + KDRatio: number; + wins: number; + constructor(data: Record, role: string) { + this.kills = data[`${role}_kills`]; + this.deaths = data[`${role}_deaths`]; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data[`${role}_wins`]; + } +} + +/** + * VampireZ class + */ +class VampireZ { + coins: number; + goldBought: number; + blood: boolean; + zombieKills: number; + human: VampireZRole; + vampire: VampireZRole; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + constructor(data: Record) { + this.coins = data.coins || 0; + this.goldBought = data.gold_bought || 0; + this.blood = data.blood || false; + this.zombieKills = data.zombie_kills || 0; + this.human = new VampireZRole(data, 'human'); + this.vampire = new VampireZRole(data, 'vampire'); + this.kills = this.human.kills + this.vampire.kills; + this.deaths = this.human.deaths + this.vampire.deaths; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = this.human.wins + this.vampire.wins; + } +} + +export default VampireZ; diff --git a/src/structures/MiniGames/Walls.ts b/src/structures/MiniGames/Walls.ts new file mode 100644 index 00000000..99a6dbe4 --- /dev/null +++ b/src/structures/MiniGames/Walls.ts @@ -0,0 +1,26 @@ +import divide from '../../utils/divide'; +/** + * Walls class + */ +class Walls { + coins: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + assists: number; + constructor(data: Record) { + this.coins = data.coins || 0; + this.kills = data.kills || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.assists = data.assists || 0; + } +} + +export default Walls; diff --git a/src/structures/MiniGames/Warlords.ts b/src/structures/MiniGames/Warlords.ts new file mode 100644 index 00000000..6366b9b6 --- /dev/null +++ b/src/structures/MiniGames/Warlords.ts @@ -0,0 +1,82 @@ +import divide from '../../utils/divide'; + +class WarlordsClass { + wins: number; + losses: number; + WLRatio: number; + gamesPlayed: number; + damage: number; + heal: number; + damagePrevented: number; + constructor(data: Record, className: string) { + this.wins = data[`wins_${className}`] || 0; + this.losses = data[`losses_${className}`] || 0; + this.WLRatio = divide(this.wins, this.losses); + this.gamesPlayed = data[`${className}_plays`]; + this.damage = data[`damage_${className}`] || 0; + this.heal = data[`heal_${className}`] || 0; + this.damagePrevented = data[`damage_prevented_${className}`] || 0; + } +} + +/** + * Warlords class + */ +class Warlords { + coins: number; + kills: number; + deaths: number; + KDRatio: number; + wins: number; + losses: number; + WLRatio: number; + winstreak: number; + assists: number; + class: string; + pyromancer: WarlordsClass; + mage: WarlordsClass; + thunderlord: WarlordsClass; + shaman: WarlordsClass; + earthwarden: WarlordsClass; + aquamancer: WarlordsClass; + paladin: WarlordsClass; + avenger: WarlordsClass; + warrior: WarlordsClass; + defender: WarlordsClass; + cryomancer: WarlordsClass; + crusader: WarlordsClass; + berserker: WarlordsClass; + protector: WarlordsClass; + revenant: WarlordsClass; + spiritguard: WarlordsClass; + constructor(data: Record) { + this.coins = data.coins || 0; + this.kills = data.kills || 0; + this.deaths = data.deaths || 0; + this.KDRatio = divide(this.kills, this.deaths); + this.wins = data.wins || 0; + this.losses = data.losses || 0; + this.WLRatio = divide(this.wins, this.losses); + this.winstreak = data.win_streak || 0; + this.assists = data.assists || 0; + this.class = data.chosen_class || ''; + this.pyromancer = new WarlordsClass(data, 'pyromancer'); + this.mage = new WarlordsClass(data, 'mage'); + this.thunderlord = new WarlordsClass(data, 'thunderlord'); + this.shaman = new WarlordsClass(data, 'shaman'); + this.earthwarden = new WarlordsClass(data, 'earthwarden'); + this.aquamancer = new WarlordsClass(data, 'aquamancer'); + this.paladin = new WarlordsClass(data, 'paladin'); + this.avenger = new WarlordsClass(data, 'avenger'); + this.warrior = new WarlordsClass(data, 'warrior'); + this.defender = new WarlordsClass(data, 'defender'); + this.cryomancer = new WarlordsClass(data, 'cryomancer'); + this.crusader = new WarlordsClass(data, 'crusader'); + this.berserker = new WarlordsClass(data, 'berserker'); + this.protector = new WarlordsClass(data, 'protector'); + this.revenant = new WarlordsClass(data, 'revenant'); + this.spiritguard = new WarlordsClass(data, 'spiritguard'); + } +} + +export default Warlords; diff --git a/src/structures/MiniGames/WoolWars.ts b/src/structures/MiniGames/WoolWars.ts new file mode 100644 index 00000000..c72cc6c9 --- /dev/null +++ b/src/structures/MiniGames/WoolWars.ts @@ -0,0 +1,151 @@ +import { WoolWarsPrivateGamesConfig, WoolWarsStats } from '../../typings'; +import divide from '../../utils/divide'; + +function convertXPToLevel(exp: number): number { + const minimalExp = [0, 1e3, 3e3, 6e3, 1e4, 15e3]; + const baseLevel = minimalExp.length; + const baseExp = minimalExp[minimalExp.length - 1]; + const expToLevel100 = 49e4; + if (exp < baseExp) return minimalExp.findIndex((x) => exp < x); + const theoreticalLevel = (exp - baseExp) / 5e3 + baseLevel; + if (100 < theoreticalLevel) return 100 + convertXPToLevel(exp - expToLevel100); + return theoreticalLevel; +} + +function generateStatsFor(data: Record, className: string): WoolWarsStats { + const workingData = (className ? data?.classes?.[className] : data) || {}; + return { + wins: workingData.wins || 0, + gamesPlayed: workingData.games_played || 0, + woolsPlaced: workingData.wool_placed || 0, + blocksBroken: workingData.blocks_broken || 0, + placeBreakRatio: divide(workingData.wool_placed || 0, workingData.blocks_broken || 0), + kills: workingData.kills || 0, + deaths: workingData.deaths || 0, + KDRatio: divide(workingData.kills, workingData.deaths), + assists: workingData.assists || 0, + powerups: workingData.powerups_gotten || 0 + }; +} + +/** + * Wool Wars Class + */ +class WoolWars { + layers: number; + xp: number; + exactLevel: number; + level: number; + coins: number; + wins: number; + gamesPlayed: number; + woolsPlaced: number; + blocksBroken: number; + placeBreakRatio: number; + kills: number; + deaths: number; + KDRatio: number; + assists: number; + powerups: number; + selectedClass: 'ASSAULT' | 'TANK' | 'GOLEM' | 'SWORDSMAN' | 'ENGINEER' | 'ARCHER' | 'NONE'; + assault: WoolWarsStats; + tank: WoolWarsStats; + golem: WoolWarsStats; + swordsman: WoolWarsStats; + engineer: WoolWarsStats; + archer: WoolWarsStats; + ownedCosmetics: string[]; + privateGamesConfig: WoolWarsPrivateGamesConfig; + constructor(data: Record) { + /** + * Sheep layers, similar to prestige + * @type {layers:number} + */ + this.layers = data.progression?.available_layers || 0; + /** + * Wool Wars XP + * @type {xp:number} + */ + this.xp = data.progression?.experience || 0; + /** + * Wool Wars Decimal Level + * @type {exactLevel:number} + */ + this.exactLevel = convertXPToLevel(this.xp); + /** + * Wool wars level (as shown in game) + * @type {level:number} + */ + this.level = Math.floor(this.exactLevel); + /** + * Coins + * @type {coins:number} + */ + this.coins = data.coins || 0; + /** + * Wins + * @type {wins:number} + */ + this.wins = data.wins || 0; + /** + * gamesPlayed + * @type {gamesPlayed:number} + */ + this.gamesPlayed = data.games_played || 0; + /** + * woolsPlaced + * @type {woolsPlaced:number} + */ + this.woolsPlaced = data.wool_placed || 0; + /** + * blocksBroken + * @type {blocksBroken:number} + */ + this.blocksBroken = data.blocks_broken || 0; + /** + * placeBreakRatio + * @type {placeBreakRatio:number} + */ + this.placeBreakRatio = divide(this.woolsPlaced, this.blocksBroken); + /** + * kills + * @type {kills:number} + */ + this.kills = data.kills || 0; + /** + * deaths + * @type {deaths:number} + */ + this.deaths = data.deaths || 0; + /** + * KDRatio + * @type {KDRatio:number} + */ + this.KDRatio = divide(this.kills, this.deaths); + /** + * assists + * @type {assists:number} + */ + this.assists = data.assists || 0; + /** + * powerups + * @type {powerups:number} + */ + this.powerups = data.powerups_gotten || 0; + /** + * Selected class, or NONE if field isn't present in API for some reason + * @type {selectedClass:'ASSAULT'|'TANK'|'GOLEM'|'SWORDSMAN'|'ENGINEER'|'ARCHER'|'NONE'} + */ + this.selectedClass = data.wool_wars?.selected_class || 'NONE'; + this.assault = generateStatsFor(data.wool_wars?.stats, 'assault'); + this.tank = generateStatsFor(data.wool_wars?.stats, 'tank'); + this.golem = generateStatsFor(data.wool_wars?.stats, 'golem'); + this.swordsman = generateStatsFor(data.wool_wars?.stats, 'swordsman'); + this.engineer = generateStatsFor(data.wool_wars?.stats, 'engineer'); + this.archer = generateStatsFor(data.wool_wars?.stats, 'archer'); + this.ownedCosmetics = data.packages || []; + this.privateGamesConfig = data.privategames || {}; + } +} + +export default WoolWars; diff --git a/src/structures/Pet.ts b/src/structures/Pet.ts new file mode 100644 index 00000000..32abf6e2 --- /dev/null +++ b/src/structures/Pet.ts @@ -0,0 +1,41 @@ +import { recursive } from '../utils/removeSnakeCase'; + +class Pet { + isFavorite: boolean; + name: string | null; + active: boolean; + hunger: number | null; + lastFed: number | null; + lastFedAt: Date | null; + thirst: number | null; + lastDrank: number | null; + lastDrankAt: Date | null; + exercise: number | null; + lastExercised: number | null; + lastExercisedAt: Date | null; + rawNickname: string | null; + nickname: string | null; + experience: number; + + constructor(name: string, data: Record) { + this.isFavorite = data.vanityFavorites ? Boolean(data.vanityFavorites.includes(name.toUpperCase())) : false; + name = name.replace('pet_', ''); + this.name = recursive(name) || null; + this.active = data.currentPet === name.toUpperCase(); + const stats = data.petStats && data.petStats[name.toUpperCase()]; + this.hunger = stats.HUNGER ? stats.HUNGER.value : null; + this.lastFed = stats.HUNGER ? stats.HUNGER.timestamp : null; + this.lastFedAt = this.lastFed ? new Date(this.lastFed) : null; + this.thirst = stats.THIRST ? stats.THIRST.value : null; + this.lastDrank = stats.THIRST ? stats.THIRST.timestamp : null; + this.lastDrankAt = this.lastDrank ? new Date(this.lastDrank) : null; + this.exercise = stats.EXERCISE ? stats.EXERCISE.value : null; + this.lastExercised = stats.EXERCISE ? stats.EXERCISE.timestamp : null; + this.lastExercisedAt = this.lastExercised ? new Date(this.lastExercised) : null; + this.rawNickname = stats.name || null; + this.nickname = stats.name ? stats.name.replace(/§([0-9]|[a-f])|§/gm, '') : null; + this.experience = stats.experience || 0; + } +} + +export default Pet; diff --git a/src/structures/Pets.ts b/src/structures/Pets.ts new file mode 100644 index 00000000..c39c54e2 --- /dev/null +++ b/src/structures/Pets.ts @@ -0,0 +1,17 @@ +import { PetConsumables } from '../typings'; +import Pet from './Pet'; + +class Pets { + pets: Pet[]; + lastJourneyTimestamp: number | null; + lastJourneyAt: Date | null; + petConsumables: PetConsumables; + constructor(pets: string[], data: Record) { + this.pets = pets.map((x) => new Pet(x, data)); + this.lastJourneyTimestamp = data.petJourneyTimestamp || null; + this.lastJourneyAt = this.lastJourneyTimestamp ? new Date(this.lastJourneyTimestamp) : null; + this.petConsumables = data.petConsumables; + } +} + +export default Pets; diff --git a/src/structures/Player.ts b/src/structures/Player.ts new file mode 100644 index 00000000..16b1c896 --- /dev/null +++ b/src/structures/Player.ts @@ -0,0 +1,156 @@ +import { getPlayerLevel, getRank, getSocialMedia, parseClaimedRewards, playerLevelProgress } from '../utils/Player'; +import { LevelProgress, PlayerRank, PlayerSocialMedia, RanksPurchaseTime } from '../typings'; +import { recursive } from '../utils/removeSnakeCase'; +import RecentGame from './RecentGame'; +import Guild from './Guild/Guild'; +import Color from './Color'; +import Game from './Game'; +import Arcade from './MiniGames/Arcade'; +import ArenaBrawl from './MiniGames/ArenaBrawl'; +import BedWars from './MiniGames/BedWars'; +import BlitzSurvivalGames from './MiniGames/BlitzSurvivalGames'; +import BuildBattle from './MiniGames/BuildBattle'; +import CopsAndCrims from './MiniGames/CopsAndCrims'; +import Duels from './MiniGames/Duels'; +import MegaWalls from './MiniGames/MegaWalls'; +import MurderMystery from './MiniGames/MurderMystery'; +import Paintball from './MiniGames/Paintball'; +import Pit from './MiniGames/Pit'; +import Quakecraft from './MiniGames/Quakecraft'; +import SkyWars from './MiniGames/SkyWars'; +import SmashHeroes from './MiniGames/SmashHeroes'; +import SpeedUHC from './MiniGames/SpeedUHC'; +import TNTGames from './MiniGames/TNTGames'; +import TurboKartRacers from './MiniGames/TurboKartRacers'; +import UHC from './MiniGames/UHC'; +import VampireZ from './MiniGames/VampireZ'; +import Walls from './MiniGames/Walls'; +import Warlords from './MiniGames/Warlords'; +import WoolWars from './MiniGames/WoolWars'; + +class Player { + nickname: string; + uuid: string; + rank: PlayerRank; + channel: string | null; + firstLoginTimestamp: number | null; + firstLogin: Date | null; + lastLoginTimestamp: number | null; + lastLogin: Date | null; + lastLogoutTimestamp: number | null; + lastLogout: Date | null; + recentlyPlayedGame: Game | null; + plusColor: Color | null; + prefixColor: Color | null; + karma: number; + achievements: object; + achievementPoints: number; + totalExperience: number; + level: number; + socialMedia: PlayerSocialMedia[]; + giftBundlesSent: number; + giftBundlesReceived: number; + giftsSent: number; + isOnline: boolean; + lastDailyReward: Date | null; + lastDailyRewardTimestamp: number | null; + totalRewards: number | null; + totalDailyRewards: number | null; + rewardStreak: number | null; + rewardScore: number | null; + rewardHighScore: number | null; + levelProgress: LevelProgress; + guild: Guild | null; + recentGames: RecentGame[] | null; + stats: any | null; + userLanguage: string; + claimedLevelingRewards: number[]; + globalCosmetics: PlayerCosmetics | null; + ranksPurchaseTime: RanksPurchaseTime; + + constructor(data: Record, extraPayload: Record) { + this.nickname = data.displayname; + this.uuid = data.uuid; + this.rank = getRank(data); + this.channel = data.channel || null; + this.firstLoginTimestamp = data.firstLogin || null; + this.firstLogin = data.firstLogin ? new Date(data.firstLogin) : null; + this.lastLoginTimestamp = data.lastLogin || null; + this.lastLogin = data.lastLogin ? new Date(data.lastLogin) : null; + this.lastLogoutTimestamp = data.lastLogout || null; + this.lastLogout = data.lastLogout ? new Date(data.lastLogout) : null; + this.recentlyPlayedGame = data.mostRecentGameType ? new Game(data.mostRecentGameType) : null; + this.plusColor = + 'MVP+' === this.rank || 'MVP++' === this.rank + ? data.rankPlusColor + ? new Color(data.rankPlusColor) + : new Color('RED') + : null; + this.prefixColor = + 'MVP++' === this.rank ? (data.monthlyRankColor ? new Color(data.monthlyRankColor) : new Color('GOLD')) : null; + this.karma = data.karma || 0; + this.achievements = recursive(data.achievements); + this.achievementPoints = data.achievementPoints || 0; + this.totalExperience = data.networkExp || 0; + this.level = getPlayerLevel(this.totalExperience) || 0; + this.socialMedia = getSocialMedia(data.socialMedia) || []; + this.giftBundlesSent = data.giftingMeta ? data.giftingMeta.realBundlesGiven || 0 : null; + this.giftBundlesReceived = data.giftingMeta ? data.giftingMeta.realBundlesReceived || 0 : null; + this.giftsSent = data.giftingMeta ? data.giftingMeta.giftsGiven || 0 : null; + this.isOnline = + this.lastLoginTimestamp !== null && + this.lastLogoutTimestamp !== null && + this.lastLoginTimestamp > this.lastLogoutTimestamp; + this.lastDailyReward = data.lastAdsenseGenerateTime ? new Date(data.lastAdsenseGenerateTime) : null; + this.lastDailyRewardTimestamp = data.lastAdsenseGenerateTime || null; + this.totalRewards = data.totalRewards || null; + this.totalDailyRewards = data.totalDailyRewards || null; + this.rewardStreak = data.rewardStreak || null; + this.rewardScore = data.rewardScore || null; + this.rewardHighScore = data.rewardHighScore || null; + this.levelProgress = playerLevelProgress(data.networkExp); + this.guild = extraPayload?.guild || null; + this.recentGames = extraPayload?.recentGames || null; + this.stats = data.stats + ? { + arcade: data.stats.Arcade ? new Arcade({ ...data.stats.Arcade, ...data.achievements }) : null, + arena: data.stats.Arena ? new ArenaBrawl(data.stats.Arena) : null, + bedwars: data.stats.Bedwars ? new BedWars(data.stats.Bedwars) : null, + blitzsg: data.stats.HungerGames ? new BlitzSurvivalGames(data.stats.HungerGames) : null, + buildbattle: data.stats.BuildBattle ? new BuildBattle(data.stats.BuildBattle) : null, + copsandcrims: data.stats.MCGO ? new CopsAndCrims(data.stats.MCGO) : null, + duels: data.stats.Duels ? new Duels(data.stats.Duels) : null, + megawalls: data.stats.Walls3 ? new MegaWalls(data.stats.Walls3) : null, + murdermystery: data.stats.MurderMystery ? new MurderMystery(data.stats.MurderMystery) : null, + paintball: data.stats.Paintball ? new Paintball(data.stats.Paintball) : null, + pit: data.stats.Pit ? new Pit(data.stats.Pit) : null, + quakecraft: data.stats.Quake ? new Quakecraft(data.stats.Quake) : null, + skywars: data.stats.SkyWars ? new SkyWars(data.stats.SkyWars) : null, + smashheroes: data.stats.SuperSmash ? new SmashHeroes(data.stats.SuperSmash) : null, + speeduhc: data.stats.SpeedUHC ? new SpeedUHC(data.stats.SpeedUHC) : null, + tntgames: data.stats.TNTGames ? new TNTGames(data.stats.TNTGames) : null, + turbokartracers: data.stats.GingerBread ? new TurboKartRacers(data.stats.GingerBread) : null, + uhc: data.stats.UHC ? new UHC(data.stats.UHC) : null, + vampirez: data.stats.VampireZ ? new VampireZ(data.stats.VampireZ) : null, + walls: data.stats.Walls ? new Walls(data.stats.Walls) : null, + warlords: data.stats.Battleground ? new Warlords(data.stats.Battleground) : null, + woolwars: data.stats.WoolGames ? new WoolWars(data.stats.WoolGames) : null + } + : null; + this.userLanguage = data.userLanguage || 'ENGLISH'; + this.claimedLevelingRewards = parseClaimedRewards(data) || []; + this.globalCosmetics = data ? new PlayerCosmetics(data) : null; + this.ranksPurchaseTime = { + VIP: data.levelUp_VIP ? new Date(data.levelUp_VIP) : null, + VIP_PLUS: data.levelUp_VIP_PLUS ? new Date(data.levelUp_VIP_PLUS) : null, + MVP: data.levelUp_MVP ? new Date(data.levelUp_MVP) : null, + MVP_PLUS: data.levelUp_MVP_PLUS ? new Date(data.levelUp_MVP_PLUS) : null + }; + } + + toString(): string { + return this.nickname; + } +} + +export default Player; diff --git a/src/structures/PlayerCosmetics.ts b/src/structures/PlayerCosmetics.ts new file mode 100644 index 00000000..e093034a --- /dev/null +++ b/src/structures/PlayerCosmetics.ts @@ -0,0 +1,155 @@ +/* eslint-disable no-underscore-dangle */ +const { removeSnakeCaseString } = require('../utils/removeSnakeCase'); +const Pets = require('./Pets'); +/** + * Player Cosmetics class + */ +class PlayerCosmetics { + /** + * @param {object} data data + */ + constructor(data: Record) { + /** + * All cosmetics + * @type {string[]} + */ + this.allCosmetics = data?.vanityMeta?.packages || undefined; + /** + * Pets + * @type {Pets|null} + */ + this.petManager = this.allCosmetics + ? new Pets( + this.allCosmetics.filter((x) => x.startsWith('pet_')), + data + ) + : null; + } + /** + * Suits + * @type {string[]} + */ + get suits() { + if (!this._suits) { + this._suits = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('suit_')) + .map((x) => removeSnakeCaseString(x.replace('suit_', ''))) || [] + : []; + } + return this._suits; + } + /** + * Hats + * @type {string[]} + */ + get hats() { + if (!this._hats) { + this._hats = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('hat_')) + .map((x) => removeSnakeCaseString(x.replace('hat_', ''))) || [] + : []; + } + return this._hats; + } + /** + * Gadgets + * @type {string[]} + */ + get gadgets() { + if (!this._gadgets) { + this._gadgets = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('gadget_')) + .map((x) => removeSnakeCaseString(x.replace('gadget_', ''))) || [] + : []; + } + return this._gadgets; + } + /** + * Morphs + * @type {string[]} + */ + get morphs() { + if (!this._morphs) { + this._morphs = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('morph_')) + .map((x) => removeSnakeCaseString(x.replace('morph_', ''))) || [] + : []; + } + return this._morphs; + } + /** + * Cloaks + * @type {string[]} + */ + get cloaks() { + if (!this._cloaks) { + this._cloaks = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('cloak_')) + .map((x) => removeSnakeCaseString(x.replace('cloak_', ''))) || [] + : []; + } + return this._cloaks; + } + /** + * Taunts + * @type {string[]} + */ + get taunts() { + if (!this._taunts) { + this._taunts = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('taunt_')) + .map((x) => removeSnakeCaseString(x.replace('taunt_', ''))) || [] + : []; + } + return this._taunts; + } + /** + * rankColors + * @type {string[]} + */ + get rankColors() { + if (!this._rankColors) { + this._rankColors = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('rankcolor_')) + .map((x) => removeSnakeCaseString(x.replace('rankcolor_', ''))) || [] + : []; + } + return this._rankColors; + } + /** + * Particle Packs + * @type {string[]} + */ + get particlePacks() { + if (!this._particle) { + this._particle = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('particlepack_')) + .map((x) => removeSnakeCaseString(x.replace('particlepack_', ''))) || [] + : []; + } + return this._particlepacks; + } + /** + * Click Effects + * @type {string[]} + */ + get clickEffects() { + if (!this._clickfx) { + this._clickfx = this.allCosmetics + ? this.allCosmetics + .filter((x) => x.startsWith('clickeffects_')) + .map((x) => removeSnakeCaseString(x.replace('clickeffects_', ''))) || [] + : []; + } + return this._clickfx; + } +} +export default PlayerCosmetics; diff --git a/src/structures/RecentGame.ts b/src/structures/RecentGame.ts new file mode 100644 index 00000000..9305aadb --- /dev/null +++ b/src/structures/RecentGame.ts @@ -0,0 +1,27 @@ +import Game from './Game'; + +class RecentGame extends Game { + dateTimestamp: number | null; + date: Date | null; + mode: string | null; + map: string | null; + ongoing: boolean; + endedAt: Date | null; + endedTimestamp: number | null; + + constructor(data: Record) { + super(data.gameType); + this.dateTimestamp = data.date || null; + this.date = data.date ? new Date(data.date) : null; + this.mode = data.mode || null; + this.map = data.map || null; + this.ongoing = Boolean(!data.ended); + this.endedAt = data.ended ? new Date(data.ended) : null; + this.endedTimestamp = data.ended ? data.ended : null; + } + toString(): any { + return this.mode; + } +} + +export default RecentGame; diff --git a/src/structures/ServerInfo.ts b/src/structures/ServerInfo.ts new file mode 100644 index 00000000..fc6ea541 --- /dev/null +++ b/src/structures/ServerInfo.ts @@ -0,0 +1,35 @@ +import { PlayerInfo } from '../typings'; + +class ServerInfo { + protocolUsed: number; + versionInfo: string; + players: PlayerInfo; + rawMOTD: string; + cleanMOTD: string; + textMOTD: string; + faviconB64: string; + favicon: Buffer; + ping: number; + + constructor(data: Record, ping: string | number) { + this.protocolUsed = data.version.protocol || 736; + this.versionInfo = data.version.name || 'Unknown'; + this.players = { + max: data.players.max || 0, + online: data.players.online || 0, + players: data.players.sample || [], + toString: () => `${this.players.online}/${this.players.max}` + }; + this.rawMOTD = data.description || ''; + this.cleanMOTD = this.rawMOTD.replace(/§[a-z0-9]/gi, ''); + this.textMOTD = this.cleanMOTD.replace(/^\s+/gm, ''); + this.faviconB64 = data.favicon; + this.favicon = Buffer.from(this.faviconB64, 'base64'); + this.ping = parseInt(String(ping), 10); + } + toString(): string { + return `${this.textMOTD} - ${this.players} Players (${this.ping} ms) - ${this.versionInfo}`; + } +} + +export default ServerInfo; diff --git a/src/structures/SkyBlock/Auctions/Auction.ts b/src/structures/SkyBlock/Auctions/Auction.ts new file mode 100644 index 00000000..0905acdc --- /dev/null +++ b/src/structures/SkyBlock/Auctions/Auction.ts @@ -0,0 +1,46 @@ +import { SkyblockRarity } from '../../../typings'; +import BaseAuction from './BaseAuction'; +import Bid from './Bid'; + +/** + * Auction class + */ +class Auction extends BaseAuction { + coop: string[]; + auctionStartTimestamp: number | null; + auctionStart: Date | null; + auctionEnd: Date | null; + auctionEndTimestamp: number; + item: string; + itemLore: string; + itemLoreRaw: string; + rarity: SkyblockRarity; + startingBid: number; + highestBid: number; + bids: Bid[]; + claimed: boolean; + claimedBidders: string[]; + constructor(data: Record, includeItemBytes: boolean) { + super(data, includeItemBytes); + this.coop = data.coop || []; + this.auctionStartTimestamp = data.start || null; + this.auctionStart = data.start ? new Date(data.start) : null; + this.auctionEnd = data.end ? new Date(data.end) : null; + this.auctionEndTimestamp = data.end || null; + this.item = data.item_name || null; + this.itemLore = data.item_lore ? data.item_lore.replace(/§([1-9]|[a-l])|§/gm, '') : null; + this.itemLoreRaw = data.item_lore || null; + this.rarity = data.tier || null; + this.startingBid = data.starting_bid || 0; + this.highestBid = this.bin ? data.starting_bid : data.highest_bid_amount || 0; + this.bids = data.bids.length ? data.bids.map((b: any) => new Bid(b)) : []; + this.claimed = data.claimed || false; + this.claimedBidders = this.claimed ? data.claimed_bidders : []; + } + + toString(): string { + return this.item; + } +} + +export default Auction; diff --git a/src/structures/SkyBlock/Auctions/AuctionInfo.ts b/src/structures/SkyBlock/Auctions/AuctionInfo.ts new file mode 100644 index 00000000..0a9d8112 --- /dev/null +++ b/src/structures/SkyBlock/Auctions/AuctionInfo.ts @@ -0,0 +1,31 @@ +/** + * Auction info class + */ +class AuctionInfo { + page: number; + totalPages: number; + totalAuctions: number; + lastUpdatedTimestamp: number; + lastUpdatedAt: Date; + age: number; + [key: string]: any; + constructor(data: Record) { + this.page = parseInt(data.page, 10) || 0; + this.totalPages = parseInt(data.totalPages, 10) || 1; + this.totalAuctions = parseInt(data.totalAuctions, 10) || 0; + this.lastUpdatedTimestamp = data.lastUpdated; + this.lastUpdatedAt = new Date(data.lastUpdated); + this.age = parseInt(data._headers.get('age'), 10) || 0; + } + + _extend(name: any, value: any) { + this[name] = value; + return this; + } + + toString(): string { + return `${this.page} / ${this.totalPages}`; + } +} + +export default AuctionInfo; diff --git a/src/structures/SkyBlock/Auctions/BaseAuction.ts b/src/structures/SkyBlock/Auctions/BaseAuction.ts new file mode 100644 index 00000000..4940865b --- /dev/null +++ b/src/structures/SkyBlock/Auctions/BaseAuction.ts @@ -0,0 +1,25 @@ +import ItemBytes from '../../ItemBytes'; + +/** + * Base auction class + */ +class BaseAuction { + auctionId: string | null; + auctioneerUuid: string | null; + auctioneerProfile: string | null; + bin: boolean; + itemBytes: ItemBytes | null; + constructor(data: Record, includeItemBytes: boolean) { + this.auctionId = data.uuid || data.auction_id || null; + this.auctioneerUuid = data.auctioneer || data.seller || null; + this.auctioneerProfile = data.profile_id || data.seller_profile || null; + this.bin = data.bin || false; + this.itemBytes = includeItemBytes ? new ItemBytes(data.item_bytes) : null; + } + + toString(): string | null { + return this.auctionId; + } +} + +export default BaseAuction; diff --git a/src/structures/SkyBlock/Auctions/Bid.ts b/src/structures/SkyBlock/Auctions/Bid.ts new file mode 100644 index 00000000..9135a6f6 --- /dev/null +++ b/src/structures/SkyBlock/Auctions/Bid.ts @@ -0,0 +1,25 @@ +/** + * Bid class + */ +class Bid { + auctionId: string | null; + profileId: string | null; + amount: number; + timestamp: number; + at: Date | null; + bidder: string; + constructor(data: Record) { + this.auctionId = data.auction_id || null; + this.profileId = data.profile_id || null; + this.amount = data.amount || 0; + this.timestamp = data.timestamp || null; + this.at = data.timestamp ? new Date(data.timestamp) : null; + this.bidder = data.bidder || null; + } + + toString(): string { + return `${this.bidder} bid ${this.amount} coins`; + } +} + +export default Bid; diff --git a/src/structures/SkyBlock/Auctions/PartialAuction.ts b/src/structures/SkyBlock/Auctions/PartialAuction.ts new file mode 100644 index 00000000..c9eae648 --- /dev/null +++ b/src/structures/SkyBlock/Auctions/PartialAuction.ts @@ -0,0 +1,13 @@ +import BaseAuction from './BaseAuction'; + +class PartialAuction extends BaseAuction { + buyer: string | null; + price: number; + constructor(data: Record, includeItemBytes: boolean) { + super(data, includeItemBytes); + this.buyer = data.buyer || null; + this.price = parseInt(data.price, 10) || 0; + } +} + +export default PartialAuction; diff --git a/src/structures/SkyBlock/Bazzar/Order.ts b/src/structures/SkyBlock/Bazzar/Order.ts new file mode 100644 index 00000000..0e204cea --- /dev/null +++ b/src/structures/SkyBlock/Bazzar/Order.ts @@ -0,0 +1,21 @@ +/** + * Order class + */ +class Order { + amount: number; + pricePerUnit: number; + totalPrice: number; + orders: number; + constructor(data: Record) { + this.amount = data.amount || 0; + this.pricePerUnit = data.pricePerUnit || 0; + this.totalPrice = Math.round(this.amount * this.pricePerUnit * 10) / 10; + this.orders = data.orders || 0; + } + + toString(): number { + return this.totalPrice; + } +} + +export default Order; diff --git a/src/structures/SkyBlock/Bazzar/Product.ts b/src/structures/SkyBlock/Bazzar/Product.ts new file mode 100644 index 00000000..82e4ccd6 --- /dev/null +++ b/src/structures/SkyBlock/Bazzar/Product.ts @@ -0,0 +1,33 @@ +import { ProductStatus } from '../../../typings'; +import Order from './Order'; + +/** + * Product class + */ +class Product { + productId: string; + sellSummary: Order[]; + buySummary: Order[]; + status: ProductStatus; + constructor(data: Record) { + this.productId = data.product_id; + this.sellSummary = data.sell_summary.length + ? data.sell_summary.map((sellOrder: Record) => new Order(sellOrder)) + : []; + this.buySummary = data.buy_summary.length + ? data.buy_summary.map((buyOrder: Record) => new Order(buyOrder)) + : []; + this.status = { + sellPrice: isNaN(data.quick_status.sellPrice) ? 0 : Math.round(data.quick_status.sellPrice * 100) / 100, + buyPrice: isNaN(data.quick_status.buyPrice) ? 0 : Math.round(data.quick_status.buyPrice * 100) / 100, + sellVolume: isNaN(data.quick_status.sellVolume) ? 0 : data.quick_status.sellVolume, + buyVolume: isNaN(data.quick_status.buyVolume) ? 0 : data.quick_status.buyVolume, + sellMovingWeek: isNaN(data.quick_status.sellMovingWeek) ? 0 : data.quick_status.sellMovingWeek, + buyMovingWeek: isNaN(data.quick_status.buyMovingWeek) ? 0 : data.quick_status.buyMovingWeek, + sellOrders: isNaN(data.quick_status.sellOrders) ? 0 : data.quick_status.sellOrders, + buyOrders: isNaN(data.quick_status.buyOrders) ? 0 : data.quick_status.buyOrders + }; + } +} + +export default Product; diff --git a/src/structures/SkyBlock/News/SkyblockNews.ts b/src/structures/SkyBlock/News/SkyblockNews.ts new file mode 100644 index 00000000..320ba0f5 --- /dev/null +++ b/src/structures/SkyBlock/News/SkyblockNews.ts @@ -0,0 +1,37 @@ +const dateRegExp = /(\d{1,2})(?:st|nd|rd|th|) ([A-Za-z]+) (\d+)/; +const versionRegExp = /v\d+(\.\d+){1,}/; + +function parseDate(stringDate: string): Date | null { + const matched = stringDate.match(dateRegExp); + if (!matched) return null; + return new Date(matched.slice(1).join(' ')); +} + +function parseVer(stringVer: string): string | null { + const matches = versionRegExp.exec(stringVer); + if (!matches?.length) return null; + return matches[0]; +} +/** + * SkyblockNews + */ +class SkyblockNews { + title: string; + link: string; + rawDate: string; + date: Date | null; + version: string | null; + constructor(data: Record) { + this.title = data.title; + this.link = data.link; + this.rawDate = data.text; + this.date = parseDate(data.text); + this.version = parseVer(this.title); + } + + toString(): string { + return this.title; + } +} + +export default SkyblockNews; diff --git a/src/structures/SkyBlock/PlayerBingo.ts b/src/structures/SkyBlock/PlayerBingo.ts new file mode 100644 index 00000000..686328e7 --- /dev/null +++ b/src/structures/SkyBlock/PlayerBingo.ts @@ -0,0 +1,27 @@ +import { populateGoals } from '../../utils/SkyblockUtils'; +import { PlayerBingoDataPerEvent } from '../../typings'; +import BingoData from './Static/BingoData'; + +/** + * Player Bingo Class + */ +class PlayerBingo { + dataPerEvent: PlayerBingoDataPerEvent[]; + constructor(data: Record, bingoData: BingoData | null) { + const events = data.success && Array.isArray(data.events) ? data.events : []; + this.dataPerEvent = events.map((eventData) => { + let doneGoals = eventData.completed_goals; + if (!Array.isArray(doneGoals)) doneGoals = []; + const enrichable = parseInt(eventData.key, 10) === bingoData?.id; + if (enrichable) doneGoals = populateGoals(doneGoals, bingoData.goals); + return { + eventId: parseInt(eventData.key, 10) || 0, + points: parseInt(eventData.points, 10) || 0, + goalsCompleted: doneGoals, + enrichedGoals: enrichable + }; + }); + } +} + +export default PlayerBingo; diff --git a/src/structures/SkyBlock/SkyblockGarden.ts b/src/structures/SkyBlock/SkyblockGarden.ts new file mode 100644 index 00000000..b4279b9c --- /dev/null +++ b/src/structures/SkyBlock/SkyblockGarden.ts @@ -0,0 +1,74 @@ +import { + SkyblockGardenCropMilestones, + SkyblockGardenComposter, + SkyblockGardenVisitor, + SkyblockGarenCrops, + SkyblockSkillLevel +} from '../../typings'; +import { getLevelByXp } from '../../utils/SkyblockUtils'; + +/** + * Skyblock Garden class + */ +class SkyblockGarden { + level: SkyblockSkillLevel; + barnSkin: string; + unlockedPlots: string[]; + visitors: SkyblockGardenVisitor; + cropMilestones: SkyblockGardenCropMilestones; + composter: SkyblockGardenComposter; + cropUpgrades: SkyblockGarenCrops; + constructor(data: Record) { + this.level = getLevelByXp(data?.garden?.garden_experience || 0, 'garden'); + this.barnSkin = data.garden?.selected_barn_skin || ''; + this.unlockedPlots = data.garden?.unlocked_plots_ids || []; + this.visitors = { + visited: data.garden?.commission_data?.visits || {}, + completed: data.garden?.commission_data?.completed || {}, + served: { + total: data.garden?.commission_data?.total_completed || 0, + unique: data.garden?.commission_data?.unique_npcs_served || 0 + } + }; + this.cropMilestones = { + wheat: getLevelByXp(data.garden?.resources_collected?.WHEAT || 0, 'wheat'), + carrot: getLevelByXp(data.garden?.resources_collected?.CARROT_ITEM || 0, 'carrot'), + sugarCane: getLevelByXp(data.garden?.resources_collected?.SUGAR_CANE || 0, 'sugarCane'), + potato: getLevelByXp(data.garden?.resources_collected?.POTATO_ITEM || 0, 'potato'), + pumpkin: getLevelByXp(data.garden?.resources_collected?.PUMPKIN || 0, 'pumpkin'), + melon: getLevelByXp(data.garden?.resources_collected?.MELON || 0, 'melon'), + cactus: getLevelByXp(data.garden?.resources_collected?.CACTUS || 0, 'cactus'), + cocoBeans: getLevelByXp(data.garden?.resources_collected?.['INK_SACK:3'] || 0, 'cocoBeans'), + mushroom: getLevelByXp(data.garden?.resources_collected?.MUSHROOM_COLLECTION || 0, 'mushroom'), + netherWart: getLevelByXp(data.garden?.resources_collected?.NETHER_STALK || 0, 'netherWart') + }; + this.composter = { + organicMatter: data.garden?.composter_data?.organic_matter || 0, + fuelUnits: data.garden?.composter_data?.fuel_units || 0, + compostUnits: data.garden?.composter_data?.compost_units || 0, + compostItems: data.garden?.composter_data?.compost_items || 0, + conversionTicks: data.garden?.composter_data?.conversion_ticks || 0, + upgrades: { + speed: data.garden?.composter_data?.upgrades?.speed || 0, + multiDrop: data.garden?.composter_data?.upgrades?.multi_drop || 0, + fuelCap: data.garden?.composter_data?.upgrades?.fuel_cap || 0, + organicMatterCap: data.garden?.composter_data?.upgrades?.organic_matter_cap || 0, + costReduction: data.garden?.composter_data?.upgrades?.cost_reduction || 0 + } + }; + this.cropUpgrades = { + wheat: data.garden?.crop_upgrade_levels?.WHEAT || 0, + carrot: data.garden?.crop_upgrade_levels?.CARROT_ITEM || 0, + sugarCane: data.garden?.crop_upgrade_levels?.SUGAR_CANE || 0, + potato: data.garden?.crop_upgrade_levels?.POTATO_ITEM || 0, + pumpkin: data.garden?.crop_upgrade_levels?.PUMPKIN || 0, + melon: data.garden?.crop_upgrade_levels?.MELON || 0, + cactus: data.garden?.crop_upgrade_levels?.CACTUS || 0, + cocoBeans: data.garden?.crop_upgrade_levels?.['INK_SACK:3'] || 0, + mushroom: data.garden?.crop_upgrade_levels?.MUSHROOM_COLLECTION || 0, + netherWart: data.garden?.crop_upgrade_levels?.NETHER_STALK || 0 + }; + } +} + +export default SkyblockGarden; diff --git a/src/structures/SkyBlock/SkyblockInventoryItem.ts b/src/structures/SkyBlock/SkyblockInventoryItem.ts new file mode 100644 index 00000000..ee99c0ca --- /dev/null +++ b/src/structures/SkyBlock/SkyblockInventoryItem.ts @@ -0,0 +1,84 @@ +import { parseGearScore, parseRarity } from '../../utils/SkyblockUtils'; +import { SkyblockGemstoneQuality } from '../../typings'; + +class SkyblockGemstone { + type: string; + quality: SkyblockGemstoneQuality; + constructor(data: Record) { + this.type = data.type; + this.quality = data.quality; + } +} +/** + * Item class + */ +class SkyblockInventoryItem { + itemId: number; + count: number; + name: string; + lore: string; + loreArray: string[]; + loreForEmbed: string; + color: string | null; + enchantments: Record; + reforge: string; + gemstones: SkyblockGemstone[]; + damage: number; + rarity: string; + dungeonStars: number; + gearScore: number; + uuid: string; + soulbound: boolean; + artOfWar: number; + rune: object; + hotPotatoBooks: number; + recombobulated: boolean; + attributes: object; + hecatomb: number; + champion: number; + cultivating: number; + expertise: number; + compact: number; + blocksWalked: number; + constructor(data: Record) { + this.itemId = data.id || 0; + this.count = data.Count || 0; + this.name = + null !== data.tag.display.Name ? data.tag.display.Name.toString().replace(/§([1-9]|[a-f])|§/gm, '') : null; + this.lore = data.tag.display.Lore.join('\n'); + this.loreArray = data.tag.display.Lore; + this.loreForEmbed = this.lore.replace(/§([0-9]|[a-f])|§/gm, '').replace(/
/gm, '\n'); + this.color = data.tag.ExtraAttributes.color ?? data.tag.display.color ?? null; + this.enchantments = data.tag.ExtraAttributes.enchantments ?? null; + this.reforge = data.tag.ExtraAttributes.modifier ?? null; + this.gemstones = Object.entries(data.tag.ExtraAttributes.gems).map((gem) => { + return { + type: gem[0].split('_')[0], + quality: gem[1] as SkyblockGemstoneQuality + }; + }); + this.damage = data.Damage || 0; + this.rarity = parseRarity(this.loreArray[this.loreArray.length - 1]); + this.dungeonStars = data.tag.ExtraAttributes.upgrade_level ?? 0; + this.gearScore = parseGearScore(this.loreArray); + this.uuid = data.tag.ExtraAttributes.uuid ?? ''; + this.soulbound = 1 === data.tag.ExtraAttributes.donated_museum; + this.artOfWar = data.tag.ExtraAttributes.art_of_war_count ?? 0; + this.rune = data.tag.ExtraAttributes.runes ?? null; + this.hotPotatoBooks = data.tag.ExtraAttributes.hot_potato_count ?? 0; + this.recombobulated = 1 === data.tag.ExtraAttributes.rarity_upgrades; + this.attributes = data.tag.ExtraAttributes.attributes ?? {}; + this.hecatomb = data.tag.ExtraAttributes.hecatomb_s_runs ?? 0; + this.champion = data.tag.ExtraAttributes.champion_combat_xp ?? 0; + this.cultivating = data.tag.ExtraAttributes.farmed_cultivating ?? 0; + this.expertise = data.tag.ExtraAttributes.expertise_kills ?? 0; + this.compact = data.tag.ExtraAttributes.compact_blocks ?? 0; + this.blocksWalked = data.tag.ExtraAttributes.blocks_walked ?? 0; + } + + toString(): string { + return this.name; + } +} + +export default SkyblockInventoryItem; diff --git a/src/structures/SkyBlock/SkyblockMember.ts b/src/structures/SkyBlock/SkyblockMember.ts new file mode 100644 index 00000000..b010702d --- /dev/null +++ b/src/structures/SkyBlock/SkyblockMember.ts @@ -0,0 +1,253 @@ +import { getNetworth, NetworthResult } from 'skyhelper-networth'; +import { + SkyblockMemberArmor, + SkyblockMemberChocolateFactoryData, + SkyblockMemberDungeons, + SkyblockMemberEquipment, + SkyblockMemberJacobData, + SkyblockMemberSkills, + SkyblockMemberSlayer, + SkyblockMemberStats, + SkyblockMemberTrophyFishRank, + SkyblockSkillLevel +} from '../../typings'; +import Constants from '../../utils/Constants'; +import { + decode, + getBestiaryLevel, + getChocolateFactory, + getDungeons, + getJacobData, + getLevelByXp, + getMemberStats, + getPetLevel, + getSkills, + getSlayer, + getTrophyFishRank +} from '../../utils/SkyblockUtils'; +import Player from '../Player'; +import SkyblockGarden from './SkyblockGarden'; +import SkyblockInventoryItem from './SkyblockInventoryItem'; +import SkyblockMuseum from './SkyblockMuseum'; +import SkyblockPet from './SkyblockPet'; + +/** + * Skyblock member class + */ +class SkyblockMember { + uuid: string; + player: Player | null; + museum: SkyblockMuseum | null; + garden: SkyblockGarden | null; + gameMode: string | null; + selected: boolean; + profileName: string; + profileId: string; + firstJoinTimestamp: number; + firstJoinAt: Date; + experience: number; + level: number; + hotm: SkyblockSkillLevel; + trophyFish: SkyblockMemberTrophyFishRank; + highestMagicalPower: number; + fairySouls: number; + fairyExchanges: number; + skills: SkyblockMemberSkills; + bestiary: number; + slayer: SkyblockMemberSlayer | null; + dungeons: SkyblockMemberDungeons | null; + collections: object; + purse: number; + stats: SkyblockMemberStats | null; + pets: SkyblockPet[]; + jacob: SkyblockMemberJacobData; + chocolate: SkyblockMemberChocolateFactoryData; + + getArmor: () => Promise; + getWardrobe: () => Promise; + getEnderChest: () => Promise; + getInventory: () => Promise; + getPetScore: () => number; + getEquipment: () => Promise; + getPersonalVault: () => Promise; + getNetworth: () => Promise; + constructor(data: Record) { + this.uuid = data.uuid; + this.player = data.m.player || null; + this.museum = data.museum || null; + this.garden = data.garden || null; + this.gameMode = data.gameMode; + this.selected = data.selected; + this.profileName = data.profileName; + this.profileId = data.profileId; + this.firstJoinTimestamp = data.m.profile?.first_join; + this.firstJoinAt = new Date(data.m.profile?.first_join); + this.experience = data.m.leveling?.experience ?? 0; + this.level = this.experience ? this.experience / 100 : 0; + this.hotm = getLevelByXp(data.m.mining_core?.experience, 'hotm'); + this.trophyFish = getTrophyFishRank(data.m.trophy_fish?.rewards?.length ?? 0); + this.highestMagicalPower = data.m.accessory_bag_storage?.highest_magical_power ?? 0; + this.fairySouls = data.m?.fairy_soul?.total_collected ?? 0; + this.fairyExchanges = data.m?.fairy_soul?.fairy_exchanges ?? 0; + this.skills = getSkills(data.m); + this.bestiary = getBestiaryLevel(data.m); + this.slayer = getSlayer(data.m); + this.dungeons = getDungeons(data.m); + this.collections = data.m.collection ? data.m.collection : null; + this.purse = data.m?.currencies?.coin_purse ?? 0; + this.stats = data.m.player_stats ? getMemberStats(data.m.player_stats) : null; + this.pets = data.m?.pets_data?.pets ? data.m.pets_data.pets.map((pet: any) => new SkyblockPet(pet)) : []; + this.jacob = getJacobData(data.m); + this.chocolate = getChocolateFactory(data.m); + this.getArmor = async () => { + const base64 = data.m.inventory.inv_armor; + const decoded = await decode(base64.data); + const armor = { + helmet: decoded[3].id ? new SkyblockInventoryItem(decoded[3]) : null, + chestplate: decoded[2].id ? new SkyblockInventoryItem(decoded[2]) : null, + leggings: decoded[1].id ? new SkyblockInventoryItem(decoded[1]) : null, + boots: decoded[0].id ? new SkyblockInventoryItem(decoded[0]) : null + }; + return armor; + }; + this.getWardrobe = async () => { + const base64 = data.m?.inventory?.wardrobe_contents?.data; + if (!base64) return []; + const decoded = await decode(base64); + const armor = decoded + .filter((item) => 0 !== Object.keys(item).length) + .map((item) => new SkyblockInventoryItem(item)); + return armor; + }; + this.getEnderChest = async () => { + let chest = data.m.inventory.ender_chest_contents; + if (!chest) return []; + + try { + chest = await decode(chest.data); + const edited = []; + for (let i = 0; i < chest.length; i++) { + if (!chest[i].id) { + continue; + } + edited.push(new SkyblockInventoryItem(chest[i])); + } + return edited; + } catch { + return []; + } + }; + this.getInventory = async () => { + let inventory = data.m.inventory.inv_contents; + if (!inventory) return []; + + try { + inventory = await decode(inventory.data); + const edited = []; + for (let i = 0; i < inventory.length; i++) { + if (!inventory[i].id) { + continue; + } + edited.push(new SkyblockInventoryItem(inventory[i])); + } + return edited; + } catch { + return []; + } + }; + this.getPetScore = () => { + const highestRarity: { [key: string]: any } = {}; + for (const pet of data.m.pets_data.pets) { + if ( + !(pet.type in highestRarity) || + (Constants.petScore as { [key: number]: number })[pet.tier] > highestRarity[pet.type] + ) { + highestRarity[pet.type] = (Constants.petScore as { [key: number]: number })[pet.tier]; + } + } + + const highestLevel: { [key: string]: any } = {}; + for (const pet of data.m.pets_data.pets) { + const maxLevel = 'GOLDEN_DRAGON' === pet.type ? 200 : 100; + const petLevel = getPetLevel(pet.exp, pet.tier, maxLevel); + + if (!(pet.type in highestLevel) || petLevel.level > highestLevel[pet.type]) { + if (petLevel.level < maxLevel) { + continue; + } + + highestLevel[pet.type] = 1; + } + } + + return ( + Object.values(highestRarity).reduce((a, b) => a + b, 0) + Object.values(highestLevel).reduce((a, b) => a + b, 0) + ); + }; + this.getEquipment = async () => { + let equipment = data.m.inventory.equipment_contents; + if (!equipment) + return { + gauntlet: null, + belt: null, + cloak: null, + necklace: null + }; + + try { + equipment = await decode(equipment.data); + const playerEquipment = { + gauntlet: equipment[3].id ? new SkyblockInventoryItem(equipment[3]) : null, + belt: equipment[2].id ? new SkyblockInventoryItem(equipment[2]) : null, + cloak: equipment[1].id ? new SkyblockInventoryItem(equipment[1]) : null, + necklace: equipment[0].id ? new SkyblockInventoryItem(equipment[0]) : null + }; + return playerEquipment; + } catch { + return { + gauntlet: null, + belt: null, + cloak: null, + necklace: null + }; + } + }; + this.getPersonalVault = async () => { + let vault = data.m.inventory.personal_vault_contents; + if (!vault) return []; + + try { + vault = await decode(vault.data); + const edited = []; + for (let i = 0; i < vault.length; i++) { + if (!vault[i].id) { + continue; + } + edited.push(new SkyblockInventoryItem(vault[i])); + } + return edited; + } catch { + return []; + } + }; + this.getNetworth = async () => { + try { + const nw = await getNetworth(data.m, data.banking?.balance ?? 0, { + onlyNetworth: true, + v2Endpoint: true, + cache: true, + museumData: data.museum?.raw ?? {} + }); + return nw; + } catch { + return null; + } + }; + } + + toString(): string { + return this.uuid; + } +} + +export default SkyblockMember; diff --git a/src/structures/SkyBlock/SkyblockMuseum.ts b/src/structures/SkyBlock/SkyblockMuseum.ts new file mode 100644 index 00000000..94fa3cef --- /dev/null +++ b/src/structures/SkyBlock/SkyblockMuseum.ts @@ -0,0 +1,49 @@ +import SkyblockMuseumItem from './SkyblockMuseumItem'; +import { decode } from '../../utils/SkyblockUtils'; + +/** + * Skyblock Museum class + */ +class SkyblockMuseum { + raw: Record; + getItems: () => Promise; + getSpecial: () => Promise; + constructor(data: Record) { + this.raw = data.m.members?.[data.uuid] ?? {}; + this.getItems = async (): Promise => { + const keys = Object.keys(data.m.members[data.uuid].items); + const items = []; + for (const key of keys) { + const decoded = await decode(data.m.members[data.uuid].items[key].items.data); + items.push( + new SkyblockMuseumItem({ + decoded: decoded, + borrowing: data.m.members[data.uuid].items[key].borrowing ?? false, + featuredSlot: data.m.members[data.uuid].items[key].featured_slot ?? null, + donatedTime: data.m.members[data.uuid].items[key].donated_time, + name: key.toLowerCase().replace(/_/g, ' ') + }) + ); + } + return items; + }; + this.getSpecial = async (): Promise => { + const items = []; + for (const item of data.m.members[data.uuid].special) { + const decoded = await decode(item.items.data); + items.push( + new SkyblockMuseumItem({ + decoded: decoded, + borrowing: item.borrowing ?? false, + featuredSlot: item.featured_slot ?? null, + donatedTime: item.donated_time, + name: null + }) + ); + } + return items; + }; + } +} + +export default SkyblockMuseum; diff --git a/src/structures/SkyBlock/SkyblockMuseumItem.ts b/src/structures/SkyBlock/SkyblockMuseumItem.ts new file mode 100644 index 00000000..532fd53b --- /dev/null +++ b/src/structures/SkyBlock/SkyblockMuseumItem.ts @@ -0,0 +1,31 @@ +import SkyblockInventoryItem from './SkyblockInventoryItem'; + +/** + * Item class + */ +class SkyblockMuseumItem { + name: string | null; + items: SkyblockInventoryItem[]; + donatedTime: number; + donatedTimeAt: Date; + borrowing: boolean; + featuredSlot: string | null; + constructor(data: Record) { + this.name = data.name; + this.items = []; + data.decoded.forEach((item: any) => { + if (!item.tag) return; + this.items.push(new SkyblockInventoryItem(item)); + }); + this.donatedTime = data.donatedTime; + this.donatedTimeAt = new Date(data.donatedTime); + this.borrowing = data.borrowing; + this.featuredSlot = data.featuredSlot; + } + + toString(): string | null { + return this.name; + } +} + +export default SkyblockMuseumItem; diff --git a/src/structures/SkyBlock/SkyblockPet.ts b/src/structures/SkyBlock/SkyblockPet.ts new file mode 100644 index 00000000..b5a51d72 --- /dev/null +++ b/src/structures/SkyBlock/SkyblockPet.ts @@ -0,0 +1,29 @@ +import { SkyblockRarity } from '../../typings'; +import Constants from '../../utils/Constants'; + +/** + * Skyblock Pet class + */ +class SkyblockPet { + uuid: string; + type: string; + xp: number; + active: boolean; + rarity: SkyblockRarity; + petScore: number; + heldItem: string | null; + candyUsed: number; + skin: string | null; + constructor(data: Record) { + this.uuid = data.uuid; + this.type = data.type; + this.xp = data.exp || 0; + this.active = Boolean(data.active); + this.rarity = data.tier; + this.petScore = (Constants.petScore as { [key: number]: number })[data.tier] || 0; + this.heldItem = data.heldItem ? data.heldItem.replace(/^PET_ITEM_/, '') : null; + this.candyUsed = data.candyUsed || 0; + this.skin = data.skin; + } +} +export default SkyblockPet; diff --git a/src/structures/SkyBlock/SkyblockProfile.ts b/src/structures/SkyBlock/SkyblockProfile.ts new file mode 100644 index 00000000..1a29adbc --- /dev/null +++ b/src/structures/SkyBlock/SkyblockProfile.ts @@ -0,0 +1,47 @@ +import SkyblockMember from './SkyblockMember'; + +/** + * Skyblock Profile class + */ +class SkyblockProfile { + profileId: string; + profileName: string; + gameMode: string | null; + banking: object; + communityUpgrades: object; + selected: boolean; + members: SkyblockMember[]; + me: SkyblockMember | undefined; + constructor(data: Record) { + this.profileId = data.profileId; + this.profileName = data.profileName; + this.gameMode = data.gameMode; + this.banking = data.banking; + this.communityUpgrades = data.communityUpgrades; + this.selected = data.selected; + this.members = Object.keys(data.members).map( + (uuid) => + new SkyblockMember({ + uuid: uuid, + profileId: this.profileId, + profileName: this.profileName, + gameMode: this.gameMode, + m: data.members[uuid], + banking: this.banking, + communityUpgrades: this.communityUpgrades, + museum: null, + selected: this.selected + }) + ); + this.me = this.members.find((x) => x.uuid === data.uuid); + } + /** + * Profile Name + * @return {string} + */ + toString() { + return this.profileName; + } +} + +export default SkyblockProfile; diff --git a/src/structures/SkyBlock/Static/Bingo.ts b/src/structures/SkyBlock/Static/Bingo.ts new file mode 100644 index 00000000..c9b93d6b --- /dev/null +++ b/src/structures/SkyBlock/Static/Bingo.ts @@ -0,0 +1,56 @@ +function parsePosition(position: any): [number, number] { + const x = (position % 5) + 1; + const y = Math.floor(position / 5) + 1; + return [x, y]; +} +/** + * Bingo class + */ +class Bingo { + name: string; + id: string; + row: number | null; + column: number | null; + rawLore: string; + lore: string; + tiers: number[]; + tierStep: number | null; + requiredAmount: number | null; + type: 'ONE_TIME' | 'ONE_TIER' | 'TIERED'; + constructor(data: Record, position: number = 0) { + this.name = data.name; + this.id = data.id; + const [row, column] = parsePosition(position); + this.row = row; + this.column = column; + this.rawLore = data.lore; + this.lore = data.lore?.replace?.(/§([1-9]|[a-l])|§/gm, '') || []; + this.tiers = Array.isArray(data.tiers) ? data.tiers.map((x) => parseInt(x, 10) || 0) : []; + this.tierStep = this.getTierStep(); + this.requiredAmount = parseInt(data.requiredAmount, 10) ?? null; + this.type = this.tiers ? 'TIERED' : this.requiredAmount ? 'ONE_TIER' : 'ONE_TIME'; + } + + toString(): string { + return this.id; + } + /** + * Gets tier step, if constant + * @private + * @returns {number|null} + */ + getTierStep() { + if ('TIERED' !== this.type) return null; + // No step possible + if (2 > this.tiers.length) return null; + const hypotheticStep = this.tiers[1] - this.tiers[0]; + // Check if every 2 elements have the same step + const isConstant = this.tiers.slice(1).every((el, index) => { + return hypotheticStep === this.tiers[index - 1] - el; + }); + if (!isConstant) return null; + return hypotheticStep; + } +} + +export default Bingo; diff --git a/src/structures/SkyBlock/Static/BingoData.ts b/src/structures/SkyBlock/Static/BingoData.ts new file mode 100644 index 00000000..9a59061e --- /dev/null +++ b/src/structures/SkyBlock/Static/BingoData.ts @@ -0,0 +1,24 @@ +import Bingo from './Bingo'; + +/** + * SB Bingo Class + */ +class BingoData { + lastUpdatedTimestamp: number; + lastUpdatedAt: Date | null; + id: number | null; + goals: Bingo[] | null; + constructor(data: Record) { + this.lastUpdatedTimestamp = parseInt(data.lastUpdated, 10); + this.lastUpdatedAt = new Date(this.lastUpdatedTimestamp); + this.id = parseInt(data.id, 10) || null; + this.goals = Array.isArray(data.goals) ? data.goals.map((goal, index) => new Bingo(goal, index)) : null; + } + + getGoal(column: number, row: number): Bingo | undefined { + if (!this.goals || 1 > this.goals.length) return; + return this.goals.find((goal) => goal.row === row && goal.column === column); + } +} + +export default BingoData; diff --git a/src/structures/SkyBlock/Static/Candidate.ts b/src/structures/SkyBlock/Static/Candidate.ts new file mode 100644 index 00000000..a35cb69f --- /dev/null +++ b/src/structures/SkyBlock/Static/Candidate.ts @@ -0,0 +1,21 @@ +import Perk from './Perk'; + +/** + * Candidate class + */ +class Candidate { + name: string; + keyBenefit: string; + perks: Perk[]; + isMayor: boolean; + votesReceived: number; + constructor(data: Record, isMayor: boolean = false) { + this.name = data.name; + this.keyBenefit = data.key; + this.perks = data.perks.map((x: any) => new Perk(x)); + this.isMayor = isMayor || false; + this.votesReceived = parseInt(data.votes, 10) || 0; + } +} + +export default Candidate; diff --git a/src/structures/SkyBlock/Static/FireSale.ts b/src/structures/SkyBlock/Static/FireSale.ts new file mode 100644 index 00000000..3f12e93f --- /dev/null +++ b/src/structures/SkyBlock/Static/FireSale.ts @@ -0,0 +1,27 @@ +/** + * SB Fire Sale + */ +class FireSale { + itemId: string | null; + startTimestamp: number; + startAt: Date; + endTimestamp: number; + endAt: Date; + amount: number; + price: number; + constructor(data: Record) { + this.itemId = data.item_id || null; + this.startTimestamp = parseInt(data.start, 10); + this.startAt = new Date(this.startTimestamp); + this.endTimestamp = parseInt(data.end, 10); + this.endAt = new Date(this.endTimestamp); + this.amount = data.amount || 0; + this.price = data.price || 0; + } + + toString(): string | null { + return this.itemId; + } +} + +export default FireSale; diff --git a/src/structures/SkyBlock/Static/Government.ts b/src/structures/SkyBlock/Static/Government.ts new file mode 100644 index 00000000..46245662 --- /dev/null +++ b/src/structures/SkyBlock/Static/Government.ts @@ -0,0 +1,45 @@ +import Candidate from './Candidate'; + +/** + * SB Government Class + */ +class GovernmentData { + lastUpdatedTimestamp: number; + lastUpdatedAt: Date | null; + lastElectionResults: Map; + mayor: Candidate | undefined; + runningYear: number; + currentElectionResults: Map | null; + currentElectionFor: number | null; + constructor(data: Record) { + this.lastUpdatedTimestamp = parseInt(data.lastUpdated, 10); + this.lastUpdatedAt = new Date(this.lastUpdatedTimestamp); + const lastElectionResults = data.mayor.election.candidates.map( + (x: any) => new Candidate(x, x.name === data.mayor.name) + ); + this.lastElectionResults = new Map( + lastElectionResults + .sort((a: any, b: any) => a.votesReceived - b.votesReceived) + .reverse() + .map((x: any) => [x.name, x]) + ); + this.mayor = this.lastElectionResults.get(data.mayor.name); + this.runningYear = parseInt(data.mayor.election.year, 10) || 0; + const thisElection = data.current?.candidates.map((x: any) => new Candidate(x, x.name === data.mayor.name)) || null; + this.currentElectionResults = thisElection + ? new Map( + thisElection + .sort((a: any, b: any) => a.votesReceived - b.votesReceived) + .reverse() + .map((x: any) => [x.name, x]) + ) + : null; + this.currentElectionFor = parseInt(data.current?.year, 10) || null; + } + + toString(): string { + return this.mayor?.name || ''; + } +} + +export default GovernmentData; diff --git a/src/structures/SkyBlock/Static/Perk.ts b/src/structures/SkyBlock/Static/Perk.ts new file mode 100644 index 00000000..159a3e85 --- /dev/null +++ b/src/structures/SkyBlock/Static/Perk.ts @@ -0,0 +1,13 @@ +/** + * Candidate class + */ +class Perk { + name: string; + description: string; + constructor(data: Record) { + this.name = data.name; + this.description = data.description; + } +} + +export default Perk; diff --git a/src/structures/Static/Achievement.ts b/src/structures/Static/Achievement.ts new file mode 100644 index 00000000..db46e048 --- /dev/null +++ b/src/structures/Static/Achievement.ts @@ -0,0 +1,52 @@ +import AchievementTier from './AchievementTier'; + +function collectAll(data: AchievementTier | null) { + if (data === null) { + return { totalPoints: 0, totalAmount: 0 }; + } + const mTier = data.maxTier; + let totalPoints = 0; + let totalAmount = 0; + for (let i = 1; i <= mTier; i++) { + totalPoints += data.getTier(i).pointsRewarded; + totalAmount += data.getTier(i).amountRequired; + } + return { totalPoints, totalAmount }; +} + +/** + * Achievement Class + */ +class Achievement { + name: string; + codeName: string; + description: string; + type: 'ONE_TIME' | 'TIERED'; + rarity: Record<'local' | 'localPercentage' | 'global' | 'globalPercentage', number> | null; + tierInformation: AchievementTier | null; + points: number; + totalAmountRequired: number | null; + constructor(achievementName: string, data: Record) { + this.name = data.name.trim(); + this.codeName = achievementName; + this.description = data.description.trim(); + this.type = data.tiers ? 'TIERED' : 'ONE_TIME'; + this.rarity = { + local: parseFloat(data.gamePercentUnlocked) || 0, + localPercentage: parseFloat(data.gamePercentUnlocked) * 100 || 0, + global: data.globalPercentUnlocked, + globalPercentage: parseFloat(data.globalPercentUnlocked) * 100 || 0 + }; + this.tierInformation = 'TIERED' === this.type ? new AchievementTier(data.tiers) : null; + + const { totalPoints = 0, totalAmount = 0 }: { totalPoints: number; totalAmount: number } = + 'TIERED' === this.type ? collectAll(this.tierInformation) : { totalPoints: 0, totalAmount: 0 }; + this.points = 'ONE_TIME' === this.type ? parseInt(data.points, 10) : totalPoints; + this.totalAmountRequired = 'TIERED' === this.type ? totalAmount : null; + } + toString(): string { + return this.codeName; + } +} + +export default Achievement; diff --git a/src/structures/Static/AchievementTier.ts b/src/structures/Static/AchievementTier.ts new file mode 100644 index 00000000..e29d5d2f --- /dev/null +++ b/src/structures/Static/AchievementTier.ts @@ -0,0 +1,24 @@ +/** + * AchievementTier class + */ +class AchievementTier { + maxTier: number; + tierInfo: any; + constructor(data: Record) { + this.maxTier = data.length; + this.tierInfo = data.sort( + ({ tier: tierA }: { tier: number }, { tier: tierB }: { tier: number }) => Number(tierA) - Number(tierB) + ); + } + + getTier(tier: number): Record<'pointsRewarded' | 'amountRequired', number> { + const index = tier - 1; + const info = this.tierInfo[index]; + return { + pointsRewarded: parseInt(info.points, 10) || 0, + amountRequired: parseInt(info.amount, 10) || 0 + }; + } +} + +export default AchievementTier; diff --git a/src/structures/Static/Achievements.ts b/src/structures/Static/Achievements.ts new file mode 100644 index 00000000..e4b63563 --- /dev/null +++ b/src/structures/Static/Achievements.ts @@ -0,0 +1,23 @@ +import { StaticGameNames } from '../../typings'; +import GameAchievements from './GameAchievements'; + +/** + * Achievement class + */ +class Achievements { + lastUpdatedTimestamp: number; + lastUpdatedAt: Date | null; + achievementsPerGame: Record; + constructor(data: Record) { + this.lastUpdatedTimestamp = parseInt(data.lastUpdated, 10); + this.lastUpdatedAt = new Date(this.lastUpdatedTimestamp); + this.achievementsPerGame = Object.fromEntries( + Object.entries(data.achievements).map(([game, data]) => [ + game, + new GameAchievements(game as StaticGameNames, data as Record) + ]) + ) as Record; + } +} + +export default Achievements; diff --git a/src/structures/Static/Challenges.ts b/src/structures/Static/Challenges.ts new file mode 100644 index 00000000..34710588 --- /dev/null +++ b/src/structures/Static/Challenges.ts @@ -0,0 +1,23 @@ +import { StaticGameNames } from '../../typings'; +import GameChallenges from './GameChallenges'; + +/** + * Challenges class + */ +class Challenges { + lastUpdatedTimestamp: number; + lastUpdatedAt: Date | null; + challengesPerGame: Record; + constructor(data: Record) { + this.lastUpdatedTimestamp = parseInt(data.lastUpdated, 10); + this.lastUpdatedAt = new Date(this.lastUpdatedTimestamp); + this.challengesPerGame = Object.fromEntries( + Object.entries(data.challenges).map(([game, data]) => [ + game, + new GameChallenges(game as StaticGameNames, data as Record) + ]) + ) as Record; + } +} + +export default Challenges; diff --git a/src/structures/Static/GameAchievements.ts b/src/structures/Static/GameAchievements.ts new file mode 100644 index 00000000..fc6ec95c --- /dev/null +++ b/src/structures/Static/GameAchievements.ts @@ -0,0 +1,22 @@ +import { StaticGameNames } from '../../typings'; +import Achievement from './Achievement'; + +/** + * Game achievements class + */ +class GameAchievements { + category: StaticGameNames; + totalPoints: number; + totalLegacyPoints: number; + achievements: Achievement[]; + constructor(name: StaticGameNames, data: Record) { + this.category = name; + this.totalPoints = parseInt(data.total_points, 10) || 0; + this.totalLegacyPoints = parseInt(data.total_legacy_points, 10) || 0; + this.achievements = Object.entries({ ...(data.one_time || {}), ...(data.tiered || {}) }).map( + ([name, data]) => new Achievement(name, data as Record) + ); + } +} + +export default GameAchievements; diff --git a/src/structures/Static/GameChallenges.ts b/src/structures/Static/GameChallenges.ts new file mode 100644 index 00000000..4ebdfd09 --- /dev/null +++ b/src/structures/Static/GameChallenges.ts @@ -0,0 +1,25 @@ +import { ChallengeData, StaticGameNames } from '../../typings'; + +/** + * Game challenges class + */ +class GameChallenges { + category: StaticGameNames; + challenges: Map; + constructor(name: StaticGameNames, data: Record) { + this.category = name; + this.challenges = new Map(); + + data.forEach((challenge: any) => { + const content = { + id: challenge.id, + name: challenge.name, + reward: parseInt(challenge.rewards[0].amount, 10) || 0, + rewardType: challenge.rewards[0].type + }; + this.challenges.set(challenge.id, content); + }); + } +} + +export default GameChallenges; diff --git a/src/structures/Static/GameQuests.ts b/src/structures/Static/GameQuests.ts new file mode 100644 index 00000000..ad2a8613 --- /dev/null +++ b/src/structures/Static/GameQuests.ts @@ -0,0 +1,16 @@ +import { StaticGameNames } from '../../typings'; +import Quest from './Quest'; + +/** + * Game quests class + */ +class GameQuests { + game: StaticGameNames; + quests: Quest[]; + constructor(name: StaticGameNames, data: Record) { + this.game = name; + this.quests = (data || []).map((x: any) => new Quest(x)); + } +} + +export default GameQuests; diff --git a/src/structures/Static/GuildAchievements.ts b/src/structures/Static/GuildAchievements.ts new file mode 100644 index 00000000..c0a53018 --- /dev/null +++ b/src/structures/Static/GuildAchievements.ts @@ -0,0 +1,22 @@ +import Achievement from './Achievement'; + +/** + * Achievement class + */ +class GuildAchievements { + lastUpdatedTimestamp: number; + lastUpdatedAt: Date | null; + achievements: Record; + constructor(data: Record) { + this.lastUpdatedTimestamp = parseInt(data.lastUpdated, 10); + this.lastUpdatedAt = new Date(this.lastUpdatedTimestamp); + this.achievements = Object.fromEntries( + Object.entries({ ...(data.tiered || {}), ...(data.one_time || {}) }).map(([name, value]) => [ + name, + new Achievement(name, value as Record) + ]) + ); + } +} + +export default GuildAchievements; diff --git a/src/structures/Static/Quest.ts b/src/structures/Static/Quest.ts new file mode 100644 index 00000000..6cf8a876 --- /dev/null +++ b/src/structures/Static/Quest.ts @@ -0,0 +1,30 @@ +import { QuestObjective, QuestReward } from '../../typings'; + +/** + * Quest Class + */ +class Quest { + questName: string; + questID: string; + description: string; + type: 'DAILY' | 'WEEKLY'; + objectives: QuestObjective[]; + rewards: QuestReward[]; + constructor(data: Record) { + this.questName = data.name.trim(); + this.questID = data.id; + this.description = data.description.trim(); + this.type = 'DailyResetQuestRequirement' === data.requirements?.[0].type ? 'DAILY' : 'WEEKLY'; + this.objectives = data.objectives.map((objective: any) => ({ + id: objective.id, + type: 'IntegerObjective' === objective.type ? 'Integer' : 'Boolean', + amountNeeded: parseInt(objective.integer || '1', 10) + })); + this.rewards = data.rewards || []; + } + toString(): string { + return this.questName; + } +} + +export default Quest; diff --git a/src/structures/Static/Quests.ts b/src/structures/Static/Quests.ts new file mode 100644 index 00000000..a57cf33f --- /dev/null +++ b/src/structures/Static/Quests.ts @@ -0,0 +1,23 @@ +import { StaticGameNames } from '../../typings'; +import GameQuests from './GameQuests'; + +/** + * Quest class + */ +class Quests { + lastUpdatedTimestamp: number; + lastUpdatedAt: Date | null; + questsPerGame: Record; + constructor(data: Record) { + this.lastUpdatedTimestamp = parseInt(data.lastUpdated, 10); + this.lastUpdatedAt = new Date(this.lastUpdatedTimestamp); + this.questsPerGame = Object.fromEntries( + Object.entries(data.quests).map(([game, data]) => [ + game, + new GameQuests(game as StaticGameNames, data as Record) + ]) + ) as Record; + } +} + +export default Quests; diff --git a/src/structures/Status.ts b/src/structures/Status.ts new file mode 100644 index 00000000..5f7b494b --- /dev/null +++ b/src/structures/Status.ts @@ -0,0 +1,19 @@ +import Game from './Game'; + +class Status { + online: boolean; + game: Game | null; + mode: string | null; + map: string | null; + constructor(data: Record) { + this.online = data.online; + this.game = data.gameType ? new Game(data.gameType) : null; + this.mode = data.mode ?? null; + this.map = data.map ?? null; + } + toString(): string { + return this.online ? 'Online' : 'Offline'; + } +} + +export default Status; diff --git a/src/structures/Watchdog/Stats.ts b/src/structures/Watchdog/Stats.ts new file mode 100644 index 00000000..b52cc32e --- /dev/null +++ b/src/structures/Watchdog/Stats.ts @@ -0,0 +1,19 @@ +/** + * WatchdogStats class + */ +class WatchdogStats { + byWatchdogTotal: number; + byWatchdogLastMinute: number; + byWatchdogRollingDay: number; + byStaffTotal: number; + byStaffRollingDay: number; + constructor(data: Record) { + this.byWatchdogTotal = data.watchdog_total || 0; + this.byWatchdogLastMinute = data.watchdog_lastMinute || 0; + this.byWatchdogRollingDay = data.watchdog_rollingDaily || 0; + this.byStaffTotal = data.staff_total || 0; + this.byStaffRollingDay = data.staff_rollingDaily || 0; + } +} + +export default WatchdogStats; diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 86c89d11..b8ea98f4 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -1,3 +1,6 @@ +import PitInventoryItem from '../structures/MiniGames/PitInventoryItem'; +import SkyblockInventoryItem from '../structures/SkyBlock/SkyblockInventoryItem'; + export interface ClientOptions { cache?: boolean; hypixelCacheTime?: number; @@ -279,3 +282,426 @@ export interface SkyblockMemberChocolateFactoryData { barnCapacity: number; prestige: number; } + +export interface PlayerInfo { + max: number; + online: number; + players: any[]; + toString(): string; +} + +export type PlayerRank = 'VIP' | 'VIP+' | 'MVP' | 'MVP+' | 'MVP++' | 'Game Master' | 'Admin' | 'YouTube'; + +export interface RanksPurchaseTime { + VIP: Date | null; + VIP_PLUS: Date | null; + MVP: Date | null; + MVP_PLUS: Date | null; +} + +export interface PetConsumables { + BAKED_POTATO: number; + COOKIE: number; + FEATHER: number; + HAY_BLOCK: number; + SLIME_BALL: number; + COOKED_BEEF: number; + RED_ROSE: number; + WATER_BUCKET: number; + MELON: number; + STICK: number; + WOOD_SWORD: number; + MILK_BUCKET: number; + GOLD_RECORD: number; + LEASH: number; + LAVA_BUCKET: number; + BONE: number; + MAGMA_CREAM: number; + WHEAT: number; + MUSHROOM_SOUP: number; + BREAD: number; + PUMPKIN_PIE: number; + APPLE: number; + CARROT_ITEM: number; + RAW_FISH: number; + PORK: number; + CAKE: number; + ROTTEN_FLESH: number; +} + +export type BedWarsPrestige = + | 'Stone' + | 'Iron' + | 'Gold' + | 'Diamond' + | 'Emerald' + | 'Sapphire' + | 'Ruby' + | 'Crystal' + | 'Opal' + | 'Amethyst' + | 'Rainbow' + | 'Iron Prime' + | 'Gold Prime' + | 'Diamond Prime' + | 'Emerald Prime' + | 'Sapphire Prime' + | 'Ruby Prime' + | 'Crystal Prime' + | 'Opal Prime' + | 'Amethyst Prime' + | 'Mirror' + | 'Light' + | 'Dawn' + | 'Dusk' + | 'Air' + | 'Wind' + | 'Nebula' + | 'Thunder' + | 'Earth' + | 'Water' + | 'Fire' + | 'Sunrise' + | 'Eclipse' + | 'Gamma' + | 'Majestic' + | 'Andesine' + | 'Marine' + | 'Element' + | 'Galaxy' + | 'Atomic' + | 'Sunset' + | 'Time' + | 'Winter' + | 'Obsidian' + | 'Spring' + | 'Ice' + | 'Summer' + | 'Spinel' + | 'Autumn' + | 'Mystic' + | 'Eternal'; + +export interface BedWarsCollectedItems { + iron: number; + gold: number; + diamond: number; + emerald: number; +} + +export interface BedWarsAvg { + kills: number; + finalKills: number; + bedsBroken: number; +} + +export interface BedWarsBeds { + lost: number; + broken: number; + BLRatio: number; +} + +export interface BedWarsModeStats { + winstreak: number; + playedGames: number; + kills: number; + deaths: number; + wins: number; + losses: number; + finalKills: number; + finalDeaths: number; + beds: BedWarsBeds; + avg: BedWarsAvg; + KDRatio: number; + WLRatio: number; + finalKDRatio: number; +} + +export interface BedwarsDreamStats { + ultimate: BedwarsDreamModeStats; + rush: BedwarsDreamModeStats; + armed: BedwarsDreamModeStats; + lucky: BedwarsDreamModeStats; + voidless: BedwarsDreamModeStats; +} + +export interface BedwarsDreamModeStats { + doubles: BedWarsModeStats; + fours: BedWarsModeStats; +} + +export interface BedWarsPracticeAttempts { + failed: number; + successful: number; + total: number; +} + +export interface BedWarsPracticeElevation { + straight: number; + diagonal: number; +} + +export interface BedWarsPracticeElevations { + none: BedWarsPracticeElevation; + slight: BedWarsPracticeElevation; + staircase: BedWarsPracticeElevation; +} + +export interface BedWarsPracticeRecord { + elevation: BedWarsPracticeElevations; +} + +export interface BedWarsPracticeRecords { + blocks30: BedWarsPracticeRecord; + blocks50: BedWarsPracticeRecord; + blocks100: BedWarsPracticeRecord; +} + +export interface BedWarsPracticeBridging { + blocksPlaced: number; + attempts: BedWarsPracticeAttempts; + records: BedWarsPracticeRecords; +} + +export interface BedWarsPracticePearlClutching { + attempts: BedWarsPracticeAttempts; +} + +export interface BedWarsPracticeBase { + blocksPlaced: number; + attempts: BedWarsPracticeAttempts; +} + +export interface BedWarsPracticeStats { + selected: string; + bridging: BedWarsPracticeBridging; + fireballJumping: BedWarsPracticeBase; + pearlClutching: BedWarsPracticePearlClutching; + mlg: BedWarsPracticeBase; +} + +export interface BuildBattleWins { + solo: number; + teams: number; + pro: number; + gtb: number; +} + +export interface PitArmor { + helmet: PitInventoryItem | null; + chestplate: PitInventoryItem | null; + leggings: PitInventoryItem | null; + boots: PitInventoryItem | null; +} + +export type SkyWarsPrestige = + | 'Iron' + | 'Gold' + | 'Diamond' + | 'Emerald' + | 'Sapphire' + | 'Ruby' + | 'Crystal' + | 'Opal' + | 'Amethyst' + | 'Rainbow' + | 'Mythic'; + +export type SkyWarsPrestigeIcons = + | '⋆' + | '★' + | '☆' + | '⁕' + | '✶' + | '✳' + | '✴' + | '✷' + | '❋' + | '✼' + | '❂' + | '❁' + | '☬' + | '✙' + | '❤️' + | '☠' + | '✦' + | '✌' + | '❦' + | '✵' + | '❣' + | '☯' + | '✺' + | 'ಠ_ಠ' + | '⚔'; + +export interface WoolWarsStats { + wins: number; + gamesPlayed: number; + woolsPlaced: number; + blocksBroken: number; + placeBreakRatio: number; + kills: number; + deaths: number; + KDRatio: number; + assists: number; + powerups: number; +} + +export interface WoolWarsPrivateGamesConfig { + one_hit_one_kil: boolean; + rainbow_wool: 'Enabled' | 'Disabled'; + health_buff: string; + game_speed: string; + speed: string; + no_class: 'Enabled' | 'Disabled'; + respawn_enable: boolean; +} + +export interface QuestObjective { + id: string; + type: 'Integer' | 'Boolean'; + amountNeeded: number; +} + +export interface QuestReward { + type: string; + amount: number; +} + +export interface ChallengeData { + id: string; + name: string; + reward: number; + rewardType: string; +} + +export type StaticGameNames = + | 'arcade' + | 'arena' + | 'bedwars' + | 'hungergames' + | 'buildbattle' + | 'truecombat' + | 'duels' + | 'mcgo' + | 'murdermystery' + | 'paintball' + | 'quake' + | 'skyclash' + | 'skywars' + | 'supersmash' + | 'speeduhc' + | 'gingerbread' + | 'tntgames' + | 'uhc' + | 'vampirez' + | 'walls3' + | 'walls' + | 'battleground' + | 'woolgames'; + +export type SkyblockGemstoneQuality = 'Rough' | 'Flawed' | 'Fine' | 'Flawless' | 'Perfect'; + +export type SkyblockRarity = + | 'COMMON' + | 'UNCOMMON' + | 'RARE' + | 'EPIC' + | 'LEGENDARY' + | 'MYTHIC' + | 'DIVINE' + | 'SPECIAL' + | 'VERY_SPECIAL'; + +export interface SkyblockGardenVisitor { + visited: Record; + completed: Record; + served: SkyblockGardenVisitorServed; +} + +export interface SkyblockGardenVisitorServed { + total: number; + unique: number; +} + +export interface SkyblockGardenComposterUpgrades { + speed: number; + multiDrop: number; + fuelCap: number; + organicMatterCap: number; + costReduction: number; +} + +export interface SkyblockGardenComposter { + organicMatter: number; + fuelUnits: number; + compostUnits: number; + compostItems: number; + conversionTicks: number; + upgrades: SkyblockGardenComposterUpgrades; +} + +export interface SkyblockGarenCrops { + wheat: number; + carrot: number; + sugarCane: number; + potato: number; + pumpkin: number; + melon: number; + cactus: number; + cocoBeans: number; + mushroom: number; + netherWart: number; +} + +export interface SkyblockGardenCropMilestones { + wheat: SkyblockSkillLevel; + carrot: SkyblockSkillLevel; + sugarCane: SkyblockSkillLevel; + potato: SkyblockSkillLevel; + pumpkin: SkyblockSkillLevel; + melon: SkyblockSkillLevel; + cactus: SkyblockSkillLevel; + cocoBeans: SkyblockSkillLevel; + mushroom: SkyblockSkillLevel; + netherWart: SkyblockSkillLevel; +} + +export type SkyblockMemberTrophyFishRank = 'Bronze' | 'Silver' | 'Gold' | 'Diamond'; + +export interface SkyblockMemberEquipment { + gauntlet: SkyblockInventoryItem | null; + belt: SkyblockInventoryItem | null; + cloak: SkyblockInventoryItem | null; + necklace: SkyblockInventoryItem | null; +} + +export interface SkyblockMemberArmor { + helmet: SkyblockInventoryItem | null; + chestplate: SkyblockInventoryItem | null; + leggings: SkyblockInventoryItem | null; + boots: SkyblockInventoryItem | null; +} + +export interface SkyblockMemberStats { + kills: Record; + deaths: Record; +} + +export interface PlayerBingoDataPerEvent { + eventId: number; + points: number; + enrichedGoals: boolean; + goalsCompleted: Bingo[] | string[]; +} + +export interface ProductStatus { + sellPrice: number; + buyPrice: number; + sellVolume: number; + buyVolume: number; + sellMovingWeek: number; + buyMovingWeek: number; + sellOrders: number; + buyOrders: number; +} diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index 887f7672..aa658a40 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -712,7 +712,8 @@ export default { RARE: 3, EPIC: 4, LEGENDARY: 5, - MYTHIC: 6 + MYTHIC: 6, + VERY_SPECIAL: 6 }, petRarityOffset: { COMMON: 0, diff --git a/src/utils/Player.ts b/src/utils/Player.ts index 77b30d77..5b82ec41 100644 --- a/src/utils/Player.ts +++ b/src/utils/Player.ts @@ -1,6 +1,6 @@ -import { LevelProgress, PlayerSocialMedia } from '../typings'; +import { LevelProgress, PlayerRank, PlayerSocialMedia } from '../typings'; -export function getRank(player: Record): string { +export function getRank(player: Record): PlayerRank { let rank; if (player.prefix) { rank = player.prefix.replace(/§[0-9|a-z]|\[|\]/g, ''); @@ -81,26 +81,14 @@ export function playerLevelProgress(xp: number): LevelProgress { }; } -export function getSocialMedia(data: Record): PlayerSocialMedia | null { +export function getSocialMedia(data: Record): PlayerSocialMedia[] { const links = data.links; const formattedNames = ['Twitter', 'YouTube', 'Instagram', 'Twitch', 'Hypixel', 'Discord']; const upperNames = ['TWITTER', 'YOUTUBE', 'INSTAGRAM', 'TWITCH', 'HYPIXEL', 'DISCORD']; - if (!links) return null; - const socialMedia: PlayerSocialMedia = { - name: '', - link: '', - id: '' - }; return Object.keys(links) .map((x) => upperNames.indexOf(x)) .filter((x) => -1 !== x) - .map((x) => ({ name: formattedNames[x], link: links[upperNames[x]], id: upperNames[x] })) - .reduce((acc, curr) => { - acc.name = curr.name; - acc.link = curr.link; - acc.id = curr.id; - return acc; - }, socialMedia); + .map((x) => ({ name: formattedNames[x], link: links[upperNames[x]], id: upperNames[x] })); } export function parseClaimedRewards(data: Record): number[] { diff --git a/src/utils/SkyblockUtils.ts b/src/utils/SkyblockUtils.ts index 176da037..228d1eea 100644 --- a/src/utils/SkyblockUtils.ts +++ b/src/utils/SkyblockUtils.ts @@ -1,18 +1,21 @@ import { SkyblockMemberChocolateFactoryData, - SkyblockMemberDungeons, + SkyblockMemberTrophyFishRank, + SkyblockMemberSlayerLevel, SkyblockMemberJacobData, + SkyblockMemberDungeons, SkyblockMemberSkills, SkyblockMemberSlayer, - SkyblockMemberSlayerLevel, - SkyblockSkillLevel + SkyblockSkillLevel, + SkyblockRarity, + SkyblockMemberStats } from '../typings'; import Constants from './Constants'; import nbt from 'prismarine-nbt'; -export async function decode(base64: string, isBuffer = false): Promise { +export async function decode(base64: string | Buffer, isBuffer = false): Promise { const parseNbt = require('util').promisify(nbt.parse); - const buffer = isBuffer ? base64 : Buffer.from(base64, 'base64'); + const buffer = isBuffer ? base64 : Buffer.from(String(base64), 'base64'); let data = await parseNbt(buffer); data = nbt.simplify(data); const newdata = []; @@ -148,7 +151,7 @@ export function getSlayerLevel(slayer: Record): SkyblockMemberSlaye }; } -export function getMemberStats(obj: Record) { +export function getMemberStats(obj: Record): SkyblockMemberStats { return Object.keys(obj).reduce( (result, currentKey) => { const key = currentKey.replace(/_[a-z]/gi, (match) => match[1].toUpperCase()); @@ -172,7 +175,7 @@ export function getMemberStats(obj: Record) { ); } -export function getTrophyFishRank(level: number): 'Bronze' | 'Silver' | 'Gold' | 'Diamond' { +export function getTrophyFishRank(level: number): SkyblockMemberTrophyFishRank { if (1 === level) { return 'Bronze'; } else if (2 === level) { @@ -207,58 +210,58 @@ export function getSkills(data: Record): SkyblockMemberSkills { return skillsObject; } -// function formatBestiaryMobs(userProfile, mobs) { -// const output = []; -// for (const mob of mobs) { -// const mobBracket = Constants.bestiaryBrackets[mob.bracket]; - -// const totalKills = mob.mobs.reduce((acc, cur) => { -// return acc + (userProfile.bestiary.kills[cur] ?? 0); -// }, 0); - -// const maxKills = mob.cap; -// const nextTierKills = mobBracket.find((tier) => totalKills < tier && tier <= maxKills); -// const tier = nextTierKills ? mobBracket.indexOf(nextTierKills) : mobBracket.indexOf(maxKills) + 1; - -// output.push({ -// tier: tier -// }); -// } - -// return output; -// } - -// function getBestiaryLevel(userProfile) { -// try { -// if (userProfile.bestiary?.kills === undefined) { -// return null; -// } - -// const output = {}; -// let tiersUnlocked = 0; -// for (const [category, data] of Object.entries(Constants.bestiary)) { -// const { mobs } = data; -// output[category] = {}; - -// if ('fishing' === category) { -// for (const [key, value] of Object.entries(data)) { -// output[category][key] = { -// mobs: formatBestiaryMobs(userProfile, value.mobs) -// }; -// tiersUnlocked += output[category][key].mobs.reduce((acc, cur) => acc + cur.tier, 0); -// } -// } else { -// output[category].mobs = formatBestiaryMobs(userProfile, mobs); -// tiersUnlocked += output[category].mobs.reduce((acc, cur) => acc + cur.tier, 0); -// } -// } - -// return tiersUnlocked / 10; -// } catch (error) { -// console.log(error); -// return null; -// } -// } +function formatBestiaryMobs(userProfile: Record, mobs: any) { + const output = []; + for (const mob of mobs) { + const mobBracket = (Constants.bestiaryBrackets as { [key: number]: number[] })[mob.bracket]; + + const totalKills = mob.mobs.reduce((acc: any, cur: any) => { + return acc + (userProfile.bestiary.kills[cur] ?? 0); + }, 0); + + const maxKills = mob.cap; + const nextTierKills = mobBracket.find((tier: any) => totalKills < tier && tier <= maxKills); + const tier = nextTierKills ? mobBracket.indexOf(nextTierKills) : mobBracket.indexOf(maxKills) + 1; + + output.push({ + tier: tier + }); + } + + return output; +} + +export function getBestiaryLevel(userProfile: Record): number { + try { + if (userProfile.bestiary?.kills === undefined) { + return 0; + } + + const output: { [key: string]: any } = {}; + let tiersUnlocked = 0; + for (const [category, data] of Object.entries(Constants.bestiary)) { + const { mobs } = data as { mobs: any }; + output[category] = {}; + + if ('fishing' === category) { + for (const [key, value] of Object.entries(data)) { + output[category][key] = { + mobs: formatBestiaryMobs(userProfile, value.mobs) + }; + tiersUnlocked += output[category][key].mobs.reduce((acc: any, cur: any) => acc + cur.tier, 0); + } + } else { + output[category].mobs = formatBestiaryMobs(userProfile, mobs); + tiersUnlocked += output[category].mobs.reduce((acc: any, cur: any) => acc + cur.tier, 0); + } + } + + return tiersUnlocked / 10; + } catch (error) { + console.log(error); + return 0; + } +} export function getSlayer(data: Record): SkyblockMemberSlayer | null { if (!data?.slayer?.slayer_bosses) return null; @@ -287,7 +290,7 @@ export function getDungeons(data: Record): SkyblockMemberDungeons | }; } -function getJacobData(data: Record): SkyblockMemberJacobData { +export function getJacobData(data: Record): SkyblockMemberJacobData { if (!data.jacobs_contest) { return { medals: { @@ -432,7 +435,7 @@ export function getPetLevel(petExp: number, offsetRarity: number, maxLevel: numb }; } -export function parseRarity(str: string) { +export function parseRarity(str: string): SkyblockRarity { const rarityArray = [ 'COMMON', 'UNCOMMON', @@ -445,14 +448,16 @@ export function parseRarity(str: string) { 'VERY SPECIAL' ]; for (const rarity of rarityArray) { - if (str.includes(rarity)) return rarity; + if (str.includes(rarity)) return rarity as SkyblockRarity; } + return 'COMMON'; } -export function parseGearScore(lore: any) { +export function parseGearScore(lore: any): number { for (const line of lore) { if (line.match(/Gear Score: §[0-9a-f](\d+)/)) return Number(line.match(/Gear Score: §d(\d+)/)[1]); } + return 0; } export function populateGoals(achieved: any[], all: any) { diff --git a/src/utils/removeSnakeCase.ts b/src/utils/removeSnakeCase.ts index ec5cca2e..8c5aabe0 100644 --- a/src/utils/removeSnakeCase.ts +++ b/src/utils/removeSnakeCase.ts @@ -1,8 +1,8 @@ -function validateJSON(obj: any) { +export function validateJSON(obj: any) { return 'object' === typeof obj && '{' === JSON.stringify(obj)[0]; } -function recursive(obj: Record, lowerCase: boolean = false): any { +export function recursive(obj: any, lowerCase: boolean = false): any { if (!validateJSON(obj)) return obj; return Object.keys(obj).reduce( (pV, cV) => ({ @@ -13,6 +13,6 @@ function recursive(obj: Record, lowerCase: boolean = false): any { ); } -function removeSnakeCaseString(str: string): string { +export function removeSnakeCaseString(str: string): string { return str.toLowerCase().replace(/_[a-z]/gi, (x) => x[1].toUpperCase()); } diff --git a/tsconfig.json b/tsconfig.json index 757355e1..5886fe9f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,4 +8,4 @@ "target": "ES2022", "strict": true } -} \ No newline at end of file +}