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:
89
src/modules/quest/quest.service.ts
Normal file
89
src/modules/quest/quest.service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
|
||||
import { quests, userQuests, users } from "@/db/schema";
|
||||
import { eq, and, sql } from "drizzle-orm";
|
||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||
import { economyService } from "@/modules/economy/economy.service";
|
||||
import { levelingService } from "@/modules/leveling/leveling.service";
|
||||
|
||||
export const questService = {
|
||||
assignQuest: async (userId: string, questId: number, tx?: any) => {
|
||||
const execute = async (txFn: any) => {
|
||||
return await txFn.insert(userQuests)
|
||||
.values({
|
||||
userId: BigInt(userId),
|
||||
questId: questId,
|
||||
progress: 0,
|
||||
})
|
||||
.onConflictDoNothing() // Ignore if already assigned
|
||||
.returning();
|
||||
};
|
||||
return tx ? await execute(tx) : await DrizzleClient.transaction(execute);
|
||||
},
|
||||
|
||||
updateProgress: async (userId: string, questId: number, progress: number, tx?: any) => {
|
||||
const execute = async (txFn: any) => {
|
||||
return await txFn.update(userQuests)
|
||||
.set({ progress: progress })
|
||||
.where(and(
|
||||
eq(userQuests.userId, BigInt(userId)),
|
||||
eq(userQuests.questId, questId)
|
||||
))
|
||||
.returning();
|
||||
};
|
||||
return tx ? await execute(tx) : await DrizzleClient.transaction(execute);
|
||||
},
|
||||
|
||||
completeQuest: async (userId: string, questId: number, tx?: any) => {
|
||||
const execute = async (txFn: any) => {
|
||||
const userQuest = await txFn.query.userQuests.findFirst({
|
||||
where: and(
|
||||
eq(userQuests.userId, BigInt(userId)),
|
||||
eq(userQuests.questId, questId)
|
||||
),
|
||||
with: {
|
||||
quest: true,
|
||||
}
|
||||
});
|
||||
|
||||
if (!userQuest) throw new Error("Quest not assigned");
|
||||
if (userQuest.completedAt) throw new Error("Quest already completed");
|
||||
|
||||
// Mark completed
|
||||
await txFn.update(userQuests)
|
||||
.set({ completedAt: new Date() })
|
||||
.where(and(
|
||||
eq(userQuests.userId, BigInt(userId)),
|
||||
eq(userQuests.questId, questId)
|
||||
));
|
||||
|
||||
// Distribute Rewards
|
||||
const rewards = userQuest.quest.rewards as { xp?: number, balance?: number };
|
||||
const results = { xp: 0n, balance: 0n };
|
||||
|
||||
if (rewards?.balance) {
|
||||
const bal = BigInt(rewards.balance);
|
||||
await economyService.modifyUserBalance(userId, bal, 'QUEST_REWARD', `Reward for quest ${questId}`, txFn);
|
||||
results.balance = bal;
|
||||
}
|
||||
|
||||
if (rewards?.xp) {
|
||||
const xp = BigInt(rewards.xp);
|
||||
await levelingService.addXp(userId, xp, txFn);
|
||||
results.xp = xp;
|
||||
}
|
||||
|
||||
return { success: true, rewards: results };
|
||||
};
|
||||
|
||||
return tx ? await execute(tx) : await DrizzleClient.transaction(execute);
|
||||
},
|
||||
|
||||
getUserQuests: async (userId: string) => {
|
||||
return await DrizzleClient.query.userQuests.findMany({
|
||||
where: eq(userQuests.userId, BigInt(userId)),
|
||||
with: {
|
||||
quest: true,
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user