forked from syntaxbullet/AuroraBot-discord
feat: Introduce GameConfig to centralize constants for leveling, economy, and inventory, adding new transfer and inventory limits.
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
import { users, transactions, cooldowns } from "@/db/schema";
|
||||
import { eq, sql, and } from "drizzle-orm";
|
||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||
|
||||
const DAILY_REWARD_AMOUNT = 100n;
|
||||
const STREAK_BONUS = 10n;
|
||||
const DAILY_COOLDOWN = 24 * 60 * 60 * 1000; // 24 hours in ms
|
||||
import { GameConfig } from "@/config/game";
|
||||
|
||||
export const economyService = {
|
||||
transfer: async (fromUserId: string, toUserId: string, amount: bigint, tx?: any) => {
|
||||
@@ -112,9 +109,9 @@ export const economyService = {
|
||||
streak = 1;
|
||||
}
|
||||
|
||||
const bonus = (BigInt(streak) - 1n) * STREAK_BONUS;
|
||||
const bonus = (BigInt(streak) - 1n) * GameConfig.economy.daily.streakBonus;
|
||||
|
||||
const totalReward = DAILY_REWARD_AMOUNT + bonus;
|
||||
const totalReward = GameConfig.economy.daily.amount + bonus;
|
||||
|
||||
// Update User w/ Economy Service (reuse modifyUserBalance if we split it out, but here manual is fine for atomic combined streak update)
|
||||
// Actually, we can just update directly here as we are already refining specific fields like streak.
|
||||
@@ -127,7 +124,7 @@ export const economyService = {
|
||||
.where(eq(users.id, BigInt(userId)));
|
||||
|
||||
// Set new cooldown (now + 24h)
|
||||
const nextReadyAt = new Date(now.getTime() + DAILY_COOLDOWN);
|
||||
const nextReadyAt = new Date(now.getTime() + GameConfig.economy.daily.cooldownMs);
|
||||
|
||||
await txFn.insert(cooldowns)
|
||||
.values({
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
import { inventory, items, users } from "@/db/schema";
|
||||
import { eq, and, sql } from "drizzle-orm";
|
||||
import { eq, and, sql, count } from "drizzle-orm";
|
||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||
import { economyService } from "@/modules/economy/economy.service";
|
||||
import { GameConfig } from "@/config/game";
|
||||
|
||||
export const inventoryService = {
|
||||
addItem: async (userId: string, itemId: number, quantity: bigint = 1n, tx?: any) => {
|
||||
@@ -16,9 +17,14 @@ export const inventoryService = {
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
const newQuantity = (existing.quantity ?? 0n) + quantity;
|
||||
if (newQuantity > GameConfig.inventory.maxStackSize) {
|
||||
throw new Error(`Cannot exceed max stack size of ${GameConfig.inventory.maxStackSize}`);
|
||||
}
|
||||
|
||||
const [entry] = await txFn.update(inventory)
|
||||
.set({
|
||||
quantity: sql`${inventory.quantity} + ${quantity}`,
|
||||
quantity: newQuantity,
|
||||
})
|
||||
.where(and(
|
||||
eq(inventory.userId, BigInt(userId)),
|
||||
@@ -27,6 +33,20 @@ export const inventoryService = {
|
||||
.returning();
|
||||
return entry;
|
||||
} else {
|
||||
// Check Slot Limit
|
||||
const [inventoryCount] = await txFn
|
||||
.select({ count: count() })
|
||||
.from(inventory)
|
||||
.where(eq(inventory.userId, BigInt(userId)));
|
||||
|
||||
if (inventoryCount.count >= GameConfig.inventory.maxSlots) {
|
||||
throw new Error(`Inventory full (Max ${GameConfig.inventory.maxSlots} slots)`);
|
||||
}
|
||||
|
||||
if (quantity > GameConfig.inventory.maxStackSize) {
|
||||
throw new Error(`Cannot exceed max stack size of ${GameConfig.inventory.maxStackSize}`);
|
||||
}
|
||||
|
||||
const [entry] = await txFn.insert(inventory)
|
||||
.values({
|
||||
userId: BigInt(userId),
|
||||
@@ -105,16 +125,9 @@ export const inventoryService = {
|
||||
// Since we are modifying buyItem, we can just inline the item addition or call addItem if we update it.
|
||||
// Let's assume we update addItem next. For now, inline the add logic but cleaner.
|
||||
|
||||
const existingInv = await txFn.query.inventory.findFirst({
|
||||
where: and(eq(inventory.userId, BigInt(userId)), eq(inventory.itemId, itemId)),
|
||||
});
|
||||
|
||||
if (existingInv) {
|
||||
await txFn.update(inventory).set({ quantity: sql`${inventory.quantity} + ${quantity}` })
|
||||
.where(and(eq(inventory.userId, BigInt(userId)), eq(inventory.itemId, itemId)));
|
||||
} else {
|
||||
await txFn.insert(inventory).values({ userId: BigInt(userId), itemId, quantity });
|
||||
}
|
||||
// Add Item using inner logic or self-call if we refactor properly.
|
||||
// Calling addItem directly within the same transaction scope:
|
||||
await inventoryService.addItem(userId, itemId, quantity, txFn);
|
||||
|
||||
return { success: true, item, totalPrice };
|
||||
};
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
import { users, cooldowns } from "@/db/schema";
|
||||
import { eq, sql, and } from "drizzle-orm";
|
||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||
|
||||
// Simple configurable curve: Base * (Level ^ Exponent)
|
||||
const XP_BASE = 100;
|
||||
const XP_EXPONENT = 2.5;
|
||||
const CHAT_XP_COOLDOWN_MS = 60000; // 1 minute
|
||||
const MIN_CHAT_XP = 15;
|
||||
const MAX_CHAT_XP = 25;
|
||||
import { GameConfig } from "@/config/game";
|
||||
|
||||
export const levelingService = {
|
||||
// Calculate XP required for a specific level
|
||||
getXpForLevel: (level: number) => {
|
||||
return Math.floor(XP_BASE * Math.pow(level, XP_EXPONENT));
|
||||
return Math.floor(GameConfig.leveling.base * Math.pow(level, GameConfig.leveling.exponent));
|
||||
},
|
||||
|
||||
// Pure XP addition - No cooldown checks
|
||||
@@ -77,13 +71,13 @@ export const levelingService = {
|
||||
}
|
||||
|
||||
// Calculate random XP
|
||||
const amount = BigInt(Math.floor(Math.random() * (MAX_CHAT_XP - MIN_CHAT_XP + 1)) + MIN_CHAT_XP);
|
||||
const amount = BigInt(Math.floor(Math.random() * (GameConfig.leveling.chat.maxXp - GameConfig.leveling.chat.minXp + 1)) + GameConfig.leveling.chat.minXp);
|
||||
|
||||
// Add XP
|
||||
const result = await levelingService.addXp(id, amount, txFn);
|
||||
|
||||
// Update/Set Cooldown
|
||||
const nextReadyAt = new Date(now.getTime() + CHAT_XP_COOLDOWN_MS);
|
||||
const nextReadyAt = new Date(now.getTime() + GameConfig.leveling.chat.cooldownMs);
|
||||
|
||||
await txFn.insert(cooldowns)
|
||||
.values({
|
||||
|
||||
Reference in New Issue
Block a user