mirror of
https://github.com/aydenjahola/discord-multipurpose-bot.git
synced 2024-11-23 09:15:56 +00:00
economy: update the logic and add random work with different prices, add daily bonus + discount on shop and make shop per guild id
This commit is contained in:
parent
e12591e561
commit
81cfdd4b21
8 changed files with 110 additions and 137 deletions
|
@ -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] });
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,38 +37,49 @@ 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!`
|
||||
)
|
||||
.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: [errorEmbed] });
|
||||
return;
|
||||
}
|
||||
|
||||
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've claimed **${reward}** coins and extended your streak!${rareItemMessage}`
|
||||
)
|
||||
.addFields({
|
||||
name: "Streak Bonus",
|
||||
value: `Current streak: **${userEconomy.streak}** days`,
|
||||
inline: true,
|
||||
})
|
||||
.setFooter({
|
||||
text: `Requested by ${user.username}`,
|
||||
iconURL: user.displayAvatarURL(),
|
||||
})
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({ embeds: [successEmbed] });
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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`)
|
||||
|
|
|
@ -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.")
|
||||
.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!`
|
||||
)
|
||||
.setTitle("Shop")
|
||||
.setDescription("No items in the shop currently.")
|
||||
.setTimestamp()
|
||||
.setFooter({
|
||||
text: `Requested by ${user.username}`,
|
||||
iconURL: user.displayAvatarURL(),
|
||||
});
|
||||
|
||||
await interaction.reply({ embeds: [successEmbed] });
|
||||
await interaction.reply({ embeds: [emptyEmbed] });
|
||||
return;
|
||||
}
|
||||
|
||||
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}`;
|
||||
});
|
||||
|
||||
const shopEmbed = new EmbedBuilder()
|
||||
.setColor("#00ff00")
|
||||
.setTitle("Shop")
|
||||
.setDescription(shopItemsDetails.join("\n"))
|
||||
.setTimestamp()
|
||||
.setFooter({
|
||||
text: `Requested by ${user.username}`,
|
||||
iconURL: user.displayAvatarURL(),
|
||||
});
|
||||
|
||||
await interaction.reply({ embeds: [shopEmbed] });
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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}`,
|
||||
|
|
12
index.js
12
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue