Ruby-Cogs/inventory/inventory.py

245 lines
No EOL
9.9 KiB
Python

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)))