Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1c5e812
Fix c4 invalid opponents + module warning
DEVTomatoCake Feb 21, 2023
b2816d4
highlight c4 win sequence
DEVTomatoCake Feb 22, 2023
6b3ade0
prepare uno
DEVTomatoCake Feb 22, 2023
e50f466
uno controls
DEVTomatoCake Feb 24, 2023
0827a9b
almost finish uno (send help)
DEVTomatoCake Feb 24, 2023
97d27ff
uno: eslint + en
DEVTomatoCake Feb 25, 2023
857c115
fix 2 small uno bugs
DEVTomatoCake Feb 25, 2023
5df4494
start now button
DEVTomatoCake Feb 25, 2023
86b31b2
uno avoid duplicate
DEVTomatoCake Feb 25, 2023
21b44c4
add uno player limit
DEVTomatoCake Feb 25, 2023
7500183
uno: display previous cards + fixes
DEVTomatoCake Feb 25, 2023
b03955c
translate previous cards
DEVTomatoCake Feb 25, 2023
2cf23e8
add partly quiz module
DEVTomatoCake Mar 6, 2023
1142ca2
remove quiz end + add leaderboard
DEVTomatoCake Mar 7, 2023
003510d
leaderboard command + quizlist conf
DEVTomatoCake Mar 8, 2023
fc66a84
Quiz list conf + more qplay work
DEVTomatoCake Mar 9, 2023
de13dce
more quiz play work .-.
DEVTomatoCake Mar 11, 2023
31fee7b
db model fixes
DEVTomatoCake Mar 11, 2023
b77e1fb
eslint fix
DEVTomatoCake Mar 11, 2023
e8e3177
more quiz work (finished?)
DEVTomatoCake Mar 13, 2023
3e48cf3
fix weird double msg bug
DEVTomatoCake Mar 13, 2023
467cbb6
add quiz selection mode
DEVTomatoCake Mar 13, 2023
6379375
Merge branch 'main' into main
DEVTomatoCake Mar 13, 2023
b3d46b4
add required role create config
DEVTomatoCake Mar 13, 2023
d7ff2d9
Merge branch 'main' of https://github.com/DEVTomatoCake/ScootKit-Cust…
DEVTomatoCake Mar 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"config": {
"checking-config": "Konfiguration wird überprüft...",
"done-with-checking": "Konfiguration erfolgreich überprüft.",
"creating-file": "Konfiguration %m/%f exestiert aktuell nicht, wird aber gleich erstellt...",
"creating-file": "Konfiguration %m/%f existiert aktuell nicht, wird aber gleich erstellt...",
"checking-of-field-failed": "Ein Fehler bei der Überprüfung von %fieldName in %m/%f ist aufgetreten",
"saved-file": "Konfiguration %f in %m wurde erfolgreich generiert.",
"moduleconf-regeneration": "Modul-Konfiguration wird regeniert, es werden keine Einstellungen überschrieben.",
Expand Down Expand Up @@ -926,5 +926,40 @@
"not-host": "Du bist nicht der Ersteller des Spiels!",
"max-players": "Das Spiel ist voll!",
"previous-cards": "Vorherige Karten: "
},
"quiz": {
"what-have-i-voted": "Was habe ich gewählt?",
"vote": "Abstimmen!",
"vote-this": "Wähle diese Option, wenn du denkst, dass diese richtig ist.",
"voted-successfully": "Erfolgreich ausgewählt. Danke für deine Teilnahme.",
"not-voted-yet": "Du hast noch keine Antwort ausgewählt, also kann ich dir nicht zeigen, für was du abgestimmt hast?",
"you-voted": "Du hast **%o** als Antwort ausgewählt.",
"change-opinion": "Du kannst deine Auswahl jederzeit ändern, indem du einfach etwas anderes über dem Knopf, den du gerade angeklickt hast, auswählst.",
"cannot-change-opinion": "Du kannst deine Auswahl nicht ändern, da der Ersteller diese Funktion deaktiviert hat.",
"select-correct": "Wähle alle richtigen Antworten aus",
"this-correct": "Diese Antwort als richtig markieren",
"cmd-description": "Erstelle oder spiele Quiz",
"cmd-create-normal-description": "Erstelle ein Quiz mit bis zu 10 Antworten",
"cmd-create-bool-description": "Erstelle ein Quiz, bei dem Nutzer nur Ja oder Nein auswählen können",
"cmd-play-description": "Spiele ein Server-Quiz",
"cmd-leaderboard-description": "Zeigt das Quiz-Leaderboard des Servers",
"cmd-create-description-description": "Thema / Beschreibung des Quiz",
"cmd-create-channel-description": "Kanal, in welchem dieses Quiz erstellt werden soll",
"cmd-create-endAt-description": "Relative Dauer des Quiz",
"cmd-create-option-description": "Option Nummer %o",
"cmd-create-canchange-description": "Ob die Teilnehmer ihre Auswahl nachträglich ändern können (Standard: Nein)",
"daily-quiz-limit": "Du hast das Limit von **%l** täglichen Quiz erreicht. Du kannst %timestamp wieder Quiz spielen.",
"created": "Quiz erfolgreich in %c erstellt.",
"correct-highlighted": "Alle richtigen Antworten wurden hervorgehoben.",
"answer-correct": "✅ Deine Antwort war richtig, du hast einen Punkt fürs Leaderboard erhalten!",
"answer-wrong": "❌ Deine Antwort war falsch!",
"bool-true": "Aussage stimmt",
"bool-false": "Aussage stimmt nicht",
"leaderboard-channel-not-found": "Der Leaderboard-Kanal wurde nicht gefunden oder sein Typ ist nicht erlaubt.",
"leaderboard-notation": "**%p. %u**: %xp XP",
"your-rank": "Du hast **%xp** Punkte in Quiz gesammelt!",
"no-rank": "Du hast noch nie ein Quiz erfolgreich beendet!",
"no-quiz": "Es wurden noch keine Quiz erstellt. Serveradmins können auf https://scnx.app/glink?page=bot/configuration?query=quiz&file=quiz%7Cconfigs%2FquizList Quiz hinzufügen.",
"no-permission": "Du hast keine Berechtigung, um Quiz mit dem Befehl zu erstellen."
}
}
259 changes: 259 additions & 0 deletions modules/quiz/commands/quiz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
const {MessageEmbed} = require('discord.js');
const durationParser = require('parse-duration');
const {localize} = require('../../../src/functions/localize');
const {createQuiz} = require('../quizUtil');

