feat: Introduce new modules for class, inventory, leveling, and quests with expanded schema, refactor user service, and add verification scripts.

This commit is contained in:
syntaxbullet
2025-12-07 23:03:33 +01:00
parent be471f348d
commit 29c0a4752d
21 changed files with 1228 additions and 163 deletions

View File

@@ -0,0 +1,58 @@
import { users } from "@/db/schema";
import { eq, sql } from "drizzle-orm";
import { DrizzleClient } from "@/lib/DrizzleClient";
// Simple configurable curve: Base * (Level ^ Exponent)
const XP_BASE = 1000;
const XP_EXPONENT = 1.5;
export const levelingService = {
// Calculate XP required for a specific level
getXpForLevel: (level: number) => {
return Math.floor(XP_BASE * Math.pow(level, XP_EXPONENT));
},
addXp: async (id: string, amount: bigint, tx?: any) => {
const execute = async (txFn: any) => {
// Get current state
const user = await txFn.query.users.findFirst({
where: eq(users.id, BigInt(id)),
});
if (!user) throw new Error("User not found");
let newXp = (user.xp ?? 0n) + amount;
let currentLevel = user.level ?? 1;
let levelUp = false;
// Check for level up loop
let xpForNextLevel = BigInt(levelingService.getXpForLevel(currentLevel));
while (newXp >= xpForNextLevel) {
newXp -= xpForNextLevel;
currentLevel++;
levelUp = true;
xpForNextLevel = BigInt(levelingService.getXpForLevel(currentLevel));
}
// Update user
const [updatedUser] = await txFn.update(users)
.set({
xp: newXp,
level: currentLevel,
})
.where(eq(users.id, BigInt(id)))
.returning();
return { user: updatedUser, levelUp, currentLevel };
}
if (tx) {
return await execute(tx);
} else {
return await DrizzleClient.transaction(async (t) => {
return await execute(t);
})
}
},
};