From 81cfdd4b21dd21ee952eeda19f261bbb2c820dc9 Mon Sep 17 00:00:00 2001 From: Ayden Jahola Date: Sat, 26 Oct 2024 19:33:45 +0100 Subject: [PATCH] economy: update the logic and add random work with different prices, add daily bonus + discount on shop and make shop per guild id --- commands/economy/balance.js | 16 ++++-- commands/economy/daily.js | 35 ++++++++---- commands/economy/inventory.js | 24 ++------ commands/economy/shop.js | 101 +++++++--------------------------- commands/economy/work.js | 27 +++++---- index.js | 12 +++- models/ShopItem.js | 8 ++- utils/seedShopItems.js | 24 ++++++-- 8 files changed, 110 insertions(+), 137 deletions(-) diff --git a/commands/economy/balance.js b/commands/economy/balance.js index e65e355..d6dffaa 100644 --- a/commands/economy/balance.js +++ b/commands/economy/balance.js @@ -4,32 +4,38 @@ const UserEconomy = require("../../models/UserEconomy"); module.exports = { data: new SlashCommandBuilder() .setName("balance") - .setDescription("Check your balance"), + .setDescription("Check your balance and claim a bonus for checking daily!"), 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, }); + } else { + userEconomy.balance += checkInBonus; + await userEconomy.save(); } const embed = new EmbedBuilder() .setColor("#0099ff") .setTitle(`${user.username}'s Balance`) - .setDescription(`You have **${userEconomy.balance}** coins.`) - .setTimestamp() + .setDescription( + `Your balance: **${userEconomy.balance}** coins. (Check-in Bonus: +${checkInBonus} coins)` + ) .setFooter({ text: `Requested by ${user.username}`, iconURL: user.displayAvatarURL(), - }); + }) + .setTimestamp(); + await interaction.reply({ embeds: [embed] }); }, }; diff --git a/commands/economy/daily.js b/commands/economy/daily.js index c6772ba..02eeb0c 100644 --- a/commands/economy/daily.js +++ b/commands/economy/daily.js @@ -4,11 +4,13 @@ const UserEconomy = require("../../models/UserEconomy"); module.exports = { data: new SlashCommandBuilder() .setName("daily") - .setDescription("Claim your daily reward"), + .setDescription("Claim your daily reward and start a streak!"), async execute(interaction) { const { user, guild } = interaction; - const dailyReward = 100; + const dailyBaseReward = 100; + const streakBonus = 10; + const rareItemChance = 0.1; const oneDay = 24 * 60 * 60 * 1000; let userEconomy = await UserEconomy.findOne({ @@ -35,37 +37,48 @@ module.exports = { .setColor("#ff0000") .setTitle("Daily Reward Claim") .setDescription( - `You have already claimed your daily reward today. Come back in **${hours}h ${minutes}m ${seconds}s**!` + `Come back in **${hours}h ${minutes}m ${seconds}s** for your next reward!` ) + .setTimestamp() .setFooter({ - text: `Requested in ${guild.name}`, - iconURL: guild.iconURL() || null, + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), }); await interaction.reply({ embeds: [errorEmbed] }); return; } - userEconomy.balance += dailyReward; + let reward = dailyBaseReward + userEconomy.streak * streakBonus; + userEconomy.streak += 1; 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!"; + } + await userEconomy.save(); const successEmbed = new EmbedBuilder() .setColor("#00ff00") .setTitle("Daily Reward Claimed!") .setDescription( - `You claimed your daily reward of **${dailyReward}** coins!` + `You've claimed **${reward}** coins and extended your streak!${rareItemMessage}` ) .addFields({ - name: "Total Balance", - value: `You now have **${userEconomy.balance}** coins.`, + name: "Streak Bonus", + value: `Current streak: **${userEconomy.streak}** days`, inline: true, }) - .setTimestamp() .setFooter({ text: `Requested by ${user.username}`, iconURL: user.displayAvatarURL(), - }); + }) + .setTimestamp(); await interaction.reply({ embeds: [successEmbed] }); }, diff --git a/commands/economy/inventory.js b/commands/economy/inventory.js index 0739d48..e070695 100644 --- a/commands/economy/inventory.js +++ b/commands/economy/inventory.js @@ -5,11 +5,10 @@ const ShopItem = require("../../models/ShopItem"); module.exports = { data: new SlashCommandBuilder() .setName("inventory") - .setDescription("View your inventory"), + .setDescription("View your inventory with item rarity"), async execute(interaction) { const { user, guild } = interaction; - const inventory = await UserInventory.find({ userId: user.id, guildId: guild.id, @@ -20,9 +19,10 @@ module.exports = { .setColor("#ff0000") .setTitle("Inventory") .setDescription("Your inventory is empty.") + .setTimestamp() .setFooter({ - text: `Requested in ${guild.name}`, - iconURL: guild.iconURL() || null, + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), }); await interaction.reply({ embeds: [emptyEmbed] }); @@ -33,7 +33,7 @@ module.exports = { inventory.map(async (item) => { const shopItem = await ShopItem.findOne({ itemId: item.itemId }); if (item.quantity > 0) { - return `${shopItem.name} (x${item.quantity})`; + return `${shopItem.name} (x${item.quantity}) - **Rarity**: ${shopItem.rarity}`; } return null; }) @@ -41,20 +41,6 @@ module.exports = { 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`) diff --git a/commands/economy/shop.js b/commands/economy/shop.js index 797abbf..3ba06dd 100644 --- a/commands/economy/shop.js +++ b/commands/economy/shop.js @@ -1,108 +1,49 @@ 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") - ), + .setDescription("Browse the shop for items with rarity and discounts!"), async execute(interaction) { const { user, guild } = interaction; - const itemId = interaction.options.getString("item"); + const discountChance = 0.3; + const items = await ShopItem.find({ guildId: guild.id }); - 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() + if (items.length === 0) { + const emptyEmbed = new EmbedBuilder() .setColor("#ff0000") - .setTitle("❌ Item Not Found") - .setDescription("The specified item could not be found in the shop.") + .setTitle("Shop") + .setDescription("No items in the shop currently.") + .setTimestamp() .setFooter({ - text: `Requested in ${guild.name}`, - iconURL: guild.iconURL() || null, + text: `Requested by ${user.username}`, + iconURL: user.displayAvatarURL(), }); - await interaction.reply({ embeds: [notFoundEmbed] }); + await interaction.reply({ embeds: [emptyEmbed] }); return; } - const userEconomy = await UserEconomy.findOne({ - userId: user.id, - guildId: guild.id, + const shopItemsDetails = items.map((item) => { + const discount = Math.random() < discountChance ? 0.8 : 1; + const price = Math.floor(item.price * discount); + const discountText = discount < 1 ? " (Discounted!)" : ""; + + return `${item.name} - **${price}** coins${discountText} - Rarity: ${item.rarity}`; }); - 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() + const shopEmbed = new EmbedBuilder() .setColor("#00ff00") - .setTitle("🎉 Purchase Successful") - .setDescription( - `You've successfully purchased **${shopItem.name}** for **${shopItem.price}** coins!` - ) + .setTitle("Shop") + .setDescription(shopItemsDetails.join("\n")) .setTimestamp() .setFooter({ text: `Requested by ${user.username}`, iconURL: user.displayAvatarURL(), }); - await interaction.reply({ embeds: [successEmbed] }); + await interaction.reply({ embeds: [shopEmbed] }); }, }; diff --git a/commands/economy/work.js b/commands/economy/work.js index a317cf9..ddea4da 100644 --- a/commands/economy/work.js +++ b/commands/economy/work.js @@ -4,29 +4,35 @@ const UserEconomy = require("../../models/UserEconomy"); module.exports = { data: new SlashCommandBuilder() .setName("work") - .setDescription("Work to earn coins!"), + .setDescription("Work to earn coins and experience random events!"), async execute(interaction) { const { user, guild } = interaction; - const workReward = 100; - const cooldownTime = 60 * 60 * 1000; + const jobs = [ + { name: "Farmer", reward: 100 }, + { name: "Miner", reward: 150 }, + { name: "Chef", reward: 120 }, + { name: "Artist", reward: 130 }, + ]; + const randomJob = jobs[Math.floor(Math.random() * jobs.length)]; + const randomBonus = + Math.random() < 0.1 ? Math.floor(Math.random() * 200) : 0; + const workReward = randomJob.reward + randomBonus; let userEconomy = await UserEconomy.findOne({ userId: user.id, guildId: guild.id, }); + const cooldownTime = 60 * 60 * 1000; 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)); @@ -54,12 +60,9 @@ module.exports = { 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, - }) + .setDescription( + `You worked as a **${randomJob.name}** and earned **${workReward}** coins!` + ) .setTimestamp() .setFooter({ text: `Requested by ${user.username}`, diff --git a/index.js b/index.js index b50e69b..e9cd2e4 100644 --- a/index.js +++ b/index.js @@ -62,11 +62,14 @@ client.once("ready", async () => { console.log(`🤖 Logged in as ${client.user.tag}`); console.log(`==============================`); - // Seed the shop items - await seedShopItems(); - // Register commands for all existing guilds const guilds = client.guilds.cache.map((guild) => guild.id); + + // Seed the shop items + for (const guildId of guilds) { + await seedShopItems(guildId); // Pass guildId to seedShopItems + } + for (const guildId of guilds) { await registerCommands(guildId); } @@ -87,6 +90,9 @@ client.on("guildCreate", async (guild) => { await ServerSettings.create({ guildId: guild.id }); console.log(`✅ Registered new server: ${guild.name} (ID: ${guild.id})`); + // seed items for new guild with guildId + await seedShopItems(guild.id); + // Register slash commands for the new guild await registerCommands(guild.id); } catch (error) { diff --git a/models/ShopItem.js b/models/ShopItem.js index ef48a61..71a29ec 100644 --- a/models/ShopItem.js +++ b/models/ShopItem.js @@ -1,10 +1,16 @@ const mongoose = require("mongoose"); const shopItemSchema = new mongoose.Schema({ - itemId: { type: String, required: true, unique: true }, + itemId: { type: String, required: true }, + guildId: { type: String, required: true }, name: { type: String, required: true }, price: { type: Number, required: true }, description: { type: String, required: true }, + rarity: { + type: String, + enum: ["Common", "Rare", "Epic", "Legendary"], + default: "Common", + }, }); module.exports = mongoose.model("ShopItem", shopItemSchema); diff --git a/utils/seedShopItems.js b/utils/seedShopItems.js index 4a80d4a..930f346 100644 --- a/utils/seedShopItems.js +++ b/utils/seedShopItems.js @@ -1,14 +1,14 @@ const ShopItem = require("../models/ShopItem"); -async function seedShopItems() { +async function seedShopItems(guildId) { 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.", + rarity: "Rare", }, { itemId: "reaver_vandal", @@ -16,6 +16,7 @@ async function seedShopItems() { price: 1500, description: "One of the most popular Vandal skins with a haunting aesthetic and special animations.", + rarity: "Epic", }, { itemId: "sovereign_ghost", @@ -23,6 +24,7 @@ async function seedShopItems() { price: 800, description: "Golden elegance for the Ghost pistol with unique sound effects.", + rarity: "Common", }, { itemId: "araxys_operator", @@ -30,6 +32,7 @@ async function seedShopItems() { price: 2000, description: "A top-tier sniper skin with alien-like animations and sound effects.", + rarity: "Legendary", }, { itemId: "glitchpop_bulldog", @@ -37,15 +40,15 @@ async function seedShopItems() { price: 900, description: "A flashy skin for the Bulldog with vibrant colors and cyberpunk vibe.", + rarity: "Rare", }, - - // 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.", + rarity: "Legendary", }, { itemId: "ak47_redline", @@ -53,6 +56,7 @@ async function seedShopItems() { price: 1000, description: "A simple yet iconic AK-47 skin with red and black color scheme.", + rarity: "Common", }, { itemId: "m4a4_howl", @@ -60,6 +64,7 @@ async function seedShopItems() { price: 2200, description: "A rare and valuable skin for the M4A4 with a striking wolf design.", + rarity: "Epic", }, { itemId: "desert_eagle_kumicho_dragon", @@ -67,6 +72,7 @@ async function seedShopItems() { price: 800, description: "A Desert Eagle skin with an intricate dragon design and a metallic finish.", + rarity: "Rare", }, { itemId: "usp_kill_confirmed", @@ -74,14 +80,20 @@ async function seedShopItems() { price: 1100, description: "A detailed skin for the USP-S with a unique comic-style design.", + rarity: "Epic", }, ]; + // Upsert each item with guildId included, so changes to price, rarity, etc., get updated for (const item of items) { - await ShopItem.updateOne({ itemId: item.itemId }, item, { upsert: true }); + await ShopItem.updateOne( + { itemId: item.itemId, guildId }, + { ...item, guildId }, + { upsert: true } + ); } - console.log("✅ Shop items seeded!"); + console.log(`✅ Shop items seeded with rarity for guild: ${guildId}`); } module.exports = seedShopItems;