/**
* Handles quiz create commands
* @param {Discord.ApplicationCommandInteraction} interaction
*/
async function create(interaction) {
const config = interaction.client.configurations['quiz']['config'];
if (!interaction.member.roles.cache.has(config.createAllowedRole)) return interaction.reply({content: localize('quiz', 'no-permission'), ephemeral: true});

let endAt;
let options = [];
let emojis = config.emojis;
if (interaction.options.getSubcommand() === 'create-bool') {
options = [{text: localize('quiz', 'bool-true')}, {text: localize('quiz', 'bool-false')}];
emojis = [null, emojis.true, emojis.false];
} else {
for (let step = 1; step <= 10; step++) {
if (interaction.options.getString('option' + step)) options.push({text: interaction.options.getString('option' + step)});
}
}

const selectOptions = [];
for (const vId in options) {
selectOptions.push({
label: options[vId].text,
value: vId,
description: localize('quiz', 'this-correct'),
emoji: emojis[parseInt(vId) + 1]
});
}
const msg = await interaction.reply({
components: [{
type: 'ACTION_ROW',
components: [{
/* eslint-disable camelcase */
type: 'SELECT_MENU',
custom_id: 'quiz',
placeholder: localize('quiz', 'select-correct'),
min_values: 1,
max_values: interaction.options.getSubcommand() === 'create-bool' ? 1 : options.length,
options: selectOptions
}]
}],
ephemeral: true,
fetchReply: true
});
const collector = msg.createMessageComponentCollector({filter: i => interaction.user.id === i.user.id, componentType: 'SELECT_MENU', max: 1});
collector.on('collect', async i => {
i.values.forEach(option => {
options[option].correct = true;
});

if (interaction.options.getString('duration')) endAt = new Date(new Date().getTime() + durationParser(interaction.options.getString('duration')));
await createQuiz({
description: interaction.options.getString('description', true),
channel: interaction.options.getChannel('channel', true),
endAt,
options,
canChangeVote: interaction.options.getBoolean('canchange') || false,
type: interaction.options.getSubcommand() === 'create-bool' ? 'bool' : 'normal'
}, interaction.client);
i.update({
content: localize('quiz', 'created', {c: interaction.options.getChannel('channel').toString()}),
components: []
});
});
}

