From 16bb46403b99757e3c643112db35f0b7896df6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Gro=C3=9F?= Date: Mon, 26 Sep 2022 16:09:23 +0200 Subject: [PATCH] Burn: Added card burning for notes and gems --- commands/burn.js | 62 +++++++++++++++++ commands/collection.js | 6 +- commands/profile.js | 2 +- commands/stats.js | 12 +++- commands/view.js | 5 +- config/constants.js | 30 +++++++- events/autocompleteRequest.js | 69 ++++++++++++------- .../20220926133658-add-burned-to-cards.js | 26 +++++++ models/card.js | 1 + 9 files changed, 183 insertions(+), 30 deletions(-) create mode 100644 commands/burn.js create mode 100644 migrations/20220926133658-add-burned-to-cards.js diff --git a/commands/burn.js b/commands/burn.js new file mode 100644 index 0000000..8158c57 --- /dev/null +++ b/commands/burn.js @@ -0,0 +1,62 @@ +const { SlashCommandBuilder, AttachmentBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = require("discord.js"); +const { Card, User, Band, Character } = require("../models"); +const { QUALITY_VALUES, QUALITY_NAMES, CURRENCY_SYMBOLS } = require("../config/constants"); +const { UserUtils } = require("../util"); +const fs = require("fs"); +const edit = require("./edit"); + +//fetch all cards owned by the user and list them +module.exports = { + data: new SlashCommandBuilder() + .setName("burn") + .setDescription("Burn a specific card") + .addStringOption((option) => + option + .setName("id") + .setDescription("Card identifier") + .setRequired(true) + .setAutocomplete(true) + ), + async execute(interaction) { + await interaction.deferReply(); + + let card = await Card.findOne({ + where: { + identifier: interaction.options.getString("id") + }, + include: [ + { model: Character, include: [{ model: Band }] }, + { model: User} + ] + }); + if (card === null) { + interaction.editReply({ content: "Card not found" }); + return; + } + if (card.User.discordId !== interaction.user.id) { + interaction.editReply({ content: "You do not own this card" }); + return; + } + if (card.burned) { + interaction.editReply({ content: "This card is already burned" }); + return; + } + + const embed = new EmbedBuilder() + .setTitle(`${interaction.member.displayName} burned ${card.identifier}`) + .setDescription(`+${QUALITY_VALUES[card.quality].value} ${CURRENCY_SYMBOLS[QUALITY_VALUES[card.quality].type]}`) + .addFields( + { name: `${card.Character.name}`, value: `${card.Character.Band.name}` }, + { name: 'Print Number', value: `${card.printNr}`, inline: true }, + { name: 'Quality', value: `${QUALITY_NAMES[card.quality]}`, inline: true } + ) + .setColor(0xFF0000) + .setFooter({ text: `${card.identifier}`, iconURL: 'https://cdn.discordapp.com/attachments/856904078754971658/1017431187234508820/fp.png' }) + .setTimestamp(card.createdAt); + + let user = await UserUtils.getUserByDiscordId(interaction.user.id); + await user.addCurrency(QUALITY_VALUES[card.quality].value, QUALITY_VALUES[card.quality].type, `burned ${card.identifier}`); + await card.update({ burned: true }); + const message = await interaction.editReply({ embeds: [embed], fetchReply: true }); + } +} \ No newline at end of file diff --git a/commands/collection.js b/commands/collection.js index 78388e6..d325051 100644 --- a/commands/collection.js +++ b/commands/collection.js @@ -89,7 +89,8 @@ module.exports = { if (group) { cards = await Card.findAndCountAll({ where: { - userId: user.id + userId: user.id, + burned: false }, group: ["characterId"], attributes: ["characterId", [Card.sequelize.fn("COUNT", "characterId"), "count"]], @@ -104,7 +105,8 @@ module.exports = { } else { cards = await Card.findAndCountAll({ where: { - userId: user.id + userId: user.id, + burned: false }, limit: pageSize, offset: offset, diff --git a/commands/profile.js b/commands/profile.js index 4d4a6cb..3451185 100644 --- a/commands/profile.js +++ b/commands/profile.js @@ -51,7 +51,7 @@ module.exports = { let slots = ['slotOne', 'slotTwo', 'slotThree', 'slotFour']; let renderedCards = []; for (slot of slots) { - let card = await Card.findOne({ where: { id: profile[slot] }}); + let card = await Card.findOne({ where: { id: profile[slot], burned: false } }); if (card) { let cardImage = await Rendering.renderCard(card); renderedCards.push(cardImage); diff --git a/commands/stats.js b/commands/stats.js index 1a7dbd7..16da704 100644 --- a/commands/stats.js +++ b/commands/stats.js @@ -1,6 +1,6 @@ const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); const { UserUtils } = require('../util'); -const { QUALITY, QUALITY_NAMES } = require('../config/constants'); +const { CURRENCY_SYMBOLS, QUALITY_NAMES } = require('../config/constants'); module.exports = { data: new SlashCommandBuilder() .setName("stats") @@ -22,7 +22,15 @@ module.exports = { let qualityCount = Array(6).fill(0); let qualities = Object.values(QUALITY_NAMES); + let totalCards = 0; + let burnedCards = 0; + for (card of userCards.rows) { + if (card.burned) { + burnedCards++; + continue; + } + totalCards++; qualityCount[card.quality-1]++; } @@ -33,7 +41,7 @@ module.exports = { let embed = new EmbedBuilder() .setTitle(`${discordUser.username}'s Stats`) .addFields( - { name: "Cards owned", value: `${qualities.join('\n')}\n${userCards.count} total`, inline: true }, + { name: "Cards owned", value: `${qualities.join('\n')}\n${totalCards} total - ${burnedCards} burned`, inline: true }, { name: "Level", value: `${level.currentLevel}`, inline: true }, { name: "Progress", value: `${level.currentExperience} / ${level.nextLevelExperience}\n${level.remaining} XP remaining`, inline: true }, { name: "Registered since", value: `${registrationDate}`, inline: true } diff --git a/commands/view.js b/commands/view.js index 93f7946..02bd339 100644 --- a/commands/view.js +++ b/commands/view.js @@ -92,7 +92,10 @@ module.exports = { .setColor(0x00ff00) .setFooter({ text: `${card.identifier}`, iconURL: 'https://cdn.discordapp.com/attachments/856904078754971658/1017431187234508820/fp.png' }) .setTimestamp(card.createdAt); - + if (card.burned) { + embed.setColor(0xff0000); + embed.addFields({ name: "Burned", value: "This card has been burned" }); + } const message = await interaction.editReply({ embeds: [embed], files: [cardImage], fetchReply: true }); }, diff --git a/config/constants.js b/config/constants.js index 8a263ef..b64cf54 100644 --- a/config/constants.js +++ b/config/constants.js @@ -26,7 +26,35 @@ const CURRENCY_NAMES = { 2 : "Gems" } +const QUALITY_VALUES = { + 1 : { + type: 1, + value: 2 + }, + 2 : { + type: 1, + value: 5 + }, + 3 : { + type: 1, + value: 10 + }, + 4 : { + type: 1, + value: 15 + }, + 5 : { + type: 1, + value: 20 + }, + 6 : { + type: 2, + value: 2 + } +} + exports.QUALITY = QUALITY; exports.QUALITY_NAMES = QUALITY_NAMES; exports.CURRENCY_SYMBOLS = CURRENCY_SYMBOLS; -exports.CURRENCY_NAMES = CURRENCY_NAMES; \ No newline at end of file +exports.CURRENCY_NAMES = CURRENCY_NAMES; +exports.QUALITY_VALUES = QUALITY_VALUES; \ No newline at end of file diff --git a/events/autocompleteRequest.js b/events/autocompleteRequest.js index b817665..2a33294 100644 --- a/events/autocompleteRequest.js +++ b/events/autocompleteRequest.js @@ -2,6 +2,8 @@ const { InteractionType } = require('discord.js'); const { UserUtils } = require('../util'); const { Card, Character, User } = require('../models'); const Sequelize = require('sequelize'); +const { QUALITY_NAMES } = require('../config/constants'); + module.exports = { name: "interactionCreate", async execute (interaction) { @@ -9,30 +11,21 @@ module.exports = { if (!isRegistered) return; if (interaction.type !== InteractionType.ApplicationCommandAutocomplete) return; console.log(`Autocomplete request from ${interaction.user.tag} (${interaction.user.id}) for ${interaction.commandName} with ${interaction.options.getFocused(true).value}`); + + let user = await UserUtils.getUserByDiscordId(interaction.member.id); + let focusedOption = interaction.options.getFocused(true); + let choices = []; + + if (interaction.commandName === "burn") { + choices = await this.fetchCards(focusedOption, { user: user, ownedOnly: true }); + } + if (interaction.commandName === 'view') { const viewType = interaction.options.getString('type'); - let focusedOption = interaction.options.getFocused(true); - - let choices = []; - + switch (viewType) { case 'card': - const cards = await Card.findAll({ - where: { - identifier: { - [Sequelize.Op.like]: `%${focusedOption.value}%` - } - }, - include: [{ model: Character }, { model: User }], - limit: 10 - }); - for (let i = 0; i < cards.length; i++) { - choices.push({ - name: `${cards[i].identifier} - ${cards[i].Character.name}`, - value: cards[i].identifier - }); - } - break; + choices = await this.fetchCards(focusedOption, { user: user}); case 'character': if(focusedOption.value.length < 3) break; const characters = await Character.findAll({ @@ -53,9 +46,39 @@ module.exports = { case 'band': break; } - - await interaction.respond(choices); - return; } + if (choices.length > 0) { + console.log(choices); + await interaction.respond(choices); + } + return; + }, + async fetchCards (focusedOption, options={}) { + let choices = []; + let condition = { + where: { + identifier: { + [Sequelize.Op.like]: `%${focusedOption.value}%` + }, + burned: false + }, + include: [{ model: Character }, { model: User }], + limit: 10 + } + if (options.ownedOnly) { + condition.where.userId = { [Sequelize.Op.eq]: options.user.id }; + } + const cards = await Card.findAll(condition); + for (let i = 0; i < cards.length; i++) { + let owned = ""; + if (options.user) { + owned = cards[i].userId === options.user.id ? " (owned)" : ""; + } + choices.push({ + name: `${cards[i].identifier} - ${cards[i].Character.name} (${QUALITY_NAMES[cards[i].quality]})${owned}`, + value: cards[i].identifier + }); + } + return choices; } } \ No newline at end of file diff --git a/migrations/20220926133658-add-burned-to-cards.js b/migrations/20220926133658-add-burned-to-cards.js new file mode 100644 index 0000000..6cdbb49 --- /dev/null +++ b/migrations/20220926133658-add-burned-to-cards.js @@ -0,0 +1,26 @@ +'use strict'; + +module.exports = { + async up (queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + await queryInterface.addColumn('Cards', 'burned', { + type: Sequelize.BOOLEAN, + defaultValue: false + }); + }, + + async down (queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + await queryInterface.removeColumn('Cards', 'burned'); + } +}; diff --git a/models/card.js b/models/card.js index c3029a2..5c6f6d0 100644 --- a/models/card.js +++ b/models/card.js @@ -21,6 +21,7 @@ module.exports = (sequelize, DataTypes) => { userId: DataTypes.INTEGER, imageHash: DataTypes.STRING, enabled: { type: DataTypes.BOOLEAN, defaultValue: true }, + burned: { type: DataTypes.BOOLEAN, defaultValue: false }, printNr: DataTypes.INTEGER, }, { sequelize,