diff --git a/src/graphics/studentID.ts b/src/graphics/studentID.ts index 22b439f..552963a 100644 --- a/src/graphics/studentID.ts +++ b/src/graphics/studentID.ts @@ -97,9 +97,12 @@ export async function generateStudentIdCard(data: StudentCardData): Promise { - return Math.floor(config.leveling.base * Math.pow(level, config.leveling.exponent)); + // Calculate total XP required to REACH a specific level (Cumulative) + // Level 1 = 0 XP + // Level 2 = Base * (1^Exp) + // Level 3 = Level 2 + Base * (2^Exp) + // ... + getXpToReachLevel: (level: number) => { + let total = 0; + for (let l = 1; l < level; l++) { + total += Math.floor(config.leveling.base * Math.pow(l, config.leveling.exponent)); + } + return total; }, - // Pure XP addition - No cooldown checks + // Calculate level from Total XP + getLevelFromXp: (totalXp: bigint) => { + let level = 1; + let xp = Number(totalXp); + + while (true) { + // XP needed to complete current level and reach next + const xpForNext = Math.floor(config.leveling.base * Math.pow(level, config.leveling.exponent)); + if (xp < xpForNext) { + return level; + } + xp -= xpForNext; + level++; + } + }, + + // Get XP needed to complete the current level (for calculating next level threshold in isolation) + // Used internally or for display + getXpForNextLevel: (currentLevel: number) => { + return Math.floor(config.leveling.base * Math.pow(currentLevel, config.leveling.exponent)); + }, + + // Cumulative XP addition addXp: async (id: string, amount: bigint, tx?: Transaction) => { return await withTransaction(async (txFn) => { // Get current state @@ -20,30 +50,24 @@ export const levelingService = { if (!user) throw new Error("User not found"); - let newXp = (user.xp ?? 0n) + amount; - let currentLevel = user.level ?? 1; - let levelUp = false; + const currentXp = user.xp ?? 0n; + const newXp = currentXp + amount; - // Check for level up loop - let xpForNextLevel = BigInt(levelingService.getXpForLevel(currentLevel)); - - while (newXp >= xpForNextLevel) { - newXp -= xpForNextLevel; - currentLevel++; - levelUp = true; - xpForNextLevel = BigInt(levelingService.getXpForLevel(currentLevel)); - } + // Calculate new level based on TOTAL accumulated XP + const newLevel = levelingService.getLevelFromXp(newXp); + const currentLevel = user.level ?? 1; + const levelUp = newLevel > currentLevel; // Update user const [updatedUser] = await txFn.update(users) .set({ xp: newXp, - level: currentLevel, + level: newLevel, }) .where(eq(users.id, BigInt(id))) .returning(); - return { user: updatedUser, levelUp, currentLevel }; + return { user: updatedUser, levelUp, currentLevel: newLevel }; }, tx); },