New home for away, seen, and hunting

This commit is contained in:
aikaterna
2017-11-15 20:42:31 -08:00
parent 11465d7a9c
commit 8abe72a0fc
7 changed files with 478 additions and 0 deletions

View File

@@ -3,14 +3,24 @@ Cogs for Red-DiscordBot by Twentysix26.
autoeconomy - New users that join the server will be automatically given a bank account.
away - By Paddolicious#8880. Set and unset a user as being "away".
cah - Cards Against Humanity. A port of CorpBot's module: https://github.com/corpnewt/CorpBot.py
chatchart - Generates a pie chart to display chat activity over the last 5000 messages. Requested by violetnyte.
hunting - By Paddolicious#8880. It hunts birds... and things that fly.
imgwelcome - Welcome users to your server with a customized image.
pug - Warcraft pug checker. A port of PugBot's module: https://github.com/reznok/PugBot
riot - an old Fredboat command, requested by Mewleficent.
seen - By Paddolicious#8880. Check when the user was last active on a server.
The chatterbot cog that was previously on this repo has been removed in favor of: https://github.com/Nobleasskicker/GrandeCogs/tree/master/chat
Q: Why do you have some of Paddo's cogs on your repo?
A: He recently made an announcement about finding a new home for a few cogs. I've picked up a couple and I welcome PRs or feature requests. I'm also intending to port these for Red v3 as I can.

88
away/away.py Normal file
View File

@@ -0,0 +1,88 @@
import os
import discord
from .utils import checks
from discord.ext import commands
from cogs.utils.dataIO import dataIO
class Away:
"""Le away cog"""
def __init__(self, bot):
self.bot = bot
self.data = dataIO.load_json('data/away/away.json')
async def listener(self, message):
tmp = {}
server = message.server
if server.id not in self.data:
for mention in message.mentions:
tmp[mention] = True
if message.author.id != self.bot.user.id:
for author in tmp:
if author.id in self.data:
try:
avatar = author.avatar_url if author.avatar else author.default_avatar_url
if self.data[author.id]['MESSAGE']:
em = discord.Embed(description=self.data[author.id]['MESSAGE'], color=discord.Color.blue())
em.set_author(name='{} is currently away'.format(author.display_name), icon_url=avatar)
else:
em = discord.Embed(color=discord.Color.blue())
em.set_author(name='{} is currently away'.format(author.display_name), icon_url=avatar)
await self.bot.send_message(message.channel, embed=em)
except:
if self.data[author.id]['MESSAGE']:
msg = '{} is currently away and has set the following message: `{}`'.format(author.display_name, self.data[author.id]['MESSAGE'])
else:
msg = '{} is currently away'.format(author.display_name)
await self.bot.send_message(message.channel, msg)
@commands.command(pass_context=True, name="away")
async def _away(self, context, *message: str):
"""Tell the bot you're away or back."""
author = context.message.author
if author.id in self.data:
del self.data[author.id]
msg = 'You\'re now back.'
else:
self.data[context.message.author.id] = {}
if len(str(message)) < 256:
self.data[context.message.author.id]['MESSAGE'] = ' '.join(context.message.clean_content.split()[1:])
else:
self.data[context.message.author.id]['MESSAGE'] = True
msg = 'You\'re now set as away.'
dataIO.save_json('data/away/away.json', self.data)
await self.bot.say(msg)
@commands.command(pass_context=True, name="toggleaway")
@checks.mod_or_permissions(administrator=True)
async def _ignore(self, context):
server = context.message.server
if server.id in self.data:
del self.data[server.id]
message = 'Not ignoring this server anymore.'
else:
self.data[server.id] = True
message = 'Ignoring this server.'
dataIO.save_json('data/away/away.json', self.data)
await self.bot.say(message)
def check_folder():
if not os.path.exists('data/away'):
print('Creating data/away folder...')
os.makedirs('data/away')
def check_file():
f = 'data/away/away.json'
if not dataIO.is_valid_json(f):
dataIO.save_json(f, {})
print('Creating default away.json...')
def setup(bot):
check_folder()
check_file()
n = Away(bot)
bot.add_listener(n.listener, 'on_message')
bot.add_cog(n)

7
away/info.json Normal file
View File

@@ -0,0 +1,7 @@
{
"AUTHOR" : "Paddolicious#8880",
"NAME" : "Away",
"SHORT" : "Sets and unsets a user away.",
"DESCRIPTION" : "Sets the user as away. When someone mentions the users the bot replies with either its own message or a message set by the user that the user is away.",
"TAGS": ["away", "member", "tool"]
}

240
hunting/hunting.py Normal file
View File

