refactor(fun): cogs into one group

Combined all fun commands into a single 'fun' GroupCog with subcommands, replacing individual cogs for coinflip, eightball, minesweeper, randomfact, and rockpaperscissors. Updated bot.py to load the fun cog as a package and adjusted help.py to reflect the new command structure. This improves organization and discoverability of fun commands.
This commit is contained in:
neoarz
2025-09-28 22:48:10 -04:00
parent 6ed3b0d378
commit e7ee97074b
8 changed files with 114 additions and 93 deletions

42
bot.py
View File

@@ -86,21 +86,33 @@ class DiscordBot(commands.Bot):
for folder in os.listdir(cogs_path): for folder in os.listdir(cogs_path):
folder_path = os.path.join(cogs_path, folder) folder_path = os.path.join(cogs_path, folder)
if os.path.isdir(folder_path) and not folder.startswith('__'): if os.path.isdir(folder_path) and not folder.startswith('__'):
for file in os.listdir(folder_path): init_file = os.path.join(folder_path, "__init__.py")
if file.endswith(".py") and not file.startswith('__'): if os.path.exists(init_file):
extension = file[:-3] try:
full_name = f"{folder}.{extension}".lower() await self.load_extension(f"cogs.{folder}")
if extension.lower() in disabled_cogs or full_name in disabled_cogs: if folder != "fun":
self.logger.info(f"Skipped disabled extension '{full_name}'") self.logger.info(f"Loaded extension '{folder}'")
continue except Exception as e:
try: exception = f"{type(e).__name__}: {e}"
await self.load_extension(f"cogs.{folder}.{extension}") self.logger.error(
self.logger.info(f"Loaded extension '{folder}.{extension}'") f"Failed to load extension {folder}\n{exception}"
except Exception as e: )
exception = f"{type(e).__name__}: {e}" else:
self.logger.error( for file in os.listdir(folder_path):
f"Failed to load extension {folder}.{extension}\n{exception}" if file.endswith(".py") and not file.startswith('__'):
) extension = file[:-3]
full_name = f"{folder}.{extension}".lower()
if extension.lower() in disabled_cogs or full_name in disabled_cogs:
self.logger.info(f"Skipped disabled extension '{full_name}'")
continue
try:
await self.load_extension(f"cogs.{folder}.{extension}")
self.logger.info(f"Loaded extension '{folder}.{extension}'")
except Exception as e:
exception = f"{type(e).__name__}: {e}"
self.logger.error(
f"Failed to load extension {folder}.{extension}\n{exception}"
)
for file in os.listdir(cogs_path): for file in os.listdir(cogs_path):
if file.endswith(".py") and not file.startswith('__'): if file.endswith(".py") and not file.startswith('__'):

55
cogs/fun/__init__.py Normal file
View File

