337 lines
9.9 KiB
TypeScript
337 lines
9.9 KiB
TypeScript
import { MessageFlags } from "discord.js";
|
|
import type { TriviaSession, TriviaResult } from "@shared/modules/trivia/trivia.service";
|
|
|
|
/**
|
|
* Get color based on difficulty level
|
|
*/
|
|
function getDifficultyColor(difficulty: string): number {
|
|
switch (difficulty.toLowerCase()) {
|
|
case 'easy':
|
|
return 0x57F287; // Green
|
|
case 'medium':
|
|
return 0xFEE75C; // Yellow
|
|
case 'hard':
|
|
return 0xED4245; // Red
|
|
default:
|
|
return 0x5865F2; // Blurple
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get emoji for difficulty level
|
|
*/
|
|
function getDifficultyEmoji(difficulty: string): string {
|
|
switch (difficulty.toLowerCase()) {
|
|
case 'easy':
|
|
return '🟢';
|
|
case 'medium':
|
|
return '🟡';
|
|
case 'hard':
|
|
return '🔴';
|
|
default:
|
|
return '⭐';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate Components v2 message for a trivia question
|
|
*/
|
|
export function getTriviaQuestionView(session: TriviaSession, username: string): {
|
|
components: any[];
|
|
flags: number;
|
|
} {
|
|
const { question, allAnswers, entryFee, potentialReward, expiresAt, sessionId } = session;
|
|
|
|
// Calculate time remaining
|
|
const now = Date.now();
|
|
const timeLeft = Math.max(0, expiresAt.getTime() - now);
|
|
const secondsLeft = Math.floor(timeLeft / 1000);
|
|
|
|
const difficultyEmoji = getDifficultyEmoji(question.difficulty);
|
|
const difficultyText = question.difficulty.charAt(0).toUpperCase() + question.difficulty.slice(1);
|
|
const accentColor = getDifficultyColor(question.difficulty);
|
|
|
|
const components: any[] = [];
|
|
|
|
// Main Container with difficulty accent color
|
|
components.push({
|
|
type: 17, // Container
|
|
accent_color: accentColor,
|
|
components: [
|
|
// Title and metadata section
|
|
{
|
|
type: 10, // Text Display
|
|
content: `# 🎯 Trivia Challenge\n**${difficultyEmoji} ${difficultyText}** • 📚 ${question.category}`
|
|
},
|
|
// Separator
|
|
{
|
|
type: 14, // Separator
|
|
spacing: 1,
|
|
divider: true
|
|
},
|
|
// Question
|
|
{
|
|
type: 10, // Text Display
|
|
content: `### ${question.question}`
|
|
},
|
|
// Stats section
|
|
{
|
|
type: 14, // Separator
|
|
spacing: 1,
|
|
divider: false
|
|
},
|
|
{
|
|
type: 10, // Text Display
|
|
content: `⏱️ **Time:** <t:${Math.floor(expiresAt.getTime() / 1000)}:R> (${secondsLeft}s)\n💰 **Stakes:** ${entryFee} AU ➜ ${potentialReward} AU\n👤 **Player:** ${username}`
|
|
}
|
|
]
|
|
});
|
|
|
|
// Answer buttons
|
|
if (question.type === 'boolean') {
|
|
const trueIndex = allAnswers.indexOf('True');
|
|
const falseIndex = allAnswers.indexOf('False');
|
|
|
|
components.push({
|
|
type: 1, // Action Row
|
|
components: [
|
|
{
|
|
type: 2, // Button
|
|
custom_id: `trivia_answer_${sessionId}_${trueIndex}`,
|
|
label: 'True',
|
|
style: 3, // Success
|
|
emoji: { name: '✅' }
|
|
},
|
|
{
|
|
type: 2, // Button
|
|
custom_id: `trivia_answer_${sessionId}_${falseIndex}`,
|
|
label: 'False',
|
|
style: 4, // Danger
|
|
emoji: { name: '❌' }
|
|
}
|
|
]
|
|
});
|
|
} else {
|
|
const labels = ['A', 'B', 'C', 'D'];
|
|
const emojis = ['🇦', '🇧', '🇨', '🇩'];
|
|
|
|
const buttonRow: any = {
|
|
type: 1, // Action Row
|
|
components: []
|
|
};
|
|
|
|
for (let i = 0; i < allAnswers.length && i < 4; i++) {
|
|
const label = labels[i];
|
|
const emoji = emojis[i];
|
|
const answer = allAnswers[i];
|
|
|
|
if (!label || !emoji || !answer) continue;
|
|
|
|
buttonRow.components.push({
|
|
type: 2, // Button
|
|
custom_id: `trivia_answer_${sessionId}_${i}`,
|
|
label: `${label}: ${answer.substring(0, 30)}${answer.length > 30 ? '...' : ''}`,
|
|
style: 2, // Secondary
|
|
emoji: { name: emoji }
|
|
});
|
|
}
|
|
|
|
components.push(buttonRow);
|
|
}
|
|
|
|
// Give Up button in separate row
|
|
components.push({
|
|
type: 1, // Action Row
|
|
components: [
|
|
{
|
|
type: 2, // Button
|
|
custom_id: `trivia_giveup_${sessionId}`,
|
|
label: 'Give Up',
|
|
style: 4, // Danger
|
|
emoji: { name: '🏳️' }
|
|
}
|
|
]
|
|
});
|
|
|
|
return {
|
|
components,
|
|
flags: MessageFlags.IsComponentsV2
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate Components v2 result message
|
|
*/
|
|
export function getTriviaResultView(
|
|
result: TriviaResult,
|
|
question: string,
|
|
userAnswer?: string,
|
|
allAnswers?: string[],
|
|
entryFee: bigint = 0n
|
|
): {
|
|
components: any[];
|
|
flags: number;
|
|
} {
|
|
const { correct, reward, correctAnswer } = result;
|
|
const components: any[] = [];
|
|
|
|
if (correct) {
|
|
// Success container
|
|
components.push({
|
|
type: 17, // Container
|
|
accent_color: 0x57F287, // Green
|
|
components: [
|
|
{
|
|
type: 10, // Text Display
|
|
content: `# 🎉 Correct Answer!\n### ${question}`
|
|
},
|
|
{
|
|
type: 14, // Separator
|
|
spacing: 1,
|
|
divider: true
|
|
},
|
|
{
|
|
type: 10, // Text Display
|
|
content: `✅ **Your answer:** ${correctAnswer}\n\n💰 **Reward:** +${reward} AU\n\n🏆 Great job! Keep it up!`
|
|
}
|
|
]
|
|
});
|
|
} else {
|
|
const answerDisplay = userAnswer
|
|
? `❌ **Your answer:** ${userAnswer}\n✅ **Correct answer:** ${correctAnswer}`
|
|
: `✅ **Correct answer:** ${correctAnswer}`;
|
|
|
|
// Error container
|
|
components.push({
|
|
type: 17, // Container
|
|
accent_color: 0xED4245, // Red
|
|
components: [
|
|
{
|
|
type: 10, // Text Display
|
|
content: `# ❌ Incorrect Answer\n### ${question}`
|
|
},
|
|
{
|
|
type: 14, // Separator
|
|
spacing: 1,
|
|
divider: true
|
|
},
|
|
{
|
|
type: 10, // Text Display
|
|
content: `${answerDisplay}\n\n💸 **Entry fee lost:** ${entryFee} AU\n\n📚 Better luck next time!`
|
|
}
|
|
]
|
|
});
|
|
}
|
|
|
|
// Show disabled buttons with visual feedback
|
|
if (allAnswers && allAnswers.length > 0) {
|
|
const buttonRow: any = {
|
|
type: 1, // Action Row
|
|
components: []
|
|
};
|
|
|
|
const labels = ['A', 'B', 'C', 'D'];
|
|
const emojis = ['🇦', '🇧', '🇨', '🇩'];
|
|
|
|
for (let i = 0; i < allAnswers.length && i < 4; i++) {
|
|
const label = labels[i];
|
|
const emoji = emojis[i];
|
|
const answer = allAnswers[i];
|
|
|
|
if (!label || !emoji || !answer) continue;
|
|
|
|
const isCorrect = answer === correctAnswer;
|
|
const wasUserAnswer = answer === userAnswer;
|
|
|
|
buttonRow.components.push({
|
|
type: 2, // Button
|
|
custom_id: `trivia_result_${i}`,
|
|
label: `${label}: ${answer.substring(0, 30)}${answer.length > 30 ? '...' : ''}`,
|
|
style: isCorrect ? 3 : wasUserAnswer ? 4 : 2, // Success : Danger : Secondary
|
|
emoji: { name: isCorrect ? '✅' : wasUserAnswer ? '❌' : emoji },
|
|
disabled: true
|
|
});
|
|
}
|
|
|
|
components.push(buttonRow);
|
|
}
|
|
|
|
return {
|
|
components,
|
|
flags: MessageFlags.IsComponentsV2
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate Components v2 timeout message
|
|
*/
|
|
export function getTriviaTimeoutView(
|
|
question: string,
|
|
correctAnswer: string,
|
|
allAnswers?: string[],
|
|
entryFee: bigint = 0n
|
|
): {
|
|
components: any[];
|
|
flags: number;
|
|
} {
|
|
const components: any[] = [];
|
|
|
|
// Timeout container
|
|
components.push({
|
|
type: 17, // Container
|
|
accent_color: 0xFEE75C, // Yellow
|
|
components: [
|
|
{
|
|
type: 10, // Text Display
|
|
content: `# ⏱️ Time's Up!\n### ${question}`
|
|
},
|
|
{
|
|
type: 14, // Separator
|
|
spacing: 1,
|
|
divider: true
|
|
},
|
|
{
|
|
type: 10, // Text Display
|
|
content: `⏰ **You ran out of time!**\n✅ **Correct answer:** ${correctAnswer}\n\n💸 **Entry fee lost:** ${entryFee} AU\n\n⚡ Be faster next time!`
|
|
}
|
|
]
|
|
});
|
|
|
|
// Show disabled buttons with correct answer highlighted
|
|
if (allAnswers && allAnswers.length > 0) {
|
|
const buttonRow: any = {
|
|
type: 1, // Action Row
|
|
components: []
|
|
};
|
|
|
|
const labels = ['A', 'B', 'C', 'D'];
|
|
const emojis = ['🇦', '🇧', '🇨', '🇩'];
|
|
|
|
for (let i = 0; i < allAnswers.length && i < 4; i++) {
|
|
const label = labels[i];
|
|
const emoji = emojis[i];
|
|
const answer = allAnswers[i];
|
|
|
|
if (!label || !emoji || !answer) continue;
|
|
|
|
const isCorrect = answer === correctAnswer;
|
|
|
|
buttonRow.components.push({
|
|
type: 2, // Button
|
|
custom_id: `trivia_timeout_${i}`,
|
|
label: `${label}: ${answer.substring(0, 30)}${answer.length > 30 ? '...' : ''}`,
|
|
style: isCorrect ? 3 : 2, // Success : Secondary
|
|
emoji: { name: isCorrect ? '✅' : emoji },
|
|
disabled: true
|
|
});
|
|
}
|
|
|
|
components.push(buttonRow);
|
|
}
|
|
|
|
return {
|
|
components,
|
|
flags: MessageFlags.IsComponentsV2
|
|
};
|
|
}
|