From 6330e1d3fb8920059a46e6b0a828ebd6fe3a42dd Mon Sep 17 00:00:00 2001 From: Isaac Overacker Date: Sun, 26 Nov 2023 20:07:04 -0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Set=20XP=20tracker=20to=20more=20se?= =?UTF-8?q?nsible=20values=20for=20experience-based=20leveling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of 0 / 355000, set the XP tracker's current `value` to the amount of experience earned within the current level and the `max` to the experience required to reach the next level. --- src/convert.ts | 15 +++- src/fifth-edition.ts | 150 +++++++++++++++++++++++++++++++++++++++ test/convert.exp.test.ts | 33 +++++++-- 3 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 src/fifth-edition.ts diff --git a/src/convert.ts b/src/convert.ts index c91cc48..58b9b80 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -26,6 +26,11 @@ import { DdbSpell, DdbSpellActivationType, } from './ddb'; +import { + getBaseExperienceForLevel, + getExperienceRequiredForNextLevel, + getLevelFromExp, +} from './fifth-edition'; // Shared between both platforms const STR = 1; @@ -1040,13 +1045,19 @@ const convertSpellHigherLevels = (ddbSpell: DdbSpell): AlchemySpellAtHigherLevel */ const convertTrackers = (ddbCharacter: DdbCharacter): AlchemyTracker[] => { + const totalExp = ddbCharacter.currentXp; + const level = getLevelFromExp(totalExp); + const baseExp = getBaseExperienceForLevel(level); + const nextLevelExp = getExperienceRequiredForNextLevel(totalExp); + const expIntoLevel = totalExp - baseExp; + return [ { name: 'XP', category: 'experience', color: 'Yellow', - max: 355000, - value: ddbCharacter.currentXp, + max: nextLevelExp, + value: expIntoLevel, type: 'Bar', sortOrder: 0, }, diff --git a/src/fifth-edition.ts b/src/fifth-edition.ts new file mode 100644 index 0000000..217eb6e --- /dev/null +++ b/src/fifth-edition.ts @@ -0,0 +1,150 @@ +/** + * Returns the experience required for the next level given a 5e character's + * total experience. + * @param currentExp The character's current total experience. + * @returns The amount of experience required for the next level. + */ +export const getExperienceRequiredForNextLevel = ( + currentExp: number, +): number => { + if (currentExp < 300) { + return 300; + } else if (currentExp < 900) { + return 900; + } else if (currentExp < 2700) { + return 2700; + } else if (currentExp < 6500) { + return 6500; + } else if (currentExp < 14000) { + return 14000; + } else if (currentExp < 23000) { + return 23000; + } else if (currentExp < 34000) { + return 34000; + } else if (currentExp < 48000) { + return 48000; + } else if (currentExp < 64000) { + return 64000; + } else if (currentExp < 85000) { + return 85000; + } else if (currentExp < 100000) { + return 100000; + } else if (currentExp < 120000) { + return 120000; + } else if (currentExp < 140000) { + return 140000; + } else if (currentExp < 165000) { + return 165000; + } else if (currentExp < 195000) { + return 195000; + } else if (currentExp < 225000) { + return 225000; + } else if (currentExp < 265000) { + return 265000; + } else if (currentExp < 305000) { + return 305000; + } else if (currentExp < 355000) { + return 355000; + } else { + return NaN; + } +}; + +/** + * Returns the minimum experience required for a level given a 5e character's + * current level. + * @param currentLevel The character's current level. + * @returns The minimum amount of experience required for the level. + */ +export const getBaseExperienceForLevel = (level: number): number => { + if (level <= 1) { + return 0; + } else if (level === 2) { + return 300; + } else if (level === 3) { + return 900; + } else if (level === 4) { + return 2700; + } else if (level === 5) { + return 6500; + } else if (level === 6) { + return 14000; + } else if (level === 7) { + return 23000; + } else if (level === 8) { + return 34000; + } else if (level === 9) { + return 48000; + } else if (level === 10) { + return 64000; + } else if (level === 11) { + return 85000; + } else if (level === 12) { + return 100000; + } else if (level === 13) { + return 120000; + } else if (level === 14) { + return 140000; + } else if (level === 15) { + return 165000; + } else if (level === 16) { + return 195000; + } else if (level === 17) { + return 225000; + } else if (level === 18) { + return 265000; + } else if (level === 19) { + return 305000; + } else { + return 355000; + } +}; + +/** + * Returns the level corresponding to a given amount of experience. + * @param exp The character's current total experience. + * @returns The character's level. + */ +export const getLevelFromExp = (exp: number): number => { + if (exp < 300) { + return 1; + } else if (exp < 900) { + return 2; + } else if (exp < 2700) { + return 3; + } else if (exp < 6500) { + return 4; + } else if (exp < 14000) { + return 5; + } else if (exp < 23000) { + return 6; + } else if (exp < 34000) { + return 7; + } else if (exp < 48000) { + return 8; + } else if (exp < 64000) { + return 9; + } else if (exp < 85000) { + return 10; + } else if (exp < 100000) { + return 11; + } else if (exp < 120000) { + return 12; + } else if (exp < 140000) { + return 13; + } else if (exp < 165000) { + return 14; + } else if (exp < 195000) { + return 15; + } else if (exp < 225000) { + return 16; + } else if (exp < 265000) { + return 17; + } else if (exp < 305000) { + return 18; + } else if (exp < 355000) { + return 19; + } else { + return 20; + } +}; diff --git a/test/convert.exp.test.ts b/test/convert.exp.test.ts index 0aaf9b2..c2a07f5 100644 --- a/test/convert.exp.test.ts +++ b/test/convert.exp.test.ts @@ -6,12 +6,31 @@ import { DeepPartial } from './test-helpers'; describe('Convert DDB currentXp to Alchemy tracker', () => { test.each` - currentXp | expected - ${10} | ${10} - ${0} | ${0} + currentXp | expectedValue | expectedMax + ${0} | ${0} | ${300} + ${300} | ${0} | ${900} + ${600} | ${300} | ${900} + ${900} | ${0} | ${2700} + ${1500} | ${600} | ${2700} + ${2700} | ${0} | ${6500} + ${6500} | ${0} | ${14000} + ${14000} | ${0} | ${23000} + ${23000} | ${0} | ${34000} + ${34000} | ${0} | ${48000} + ${48000} | ${0} | ${64000} + ${64000} | ${0} | ${85000} + ${85000} | ${0} | ${100000} + ${100000} | ${0} | ${120000} + ${120000} | ${0} | ${140000} + ${140000} | ${0} | ${165000} + ${165000} | ${0} | ${195000} + ${195000} | ${0} | ${225000} + ${225000} | ${0} | ${265000} + ${265000} | ${0} | ${305000} + ${305000} | ${0} | ${355000} `( - 'returns tracker.value=$expected when currentXp=$currentXp', - ({ currentXp, expected }) => { + 'returns tracker.value=$expectedValue and tracker.max=$expectedMax when currentXp=$currentXp', + ({ currentXp, expectedValue, expectedMax }) => { const ddbChar: DeepPartial = { currentXp, }; @@ -24,8 +43,8 @@ describe('Convert DDB currentXp to Alchemy tracker', () => { (t) => t.category === 'experience', ); - expect(expTracker.value).toEqual(expected); - expect(expTracker.max).toEqual(355000); + expect(expTracker.value).toEqual(expectedValue); + expect(expTracker.max).toEqual(expectedMax); }, ); });