diff options
Diffstat (limited to 'bot/seasons')
| -rw-r--r-- | bot/seasons/valentines/lovecalculator.py | 85 |
1 files changed, 50 insertions, 35 deletions
diff --git a/bot/seasons/valentines/lovecalculator.py b/bot/seasons/valentines/lovecalculator.py index b995aef4..aec72ef8 100644 --- a/bot/seasons/valentines/lovecalculator.py +++ b/bot/seasons/valentines/lovecalculator.py @@ -1,70 +1,85 @@ +import bisect +import hashlib import json import logging +import random from pathlib import Path -from random import choice import discord +from discord import Member from discord.ext import commands +from discord.ext.commands import clean_content +from typing import Union from bot.constants import Roles log = logging.getLogger(__name__) -with open(Path("bot", "resources", "valentines", "love_matches.json"), "r") as file: +with Path('bot', 'resources', 'valentines', 'love_matches.json').open() as file: LOVE_DATA = json.load(file) -LOVE_LEVELS = [int(x) for x in LOVE_DATA] + LOVE_DATA = sorted((int(key), value) for key, value in LOVE_DATA.items()) class LoveCalculator: """ A cog for calculating the love between two people """ + def __init__(self, bot): self.bot = bot @commands.command(aliases=('love_calculator', 'love_calc')) - @commands.cooldown(rate=1, per=5.0, type=commands.BucketType.user) - async def love(self, ctx, name_one: discord.Member, name_two: discord.Member = None): + @commands.cooldown(rate=1, per=5, type=commands.BucketType.user) + async def love(self, ctx, who: Union[Member, str], whom: Union[Member, str] = None): """ - Calculates the love between two given names - - DO NOT SPAM @mentions! There are five ways to hand over a name to this command: - 1. ID of the user - 2. Name + Discriminator of the user (name#discrim) (1) - 3. Username (1) - 4. Nickname (1) - 5. @mention - - Using method 1-4 is highly encouraged, as nobody likes unwanted pings + they'll count as spam. - Skipping the second name will lead to something awesome. - - *(1): If the name has any form of spacing, the name must be wrapped inside quotes. Example: - .love Ves Zappa Niko Laus -> Will not work - .love "Ves Zappa" "Niko Laus" -> Will work + Tells you how much the two love each other. """ - - if name_two is None: + # TODO better docstring + # figure out how to cram info about the intricacies of the command somehow + # - member conversion + # - asymmetry + # - consistency (from hashing) + # - need for quotes + # - I'm probably forgetting something + + if whom is None: staff = ctx.guild.get_role(Roles.helpers).members - name_two = choice(staff) - - love_meter = (name_one.id + name_two.id) % 101 - love_idx = str(sorted(x for x in LOVE_LEVELS if x <= love_meter)[-1]) - love_status = choice(LOVE_DATA[love_idx]["titles"]) - + whom = random.choice(staff) + + # if inputs were members, make sure to show name#discrim + # also make sure to escape all discord markdown to prevent mischief + cleaner = clean_content(escape_markdown=True, use_nicknames=False) + who, whom = [await cleaner.convert(ctx, str(arg)) for arg in (who, whom)] + + # hash inputs to guarantee consistent results (hashing algorithm choice arbitrary) + # + # hashlib is used over the builtin hash() function + # to guarantee same result over multiple runtimes + # TODO: make it so `a ab` and `aa b` yield different results? + m = hashlib.sha256(who.encode() + whom.encode()) + # mod 101 for [0, 100] + love_percent = sum(m.digest()) % 101 + + # We need the -1 due to how bisect returns the point + # see the documentation for further detail + # https://docs.python.org/3/library/bisect.html#bisect.bisect + index = bisect.bisect(LOVE_DATA, (love_percent,)) - 1 + # we already have the nearest "fit" love level + # we only need the dict, so we can ditch the first element + _, data = LOVE_DATA[index] + + status = random.choice(data['titles']) embed = discord.Embed( - title=love_status, - description=( - f'{name_one.display_name} \u2764 {name_two.display_name}' - f' scored {love_meter}%!\n\u200b' - ), + title=status, + description=f'{who} \N{HEAVY BLACK HEART} {whom} scored {love_percent}%!\n\u200b', color=discord.Color.dark_magenta() ) embed.add_field( name='A letter from Dr. Love:', - value=LOVE_DATA[love_idx]["text"] + value=data['text'] ) - await ctx.message.channel.send(embed=embed) + await ctx.send(embed=embed) def setup(bot): |