diff options
Diffstat (limited to 'bot/seasons/easter')
| -rw-r--r-- | bot/seasons/easter/__init__.py | 4 | ||||
| -rw-r--r-- | bot/seasons/easter/april_fools_vids.py | 11 | ||||
| -rw-r--r-- | bot/seasons/easter/avatar_easterifier.py | 12 | ||||
| -rw-r--r-- | bot/seasons/easter/bunny_name_generator.py | 92 | ||||
| -rw-r--r-- | bot/seasons/easter/conversationstarters.py | 4 | ||||
| -rw-r--r-- | bot/seasons/easter/egg_decorating.py | 12 | ||||
| -rw-r--r-- | bot/seasons/easter/egg_hunt/__init__.py | 1 | ||||
| -rw-r--r-- | bot/seasons/easter/egg_hunt/cog.py | 25 | ||||
| -rw-r--r-- | bot/seasons/easter/egghead_quiz.py | 8 | ||||
| -rw-r--r-- | bot/seasons/easter/traditions.py | 4 |
10 files changed, 117 insertions, 56 deletions
diff --git a/bot/seasons/easter/__init__.py b/bot/seasons/easter/__init__.py index 83d12ead..1d77b6a6 100644 --- a/bot/seasons/easter/__init__.py +++ b/bot/seasons/easter/__init__.py @@ -30,4 +30,6 @@ class Easter(SeasonBase): end_date = "30/04" colour = Colours.pink - icon = "/logos/logo_seasonal/easter/easter.png" + icon = ( + "/logos/logo_seasonal/easter/easter.png", + ) diff --git a/bot/seasons/easter/april_fools_vids.py b/bot/seasons/easter/april_fools_vids.py index 5dae8485..9fbe87a0 100644 --- a/bot/seasons/easter/april_fools_vids.py +++ b/bot/seasons/easter/april_fools_vids.py @@ -9,7 +9,8 @@ log = logging.getLogger(__name__) class AprilFoolVideos(commands.Cog): - """A cog for april fools that gets a random april fools video from youtube.""" + """A cog for April Fools' that gets a random April Fools' video from Youtube.""" + def __init__(self, bot): self.bot = bot self.yt_vids = self.load_json() @@ -17,15 +18,15 @@ class AprilFoolVideos(commands.Cog): @staticmethod def load_json(): - """A function to load json data.""" - p = Path('bot', 'resources', 'easter', 'april_fools_vids.json') + """A function to load JSON data.""" + p = Path('bot/resources/easterapril_fools_vids.json') with p.open() as json_file: all_vids = load(json_file) return all_vids @commands.command(name='fool') async def aprial_fools(self, ctx): - """Gets a random april fools video from youtube.""" + """Get a random April Fools' video from Youtube.""" random_youtuber = random.choice(self.youtubers) category = self.yt_vids[random_youtuber] random_vid = random.choice(category) @@ -33,6 +34,6 @@ class AprilFoolVideos(commands.Cog): def setup(bot): - """A function to add the cog.""" + """April Fools' Cog load.""" bot.add_cog(AprilFoolVideos(bot)) log.info('April Fools videos cog loaded!') diff --git a/bot/seasons/easter/avatar_easterifier.py b/bot/seasons/easter/avatar_easterifier.py index 9f7ea271..ad8b5473 100644 --- a/bot/seasons/easter/avatar_easterifier.py +++ b/bot/seasons/easter/avatar_easterifier.py @@ -31,12 +31,10 @@ class AvatarEasterifier(commands.Cog): Returns a merge between the original colour and the closest colour """ - r1, g1, b1 = x def distance(point): """Finds the difference between a pastel colour and the original pixel colour""" - r2, g2, b2 = point return ((r1 - r2)**2 + (g1 - g2)**2 + (b1 - b2)**2) @@ -45,6 +43,7 @@ class AvatarEasterifier(commands.Cog): r = (r1 + r2) // 2 g = (g1 + g2) // 2 b = (b1 + b2) // 2 + return (r, g, b) @commands.command(pass_context=True, aliases=["easterify"]) @@ -57,7 +56,6 @@ class AvatarEasterifier(commands.Cog): Colours are split by spaces, unless you wrap the colour name in double quotes. Discord colour names, HTML colour names, XKCD colour names and hex values are accepted. """ - async def send(*args, **kwargs): """ This replaces the original ctx.send. @@ -71,8 +69,7 @@ class AvatarEasterifier(commands.Cog): async with ctx.typing(): # Grabs image of avatar - async with self.bot.http_session.get(ctx.author.avatar_url_as(size=256)) as resp: - image_bytes = await resp.read() + image_bytes = await ctx.author.avatar_url_as(size=256).read() old = Image.open(BytesIO(image_bytes)) old = old.convert("RGBA") @@ -107,7 +104,7 @@ class AvatarEasterifier(commands.Cog): im.alpha_composite(egg, (im.width - egg.width, (im.height - egg.height)//2)) # Right centre. ctx.send = send_message # Reassigns ctx.send else: - bunny = Image.open(Path("bot", "resources", "easter", "chocolate_bunny.png")) + bunny = Image.open(Path("bot/resources/easter/chocolate_bunny.png")) im.alpha_composite(bunny, (im.width - bunny.width, (im.height - bunny.height)//2)) # Right centre. bufferedio = BytesIO() @@ -127,7 +124,6 @@ class AvatarEasterifier(commands.Cog): def setup(bot): - """Cog load.""" - + """Avatar Easterifier Cog load.""" bot.add_cog(AvatarEasterifier(bot)) log.info("AvatarEasterifier cog loaded") diff --git a/bot/seasons/easter/bunny_name_generator.py b/bot/seasons/easter/bunny_name_generator.py new file mode 100644 index 00000000..1fca3c20 --- /dev/null +++ b/bot/seasons/easter/bunny_name_generator.py @@ -0,0 +1,92 @@ +import json +import logging +import random +import re +from pathlib import Path + +from discord.ext import commands + +log = logging.getLogger(__name__) + +with open(Path("bot", "resources", "easter", "bunny_names.json"), "r", encoding="utf8") as f: + BUNNY_NAMES = json.load(f) + + +class BunnyNameGenerator(commands.Cog): + """Generate a random bunny name, or bunnify your Discord username!""" + + def __init__(self, bot): + self.bot = bot + + def find_separators(self, displayname): + """Check if Discord name contains spaces so we can bunnify an individual word in the name.""" + new_name = re.split(r'[_.\s]', str(displayname)) + if displayname not in new_name: + return new_name + + def find_vowels(self, displayname): + """ + Finds vowels in the user's display name. + + If the Discord name contains a vowel and the letter y, + it will match one or more of these patterns. + Only the most recently matched pattern will apply the changes. + """ + expressions = [ + (r'a.+y', 'patchy'), + (r'e.+y', 'ears'), + (r'i.+y', 'ditsy'), + (r'o.+y', 'oofy'), + (r'u.+y', 'uffy'), + ] + + for exp, vowel_sub in expressions: + new_name = re.sub(exp, vowel_sub, displayname) + if new_name != displayname: + return new_name + + def append_name(self, displayname): + """Adds a suffix to the end of the Discord name""" + extensions = ['foot', 'ear', 'nose', 'tail'] + suffix = random.choice(extensions) + appended_name = displayname + suffix + + return appended_name + + @commands.command() + async def bunnyname(self, ctx): + """Picks a random bunny name from a JSON file""" + await ctx.send(random.choice(BUNNY_NAMES["names"])) + + @commands.command() + async def bunnifyme(self, ctx): + """Gets your Discord username and bunnifies it""" + username = ctx.message.author.display_name + + # If name contains spaces or other separators, get the individual words to randomly bunnify + spaces_in_name = self.find_separators(username) + + # If name contains vowels, see if it matches any of the patterns in this function + # If there are matches, the bunnified name is returned. + vowels_in_name = self.find_vowels(username) + + # Default if the checks above return None + unmatched_name = self.append_name(username) + + if spaces_in_name is not None: + replacements = ['Cotton', 'Fluff', 'Floof' 'Bounce', 'Snuffle', 'Nibble', 'Cuddle', 'Velvetpaw', 'Carrot'] + word_to_replace = random.choice(spaces_in_name) + substitute = random.choice(replacements) + bunnified_name = username.replace(word_to_replace, substitute) + elif vowels_in_name is not None: + bunnified_name = vowels_in_name + elif unmatched_name: + bunnified_name = unmatched_name + + await ctx.send(bunnified_name) + + +def setup(bot): + """Bunny Name Generator Cog load.""" + bot.add_cog(BunnyNameGenerator(bot)) + log.info("BunnyNameGenerator cog loaded.") diff --git a/bot/seasons/easter/conversationstarters.py b/bot/seasons/easter/conversationstarters.py index b479406b..c2cdf26c 100644 --- a/bot/seasons/easter/conversationstarters.py +++ b/bot/seasons/easter/conversationstarters.py @@ -7,7 +7,7 @@ from discord.ext import commands log = logging.getLogger(__name__) -with open(Path('bot', 'resources', 'easter', 'starter.json'), 'r', encoding="utf8") as f: +with open(Path("bot/resources/easter/starter.json"), "r", encoding="utf8") as f: starters = json.load(f) @@ -20,12 +20,10 @@ class ConvoStarters(commands.Cog): @commands.command() async def topic(self, ctx): """Responds with a random topic to start a conversation.""" - await ctx.send(random.choice(starters['starters'])) def setup(bot): """Conversation starters Cog load.""" - bot.add_cog(ConvoStarters(bot)) log.info("ConvoStarters cog loaded") diff --git a/bot/seasons/easter/egg_decorating.py b/bot/seasons/easter/egg_decorating.py index d283e42a..ee8a80e5 100644 --- a/bot/seasons/easter/egg_decorating.py +++ b/bot/seasons/easter/egg_decorating.py @@ -12,10 +12,10 @@ from discord.ext import commands log = logging.getLogger(__name__) -with open(Path("bot", "resources", "evergreen", "html_colours.json")) as f: +with open(Path("bot/resources/evergreen/html_colours.json")) as f: HTML_COLOURS = json.load(f) -with open(Path("bot", "resources", "evergreen", "xkcd_colours.json")) as f: +with open(Path("bot/resources/evergreen/xkcd_colours.json")) as f: XKCD_COLOURS = json.load(f) COLOURS = [ @@ -51,7 +51,6 @@ class EggDecorating(commands.Cog): Colours are split by spaces, unless you wrap the colour name in double quotes. Discord colour names, HTML colour names, XKCD colour names and hex values are accepted. """ - if len(colours) < 2: return await ctx.send("You must include at least 2 colours!") @@ -72,13 +71,13 @@ class EggDecorating(commands.Cog): return await ctx.send(f"Sorry, I don't know the colour {invalid[0]}!") async with ctx.typing(): - # expand list to 8 colours + # Expand list to 8 colours colours_n = len(colours) if colours_n < 8: q, r = divmod(8, colours_n) colours = colours * q + colours[:r] num = random.randint(1, 6) - im = Image.open(Path("bot", "resources", "easter", "easter_eggs", f"design{num}.png")) + im = Image.open(Path(f"bot/resources/easter/easter_eggs/design{num}.png")) data = list(im.getdata()) replaceable = {x for x in data if x not in IRREPLACEABLE} @@ -113,7 +112,6 @@ class EggDecorating(commands.Cog): def setup(bot): - """Cog load.""" - + """Egg decorating Cog load.""" bot.add_cog(EggDecorating(bot)) log.info("EggDecorating cog loaded.") diff --git a/bot/seasons/easter/egg_hunt/__init__.py b/bot/seasons/easter/egg_hunt/__init__.py index 43bda223..0e4b9e16 100644 --- a/bot/seasons/easter/egg_hunt/__init__.py +++ b/bot/seasons/easter/egg_hunt/__init__.py @@ -7,6 +7,5 @@ log = logging.getLogger(__name__) def setup(bot): """Easter Egg Hunt Cog load.""" - bot.add_cog(EggHunt()) log.info("EggHunt cog loaded") diff --git a/bot/seasons/easter/egg_hunt/cog.py b/bot/seasons/easter/egg_hunt/cog.py index c9e2dc18..30fd3284 100644 --- a/bot/seasons/easter/egg_hunt/cog.py +++ b/bot/seasons/easter/egg_hunt/cog.py @@ -15,7 +15,7 @@ from .constants import Colours, EggHuntSettings, Emoji, Roles log = logging.getLogger(__name__) -DB_PATH = Path("bot", "resources", "persist", "egg_hunt.sqlite") +DB_PATH = Path("bot/resources/persist/egg_hunt.sqlite") TEAM_MAP = { Roles.white: Emoji.egg_white, @@ -31,7 +31,6 @@ MUTED = GUILD.get_role(MainRoles.muted) def get_team_role(user: discord.Member) -> discord.Role: """Helper function to get the team role for a member.""" - if Roles.white in user.roles: return Roles.white if Roles.blurple in user.roles: @@ -40,7 +39,6 @@ def get_team_role(user: discord.Member) -> discord.Role: async def assign_team(user: discord.Member) -> discord.Member: """Helper function to assign a new team role for a member.""" - db = sqlite3.connect(DB_PATH) c = db.cursor() c.execute(f"SELECT team FROM user_scores WHERE user_id = {user.id}") @@ -81,7 +79,6 @@ class EggMessage: @staticmethod def add_user_score_sql(user_id: int, team: str, score: int) -> str: """Builds the SQL for adding a score to a user in the database.""" - return ( "INSERT INTO user_scores(user_id, team, score)" f"VALUES({user_id}, '{team}', {score})" @@ -91,12 +88,10 @@ class EggMessage: @staticmethod def add_team_score_sql(team_name: str, score: int) -> str: """Builds the SQL for adding a score to a team in the database.""" - return f"UPDATE team_scores SET team_score=team_score+{score} WHERE team_id='{team_name}'" def finalise_score(self): """Sums and actions scoring for this egg drop session.""" - db = sqlite3.connect(DB_PATH) c = db.cursor() @@ -139,7 +134,6 @@ class EggMessage: async def start_timeout(self, seconds: int = 5): """Begins a task that will sleep until the given seconds before finalizing the session.""" - if self.timeout_task: self.timeout_task.cancel() self.timeout_task = None @@ -156,7 +150,6 @@ class EggMessage: def is_valid_react(self, reaction: discord.Reaction, user: discord.Member) -> bool: """Validates a reaction event was meant for this session.""" - if user.bot: return False if reaction.message.id != self.message.id: @@ -164,7 +157,7 @@ class EggMessage: if reaction.emoji != self.egg: return False - # ignore the pushished + # Ignore the punished if MUTED in user.roles: return False @@ -172,7 +165,6 @@ class EggMessage: async def collect_reacts(self, reaction: discord.Reaction, user: discord.Member): """Handles emitted reaction_add events via listener.""" - if not self.is_valid_react(reaction, user): return @@ -191,7 +183,6 @@ class EggMessage: async def start(self): """Starts the egg drop session.""" - log.debug(f"EggHunt session started for message {self.message.id}.") bot.add_listener(self.collect_reacts, name="on_reaction_add") with contextlib.suppress(discord.Forbidden): @@ -290,7 +281,6 @@ class SuperEggMessage(EggMessage): async def start_timeout(self, seconds=None): """Starts the super egg session.""" - if not seconds: return count = 4 @@ -348,7 +338,6 @@ class EggHunt(commands.Cog): def prepare_db(self): """Ensures database tables all exist and if not, creates them.""" - db = sqlite3.connect(DB_PATH) c = db.cursor() @@ -370,19 +359,16 @@ class EggHunt(commands.Cog): def task_cleanup(self, task): """Returns task result and restarts. Used as a done callback to show raised exceptions.""" - task.result() self.task = asyncio.create_task(self.super_egg()) @staticmethod def current_timestamp() -> float: """Returns a timestamp of the current UTC time.""" - return datetime.utcnow().replace(tzinfo=timezone.utc).timestamp() async def super_egg(self): """Manages the timing of super egg drops.""" - while True: now = int(self.current_timestamp()) @@ -470,7 +456,6 @@ class EggHunt(commands.Cog): @commands.Cog.listener() async def on_raw_reaction_add(self, payload): """Reaction event listener for reaction logging for later anti-cheat analysis.""" - if payload.channel_id not in EggHuntSettings.allowed_channels: return @@ -487,7 +472,6 @@ class EggHunt(commands.Cog): @commands.Cog.listener() async def on_message(self, message): """Message event listener for random egg drops.""" - if self.current_timestamp() < EggHuntSettings.start_time: return @@ -526,13 +510,11 @@ class EggHunt(commands.Cog): out. They stay around for 5 minutes and the team with the most reacts wins the points. """ - await ctx.invoke(bot.get_command("help"), command="hunt") @hunt.command() async def countdown(self, ctx): """Show the time status of the Egg Hunt event.""" - now = self.current_timestamp() if now > EggHuntSettings.end_time: return await ctx.send("The Hunt has ended.") @@ -551,7 +533,6 @@ class EggHunt(commands.Cog): @hunt.command() async def leaderboard(self, ctx): """Show the Egg Hunt Leaderboards.""" - db = sqlite3.connect(DB_PATH) c = db.cursor() c.execute(f"SELECT *, RANK() OVER(ORDER BY score DESC) AS rank FROM user_scores LIMIT 10") @@ -593,7 +574,6 @@ class EggHunt(commands.Cog): @hunt.command() async def rank(self, ctx, *, member: discord.Member = None): """Get your ranking in the Egg Hunt Leaderboard.""" - member = member or ctx.author db = sqlite3.connect(DB_PATH) c = db.cursor() @@ -614,7 +594,6 @@ class EggHunt(commands.Cog): @hunt.command() async def clear_db(self, ctx): """Resets the database to it's initial state.""" - def check(msg): if msg.author != ctx.author: return False diff --git a/bot/seasons/easter/egghead_quiz.py b/bot/seasons/easter/egghead_quiz.py index 8dd2c21d..3e0cc598 100644 --- a/bot/seasons/easter/egghead_quiz.py +++ b/bot/seasons/easter/egghead_quiz.py @@ -11,7 +11,7 @@ from bot.constants import Colours log = logging.getLogger(__name__) -with open(Path('bot', 'resources', 'easter', 'egghead_questions.json'), 'r', encoding="utf8") as f: +with open(Path("bot/resources/easter/egghead_questions.json"), "r", encoding="utf8") as f: EGGHEAD_QUESTIONS = load(f) @@ -41,7 +41,6 @@ class EggheadQuiz(commands.Cog): Also informs of the percentages and votes of each option """ - random_question = random.choice(EGGHEAD_QUESTIONS) question, answers = random_question["question"], random_question["answers"] answers = [(EMOJIS[i], a) for i, a in enumerate(answers)] @@ -69,7 +68,7 @@ class EggheadQuiz(commands.Cog): total_no = sum([len(await r.users().flatten()) for r in msg.reactions]) - len(valid_emojis) # - bot's reactions if total_no == 0: - return await msg.delete() # to avoid ZeroDivisionError if nobody reacts + return await msg.delete() # To avoid ZeroDivisionError if nobody reacts results = ["**VOTES:**"] for emoji, _ in answers: @@ -115,7 +114,6 @@ class EggheadQuiz(commands.Cog): def setup(bot): - """Cog load.""" - + """Egghead Quiz Cog load.""" bot.add_cog(EggheadQuiz(bot)) log.info("EggheadQuiz bot loaded") diff --git a/bot/seasons/easter/traditions.py b/bot/seasons/easter/traditions.py index 05cd79f3..f04b8828 100644 --- a/bot/seasons/easter/traditions.py +++ b/bot/seasons/easter/traditions.py @@ -7,7 +7,7 @@ from discord.ext import commands log = logging.getLogger(__name__) -with open(Path('bot', 'resources', 'easter', 'traditions.json'), 'r', encoding="utf8") as f: +with open(Path("bot/resources/easter/traditions.json"), "r", encoding="utf8") as f: traditions = json.load(f) @@ -20,7 +20,6 @@ class Traditions(commands.Cog): @commands.command(aliases=('eastercustoms',)) async def easter_tradition(self, ctx): """Responds with a random tradition or custom""" - random_country = random.choice(list(traditions)) await ctx.send(f"{random_country}:\n{traditions[random_country]}") @@ -28,6 +27,5 @@ class Traditions(commands.Cog): def setup(bot): """Traditions Cog load.""" - bot.add_cog(Traditions(bot)) log.info("Traditions cog loaded") |