New home for away, seen, and hunting
This commit is contained in:
10
README.md
10
README.md
@@ -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
88
away/away.py
Normal 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
7
away/info.json
Normal 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
240
hunting/hunting.py
Normal 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
7
hunting/info.json
Normal 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
7
seen/info.json
Normal 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
119
seen/seen.py
Normal 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)
|
||||
Reference in New Issue
Block a user