import asyncio import discord from redbot.core import commands, Config # type: ignore from redbot.core.bot import Red # type: ignore from redbot.core.utils.chat_formatting import box, humanize_list # type: ignore from typing import Dict, List, Optional class Inventory(commands.Cog): """A cog for managing user inventories and trading items between users.""" def __init__(self, bot: Red): self.bot = bot self.config = Config.get_conf( self, identifier=582650110, # Unique identifier for this cog force_registration=True ) # Default user settings default_user = { "inventory": {}, # {item_name: quantity} "trade_history": [], # List of recent trades "trading_with": None, # User currently trading with "trade_offer": {}, # Current trade offer "trade_accepted": False # Whether user has accepted current trade } # Default guild settings default_guild = { "items": { "common_sword": {"name": "Common Sword", "value": 100, "description": "A basic sword"}, "health_potion": {"name": "Health Potion", "value": 50, "description": "Restores health"}, "magic_scroll": {"name": "Magic Scroll", "value": 200, "description": "Contains magical spells"} } } self.config.register_user(**default_user) self.config.register_guild(**default_guild) async def initialize(self): """Initialize the cog.""" pass @commands.group() async def inventory(self, ctx: commands.Context): """Inventory management commands""" if ctx.invoked_subcommand is None: await self.show_inventory(ctx) async def show_inventory(self, ctx: commands.Context): """Show a user's inventory""" inventory = await self.config.user(ctx.author).inventory() if not inventory: await ctx.send("Your inventory is empty!") return guild_items = await self.config.guild(ctx.guild).items() # Format inventory display output = ["Your Inventory:"] for item_id, quantity in inventory.items(): if item_id in guild_items: item = guild_items[item_id] output.append(f"{item['name']} (x{quantity}) - Worth: {item['value']} coins") await ctx.send(box("\n".join(output))) @commands.command() async def additem(self, ctx: commands.Context, item_id: str, quantity: int = 1): """Add an item to your inventory (Admin only)""" if not await self.bot.is_owner(ctx.author): await ctx.send("Only the bot owner can add items!") return guild_items = await self.config.guild(ctx.guild).items() if item_id not in guild_items: await ctx.send(f"Invalid item ID! Available items: {', '.join(guild_items.keys())}") return async with self.config.user(ctx.author).inventory() as inventory: if item_id in inventory: inventory[item_id] += quantity else: inventory[item_id] = quantity await ctx.send(f"Added {quantity}x {guild_items[item_id]['name']} to your inventory!") @commands.group() async def trade(self, ctx: commands.Context): """Trading commands""" pass @trade.command(name="offer") async def trade_offer(self, ctx: commands.Context, user: discord.Member, item_id: str, quantity: int = 1): """Offer to trade an item to another user""" if user.bot: await ctx.send("You can't trade with bots!") return if user == ctx.author: await ctx.send("You can't trade with yourself!") return # Check if user has the item inventory = await self.config.user(ctx.author).inventory() if item_id not in inventory or inventory[item_id] < quantity: await ctx.send("You don't have enough of that item!") return # Check if either user is already trading author_trading = await self.config.user(ctx.author).trading_with() target_trading = await self.config.user(user).trading_with() if author_trading or target_trading: await ctx.send("One of the users is already in a trade!") return # Set up the trade await self.config.user(ctx.author).trading_with.set(user.id) await self.config.user(user).trading_with.set(ctx.author.id) await self.config.user(ctx.author).trade_offer.set({item_id: quantity}) await self.config.user(ctx.author).trade_accepted.set(False) await self.config.user(user).trade_accepted.set(False) guild_items = await self.config.guild(ctx.guild).items() item_name = guild_items[item_id]["name"] await ctx.send(f"{user.mention}, {ctx.author.name} wants to trade {quantity}x {item_name} with you!\n" f"Use `{ctx.prefix}trade accept` to accept or `{ctx.prefix}trade cancel` to decline.") @trade.command(name="accept") async def trade_accept(self, ctx: commands.Context): """Accept a trade offer""" trading_with = await self.config.user(ctx.author).trading_with() if not trading_with: await ctx.send("You don't have any pending trades!") return trader = ctx.guild.get_member(trading_with) if not trader: await ctx.send("Could not find the user you're trading with!") await self.cancel_trade(ctx.author) return # Get the trade details trade_offer = await self.config.user(trader).trade_offer() if not trade_offer: await ctx.send("No items were offered for trade!") await self.cancel_trade(ctx.author) return # Process the trade trader_inventory = await self.config.user(trader).inventory() receiver_inventory = await self.config.user(ctx.author).inventory() for item_id, quantity in trade_offer.items(): # Remove from trader if trader_inventory[item_id] < quantity: await ctx.send("The trader no longer has enough items!") await self.cancel_trade(ctx.author) return trader_inventory[item_id] -= quantity if trader_inventory[item_id] <= 0: del trader_inventory[item_id] # Add to receiver if item_id in receiver_inventory: receiver_inventory[item_id] += quantity else: receiver_inventory[item_id] = quantity # Save the new inventories await self.config.user(trader).inventory.set(trader_inventory) await self.config.user(ctx.author).inventory.set(receiver_inventory) # Record the trade in history guild_items = await self.config.guild(ctx.guild).items() trade_record = { "from": trader.id, "to": ctx.author.id, "items": {item_id: {"name": guild_items[item_id]["name"], "quantity": qty} for item_id, qty in trade_offer.items()} } async with self.config.user(trader).trade_history() as history: history.append(trade_record) async with self.config.user(ctx.author).trade_history() as history: history.append(trade_record) # Clear the trade await self.cancel_trade(ctx.author) await self.cancel_trade(trader) # Notify users items_traded = [f"{qty}x {guild_items[item_id]['name']}" for item_id, qty in trade_offer.items()] await ctx.send(f"Trade completed! {trader.name} traded {humanize_list(items_traded)} to {ctx.author.name}") @trade.command(name="cancel") async def trade_cancel(self, ctx: commands.Context): """Cancel a pending trade""" trading_with = await self.config.user(ctx.author).trading_with() if not trading_with: await ctx.send("You don't have any pending trades!") return other_user = ctx.guild.get_member(trading_with) await self.cancel_trade(ctx.author) if other_user: await self.cancel_trade(other_user) await ctx.send("Trade cancelled!") async def cancel_trade(self, user): """Helper function to cancel a trade for a user""" await self.config.user(user).trading_with.set(None) await self.config.user(user).trade_offer.set({}) await self.config.user(user).trade_accepted.set(False) @commands.command() async def iteminfo(self, ctx: commands.Context, item_id: str): """Get information about an item""" guild_items = await self.config.guild(ctx.guild).items() if item_id not in guild_items: await ctx.send(f"Invalid item ID! Available items: {', '.join(guild_items.keys())}") return item = guild_items[item_id] await ctx.send(box( f"Item: {item['name']}\n" f"Value: {item['value']} coins\n" f"Description: {item['description']}" )) @commands.command() async def listitems(self, ctx: commands.Context): """List all available items""" guild_items = await self.config.guild(ctx.guild).items() output = ["Available Items:"] for item_id, item in guild_items.items(): output.append(f"{item_id}: {item['name']} - {item['value']} coins") await ctx.send(box("\n".join(output)))