diff --git a/README.md b/README.md index c3af4191..e734a123 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ To install any cog you want: | AutoPublisyher | Automatically push news channel messages. | 2.5.0 | ltzmax, AAA3A | ✅ | | Counting | Count from 1 to infinity! with some customizable settings. | 1.3.3 | ltzmax | ✅ | | GitHub | GitHub RSS Commit Feeds | 1.0.1 | Obi-Wan3, ltzmax | ✅ | +| GuessFlag | Play A game of Guess the flag of a country. | 1.0.0 | ltzmax | ✅ | | lockdown | Let moderators lockdown a channel to prevent messages from being sent. | 1.3.0 | ltzmax | ✅ | | nbaschedule | Get the current NBA schedule for next game. | 1.0.1 | ltzmax | ✅ | | NoSpoiler | Prevent using spoiler messages | 1.8.0 | ltzmax | ✅ | diff --git a/docs/GuessFlag.md b/docs/GuessFlag.md new file mode 100644 index 00000000..a051d8ff --- /dev/null +++ b/docs/GuessFlag.md @@ -0,0 +1,29 @@ +Guess the flag of a country game.

Win credits to your `[p]bank balance` if you guess the flag correctly and lose credits from your `[p]bank balance` if you guess it wrong. + +# [p]guessflagset +Settings for Guess the Flag game.
+ - Usage: `[p]guessflagset` + - Restricted to: `BOT_OWNER` +## [p]guessflagset view +View the current settings.
+ - Usage: `[p]guessflagset view` +## [p]guessflagset creditloss +Set the amount of credits to lose.
+ - Usage: `[p]guessflagset creditloss ` +## [p]guessflagset creditwin +Set the amount of credits to win.
+ - Usage: `[p]guessflagset creditwin ` +# [p]guessflag +Play A game of Guess the flag of a country.
+ +You can only play this game once every 60 seconds.
+ +You have 30 seconds to guess the flag of a country.
+You will win credits if you guess the flag correctly and lose credits if you guess it wrong.
+ +The default credit win amount is 100 and the default credit loss amount is 50 credits but can be changed by the bot owner.
+ - Usage: `[p]guessflag` + - Cooldown: `1 per 60.0 seconds` +## [p]guessflag stats +View your stats or another user's stats.
+ - Usage: `[p]guessflag stats [user=None]` diff --git a/guessflag/__init__.py b/guessflag/__init__.py new file mode 100644 index 00000000..cf9590f8 --- /dev/null +++ b/guessflag/__init__.py @@ -0,0 +1,10 @@ +from redbot.core.bot import Red + +from .guessflag import GuessFlag + +__red_end_user_data_statement__ = "This cog does not persistently store data about users." + + +async def setup(bot: Red) -> None: + cog = GuessFlag(bot) + await bot.add_cog(cog) diff --git a/guessflag/guessflag.py b/guessflag/guessflag.py new file mode 100644 index 00000000..6ebbf520 --- /dev/null +++ b/guessflag/guessflag.py @@ -0,0 +1,211 @@ +import asyncio +import logging +import random + +import aiohttp +import discord +import orjson +from redbot.core import Config, bank, commands +from redbot.core.errors import BalanceTooHigh +from redbot.core.utils.chat_formatting import box, humanize_number +from tabulate import tabulate + +log = logging.getLogger("red.maxcogs.guessflag") + + +async def fetch_flags(): + async with aiohttp.ClientSession() as session: + async with session.get("https://restcountries.com/v3.1/all") as response: + if response.status == 200: + countries = orjson.loads(await response.read()) + flags = { + country["name"]["common"]: country["flags"]["png"] for country in countries + } + return flags + else: + log.error(f"Failed to fetch flags: {response.status}") + return {} + + +def get_random_flag(flags): + country, flag_url = random.choice(list(flags.items())) + options = random.sample(list(flags.keys()), 24) + if country not in options: + options.append(country) + random.shuffle(options) + return country, flag_url, options + + +class GuessFlag(commands.Cog): + """ + Play A game of Guess the flag of a country. + + Win credits to your `[p]bank balance` if you guess the flag correctly and lose credits from your `[p]bank balance` if you guess it wrong. + """ + + __version__: Final[str] = "1.0.0" + __author__: Final[str] = "MAX" + __docs__: Final[str] = "https://github.com/ltzmax/maxcogs/blob/master/docs/GuessFlag.md" + + def __init__(self, bot): + self.bot = bot + self.flags = None + bot.loop.create_task(self.load_flags()) + self.config = Config.get_conf(self, identifier=9008567, force_registration=True) + default_global = {"default_credit_win": 100, "default_credit_loss": 50} + default_user = {"stats_won": 0, "stats_lost": 0} + self.config.register_user(**default_user) + self.config.register_global(**default_global) + + def format_help_for_context(self, ctx: commands.Context) -> str: + """Thanks Sinbad!""" + pre_processed = super().format_help_for_context(ctx) + return f"{pre_processed}\n\nAuthor: {self.__author__}\nCog Version: {self.__version__}\nDocs: {self.__docs__}" + + async def red_delete_data_for_user(self, **kwargs: Any) -> None: + """Nothing to delete.""" + return + + async def load_flags(self): + self.flags = await fetch_flags() + + @commands.group() + @commands.is_owner() + async def guessflagset(self, ctx): + """ + Settings for Guess the Flag game. + """ + + @guessflagset.command() + async def creditwin(self, ctx, amount: commands.Range[int, 50, 1000000000]): + """Set the amount of credits to win.""" + await self.config.default_credit_win.set(amount) + await ctx.send(f"Credit win amount set to {amount}.") + + @guessflagset.command() + async def creditloss(self, ctx, amount: commands.Range[int, 50, 1000000000]): + """Set the amount of credits to lose.""" + await self.config.default_credit_loss.set(amount) + await ctx.send(f"Credit loss amount set to {amount}.") + + @guessflagset.command() + async def view(self, ctx): + """View the current settings.""" + credit_win = await self.config.default_credit_win() + credit_loss = await self.config.default_credit_loss() + await ctx.send(f"Credit win amount: {credit_win}\nCredit loss amount: {credit_loss}") + + @commands.group(invoke_without_command=True) + @commands.bot_has_permissions(embed_links=True) + @commands.cooldown(1, 60, commands.BucketType.user) + async def guessflag(self, ctx): + """ + Play A game of Guess the flag of a country. + + You can only play this game once every 60 seconds. + + You have 30 seconds to guess the flag of a country. + You will win credits if you guess the flag correctly and lose credits if you guess it wrong. + + The default credit win amount is 100 and the default credit loss amount is 50 credits but can be changed by the bot owner. + """ + if not self.flags: + return await ctx.send("Flags are still loading, please try again later.") + + country, flag_url, options = get_random_flag(self.flags) + + embed = discord.Embed( + title="Guess the Flag!", + description="You have 30 seconds to guess the flag.", + color=await ctx.embed_color(), + ) + embed.set_image(url=flag_url) + + view = GuessFlagView(ctx.author, country, options, self.config) + message = await ctx.send(embed=embed, view=view) + view.message = message + + @guessflag.command() + async def stats(self, ctx, user: discord.User = None): + """View your stats or another user's stats.""" + user = user or ctx.author + + if ( + not await self.config.user(user).stats_won() + and not await self.config.user(user).stats_lost() + ): + return await ctx.send("You haven't played this game yet.") + + stats_won = await self.config.user(user).stats_won() + stats_lost = await self.config.user(user).stats_lost() + table = tabulate( + [["Won", stats_won], ["Lost", stats_lost]], + headers=["Title", "Stats"], + tablefmt="simple", + ) + await ctx.send(box(table, lang="prolog")) + + +# Too lazy to make a separate file for this class +# This class is for the buttons in the GuessFlag game view +class GuessFlagView(discord.ui.View): + def __init__(self, author, correct_country, options, config): + super().__init__(timeout=30) + self.author = author + self.correct_country = correct_country + self.config = config + for option in options: + button = discord.ui.Button( + label=option, style=discord.ButtonStyle.primary, custom_id=option + ) + button.callback = self.button_callback + self.add_item(button) + + async def on_timeout(self) -> None: + for item in self.children: + item: discord.ui.Item + item.disabled = True + try: + if self.message: + await self.message.edit(view=self) + except discord.HTTPException: + log.error("Failed to edit message.", exc_info=True) + pass + + async def button_callback(self, interaction): + if interaction.user != self.author: + return await interaction.response.send_message( + "This is not your game!", ephemeral=True + ) + + for item in self.children: + item.disabled = True + if item.custom_id == self.correct_country: + item.style = discord.ButtonStyle.success # Green for correct answer + else: + item.style = discord.ButtonStyle.danger # Red for wrong answers + + credit = await bank.get_balance(interaction.user) + credit_name = await bank.get_currency_name(interaction.user) + credit_win = await self.config.default_credit_win() + credit_loss = await self.config.default_credit_loss() + stats_lost = await self.config.user(interaction.user).stats_lost() + stats_won = await self.config.user(interaction.user).stats_won() + if interaction.data["custom_id"] == self.correct_country: + try: + await bank.deposit_credits(interaction.user, credit_win) + except BalanceTooHigh as e: + return await interaction.response.send_message( + "You have reached the maximum balance.", ephemeral=True + ) + await self.config.user(interaction.user).stats_won.set(stats_won + 1) + await interaction.response.send_message( + f"Correct {interaction.user.mention}! You got {credit_win} {credit_name}." + ) + else: + await bank.withdraw_credits(interaction.user, credit_loss) + await self.config.user(interaction.user).stats_lost.set(stats_lost + 1) + await interaction.response.send_message( + f"Wrong answer {interaction.user.mention}! It's {self.correct_country} and you lost {credit_loss} {credit_name}." + ) + await interaction.message.edit(view=self) diff --git a/guessflag/info.json b/guessflag/info.json new file mode 100644 index 00000000..56e738cb --- /dev/null +++ b/guessflag/info.json @@ -0,0 +1,26 @@ +{ + "author": [ + "max" + ], + "name": "GuessFlag", + "install_msg": "Thanks for installing.", + "description": "Win credits to your `[p]bank balance` if you guess the flag correctly and lose credits from your `[p]bank balance` if you guess it wrong.", + "short": "Play A game of Guess the flag of a country.", + "hidden": false, + "min_bot_version": "3.5.13", + "tags": [ + "economy", + "credits" + ], + "permissions": [ + "manage_messages" + ], + "requirements": ["tabulate"], + "min_python_version": [ + 3, + 9, + 0 + ], + "end_user_data_statement": "This cog does not store any End User Data.", + "type": "COG" +}