First Commit

This commit is contained in:
2025-09-16 15:00:16 +02:00
commit c8980f785f
188 changed files with 43407 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+224
View File
@@ -0,0 +1,224 @@
import datetime
import time
import os
import discord
from discord.ext import commands
async def reload_all(client, ctx):
"""
Reloads all cogs (modules) in the 'cogs' folder and syncs the command tree.
Args:
client (discord.Client): The bot's main client object.
ctx (commands.Context): The context in which the command was invoked.
"""
cogs_folder = os.path.abspath(os.path.dirname(__file__)) # Get the cogs folder path
for filename in os.listdir(cogs_folder):
if filename.endswith(".py"):
try:
await client.reload_extension(f"implementing.{filename[:-3]}")
except Exception as e:
print(f"Error reloading {filename}: {e}")
await client.load_extension(f"implementing.{filename[:-3]}")
await client.tree.sync() # Synchronize command tree
await ctx.reply("Reloaded all cogs.")
class Admin(commands.Cog):
"""Cog that provides administrative commands for bot control and information."""
def __init__(self, client):
self.client = client
@commands.command(
name="ping",
brief="Bot Latency",
description="Displays the bot's latency in milliseconds.",
)
async def _ping(self, ctx):
"""
Responds with the bot's latency (ping time).
Args:
ctx (commands.Context): The context in which the command was invoked.
"""
latency = round(self.client.latency * 1000, 2) # Convert to ms
await ctx.reply(f"Pong! 🏓\nLatency: {latency}ms")
@commands.command(
name="info",
brief="Bot Info",
description="Provides information about the bot's owner and team (if applicable).",
)
async def _info(self, ctx):
"""
Displays information about the bot's owner or team members.
Args:
ctx (commands.Context): The context in which the command was invoked.
"""
app_info = await self.client.application_info()
if app_info.team:
team_members = "\n".join(
f"{member.name}#{member.discriminator} ({'Owner' if member.id == app_info.team.owner_id else 'Member'})"
for member in app_info.team.members
)
await ctx.reply(
f"Bot is part of the team: {app_info.team.name}\nMembers:\n{team_members}"
)
else:
await ctx.reply(
f"Bot is owned by {app_info.owner} and is not part of a team."
)
@commands.command(
name="uptime",
brief="Bot Runtime",
description="Displays how long the bot has been running since its last restart.",
)
async def _uptime(self, ctx):
"""
Calculates and sends the bot's uptime based on a start timestamp.
Args:
ctx (commands.Context): The context in which the command was invoked.
"""
with open("time.txt", "r") as file:
start_time = float(file.read())
uptime = str(
datetime.timedelta(seconds=int(time.time() - start_time))
) # Calculate uptime
await ctx.send(f"Uptime: {uptime}")
@commands.hybrid_command(
name="reload",
brief="Reload Cog",
description="Reloads a specific cog or all cogs.",
aliases=["rl"],
)
@commands.is_owner()
async def _reload(self, ctx, extension: str):
"""
Reloads a specified cog/module or all modules if 'all' is passed.
Args:
ctx (commands.Context): The context in which the command was invoked.
extension (str): Name of the cog to reload, or 'all' to reload all cogs.
"""
if extension.lower() == "all":
await reload_all(self.client, ctx)
return
try:
await self.client.unload_extension(f"implementing.{extension}")
await self.client.load_extension(f"implementing.{extension}")
await ctx.send(f"Successfully reloaded {extension}.")
except commands.ExtensionNotLoaded:
await ctx.send(f"Extension {extension} was not loaded, loading it now.")
try:
await self.client.load_extension(f"implementing.{extension}")
await ctx.send(f"Successfully loaded {extension}.")
except Exception as e:
await ctx.send(f"Failed to load {extension}: {e}")
except commands.ExtensionNotFound:
await ctx.send(f"Extension {extension} was not found.")
except Exception as e:
await ctx.send(f"Failed to reload {extension}: {e}")
@commands.hybrid_command(
name="purge",
brief="Delete messages",
description="Deletes a specified number of messages from the current channel (default: 100).",
)
@commands.has_permissions(manage_channels=True)
@commands.cooldown(1, 10, commands.BucketType.user)
async def _purge(self, ctx, n: int = 100):
"""
Deletes a specified number of messages from the current channel.
Args:
ctx (commands.Context): The context in which the command was invoked.
n (int, optional): The number of messages to delete. Defaults to 100.
"""
n += 1
if n <= 0:
return
if n < 100:
await ctx.channel.purge(limit=n)
await ctx.channel.send(
f"Successfully purged last {n-1} messages", delete_after=2
)
elif n == 100:
await ctx.channel.purge()
await ctx.channel.send(
"Successfully purged last 100 messages", delete_after=2
)
else: # n > 100
for i in range(n // 100):
await ctx.channel.purge()
await ctx.channel.purge(limit=n % 100)
await ctx.channel.send(
f"Successfully purged last {n-1} messages", delete_after=2
)
@commands.hybrid_command(
name="nuke",
brief="Clear channel",
description="Deletes all messages by duplicating and deleting the channel.",
)
@commands.has_permissions(manage_channels=True)
@commands.cooldown(1, 30, commands.BucketType.user)
async def _nuke(self, ctx, channel_name: str = "Current"):
"""
Duplicates and deletes a specified channel (or the current channel) to clear messages.
Args:
ctx (commands.Context): The context in which the command was invoked.
channel_name (str, optional): Name of the channel to nuke. Defaults to 'Current' (the invoking channel).
"""
# Determine the channel ID based on the channel_name parameter
if channel_name.lower() == "current":
channel_id = ctx.channel.id
else:
channel_id = discord.utils.get(ctx.guild.channels, name=channel_name)
if channel_id is None:
return await ctx.send(f"Channel **{channel_name}** was not found.")
existing_channel = self.client.get_channel(channel_id)
if existing_channel:
await existing_channel.clone(reason="Channel has been nuked")
await existing_channel.delete()
await self._send_embed(
ctx,
f"Channel **{existing_channel.name}** has been nuked.",
discord.Color.red(),
)
else:
await ctx.send(f"No channel with ID {channel_id} was found.")
@commands.command(
name="guildids",
brief="List all guild IDs",
description="Lists all guild IDs the bot is currently in. Owner only.",
)
@commands.is_owner()
async def _guildids(self, ctx):
"""
Sends a list of all guild IDs the bot is in to the owner.
Args:
ctx (commands.Context): The context in which the command was invoked.
"""
guild_ids = [str(guild.id) for guild in self.client.guilds]
guilds_str = "\n".join(guild_ids)
await ctx.author.send(f"Guild IDs:\n{guilds_str}")
await ctx.reply("Sent you a DM with all guild IDs.")
async def _send_embed(self, ctx, description, color=discord.Color.blurple()):
embed = discord.Embed(description=description, color=color)
await ctx.send(embed=embed)
async def setup(client):
"""Sets up the Admin cog for the bot."""
await client.add_cog(Admin(client))
+430
View File
@@ -0,0 +1,430 @@
import discord
import datetime
import random
from discord.ext import commands
from utils.sql_commands import DatabaseManager
import asyncio
def random_gradient():
"""
Generate a random color in hexadecimal format.
Returns:
int: A random color in hexadecimal format (e.g., 0xFFFFFF).
"""
return random.randint(0, 0xFFFFFF)
def ordinal(number):
"""
Convert a number to its ordinal representation (e.g., 1st, 2nd, 3rd).
Args:
number (int): The number to convert to an ordinal.
Returns:
str: The ordinal representation of the given number.
"""
if 10 <= number % 100 <= 20:
suffix = "th"
else:
suffix = {1: "st", 2: "nd", 3: "rd"}.get(number % 10, "th")
return f"{number}{suffix}"
async def get_channel_id(bot, ctx, allow_blank=False):
"""
Prompt the user to input a channel ID, allowing for options to skip or remove.
Args:
bot (discord.Client): The bot instance.
ctx (commands.Context): The context in which the command was invoked.
allow_blank (bool, optional): If True, allows 'skip' or 'remove' as options.
Returns:
int or str: The ID of the mentioned channel, "pass" if skipped, or None if removed.
"""
try:
msg = await bot.wait_for(
"message", check=lambda message: message.author == ctx.author, timeout=60
)
# Handle blank input options
if allow_blank:
if msg.content.lower() == "skip":
return "pass"
if msg.content.lower() == "remove":
return None
# Check if a channel was mentioned
if msg.channel_mentions:
return msg.channel_mentions[0].id
await ctx.send("Please mention a valid channel.")
return await get_channel_id(bot, ctx, allow_blank)
except asyncio.TimeoutError:
await ctx.send("You took too long to respond. Please run the command again.")
return None
async def server_join_embed(db: DatabaseManager, member: discord.Member):
"""
Create a dynamic welcome embed for a new server member.
Args:
db (DatabaseManager): The database manager instance.
member (discord.Member): The new member joining the server.
Returns:
discord.Embed: A dynamically generated welcome embed for the new member.
"""
guild_channels = db.fetch_one(
"SELECT * FROM guilds WHERE GUILD = %s", (member.guild.id,)
)
# Prepare welcome messages
welcome_messages = [
f"🌟 Welcome to {member.guild.name}, {member.name}! 🌟",
f"🎉 Greetings, {member.name}! Welcome to {member.guild.name}!",
f"🚀 Ahoy, {member.name}! Set sail for adventure in {member.guild.name}!",
]
selected_message = random.choice(welcome_messages)
# Create embed
embed = discord.Embed(
title=selected_message,
description="We're delighted to have you join our community. Enjoy your stay!",
color=random_gradient(),
)
embed.set_thumbnail(url=member.display_avatar)
# Dynamic fields based on available channels
fields = [
(
"➡️ Get Started",
f"Check out the {get_channel_mention(guild_channels, 'RULES', member)} channel for server rules.",
),
(
"📚 Server Guide",
f"Explore the server guide in {get_channel_mention(guild_channels, 'GUIDE', member)}.",
),
(
"👋 Introduce Yourself",
f"Head over to {get_channel_mention(guild_channels, 'INTRODUCTIONS', member)} and let us know a bit about yourself.",
),
(
"💼 Join our Events",
f"Participate in {get_channel_mention(guild_channels, 'EVENTS', member)} for exciting events!",
),
]
for name, value in fields:
if value:
embed.add_field(name=name, value=value, inline=False)
# Member count update
if guild_channels.get("MEMBERCOUNT"):
member_count_channel = member.guild.get_channel(
int(guild_channels["MEMBERCOUNT"])
)
if member_count_channel:
await member_count_channel.edit(
name=f"Members: {len(member.guild.members)}"
)
# Joining position
join_position = sorted(member.guild.members, key=lambda m: m.joined_at).index(member) + 1 # type: ignore
embed.add_field(
name="🏆 Joining Position",
value=f"You are the {ordinal(join_position)} member to join!",
inline=False,
)
# Greeting based on time of day
current_time = datetime.datetime.now().time()
greeting = (
"Good morning!"
if 6 <= current_time.hour < 12
else "Good afternoon!" if 12 <= current_time.hour < 18 else "Good evening!"
)
embed.insert_field_at(
0, name="🌞 Time of Day Greeting", value=greeting, inline=False
)
return embed
def get_channel_mention(guild_channels, key, member):
"""
Retrieve a mention for a channel based on a key in the guild channels data.
Args:
guild_channels (dict): The dictionary containing channel IDs.
key (str): The key for the channel to mention.
member (discord.Member): The member for whom the mention is being created.
Returns:
str or None: The mention for the channel if found, otherwise None.
"""
channel_id = guild_channels.get(key)
if channel_id:
channel = member.guild.get_channel(int(channel_id))
return channel.mention if channel else None
return None
class Channels(commands.Cog):
"""Cog that handles channel-related commands and events."""
def __init__(self, client):
self.client = client
self.db = DatabaseManager()
@commands.Cog.listener()
async def on_member_join(self, member: discord.Member):
"""
Event listener for new member joins. Sends a welcome embed if a welcome channel is set.
Args:
member (discord.Member): The new member joining the server.
"""
embed = await server_join_embed(self.db, member)
# Fetch the welcome channel ID for the given guild
result = self.db.fetch_one(
"SELECT WELCOME FROM guilds WHERE GUILD = %s", (member.guild.id,)
)
# Safely get the WELCOME value, defaulting to None if not found
channel_id = result.get("WELCOME") if result else None
if channel_id is None:
return # No welcome channel set
welcome_channel = self.client.get_channel(int(channel_id))
if welcome_channel:
await welcome_channel.send(embed=embed)
@commands.command(
name="setchannels",
brief="Setup channel IDs in the database",
description="Adds or removes channel IDs to/from the database for use by the bot.",
)
@commands.has_permissions(manage_channels=True)
async def _channel_setup(self, ctx, specific_channel: str | None = None):
"""
Command to set up channel IDs in the database by prompting the user.
Args:
ctx (commands.Context): The context in which the command was invoked.
specific_channel (str, optional): The specific channel to set up, or None to set up all channels.
"""
channels = {}
channel_types = [
"Welcome",
"Rules",
"Guide",
"Introductions",
"Events",
"MemberCount",
"Logging",
"Ticketing",
]
if specific_channel and specific_channel.capitalize() in channel_types:
channel_types = [specific_channel.capitalize()]
await ctx.reply(
"Let's set up the channels.\nPlease provide the channel ID,\nskip to keep it unchanged or\nremove to unset the channel:\n\n"
)
# Collect channel IDs
for channel_type in channel_types:
await ctx.send(f"{len(channels)}. {channel_type} Channel ID:")
channels[channel_type] = await get_channel_id(
self.client, ctx, allow_blank=True
)
# Check if existing entries need updating
overwrite = (self.db.fetch_one("SELECT GUILD FROM guilds WHERE GUILD = %s", (ctx.guild.id,))is not None)
# Prepare data for the insert or update operation
data = tuple(
{
"GUILD": ctx.guild.id,
"WELCOME": channels.get("Welcome"),
"RULES": channels.get("Rules"),
"GUIDE": channels.get("Guide"),
"INTRODUCTIONS": channels.get("Introductions"),
"EVENTS": channels.get("Events"),
"MEMBERCOUNT": channels.get("MemberCount"),
"LOGGING": channels.get("Logging"),
"TICKETING": channels.get("Ticketing"),
}.values()
)
# Insert or update the channels in the database
self.db.insert(
"INSERT INTO guilds (GUILD, WELCOME, RULES, GUIDE, INTRODUCTIONS, EVENTS, MEMBERCOUNT, LOGGING, TICKETING) "
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ",
data,
overwrite=overwrite,
)
# Create a response message for the user
response = "\n".join(
[
f"{channel_type} Channel ID: {get_channel_mention(channels, channel_type, ctx.author)}"
for channel_type in channels
if channel_type != "pass"
]
)
await ctx.send(f"Channels set!\n{response}")
@commands.command(
name="welcomeTest",
brief="Test welcome message",
description="Sends a welcome message to the welcome channel.",
)
@commands.has_permissions(manage_channels=True)
async def _welcome_test(self, ctx):
"""
Command to test the welcome message in the designated welcome channel.
Args:
ctx (commands.Context): The context in which the command was invoked.
"""
member = ctx.author
embed = await server_join_embed(self.db, member)
channel_id = self.db.fetch_one(
"SELECT WELCOME FROM guilds WHERE GUILD=%s", (ctx.guild.id,)
).get("WELCOME")
if channel_id is None:
await ctx.reply("No Welcome Channel Set")
return
welcome_channel = self.client.get_channel(int(channel_id))
if welcome_channel:
await welcome_channel.send(embed=embed)
else:
await ctx.reply(
"The Welcome Channel is invalid. Please set a valid channel."
)
@commands.command(
name="autocreatechannels",
brief="Auto-create all recommended channels and categories if missing.",
description="Creates all recommended channels and categories if they do not exist.",
)
@commands.has_permissions(manage_channels=True)
async def autocreatechannels(self, ctx):
"""
Command to auto-create all recommended channels and categories if missing.
"""
# Recommended categories and their channels
categories_and_channels = {
"Welcome & Info": [
"welcome",
"rules",
"server-guide",
"introductions",
"announcements",
],
"Community": [
"general",
"off-topic",
"media",
"bot-commands",
"suggestions",
"polls",
],
"Support": ["help", "faq"],
"Events": ["events", "event-signup", "giveaways"],
"Moderation": ["mod-log", "reports"],
"Voice": ["General Voice", "Music", "AFK"],
"Management": ["member-count", "ticketing"],
"Staff": ["staff", "staff-announcements", "staff-logs"],
}
created = []
for category_name, channel_names in categories_and_channels.items():
category = await self.ensure_category(ctx.guild, category_name)
for ch_name in channel_names:
# For voice channels
if (
"voice" in ch_name.lower()
or ch_name.lower() == "music"
or ch_name.lower() == "afk"
):
ch_type = discord.ChannelType.voice
else:
ch_type = discord.ChannelType.text
channel = discord.utils.get(ctx.guild.channels, name=ch_name)
if not channel:
channel = await self.ensure_channel(
ctx.guild, ch_name, type=ch_type, category=category
)
created.append(channel.mention)
# Set permissions template for some channels
if ch_name.lower() == "rules" and isinstance(channel, discord.TextChannel):
await self.set_channel_permissions(channel, "rules")
if created:
await ctx.send(f"Created channels: {', '.join(created)}")
else:
await ctx.send("All recommended channels already exist.")
async def ensure_channel(
self, guild: discord.Guild, name, type=discord.ChannelType.text, category=None
):
existing = discord.utils.get(guild.channels, name=name)
if existing:
return existing
if type == discord.ChannelType.voice:
return await guild.create_voice_channel(name, category=category)
else:
return await guild.create_text_channel(name, category=category)
async def ensure_category(self, guild: discord.Guild, name):
existing = discord.utils.get(guild.categories, name=name)
if existing:
return existing
return await guild.create_category(name)
async def set_channel_permissions(self, channel: discord.TextChannel, template):
if template == "rules":
await channel.set_permissions(
channel.guild.default_role, send_messages=False
)
# Add more permission logic as needed
@commands.command()
@commands.has_permissions(manage_channels=True)
async def cleanup_channels(self, ctx):
unused = [ch for ch in ctx.guild.text_channels if ch.last_message_id is None]
for ch in unused:
await ch.delete(reason="Channel cleanup")
await ctx.send(f"Deleted {len(unused)} unused channels.")
@commands.command()
async def channelinfo(self, ctx, channel: discord.TextChannel | None = None):
channel = channel or ctx.channel
embed = discord.Embed(title=f"Info for #{channel.name}")
embed.add_field(name="ID", value=channel.id)
embed.add_field(name="Created", value=channel.created_at)
embed.add_field(name="Topic", value=channel.topic or "None")
embed.add_field(name="Slowmode", value=channel.slowmode_delay)
await ctx.send(embed=embed)
async def setup(client):
"""
Setup function to load the Channels cog.
Args:
client (commands.Bot): The bot instance.
"""
await client.add_cog(Channels(client))
+330
View File
@@ -0,0 +1,330 @@
import discord
from discord.ext import commands
import random
import asyncio
from collections import Counter
ROLES = ["Werewolf", "Seer", "Doctor", "Villager"]
ROLE_DESCRIPTIONS = {
"Werewolf": "You are a **Werewolf**! Work with your fellow werewolves at night to eliminate villagers. Your goal is to outnumber the villagers.",
"Seer": "You are the **Seer**! Each night, you may select a player to learn their true role.",
"Doctor": "You are the **Doctor**! Each night, you may choose a player to protect from elimination.",
"Villager": "You are a **Villager**! Try to find and vote out the werewolves during the day.",
}
class WerewolvesGame:
def __init__(self, channel):
self.channel = channel
self.players = []
self.started = False
self.roles = {} # user_id: role
self.phase = "lobby" # or "night", "day"
self.role_threads = {} # role: thread
self.votes = {}
self.vote_targets = []
self.alive = set()
def add_player(self, user):
if user not in self.players:
self.players.append(user)
def assign_roles(self):
# For 6+ players: 2 werewolves, 1 seer, 1 doctor, rest villagers
n = len(self.players)
roles_list = ["Werewolf"] * 2 + ["Seer", "Doctor"]
roles_list += ["Villager"] * (n - len(roles_list))
random.shuffle(roles_list)
self.roles = {player.id: role for player, role in zip(self.players, roles_list)}
def get_players_by_role(self, role):
return [p for p in self.players if self.roles.get(p.id) == role]
def reset_votes(self):
self.votes = {}
self.vote_targets = []
def vote(self, voter, target):
self.votes[voter.id] = target.id
def tally_votes(self):
if not self.votes:
return None
count = Counter(self.votes.values())
most_common = count.most_common(1)
if most_common:
return most_common[0][0] # user_id of voted out
return None
class Games(commands.Cog):
def __init__(self, client):
self.client = client
self.active_games = {} # channel_id: WerewolvesGame
@commands.command(name="joinwerewolves", hidden=True)
async def join_werewolves(self, ctx):
game = self.active_games.get(ctx.channel.id)
if not game:
game = WerewolvesGame(ctx.channel)
self.active_games[ctx.channel.id] = game
if game.started:
await ctx.reply("Game already started!")
return
game.add_player(ctx.author)
await ctx.reply(f"{ctx.author.display_name} joined the game!")
@commands.command(name="startwerewolves", hidden=True)
async def start_werewolves(self, ctx):
game = self.active_games.get(ctx.channel.id)
if not game or len(game.players) < 2:
await ctx.reply("Need at least 6 players to start!")
return
if game.started:
await ctx.reply("Game already started!")
return
game.started = True
game.assign_roles()
# Create threads for roles
await self.create_role_threads(game)
# Announce roles in threads (description only once per thread)
# Werewolf thread: mention all werewolves, send description once
werewolves = game.get_players_by_role("Werewolf")
if werewolves:
thread = game.role_threads["Werewolf"]
mentions = " ".join([p.mention for p in werewolves])
desc = ROLE_DESCRIPTIONS["Werewolf"]
await thread.send(f"{mentions}\nYou are **Werewolves**!\n\n{desc}")
# Seer thread
seer = game.get_players_by_role("Seer")
if seer:
thread = game.role_threads["Seer"]
desc = ROLE_DESCRIPTIONS["Seer"]
await thread.send(f"{seer[0].mention}\nYou are the **Seer**!\n\n{desc}")
# Doctor thread
doctor = game.get_players_by_role("Doctor")
if doctor:
thread = game.role_threads["Doctor"]
desc = ROLE_DESCRIPTIONS["Doctor"]
await thread.send(f"{doctor[0].mention}\nYou are the **Doctor**!\n\n{desc}")
await ctx.send(
"Game started! Roles have been assigned in private threads.\nThe game cycle will begin in 30 seconds..."
)
# Start the game cycle after 30 seconds
await asyncio.sleep(30)
await self.start_cycle(ctx)
async def create_role_threads(self, game: WerewolvesGame):
# Werewolves share a thread, others get solo threads
channel = game.channel
werewolves = game.get_players_by_role("Werewolf")
seer = game.get_players_by_role("Seer")
doctor = game.get_players_by_role("Doctor")
# Create werewolf group thread
if werewolves:
thread = await channel.create_thread(
name="Werewolves Actions",
type=discord.ChannelType.private_thread,
auto_archive_duration=60,
reason="Werewolves game: Werewolves thread",
)
for member in werewolves:
await thread.add_user(member)
game.role_threads["Werewolf"] = thread
# Create seer thread
if seer:
thread = await channel.create_thread(
name="Seer Actions",
type=discord.ChannelType.private_thread,
auto_archive_duration=60,
reason="Werewolves game: Seer thread",
)
await thread.add_user(seer[0])
game.role_threads["Seer"] = thread
# Create doctor thread
if doctor:
thread = await channel.create_thread(
name="Doctor Actions",
type=discord.ChannelType.private_thread,
auto_archive_duration=60,
reason="Werewolves game: Doctor thread",
)
await thread.add_user(doctor[0])
game.role_threads["Doctor"] = thread
@commands.command(name="playwerewolves")
@commands.guild_only()
async def play_werewolves(self, ctx):
"""Create a private game room for Werewolves and start the game setup."""
guild = ctx.guild
overwrites = {
guild.default_role: discord.PermissionOverwrite(read_messages=False),
ctx.author: discord.PermissionOverwrite(
read_messages=True, send_messages=True
),
}
category = ctx.channel.category
channel_name = f"werewolves-room-{ctx.author.display_name}".replace(
" ", "-"
).lower()
channel = await guild.create_text_channel(
name=channel_name,
overwrites=overwrites,
category=category,
reason="Private Werewolves game room",
)
await channel.send(
f"{ctx.author.mention} Your private **Werewolves** game room has been created!\n"
f"Use `py addwerewolves <username>` in this channel to add others.\n"
f"Use `py joinwerewolves` in this channel to join the game.\n"
f"Once enough players have joined, use `py startwerewolves` to start the game."
)
# Optionally, auto-join the creator to the game
game = WerewolvesGame(channel)
game.add_player(ctx.author)
self.active_games[channel.id] = game
@commands.command(name="addwerewolves", hidden=True)
@commands.guild_only()
async def add_werewolves(
self,
ctx,
member: discord.Member | None = None,
*,
identifier: str | None = None,
):
"""Add a user to the current Werewolves game room by username (case-insensitive, not mention)."""
game = self.active_games.get(ctx.channel.id)
if not game:
await ctx.reply("This is not a Werewolves game room.")
return
# Only allow the creator (first player) to add others
if ctx.author != game.players[0]:
await ctx.reply("Only the game creator can add players to the room.")
return
# Find member by username (case-insensitive)
if member is None and identifier:
try:
member = ctx.guild.get_member(int(identifier))
except ValueError:
member = discord.utils.find(
lambda m: m.name.lower() == identifier.lower()
or m.display_name.lower() == identifier.lower(),
ctx.guild.members,
)
if not member:
await ctx.reply(f"User '{member}' not found in this server.")
return
await ctx.channel.set_permissions(
member,
read_messages=True,
send_messages=True,
)
await ctx.send(
f"{member.mention} has been added to the game room! They can now join the game with `py joinwerewolves`."
)
@commands.command(name="startcycle", hidden=True)
async def start_cycle(self, ctx):
"""Start the Werewolves game cycle (night/day loop)."""
game = self.active_games.get(ctx.channel.id)
if not game or not game.started:
await ctx.send("No active game to start the cycle.")
return
await ctx.send("The game cycle is starting!")
game.phase = "night"
game.alive = set(game.players)
game.reset_votes()
while True:
# NIGHT PHASE
await ctx.send(
"🌙 **Night falls!** Werewolves, Seer, and Doctor, check your threads."
)
await asyncio.sleep(10) # Replace with your night action logic and timing
# DAY PHASE
await ctx.send(
"☀️ **Day breaks!** Discuss and vote to eliminate a player. Use `py vote <username>`."
)
game.reset_votes()
await self.day_voting(ctx, game)
voted_out_id = game.tally_votes()
if voted_out_id:
voted_out = discord.utils.get(ctx.guild.members, id=voted_out_id)
if voted_out in game.alive:
game.alive.remove(voted_out)
await ctx.send(f"{voted_out.mention} has been eliminated!")
else:
await ctx.send("No one was eliminated today.")
# Check win condition (example: only werewolves or villagers left)
werewolves = [p for p in game.alive if game.roles.get(p.id) == "Werewolf"]
villagers = [p for p in game.alive if game.roles.get(p.id) != "Werewolf"]
if not werewolves:
await ctx.send("Villagers win! 🎉")
break
if len(werewolves) >= len(villagers):
await ctx.send("Werewolves win! 🐺")
break
await asyncio.sleep(5) # Short pause before next night
@commands.command(name="vote", hidden=True)
async def vote(
self,
ctx,
member: discord.Member | None = None,
*,
identifier: str | None = None,
):
"""Vote to eliminate a player during the day phase."""
game = self.active_games.get(ctx.channel.id)
if not game or ctx.author not in game.alive:
await ctx.reply("You are not in the game or not alive.")
return
# Find member by username (case-insensitive)
if member is None and identifier:
try:
member = ctx.guild.get_member(int(identifier))
except ValueError:
member = discord.utils.find(
lambda m: m.name.lower() == identifier.lower()
or m.display_name.lower() == identifier.lower(),
ctx.guild.members,
)
if not member:
await ctx.reply(f"User '{member}' not found in this server.")
return
if not member or member not in game.alive:
await ctx.reply("That player is not alive or not found.")
return
game.vote(ctx.author, member)
await ctx.send(
f"{ctx.author.display_name} voted to eliminate {member.display_name}."
)
async def day_voting(self, ctx, game, timeout=30):
"""Wait for votes during the day phase."""
await ctx.send(f"You have {timeout} seconds to vote.")
await asyncio.sleep(timeout)
async def setup(client):
await client.add_cog(Games(client))
View File
+129
View File
@@ -0,0 +1,129 @@
import discord
import datetime
from discord.ext import commands, tasks
from utils.sql_commands import DatabaseManager
from dotenv import dotenv_values
def check(author):
def inner_check(message):
return message.author == author
return inner_check
class Birthday(commands.Cog):
def __init__(self, client):
self.client = client
self.db = DatabaseManager("")
self.birthday_checks = {}
async def cog_load(self):
self.check_birthdays.start()
async def cog_unload(self):
self.check_birthdays.cancel()
@tasks.loop(seconds=60*60*24) # daily
async def check_birthdays(self):
today = datetime.date.today()
for guild in self.client.guilds:
guild_id = guild.id
for member in guild.members:
user_id = member.id
user_data = self.db.fetch_one("SELECT * FROM users WHERE ID = %s", (user_id,))
if user_data is None or user_data.get("birthday") is None:
continue
birthday = datetime.datetime.strptime(user_data.get("birthday"), "%Y-%m-%d").date()
if birthday.month == today.month and birthday.day == today.day:
# send birthday message
try:
channel = guild.text_channels[0]
await channel.send(f"Happy birthday, {member.mention}! 🎉")
except discord.Forbidden:
continue
except discord.HTTPException:
continue
# give birthday reward
reward = self.db.fetch_one("SELECT * FROM rewards WHERE type = 'birthday'")
if reward is not None:
try:
await self.client.get_cog("Economy").add_points(user_id, guild_id, reward.get("amount"), "birthday reward")
except Exception as e:
print(f"Error giving birthday reward: {e}")
# give birthday star role
role = discord.utils.get(guild.roles, name="Birthday Star")
if role is not None:
try:
await member.add_roles(role)
except discord.Forbidden:
continue
except discord.HTTPException:
continue
# log birthday reward
try:
self.db.execute_query("INSERT INTO logs (guild_id, user_id, type, message) VALUES (%s, %s, 'birthday_reward', 'claimed birthday reward')", (guild_id, user_id))
except Exception as e:
print(f"Error logging birthday reward: {e}")
@check_birthdays.before_loop
async def before_check_birthdays(self):
await self.client.wait_until_ready()
@commands.command(name="setbirthday", aliases=["sb"])
async def setbirthday(self, ctx, month: int, day: int):
if month < 1 or month > 12 or day < 1 or day > 31:
return await ctx.send("Invalid date")
user_id = ctx.author.id
user_data = self.db.fetch_one("SELECT * FROM users WHERE ID = %s", (user_id,))
if user_data is not None and user_data.get("birthday") is not None:
return await ctx.send("You've already set your birthday")
self.db.execute_query("UPDATE users SET birthday = %s WHERE ID = %s", (f"{datetime.date.today().year}-{month}-{day}", user_id))
await ctx.send("Your birthday has been set")
@commands.command(name="claimbirthday", aliases=["cb"])
async def claimbirthday(self, ctx):
user_id = ctx.author.id
user_data = self.db.fetch_one("SELECT * FROM users WHERE ID = %s", (user_id,))
if user_data is None or user_data.get("birthday") is None:
return await ctx.send("You haven't set your birthday")
today = datetime.date.today()
birthday = datetime.datetime.strptime(user_data.get("birthday"), "%Y-%m-%d").date()
if birthday.month != today.month or birthday.day != today.day:
return await ctx.send("It's not your birthday")
reward = self.db.fetch_one("SELECT * FROM rewards WHERE type = 'birthday'")
if reward is None:
return await ctx.send("No birthday reward set")
await self.client.get_cog("Economy").add_points(user_id, ctx.guild.id, reward.get("amount"), "birthday reward")
await ctx.send("You've claimed your birthday reward")
@commands.command(name="listbirthdays", aliases=["lb"])
async def listbirthdays(self, ctx):
today = datetime.date.today()
birthdays = []
for guild in self.client.guilds:
for member in guild.members:
user_id = member.id
user_data = self.db.fetch_one("SELECT * FROM users WHERE ID = %s", (user_id,))
if user_data is None or user_data.get("birthday") is None:
continue
birthday = datetime.datetime.strptime(user_data.get("birthday"), "%Y-%m-%d").date()
if birthday.month == today.month and birthday.day == today.day:
birthdays.append(member.mention)
if not birthdays:
await ctx.send("No birthdays today")
else:
await ctx.send(f"Happy birthday to {', '.join(birthdays)}! 🎉")
+174
View File
@@ -0,0 +1,174 @@
# blush cry dance lewd pout shrug sleepy smile smug thumbsup wag thinking triggered teehee deredere thonking scoff happy thumbs grin
import discord
from discord.ext import commands
from utils import sql_commands as mydb
from random import choice
class Emotes(commands.Cog):
def __init__(self, client):
self.client = client
self.emotes = {
"blush": ["https://media.giphy.com/media/3o6Zt6ML6BklcajjsA/giphy.gif"],
"cry": ["https://media.giphy.com/media/ROF8OQvDmxytW/giphy.gif"],
"dance": ["https://media.giphy.com/media/l0MYt5jPR6QX5pnqM/giphy.gif"],
# ...add more emotes...
}
self.emote_packs = {
"happy": ["smile", "grin", "thumbsup"],
"sleepy": ["sleepy", "yawn"],
# ...add more packs...
}
self.cooldowns = {} # {user_id: {emote: timestamp}}
self.emote_usage = {} # {user_id: {emote: count}}
self.unlocked_emotes = {} # {user_id: set(emote_names)}
self.pending_emotes = [] # [(user_id, emote_name, url)]
# --- Emote Command for Each Emote ---
@commands.command(name="emote")
async def emote(self, ctx, emote_name: str, member: discord.Member = None):
"""Send an emote GIF, optionally mentioning a user."""
emote = emote_name.lower()
# Economy/level check
if emote not in self.emotes and emote not in self.get_custom_emotes():
await ctx.send("Unknown emote.")
return
if not self.has_unlocked(ctx.author.id, emote):
await ctx.send("You haven't unlocked this emote yet!")
return
# Cooldown check (10s per emote per user)
import time
now = time.time()
user_cooldowns = self.cooldowns.setdefault(ctx.author.id, {})
if emote in user_cooldowns and now - user_cooldowns[emote] < 10:
await ctx.send("You're using that emote too quickly!")
return
user_cooldowns[emote] = now
# Usage tracking
user_usage = self.emote_usage.setdefault(ctx.author.id, {})
user_usage[emote] = user_usage.get(emote, 0) + 1
url = choice(self.emotes.get(emote, self.get_custom_emotes().get(emote, [""])))
mention = member.mention if member else ""
await ctx.send(
f"{ctx.author.mention} {mention}", embed=discord.Embed().set_image(url=url)
)
# --- Individual Emote Commands (e.g., !blush, !cry, !dance) ---
# Dynamically add a command for each emote
def __init_subclass__(cls):
def make_emote_cmd(emote):
async def _cmd(self, ctx, member: discord.Member = None):
await self.emote(ctx, emote, member)
return _cmd
for emote in ["blush", "cry", "dance"]: # Add all your emote names here
setattr(cls, emote, commands.command(name=emote)(make_emote_cmd(emote)))
# --- Emote Combos ---
@commands.command(name="emotecombo")
async def emote_combo(self, ctx, *emotes):
"""Send multiple emotes in one message."""
urls = []
for emote in emotes:
if self.has_unlocked(ctx.author.id, emote) and (
emote in self.emotes or emote in self.get_custom_emotes()
):
urls.append(
choice(
self.emotes.get(
emote, self.get_custom_emotes().get(emote, [""])
)
)
)
if not urls:
await ctx.send("No valid emotes found.")
return
for url in urls:
embed = discord.Embed().set_image(url=url)
await ctx.send(embed=embed)
# --- Emote Packs ---
@commands.command(name="emotepack")
async def emote_pack(self, ctx, pack_name: str):
"""Send all emotes from a pack."""
pack = self.emote_packs.get(pack_name.lower())
if not pack:
await ctx.send("Unknown emote pack.")
return
for emote in pack:
if self.has_unlocked(ctx.author.id, emote) and (
emote in self.emotes or emote in self.get_custom_emotes()
):
url = choice(
self.emotes.get(emote, self.get_custom_emotes().get(emote, [""]))
)
await ctx.send(embed=discord.Embed().set_image(url=url))
# --- Emote Leaderboard ---
@commands.command(name="emoteleaderboard")
async def emote_leaderboard(self, ctx):
"""Show top emote users."""
leaderboard = sorted(
((uid, sum(uses.values())) for uid, uses in self.emote_usage.items()),
key=lambda x: x[1],
reverse=True,
)[:10]
desc = ""
for i, (uid, count) in enumerate(leaderboard, 1):
user = self.client.get_user(uid)
desc += f"{i}. {user.mention if user else uid}: {count} emotes\n"
await ctx.send(
embed=discord.Embed(
title="Emote Leaderboard", description=desc or "No data."
)
)
# --- Emote Reactions ---
@commands.command(name="react")
async def react(self, ctx, emote_name: str, message_id: int):
"""React to a message with an emote (as emoji if available)."""
emote = emote_name.lower()
try:
msg = await ctx.channel.fetch_message(message_id)
# If you have custom emoji, use them; else, fallback to unicode or skip
await msg.add_reaction("😄") # Replace with actual emoji logic
await ctx.send("Reacted!")
except Exception:
await ctx.send("Could not react to that message.")
# --- Custom Emotes Submission ---
@commands.command(name="submit_emote")
async def submit_emote(self, ctx, emote_name: str, url: str):
"""Submit a custom emote for approval."""
self.pending_emotes.append((ctx.author.id, emote_name, url))
await ctx.send(
f"Emote `{emote_name}` submitted for approval! (Admins: review pending list)"
)
def get_custom_emotes(self):
# In production, load from DB or approved list
return {}
# --- Unlock Emotes with Level/Economy ---
@commands.command(name="unlock_emote")
async def unlock_emote(self, ctx, emote_name: str):
"""Unlock an emote using currency or level."""
# Example: check user balance/level, deduct cost, unlock emote
# Replace with your actual economy/level logic
user_id = ctx.author.id
unlocked = self.unlocked_emotes.setdefault(user_id, set())
unlocked.add(emote_name)
await ctx.send(f"Emote `{emote_name}` unlocked!")
def has_unlocked(self, user_id, emote_name):
# Always unlocked for now, add logic for locked emotes
return True
async def setup(client):
await client.add_cog(Emotes(client))
+281
View File
@@ -0,0 +1,281 @@
import discord
from discord.ext import commands
from random import choice
import requests
from dotenv import dotenv_values
# Initialize responses for eightball command
eightball_responses = [
"Yes, definitely.",
"No, not at all.",
"Ask again later.",
"Outlook not so good.",
"Most likely.",
"Don't count on it.",
"Signs point to yes.",
"Very doubtful.",
"Without a doubt.",
"My sources say no.",
"Outlook is good.",
"It is certain.",
"Cannot predict now.",
"Better not tell you now.",
"Yes, in due time.",
"No, never.",
"Concentrate and ask again.",
"Very likely.",
"My reply is no.",
"Outlook not good.",
"Yes, for sure.",
"Don't hold your breath.",
"As I see it, yes.",
"It is decidedly so.",
"My sources say yes.",
"Definitely not.",
"Yes, definitely.",
"Very unlikely.",
"Ask again another time.",
"Cannot foretell now.",
"The outlook is bleak.",
"Not in a million years.",
"It is certain.",
"Outlook not good.",
"Signs point to yes.",
"Without a doubt.",
"My sources say no.",
"Yes, in due time.",
"Definitely not.",
"Ask again later.",
"Better not tell you now.",
"Very likely.",
"Yes, for sure.",
"No, not at all.",
"Don't count on it.",
"As I see it, yes.",
"My reply is no.",
"Concentrate and ask again.",
"Outlook is good.",
"It is decidedly so.",
"My sources say yes.",
"Very unlikely.",
"Cannot predict now.",
"Yes, definitely.",
"Not in a million years.",
"Ask again another time.",
"Without a doubt.",
"Signs point to yes.",
"The outlook is bleak.",
"Definitely not.",
"Outlook not good.",
"Yes, for sure.",
"Better not tell you now.",
"My sources say no.",
"It is certain.",
"Very likely.",
"Don't count on it.",
"Concentrate and ask again.",
"No, not at all.",
"Ask again later.",
"Yes, definitely.",
"Without a doubt.",
"Outlook is good.",
"My sources say yes.",
"Not in a million years.",
"Very unlikely.",
"Definitely not.",
"Better not tell you now.",
"As I see it, yes.",
"The outlook is bleak.",
"Concentrate and ask again.",
"Yes, for sure.",
"Signs point to yes.",
"My reply is no.",
"Cannot predict now.",
"Ask again another time.",
"No, not at all.",
"Don't count on it.",
"Outlook not so good.",
"It is certain.",
"Without a doubt.",
"Very likely.",
"Yes, definitely.",
"My sources say no.",
"Better not tell you now.",
"Definitely not.",
"Ask again later.",
"Concentrate and ask again.",
"The outlook is bleak.",
"Not in a million years.",
"Yes, for sure.",
"As I see it, yes.",
"Don't count on it.",
"Very unlikely.",
"My reply is no.",
"Ask again another time.",
"Signs point to yes.",
"Outlook is good.",
"Without a doubt.",
"It is certain.",
"Yes, definitely.",
"Definitely not.",
"Better not tell you now.",
"Concentrate and ask again.",
"No, not at all.",
"My sources say yes.",
"The outlook is bleak.",
"Very likely.",
"Ask again later.",
"Don't count on it.",
"As I see it, yes.",
"Yes, for sure.",
"Not in a million years.",
"Cannot predict now.",
"Outlook not good.",
"Without a doubt.",
"My reply is no.",
"Yes, definitely.",
"Better not tell you now.",
"Concentrate and ask again.",
"Definitely not.",
"Ask again another time.",
"Signs point to yes.",
"It is certain.",
"Very unlikely.",
"Outlook is good.",
"No, not at all.",
"The outlook is bleak.",
"As I see it, yes.",
"My sources say no.",
"Without a doubt.",
"Better not tell you now.",
"Concentrate and ask again.",
"Yes, for sure.",
"Not in a million years.",
"Ask again later.",
"Definitely not.",
"My reply is no.",
"Outlook not so good.",
"Very likely.",
"It is certain.",
"Signs point to yes.",
"Don't count on it.",
"Yes, definitely.",
"Better not tell you now.",
"Concentrate and ask again.",
"Without a doubt.",
"Ask again another time.",
"Definitely not.",
"Outlook is good.",
"No, not at all.",
"The outlook is bleak.",
"As I see it, yes.",
"Very unlikely.",
"My sources say yes.",
"Yes, for sure.",
"Cannot predict now.",
"Better not tell you now.",
"Concentrate and ask again.",
"It is certain.",
"Ask again later.",
"Signs point to yes.",
"Outlook not good.",
"Without a doubt.",
"Definitely not.",
"Don't count on it.",
"My reply is no.",
"The outlook is bleak.",
"Very likely.",
"Yes, for sure.",
"As I see it, yes.",
"No, not at all.",
"Concentrate and ask again.",
"Better not tell you now.",
"Ask again another time.",
"My sources say yes.",
"It is certain.",
"Outlook is good.",
"Yes, definitely.",
"Without a doubt.",
"Definitely not.",
"Very unlikely.",
"The outlook is bleak.",
"Concentrate and ask again.",
"Signs point to yes.",
"No, not at all.",
"Ask again later.",
"Better not tell you now.",
"As I see it, yes.",
"My reply is no.",
"Yes, for sure.",
]
class Fun(commands.Cog):
def __init__(self, client):
self.client = client
# Load environment variables for API keys
config = dotenv_values(".env")
self.tenor_api_key = config.get("TENORAPI")
@commands.command(
name="eightball",
aliases=["eb", "8ball", "8b"],
brief="Ask a question and I shall answer.",
description="I will predict the answer to any and all of your questions.",
)
async def eight_ball(self, ctx, *, question: str):
"""Respond with a random answer to a yes/no question."""
if question:
response = choice(eightball_responses)
await ctx.send(f"Answer: {response}")
else:
await ctx.send("Please ask a question for the 8ball to answer.")
@commands.command()
async def randomgif(self, ctx, *query):
"""Fetch and display a random GIF based on a search query."""
if not self.tenor_api_key:
await ctx.send("Tenor API key is not configured.")
return
search_query = "%20".join(query) if query else "funny"
api_url = f"https://tenor.googleapis.com/v2/search?q={search_query}&key={self.tenor_api_key}&limit=10"
try:
response = requests.get(api_url)
response.raise_for_status()
gif_data = response.json()
if gif_data.get("results"):
gif_url = choice(gif_data["results"])["media_formats"]["gif"]["url"]
embed = discord.Embed(title="Here's a random GIF!")
embed.set_image(url=gif_url)
await ctx.send(embed=embed)
else:
await ctx.send("No GIFs found for your query.")
except requests.RequestException as error:
await ctx.send(f"Error fetching Tenor GIF: {error}")
@commands.command()
async def meme(self, ctx):
"""Fetch and display a random meme."""
api_url = "https://meme-api.com/memes/random"
try:
response = requests.get(api_url)
response.raise_for_status()
meme_data = response.json()
meme_url = meme_data.get("url")
if meme_url:
await ctx.send(meme_url)
else:
await ctx.send("Couldn't fetch a meme at the moment.")
except requests.RequestException:
await ctx.send("Error fetching meme.")
async def setup(client):
await client.add_cog(Fun(client))
+120
View File
@@ -0,0 +1,120 @@
import discord
from discord.ext import commands
from utils import sql_commands as mydb
from random import choice
slap = ["https://media1.tenor.com/m/tfu-SnLkaP4AAAAC/alarm-clock.gif", "https://media1.tenor.com/m/yCC2nXLRPBgAAAAC/utku-tokat.gif", "https://media.tenor.com/fZQYHVUDfckAAAAi/slap.gif", "https://media.tenor.com/TVPYqh_E1JYAAAAi/peach-goma-peach-and-goma.gif"]
sad = ["https://media1.tenor.com/m/a-ooSHLa2lsAAAAC/im-sad.gif","https://media1.tenor.com/m/M_V1fbsCEbAAAAAd/sad-om-nom.gif", "https://media1.tenor.com/m/bwtBRKlfEzgAAAAC/sad-crying.gif", "https://media1.tenor.com/m/5t-iIxnzE8MAAAAC/sad-bear-cry.gif", "https://media1.tenor.com/m/CKez5CfynccAAAAd/looking-out-the-window-om-nom.gif"]
hug = ["https://media1.tenor.com/m/2qjVr7KUQKgAAAAC/hug.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/hug.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/hug-cute.gif", "https://media1.tenor.com/m/KkO5IjxVQKMAAAAC/hug.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/hug.gif", "https://media1.tenor.com/m/4yPv5fJiHf4AAAAC/hug.gif", "https://media1.tenor.com/m/2qjVr7KUQKgAAAAC/hug.gif", ]
kiss = ["https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/kiss.gif", "https://media1.tenor.com/m/KkO5IjxVQKMAAAAC/kiss.gif", "https://media1.tenor.com/m/4yPv5fJiHf4AAAAC/kiss.gif", "https://media1.tenor.com/m/2qjVr7KUQKgAAAAC/kiss.gif", ]
pat = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/head-pat.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/head-pat.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/head-pat.gif", ]
wave = ["https://media1.tenor.com/m/a-ooSHLa2lsAAAAC/bye.gif", "https://media1.tenor.com/m/a-ooSHLa2lsAAAAC/bye.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/wave.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/wave.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/wave.gif", ]
poke = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/poke.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/poke.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/poke.gif", ]
dance = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/dance.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/dance.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/dance.gif", ]
cry = ["https://media1.tenor.com/m/2qjVr7KUQKgAAAAC/cry.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/cry.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/cry.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/cry.gif", ]
laugh = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/laugh.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/laugh.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/laugh.gif", ]
highfive = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/highfive.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/highfive.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/highfive.gif", ]
punch = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/punch.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/punch.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/punch.gif", ]
blush = ["https://media1.tenor.com/m/EiIiIiIiIiIiIiIi.gif", "https://media1.tenor.com/m/7yTtTtTtTtTtTtTt.gif", "https://media1.tenor.com/m/8v4XfJiHf4AAAAAC/blush.gif", "https://media1.tenor.com/m/9Vj8kHt3n4wAAAAC/blush.gif", "https://media1.tenor.com/m/0qJj8kVb8nQAAAAC/blush.gif", ]
class Interactions(commands.Cog):
def __init__(self, client):
self.client = client
@commands.command(name="slap")
async def _slap_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(slap))
embed.add_field(name=f"{ctx.author.name} slaps {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="sad")
async def _sad_gif(self, ctx, *reason):
embed = discord.Embed()
embed.set_image(url=choice(sad))
embed.add_field(name=f"{ctx.author.name} is Sad", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="hug")
async def _hug_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(hug))
embed.add_field(name=f"{ctx.author.name} hugs {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="kiss")
async def _kiss_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(kiss))
embed.add_field(name=f"{ctx.author.name} kisses {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="pat")
async def _pat_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(pat))
embed.add_field(name=f"{ctx.author.name} pats {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="wave")
async def _wave_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(wave))
embed.add_field(name=f"{ctx.author.name} waves at {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="poke")
async def _poke_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(poke))
embed.add_field(name=f"{ctx.author.name} pokes {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="dance")
async def _dance_gif(self, ctx, *reason):
embed = discord.Embed()
embed.set_image(url=choice(dance))
embed.add_field(name=f"{ctx.author.name} dances", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="cry")
async def _cry_gif(self, ctx, *reason):
embed = discord.Embed()
embed.set_image(url=choice(cry))
embed.add_field(name=f"{ctx.author.name} cries", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="laugh")
async def _laugh_gif(self, ctx, *reason):
embed = discord.Embed()
embed.set_image(url=choice(laugh))
embed.add_field(name=f"{ctx.author.name} laughs", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="highfive")
async def _highfive_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(highfive))
embed.add_field(name=f"{ctx.author.name} highfives {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="punch")
async def _punch_gif(self, ctx, member:discord.Member, *reason):
embed = discord.Embed()
embed.set_image(url=choice(punch))
embed.add_field(name=f"{ctx.author.name} punches {member.name}", value=" ".join(reason))
await ctx.reply(embed=embed)
@commands.command(name="blush")
async def _blush_gif(self, ctx, *reason):
embed = discord.Embed()
embed.set_image(url=choice(blush))
embed.add_field(name=f"{ctx.author.name} blushes", value=" ".join(reason) or "No reason provided")
await ctx.reply(embed=embed)
async def setup(client):
await client.add_cog(Interactions(client))
+509
View File
@@ -0,0 +1,509 @@
import discord
from discord.ext import commands, tasks
from utils.sql_commands import DatabaseManager
from utils.bank_functions import bank_data, update_money
from random import choice
from datetime import datetime, timedelta
import logging
TICKET_TYPES = {
"standard": {"price": 500, "weight": 1},
"premium": {"price": 2000, "weight": 5},
}
LOTTERY_INTERVAL_HOURS = 24 # Draw every 24 hours
MAX_TICKETS_PER_USER = 10
ROLLOVER_BONUS = 500
class Lottery(commands.Cog):
def __init__(self, client):
self.client = client
self.db = DatabaseManager()
self.lottery_draw.start()
def cog_unload(self):
self.lottery_draw.cancel()
def get_jackpot(self) -> int:
try:
result = self.db.fetch_one("SELECT jackpot FROM lottery_state WHERE id = 1")
return int(result["jackpot"]) if result else 0
except Exception as e:
logging.error(f"Error fetching jackpot: {e}")
return 0
def set_jackpot(self, amount: int) -> None:
try:
self.db.execute_query(
"UPDATE lottery_state SET jackpot = %s WHERE id = 1", (amount,)
)
except Exception as e:
logging.error(f"Error setting jackpot: {e}")
def add_to_jackpot(self, amount: int) -> None:
try:
self.db.execute_query(
"UPDATE lottery_state SET jackpot = jackpot + %s WHERE id = 1",
(amount,),
)
except Exception as e:
logging.error(f"Error adding to jackpot: {e}")
def get_last_draw_time(self) -> datetime:
try:
result = self.db.fetch_one(
"SELECT last_draw FROM lottery_draw_time WHERE id = 1"
)
last_draw = result["last_draw"] if result and result["last_draw"] else None
if last_draw is None:
# Set to now if missing and update DB
now = datetime.utcnow()
self.set_last_draw_time(now)
return now
if isinstance(last_draw, str):
try:
last_draw = datetime.fromisoformat(last_draw)
except Exception:
last_draw = datetime.strptime(last_draw, "%Y-%m-%d %H:%M:%S")
return last_draw
except Exception as e:
logging.error(f"Error fetching last draw time: {e}")
now = datetime.utcnow()
self.set_last_draw_time(now)
return now
def set_last_draw_time(self, draw_time: datetime) -> None:
try:
self.db.execute_query(
"UPDATE lottery_draw_time SET last_draw = %s WHERE id = 1", (draw_time,)
)
except Exception as e:
logging.error(f"Error setting last draw time: {e}")
def notify_lottery_result(self, user_id: int):
try:
result = self.db.fetch_one(
"SELECT * FROM lottery_results WHERE WINNER_ID = %s AND CLAIMED = 0 ORDER BY DRAW_TIME DESC LIMIT 1",
(user_id,),
)
if not result:
return None
# Remove the result after notifying
self.db.execute_query(
"DELETE FROM lottery_results WHERE ID = %s", (result["ID"],)
)
return (True, result["AMOUNT"])
except Exception as e:
logging.error(f"Error notifying lottery result: {e}")
return None
@commands.command(
name="buyticket",
help=f"Buy one or more lottery tickets for yourself or a group.",
)
async def buy_ticket(
self,
ctx: commands.Context,
ticket_type: str = "standard",
amount: int = 1,
group_id: str | None = None,
member: discord.Member | None = None,
):
ticket_type = ticket_type.lower()
if ticket_type not in TICKET_TYPES:
await ctx.reply(
f"Invalid ticket type. Choose from: {', '.join(TICKET_TYPES)}"
)
return
if amount < 1 or amount > MAX_TICKETS_PER_USER:
await ctx.reply(
f"You can only buy between 1 and {MAX_TICKETS_PER_USER} tickets at once."
)
return
user = member or ctx.author
price = TICKET_TYPES[ticket_type]["price"] * amount
try:
# Notify about last draw if relevant (only if user is the winner)
notify = self.notify_lottery_result(user.id)
if notify:
await ctx.reply(
f"🎉 You won the last lottery! Jackpot: {notify[1]:,} coins.",
mention_author=False,
)
user_data = await bank_data(user)
wallet = int(user_data.get("WALLET", 0))
if wallet < price:
await ctx.reply(
f"You need at least {price} coins to buy {amount} {ticket_type} ticket(s).",
mention_author=False,
)
return
if group_id:
group_exists = self.db.fetch_one(
"SELECT 1 FROM lottery_groups WHERE group_id = %s", (group_id,)
)
in_group = self.db.fetch_one(
"SELECT 1 FROM lottery_group_members WHERE group_id = %s AND user_id = %s",
(group_id, user.id),
)
if not group_exists or not in_group:
await ctx.reply(
"You must be a member of the group to buy tickets for it."
)
return
user_ticket_count = self.db.fetch_one(
"SELECT COUNT(*) as count FROM lottery_tickets WHERE USERID = %s",
(user.id,),
)["count"]
if user_ticket_count + amount > MAX_TICKETS_PER_USER:
await ctx.reply(
f"You can only have {MAX_TICKETS_PER_USER} tickets per draw. You currently have {user_ticket_count}."
)
return
# Deduct ticket price
await update_money(user, wallet=-price)
self.add_to_jackpot(price)
# Store tickets in DB (one row per ticket for higher odds with multiple tickets)
for _ in range(amount):
self.db.execute_query(
"INSERT INTO lottery_tickets (USERID, TIMESTAMP, TICKET_TYPE, group_id) VALUES (%s, %s, %s, %s)",
(user.id, datetime.utcnow(), ticket_type, group_id),
)
jackpot = self.get_jackpot()
await ctx.reply(
f"🎟️ {amount} {ticket_type.capitalize()} ticket(s) bought! Jackpot is now {jackpot:,} coins.",
mention_author=False,
)
except Exception as e:
logging.error(f"Error in buy_ticket: {e}")
await ctx.reply(
"An error occurred while buying your ticket(s).", mention_author=False
)
@commands.command(name="lotterystats", help="Show current lottery stats.")
async def lottery_stats(self, ctx: commands.Context):
try:
# Show last winner and their prize
last_result = self.db.fetch_one(
"SELECT * FROM lottery_results ORDER BY DRAW_TIME DESC LIMIT 1"
)
winner_text = "No draws yet."
if last_result:
winner = self.client.get_user(
last_result["WINNER_ID"]
) or await self.client.fetch_user(last_result["WINNER_ID"])
winner_text = f"Last winner: {winner.mention if winner else 'Unknown'} ({last_result['AMOUNT']:,} coins)"
ticket_count = self.db.fetch_one(
"SELECT COUNT(*) as count FROM lottery_tickets"
)["count"]
jackpot = self.get_jackpot()
# Check if the user has an unclaimed win
unclaimed = self.db.fetch_one(
"SELECT * FROM lottery_results WHERE WINNER_ID = %s AND CLAIMED = 0 ORDER BY DRAW_TIME DESC LIMIT 1",
(ctx.author.id,),
)
winner_note = ""
if unclaimed:
# Mark as claimed and pay out
self.db.execute_query(
"UPDATE lottery_results SET CLAIMED = 1 WHERE ID = %s",
(unclaimed["ID"],),
)
await update_money(ctx.author, wallet=unclaimed["AMOUNT"])
winner_note = f"\n🎉 **You have won {unclaimed['AMOUNT']:,} coins! Your prize has been paid out.**"
await ctx.reply(
f"{winner_text}\n"
f"🎰 There are currently **{ticket_count}** tickets in the pool.\n"
f"💰 Jackpot: **{jackpot:,}** coins.\n"
f"Next draw in: {self.time_until_draw()}"
f"{winner_note}",
mention_author=False,
)
except Exception as e:
logging.error(f"Error in lottery_stats: {e}")
await ctx.reply(
"An error occurred while fetching lottery stats.", mention_author=False
)
def time_until_draw(self) -> str:
now = datetime.utcnow()
last_draw = self.get_last_draw_time()
next_draw = last_draw + timedelta(hours=LOTTERY_INTERVAL_HOURS)
remaining = next_draw - now
if remaining.total_seconds() < 0:
return "Drawing soon!"
hours, remainder = divmod(int(remaining.total_seconds()), 3600)
minutes, seconds = divmod(remainder, 60)
return f"{hours}h {minutes}m {seconds}s"
@tasks.loop(minutes=1)
async def lottery_draw(self):
now = datetime.utcnow()
last_draw = self.get_last_draw_time()
if (now - last_draw).total_seconds() < LOTTERY_INTERVAL_HOURS * 3600:
return # Not time yet
await self._run_lottery_draw()
@commands.command(name="testdraw", help="Manually trigger the lottery draw.")
@commands.is_owner()
async def testdraw(self, ctx: commands.Context):
await ctx.send("Starting lottery draw...")
await self._run_lottery_draw()
async def _run_lottery_draw(self):
try:
await self.client.wait_until_ready()
tickets = self.db.fetch_all(
"SELECT USERID, TICKET_TYPE FROM lottery_tickets"
)
jackpot = self.get_jackpot()
if not tickets or jackpot <= 0:
self.set_jackpot(self.get_jackpot() + ROLLOVER_BONUS)
self.set_last_draw_time(datetime.utcnow())
return
# Build weighted ticket list
weighted_tickets = []
for t in tickets:
luck_row = self.db.fetch_one(
"SELECT LUCK FROM lottery_luck WHERE USERID = %s", (t["USERID"],)
)
luck = luck_row["LUCK"] if luck_row else 0
ticket_type_weight = TICKET_TYPES[t["TICKET_TYPE"]]["weight"]
weight = ticket_type_weight * (1 + luck)
weighted_tickets.extend([t["USERID"]] * weight)
winner_id = choice(weighted_tickets)
# Find group for winning ticket BEFORE deleting tickets
group_id = self.db.fetch_one(
"SELECT group_id FROM lottery_tickets WHERE USERID = %s LIMIT 1",
(winner_id,),
)["group_id"]
self.db.execute_query("DELETE FROM lottery_tickets") # Reset for next round
if group_id:
members = self.db.fetch_all(
"SELECT user_id FROM lottery_group_members WHERE group_id = %s",
(group_id,),
)
member_ids = [m["user_id"] for m in members]
split_prize = (jackpot // 2) // len(member_ids)
for uid in member_ids:
member = self.client.get_user(uid) or await self.client.fetch_user(
uid
)
await update_money(member, wallet=split_prize)
# Store group win in results with WIN_TYPE='group'
self.db.execute_query(
"INSERT INTO lottery_results (WINNER_ID, AMOUNT, DRAW_TIME, CLAIMED, WIN_TYPE) VALUES (%s, %s, %s, 0, %s)",
(group_id, jackpot // 2, datetime.utcnow(), "group"),
)
else:
# Store solo win in results with WIN_TYPE='user'
self.db.execute_query(
"INSERT INTO lottery_results (WINNER_ID, AMOUNT, DRAW_TIME, CLAIMED, WIN_TYPE) VALUES (%s, %s, %s, 0, %s)",
(winner_id, jackpot // 2, datetime.utcnow(), "user"),
)
# Carry over half the jackpot (rounded down)
carryover = jackpot // 2
self.set_jackpot(carryover)
self.set_last_draw_time(datetime.utcnow())
# Reset winner's luck, increment others'
self.db.execute_query(
"UPDATE lottery_luck SET LUCK = 0 WHERE USERID = %s", (winner_id,)
)
self.db.execute_query(
"UPDATE lottery_luck SET LUCK = LUCK + 1 WHERE USERID != %s",
(winner_id,),
)
except Exception as e:
logging.error(f"Error in _run_lottery_draw: {e}")
@lottery_draw.before_loop
async def before_lottery_draw(self):
await self.client.wait_until_ready()
@commands.command(name="lotteryhistory")
async def lottery_history(self, ctx):
results = self.db.fetch_all(
"SELECT * FROM lottery_results ORDER BY DRAW_TIME DESC LIMIT 10"
)
if not results:
await ctx.reply("No lottery draws yet.")
return
lines = []
for res in results:
if res.get("WIN_TYPE") == "group":
lines.append(
f"{res['DRAW_TIME'].strftime('%Y-%m-%d')}: Group `{res['WINNER_ID']}` won {res['AMOUNT']:,} coins"
)
else:
winner = self.client.get_user(
res["WINNER_ID"]
) or await self.client.fetch_user(res["WINNER_ID"])
lines.append(
f"{res['DRAW_TIME'].strftime('%Y-%m-%d')}: {winner.mention if winner else 'Unknown'} won {res['AMOUNT']:,} coins"
)
await ctx.reply("\n".join(lines))
@commands.command(name="lotteryleaderboard")
async def lottery_leaderboard(self, ctx):
winners = self.db.fetch_all(
"SELECT WINNER_ID, COUNT(*) as wins, SUM(AMOUNT) as total FROM lottery_results GROUP BY WINNER_ID ORDER BY wins DESC LIMIT 10"
)
if not winners:
await ctx.reply("No winners yet.")
return
lines = []
for w in winners:
user = self.client.get_user(w["WINNER_ID"]) or await self.client.fetch_user(
w["WINNER_ID"]
)
lines.append(
f"{user.mention if user else 'Unknown'}: {w['wins']} wins, {w['total']:,} coins"
)
await ctx.reply("\n".join(lines))
@commands.command(name="initluck")
@commands.is_owner()
async def init_luck(self, ctx):
"""Initialize or reset the luck of a user."""
user = ctx.author
self.db.execute_query(
"INSERT IGNORE INTO lottery_luck (USERID, LUCK) VALUES (%s, 0)", (user.id,)
)
await ctx.reply(f"Your luck has been initialized/reset.")
@commands.command(name="creategroup")
async def create_group(self, ctx, group_id: str):
exists = self.db.fetch_one(
"SELECT 1 FROM lottery_groups WHERE group_id = %s", (group_id,)
)
if exists:
await ctx.reply("A group with that ID already exists.")
return
self.db.execute_query(
"INSERT INTO lottery_groups (group_id, creator_id) VALUES (%s, %s)",
(group_id, ctx.author.id),
)
self.db.execute_query(
"INSERT INTO lottery_group_members (group_id, user_id) VALUES (%s, %s)",
(group_id, ctx.author.id),
)
await ctx.reply(f"Group `{group_id}` created and you have joined it.")
@commands.command(name="joingroup")
async def join_group(self, ctx, group_id: str):
exists = self.db.fetch_one(
"SELECT 1 FROM lottery_groups WHERE group_id = %s", (group_id,)
)
if not exists:
await ctx.reply("That group does not exist.")
return
already = self.db.fetch_one(
"SELECT 1 FROM lottery_group_members WHERE group_id = %s AND user_id = %s",
(group_id, ctx.author.id),
)
if already:
await ctx.reply("You are already in this group.")
return
self.db.execute_query(
"INSERT INTO lottery_group_members (group_id, user_id) VALUES (%s, %s)",
(group_id, ctx.author.id),
)
await ctx.reply(f"You have joined group `{group_id}`.")
@commands.command(name="leavegroup")
async def leave_group(self, ctx, group_id: str):
self.db.execute_query(
"DELETE FROM lottery_group_members WHERE group_id = %s AND user_id = %s",
(group_id, ctx.author.id),
)
await ctx.reply(f"You have left group `{group_id}`.")
@commands.command(name="deletegroup")
async def delete_group(self, ctx, group_id: str):
# Check if group exists and if user is creator
group = self.db.fetch_one(
"SELECT creator_id FROM lottery_groups WHERE group_id = %s", (group_id,)
)
if not group:
await ctx.reply("That group does not exist.")
return
if group["creator_id"] != ctx.author.id:
await ctx.reply("Only the group creator can delete this group.")
return
# Check if group is empty (no members except possibly the creator)
members = self.db.fetch_all(
"SELECT user_id FROM lottery_group_members WHERE group_id = %s", (group_id,)
)
if len(members) > 1 or (
len(members) == 1 and members[0]["user_id"] != ctx.author.id
):
await ctx.reply(
"You can only delete a group if it is empty (no members except you)."
)
return
# Delete group and membership
self.db.execute_query(
"DELETE FROM lottery_group_members WHERE group_id = %s", (group_id,)
)
self.db.execute_query(
"DELETE FROM lottery_groups WHERE group_id = %s", (group_id,)
)
await ctx.reply(f"Group `{group_id}` has been deleted.")
@commands.command(name="refundtickets")
async def refund_tickets(self, ctx, amount: int = 1):
user = ctx.author
tickets = self.db.fetch_all(
"SELECT * FROM lottery_tickets WHERE USERID = %s", (user.id,)
)
if not tickets:
await ctx.reply("You have no tickets to refund for this draw.")
return
if amount is None:
amount = len(tickets)
if amount < 1 or amount > len(tickets):
await ctx.reply(
f"You can only refund between 1 and {len(tickets)} tickets."
)
return
# Refund only the specified amount
tickets_to_refund = tickets[:amount]
total_refund = 0
ticket_ids = []
for ticket in tickets_to_refund:
price = TICKET_TYPES[ticket["TICKET_TYPE"]]["price"]
refund = int(price * 0.8)
total_refund += refund
ticket_ids.append(ticket["ID"])
# Remove only the refunded tickets
format_strings = ",".join(["%s"] * len(ticket_ids))
self.db.execute_query(
f"DELETE FROM lottery_tickets WHERE ID IN ({format_strings})",
tuple(ticket_ids),
)
await update_money(user, wallet=total_refund)
await ctx.reply(
f"{amount} ticket(s) refunded for {total_refund:,} coins (80% of purchase price)."
)
async def setup(client):
await client.add_cog(Lottery(client))
View File
+54
View File
@@ -0,0 +1,54 @@
import discord
from discord.ext import commands
class Roles(commands.Cog):
def __init__(self, client):
self.client = client
@commands.command(name="giveRole")
@commands.has_permissions(manage_roles=True)
async def _add_role(self, ctx, member: discord.Member, role):
role = discord.utils.get(ctx.guild.roles, name=role)
await member.add_roles(role)
await ctx.reply("role given", delete_after=2)
@commands.command(name="showRoles")
@commands.has_permissions(manage_roles=True)
async def _show_role(self, ctx):
roles = [role for role in ctx.guild.roles][1:]
embed = discord.Embed(
colour=discord.Colour.purple(),
timestamp=ctx.message.created_at,
title=f"Roles",
)
embed.add_field(
name="Roles:", value="\n".join([role.mention for role in roles])
)
await ctx.send(embed=embed)
@commands.command(name="takeRole")
@commands.has_permissions(manage_roles=True)
async def _take_role(self, ctx, member: discord.Member, role):
role = discord.utils.get(ctx.guild.roles, name=role)
await member.remove_roles(role)
await ctx.reply("role taken", delete_after=2)
@commands.command(name="deleteRole")
@commands.has_permissions(manage_roles=True)
async def _delete_role(self, ctx, role_name):
role_object = discord.utils.get(ctx.guild.roles, name=role_name)
await role_object.delete()
@commands.command("addRole")
@commands.has_permissions(
manage_roles=True
) # Check if the user executing the command can manage roles
async def _create_role(self, ctx, name):
guild = ctx.guild
await guild.create_role(name=name)
await ctx.send(f"Role `{name}` has been created")
async def setup(client):
await client.add_cog(Roles(client))
+57
View File
@@ -0,0 +1,57 @@
import discord
import requests
from discord.ext import commands
from discord.ui import Select, View
from random import shuffle
from utils import sql_commands as mydb
from utils.bank_functions import *
class MyView(View):
def __init__(self, right: str, wrong: list):
super().__init__()
self.right = right
options = wrong.copy()
options.append(right)
shuffle(options)
select = Select(
placeholder="Pick an answer:",
min_values=1,
max_values=1,
options=[discord.SelectOption(label=option) for option in options]
)
self.add_item(select)
select.callback = self.select_callback # Set the callback method
async def select_callback(self, interaction: discord.Interaction):
if interaction.data['values'][0] == self.right: # type: ignore
await interaction.response.edit_message(content=f"You are correct!\n{self.right} was the right answer.", view=None)
else:
await interaction.response.edit_message(content=f"Oh no, that's not right!\n{self.right} was the right answer.", view=None)
class Test(commands.Cog):
def __init__(self, client):
self.client = client
@commands.is_owner()
@commands.command(name="quiz")
async def quiz(self, ctx):
response = requests.get("https://opentdb.com/api.php?amount=1&category=18&difficulty=medium&type=multiple").json()["results"][0]
question = response["question"]
view = MyView(response["correct_answer"], response["incorrect_answers"])
await ctx.send(question, view=view)
@commands.is_owner()
@commands.command(name="lottery", aliases=["bet" , "lotto"])
async def lottery(self, ctx, amount:int=None): #type: ignore
if amount == None:
await ctx.send(mydb.select("JACKPOT", "global", True, "ID", "1"))
return
# mydb.select()
async def setup(client):
await client.add_cog(Test(client))
+302
View File
@@ -0,0 +1,302 @@
import discord
from random import shuffle, choice
from discord.ext import commands
import utils.sql_commands as mydb
lottery_list = ["🎁", "🎮", "🎷", "🔫", "📸", "🎃", "🏅"]
lottery_win = {
"🎁": 2,
"🎁🎁": 5,
"🎁🎁🎁": 500,
"🔫🔫🔫": 25,
"📸📸📸": 50,
"🎃🎃🎃": 75,
"🏅🏅🏅": 100,
"🎮🎮🎮": 250,
"🎷🎷🎷": 1000,
}
bj_values = {
"2♦️": 2,
"2♥️": 2,
"2♣️": 2,
"2♠️": 2,
"3♦️": 3,
"3♥️": 3,
"3♣️": 3,
"3♠️": 3,
"4♦️": 4,
"4♥️": 4,
"4♣️": 4,
"4♠️": 4,
"5♦️": 5,
"5♥️": 5,
"5♣️": 5,
"5♠️": 5,
"6♦️": 6,
"6♥️": 6,
"6♣️": 6,
"6♠️": 6,
"7♦️": 7,
"7♥️": 7,
"7♣️": 7,
"7♠️": 7,
"8♦️": 8,
"8♥️": 8,
"8♣️": 8,
"8♠️": 8,
"9♦️": 9,
"9♥️": 9,
"9♣️": 9,
"9♠️": 9,
"10♦️": 10,
"10♥️": 10,
"10♣️": 10,
"10♠️": 10,
"J♦️": 10,
"J♥️": 10,
"J♣️": 10,
"J♠️": 10,
"Q♦️": 10,
"Q♥️": 10,
"Q♣️": 10,
"Q♠️": 10,
"K♦️": 10,
"K♥️": 10,
"K♣️": 10,
"K♠️": 10,
"A♦️": 11,
"A♥️": 11,
"A♣️": 11,
"A♠️": 11,
}
class Deck:
def __init__(self):
self.deck = list(bj_values.keys())
shuffle(self.deck)
async def deal(self):
return self.deck.pop()
class Hand:
def __init__(self, name, bet):
self.cards = []
self.value = 0
self.aces = 0
self.bust = False
self.name = name
self.bet = bet
async def win_bet(self):
pass
async def lose_bet(self):
pass
async def add_card(self, card):
self.cards.append(card)
self.aces = ("".join(self.cards)).count("A")
value = 0
for card in self.cards:
value += bj_values[card]
self.value = value
while self.value > 21 and self.aces:
self.value -= 10
self.aces -= 1
async def hit(deck, hand):
await hand.add_card(await deck.deal())
async def double(deck, hand):
pass
async def split(deck, hands):
pass
async def payout(ctx, play, amount, multiplier):
await ctx.reply(
f"{play}\nBet: {amount:,}\nYou won {amount * multiplier:,} Flooneys"
)
async def check_winner(msg: discord.Interaction, player_hand, dealer_hand):
p_value, d_value = player_hand.value, dealer_hand.value
embed = discord.Embed(description="Blackjack")
embed.add_field(name="Bet: ", value="amount", inline=True)
embed.add_field(
name=player_hand.name,
value=f"{', '.join(player_hand.cards)}: {player_hand.value}",
inline=False,
)
embed.add_field(
name=dealer_hand.name,
value=f"{', '.join(dealer_hand.cards)}: {dealer_hand.value}",
inline=False,
)
if (p_value > d_value and not player_hand.bust) or dealer_hand.bust:
embed.add_field(name="Winner:", value=f"{player_hand.name}", inline=False)
player_balance = int(mydb.select("WALLET", "economy", True, "ID", player_hand.name.id).get("WALLET", None))
mydb.add("economy", "ID", "WALLET", player_hand.name.id, player_balance + player_hand.bet*2, True)
elif p_value < d_value and dealer_hand.bust:
embed.add_field(name="Winner:", value=f"{dealer_hand.name}", inline=False)
else:
embed.add_field(name="Winner:", value=f"Draw", inline=False)
await msg.edit_original_response(embed=embed)
async def dealer(msg: discord.Interaction, player_hand, dealer_hand, cards):
while dealer_hand.value < 17 and not player_hand.bust and not dealer_hand.bust:
await hit(cards, dealer_hand)
if dealer_hand.value > 21:
dealer_hand.bust = True
embed = discord.Embed(description="Blackjack")
embed.add_field(name="Bet: ", value="amount", inline=True)
embed.add_field(
name=player_hand.name,
value=f"{', '.join(player_hand.cards)}: {player_hand.value}",
inline=False,
)
embed.add_field(
name=dealer_hand.name,
value=f"{', '.join(dealer_hand.cards)}: {dealer_hand.value}",
inline=False,
)
await msg.edit_original_response(embed=embed)
await check_winner(msg, player_hand, dealer_hand)
class MyView(discord.ui.View):
def __init__(self, player_hand, dealer_hand, cards):
super().__init__()
self.player_hand = player_hand
self.dealer_hand = dealer_hand
self.cards = cards
@discord.ui.button(label="Hit", style=discord.ButtonStyle.primary, emoji="")
async def hit(self, interaction: discord.Interaction, button: discord.ui.Button):
await hit(self.cards, self.player_hand)
embed = discord.Embed(description="Blackjack")
embed.add_field(name="Bet: ", value="amount", inline=True)
embed.add_field(
name=self.player_hand.name,
value=f"{', '.join(self.player_hand.cards)}: {self.player_hand.value}",
inline=False,
)
embed.add_field(
name=self.dealer_hand.name,
value=f"{(self.dealer_hand.cards)[0]}",
inline=False,
)
msg = interaction
if self.player_hand.value < 21:
await msg.response.edit_message(embed=embed)
else:
await msg.response.edit_message(embed=embed, view=None)
if self.player_hand.value > 21:
self.player_hand.bust = True
await dealer(msg, self.player_hand, self.dealer_hand, self.cards)
@discord.ui.button(label="Stand", style=discord.ButtonStyle.secondary, emoji="🛑")
async def stand(self, interaction: discord.Interaction, button: discord.ui.Button):
embed = discord.Embed(description="Blackjack")
embed.add_field(name="Bet: ", value=self.player_hand.bet, inline=True)
embed.add_field(
name=self.player_hand.name,
value=f"{', '.join(self.player_hand.cards)}: {self.player_hand.value}",
inline=False,
)
embed.add_field(
name=self.dealer_hand.name,
value=f"{(self.dealer_hand.cards)[0]}",
inline=False,
)
msg = interaction
await msg.response.edit_message(embed=embed, view=None)
await dealer(msg, self.player_hand, self.dealer_hand, self.cards)
class Gamble(commands.Cog):
def __init__(self, client):
self.client = client
@commands.command()
async def blackjack(self, ctx, bet):
amount = int(bet)
cards = Deck()
player_balance = int(mydb.select("WALLET", "economy", True, "ID", ctx.author.id).get(
"WALLET", None
)
)
if player_balance < bet or bet < 0:
await ctx.reply("You have insufficient funds.")
return
mydb.add("economy", "ID", "WALLET", ctx.author.id, player_balance - bet, True)
player_hand, dealer_hand = Hand(ctx.author, amount), Hand("Dealer", None)
# setup
for _ in range(2):
await player_hand.add_card(await cards.deal())
await dealer_hand.add_card(await cards.deal())
embed = discord.Embed(description="Blackjack")
embed.add_field(name="Bet: ", value=amount, inline=True)
embed.add_field(
name=ctx.author,
value=f"{', '.join(player_hand.cards)}: {player_hand.value}",
inline=False,
)
embed.add_field(name="Dealer", value=f"{(dealer_hand.cards)[0]}", inline=False)
view = MyView(player_hand, dealer_hand, cards)
await ctx.send(embed=embed, view=view)
@commands.command()
async def show_buttons(self, ctx):
await ctx.reply(
"This is a button!", view=MyView(None, None, None)
) # Send a message with our View class that contains the button
@commands.cooldown(1, 1, commands.BucketType.user)
@commands.command(name="lottery", aliases=["slots"])
async def lottery(self, ctx, bet: int):
player_balance = int(
mydb.select("WALLET", "economy", True, "ID", ctx.author.id).get(
"WALLET", None
)
)
if player_balance < bet or bet < 0:
await ctx.reply("You have insufficient funds.")
return
play = "".join([choice(lottery_list) for _ in range(3)])
if play in lottery_win:
mult = lottery_win[play]
await payout(ctx, play, bet, mult)
elif play.count("🎁") == 2:
mult = lottery_win["🎁🎁"]
await payout(ctx, play, bet, mult)
elif play.count("🎁") == 1:
mult = lottery_win["🎁"]
await payout(ctx, play, bet, mult)
else:
mydb.add("economy", "ID", "WALLET", ctx.author.id, player_balance - bet, True)
await ctx.reply(f"{play}\nYou lost {int(bet):,} Flooneys")
async def setup(client):
await client.add_cog(Gamble(client))