@@ -0,0 +1,240 @@
from __main__ import send_cmd_help
from .utils.dataIO import dataIO
from discord.ext import commands
from .utils import checks
import datetime
import asyncio
import discord
import random
import time
import os
# TODO
# Show error when timing intervals are the same
class Hunting:
def __init__(self, bot):
self.bot = bot
self.scores = dataIO.load_json('data/hunting/scores.json')
self.subscriptions = dataIO.load_json('data/hunting/subscriptions.json')
self.settings = dataIO.load_json('data/hunting/settings.json')
self.animals = {'duck': ':duck: **_Quack!_**', 'penguin': ':penguin: **_Noot!_**', 'chicken': ':rooster: **_Bah-gawk!_**', 'pigeon': ':dove: **_Coo!_**'}
self.in_game = []
self.paused_games = []
self._latest_message_check_message_limit = 5
self._latest_message_check_wait_limit = self.settings['hunt_interval_maximum'] * 2
self.next = None
async def _save_scores(self):
dataIO.save_json('data/hunting/scores.json', self.scores)
async def _save_subscriptions(self):
dataIO.save_json('data/hunting/subscriptions.json', self.subscriptions)
async def _save_settings(self):
dataIO.save_json('data/hunting/settings.json', self.settings)
@commands.group(pass_context=True, no_pm=True, name='hunting')
async def _hunting(self, context):
"""Hunting, it hunts birds... and things that fly"""
if context.invoked_subcommand is None:
await send_cmd_help(context)
@_hunting.command(pass_context=True, no_pm=True, name='start')
async def _start(self, context):
"""Start the hunt"""
server = context.message.server
channel = context.message.channel
if server.id in self.subscriptions:
message = '**We\'re already hunting!**'
else:
self.subscriptions[server.id] = channel.id
message = '**The hunt has started. Good luck to all.**'
await self._save_subscriptions()
await self.bot.say(message)
@_hunting.command(pass_context=True, no_pm=True, name='stop')
async def _stop(self, context):
"""Stop the hunt"""
server = context.message.server
if server.id not in self.subscriptions:
message = '**We\'re not hunting!**'
else:
del self.subscriptions[server.id]
message = '**The hunt has stopped.**'
await self._save_subscriptions()
await self.bot.say(message)
@_hunting.command(no_pm=True, name='timing')
@checks.is_owner()
async def _timing(self, interval_min: int, interval_max: int, bang_timeout: int):
"""Change the timing"""
if interval_min > interval_max:
message = '**`interval_min` needs to be lower than `interval_max`**'
elif interval_min < 0 and interval_max < 0 and bang_timeout < 0:
message = '**Please no negative numbers!**'
elif interval_min == interval_max:
message = '**`interval_min` and `interval_max` cannot be the same**'
else:
self.settings['hunt_interval_minimum'] = interval_min
self.settings['hunt_interval_maximum'] = interval_max
self.settings['wait_for_bang_timeout'] = bang_timeout
await self._save_settings()
message = '**Timing has been set.**'
await self.bot.say(message)
@_hunting.command(pass_context=True, no_pm=True, name='next')
@checks.is_owner()
async def _next(self, context):
"""When will the next occurance happen?"""
if self.next:
time = abs(datetime.datetime.utcnow() - self.next)
total_seconds = int(time.total_seconds())
hours, remainder = divmod(total_seconds, 60*60)
minutes, seconds = divmod(remainder, 60)
message = '**The next occurance will be in {} hours and {} minutes.**'.format(hours, minutes)
else:
message = '**There is currently no hunt.**'
await self.bot.say(message)
@_hunting.command(pass_context=True, no_pm=True, name='score')
async def _score(self, context, member: discord.Member):
"""This will show the score of a hunter"""
server = context.message.server
if server.id in self.scores:
if member.id in self.scores[server.id]:
message = '**{} shot a total of {} animals ({})**'.format(member.mention, self.scores[server.id][member.id]['total'], ', '.join([str(self.scores[server.id][member.id]['score'][x]) + ' ' + x.capitalize() + 's' for x in self.scores[server.id][member.id]['score']])) # (', '.join([str(self.scores[server.id][member.id]['score'][x]) + ' ' + x.capitalize() + 's' for x in self.scores[server.id][member.id]['score']]))
else:
message = '**Please shoot something before you can brag about it.**'
else:
message = '**Please shoot something before you can brag about it.**'
await self.bot.say(message)
@_hunting.command(pass_context=True, no_pm=True, name='clearscore')
@checks.serverowner()
async def _clearscore(self, context):
"""Clear the leaderboard"""
server = context.message.server
if server.id in self.scores:
self.scores[server.id] = {}
await self._save_scores()
message = 'Leaderboard is cleared'
else:
message = 'There\'s nothing to clear'
await self.bot.say(message)
@_hunting.command(pass_context=True, no_pm=True, name='leaderboard', aliases=['scores'])
async def _huntingboard(self, context):
"""This will show the top hunters on this server"""
server = context.message.server
if server.id in self.scores:
p = self.scores[server.id]
scores = sorted(p, key=lambda x: (p[x]['total']), reverse=True)
message = '```\n{:<4}{:<8}{}\n\n'.format('#', 'TOTAL', 'USERNAME')
for i, hunter in enumerate(scores, 1):
if i > 10:
break
message += '{:<4}{:<8}{} ({})\n'.format(i, p[hunter]['total'], p[hunter]['author_name'], ', '.join([str(p[hunter]['score'][x]) + ' ' + x.capitalize() + 's' for x in p[hunter]['score']]))
message += '```'
else:
message = '**Please shoot something before you can brag about it.**'
await self.bot.say(message)
async def add_score(self, server, author, avian):
if server.id not in self.scores:
self.scores[server.id] = {}
if author.id not in self.scores[server.id]:
self.scores[server.id][author.id] = {}
self.scores[server.id][author.id]['score'] = {}
self.scores[server.id][author.id]['total'] = 0
self.scores[server.id][author.id]['author_name'] = ''
for a in list(self.animals.keys()):
self.scores[server.id][author.id]['score'][a] = 0
if avian not in self.scores[server.id][author.id]['score']:
self.scores[server.id][author.id]['score'][avian] = 0
self.scores[server.id][author.id]['author_name'] = author.display_name
self.scores[server.id][author.id]['score'][avian] += 1
self.scores[server.id][author.id]['total'] += 1
await self._save_scores()
async def _wait_for_bang(self, server, channel):
def check(message):
return message.content.lower().split(' ')[0] == 'bang' or message.content.lower() == 'b' if message.content else False
animal = random.choice(list(self.animals.keys()))
await self.bot.send_message(channel, self.animals[animal])
message = await self.bot.wait_for_message(channel=channel, timeout=self.settings['wait_for_bang_timeout'], check=check)
if message:
author = message.author
if random.randrange(0, 17) > 1:
await self.add_score(server, author, animal)
msg = '**{} shot a {}!**'.format(author.mention, animal)
else:
msg = '**{} missed the shot and the {} got away!**'.format(author.mention, animal)
else:
msg = '**The {} got away!** :confused:'.format(animal)
self.in_game.remove(channel.id)
await self.bot.send_message(channel, msg)
async def _latest_message_check(self, channel):
async for message in self.bot.logs_from(channel, limit=self._latest_message_check_message_limit, reverse=True):
delta = datetime.datetime.utcnow() - message.timestamp
if delta.total_seconds() < self._latest_message_check_wait_limit and message.author.id != self.bot.user.id:
if channel.id in self.paused_games:
self.paused_games.remove(channel.id)
return True
if channel.id not in self.paused_games:
self.paused_games.append(channel.id)
await self.bot.send_message(channel, '**It seems there are no hunters here. The hunt will be resumed when someone treads here again.**')
return False
async def _hunting_loop(self):
while self == self.bot.get_cog('Hunting'):
wait_time = random.randrange(self.settings['hunt_interval_minimum'], self.settings['hunt_interval_maximum'])
self.next = datetime.datetime.fromtimestamp(int(time.mktime(datetime.datetime.utcnow().timetuple())) + wait_time)
await asyncio.sleep(wait_time)
for server in self.subscriptions:
if self.subscriptions[server] not in self.in_game:
channel = self.bot.get_channel(self.subscriptions[server])
server = self.bot.get_server(server)
if await self._latest_message_check(channel):
self.in_game.append(self.subscriptions[server.id])
self.bot.loop = asyncio.get_event_loop()
self.bot.loop.create_task(self._wait_for_bang(server, channel))
def check_folder():
if not os.path.exists('data/hunting'):
print('Creating data/hunting folder...')
os.makedirs('data/hunting')
def check_files():
f = 'data/hunting/settings.json'
if not dataIO.is_valid_json(f):
print('Creating empty settings.json...')
data = {}
data['hunt_interval_minimum'] = 300
data['hunt_interval_maximum'] = 600
data['wait_for_bang_timeout'] = 30
dataIO.save_json(f, data)
f = 'data/hunting/subscriptions.json'
if not dataIO.is_valid_json(f):
print('Creating empty subscriptions.json...')
dataIO.save_json(f, {})
f = 'data/hunting/scores.json'
if not dataIO.is_valid_json(f):
print('Creating empty scores.json...')
dataIO.save_json(f, {})
def setup(bot):
check_folder()
check_files()
cog = Hunting(bot)
loop = asyncio.get_event_loop()
loop.create_task(cog._hunting_loop())
bot.add_cog(cog)

