mirror of
				https://github.com/aydenjahola/discord-multipurpose-bot.git
				synced 2025-11-04 00:01:41 +00:00 
			
		
		
		
	add economy system
This commit is contained in:
		
							parent
							
								
									9453225b23
								
							
						
					
					
						commit
						fc46176044
					
				
					 12 changed files with 655 additions and 0 deletions
				
			
		
							
								
								
									
										35
									
								
								commands/economy/balance.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								commands/economy/balance.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
 | 
				
			||||||
 | 
					const UserEconomy = require("../../models/UserEconomy");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  data: new SlashCommandBuilder()
 | 
				
			||||||
 | 
					    .setName("balance")
 | 
				
			||||||
 | 
					    .setDescription("Check your balance"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async execute(interaction) {
 | 
				
			||||||
 | 
					    const { user, guild } = interaction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let userEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!userEconomy) {
 | 
				
			||||||
 | 
					      userEconomy = await UserEconomy.create({
 | 
				
			||||||
 | 
					        userId: user.id,
 | 
				
			||||||
 | 
					        guildId: guild.id,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const embed = new EmbedBuilder()
 | 
				
			||||||
 | 
					      .setColor("#0099ff")
 | 
				
			||||||
 | 
					      .setTitle(`${user.username}'s Balance`)
 | 
				
			||||||
 | 
					      .setDescription(`You have **${userEconomy.balance}** coins.`)
 | 
				
			||||||
 | 
					      .setTimestamp()
 | 
				
			||||||
 | 
					      .setFooter({
 | 
				
			||||||
 | 
					        text: `Requested by ${user.username}`,
 | 
				
			||||||
 | 
					        iconURL: user.displayAvatarURL(),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    await interaction.reply({ embeds: [embed] });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										72
									
								
								commands/economy/daily.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								commands/economy/daily.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,72 @@
 | 
				
			||||||
 | 
					const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
 | 
				
			||||||
 | 
					const UserEconomy = require("../../models/UserEconomy");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  data: new SlashCommandBuilder()
 | 
				
			||||||
 | 
					    .setName("daily")
 | 
				
			||||||
 | 
					    .setDescription("Claim your daily reward"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async execute(interaction) {
 | 
				
			||||||
 | 
					    const { user, guild } = interaction;
 | 
				
			||||||
 | 
					    const dailyReward = 100;
 | 
				
			||||||
 | 
					    const oneDay = 24 * 60 * 60 * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let userEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!userEconomy) {
 | 
				
			||||||
 | 
					      userEconomy = await UserEconomy.create({
 | 
				
			||||||
 | 
					        userId: user.id,
 | 
				
			||||||
 | 
					        guildId: guild.id,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const now = new Date();
 | 
				
			||||||
 | 
					    if (userEconomy.lastDaily && now - userEconomy.lastDaily < oneDay) {
 | 
				
			||||||
 | 
					      const remainingTime =
 | 
				
			||||||
 | 
					        new Date(userEconomy.lastDaily.getTime() + oneDay) - now;
 | 
				
			||||||
 | 
					      const hours = Math.floor((remainingTime / (1000 * 60 * 60)) % 24);
 | 
				
			||||||
 | 
					      const minutes = Math.floor((remainingTime / (1000 * 60)) % 60);
 | 
				
			||||||
 | 
					      const seconds = Math.floor((remainingTime / 1000) % 60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const errorEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#ff0000")
 | 
				
			||||||
 | 
					        .setTitle("Daily Reward Claim")
 | 
				
			||||||
 | 
					        .setDescription(
 | 
				
			||||||
 | 
					          `You have already claimed your daily reward today. Come back in **${hours}h ${minutes}m ${seconds}s**!`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [errorEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    userEconomy.balance += dailyReward;
 | 
				
			||||||
 | 
					    userEconomy.lastDaily = now;
 | 
				
			||||||
 | 
					    await userEconomy.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const successEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					      .setColor("#00ff00")
 | 
				
			||||||
 | 
					      .setTitle("Daily Reward Claimed!")
 | 
				
			||||||
 | 
					      .setDescription(
 | 
				
			||||||
 | 
					        `You claimed your daily reward of **${dailyReward}** coins!`
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      .addFields({
 | 
				
			||||||
 | 
					        name: "Total Balance",
 | 
				
			||||||
 | 
					        value: `You now have **${userEconomy.balance}** coins.`,
 | 
				
			||||||
 | 
					        inline: true,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .setTimestamp()
 | 
				
			||||||
 | 
					      .setFooter({
 | 
				
			||||||
 | 
					        text: `Requested by ${user.username}`,
 | 
				
			||||||
 | 
					        iconURL: user.displayAvatarURL(),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await interaction.reply({ embeds: [successEmbed] });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										70
									
								
								commands/economy/inventory.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								commands/economy/inventory.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
 | 
				
			||||||
 | 
					const UserInventory = require("../../models/UserInventory");
 | 
				
			||||||
 | 
					const ShopItem = require("../../models/ShopItem");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  data: new SlashCommandBuilder()
 | 
				
			||||||
 | 
					    .setName("inventory")
 | 
				
			||||||
 | 
					    .setDescription("View your inventory"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async execute(interaction) {
 | 
				
			||||||
 | 
					    const { user, guild } = interaction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const inventory = await UserInventory.find({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (inventory.length === 0) {
 | 
				
			||||||
 | 
					      const emptyEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#ff0000")
 | 
				
			||||||
 | 
					        .setTitle("Inventory")
 | 
				
			||||||
 | 
					        .setDescription("Your inventory is empty.")
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [emptyEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const itemDetails = await Promise.all(
 | 
				
			||||||
 | 
					      inventory.map(async (item) => {
 | 
				
			||||||
 | 
					        const shopItem = await ShopItem.findOne({ itemId: item.itemId });
 | 
				
			||||||
 | 
					        if (item.quantity > 0) {
 | 
				
			||||||
 | 
					          return `${shopItem.name} (x${item.quantity})`;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const filteredItemDetails = itemDetails.filter((detail) => detail !== null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (filteredItemDetails.length === 0) {
 | 
				
			||||||
 | 
					      const noItemsEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#ff0000")
 | 
				
			||||||
 | 
					        .setTitle("Inventory")
 | 
				
			||||||
 | 
					        .setDescription("Your inventory is empty.")
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [noItemsEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const inventoryEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					      .setColor("#00ff00")
 | 
				
			||||||
 | 
					      .setTitle(`${user.username}'s Inventory`)
 | 
				
			||||||
 | 
					      .setDescription(filteredItemDetails.join("\n"))
 | 
				
			||||||
 | 
					      .setTimestamp()
 | 
				
			||||||
 | 
					      .setFooter({
 | 
				
			||||||
 | 
					        text: `Requested by ${user.username}`,
 | 
				
			||||||
 | 
					        iconURL: user.displayAvatarURL(),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await interaction.reply({ embeds: [inventoryEmbed] });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										108
									
								
								commands/economy/shop.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								commands/economy/shop.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,108 @@
 | 
				
			||||||
 | 
					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("View the shop and buy items")
 | 
				
			||||||
 | 
					    .addStringOption((option) =>
 | 
				
			||||||
 | 
					      option.setName("item").setDescription("The ID of the item to buy")
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async execute(interaction) {
 | 
				
			||||||
 | 
					    const { user, guild } = interaction;
 | 
				
			||||||
 | 
					    const itemId = interaction.options.getString("item");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!itemId) {
 | 
				
			||||||
 | 
					      const items = await ShopItem.find();
 | 
				
			||||||
 | 
					      const itemDescriptions = items.map(
 | 
				
			||||||
 | 
					        (item) => `**${item.itemId}**: ${item.name} - **${item.price}** coins`
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const shopEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#00bfff")
 | 
				
			||||||
 | 
					        .setTitle("🛒 Shop Items")
 | 
				
			||||||
 | 
					        .setDescription(
 | 
				
			||||||
 | 
					          itemDescriptions.length > 0
 | 
				
			||||||
 | 
					            ? itemDescriptions.join("\n")
 | 
				
			||||||
 | 
					            : "No items available at the moment."
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [shopEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const shopItem = await ShopItem.findOne({ itemId });
 | 
				
			||||||
 | 
					    if (!shopItem) {
 | 
				
			||||||
 | 
					      const notFoundEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#ff0000")
 | 
				
			||||||
 | 
					        .setTitle("❌ Item Not Found")
 | 
				
			||||||
 | 
					        .setDescription("The specified item could not be found in the shop.")
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [notFoundEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (!userEconomy || userEconomy.balance < shopItem.price) {
 | 
				
			||||||
 | 
					      const insufficientFundsEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#ff0000")
 | 
				
			||||||
 | 
					        .setTitle("💸 Insufficient Funds")
 | 
				
			||||||
 | 
					        .setDescription("You don't have enough coins to purchase this item.")
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [insufficientFundsEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    userEconomy.balance -= shopItem.price;
 | 
				
			||||||
 | 
					    await userEconomy.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let userInventory = await UserInventory.findOne({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					      itemId,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (userInventory) {
 | 
				
			||||||
 | 
					      userInventory.quantity += 1;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      userInventory = new UserInventory({
 | 
				
			||||||
 | 
					        userId: user.id,
 | 
				
			||||||
 | 
					        guildId: guild.id,
 | 
				
			||||||
 | 
					        itemId,
 | 
				
			||||||
 | 
					        quantity: 1,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await userInventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const successEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					      .setColor("#00ff00")
 | 
				
			||||||
 | 
					      .setTitle("🎉 Purchase Successful")
 | 
				
			||||||
 | 
					      .setDescription(
 | 
				
			||||||
 | 
					        `You've successfully purchased **${shopItem.name}** for **${shopItem.price}** coins!`
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      .setTimestamp()
 | 
				
			||||||
 | 
					      .setFooter({
 | 
				
			||||||
 | 
					        text: `Requested by ${user.username}`,
 | 
				
			||||||
 | 
					        iconURL: user.displayAvatarURL(),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await interaction.reply({ embeds: [successEmbed] });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										166
									
								
								commands/economy/trade.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								commands/economy/trade.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,166 @@
 | 
				
			||||||
 | 
					const { SlashCommandBuilder } = require("discord.js");
 | 
				
			||||||
 | 
					const UserInventory = require("../../models/UserInventory");
 | 
				
			||||||
 | 
					const UserEconomy = require("../../models/UserEconomy");
 | 
				
			||||||
 | 
					const Trade = require("../../models/Trade");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  data: new SlashCommandBuilder()
 | 
				
			||||||
 | 
					    .setName("trade")
 | 
				
			||||||
 | 
					    .setDescription("Trade an item and/or coins with another user")
 | 
				
			||||||
 | 
					    .addUserOption((option) =>
 | 
				
			||||||
 | 
					      option
 | 
				
			||||||
 | 
					        .setName("user")
 | 
				
			||||||
 | 
					        .setDescription("The user to trade with")
 | 
				
			||||||
 | 
					        .setRequired(true)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .addStringOption((option) =>
 | 
				
			||||||
 | 
					      option
 | 
				
			||||||
 | 
					        .setName("item")
 | 
				
			||||||
 | 
					        .setDescription("The ID of the item to trade")
 | 
				
			||||||
 | 
					        .setRequired(true)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .addIntegerOption((option) =>
 | 
				
			||||||
 | 
					      option
 | 
				
			||||||
 | 
					        .setName("quantity")
 | 
				
			||||||
 | 
					        .setDescription("Quantity of the item to trade")
 | 
				
			||||||
 | 
					        .setRequired(true)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .addIntegerOption((option) =>
 | 
				
			||||||
 | 
					      option
 | 
				
			||||||
 | 
					        .setName("coins")
 | 
				
			||||||
 | 
					        .setDescription("Amount of coins to trade")
 | 
				
			||||||
 | 
					        .setRequired(false)
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async execute(interaction) {
 | 
				
			||||||
 | 
					    const { user, guild } = interaction;
 | 
				
			||||||
 | 
					    const tradeUser = interaction.options.getUser("user");
 | 
				
			||||||
 | 
					    const itemId = interaction.options.getString("item");
 | 
				
			||||||
 | 
					    const quantity = interaction.options.getInteger("quantity");
 | 
				
			||||||
 | 
					    const coins = interaction.options.getInteger("coins") || 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (tradeUser.id === user.id) {
 | 
				
			||||||
 | 
					      await interaction.reply("You can't trade items with yourself.");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userInventory = await UserInventory.findOne({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					      itemId,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (!userInventory || userInventory.quantity < quantity) {
 | 
				
			||||||
 | 
					      await interaction.reply("You don't have enough of this item to trade.");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const tradeUserEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: tradeUser.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (!tradeUserEconomy || tradeUserEconomy.balance < coins) {
 | 
				
			||||||
 | 
					      await interaction.reply(
 | 
				
			||||||
 | 
					        `${tradeUser.username} does not have enough coins to trade.`
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const tradeProposal = new Trade({
 | 
				
			||||||
 | 
					      from: user.id,
 | 
				
			||||||
 | 
					      to: tradeUser.id,
 | 
				
			||||||
 | 
					      itemId,
 | 
				
			||||||
 | 
					      quantity,
 | 
				
			||||||
 | 
					      coins,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    await tradeProposal.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await interaction.reply({
 | 
				
			||||||
 | 
					      content: `Trade proposed: You are trading **${quantity}** of **${itemId}** and **${coins}** coins with ${tradeUser.username}.`,
 | 
				
			||||||
 | 
					      ephemeral: true,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await tradeUser.send(
 | 
				
			||||||
 | 
					      `Trade proposal: You are being offered **${quantity}** of **${itemId}** and **${coins}** coins by ${user.username}. Type \`/accept ${tradeProposal._id}\` to accept or \`/reject ${tradeProposal._id}\` to reject the trade.`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async accept(interaction) {
 | 
				
			||||||
 | 
					    const tradeId = interaction.options.getString("tradeId");
 | 
				
			||||||
 | 
					    const tradeProposal = await Trade.findById(tradeId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!tradeProposal) {
 | 
				
			||||||
 | 
					      await interaction.reply("Trade not found or already completed.");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { from, to, itemId, quantity, coins } = tradeProposal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const fromInventory = await UserInventory.findOne({
 | 
				
			||||||
 | 
					      userId: from,
 | 
				
			||||||
 | 
					      guildId: interaction.guild.id,
 | 
				
			||||||
 | 
					      itemId,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!fromInventory || fromInventory.quantity < quantity) {
 | 
				
			||||||
 | 
					      await interaction.reply(
 | 
				
			||||||
 | 
					        "Trade cannot be completed because the item no longer exists in the sender's inventory."
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let toInventory = await UserInventory.findOne({
 | 
				
			||||||
 | 
					      userId: to,
 | 
				
			||||||
 | 
					      guildId: interaction.guild.id,
 | 
				
			||||||
 | 
					      itemId,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (toInventory) {
 | 
				
			||||||
 | 
					      toInventory.quantity += quantity;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      toInventory = new UserInventory({
 | 
				
			||||||
 | 
					        userId: to,
 | 
				
			||||||
 | 
					        guildId: interaction.guild.id,
 | 
				
			||||||
 | 
					        itemId,
 | 
				
			||||||
 | 
					        quantity,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await toInventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const fromEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: from,
 | 
				
			||||||
 | 
					      guildId: interaction.guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const toEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: to,
 | 
				
			||||||
 | 
					      guildId: interaction.guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fromEconomy) {
 | 
				
			||||||
 | 
					      fromEconomy.balance -= coins;
 | 
				
			||||||
 | 
					      await fromEconomy.save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (toEconomy) {
 | 
				
			||||||
 | 
					      toEconomy.balance += coins;
 | 
				
			||||||
 | 
					      await toEconomy.save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await Trade.deleteOne({ _id: tradeId });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await interaction.reply(
 | 
				
			||||||
 | 
					      `Trade completed! You traded **${quantity}** of **${itemId}** and **${coins}** coins with ${interaction.user.username}.`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async reject(interaction) {
 | 
				
			||||||
 | 
					    const tradeId = interaction.options.getString("tradeId");
 | 
				
			||||||
 | 
					    const tradeProposal = await Trade.findById(tradeId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!tradeProposal) {
 | 
				
			||||||
 | 
					      await interaction.reply("Trade not found or already completed.");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await Trade.deleteOne({ _id: tradeId });
 | 
				
			||||||
 | 
					    await interaction.reply(`Trade rejected.`);
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										70
									
								
								commands/economy/work.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								commands/economy/work.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
 | 
				
			||||||
 | 
					const UserEconomy = require("../../models/UserEconomy");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  data: new SlashCommandBuilder()
 | 
				
			||||||
 | 
					    .setName("work")
 | 
				
			||||||
 | 
					    .setDescription("Work to earn coins!"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async execute(interaction) {
 | 
				
			||||||
 | 
					    const { user, guild } = interaction;
 | 
				
			||||||
 | 
					    const workReward = 100;
 | 
				
			||||||
 | 
					    const cooldownTime = 60 * 60 * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let userEconomy = await UserEconomy.findOne({
 | 
				
			||||||
 | 
					      userId: user.id,
 | 
				
			||||||
 | 
					      guildId: guild.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!userEconomy) {
 | 
				
			||||||
 | 
					      userEconomy = await UserEconomy.create({
 | 
				
			||||||
 | 
					        userId: user.id,
 | 
				
			||||||
 | 
					        guildId: guild.id,
 | 
				
			||||||
 | 
					        lastWork: null,
 | 
				
			||||||
 | 
					        balance: 0,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const now = new Date();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (userEconomy.lastWork && now - userEconomy.lastWork < cooldownTime) {
 | 
				
			||||||
 | 
					      const remainingTime = cooldownTime - (now - userEconomy.lastWork);
 | 
				
			||||||
 | 
					      const remainingMinutes = Math.ceil(remainingTime / (60 * 1000));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const cooldownEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					        .setColor("#ff0000")
 | 
				
			||||||
 | 
					        .setTitle("Cooldown")
 | 
				
			||||||
 | 
					        .setDescription(
 | 
				
			||||||
 | 
					          `You need to wait **${remainingMinutes}** minutes before you can work again.`
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .setFooter({
 | 
				
			||||||
 | 
					          text: `Requested in ${guild.name}`,
 | 
				
			||||||
 | 
					          iconURL: guild.iconURL() || null,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await interaction.reply({ embeds: [cooldownEmbed] });
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    userEconomy.balance += workReward;
 | 
				
			||||||
 | 
					    userEconomy.lastWork = now;
 | 
				
			||||||
 | 
					    await userEconomy.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const successEmbed = new EmbedBuilder()
 | 
				
			||||||
 | 
					      .setColor("#00ff00")
 | 
				
			||||||
 | 
					      .setTitle("Work Success")
 | 
				
			||||||
 | 
					      .setDescription(`You worked hard and earned **${workReward}** coins!`)
 | 
				
			||||||
 | 
					      .addFields({
 | 
				
			||||||
 | 
					        name: "Total Balance",
 | 
				
			||||||
 | 
					        value: `${userEconomy.balance} coins`,
 | 
				
			||||||
 | 
					        inline: true,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .setTimestamp()
 | 
				
			||||||
 | 
					      .setFooter({
 | 
				
			||||||
 | 
					        text: `Requested by ${user.username}`,
 | 
				
			||||||
 | 
					        iconURL: user.displayAvatarURL(),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await interaction.reply({ embeds: [successEmbed] });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										4
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								index.js
									
									
									
									
									
								
							| 
						 | 
					@ -10,6 +10,7 @@ const mongoose = require("mongoose");
 | 
				
			||||||
const fs = require("fs");
 | 
					const fs = require("fs");
 | 
				
			||||||
const path = require("path");
 | 
					const path = require("path");
 | 
				
			||||||
const ServerSettings = require("./models/ServerSettings");
 | 
					const ServerSettings = require("./models/ServerSettings");
 | 
				
			||||||
 | 
					const seedShopItems = require("./utils/seedShopItems");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const client = new Client({
 | 
					const client = new Client({
 | 
				
			||||||
  intents: [
 | 
					  intents: [
 | 
				
			||||||
| 
						 | 
					@ -61,6 +62,9 @@ client.once("ready", async () => {
 | 
				
			||||||
  console.log(`🤖 Logged in as ${client.user.tag}`);
 | 
					  console.log(`🤖 Logged in as ${client.user.tag}`);
 | 
				
			||||||
  console.log(`==============================`);
 | 
					  console.log(`==============================`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Seed the shop items
 | 
				
			||||||
 | 
					  await seedShopItems();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Register commands for all existing guilds
 | 
					  // Register commands for all existing guilds
 | 
				
			||||||
  const guilds = client.guilds.cache.map((guild) => guild.id);
 | 
					  const guilds = client.guilds.cache.map((guild) => guild.id);
 | 
				
			||||||
  for (const guildId of guilds) {
 | 
					  for (const guildId of guilds) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								models/ShopItem.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								models/ShopItem.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					const mongoose = require("mongoose");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const shopItemSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  itemId: { type: String, required: true, unique: true },
 | 
				
			||||||
 | 
					  name: { type: String, required: true },
 | 
				
			||||||
 | 
					  price: { type: Number, required: true },
 | 
				
			||||||
 | 
					  description: { type: String, required: true },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model("ShopItem", shopItemSchema);
 | 
				
			||||||
							
								
								
									
										12
									
								
								models/Trade.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								models/Trade.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					const mongoose = require("mongoose");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tradeSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  from: { type: String, required: true },
 | 
				
			||||||
 | 
					  to: { type: String, required: true },
 | 
				
			||||||
 | 
					  itemId: { type: String, required: true },
 | 
				
			||||||
 | 
					  quantity: { type: Number, required: true },
 | 
				
			||||||
 | 
					  coins: { type: Number, required: true },
 | 
				
			||||||
 | 
					  createdAt: { type: Date, default: Date.now, expires: "1d" },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model("Trade", tradeSchema);
 | 
				
			||||||
							
								
								
									
										11
									
								
								models/UserEconomy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								models/UserEconomy.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					const mongoose = require("mongoose");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const userEconomySchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  userId: { type: String, required: true, unique: true },
 | 
				
			||||||
 | 
					  guildId: { type: String, required: true },
 | 
				
			||||||
 | 
					  balance: { type: Number, default: 200 },
 | 
				
			||||||
 | 
					  lastDaily: { type: Date, default: null },
 | 
				
			||||||
 | 
					  lastWork: { type: Date, default: null },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model("UserEconomy", userEconomySchema);
 | 
				
			||||||
							
								
								
									
										10
									
								
								models/UserInventory.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								models/UserInventory.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					const mongoose = require("mongoose");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const userInventorySchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  userId: { type: String, required: true },
 | 
				
			||||||
 | 
					  guildId: { type: String, required: true },
 | 
				
			||||||
 | 
					  itemId: { type: String, required: true },
 | 
				
			||||||
 | 
					  quantity: { type: Number, default: 1 },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model("UserInventory", userInventorySchema);
 | 
				
			||||||
							
								
								
									
										87
									
								
								utils/seedShopItems.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								utils/seedShopItems.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					const ShopItem = require("../models/ShopItem");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function seedShopItems() {
 | 
				
			||||||
 | 
					  const items = [
 | 
				
			||||||
 | 
					    // Valorant Skins
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "prime_vandal",
 | 
				
			||||||
 | 
					      name: "Prime Vandal",
 | 
				
			||||||
 | 
					      price: 1200,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A futuristic skin for the Vandal with a sleek design and special effects.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "reaver_vandal",
 | 
				
			||||||
 | 
					      name: "Reaver Vandal",
 | 
				
			||||||
 | 
					      price: 1500,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "One of the most popular Vandal skins with a haunting aesthetic and special animations.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "sovereign_ghost",
 | 
				
			||||||
 | 
					      name: "Sovereign Ghost",
 | 
				
			||||||
 | 
					      price: 800,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "Golden elegance for the Ghost pistol with unique sound effects.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "araxys_operator",
 | 
				
			||||||
 | 
					      name: "Araxys Operator",
 | 
				
			||||||
 | 
					      price: 2000,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A top-tier sniper skin with alien-like animations and sound effects.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "glitchpop_bulldog",
 | 
				
			||||||
 | 
					      name: "Glitchpop Bulldog",
 | 
				
			||||||
 | 
					      price: 900,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A flashy skin for the Bulldog with vibrant colors and cyberpunk vibe.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // CS2 Skins
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "dragon_lore_awp",
 | 
				
			||||||
 | 
					      name: "AWP Dragon Lore",
 | 
				
			||||||
 | 
					      price: 2500,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A legendary skin for the AWP with dragon designs, a rare and coveted item.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "ak47_redline",
 | 
				
			||||||
 | 
					      name: "AK-47 Redline",
 | 
				
			||||||
 | 
					      price: 1000,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A simple yet iconic AK-47 skin with red and black color scheme.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "m4a4_howl",
 | 
				
			||||||
 | 
					      name: "M4A4 Howl",
 | 
				
			||||||
 | 
					      price: 2200,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A rare and valuable skin for the M4A4 with a striking wolf design.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "desert_eagle_kumicho_dragon",
 | 
				
			||||||
 | 
					      name: "Desert Eagle Kumicho Dragon",
 | 
				
			||||||
 | 
					      price: 800,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A Desert Eagle skin with an intricate dragon design and a metallic finish.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      itemId: "usp_kill_confirmed",
 | 
				
			||||||
 | 
					      name: "USP-S Kill Confirmed",
 | 
				
			||||||
 | 
					      price: 1100,
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "A detailed skin for the USP-S with a unique comic-style design.",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const item of items) {
 | 
				
			||||||
 | 
					    await ShopItem.updateOne({ itemId: item.itemId }, item, { upsert: true });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  console.log("✅ Shop items seeded!");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = seedShopItems;
 | 
				
			||||||
		Loading…
	
		Reference in a new issue