module.exports.subcommands = {
'create': create,
'create-bool': create,
'play': async function (interaction) {
let user = await interaction.client.models['quiz']['QuizUser'].findAll({where: {userId: interaction.user.id}});
if (user.length > 0) user = user[0];
else user = await interaction.client.models['quiz']['QuizUser'].create({userID: interaction.user.id, dailyQuiz: 0});

if (user.dailyQuiz >= interaction.client.configurations['quiz']['config'].dailyQuizLimit) {
const now = new Date();
now.setDate(now.getDate() + 1);
now.setHours(0);
now.setMinutes(0);
now.setSeconds(0);

return interaction.reply({
content: localize('quiz', 'daily-quiz-limit', {l: interaction.client.configurations['quiz']['config'].dailyQuizLimit, timestamp: '<t:' + Math.round(now.getTime() / 1000) + ':R>'}),
ephemeral: true
});
}
if (!interaction.client.configurations['quiz']['quizList'] || interaction.client.configurations['quiz']['quizList'].length === 0) return interaction.reply({content: localize('quiz', 'no-quiz'), ephemeral: true});

const updatedUser = {dailyQuiz: user.dailyQuiz + 1};
let quiz = {};
if (interaction.client.configurations['quiz']['config'].mode.toLowerCase() === 'continuous') {
quiz = interaction.client.configurations['quiz']['quizList'][user.nextQuizID] || interaction.client.configurations['quiz']['quizList'][0];
updatedUser.nextQuizID = interaction.client.configurations['quiz']['quizList'][user.nextQuizID + 1] ? user.nextQuizID + 1 : 0;
} else quiz = interaction.client.configurations['quiz']['quizList'][Math.floor(Math.random() * interaction.client.configurations['quiz']['quizList'].length)];

quiz.channel = interaction.channel;
quiz.options = [
...quiz.wrongOptions.map(o => ({text: o})),
...quiz.correctOptions.map(o => ({text: o, correct: true}))
];
quiz.endAt = new Date(new Date().getTime() + durationParser(quiz.duration));
quiz.canChangeVote = false;
quiz.private = true;
createQuiz(quiz, interaction.client, interaction);

interaction.client.models['quiz']['QuizUser'].update(updatedUser, {where: {userID: interaction.user.id}});
},
'leaderboard': async function (interaction) {
const moduleStrings = interaction.client.configurations['quiz']['strings'];
const users = await interaction.client.models['quiz']['QuizUser'].findAll({
order: [
['xp', 'DESC']
],
limit: 15
});

let leaderboardString = '';
let i = 0;
for (const user of users) {
const member = interaction.guild.members.cache.get(user.userID);
if (!member) continue;
i++;
leaderboardString = leaderboardString + localize('quiz', 'leaderboard-notation', {
p: i,
u: member.user.toString(),
xp: user.xp
}) + '\n';
}
if (leaderboardString.length === 0) leaderboardString = localize('levels', 'no-user-on-leaderboard');

const embed = new MessageEmbed()
.setTitle(moduleStrings.embed.leaderboardTitle)
.setColor(moduleStrings.embed.leaderboardColor)
.setFooter({text: interaction.client.strings.footer, iconURL: interaction.client.strings.footerImgUrl})
.setThumbnail(interaction.guild.iconURL())
.addField(moduleStrings.embed.leaderboardSubtitle, leaderboardString);

if (!interaction.client.strings.disableFooterTimestamp) embed.setTimestamp();

const components = [{
type: 'ACTION_ROW',
components: [{
type: 'BUTTON',
label: moduleStrings.embed.leaderboardButton,
style: 'SUCCESS',
customId: 'show-quiz-rank'
}]
}];

interaction.reply({embeds: [embed], components});
}
};

module.exports.config = {
name: 'quiz',
description: localize('quiz', 'cmd-description'),
defaultPermission: false,
options: function () {
const options = [
{
type: 'SUB_COMMAND',
name: 'create',
description: localize('quiz', 'cmd-create-normal-description'),
options: [{
type: 'STRING',
name: 'description',
required: true,
description: localize('quiz', 'cmd-create-description-description')
},
{
type: 'CHANNEL',
name: 'channel',
required: true,
channelTypes: ['GUILD_TEXT', 'GUILD_NEWS', 'GUILD_VOICE'],
description: localize('quiz', 'cmd-create-channel-description')
},
{
type: 'STRING',
name: 'duration',
required: true,
description: localize('quiz', 'cmd-create-endAt-description')
},
{
type: 'STRING',
name: 'option1',
required: true,
description: localize('quiz', 'cmd-create-option-description', {o: 1})
},
{
type: 'STRING',
name: 'option2',
required: true,
description: localize('quiz', 'cmd-create-option-description', {o: 2})
},
{
type: 'BOOLEAN',
name: 'canchange',
required: false,
description: localize('quiz', 'cmd-create-canchange-description')
}]
},
{
type: 'SUB_COMMAND',
name: 'create-bool',
description: localize('quiz', 'cmd-create-bool-description'),
options: [{
type: 'STRING',
name: 'description',
required: true,
description: localize('quiz', 'cmd-create-description-description')
},
{
type: 'CHANNEL',
name: 'channel',
required: true,
channelTypes: ['GUILD_TEXT', 'GUILD_NEWS', 'GUILD_VOICE'],
description: localize('quiz', 'cmd-create-channel-description')
},
{
type: 'BOOLEAN',
name: 'canchange',
required: false,
description: localize('quiz', 'cmd-create-canchange-description')
},
{
type: 'STRING',
name: 'duration',
required: false,
description: localize('quiz', 'cmd-create-endAt-description')
}]
},
{
type: 'SUB_COMMAND',
name: 'play',
description: localize('quiz', 'cmd-play-description')
},
{
type: 'SUB_COMMAND',
name: 'leaderboard',
description: localize('quiz', 'cmd-leaderboard-description')
}
];
for (let step = 1; step <= 7; step++) {
options[0].options.push({
type: 'STRING',
name: `option${2 + step}`,
required: false,
description: localize('quiz', 'cmd-create-option-description', {o: 2 + step})
});
}
return options;
}
};
Loading