7
hunting/info.json Normal file
View File

@@ -0,0 +1,7 @@
{
"AUTHOR" : "Paddolicious#8880",
"NAME" : "Hunting",
"SHORT" : "Hunting, it hunts birds... and things that fly",
"DESCRIPTION" : "Hunting, it hunts birds... and things that fly",
"TAGS": ["Hunting", "hunt", "birds", "paddo"]
}

7
seen/info.json Normal file
View File

@@ -0,0 +1,7 @@
{
"AUTHOR" : "Paddolicious#8880",
"NAME" : "Seen",
"SHORT" : "Check when the user was last active on a server.",
"DESCRIPTION" : "Check when the user was last active on a server.",
"TAGS": ["Seen", "member", "tools"]
}

119
seen/seen.py Normal file
View File

@@ -0,0 +1,119 @@
from discord.ext import commands
from cogs.utils.dataIO import dataIO
import discord
import os
import asyncio
from datetime import datetime
DB_VERSION = 2
class Seen:
'''Check when someone was last seen.'''
def __init__(self, bot):
self.bot = bot
self.seen = dataIO.load_json('data/seen/seen.json')
self.new_data = False
async def data_writer(self):
while self == self.bot.get_cog('Seen'):
if self.new_data:
dataIO.save_json('data/seen/seen.json', self.seen)
self.new_data = False
await asyncio.sleep(60)
else:
await asyncio.sleep(30)
@commands.command(pass_context=True, no_pm=True, name='seen')
async def _seen(self, context, username: discord.Member):
'''seen <@username>'''
server = context.message.server
author = username
timestamp_now = context.message.timestamp
if server.id in self.seen:
if author.id in self.seen[server.id]:
data = self.seen[server.id][author.id]
timestamp_then = datetime.fromtimestamp(data['TIMESTAMP'])
timestamp = timestamp_now - timestamp_then
days = timestamp.days
seconds = timestamp.seconds
hours = seconds // 3600
seconds = seconds - (hours * 3600)
minutes = seconds // 60
if sum([days, hours, minutes]) < 1:
ts = 'just now'
else:
ts = ''
if days == 1:
ts += '{} day, '.format(days)
elif days > 1:
ts += '{} days, '.format(days)
if hours == 1:
ts += '{} hour, '.format(hours)
elif hours > 1:
ts += '{} hours, '.format(hours)
if minutes == 1:
ts += '{} minute ago'.format(minutes)
elif minutes > 1:
ts += '{} minutes ago'.format(minutes)
em = discord.Embed(color=discord.Color.green())
avatar = author.avatar_url if author.avatar else author.default_avatar_url
em.set_author(name='{} was seen {}'.format(author.display_name, ts), icon_url=avatar)
await self.bot.say(embed=em)
else:
message = 'I haven\'t seen {} yet.'.format(author.display_name)
await self.bot.say('{}'.format(message))
else:
message = 'I haven\'t seen {} yet.'.format(author.display_name)
await self.bot.say('{}'.format(message))
async def on_message(self, message):
if not message.channel.is_private and self.bot.user.id != message.author.id:
if not any(message.content.startswith(n) for n in self.bot.settings.prefixes):
server = message.server
author = message.author
ts = message.timestamp.timestamp()
data = {}
data['TIMESTAMP'] = ts
if server.id not in self.seen:
self.seen[server.id] = {}
self.seen[server.id][author.id] = data
self.new_data = True
def check_folder():
if not os.path.exists('data/seen'):
print('Creating data/seen folder...')
os.makedirs('data/seen')
def check_file():
data = {}
data['db_version'] = DB_VERSION
f = 'data/seen/seen.json'
if not dataIO.is_valid_json(f):
print('Creating seen.json...')
dataIO.save_json(f, data)
else:
check = dataIO.load_json(f)
if 'db_version' in check:
if check['db_version'] < DB_VERSION:
data = {}
data['db_version'] = DB_VERSION
dataIO.save_json(f, data)
print('SEEN: Database version too old, resetting!')
else:
data = {}
data['db_version'] = DB_VERSION
dataIO.save_json(f, data)
print('SEEN: Database version too old, resetting!')
def setup(bot):
check_folder()
check_file()
n = Seen(bot)
loop = asyncio.get_event_loop()
loop.create_task(n.data_writer())
bot.add_cog(n)