@@ -0,0 +1,55 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
from .coinflip import coinflip_command
from .eightball import eightball_command
from .minesweeper import minesweeper_command
from .randomfact import randomfact_command
from .rockpaperscissors import rps_command
class Fun(commands.GroupCog, name="fun"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.hybrid_command(
name="coinflip",
description="Make a coin flip, but give your bet before."
)
async def coinflip(self, context):
return await coinflip_command()(self, context)
@commands.hybrid_command(
name="8ball",
description="Ask any question to the bot.",
)
async def eight_ball(self, context, *, question: str):
return await eightball_command()(self, context, question=question)
@commands.hybrid_command(
name="minesweeper",
description="Play a buttoned minesweeper mini-game."
)
async def minesweeper(self, context):
return await minesweeper_command()(self, context)
@commands.hybrid_command(name="randomfact", description="Get a random fact.")
async def randomfact(self, context):
return await randomfact_command()(self, context)
@commands.hybrid_command(
name="rps", description="Play the rock paper scissors game against the bot."
)
async def rock_paper_scissors(self, context):
return await rps_command()(self, context)
async def setup(bot) -> None:
cog = Fun(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'fun.coinflip'")
bot.logger.info("Loaded extension 'fun.8ball'")
bot.logger.info("Loaded extension 'fun.minesweeper'")
bot.logger.info("Loaded extension 'fun.randomfact'")
bot.logger.info("Loaded extension 'fun.rps'")

View File

@@ -1,7 +1,6 @@
import random import random
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class Choice(discord.ui.View): class Choice(discord.ui.View):
def __init__(self) -> None: def __init__(self) -> None:
@@ -22,18 +21,12 @@ class Choice(discord.ui.View):
self.value = "tails" self.value = "tails"
self.stop() self.stop()
class CoinFlip(commands.Cog, name="coinflip"): def coinflip_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="coinflip", description="Make a coin flip, but give your bet before." name="coinflip",
description="Make a coin flip, but give your bet before."
) )
async def coinflip(self, context: Context) -> None: async def coinflip(self, context):
"""
Make a coin flip, but give your bet before.
:param context: The hybrid command context.
"""
buttons = Choice() buttons = Choice()
embed = discord.Embed( embed = discord.Embed(
title="Coinflip", title="Coinflip",
@@ -59,6 +52,5 @@ class CoinFlip(commands.Cog, name="coinflip"):
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
await message.edit(embed=embed, view=None, content=None) await message.edit(embed=embed, view=None, content=None)
async def setup(bot) -> None: return coinflip
await bot.add_cog(CoinFlip(bot))

View File

@@ -1,26 +1,12 @@
import random import random
import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class EightBall(commands.Cog, name="8ball"):
def __init__(self, bot) -> None:
self.bot = bot
def eightball_command():
@commands.hybrid_command( @commands.hybrid_command(
name="8ball", name="8ball",
description="Ask any question to the bot.", description="Ask any question to the bot.",
) )
@app_commands.describe(question="The question you want to ask.") async def eight_ball(self, context, *, question: str):
async def eight_ball(self, context: Context, *, question: str) -> None:
"""
Ask any question to the bot.
:param context: The hybrid command context.
:param question: The question that should be asked by the user.
"""
answers = [ answers = [
"It is certain.", "It is certain.",
"It is decidedly so.", "It is decidedly so.",
@@ -51,7 +37,5 @@ class EightBall(commands.Cog, name="8ball"):
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
embed.set_footer(text=f"The question was: {question}") embed.set_footer(text=f"The question was: {question}")
await context.send(embed=embed) await context.send(embed=embed)
return eight_ball
async def setup(bot) -> None:
await bot.add_cog(EightBall(bot))

View File

@@ -2,8 +2,6 @@ import random
from itertools import repeat from itertools import repeat
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class RowButton(discord.ui.Button): class RowButton(discord.ui.Button):
def __init__(self, ctx, label, custom_id, bombs, board): def __init__(self, ctx, label, custom_id, bombs, board):
@@ -66,7 +64,6 @@ class RowButton(discord.ui.Button):
await interaction.edit_original_response(view=view) await interaction.edit_original_response(view=view)
class MsView(discord.ui.View): class MsView(discord.ui.View):
def __init__(self, ctx, options, bombs, board): def __init__(self, ctx, options, bombs, board):
super().__init__() super().__init__()
@@ -155,21 +152,13 @@ class MsView(discord.ui.View):
self.GetBoardPos(pos) self.GetBoardPos(pos)
] = bombemo ] = bombemo
def minesweeper_command():
class Minesweeper(commands.Cog, name="minesweeper"):
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="minesweeper", name="minesweeper",
description="Play a buttoned minesweeper mini-game." description="Play a buttoned minesweeper mini-game."
) )
async def minesweeper(self, context: Context) -> None: async def minesweeper(self, context):
""" board = [[" "] * 5 for _ in range(5)]
Play a buttoned minesweeper mini-game.
:param context: The hybrid command context.
"""
board = [[" "] * 5 for _ in range(5)] # Unicode block character, usually doesnt show up in Discord or github, search up invisible character on google
bombs = 0 bombs = 0
bombpositions = [] bombpositions = []
for x in repeat(None, random.randint(4, 11)): for x in repeat(None, random.randint(4, 11)):
@@ -197,7 +186,5 @@ class Minesweeper(commands.Cog, name="minesweeper"):
view = MsView(context, ExtractBlocks(), bombpositions, board) view = MsView(context, ExtractBlocks(), bombpositions, board)
message = await context.send(embed=embed, view=view) message = await context.send(embed=embed, view=view)
view.message = message view.message = message
return minesweeper
async def setup(bot) -> None:
await bot.add_cog(Minesweeper(bot))

