diff --git a/commands/economy/balance.js b/commands/economy/balance.js index d6dffaa..45ceb61 100644 --- a/commands/economy/balance.js +++ b/commands/economy/balance.js @@ -4,32 +4,28 @@ const UserEconomy = require("../../models/UserEconomy"); module.exports = { data: new SlashCommandBuilder() .setName("balance") - .setDescription("Check your balance and claim a bonus for checking daily!"), + .setDescription("Check your balance."), async execute(interaction) { const { user, guild } = interaction; + let userEconomy = await UserEconomy.findOne({ userId: user.id, guildId: guild.id, }); - const checkInBonus = 10; if (!userEconomy) { userEconomy = await UserEconomy.create({ userId: user.id, guildId: guild.id, + balance: 0, }); - } else { - userEconomy.balance += checkInBonus; - await userEconomy.save(); } const embed = new EmbedBuilder() .setColor("#0099ff") .setTitle(`${user.username}'s Balance`) - .setDescription( - `Your balance: **${userEconomy.balance}** coins. (Check-in Bonus: +${checkInBonus} coins)` - ) + .setDescription(`Your balance: **${userEconomy.balance}** coins.`) .setFooter({ text: `Requested by ${user.username}`, iconURL: user.displayAvatarURL(), diff --git a/commands/economy/daily.js b/commands/economy/daily.js index 896f175..1bf3ffa 100644 --- a/commands/economy/daily.js +++ b/commands/economy/daily.js @@ -22,7 +22,8 @@ module.exports = { userEconomy = await UserEconomy.create({ userId: user.id, guildId: guild.id, - streak: 0, // Initialize streak + streak: 0, + balance: 0, }); } @@ -56,17 +57,14 @@ module.exports = { } userEconomy.streak += 1; - - let reward = dailyBaseReward + userEconomy.streak * streakBonus; + const reward = dailyBaseReward + userEconomy.streak * streakBonus; userEconomy.lastDaily = now; userEconomy.balance += reward; const rareItemEarned = Math.random() < rareItemChance; - let rareItemMessage = ""; - - if (rareItemEarned) { - rareItemMessage = "\nYou also found a **rare item** in your reward!"; - } + const rareItemMessage = rareItemEarned + ? "\nYou also found a **rare item** in your reward!" + : ""; await userEconomy.save(); diff --git a/commands/economy/inventory.js b/commands/economy/inventory.js index e070695..a9ec5ff 100644 --- a/commands/economy/inventory.js +++ b/commands/economy/inventory.js @@ -32,8 +32,17 @@ module.exports = { const itemDetails = await Promise.all( inventory.map(async (item) => { const shopItem = await ShopItem.findOne({ itemId: item.itemId }); + + if (!shopItem) { + return null; + } + if (item.quantity > 0) { - return `${shopItem.name} (x${item.quantity}) - **Rarity**: ${shopItem.rarity}`; + return `${shopItem.name} (x${item.quantity}) - **Rarity**: ${ + shopItem.rarity + } - **Type**: ${shopItem.type} - **Category**: ${ + shopItem.category || "N/A" + }`; } return null; }) @@ -44,7 +53,9 @@ module.exports = { const inventoryEmbed = new EmbedBuilder() .setColor("#00ff00") .setTitle(`${user.username}'s Inventory`) - .setDescription(filteredItemDetails.join("\n")) + .setDescription( + filteredItemDetails.join("\n") || "No items in inventory." + ) .setTimestamp() .setFooter({ text: `Requested by ${user.username}`, diff --git a/commands/economy/sell.js b/commands/economy/sell.js new file mode 100644 index 0000000..27276c6 --- /dev/null +++ b/commands/economy/sell.js @@ -0,0 +1,208 @@ +const { + SlashCommandBuilder, + EmbedBuilder, + ActionRowBuilder, + StringSelectMenuBuilder, +} = require("discord.js"); +const UserInventory = require("../../models/UserInventory"); +const ShopItem = require("../../models/ShopItem"); +const UserEconomy = require("../../models/UserEconomy"); + +module.exports = { + data: new SlashCommandBuilder() + .setName("sell") + .setDescription("Sell an item from your inventory."), + + async execute(interaction) { + const { user, guild } = interaction; + + const userInventory = await UserInventory.find({ + userId: user.id, + guildId: guild.id, + }); + + if (userInventory.length === 0) { + const errorEmbed = new EmbedBuilder() + .setColor("#ff0000") + .setTitle("🛑 Inventory Empty") + .setDescription("You have no items in your inventory to sell.") + .setTimestamp() + .setFooter({ + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), + }); + + await interaction.reply({ embeds: [errorEmbed], ephemeral: false }); + return; + } + + const selectMenu = new StringSelectMenuBuilder() + .setCustomId("sell_item") + .setPlaceholder("Select an item to sell") + .addOptions( + userInventory.map((item) => ({ + label: item.itemId, + value: item.itemId, + })) + ); + + const row = new ActionRowBuilder().addComponents(selectMenu); + + const promptEmbed = new EmbedBuilder() + .setColor("#00ffff") + .setTitle("📦 Select Item to Sell") + .setDescription( + "Choose an item from your inventory to sell. The selling price is 50% less than the original item price." + ) + .setTimestamp() + .setFooter({ + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), + }); + + await interaction.reply({ embeds: [promptEmbed], components: [row] }); + + const filter = (i) => { + return i.user.id === user.id; + }; + + const collector = interaction.channel.createMessageComponentCollector({ + filter, + time: 15000, + }); + + collector.on("collect", async (i) => { + if (i.customId === "sell_item") { + const selectedItemId = i.values[0]; + const selectedItem = userInventory.find( + (item) => item.itemId === selectedItemId + ); + + const shopItem = await ShopItem.findOne({ + itemId: selectedItemId, + guildId: guild.id, + }); + + if (!shopItem) { + await i.reply({ + content: "Item not found in the shop.", + ephemeral: false, + }); + return; + } + + const sellingPrice = Math.floor(shopItem.price / 2); + + const quantityPrompt = new EmbedBuilder() + .setColor("#ffff00") + .setTitle(`💰 Selling ${shopItem.name}`) + .setDescription( + `How many of **${shopItem.name}** would you like to sell?` + ) + .addFields({ + name: "Sell Price", + value: `Each item sells for **${sellingPrice}** coins.`, + inline: true, + }) + .setTimestamp() + .setFooter({ + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), + }); + + await i.reply({ embeds: [quantityPrompt], ephemeral: false }); + + const quantityFilter = (response) => { + return ( + response.author.id === user.id && + !isNaN(response.content) && + response.content > 0 + ); + }; + + const quantityCollector = interaction.channel.createMessageCollector({ + filter: quantityFilter, + time: 15000, + }); + + quantityCollector.on("collect", async (response) => { + const quantityToSell = parseInt(response.content); + + if (quantityToSell > selectedItem.quantity) { + await response.reply({ + content: `You do not have enough **${shopItem.name}** to sell!`, + ephemeral: false, + }); + return; + } + + let userEconomy = await UserEconomy.findOne({ + userId: user.id, + guildId: guild.id, + }); + + if (!userEconomy) { + userEconomy = await UserEconomy.create({ + userId: user.id, + guildId: guild.id, + balance: 0, + }); + } + + userEconomy.balance += sellingPrice * quantityToSell; + await userEconomy.save(); + + selectedItem.quantity -= quantityToSell; + if (selectedItem.quantity === 0) { + await UserInventory.deleteOne({ + userId: user.id, + itemId: selectedItemId, + }); + } else { + await selectedItem.save(); + } + + const successEmbed = new EmbedBuilder() + .setColor("#00ff00") + .setTitle("🎉 Item Sold!") + .setDescription( + `You sold **${quantityToSell}** of **${shopItem.name}** for **${ + sellingPrice * quantityToSell + }** coins!` + ) + .addFields({ + name: "New Balance", + value: `${userEconomy.balance} coins`, + inline: true, + }) + .setFooter({ + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), + }) + .setTimestamp(); + + await response.reply({ embeds: [successEmbed], ephemeral: false }); + quantityCollector.stop(); + }); + + quantityCollector.on("end", async (collected) => { + if (collected.size === 0) { + await i.followUp({ + content: "You did not respond in time to sell the item.", + ephemeral: false, + }); + } + }); + } + }); + + collector.on("end", async (collected) => { + if (collected.size === 0) { + await interaction.followUp({ + content: "You did not select an item in time.", + ephemeral: false, + }); + } + }); + }, +}; diff --git a/commands/economy/shop.js b/commands/economy/shop.js index c1ce528..ac8a94c 100644 --- a/commands/economy/shop.js +++ b/commands/economy/shop.js @@ -1,20 +1,30 @@ const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"); const ShopItem = require("../../models/ShopItem"); +const UserEconomy = require("../../models/UserEconomy"); +const UserInventory = require("../../models/UserInventory"); module.exports = { data: new SlashCommandBuilder() .setName("shop") - .setDescription("Browse the shop for items with rarity and discounts!"), + .setDescription("Browse the shop for items with rarity and discounts!") + .addStringOption((option) => + option + .setName("item") + .setDescription("The item you want to buy (use item name)") + .setRequired(false) + ), async execute(interaction) { const { user, guild } = interaction; const discountChance = 0.3; + const itemName = interaction.options.getString("item"); + const items = await ShopItem.find({ guildId: guild.id }); if (items.length === 0) { const emptyEmbed = new EmbedBuilder() .setColor("#ff0000") - .setTitle("Shop") + .setTitle("🛒 Shop Items") .setDescription("No items in the shop currently.") .setTimestamp() .setFooter({ @@ -26,6 +36,94 @@ module.exports = { return; } + if (itemName) { + const item = items.find( + (item) => item.name.toLowerCase() === itemName.toLowerCase() + ); + if (!item) { + await interaction.reply({ + content: "Item not found in the shop!", + ephemeral: false, + }); + return; + } + + let userEconomy = await UserEconomy.findOne({ + userId: user.id, + guildId: guild.id, + }); + if (!userEconomy) { + userEconomy = await UserEconomy.create({ + userId: user.id, + guildId: guild.id, + }); + } + + const discount = Math.random() < discountChance ? 0.8 : 1; + const price = Math.floor(item.price * discount); + + if (userEconomy.balance < price) { + const insufficientFundsEmbed = new EmbedBuilder() + .setColor("#ff0000") + .setTitle("💸 Insufficient Funds") + .setDescription( + `You don't have enough coins to buy **${item.name}**!` + ) + .addFields( + { + name: "Your Balance", + value: `${userEconomy.balance} coins`, + inline: true, + }, + { name: "Item Price", value: `${price} coins`, inline: true } + ) + .setTimestamp() + .setFooter({ + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), + }); + + await interaction.reply({ + embeds: [insufficientFundsEmbed], + ephemeral: false, + }); + return; + } + + userEconomy.balance -= price; + await userEconomy.save(); + + const userInventory = await UserInventory.findOne({ + userId: user.id, + guildId: guild.id, + itemId: item.itemId, + }); + if (userInventory) { + userInventory.quantity += 1; + await userInventory.save(); + } else { + await UserInventory.create({ + userId: user.id, + guildId: guild.id, + itemId: item.itemId, + quantity: 1, + }); + } + + const successEmbed = new EmbedBuilder() + .setColor("#00ff00") + .setTitle("🎉 Purchase Successful") + .setDescription(`You bought **${item.name}** for **${price}** coins!`) + .setTimestamp() + .setFooter({ + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), + }); + + await interaction.reply({ embeds: [successEmbed], ephemeral: false }); + return; + } + const shopItemsDetails = items.map((item) => { const discount = Math.random() < discountChance ? 0.8 : 1; const price = Math.floor(item.price * discount); @@ -38,7 +136,7 @@ module.exports = { const shopEmbed = new EmbedBuilder() .setColor("#00ff00") - .setTitle("Shop") + .setTitle("🛒 Shop Items") .setDescription(shopItemsDetails.join("\n")) .setTimestamp() .setFooter({