Red-DiscordBot/cogs/general.py
2016-06-16 23:44:49 +02:00

344 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import discord
from discord.ext import commands
from .utils.chat_formatting import *
from random import randint
from random import choice as randchoice
import datetime
import time
import aiohttp
import asyncio
settings = {"POLL_DURATION" : 60}
class General:
"""General commands."""
def __init__(self, bot):
self.bot = bot
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"]
self.poll_sessions = []
@commands.command(hidden=True)
async def ping(self):
"""Pong."""
await self.bot.say("Pong.")
@commands.command()
async def choose(self, *choices):
"""Chooses between multiple choices.
To denote multiple choices, you should use double quotes.
"""
choices = [escape_mass_mentions(choice) for choice in choices]
if len(choices) < 2:
await self.bot.say('Not enough choices to pick from.')
else:
await self.bot.say(randchoice(choices))
@commands.command(pass_context=True)
async def roll(self, ctx, number : int = 100):
"""Rolls random number (between 1 and user choice)
Defaults to 100.
"""
author = ctx.message.author
if number > 1:
n = str(randint(1, number))
return await self.bot.say("{} :game_die: {} :game_die:".format(author.mention, n))
else:
return await self.bot.say("{} Maybe higher than 1? ;P".format(author.mention))
@commands.command(pass_context=True)
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 == self.bot.user.id:
user = ctx.message.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.name.translate(table)
char = char.upper()
tran = "∀qƆpƎℲפHIſʞ˥WNOԀQᴚS┴∩ΛMX⅄Z"
table = str.maketrans(char, tran)
name = name.translate(table)
return await self.bot.say(msg + "(╯°□°)╯︵ " + name[::-1])
else:
return await self.bot.say("*flips a coin and... " + randchoice(["HEADS!*", "TAILS!*"]))
@commands.command(pass_context=True)
async def rps(self, ctx, choice : str):
"""Play rock paper scissors"""
author = ctx.message.author
rpsbot = {"rock" : ":moyai:",
"paper": ":page_facing_up:",
"scissors":":scissors:"}
choice = choice.lower()
if choice in rpsbot.keys():
botchoice = randchoice(list(rpsbot.keys()))
msgs = {
"win": " You win {}!".format(author.mention),
"square": " We're square {}!".format(author.mention),
"lose": " You lose {}!".format(author.mention)
}
if choice == botchoice:
await self.bot.say(rpsbot[botchoice] + msgs["square"])
elif choice == "rock" and botchoice == "paper":
await self.bot.say(rpsbot[botchoice] + msgs["lose"])
elif choice == "rock" and botchoice == "scissors":
await self.bot.say(rpsbot[botchoice] + msgs["win"])
elif choice == "paper" and botchoice == "rock":
await self.bot.say(rpsbot[botchoice] + msgs["win"])
elif choice == "paper" and botchoice == "scissors":
await self.bot.say(rpsbot[botchoice] + msgs["lose"])
elif choice == "scissors" and botchoice == "rock":
await self.bot.say(rpsbot[botchoice] + msgs["lose"])
elif choice == "scissors" and botchoice == "paper":
await self.bot.say(rpsbot[botchoice] + msgs["win"])
else:
await self.bot.say("Choose rock, paper or scissors.")
@commands.command(name="8", aliases=["8ball"])
async def _8ball(self, *question):
"""Ask 8 ball a question
Question must end with a question mark.
"""
question = " ".join(question)
if question.endswith("?") and question != "?":
return await self.bot.say("`" + randchoice(self.ball) + "`")
else:
return await self.bot.say("That doesn't look like a question.")
@commands.command(aliases=["sw"], pass_context=True)
async def stopwatch(self, ctx):
"""Starts/stops stopwatch"""
author = ctx.message.author
if not author.id in self.stopwatches:
self.stopwatches[author.id] = int(time.perf_counter())
await self.bot.say(author.mention + " Stopwatch started!")
else:
tmp = abs(self.stopwatches[author.id] - int(time.perf_counter()))
tmp = str(datetime.timedelta(seconds=tmp))
await self.bot.say(author.mention + " Stopwatch stopped! Time: **" + str(tmp) + "**")
self.stopwatches.pop(author.id, None)
@commands.command()
async def lmgtfy(self, *, search_terms : str):
"""Creates a lmgtfy link"""
search_terms = escape_mass_mentions(search_terms.replace(" ", "+"))
await self.bot.say("http://lmgtfy.com/?q={}".format(search_terms))
@commands.command(no_pm=True, hidden=True)
async def hug(self, user : discord.Member, intensity : int=1):
"""Because everyone likes hugs
Up to 10 intensity levels."""
name = " *" + user.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 = "(づ ̄ ³ ̄)づ" + name + " ⊂(´・ω・`⊂)"
await self.bot.say(msg)
@commands.command(pass_context=True, no_pm=True)
async def userinfo(self, ctx, user : discord.Member = None):
"""Shows users's informations"""
author = ctx.message.author
if not user:
user = author
roles = [x.name for x in user.roles if x.name != "@everyone"]
if not roles: roles = ["None"]
data = "```python\n"
data += "Name: {}\n".format(escape_mass_mentions(str(user)))
data += "ID: {}\n".format(user.id)
passed = (ctx.message.timestamp - user.created_at).days
data += "Created: {} ({} days ago)\n".format(user.created_at, passed)
passed = (ctx.message.timestamp - user.joined_at).days
data += "Joined: {} ({} days ago)\n".format(user.joined_at, passed)
data += "Roles: {}\n".format(", ".join(roles))
data += "Avatar: {}\n".format(user.avatar_url)
data += "```"
await self.bot.say(data)
@commands.command(pass_context=True, no_pm=True)
async def serverinfo(self, ctx):
"""Shows server's informations"""
server = ctx.message.server
online = str(len([m.status for m in server.members if str(m.status) == "online" or str(m.status) == "idle"]))
total_users = str(len(server.members))
text_channels = len([x for x in server.channels if str(x.type) == "text"])
voice_channels = len(server.channels) - text_channels
data = "```python\n"
data += "Name: {}\n".format(server.name)
data += "ID: {}\n".format(server.id)
data += "Region: {}\n".format(server.region)
data += "Users: {}/{}\n".format(online, total_users)
data += "Text channels: {}\n".format(text_channels)
data += "Voice channels: {}\n".format(voice_channels)
data += "Roles: {}\n".format(len(server.roles))
passed = (ctx.message.timestamp - server.created_at).days
data += "Created: {} ({} days ago)\n".format(server.created_at, passed)
data += "Owner: {}\n".format(server.owner)
data += "Icon: {}\n".format(server.icon_url)
data += "```"
await self.bot.say(data)
@commands.command()
async def urban(self, *, search_terms : str, definition_number : int=1):
"""Urban Dictionary search
Definition number must be between 1 and 10"""
# 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 = "+".join(search_terms)
url = "http://api.urbandictionary.com/v0/define?term=" + search_terms
try:
async with aiohttp.get(url) as r:
result = await r.json()
if result["list"]:
definition = result['list'][pos]['definition']
example = result['list'][pos]['example']
defs = len(result['list'])
await self.bot.say("**Definition #{} out of {}:\n**{}\n\n"
"**Example:\n**{}".format(pos+1, defs, definition, example))
else:
await self.bot.say("Your search terms gave no results.")
except IndexError:
await self.bot.say("There is no definition #{}".format(pos+1))
except:
await self.bot.say("Error.")
@commands.command(pass_context=True, no_pm=True)
async def poll(self, ctx, *text):
"""Starts/stops a poll
Usage example:
poll Is this a poll?;Yes;No;Maybe
poll stop"""
message = ctx.message
if len(text) == 1:
if text[0].lower() == "stop":
await self.endpoll(message)
return
if not self.getPollByChannel(message):
check = " ".join(text).lower()
if "@everyone" in check or "@here" in check:
await self.bot.say("Nice try.")
return
p = NewPoll(message, self)
if p.valid:
self.poll_sessions.append(p)
await p.start()
else:
await self.bot.say("poll question;option1;option2 (...)")
else:
await self.bot.say("A poll is already ongoing in this channel.")
async def endpoll(self, message):
if self.getPollByChannel(message):
p = self.getPollByChannel(message)
if p.author == message.author.id: # or isMemberAdmin(message)
await self.getPollByChannel(message).endPoll()
else:
await self.bot.say("Only admins and the author can stop the poll.")
else:
await self.bot.say("There's no poll ongoing in this channel.")
def getPollByChannel(self, message):
for poll in self.poll_sessions:
if poll.channel == message.channel:
return poll
return False
async def check_poll_votes(self, message):
if message.author.id != self.bot.user.id:
if self.getPollByChannel(message):
self.getPollByChannel(message).checkAnswer(message)
class NewPoll():
def __init__(self, message, main):
self.channel = message.channel
self.author = message.author.id
self.client = main.bot
self.poll_sessions = main.poll_sessions
msg = message.content[6:]
msg = msg.split(";")
if len(msg) < 2: # Needs at least one question and 2 choices
self.valid = False
return None
else:
self.valid = True
self.already_voted = []
self.question = msg[0]
msg.remove(self.question)
self.answers = {}
i = 1
for answer in msg: # {id : {answer, votes}}
self.answers[i] = {"ANSWER" : answer, "VOTES" : 0}
i += 1
async def start(self):
msg = "**POLL STARTED!**\n\n{}\n\n".format(self.question)
for id, data in self.answers.items():
msg += "{}. *{}*\n".format(id, data["ANSWER"])
msg += "\nType the number to vote!"
await self.client.send_message(self.channel, msg)
await asyncio.sleep(settings["POLL_DURATION"])
if self.valid:
await self.endPoll()
async def endPoll(self):
self.valid = False
msg = "**POLL ENDED!**\n\n{}\n\n".format(self.question)
for data in self.answers.values():
msg += "*{}* - {} votes\n".format(data["ANSWER"], str(data["VOTES"]))
await self.client.send_message(self.channel, msg)
self.poll_sessions.remove(self)
def checkAnswer(self, message):
try:
i = int(message.content)
if i in self.answers.keys():
if message.author.id not in self.already_voted:
data = self.answers[i]
data["VOTES"] += 1
self.answers[i] = data
self.already_voted.append(message.author.id)
except ValueError:
pass
def setup(bot):
n = General(bot)
bot.add_listener(n.check_poll_votes, "on_message")
bot.add_cog(n)