View File

@@ -1,15 +1,10 @@
import aiohttp import aiohttp
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class RandomFact(commands.Cog, name="randomfact"):
def __init__(self, bot) -> None:
self.bot = bot
def randomfact_command():
@commands.hybrid_command(name="randomfact", description="Get a random fact.") @commands.hybrid_command(name="randomfact", description="Get a random fact.")
async def randomfact(self, context: Context) -> None: async def randomfact(self, context):
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
"https://uselessfacts.jsph.pl/random.json?language=en" "https://uselessfacts.jsph.pl/random.json?language=en"
@@ -30,7 +25,5 @@ class RandomFact(commands.Cog, name="randomfact"):
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
await context.send(embed=embed) await context.send(embed=embed)
return randomfact
async def setup(bot) -> None:
await bot.add_cog(RandomFact(bot))

View File

@@ -1,7 +1,6 @@
import random import random
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class RockPaperScissors(discord.ui.Select): class RockPaperScissors(discord.ui.Select):
def __init__(self) -> None: def __init__(self) -> None:
@@ -39,7 +38,6 @@ class RockPaperScissors(discord.ui.Select):
winner = (3 + user_choice_index - bot_choice_index) % 3 winner = (3 + user_choice_index - bot_choice_index) % 3
# Get the user mention
user_mention = interaction.user.mention user_mention = interaction.user.mention
if winner == 0: if winner == 0:
@@ -61,14 +59,11 @@ class RockPaperScissorsView(discord.ui.View):
super().__init__() super().__init__()
self.add_item(RockPaperScissors()) self.add_item(RockPaperScissors())
class RPS(commands.Cog, name="rps"): def rps_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="rps", description="Play the rock paper scissors game against the bot." name="rps", description="Play the rock paper scissors game against the bot."
) )
async def rock_paper_scissors(self, context: Context) -> None: async def rock_paper_scissors(self, context):
view = RockPaperScissorsView() view = RockPaperScissorsView()
embed = discord.Embed( embed = discord.Embed(
title="Rock Paper Scissors", title="Rock Paper Scissors",
@@ -77,6 +72,5 @@ class RPS(commands.Cog, name="rps"):
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return rock_paper_scissors
await bot.add_cog(RPS(bot))

View File

@@ -47,11 +47,7 @@ class Help(commands.Cog, name="help"):
# "context_menus": "general", # "context_menus": "general",
# Fun Commands # Fun Commands
"randomfact": "fun", "fun": "fun",
"coinflip": "fun",
"rps": "fun",
"8ball": "fun",
"minesweeper": "fun",
# Moderation Commands # Moderation Commands
"kick": "moderation", "kick": "moderation",
@@ -183,6 +179,14 @@ class Help(commands.Cog, name="help"):
description = app_command.description.partition("\n")[0] if getattr(app_command, "description", None) else "No description available" description = app_command.description.partition("\n")[0] if getattr(app_command, "description", None) else "No description available"
commands_in_category.append((app_command.name, description)) commands_in_category.append((app_command.name, description))
seen_names.add(app_command.name) seen_names.add(app_command.name)
if hasattr(app_command, 'commands') and category == "fun":
for subcommand in app_command.commands:
if subcommand.name in seen_names:
continue
sub_desc = subcommand.description.partition("\n")[0] if getattr(subcommand, "description", None) else "No description available"
commands_in_category.append((f"{app_command.name} {subcommand.name}", sub_desc))
seen_names.add(f"{app_command.name} {subcommand.name}")
if not commands_in_category: if not commands_in_category:
embed = discord.Embed( embed = discord.Embed(