245 lines
No EOL
9.9 KiB
Python
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))) |