Files
Nexumi/packages/shared/src/phase3.ts
smueller fa5910ec43 Implement leveling and economy features with associated models and commands
- Added new models for leveling and economy functionalities in the Prisma schema, including LevelingConfig, MemberLevel, LevelReward, EconomyConfig, MemberEconomy, ShopItem, and InventoryItem.
- Introduced commands for managing XP, economy transactions, and shop interactions, enhancing user engagement.
- Updated job handling to include reminders and poll closing functionalities.
- Enhanced localization support for new commands and features in both German and English.
- Improved the bot's job processing capabilities with a dedicated reminder worker for scheduled tasks.
2026-07-22 12:49:17 +02:00

113 lines
3.2 KiB
TypeScript

import { z } from 'zod';
/** XP required to go from level L to L+1. */
export function xpForNextLevel(level: number): number {
return 5 * level * level + 50 * level + 100;
}
/** Total XP needed to reach a given level from 0. */
export function totalXpForLevel(level: number): number {
let total = 0;
for (let i = 0; i < level; i += 1) {
total += xpForNextLevel(i);
}
return total;
}
/** Derive level from cumulative XP. */
export function levelFromXp(xp: number): number {
let level = 0;
let remaining = Math.max(0, xp);
while (remaining >= xpForNextLevel(level)) {
remaining -= xpForNextLevel(level);
level += 1;
if (level > 1000) {
break;
}
}
return level;
}
export function progressInLevel(xp: number): { level: number; intoLevel: number; needed: number } {
const level = levelFromXp(xp);
const base = totalXpForLevel(level);
const intoLevel = xp - base;
const needed = xpForNextLevel(level);
return { level, intoLevel, needed };
}
export function randomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export const LevelUpModeSchema = z.enum(['CHANNEL', 'DM', 'OFF']);
export type LevelUpMode = z.infer<typeof LevelUpModeSchema>;
export const MultiplierMapSchema = z.record(z.string(), z.number().positive());
export type MultiplierMap = z.infer<typeof MultiplierMapSchema>;
export function parseMultiplierMap(raw: unknown): MultiplierMap {
const parsed = MultiplierMapSchema.safeParse(raw);
return parsed.success ? parsed.data : {};
}
export function formatCurrency(amount: number, symbol: string, name: string): string {
return `${symbol} ${amount.toLocaleString()} ${name}`;
}
export const EIGHT_BALL_ANSWERS = {
de: [
'Ja.',
'Nein.',
'Vielleicht.',
'Frag später nochmal.',
'Sieht gut aus.',
'Zweifelhaft.',
'Auf keinen Fall.',
'Absolut.'
],
en: [
'Yes.',
'No.',
'Maybe.',
'Ask again later.',
'Looks good.',
'Doubtful.',
'Absolutely not.',
'Absolutely.'
]
} as const;
export const TRIVIA_QUESTIONS = [
{
q: { de: 'Welche Farbe hat der Himmel an einem klaren Tag?', en: 'What color is the sky on a clear day?' },
options: { de: ['Blau', 'Grün', 'Rot', 'Gelb'], en: ['Blue', 'Green', 'Red', 'Yellow'] },
answer: 0
},
{
q: { de: 'Wie viele Kontinente gibt es?', en: 'How many continents are there?' },
options: { de: ['5', '6', '7', '8'], en: ['5', '6', '7', '8'] },
answer: 2
},
{
q: { de: 'Welches Tier ist ein Säugetier?', en: 'Which animal is a mammal?' },
options: { de: ['Hai', 'Delphin', 'Thunfisch', 'Lachs'], en: ['Shark', 'Dolphin', 'Tuna', 'Salmon'] },
answer: 1
},
{
q: { de: 'Was ist 2 + 2?', en: 'What is 2 + 2?' },
options: { de: ['3', '4', '5', '22'], en: ['3', '4', '5', '22'] },
answer: 1
},
{
q: { de: 'Hauptstadt von Frankreich?', en: 'Capital of France?' },
options: { de: ['Berlin', 'Madrid', 'Paris', 'Rom'], en: ['Berlin', 'Madrid', 'Paris', 'Rome'] },
answer: 2
}
] as const;
export const HANGMAN_WORDS = {
de: ['DISCORD', 'NEXUMI', 'SERVER', 'MODERATION', 'BOT', 'KANAL', 'ROLLE'],
en: ['DISCORD', 'NEXUMI', 'SERVER', 'MODERATION', 'BOT', 'CHANNEL', 'ROLE']
} as const;