diff --git a/src/constants.ts b/src/constants.ts index 3dd42b1..9370722 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -5,23 +5,28 @@ export const UBISERVICES_URL = 'https://public-ubiservices.ubi.com'; export const STATUS_URL = 'https://game-status-api.ubisoft.com'; export const UBI_URL = 'https://nimbus.ubisoft.com'; +// xplay ids https://github.com/Seems2Legit/Rainbow-Six-Siege-Player-Stats-API/issues/91#issuecomment-1362054176 export const SPACE_IDS = { uplay: '5172a557-50b5-4665-b7db-e3f2e8c5041d', psn: '05bfb3f7-6c21-4c42-be1f-97a33fb5cf66', - xbl: '98a601e5-ca91-4440-b1c5-753f601a2c90' + xbl: '98a601e5-ca91-4440-b1c5-753f601a2c90', + xplay: '0d2ae42d-4c27-4cb7-af6c-2099062302bb' }; export const SANDBOXES = { uplay: 'OSBOR_PC_LNCH_A', psn: 'OSBOR_PS4_LNCH_A', - xbl: 'OSBOR_XBOXONE_LNCH_A' + xbl: 'OSBOR_XBOXONE_LNCH_A', + xplay: 'OSBOR_XPLAY_LNCH_A' }; export const AVATARS_URL = 'https://ubisoft-avatars.akamaized.net'; export const CDN_URL = 'https://staticctf.akamaized.net'; export const GITHUB_ASSETS_URL = 'https://github.com/danielwerg/r6api.js/raw/master/assets'; -export const PLATFORMS = ['uplay', 'psn', 'xbl']; -export const PLATFORMSALL = [...PLATFORMS, 'steam', 'epic', 'amazon']; +// valid stats platforms with sandboxes +export const PLATFORMS = ['uplay', 'psn', 'xbl', 'xplay']; +// valid profile platforms +export const PLATFORMSALL = ['uplay', 'psn', 'xbl', 'steam', 'epic', 'amazon']; // restructure this if pvp_newcomer will still return 500 in season 22 export const BOARDS = { diff --git a/src/methods/getProgression.ts b/src/methods/getProgression.ts index b257d3f..ad6df70 100644 --- a/src/methods/getProgression.ts +++ b/src/methods/getProgression.ts @@ -1,7 +1,7 @@ import { getToken } from '../auth'; import fetch from '../fetch'; import { Platform, UUID } from '../typings'; -import { getURL } from '../utils'; +import { getTotalXp, getURL } from '../utils'; export interface IProgression { profile_id: UUID; @@ -21,6 +21,7 @@ export default (platform: Platform, ids: UUID[]) => id: profile.profile_id, level: profile.level, xp: profile.xp, + totalXp: getTotalXp(profile.level, profile.xp), lootboxProbability: { raw: profile.lootbox_probability, percent: profile.lootbox_probability diff --git a/src/utils.ts b/src/utils.ts index 211eaea..6bd9904 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -180,6 +180,40 @@ export const getURL = { '&tags=BR-rainbow-six%20GA-siege' }; +// Sources: +// https://www.reddit.com/r/Rainbow6/comments/v8bidl/updated_xp_vs_clearance_level_chart_up_to_lvl800/ +// https://docs.google.com/spreadsheets/d/1zP-dZgV3RHGswj1Wtz2wZs6Nr7RZc7syT2_kdM4L8mU/edit?usp=sharing +const firstLevels = [ + 0, 500, 1500, 3500, 3500, 4000, 4000, 4500, 4500, 4500, 5500, 5500 +] as const; + +export const getXpPerLevel = (level: number): number => { + if (!Number.isInteger(level)) return NaN; + else if (39 <= level) return -9000 + 500 * level; + else if (12 <= level && level < 39) return 4000 + 500 * ((level / 3) >> 0); + else if (0 <= level && level < 12) return firstLevels[level] ?? NaN; + else return NaN; +}; + +export const getTotalXp = (level: number, xp = 0): number => { + if (!Number.isInteger(level) || level < 0) return NaN; + let sum = 0; + for (; level > 0; level--) sum += getXpPerLevel(level); + return sum + xp; +}; + +export const getLevelByXp = (xp: number) => { + if (!Number.isInteger(xp) || xp < 0) return NaN; + let level = 0, + currentXp = 0; + for (; xp >= (currentXp = getXpPerLevel(level)); level++) xp -= currentXp; + return level - 1; +}; + +export const getXpRemainder = (xp: number) => { + return xp - getTotalXp(getLevelByXp(xp)); +}; + export const isPlatform = (value: string): value is Platform => PLATFORMS.map(platform => platform.toString()).includes(value);