From a8745297dcf7cc5ec35ad83df6c0f3033ec623cb Mon Sep 17 00:00:00 2001 From: palmtree5 Date: Sun, 14 May 2017 07:12:32 -0800 Subject: [PATCH] [General] Initial porting (#757) Polls have been removed for now and they will be remade in the future (maybe even as a separate cog) --- cogs/general/__init__.py | 5 + cogs/general/general.py | 335 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 cogs/general/__init__.py create mode 100644 cogs/general/general.py diff --git a/cogs/general/__init__.py b/cogs/general/__init__.py new file mode 100644 index 000000000..04d160dbc --- /dev/null +++ b/cogs/general/__init__.py @@ -0,0 +1,5 @@ +from .general import General + + +def setup(bot): + bot.add_cog(General()) diff --git a/cogs/general/general.py b/cogs/general/general.py new file mode 100644 index 000000000..ab361c13c --- /dev/null +++ b/cogs/general/general.py @@ -0,0 +1,335 @@ +from discord.ext import commands +from core.utils.chat_formatting import escape, italics, pagify +from random import randint, choice +from enum import Enum +from urllib.parse import quote_plus +import discord +import datetime +import time +import aiohttp + + +class RPS(Enum): + rock = "\N{MOYAI}" + paper = "\N{PAGE FACING UP}" + scissors = "\N{BLACK SCISSORS}" + + +class RPSParser: + def __init__(self, argument): + argument = argument.lower() + if argument == "rock": + self.choice = RPS.rock + elif argument == "paper": + self.choice = RPS.paper + elif argument == "scissors": + self.choice = RPS.scissors + else: + raise + + +class General: + """General commands.""" + + def __init__(self): + self.stopwatches = {} + self.ball = [ + "As I see it, yes", "It is certain", "It is decidedly so", + "Most likely", "Outlook good", "Signs point to yes", + "Without a doubt", "Yes", "Yes – definitely", "You may rely on it", + "Reply hazy, try again", "Ask again later", + "Better not tell you now", "Cannot predict now", + "Concentrate and ask again", "Don't count on it", "My reply is no", + "My sources say no", "Outlook not so good", "Very doubtful" + ] + + @commands.command(hidden=True) + async def ping(self, ctx): + """Pong.""" + await ctx.send("Pong.") + + @commands.command() + async def choose(self, ctx, *choices): + """Chooses between multiple choices. + + To denote multiple choices, you should use double quotes. + """ + choices = [escape(c, mass_mentions=True) for c in choices] + if len(choices) < 2: + await ctx.send('Not enough choices to pick from.') + else: + await ctx.send(choice(choices)) + + @commands.command() + async def roll(self, ctx, number : int = 100): + """Rolls random number (between 1 and user choice) + + Defaults to 100. + """ + author = ctx.author + if number > 1: + n = randint(1, number) + await ctx.send( + "{} :game_die: {} :game_die:".format(author.mention, n) + ) + else: + await ctx.send("{} Maybe higher than 1? ;P".format(author.mention)) + + @commands.command() + async def flip(self, ctx, user: discord.Member=None): + """Flips a coin... or a user. + + Defaults to coin. + """ + if user != None: + msg = "" + if user.id == ctx.bot.user.id: + user = ctx.author + msg = "Nice try. You think this is funny?" +\ + "How about *this* instead:\n\n" + char = "abcdefghijklmnopqrstuvwxyz" + tran = "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz" + table = str.maketrans(char, tran) + name = user.display_name.translate(table) + char = char.upper() + tran = "∀qƆpƎℲפHIſʞ˥WNOԀQᴚS┴∩ΛMX⅄Z" + table = str.maketrans(char, tran) + name = name.translate(table) + await ctx.send(msg + "(╯°□°)╯︵ " + name[::-1]) + else: + await ctx.send( + "*flips a coin and... " + choice(["HEADS!*", "TAILS!*"]) + ) + + @commands.command() + async def rps(self, ctx, your_choice : RPSParser): + """Play rock paper scissors""" + author = ctx.author + player_choice = your_choice.choice + red_choice = choice((RPS.rock, RPS.paper, RPS.scissors)) + cond = { + (RPS.rock, RPS.paper) : False, + (RPS.rock, RPS.scissors) : True, + (RPS.paper, RPS.rock) : True, + (RPS.paper, RPS.scissors) : False, + (RPS.scissors, RPS.rock) : False, + (RPS.scissors, RPS.paper) : True + } + + if red_choice == player_choice: + outcome = None # Tie + else: + outcome = cond[(player_choice, red_choice)] + + if outcome is True: + await ctx.send("{} You win {}!".format( + red_choice.value, author.mention + )) + elif outcome is False: + await ctx.send("{} You lose {}!".format( + red_choice.value, author.mention + )) + else: + await ctx.send("{} We're square {}!".format( + red_choice.value, author.mention + )) + + @commands.command(name="8", aliases=["8ball"]) + async def _8ball(self, ctx, *, question : str): + """Ask 8 ball a question + + Question must end with a question mark. + """ + if question.endswith("?") and question != "?": + await ctx.send("`" + choice(self.ball) + "`") + else: + await ctx.send("That doesn't look like a question.") + + @commands.command(aliases=["sw"]) + async def stopwatch(self, ctx): + """Starts/stops stopwatch""" + author = ctx.author + if not author.id in self.stopwatches: + self.stopwatches[author.id] = int(time.perf_counter()) + await ctx.send(author.mention + " Stopwatch started!") + else: + tmp = abs(self.stopwatches[author.id] - int(time.perf_counter())) + tmp = str(datetime.timedelta(seconds=tmp)) + await ctx.send(author.mention + " Stopwatch stopped! Time: **" + tmp + "**") + self.stopwatches.pop(author.id, None) + + @commands.command() + async def lmgtfy(self, ctx, *, search_terms : str): + """Creates a lmgtfy link""" + search_terms = escape(search_terms.replace(" ", "+"), mass_mentions=True) + await ctx.send("https://lmgtfy.com/?q={}".format(search_terms)) + + @commands.command(hidden=True) + @commands.guild_only() + async def hug(self, ctx, user : discord.Member, intensity : int=1): + """Because everyone likes hugs + + Up to 10 intensity levels.""" + name = italics(user.display_name) + if intensity <= 0: + msg = "(っ˘̩╭╮˘̩)っ" + name + elif intensity <= 3: + msg = "(っ´▽`)っ" + name + elif intensity <= 6: + msg = "╰(*´︶`*)╯" + name + elif intensity <= 9: + msg = "(つ≧▽≦)つ" + name + elif intensity >= 10: + msg = "(づ ̄ ³ ̄)づ{} ⊂(´・ω・`⊂)".format(name) + await ctx.send(msg) + + @commands.command() + @commands.guild_only() + async def userinfo(self, ctx, *, user: discord.Member=None): + """Shows users's informations""" + author = ctx.author + guild = ctx.guild + + if not user: + user = author + + # A special case for a special someone :^) + special_date = datetime.datetime(2016, 1, 10, 6, 8, 4, 443000) + is_special = (user.id == 96130341705637888 and + guild.id == 133049272517001216) + + roles = sorted(user.roles)[1:] + + joined_at = user.joined_at if not is_special else special_date + since_created = (ctx.message.created_at - user.created_at).days + since_joined = (ctx.message.created_at - joined_at).days + user_joined = joined_at.strftime("%d %b %Y %H:%M") + user_created = user.created_at.strftime("%d %b %Y %H:%M") + member_number = sorted(guild.members, + key=lambda m: m.joined_at).index(user) + 1 + + created_on = "{}\n({} days ago)".format(user_created, since_created) + joined_on = "{}\n({} days ago)".format(user_joined, since_joined) + + game = "Chilling in {} status".format(user.status) + + if user.game and user.game.name and user.game.url: + game = "Streaming: [{}]({})".format(user.game, user.game.url) + elif user.game and user.game.name: + game = "Playing {}".format(user.game) + + if roles: + roles = ", ".join([x.name for x in roles]) + else: + roles = "None" + + data = discord.Embed(description=game, colour=user.colour) + data.add_field(name="Joined Discord on", value=created_on) + data.add_field(name="Joined this server on", value=joined_on) + data.add_field(name="Roles", value=roles, inline=False) + data.set_footer(text="Member #{} | User ID: {}" + "".format(member_number, user.id)) + + name = str(user) + name = " ~ ".join((name, user.nick)) if user.nick else name + + if user.avatar: + data.set_author(name=name, url=user.avatar_url) + data.set_thumbnail(url=user.avatar_url) + else: + data.set_author(name=name) + + try: + await ctx.send(embed=data) + except discord.HTTPException: + await ctx.send("I need the `Embed links` permission " + "to send this") + + @commands.command() + @commands.guild_only() + async def serverinfo(self, ctx): + """Shows guild's informations""" + guild = ctx.guild + online = len([m.status for m in guild.members + if m.status == discord.Status.online or + m.status == discord.Status.idle]) + total_users = len(guild.members) + text_channels = len(guild.text_channels) + voice_channels = len(guild.voice_channels) + passed = (ctx.message.created_at - guild.created_at).days + created_at = ("Since {}. That's over {} days ago!" + "".format(guild.created_at.strftime("%d %b %Y %H:%M"), + passed)) + + colour = ''.join([choice('0123456789ABCDEF') for x in range(6)]) + colour = randint(0, 0xFFFFFF) + + data = discord.Embed( + description=created_at, + colour=discord.Colour(value=colour)) + data.add_field(name="Region", value=str(guild.region)) + data.add_field(name="Users", value="{}/{}".format(online, total_users)) + data.add_field(name="Text Channels", value=text_channels) + data.add_field(name="Voice Channels", value=voice_channels) + data.add_field(name="Roles", value=len(guild.roles)) + data.add_field(name="Owner", value=str(guild.owner)) + data.set_footer(text="Server ID: " + str(guild.id)) + + if guild.icon_url: + data.set_author(name=guild.name, url=guild.icon_url) + data.set_thumbnail(url=guild.icon_url) + else: + data.set_author(name=guild.name) + + try: + await ctx.send(embed=data) + except discord.HTTPException: + await ctx.send("I need the `Embed links` permission " + "to send this") + + @commands.command() + async def urban(self, ctx, *, search_terms: str, definition_number: int=1): + """Urban Dictionary search + + Definition number must be between 1 and 10""" + def encode(s): + return quote_plus(s, encoding='utf-8', errors='replace') + + # definition_number is just there to show up in the help + # all this mess is to avoid forcing double quotes on the user + + search_terms = search_terms.split(" ") + try: + if len(search_terms) > 1: + pos = int(search_terms[-1]) - 1 + search_terms = search_terms[:-1] + else: + pos = 0 + if pos not in range(0, 11): # API only provides the + pos = 0 # top 10 definitions + except ValueError: + pos = 0 + + search_terms = {"term": "+".join([s for s in search_terms])} + url = "http://api.urbandictionary.com/v0/define" + try: + async with aiohttp.ClientSession() as session: + async with session.get(url, params=search_terms) as r: + result = await r.json() + item_list = result["list"] + if item_list: + definition = item_list[pos]['definition'] + example = item_list[pos]['example'] + defs = len(item_list) + msg = ("**Definition #{} out of {}:\n**{}\n\n" + "**Example:\n**{}".format(pos+1, defs, definition, + example)) + msg = pagify(msg, ["\n"]) + for page in msg: + await ctx.send(page) + else: + await ctx.send("Your search terms gave no results.") + except IndexError: + await ctx.send("There is no definition #{}".format(pos+1)) + except: + await ctx.send("Error.")