diff options
| author | 2021-10-08 21:08:55 +0100 | |
|---|---|---|
| committer | 2021-10-08 21:08:55 +0100 | |
| commit | c81bd510cc209a814390e604949b48ae87fdc170 (patch) | |
| tree | 16763fefef76837205e666ddf04988a45b5ddd46 /bot/exts/fun | |
| parent | Make setting the old embed description cleaner (diff) | |
| parent | Merge pull request #895 from python-discord/topic-improvements (diff) | |
Merge branch 'main' into duckduckduckgoose
Diffstat (limited to 'bot/exts/fun')
| -rw-r--r-- | bot/exts/fun/anagram.py | 110 | ||||
| -rw-r--r-- | bot/exts/fun/quack.py | 75 | 
2 files changed, 185 insertions, 0 deletions
| diff --git a/bot/exts/fun/anagram.py b/bot/exts/fun/anagram.py new file mode 100644 index 00000000..9aee5f18 --- /dev/null +++ b/bot/exts/fun/anagram.py @@ -0,0 +1,110 @@ +import asyncio +import json +import logging +import random +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +TIME_LIMIT = 60 + +# anagram.json file contains all the anagrams +with open(Path("bot/resources/fun/anagram.json"), "r") as f: +    ANAGRAMS_ALL = json.load(f) + + +class AnagramGame: +    """ +    Used for creating instances of anagram games. + +    Once multiple games can be run at the same time, this class' instances +    can be used for keeping track of each anagram game. +    """ + +    def __init__(self, scrambled: str, correct: list[str]) -> None: +        self.scrambled = scrambled +        self.correct = set(correct) + +        self.winners = set() + +    async def message_creation(self, message: discord.Message) -> None: +        """Check if the message is a correct answer and remove it from the list of answers.""" +        if message.content.lower() in self.correct: +            self.winners.add(message.author.mention) +            self.correct.remove(message.content.lower()) + + +class Anagram(commands.Cog): +    """Cog for the Anagram game command.""" + +    def __init__(self, bot: Bot): +        self.bot = bot + +        self.games: dict[int, AnagramGame] = {} + +    @commands.command(name="anagram", aliases=("anag", "gram", "ag")) +    @commands.guild_only() +    async def anagram_command(self, ctx: commands.Context) -> None: +        """ +        Given shuffled letters, rearrange them into anagrams. + +        Show an embed with scrambled letters which if rearranged can form words. +        After a specific amount of time, list the correct answers and whether someone provided a +        correct answer. +        """ +        if self.games.get(ctx.channel.id): +            await ctx.send("An anagram is already being solved in this channel!") +            return + +        scrambled_letters, correct = random.choice(list(ANAGRAMS_ALL.items())) + +        game = AnagramGame(scrambled_letters, correct) +        self.games[ctx.channel.id] = game + +        anagram_embed = discord.Embed( +            title=f"Find anagrams from these letters: '{scrambled_letters.upper()}'", +            description=f"You have {TIME_LIMIT} seconds to find correct words.", +            colour=Colours.purple, +        ) + +        await ctx.send(embed=anagram_embed) +        await asyncio.sleep(TIME_LIMIT) + +        if game.winners: +            win_list = ", ".join(game.winners) +            content = f"Well done {win_list} for getting it right!" +        else: +            content = "Nobody got it right." + +        answer_embed = discord.Embed( +            title=f"The words were:  `{'`, `'.join(ANAGRAMS_ALL[game.scrambled])}`!", +            colour=Colours.pink, +        ) + +        await ctx.send(content, embed=answer_embed) + +        # Game is finished, let's remove it from the dict +        self.games.pop(ctx.channel.id) + +    @commands.Cog.listener() +    async def on_message(self, message: discord.Message) -> None: +        """Check a message for an anagram attempt and pass to an ongoing game.""" +        if message.author.bot or not message.guild: +            return + +        game = self.games.get(message.channel.id) +        if not game: +            return + +        await game.message_creation(message) + + +def setup(bot: Bot) -> None: +    """Load the Anagram cog.""" +    bot.add_cog(Anagram(bot)) diff --git a/bot/exts/fun/quack.py b/bot/exts/fun/quack.py new file mode 100644 index 00000000..0c228aed --- /dev/null +++ b/bot/exts/fun/quack.py @@ -0,0 +1,75 @@ +import logging +import random +from typing import Literal, Optional + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours, NEGATIVE_REPLIES + +API_URL = 'https://quackstack.pythondiscord.com' + +log = logging.getLogger(__name__) + + +class Quackstack(commands.Cog): +    """Cog used for wrapping Quackstack.""" + +    def __init__(self, bot: Bot): +        self.bot = bot + +    @commands.command() +    async def quack( +        self, +        ctx: commands.Context, +        ducktype: Literal["duck", "manduck"] = "duck", +        *, +        seed: Optional[str] = None +    ) -> None: +        """ +        Use the Quackstack API to generate a random duck. + +        If a seed is provided, a duck is generated based on the given seed. +        Either "duck" or "manduck" can be provided to change the duck type generated. +        """ +        ducktype = ducktype.lower() +        quackstack_url = f"{API_URL}/{ducktype}" +        params = {} +        if seed is not None: +            try: +                seed = int(seed) +            except ValueError: +                # We just need to turn the string into an integer any way possible +                seed = int.from_bytes(seed.encode(), "big") +            params["seed"] = seed + +        async with self.bot.http_session.get(quackstack_url, params=params) as response: +            error_embed = discord.Embed( +                title=random.choice(NEGATIVE_REPLIES), +                description="The request failed. Please try again later.", +                color=Colours.soft_red, +            ) +            if response.status != 200: +                log.error(f"Response to Quackstack returned code {response.status}") +                await ctx.send(embed=error_embed) +                return + +            data = await response.json() +            file = data["file"] + +        embed = discord.Embed( +            title=f"Quack! Here's a {ducktype} for you.", +            description=f"A {ducktype} from Quackstack.", +            color=Colours.grass_green, +            url=f"{API_URL}/docs" +        ) + +        embed.set_image(url=API_URL + file) + +        await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: +    """Loads the Quack cog.""" +    bot.add_cog(Quackstack(bot)) | 
