aboutsummaryrefslogtreecommitdiffstats
path: root/bot/seasons/easter
diff options
context:
space:
mode:
Diffstat (limited to 'bot/seasons/easter')
-rw-r--r--bot/seasons/easter/__init__.py4
-rw-r--r--bot/seasons/easter/april_fools_vids.py11
-rw-r--r--bot/seasons/easter/avatar_easterifier.py12
-rw-r--r--bot/seasons/easter/bunny_name_generator.py92
-rw-r--r--bot/seasons/easter/conversationstarters.py4
-rw-r--r--bot/seasons/easter/egg_decorating.py12
-rw-r--r--bot/seasons/easter/egg_hunt/__init__.py1
-rw-r--r--bot/seasons/easter/egg_hunt/cog.py25
-rw-r--r--bot/seasons/easter/egghead_quiz.py8
-rw-r--r--bot/seasons/easter/traditions.py4
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")