resonancerumble/discordbot.py
2024-08-09 17:00:28 +12:00

191 lines
8.9 KiB
Python

import discord
from discord import app_commands
from discord.ext import commands
import pymongo
from bson.objectid import ObjectId
import logging
from config import DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, DISCORD_REDIRECT_URI, DISCORD_BOT_TOKEN, DISCORD_GUILD_ID, ACCOUNT_LINKED_ROLE_ID, DISCORD_WEBHOOK_URL
# Set up logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s:%(levelname)s:%(name)s: %(message)s')
logger = logging.getLogger('resonance_rumble_bot')
# MongoDB setup
client = pymongo.MongoClient('mongodb://localhost:27017/')
db = client['resonance_rumble']
classes_collection = db['classes']
weapons_collection = db['weapons']
skins_collection = db['skins']
users_collection = db['users']
intents = discord.Intents.all()
intents.message_content = True #v2
intents.members = True
bot = commands.Bot(command_prefix='!', intents=intents)
LINKED_ROLE_NAME = "Account-linked"
@bot.event
async def on_ready():
print(f'{bot.user} has connected to Discord!')
try:
synced = await bot.tree.sync()
print(f"Synced {len(synced)} command(s)")
except Exception as e:
print(f"Error syncing commands: {e}")
@bot.event
async def on_member_join(member):
logger.info(f"New member joined: {member.name} (ID: {member.id})")
role = discord.utils.get(member.guild.roles, name="Member")
if role:
try:
await member.add_roles(role)
logger.info(f"Successfully added Member role to {member.name}")
except discord.Forbidden:
logger.error(f"Failed to add Member role to {member.name}: Bot doesn't have permission")
except discord.HTTPException as e:
logger.error(f"Failed to add Member role to {member.name}: {str(e)}")
else:
logger.error(f"'Member' role not found in the server")
async def class_autocomplete(interaction: discord.Interaction, current: str) -> list[app_commands.Choice[str]]:
classes = classes_collection.find({}, {"name": 1})
return [
app_commands.Choice(name=class_doc["name"], value=class_doc["name"])
for class_doc in classes if current.lower() in class_doc["name"].lower()
][:25] # Discord limits to 25 choices
@bot.tree.command(name="class_info", description="Get information about a game class")
@app_commands.autocomplete(class_name=class_autocomplete)
async def class_info(interaction: discord.Interaction, class_name: str):
class_data = classes_collection.find_one({"name": class_name})
if class_data:
embed = discord.Embed(title=f"{class_name} Class Info", color=0x00ff00)
embed.add_field(name="Health", value=class_data['base_attributes']['health'], inline=True)
embed.add_field(name="Speed", value=class_data['base_attributes']['speed'], inline=True)
embed.add_field(name="Damage Multiplier", value=class_data['base_attributes']['damage_multiplier'], inline=True)
embed.add_field(name="Weapon Limit", value=class_data['weapon_limit'], inline=True)
await interaction.response.send_message(embed=embed)
else:
await interaction.response.send_message(f"Class '{class_name}' not found.", ephemeral=True)
async def weapon_autocomplete(interaction: discord.Interaction, current: str) -> list[app_commands.Choice[str]]:
weapons = weapons_collection.find({}, {"name": 1})
return [
app_commands.Choice(name=weapon["name"], value=weapon["name"])
for weapon in weapons if current.lower() in weapon["name"].lower()
][:25]
@bot.tree.command(name="weapon_info", description="Get information about a weapon")
@app_commands.autocomplete(weapon_name=weapon_autocomplete)
async def weapon_info(interaction: discord.Interaction, weapon_name: str):
weapon_data = weapons_collection.find_one({"name": weapon_name})
if weapon_data:
embed = discord.Embed(title=f"{weapon_name} Weapon Info", color=0x0000ff)
embed.add_field(name="Type", value=weapon_data['weapon_type'], inline=True)
embed.add_field(name="Damage", value=weapon_data['base_attributes']['damage'], inline=True)
embed.add_field(name="Fire Rate", value=weapon_data['base_attributes']['fire_rate'], inline=True)
embed.add_field(name="Bullet Speed", value=weapon_data['base_attributes']['bullet_speed'], inline=True)
await interaction.response.send_message(embed=embed)
else:
await interaction.response.send_message(f"Weapon '{weapon_name}' not found.", ephemeral=True)
async def skin_autocomplete(interaction: discord.Interaction, current: str) -> list[app_commands.Choice[str]]:
skins = skins_collection.find({}, {"name": 1})
return [
app_commands.Choice(name=skin["name"], value=skin["name"])
for skin in skins if current.lower() in skin["name"].lower()
][:25]
@bot.tree.command(name="skin_info", description="Get information about a skin")
@app_commands.autocomplete(skin_name=skin_autocomplete)
async def skin_info(interaction: discord.Interaction, skin_name: str):
skin_data = skins_collection.find_one({"name": skin_name})
if skin_data:
embed = discord.Embed(title=f"{skin_name} Skin Info", color=0xff00ff)
embed.add_field(name="Type", value=skin_data['type'], inline=True)
embed.add_field(name="Rarity", value=skin_data['rarity'], inline=True)
embed.add_field(name="Effect", value=skin_data['effect'], inline=True)
await interaction.response.send_message(embed=embed)
else:
await interaction.response.send_message(f"Skin '{skin_name}' not found.", ephemeral=True)
@bot.tree.command(name="leaderboard", description="Show the top players")
@app_commands.describe(category="The category for the leaderboard")
@app_commands.choices(category=[
app_commands.Choice(name="Level", value="level"),
app_commands.Choice(name="Synth Coins", value="synth_coins"),
app_commands.Choice(name="Experience", value="experience")
])
async def leaderboard(interaction: discord.Interaction, category: app_commands.Choice[str]):
top_players = list(db.users.find().sort(category.value, -1).limit(10))
embed = discord.Embed(title=f"Top 10 Players - {category.name}", color=0xffa500)
for i, player in enumerate(top_players, 1):
embed.add_field(name=f"{i}. {player['username']}", value=f"{category.name}: {player.get(category.value, 0)}", inline=False)
await interaction.response.send_message(embed=embed)
@bot.tree.command(name="check_permissions", description="Check bot's permissions")
@commands.has_permissions(administrator=True)
async def check_permissions(interaction: discord.Interaction):
bot_member = interaction.guild.get_member(bot.user.id)
permissions = bot_member.guild_permissions
embed = discord.Embed(title="Bot Permissions", color=0x00ff00)
crucial_perms = ["manage_roles", "view_channel", "send_messages", "embed_links"]
for perm, value in permissions:
if perm in crucial_perms:
embed.add_field(name=perm.replace('_', ' ').title(), value=str(value), inline=False)
await interaction.response.send_message(embed=embed)
@bot.tree.command(name="link_status", description="Check your Resonance Rumble account link status")
async def link_status(interaction: discord.Interaction):
user = users_collection.find_one({'discord_id': str(interaction.user.id)})
if user:
await add_linked_role(interaction.user)
await interaction.response.send_message(f"Your Discord account is linked to the Resonance Rumble account: {user['username']}")
else:
await interaction.response.send_message("Your Discord account is not linked to any Resonance Rumble account. Use the in-game menu to link your account.")
async def add_linked_role(member):
guild = member.guild
role = discord.utils.get(guild.roles, name=LINKED_ROLE_NAME)
if role is None:
# Create the role if it doesn't exist
role = await guild.create_role(name=LINKED_ROLE_NAME, color=discord.Color.blue())
if role not in member.roles:
try:
await member.add_roles(role)
print(f"Added {LINKED_ROLE_NAME} role to {member.name}")
except discord.Forbidden:
print(f"Bot doesn't have permission to add roles to {member.name}")
except discord.HTTPException as e:
print(f"Failed to add role to {member.name}: {str(e)}")
# You might want to add a command to manually sync roles
@bot.tree.command(name="sync_linked_role", description="Sync the Account-linked role for all linked users")
@commands.has_permissions(administrator=True)
async def sync_linked_role(interaction: discord.Interaction):
await interaction.response.defer()
guild = interaction.guild
linked_users = users_collection.find({'discord_id': {'$exists': True}})
count = 0
for user in linked_users:
member = guild.get_member(int(user['discord_id']))
if member:
await add_linked_role(member)
count += 1
await interaction.followup.send(f"Synced roles for {count} linked users.")
bot.run(DISCORD_BOT_TOKEN)