Merge branch 'master' into nudity-develop

# Conflicts:
#	nudity/info..json
pull/116/head
bobloy 6 years ago
commit 81cb93a6aa

@ -3,25 +3,35 @@
Cog Function Cog Function
| Name | Status | Description (Click to see full status) | Name | Status | Description (Click to see full status)
| --- | --- | --- | | --- | --- | --- |
| announcedaily | **Alpha** | <details><summary>Send daily announcements to all servers at a specified times</summary>Commissioned release, so suggestions will not be accepted</details> |
| audiotrivia | **Alpha** | <details><summary>Guess the audio using the core trivia cog</summary>Replaces the core Trivia cog. Needs help adding audio trivia lists, please submit a PR to contribute</details> |
| ccrole | **Beta** | <details><summary>Create custom commands that also assign roles</summary>May have some bugs, please create an issue if you find any</details> | | ccrole | **Beta** | <details><summary>Create custom commands that also assign roles</summary>May have some bugs, please create an issue if you find any</details> |
| chatter | **Alpha** | <details><summary>Chat-bot trained to talk like your guild</summary>Missing some key features, but currently functional</details> | | chatter | **Alpha** | <details><summary>Chat-bot trained to talk like your guild</summary>Missing some key features, but currently functional</details> |
| coglint | **Alpha** | <details><summary>Error check code in python syntax posted to discord</summary>Works, but probably needs more turning to work for cogs</details> | | coglint | **Alpha** | <details><summary>Error check code in python syntax posted to discord</summary>Works, but probably needs more turning to work for cogs</details> |
| exclusiverole | **Alpha** | <details><summary>Prevent certain roles from getting any other roles</summary>Fully functional, but pretty simple</details> |
| fight | **Incomplete** | <details><summary>Organize bracket tournaments within discord</summary>Still in-progress, a massive project</details> | | fight | **Incomplete** | <details><summary>Organize bracket tournaments within discord</summary>Still in-progress, a massive project</details> |
| flag | **Alpha** | <details><summary>Create temporary marks on users that expire after specified time</summary>Ported, will not import old data. Please report bugs</details> | | flag | **Alpha** | <details><summary>Create temporary marks on users that expire after specified time</summary>Ported, will not import old data. Please report bugs</details> |
| forcemention | **Alpha** | <details><summary>Mentions unmentionable roles</summary>Very simple cog, mention doesn't persist</details> | | forcemention | **Alpha** | <details><summary>Mentions unmentionable roles</summary>Very simple cog, mention doesn't persist</details> |
| hangman | **Alpha** | <details><summary>Play a game of hangman</summary>Some visual glitches and needs more customization</details> | | hangman | **Alpha** | <details><summary>Play a game of hangman</summary>Some visual glitches and needs more customization</details> |
| howdoi | **Incomplete** | <details><summary>Ask coding questions and get results from StackExchange</summary>Not yet functional</details> | | howdoi | **Incomplete** | <details><summary>Ask coding questions and get results from StackExchange</summary>Not yet functional</details> |
| leaver | **Alpha** | <details><summary>Send a message in a channel when a user leaves the server</summary>Just released, please report bugs</details> | | leaver | **Alpha** | <details><summary>Send a message in a channel when a user leaves the server</summary>Just released, please report bugs</details> |
| lovecalculator | **Alpha** | <details><summary>Calculate the love between two users</summary>[Snap-Ons] Just updated to V3</details> |
| lseen | **Alpha** | <details><summary>Track when a member was last online</summary>Alpha release, please report bugs</details> | | lseen | **Alpha** | <details><summary>Track when a member was last online</summary>Alpha release, please report bugs</details> |
| nudity | **Incomplete** | <details><summary>Checks for NSFW images posted in non-NSFW channels</summary>Library this is based on has a bug, waiting for author to merge my PR</details> |
| planttycoon | **Alpha** | <details><summary>Grow your own plants!</summary>[Snap-Ons] Updated to V3, likely to contain bugs</details> |
| qrinvite | **Alpha** | <details><summary>Create a QR code invite for the server</summary>Alpha release, please report any bugs</details> |
| reactrestrict | **Alpha** | <details><summary>Removes reactions by role per channel</summary>A bit clunky, but functional</details> | | reactrestrict | **Alpha** | <details><summary>Removes reactions by role per channel</summary>A bit clunky, but functional</details> |
| recyclingplant | **Alpha** | <details><summary>Work at a recycling plant</summary>[Snap-Ons] Just updated to V3</details> |
| rpsls | **Alpha** | <details><summary>Play Rock-Paper-Scissors-Lizard-Spock</summary>[Snap-Ons] Just updated to V3</details> |
| sayurl | **Alpha** | <details><summary>Convert any URL into text and post to discord</summary>No error checking and pretty spammy</details> | | sayurl | **Alpha** | <details><summary>Convert any URL into text and post to discord</summary>No error checking and pretty spammy</details> |
| scp | **Alpha** | <details><summary>Look-up SCP articles</summary>[Snap-Ons] Just updated to V3</details> |
| secrethitler | **Incomplete** | <details><summary>Play the Secret Hitler game</summary>Concept, no work done yet</details> | | secrethitler | **Incomplete** | <details><summary>Play the Secret Hitler game</summary>Concept, no work done yet</details> |
| stealemoji | **Alpha** | <details><summary>Steals any custom emoji it sees in a reaction</summary>Some planned upgrades for server generation</details> | | stealemoji | **Alpha** | <details><summary>Steals any custom emoji it sees in a reaction</summary>Some planned upgrades for server generation</details> |
| timerole | **Alpha** | <details><summary>Add roles to members after specified time on the server</summary>Upgraded from V2, please report any bugs</details> | | timerole | **Alpha** | <details><summary>Add roles to members after specified time on the server</summary>Upgraded from V2, please report any bugs</details> |
| tts | **Alpha** | <details><summary>Send a Text-to-Speech message as an uploaded mp3</summary>Alpha release, please report any bugs</details> | | tts | **Beta** | <details><summary>Send a Text-to-Speech message as an uploaded mp3</summary>Alpha release, please report any bugs</details> |
| qrinvite | **Alpha** | <details><summary>Create a QR code invite for the server</summary>Alpha release, please report any bugs</details> | | unicode | **Alpha** | <details><summary>Encode and Decode unicode characters</summary>[Snap-Ons] Just updated to V3</details> |
| werewolf | **Alpha** | <details><summary>Play the classic party game Werewolf within discord</summary>Another massive project currently being developed, will be fully customizable</details> | | werewolf | **Pre-Alpha** | <details><summary>Play the classic party game Werewolf within discord</summary>Another massive project currently being developed, will be fully customizable</details> |
Check out my V2 cogs at [Fox-Cogs v2](https://github.com/bobloy/Fox-Cogs) Check out my V2 cogs at [Fox-Cogs v2](https://github.com/bobloy/Fox-Cogs)

@ -0,0 +1,9 @@
from redbot.core.bot import Red
from .announcedaily import AnnounceDaily
def setup(bot: Red):
daily = AnnounceDaily(bot)
bot.add_cog(daily)
bot.loop.create_task(daily.check_day())

@ -0,0 +1,253 @@
import asyncio
import random
from datetime import datetime, timedelta
from typing import Any
import discord
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.data_manager import cog_data_path
from redbot.core.utils.chat_formatting import pagify, box
DEFAULT_MESSAGES = [
# "Example message. Uncomment and overwrite to use",
# "Example message 2. Each message is in quotes and separated by a comma"
]
Cog: Any = getattr(commands, "Cog", object)
class AnnounceDaily(Cog):
"""
Send daily announcements
"""
def __init__(self, bot: Red):
self.bot = bot
self.path = str(cog_data_path(self)).replace('\\', '/')
self.image_path = self.path + "/"
self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
default_global = {
'messages': [],
'images': [],
'time': {'hour': 0, 'minute': 0, 'second': 0}
}
default_guild = {
"channelid": None
}
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
async def _get_msgs(self):
return DEFAULT_MESSAGES + await self.config.messages()
@commands.group(name="announcedaily", aliases=['annd'])
@checks.mod_or_permissions(administrator=True)
@commands.guild_only()
async def _ad(self, ctx: commands.Context):
"""
Base command for managing AnnounceDaily settings
Do `[p]help annd <subcommand>` for more details
"""
if ctx.invoked_subcommand is None:
pass
@commands.command()
@checks.guildowner()
@commands.guild_only()
async def runannounce(self, ctx: commands.Context):
"""Manually run the daily announcement"""
await self.send_announcements()
await ctx.send("Success")
@_ad.command()
async def setchannel(self, ctx: commands.Context, channel: discord.TextChannel = None):
"""
Set the announcement channel for this server
Don't pass a channel to clear this server of receiving announcements
"""
if channel is not None:
await self.config.guild(ctx.guild).channelid.set(channel.id)
await ctx.send("Announcement channel has been set to {}".format(channel.mention))
else:
await self.config.guild(ctx.guild).channelid.set(None)
await ctx.send("Announcement channel has been cleared")
@_ad.command()
async def addmsg(self, ctx: commands.Context, *, msg):
"""
Add a message to the pool of announcement messages
"""
async with self.config.messages() as msgs:
msgs.append(msg)
await ctx.send("Message successfully added!")
@_ad.command()
async def addimg(self, ctx: commands.Context, filename=None):
"""
Add an image to the pool of announcement images
You must attach an image while executing this command
"""
if ctx.message.attachments:
att_ = ctx.message.attachments[0]
try:
h = att_.height
except AttributeError:
await ctx.send("You must attach an image, no other file will be accepted")
return
if filename is None:
filename = att_.filename
try:
# with open(self.image_path + filename, 'w') as f:
# await att_.save(f)
await att_.save(self.image_path + filename)
except discord.NotFound:
await ctx.send("Did you delete the message? Cause I couldn't download the attachment")
except discord.HTTPException:
await ctx.send("Failed to download the attachment, please try again")
else:
async with self.config.images() as images:
if filename in images:
await ctx.send("Image {} has been overwritten!".format(filename))
else:
images.append(filename)
await ctx.send("Image {} has been added!".format(filename))
else:
await ctx.send("You must attach an image when sending this command")
@_ad.command()
async def listmsg(self, ctx: commands.Context):
"""
List all registered announcement messages
"""
messages = await self.config.messages()
for page in pagify("\n".join("{} - {}".format(key, image) for key, image in enumerate(messages))):
await ctx.send(box(page))
await ctx.send("Done!")
@_ad.command()
async def listimg(self, ctx: commands.Context):
"""
List all registered announcement immages
"""
images = await self.config.images()
for page in pagify("\n".join(images)):
await ctx.send(box(page))
await ctx.send("Done!")
@_ad.command()
async def delmsg(self, ctx: commands.Context, index: int):
"""
Remove a message from the announcement pool
Must provide the index of the message, which can be found by using `[p]annd listmsg`
"""
async with self.config.messages() as messages:
try:
out = messages.pop(index)
except IndexError:
await ctx.send("Invalid index, check valid indexes with `listmsg` command")
return
await ctx.send("The following message was removed:\n```{}```".format(out))
@_ad.command()
async def delimg(self, ctx: commands.Context, filename: str):
"""
Remove an image from the announcement pool
Does not delete the file from the disk, so you may have to clean it up occasionally
"""
async with self.config.images() as images:
if filename not in images:
await ctx.send("This file doesn't exist")
else:
images.remove(filename)
await ctx.send("Successfully removed {}".format(filename))
@_ad.command()
async def settime(self, ctx: commands.Context, minutes_from_now: int):
"""
Set the daily announcement time
It will first announce at the time you provided, then it will repeat every 24 hours
"""
ann_time = datetime.now() + timedelta(minutes=minutes_from_now)
h = ann_time.hour
m = ann_time.minute
s = ann_time.second
await self.config.time.set({'hour': h, 'minute': m, 'second': s})
await ctx.send("Announcements time has been set to {}::{}::{} every day\n"
"**Changes will apply after next scheduled announcement or reload**".format(h, m, s))
async def send_announcements(self):
messages = await self._get_msgs()
images = await self.config.images()
total = len(messages) + len(images)
if total < 1:
return
x = random.randint(0, total - 1)
if x >= len(messages):
x -= len(messages)
choice = images[x]
choice = open(self.image_path + choice, 'rb')
is_image = True
else:
choice = messages[x]
is_image = False
for guild in self.bot.guilds:
channel = await self.config.guild(guild).channelid()
if channel is None:
continue
channel = guild.get_channel(channel)
if channel is None:
continue
if is_image:
await channel.send(file=discord.File(choice))
else:
await channel.send(choice)
async def check_day(self):
while self is self.bot.get_cog("AnnounceDaily"):
tomorrow = datetime.now() + timedelta(days=1)
time = await self.config.time()
h, m, s = time['hour'], time['minute'], time['second']
midnight = datetime(year=tomorrow.year, month=tomorrow.month,
day=tomorrow.day, hour=h, minute=m, second=s)
print("Sleeping for {} seconds".format((midnight - datetime.now()).seconds))
await asyncio.sleep((midnight - datetime.now()).seconds)
if self is not self.bot.get_cog("AnnounceDaily"):
print("Announce canceled, cog has been lost")
return
await self.send_announcements()
await asyncio.sleep(3)
# [p]setchannel #channelname - Set the announcement channel per server
# [p]addmsg <message goes here> - Adds a msg to the pool
# [p]addimg http://imgurl.com/image.jpg - Adds an image to the pool
# [p]listmsg - Lists all messages in the pool
# [p]listimg - Unsure about this one, but would probably just post all the images
# [p]delmsg - Remove msg from pool
# [p]delimg - Remove image from pool
# [p]settime <x> - S

@ -0,0 +1,18 @@
{
"author": [
"Bobloy"
],
"bot_version": [
3,
0,
0
],
"description": "Send daily announcements to all servers at a specified times",
"hidden": true,
"install_msg": "Thank you for installing AnnounceDaily! Get started with `[p]load announcedaily` and `[p]help AnnounceDaily`",
"requirements": [],
"short": "Send daily announcements",
"tags": [
"bobloy"
]
}

@ -0,0 +1,13 @@
from redbot.core.bot import Red
from .audiotrivia import AudioTrivia
async def setup(bot: Red):
if bot.get_cog("Trivia"):
print("Trivia is already loaded, attempting to unload it first")
bot.remove_cog("Trivia")
await bot.remove_loaded_package("trivia")
bot.unload_extension("trivia")
bot.add_cog(AudioTrivia(bot))

@ -0,0 +1,74 @@
"""Module to manage audio trivia sessions."""
import asyncio
import lavalink
from redbot.cogs.trivia import TriviaSession
class AudioSession(TriviaSession):
"""Class to run a session of audio trivia"""
def __init__(self, ctx, question_list: dict, settings: dict, player: lavalink.Player):
super().__init__(ctx, question_list, settings)
self.player = player
@classmethod
def start(cls, ctx, question_list, settings, player: lavalink.Player = None):
session = cls(ctx, question_list, settings, player)
loop = ctx.bot.loop
session._task = loop.create_task(session.run())
return session
async def run(self):
"""Run the audio trivia session.
In order for the trivia session to be stopped correctly, this should
only be called internally by `TriviaSession.start`.
"""
await self._send_startup_msg()
max_score = self.settings["max_score"]
delay = self.settings["delay"]
timeout = self.settings["timeout"]
for question, answers in self._iter_questions():
async with self.ctx.typing():
await asyncio.sleep(3)
self.count += 1
await self.player.stop()
msg = "**Question number {}!**\n\nName this audio!".format(self.count)
await self.ctx.send(msg)
# print("Audio question: {}".format(question))
# await self.ctx.invoke(self.audio.play(ctx=self.ctx, query=question))
# ctx_copy = copy(self.ctx)
# await self.ctx.invoke(self.player.play, query=question)
query = question.strip("<>")
tracks = await self.player.get_tracks(query)
seconds = tracks[0].length / 1000
if self.settings["repeat"] and seconds < delay:
tot_length = seconds + 0
while tot_length < delay:
self.player.add(self.ctx.author, tracks[0])
tot_length += seconds
else:
self.player.add(self.ctx.author, tracks[0])
if not self.player.current:
await self.player.play()
continue_ = await self.wait_for_answer(answers, delay, timeout)
if continue_ is False:
break
if any(score >= max_score for score in self.scores.values()):
await self.end_game()
break
else:
await self.ctx.send("There are no more questions!")
await self.end_game()
async def end_game(self):
await super().end_game()
await self.player.disconnect()

@ -0,0 +1,212 @@
import datetime
import pathlib
from typing import List
import lavalink
import yaml
from redbot.cogs.audio import Audio
from redbot.cogs.trivia import LOG
from redbot.cogs.trivia.trivia import InvalidListError, Trivia
from redbot.core import commands, Config, checks
from redbot.core.bot import Red
from redbot.core.data_manager import cog_data_path
from redbot.core.utils.chat_formatting import box
from .audiosession import AudioSession
class AudioTrivia(Trivia):
"""
Custom commands
Creates commands used to display text and adjust roles
"""
def __init__(self, bot: Red):
super().__init__()
self.bot = bot
self.audio = None
self.audioconf = Config.get_conf(self, identifier=651171001051118411410511810597, force_registration=True)
self.audioconf.register_guild(
delay=30.0,
repeat=True,
)
@commands.group()
@commands.guild_only()
@checks.mod_or_permissions(administrator=True)
async def atriviaset(self, ctx: commands.Context):
"""Manage Audio Trivia settings."""
audioset = self.audioconf.guild(ctx.guild)
settings_dict = await audioset.all()
msg = box(
"**Audio settings**\n"
"Answer time limit: {delay} seconds\n"
"Repeat Short Audio: {repeat}"
"".format(**settings_dict),
lang="py",
)
await ctx.send(msg)
@atriviaset.command(name="delay")
async def atriviaset_delay(self, ctx: commands.Context, seconds: float):
"""Set the maximum seconds permitted to answer a question."""
if seconds < 4.0:
await ctx.send("Must be at least 4 seconds.")
return
settings = self.audioconf.guild(ctx.guild)
await settings.delay.set(seconds)
await ctx.send("Done. Maximum seconds to answer set to {}.".format(seconds))
@atriviaset.command(name="repeat")
async def atriviaset_repeat(self, ctx: commands.Context, true_or_false: bool):
"""Set whether or not short audio will be repeated"""
settings = self.audioconf.guild(ctx.guild)
await settings.repeat.set(true_or_false)
await ctx.send("Done. Repeating short audio is now set to {}.".format(true_or_false))
@commands.group(invoke_without_command=True)
@commands.guild_only()
async def audiotrivia(self, ctx: commands.Context, *categories: str):
"""Start trivia session on the specified category.
You may list multiple categories, in which case the trivia will involve
questions from all of them.
"""
if not categories and ctx.invoked_subcommand is None:
await ctx.send_help()
return
if self.audio is None:
self.audio: Audio = self.bot.get_cog("Audio")
if self.audio is None:
await ctx.send("Audio is not loaded. Load it and try again")
return
categories = [c.lower() for c in categories]
session = self._get_trivia_session(ctx.channel)
if session is not None:
await ctx.send("There is already an ongoing trivia session in this channel.")
return
status = await self.audio.config.status()
if status:
await ctx.send("I recommend disabling audio status with `{}audioset status`".format(ctx.prefix))
if not self.audio._player_check(ctx):
try:
if not ctx.author.voice.channel.permissions_for(ctx.me).connect or self.audio._userlimit(
ctx.author.voice.channel
):
return await ctx.send("I don't have permission to connect to your channel."
)
await lavalink.connect(ctx.author.voice.channel)
lavaplayer = lavalink.get_player(ctx.guild.id)
lavaplayer.store("connect", datetime.datetime.utcnow())
except AttributeError:
return await ctx.send("Connect to a voice channel first.")
lavaplayer = lavalink.get_player(ctx.guild.id)
lavaplayer.store("channel", ctx.channel.id) # What's this for? I dunno
lavaplayer.store("guild", ctx.guild.id)
await self.audio._data_check(ctx)
if (
not ctx.author.voice or ctx.author.voice.channel != lavaplayer.channel
):
return await ctx.send("You must be in the voice channel to use the audiotrivia command.")
trivia_dict = {}
authors = []
for category in reversed(categories):
# We reverse the categories so that the first list's config takes
# priority over the others.
try:
dict_ = self.get_audio_list(category)
except FileNotFoundError:
await ctx.send(
"Invalid category `{0}`. See `{1}audiotrivia list`"
" for a list of trivia categories."
"".format(category, ctx.prefix)
)
except InvalidListError:
await ctx.send(
"There was an error parsing the trivia list for"
" the `{}` category. It may be formatted"
" incorrectly.".format(category)
)
else:
trivia_dict.update(dict_)
authors.append(trivia_dict.pop("AUTHOR", None))
continue
return
if not trivia_dict:
await ctx.send(
"The trivia list was parsed successfully, however it appears to be empty!"
)
return
settings = await self.conf.guild(ctx.guild).all()
audiosettings = await self.audioconf.guild(ctx.guild).all()
config = trivia_dict.pop("CONFIG", None)
if config and settings["allow_override"]:
settings.update(config)
settings["lists"] = dict(zip(categories, reversed(authors)))
# Delay in audiosettings overwrites delay in settings
combined_settings = {**settings, **audiosettings}
session = AudioSession.start(ctx=ctx, question_list=trivia_dict, settings=combined_settings, player=lavaplayer)
self.trivia_sessions.append(session)
LOG.debug("New audio trivia session; #%s in %d", ctx.channel, ctx.guild.id)
@audiotrivia.command(name="list")
@commands.guild_only()
async def audiotrivia_list(self, ctx: commands.Context):
"""List available trivia categories."""
lists = set(p.stem for p in self._audio_lists())
msg = box("**Available trivia lists**\n\n{}".format(", ".join(sorted(lists))))
if len(msg) > 1000:
await ctx.author.send(msg)
return
await ctx.send(msg)
def get_audio_list(self, category: str) -> dict:
"""Get the audiotrivia list corresponding to the given category.
Parameters
----------
category : str
The desired category. Case sensitive.
Returns
-------
`dict`
A dict mapping questions (`str`) to answers (`list` of `str`).
"""
try:
path = next(p for p in self._audio_lists() if p.stem == category)
except StopIteration:
raise FileNotFoundError("Could not find the `{}` category.".format(category))
with path.open(encoding="utf-8") as file:
try:
dict_ = yaml.load(file)
except yaml.error.YAMLError as exc:
raise InvalidListError("YAML parsing failed.") from exc
else:
return dict_
def _audio_lists(self) -> List[pathlib.Path]:
personal_lists = [p.resolve() for p in cog_data_path(self).glob("*.yaml")]
return personal_lists + get_core_lists()
def get_core_lists() -> List[pathlib.Path]:
"""Return a list of paths for all trivia lists packaged with the bot."""
core_lists_path = pathlib.Path(__file__).parent.resolve() / "data/lists"
return list(core_lists_path.glob("*.yaml"))

@ -0,0 +1,106 @@
AUTHOR: bobloy
https://www.youtube.com/watch?v=nfjiy-NX5b0:
- flashbang
https://www.youtube.com/watch?v=mJCE7s4W4IE:
- starting round
- round start
- start round
https://www.youtube.com/watch?v=XfLGi4cPu0Y:
- select team
- team select
https://www.youtube.com/watch?v=b6ScVgFs-DQ:
- desert eagle
- deagle
https://www.youtube.com/watch?v=JnHm-rn199Y:
- planted bomb
- bomb planted
- bomb plant
- plant bomb
https://www.youtube.com/watch?v=3wztV24tbVU:
- defusing bomb
- defuse bomb
- bomb defuse
- bomb defusing
https://www.youtube.com/watch?v=mpY9poBVje4:
- lobby
https://www.youtube.com/watch?v=zMT4ovCN7gk:
- usp-s
- usp s
- usps
https://www.youtube.com/watch?v=oI5Ww7y2aUQ:
- gut knife
https://www.youtube.com/watch?v=Dqmyxnx-OaQ:
- ak47
- ak 47
https://www.youtube.com/watch?v=Ny4hGdziZP4:
- hitmarker
- hit
- hitmaker
- marker
https://www.youtube.com/watch?v=vYUynDKM1Yw:
- awp
https://www.youtube.com/watch?v=52etXKmbQRM:
- butterfly knife
https://www.youtube.com/watch?v=99o4eyq0SzY:
- won round
- round won
- win round
- round win
https://www.youtube.com/watch?v=V5tv1ZzqI_U:
- lost round
- round lost
- lose round
- round loss
https://www.youtube.com/watch?v=1hI25OPdim0:
- flashbang toss
- toss flashbang
- throwing flashbang
- throw flashbang
- flashbang throwing
- flashbang throw
- tossing flashbang
- flashbang tossing
https://www.youtube.com/watch?v=oML0z2Aj_D4:
- firegrenade toss
- toss firegrenade
- throwing firegrenade
- throw firegrenade
- firegrenade throwing
- firegrenade throw
- tossing firegrenade
- firegrenade tossing
- fire grenade toss
- toss fire grenade
- throwing fire grenade
- throw fire grenade
- fire grenade throwing
- fire grenade throw
- tossing fire grenade
- fire grenade tossing
https://www.youtube.com/watch?v=9otQ9OLfaQc:
- grenade out
https://www.youtube.com/watch?v=tFA-8Vc32Kg:
- famas
https://www.youtube.com/watch?v=MdI1u8oXKZw:
- awp zoom
- zoom awp
- awp scope
- scope awp
https://www.youtube.com/watch?v=6NiZhX4h32Q:
- c4
https://www.youtube.com/watch?v=3N0NxsyWPiY:
- planting c4
- c4 planting
- plant c4
- c4 plant
https://www.youtube.com/watch?v=XLaJIXZ5QUc:
- awp
https://www.youtube.com/watch?v=DmuK9Wml88E:
- P90
https://www.youtube.com/watch?v=t1Ky_TbDXHY:
- smoke
https://www.youtube.com/watch?v=sJvdTbejDRY:
- kill bonus
https://www.youtube.com/watch?v=DYWi8qdvWCk:
- AK47
- AK 47

File diff suppressed because it is too large Load Diff

@ -0,0 +1,304 @@
AUTHOR: bobloy
https://www.youtube.com/watch?v=FrceWR4XnVU:
- shovel knight
https://www.youtube.com/watch?v=Fn0khIn2wfc:
- super mario world
https://www.youtube.com/watch?v=qkYSuWSPkHI:
- the legend of zelda
- legend of zelda
- zelda
https://www.youtube.com/watch?v=0hvlwLwxweI:
- dragon quest ix
- dragon quest 9
https://www.youtube.com/watch?v=GxrKe9z4CCo:
- chrono trigger
https://www.youtube.com/watch?v=pz3BQFXjEOI:
- super smash bros melee
- super smash bros. melee
- super smash brothers melee
https://www.youtube.com/watch?v=l_ioujmtqjg:
- super mario bros
- super mario brothers
- super mario bros.
https://www.youtube.com/watch?v=zTztR_y9iHc:
- banjo-kazooie
- banjo kazooie
https://www.youtube.com/watch?v=6gWyfQFdMJA:
- metroid samus returns
https://www.youtube.com/watch?v=0jXTBAGv9ZQ:
- halo
https://www.youtube.com/watch?v=Rhaq4JP_t6o:
- the elder scrolls iii morrowind
- morrowind
- elder scrolls iii
- elder scrolls 3
https://www.youtube.com/watch?v=ZksNhHyEhE0:
- sonic generations
https://www.youtube.com/watch?v=lndBgOrTWxo:
- donkey kong country 2
- donkey kong country two
https://www.youtube.com/watch?v=uTEMsmLoEA4:
- mario kart 8
- mario kart eight
https://www.youtube.com/watch?v=WA2WjP6sgrc:
- donkey kong country tropical freeze
- tropical freeze
https://www.youtube.com/watch?v=9wMjq58Fjvo:
- castle crashers
https://www.youtube.com/watch?v=sr2nK06zZkg:
- shadow of the colossus
https://www.youtube.com/watch?v=6CMTXyExkeI:
- final fantasy v
- final fantasy 5
https://www.youtube.com/watch?v=nRbROTdOgj0:
- legend of zelda skyward sword
- skyward sword
https://www.youtube.com/watch?v=LFcH84oNU6s:
- skies of arcadia
https://www.youtube.com/watch?v=VEIWhy-urqM:
- super mario galaxy
https://www.youtube.com/watch?v=IT12DW2Fm9M:
- final fantasy iv
- final fantasy 4
https://www.youtube.com/watch?v=UZbqrZJ9VA4:
- mother3
- mother 3
https://www.youtube.com/watch?v=o_ayLF9vdls:
- dragon age origins
https://www.youtube.com/watch?v=eVVXNDv8rY0:
- the elder scrolls v skyrim
- elder scrolls v
- elder scrolls 5
- the elder scrolls 5 skyrim
- skyrim
https://www.youtube.com/watch?v=kzvZE4BY0hY:
- fallout 4
https://www.youtube.com/watch?v=VTsD2FjmLsw:
- mass effect 2
https://www.youtube.com/watch?v=800be1ZmGd0:
- world of warcraft
https://www.youtube.com/watch?v=SXKrsJZWqK0:
- batman arkham city
- arkham city
https://www.youtube.com/watch?v=BLEBtvOhGnM:
- god of war iii
- god of war 3
https://www.youtube.com/watch?v=rxgTlQLm4Xg:
- gears of war 3
https://www.youtube.com/watch?v=QiPon8lr48U:
- metal gear solid 2
https://www.youtube.com/watch?v=qDnaIfiH37w:
- super smash bros wii u
- super smash bros. wii u
- super smash brothers wii u
- super smash bros wiiu
- super smash bros. wiiu
- super smash brothers wiiu
https://www.youtube.com/watch?v=_Uzlm2MaCWw:
- mega man maverick hunter x
- megaman maverick hunter x
- maverick hunter x
https://www.youtube.com/watch?v=-8wo0KBQ3oI:
- doom
https://www.youtube.com/watch?v=TN36CetQw6I:
- super smash bros brawl
- super smash bros. brawl
- super smash brothers brawl
https://www.youtube.com/watch?v=01IEjvD5lss:
- guilty gear
https://www.youtube.com/watch?v=VXX4Ft1I0Dw:
- dynasty warriors 6
https://www.youtube.com/watch?v=liRMh4LzQQU:
- doom 2016
- doom
https://www.youtube.com/watch?v=ouw3jLAUXWE:
- devil may cry 3
https://www.youtube.com/watch?v=B_MW65XxS7s:
- final fantasy vii
- final fantasy 7
https://www.youtube.com/watch?v=viM0-3PXef0:
- the witcher 3
- witcher 3
https://www.youtube.com/watch?v=WQYN2P3E06s:
- civilization vi
- civilization 6
https://www.youtube.com/watch?v=qOMQxVtbkik:
- guild wars 2
- guild wars two
https://www.youtube.com/watch?v=WwHrQdC02FY:
- final fantasy vi
- final fantasy 6
https://www.youtube.com/watch?v=2_wkJ377LzU:
- journey
https://www.youtube.com/watch?v=IJiHDmyhE1A:
- civilization iv
- civilization 4
https://www.youtube.com/watch?v=kN_LvY97Rco:
- ori and the blind forest
https://www.youtube.com/watch?v=TO7UI0WIqVw:
- super smash bros brawl
- super smash bros. brawl
- super smash brothers brawl
https://www.youtube.com/watch?v=s9XljBWGrRQ:
- kingdom hearts
https://www.youtube.com/watch?v=xkolWbZdGbM:
- shenmue
https://www.youtube.com/watch?v=h-0G_FI61a8:
- final fantasy x
- final fantasy 10
https://www.youtube.com/watch?v=do5NTPLMqXQ:
- fire emblem fates
https://www.youtube.com/watch?v=eFVj0Z6ahcI:
- persona 5
- persona five
https://www.youtube.com/watch?v=PhciLj5VzOk:
- super mario odyssey
https://www.youtube.com/watch?v=GBPbJyxqHV0:
- super mario 64
- mario 64
https://www.youtube.com/watch?v=wRWq53IFXVQ:
- the legend of zelda the wind waker
- legend of zelda the wind waker
- the legend of zelda wind waker
- legend of zelda wind waker
- wind waker
https://www.youtube.com/watch?v=nkPF5UiDi4g:
- uncharted 2
https://www.youtube.com/watch?v=CdYen5UII0s:
- battlefield 1
- battlefield one
https://www.youtube.com/watch?v=8yj-25MOgOM:
- star fox zero
- starfox zero
https://www.youtube.com/watch?v=Z9dNrmGD7mU:
- dark souls iii
- dark souls 3
https://www.youtube.com/watch?v=Bio99hoZVYI:
- fire emblem awakening
https://www.youtube.com/watch?v=4EcgruWlXnQ:
- monty on the run
https://www.youtube.com/watch?v=oEf8gPFFZ58:
- mega man 3
- megaman 3
https://www.youtube.com/watch?v=ifbr2NQ3Js0:
- castlevania
https://www.youtube.com/watch?v=W7rhEKTX-sE:
- shovel knight
https://www.youtube.com/watch?v=as_ct9tgkZA:
- mega man 2
- megaman 2
https://www.youtube.com/watch?v=FB9Pym-sdbs:
- actraiser
https://www.youtube.com/watch?v=G3zhZHU6B2M:
- ogre battle
https://www.youtube.com/watch?v=hlrOAEr6dXc:
- metroid zero mission
- zero mission
https://www.youtube.com/watch?v=jl6kjAkVw_s:
- sonic 2
https://www.youtube.com/watch?v=K8GRDNU50b8:
- the legend of zelda ocarina of time
- legend of zelda ocarina of time
- ocarina of time
https://www.youtube.com/watch?v=dTZ8uhJ5hIE:
- kirby's epic yarn
- kirbys epic yarn
https://www.youtube.com/watch?v=QaaD9CnWgig:
- super smash bros brawl
- super smash bros. brawl
- super smash brothers brawl
https://www.youtube.com/watch?v=JDqJa1RC3q8:
- kid icarus uprising
https://www.youtube.com/watch?v=MQurUl4Snio:
- punch-out!!
- punch-out
- punch out
- punchout
https://www.youtube.com/watch?v=vlz6qgahnYQ:
- super street fighter 2 turbo
- super street fighter two turbo
- street fighter 2 turbo
- street fighter two turbo
https://www.youtube.com/watch?v=FBLp-3Rw_u0:
- mario & luigi bowser's inside story
- mario and luigi bowser's inside story
- mario & luigi bowsers inside story
- mario and luigi bowsers inside story
- bowser's inside story
- bowsers inside story
https://www.youtube.com/watch?v=jqE8M2ZnFL8:
- grand theft auto 4
- grand theft auto four
https://www.youtube.com/watch?v=GQZLEegUK74:
- goldeneye 007
- goldeneye
https://www.youtube.com/watch?v=nCe7W1ajzIE:
- tmnt iv turtles in time
- tmnt iv
- tmnt 4 turtles in time
- tmnt 4
- turtles in time
https://www.youtube.com/watch?v=YHEifuLCSIY:
- ducktales
https://www.youtube.com/watch?v=rXefFHRgyE0:
- pokemon diamond
- pokemon pearl
- pokemon platinum
https://www.youtube.com/watch?v=4jaIUlz-wNU:
- warriors orochi 3
- warriors orochi three
https://www.youtube.com/watch?v=EAwWPadFsOA:
- mortal kombat
https://www.youtube.com/watch?v=XI1VpElKWF8:
- metal gear solid
https://www.youtube.com/watch?v=zz8m1oEkW5k:
- tetris blitz
https://www.youtube.com/watch?v=gMdX_Iloow8:
- ultimate marvel vs capcom 3
- marvel vs capcom 3
- ultimate marvel vs. capcom 3
- marvel vs. capcom 3
https://www.youtube.com/watch?v=vRe3h1iQ1Os:
- sonic the hedgehog 2006
- sonic the hegehog
https://www.youtube.com/watch?v=SYTS2sJWcIs:
- pokemon heartgold
- pokemon soulsilver
https://www.youtube.com/watch?v=5-BIqqSe1nU:
- red dead redemption
https://www.youtube.com/watch?v=wp6QpMWaKpE:
- bioshock
https://www.youtube.com/watch?v=R9XdMnsKvUs:
- call of duty 4 modern warfare
- call of duty 4
- modern warfare
https://www.youtube.com/watch?v=f-sQhBDsjgE:
- killzone 2
https://www.youtube.com/watch?v=-_O6F5FwQ0s:
- soul calibur v
- sould calibur 5
https://www.youtube.com/watch?v=MgK_OfW7nl4:
- the legend of zelda breath of the wild
- legend of zelda breath of the wild
- breath of the wild
https://www.youtube.com/watch?v=tz82xbLvK_k:
- undertale
https://www.youtube.com/watch?v=J46RY4PU8a8:
- chrono cross
https://www.youtube.com/watch?v=6LB7LZZGpkw:
- silent hill 2
https://www.youtube.com/watch?v=ya3yxTbkh5s:
- Ōkami
- okami
- wolf
https://www.youtube.com/watch?v=KGidvt4NTPI:
- hikari 光
- hikari
-
- light
https://www.youtube.com/watch?v=JbXVNKtmWnc:
- final fantasy vi
- final fantasy 6
https://www.youtube.com/watch?v=-jMDutXA4-M:
- final fantasy iii
- final fantasy 3

@ -0,0 +1,4 @@
https://www.youtube.com/watch?v=hfyE220BsD0:
- holiday
https://www.youtube.com/watch?v=Hh3U9iPKeXQ:
- sultans of swing

@ -0,0 +1,4 @@
https://www.youtube.com/watch?v=Hi1kUdreiWk:
- Jinx
https://www.youtube.com/watch?v=PNYHFluhOGI:
- Teemo

@ -0,0 +1,20 @@
{
"author": [
"Bobloy"
],
"bot_version": [
3,
0,
0
],
"description": "Start an Audio Trivia game",
"hidden": false,
"install_msg": "Thank you for installing Audio trivia!\n You **MUST** unload trivia to use this (`[p]unload trivia`)\n Then you can get started with `[p]load audiotrivia` and `[p]help AudioTrivia`",
"requirements": [],
"short": "Start an Audio Trivia game",
"tags": [
"fox",
"bobloy",
"games"
]
}

@ -1,13 +1,16 @@
import asyncio import asyncio
import re import re
from typing import Any
import discord import discord
from redbot.core import Config, checks from redbot.core import Config, checks
from redbot.core import commands from redbot.core import commands
from redbot.core.utils.chat_formatting import pagify, box from redbot.core.utils.chat_formatting import pagify, box
Cog: Any = getattr(commands, "Cog", object)
class CCRole:
class CCRole(Cog):
""" """
Custom commands Custom commands
Creates commands used to display text and adjust roles Creates commands used to display text and adjust roles
@ -23,7 +26,8 @@ class CCRole:
self.config.register_guild(**default_guild) self.config.register_guild(**default_guild)
@commands.group(no_pm=True) @commands.guild_only()
@commands.group()
async def ccrole(self, ctx): async def ccrole(self, ctx):
"""Custom commands management with roles """Custom commands management with roles

@ -9,7 +9,7 @@
], ],
"description": "[Incomplete] Creates custom commands to adjust roles and send custom messages", "description": "[Incomplete] Creates custom commands to adjust roles and send custom messages",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing Custom Commands w/ Roles.", "install_msg": "Thank you for installing Custom Commands w/ Roles. Get started with `[p]load ccrole` and `[p]help CCRole`",
"requirements": [], "requirements": [],
"short": "[Incomplete] Creates commands that adjust roles", "short": "[Incomplete] Creates commands that adjust roles",
"tags": [ "tags": [

@ -9,10 +9,14 @@ from redbot.core.data_manager import cog_data_path
from chatter.chatterbot import ChatBot from chatter.chatterbot import ChatBot
from chatter.chatterbot.comparisons import levenshtein_distance from chatter.chatterbot.comparisons import levenshtein_distance
from chatter.chatterbot.response_selection import get_first_response
from chatter.chatterbot.trainers import ListTrainer from chatter.chatterbot.trainers import ListTrainer
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Chatter:
class Chatter(Cog):
""" """
This cog trains a chatbot that will talk like members of your Guild This cog trains a chatbot that will talk like members of your Guild
""" """
@ -32,7 +36,16 @@ class Chatter:
"ChatterBot", "ChatterBot",
storage_adapter='chatter.chatterbot.storage.SQLStorageAdapter', storage_adapter='chatter.chatterbot.storage.SQLStorageAdapter',
database=str(data_path), database=str(data_path),
statement_comparison_function=levenshtein_distance statement_comparison_function=levenshtein_distance,
response_selection_method=get_first_response,
logic_adapters=[
'chatter.chatterbot.logic.BestMatch',
{
'import_path': 'chatter.chatterbot.logic.LowConfidenceAdapter',
'threshold': 0.65,
'default_response': ':thinking:'
}
]
) )
self.chatbot.set_trainer(ListTrainer) self.chatbot.set_trainer(ListTrainer)

@ -9,7 +9,7 @@
], ],
"description": "Create an offline chatbot that talks like your average member using Machine Learning", "description": "Create an offline chatbot that talks like your average member using Machine Learning",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing Chatter!", "install_msg": "Thank you for installing Chatter! Get started ith `[p]load chatter` and `[p]help Chatter`",
"requirements": [ "requirements": [
"sqlalchemy<1.3,>=1.2", "sqlalchemy<1.3,>=1.2",
"python-twitter<4.0,>=3.0", "python-twitter<4.0,>=3.0",

@ -4,11 +4,14 @@ from redbot.core import Config
from redbot.core import commands from redbot.core import commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.data_manager import cog_data_path from redbot.core.data_manager import cog_data_path
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class CogLint:
class CogLint(Cog):
""" """
V3 Cog Template Automatically lint code in python codeblocks
""" """
def __init__(self, bot: Red): def __init__(self, bot: Red):

@ -9,7 +9,7 @@
], ],
"description": "Lint python code posted in chat", "description": "Lint python code posted in chat",
"hidden": true, "hidden": true,
"install_msg": "Thank you for installing CogLint", "install_msg": "Thank you for installing CogLint! Get started with `[p]load coglint` and `[p]help CogLint`",
"requirements": [], "requirements": [],
"short": "Python cog linter", "short": "Python cog linter",
"tags": [ "tags": [

@ -0,0 +1,5 @@
from .dad import Dad
def setup(bot):
bot.add_cog(Dad(bot))

@ -0,0 +1,112 @@
from collections import defaultdict
from datetime import datetime, timedelta
from typing import Any
import aiohttp
import discord
from redbot.core import Config, checks
from redbot.core import commands
from redbot.core.bot import Red
Cog: Any = getattr(commands, "Cog", object)
async def fetch_url(session, url):
async with session.get(url) as response:
assert response.status == 200
return await response.json()
class Dad(Cog):
"""
Dad jokes
Nicknaming user idea comes from https://github.com/Vexs/DadBot
"""
def __init__(self, bot: Red):
self.bot = bot
self.config = Config.get_conf(self, identifier=6897100, force_registration=True)
default_guild = {
"enabled": False,
"nickname": False,
"cooldown": 240
}
self.config.register_guild(**default_guild)
self.cooldown = defaultdict(datetime.now)
@commands.command()
async def dadjoke(self, ctx: commands.Context):
headers = {"User-Agent": "FoxV3 (https://github.com/bobloy/Fox-V3)",
"Accept": "application/json"}
async with aiohttp.ClientSession(headers=headers) as session:
joke = await fetch_url(session, 'https://icanhazdadjoke.com/')
em = discord.Embed()
em.set_image(url="https://icanhazdadjoke.com/j/{}.png".format(joke['id']))
await ctx.send(embed=em)
@commands.group()
@checks.admin()
async def dad(self, ctx: commands.Context):
"""Dad joke superhub"""
pass
@dad.command(name='toggle')
async def dad_toggle(self, ctx: commands.Context):
"""Toggle automatic dad jokes on or off"""
is_on = await self.config.guild(ctx.guild).enabled()
await self.config.guild(ctx.guild).enabled.set(not is_on)
await ctx.send("Auto dad jokes are now set to {}".format(not is_on))
@dad.command(name='nickname')
async def dad_nickname(self, ctx: commands.Context):
"""Toggle nicknaming"""
is_on = await self.config.guild(ctx.guild).nickname()
await self.config.guild(ctx.guild).nickname.set(not is_on)
await ctx.send("Nicknaming is now set to {}".format(not is_on))
@dad.command(name='cooldown')
async def dad_cooldown(self, ctx: commands.Context, cooldown: int):
"""Set the auto-joke cooldown"""
await self.config.guild(ctx.guild).cooldown.set(cooldown)
await ctx.send("Dad joke cooldown is now set to {}".format(cooldown))
async def on_message(self, message: discord.Message):
guild: discord.Guild = message.guild
if guild is None:
return
guild_config = self.config.guild(guild)
is_on = await guild_config.enabled()
if not is_on:
return
if self.cooldown[guild.id] > datetime.now():
return
lower = message.clean_content.lower()
lower_split = lower.split()
if len(lower_split)==0:
return
if lower_split[0] == "i'm" and len(lower_split) >= 2:
if await guild_config.nickname():
try:
await message.author.edit(nick=lower[4:])
except discord.Forbidden:
out = lower[4:]
else:
out = message.author.mention
else:
out = lower[4:]
await message.channel.send("Hi {}, I'm {}!".format(out, guild.me.display_name))
self.cooldown[guild.id] = datetime.now() + timedelta(seconds=(await guild_config.cooldown()))

@ -0,0 +1,20 @@
{
"author": [
"Bobloy"
],
"bot_version": [
3,
0,
0
],
"description": "Tell dad jokes and give out bad nicknames",
"hidden": true,
"install_msg": "Thank you for installing Dad. Get started with `[p]load dad`, then `[p]help Dad`",
"requirements": [],
"short": "Dad joke bot",
"tags": [
"bobloy",
"utils",
"tools"
]
}

@ -0,0 +1,5 @@
from .exclusiverole import ExclusiveRole
def setup(bot):
bot.add_cog(ExclusiveRole(bot))

@ -0,0 +1,92 @@
import asyncio
import discord
from redbot.core import Config, checks, commands
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class ExclusiveRole(Cog):
"""
Custom commands
Creates commands used to display text and adjust roles
"""
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, identifier=9999114111108101)
default_guild = {
"role_list": []
}
self.config.register_guild(**default_guild)
@commands.group(no_pm=True, aliases=["exclusiverole"])
async def exclusive(self, ctx):
"""Base command for managing exclusive roles"""
if not ctx.invoked_subcommand:
pass
@exclusive.command(name="add")
@checks.mod_or_permissions(administrator=True)
async def exclusive_add(self, ctx, role: discord.Role):
"""Adds an exclusive role"""
if role.id in (await self.config.guild(ctx.guild).role_list()):
await ctx.send("That role is already exclusive")
return
async with self.config.guild(ctx.guild).role_list() as rl:
rl.append(role.id)
await self.check_guild(ctx.guild)
await ctx.send("Exclusive role added")
@exclusive.command(name="delete")
@checks.mod_or_permissions(administrator=True)
async def exclusive_delete(self, ctx, role: discord.Role):
"""Deletes an exclusive role"""
if role.id not in (await self.config.guild(ctx.guild).role_list()):
await ctx.send("That role is not exclusive")
return
async with self.config.guild(ctx.guild).role_list() as rl:
rl.remove(role.id)
await ctx.send("Exclusive role removed")
async def check_guild(self, guild: discord.Guild):
role_set = set(await self.config.guild(guild).role_list())
for member in guild.members:
try:
await self.remove_non_exclusive_roles(member, role_set=role_set)
except discord.Forbidden:
pass
async def remove_non_exclusive_roles(self, member: discord.Member, role_set=None):
if role_set is None:
role_set = set(await self.config.guild(member.guild).role_list())
member_set = set([role.id for role in member.roles])
to_remove = (member_set - role_set) - {member.guild.default_role.id}
if to_remove and member_set & role_set:
to_remove = [discord.utils.get(member.guild.roles, id=id) for id in to_remove]
await member.remove_roles(*to_remove, reason="Exclusive roles")
async def on_member_update(self, before: discord.Member, after: discord.Member):
if before.roles == after.roles:
return
await asyncio.sleep(1)
role_set = set(await self.config.guild(after.guild).role_list())
member_set = set([role.id for role in after.roles])
if role_set & member_set:
try:
await self.remove_non_exclusive_roles(after, role_set=role_set)
except discord.Forbidden:
pass

@ -0,0 +1,22 @@
{
"author": [
"Bobloy"
],
"bot_version": [
3,
0,
0
],
"description": "Assign roles to be exclusive, preventing other roles from being added",
"hidden": false,
"install_msg": "Thank you for installing ExclusiveRole. Get started with `[p]load exclusiverole` and `[p]help ExclusiveRole`",
"requirements": [],
"short": "Set roles to be exclusive",
"tags": [
"fox",
"bobloy",
"utility",
"tools",
"roles"
]
}

@ -4,9 +4,12 @@ import discord
from redbot.core import Config, checks, commands from redbot.core import Config, checks, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.utils.chat_formatting import pagify from redbot.core.utils.chat_formatting import pagify
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Flag:
class Flag(Cog):
""" """
Set expiring flags on members Set expiring flags on members
""" """
@ -25,6 +28,7 @@ class Flag:
self.config.register_guild(**default_guild) self.config.register_guild(**default_guild)
@checks.is_owner() @checks.is_owner()
@commands.guild_only()
@commands.command() @commands.command()
async def clearallflag(self, ctx: commands.Context): async def clearallflag(self, ctx: commands.Context):
"""Clears all flags for all members in this server""" """Clears all flags for all members in this server"""
@ -70,7 +74,7 @@ class Flag:
'expireday': 0 'expireday': 0
} }
# ************************Flag command group start************************ @commands.guild_only()
@checks.mod_or_permissions(manage_roles=True) @checks.mod_or_permissions(manage_roles=True)
@commands.command() @commands.command()
async def flag(self, ctx: commands.Context, member: discord.Member, *, reason): async def flag(self, ctx: commands.Context, member: discord.Member, *, reason):
@ -107,8 +111,9 @@ class Flag:
else: else:
await ctx.send("This member has no flags.. somehow..") await ctx.send("This member has no flags.. somehow..")
@commands.guild_only()
@checks.mod_or_permissions(manage_roles=True) @checks.mod_or_permissions(manage_roles=True)
@commands.command(pass_context=True, no_pm=True, aliases=['flagclear']) @commands.command(aliases=['flagclear'])
async def clearflag(self, ctx: commands.Context, member: discord.Member): async def clearflag(self, ctx: commands.Context, member: discord.Member):
"""Clears flags for a member""" """Clears flags for a member"""
guild = ctx.guild guild = ctx.guild
@ -118,7 +123,8 @@ class Flag:
await ctx.send("Success!") await ctx.send("Success!")
@commands.command(pass_context=True, no_pm=True, aliases=['flaglist']) @commands.guild_only()
@commands.command(aliases=['flaglist'])
async def listflag(self, ctx: commands.Context, member: discord.Member): async def listflag(self, ctx: commands.Context, member: discord.Member):
"""Lists flags for a member""" """Lists flags for a member"""
server = ctx.guild server = ctx.guild
@ -131,7 +137,8 @@ class Flag:
else: else:
await ctx.send("This member has no flags!") await ctx.send("This member has no flags!")
@commands.command(pass_context=True, no_pm=True, aliases=['flagall']) @commands.guild_only()
@commands.command(aliases=['flagall'])
async def allflag(self, ctx: commands.Context): async def allflag(self, ctx: commands.Context):
"""Lists all flags for the server""" """Lists all flags for the server"""
guild = ctx.guild guild = ctx.guild

@ -8,8 +8,8 @@
0 0
], ],
"description": "Add expiring flags on members to track warnings or incidents", "description": "Add expiring flags on members to track warnings or incidents",
"hidden": true, "hidden": false,
"install_msg": "Thank you for installing Flag! Get started with `[p]help Flag`", "install_msg": "Thank you for installing Flag! Get started with `[p]load flag` and `[p]help Flag`",
"requirements": [], "requirements": [],
"short": "Add expiring flags to members", "short": "Add expiring flags to members",
"tags": [ "tags": [

@ -3,9 +3,12 @@ from discord.utils import get
from redbot.core import Config, checks, commands from redbot.core import Config, checks, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class ForceMention:
class ForceMention(Cog):
""" """
Mention the unmentionables Mention the unmentionables
""" """

@ -9,7 +9,7 @@
], ],
"description": "Mentions roles that are unmentionable", "description": "Mentions roles that are unmentionable",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing ForceMention! Get started with `[p]forcemention`", "install_msg": "Thank you for installing ForceMention! Get started with `[p]load forcemention`, then `[p]forcemention`",
"requirements": [], "requirements": [],
"short": "Mention unmentionables", "short": "Mention unmentionables",
"tags": [ "tags": [

@ -2,12 +2,14 @@ from collections import defaultdict
from random import randint from random import randint
import discord import discord
from redbot.core import Config, checks from redbot.core import Config, checks, commands
from redbot.core import commands
from redbot.core.data_manager import cog_data_path from redbot.core.data_manager import cog_data_path
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Hangman:
class Hangman(Cog):
"""Lets anyone play a game of hangman with custom phrases""" """Lets anyone play a game of hangman with custom phrases"""
navigate = "🔼🔽" navigate = "🔼🔽"
letters = "🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿" letters = "🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿"
@ -17,6 +19,7 @@ class Hangman:
self.config = Config.get_conf(self, identifier=1049711010310997110) self.config = Config.get_conf(self, identifier=1049711010310997110)
default_guild = { default_guild = {
"theface": ':thinking:', "theface": ':thinking:',
"emojis": True,
} }
self.config.register_guild(**default_guild) self.config.register_guild(**default_guild)
@ -132,6 +135,7 @@ class Hangman:
@hangset.command(pass_context=True) @hangset.command(pass_context=True)
async def face(self, ctx: commands.Context, theface): async def face(self, ctx: commands.Context, theface):
"""Set the face of the hangman"""
message = ctx.message message = ctx.message
# Borrowing FlapJack's emoji validation # Borrowing FlapJack's emoji validation
# (https://github.com/flapjax/FlapJack-Cogs/blob/master/smartreact/smartreact.py) # (https://github.com/flapjax/FlapJack-Cogs/blob/master/smartreact/smartreact.py)
@ -149,6 +153,14 @@ class Hangman:
await self._update_hanglist() await self._update_hanglist()
await ctx.send("Face has been updated!") await ctx.send("Face has been updated!")
@hangset.command(pass_context=True)
async def toggleemoji(self, ctx: commands.Context):
"""Toggles whether to automatically react with the alphabet"""
current = await self.config.guild(ctx.guild).emojis()
await self.config.guild(ctx.guild).emojis.set(not current)
await ctx.send("Emoji Letter reactions have been set to {}".format(not current))
@commands.command(aliases=['hang'], pass_context=True) @commands.command(aliases=['hang'], pass_context=True)
async def hangman(self, ctx, guess: str = None): async def hangman(self, ctx, guess: str = None):
"""Play a game of hangman against the bot!""" """Play a game of hangman against the bot!"""
@ -253,7 +265,7 @@ class Hangman:
return return
if user == self.bot.user: if user == self.bot.user:
return # Don't remove bot's own reactions return # Don't react to bot's own reactions
message = reaction.message message = reaction.message
emoji = reaction.emoji emoji = reaction.emoji
@ -270,15 +282,27 @@ class Hangman:
if str(emoji) == self.navigate[-1]: if str(emoji) == self.navigate[-1]:
await self._reactmessage_nz(message) await self._reactmessage_nz(message)
async def _try_clear_reactions(self, message):
try:
await message.clear_reactions()
except discord.Forbidden:
pass
async def _reactmessage_menu(self, message): async def _reactmessage_menu(self, message):
"""React with menu options""" """React with menu options"""
await message.clear_reactions() if not await self.config.guild(message.guild).emojis():
return
await self._try_clear_reactions(message)
await message.add_reaction(self.navigate[0]) await message.add_reaction(self.navigate[0])
await message.add_reaction(self.navigate[-1]) await message.add_reaction(self.navigate[-1])
async def _reactmessage_am(self, message): async def _reactmessage_am(self, message):
await message.clear_reactions() if not await self.config.guild(message.guild).emojis():
return
await self._try_clear_reactions(message)
for x in range(len(self.letters)): for x in range(len(self.letters)):
if x in [i for i, b in enumerate("ABCDEFGHIJKLM") if b not in self._guesslist(message.guild)]: if x in [i for i, b in enumerate("ABCDEFGHIJKLM") if b not in self._guesslist(message.guild)]:
@ -287,7 +311,10 @@ class Hangman:
await message.add_reaction(self.navigate[-1]) await message.add_reaction(self.navigate[-1])
async def _reactmessage_nz(self, message): async def _reactmessage_nz(self, message):
await message.clear_reactions() if not await self.config.guild(message.guild).emojis():
return
await self._try_clear_reactions(message)
for x in range(len(self.letters)): for x in range(len(self.letters)):
if x in [i for i, b in enumerate("NOPQRSTUVWXYZ") if b not in self._guesslist(message.guild)]: if x in [i for i, b in enumerate("NOPQRSTUVWXYZ") if b not in self._guesslist(message.guild)]:
@ -297,11 +324,8 @@ class Hangman:
def _make_say(self, guild): def _make_say(self, guild):
c_say = "Guess this: " + str(self._hideanswer(guild)) + "\n" c_say = "Guess this: " + str(self._hideanswer(guild)) + "\n"
c_say += "Used Letters: " + str(self._guesslist(guild)) + "\n" c_say += "Used Letters: " + str(self._guesslist(guild)) + "\n"
c_say += self.hanglist[guild][self.the_data[guild]["hangman"]] + "\n" c_say += self.hanglist[guild][self.the_data[guild]["hangman"]] + "\n"
c_say += self.navigate[0] + " for A-M, " + self.navigate[-1] + " for N-Z" c_say += self.navigate[0] + " for A-M, " + self.navigate[-1] + " for N-Z"
return c_say return c_say

@ -9,7 +9,7 @@
], ],
"description": "Play Hangman with your friends", "description": "Play Hangman with your friends",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing Hangman!", "install_msg": "Thank you for installing Hangman! Get started with `[p]load hangman`, then `[p]help Hangman`",
"requirements": [], "requirements": [],
"short": "Play Hangman", "short": "Play Hangman",
"tags": [ "tags": [

@ -9,7 +9,7 @@
], ],
"description": "Keeps track of when people leave the server, and posts a message notifying", "description": "Keeps track of when people leave the server, and posts a message notifying",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing Leaver. Get started with `[p]help Leaver`", "install_msg": "Thank you for installing Leaver. Get started with `[p]load leaver`, then `[p]help Leaver`",
"requirements": [], "requirements": [],
"short": "Send message on leave", "short": "Send message on leave",
"tags": [ "tags": [

@ -2,9 +2,12 @@ import discord
from redbot.core import Config, checks, commands from redbot.core import Config, checks, commands
from redbot.core.commands import Context from redbot.core.commands import Context
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Leaver:
class Leaver(Cog):
""" """
Creates a goodbye message when people leave Creates a goodbye message when people leave
""" """

@ -0,0 +1,5 @@
from .lovecalculator import LoveCalculator
def setup(bot):
bot.add_cog(LoveCalculator(bot))

@ -0,0 +1,23 @@
{
"author": [
"Bobloy",
"SnappyDragon"
],
"bot_version": [
3,
0,
0
],
"description": "Calculate the love percentage for two users",
"hidden": false,
"install_msg": "Thank you for installing LoveCalculator. Love is in the air.\n Get started with `[p]load lovecalculator`, then `[p]help LoveCalculator`",
"requirements": [
"beautifulsoup4"
],
"short": "Calculate love percentage",
"tags": [
"bobloy",
"fun",
"love"
]
}

@ -0,0 +1,47 @@
import aiohttp
import discord
from bs4 import BeautifulSoup
from redbot.core import commands
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class LoveCalculator(Cog):
"""Calculate the love percentage for two users!"""
def __init__(self, bot):
self.bot = bot
@commands.command(aliases=['lovecalc'])
async def lovecalculator(self, ctx: commands.Context, lover: discord.Member, loved: discord.Member):
"""Calculate the love percentage!"""
x = lover.display_name
y = loved.display_name
url = 'https://www.lovecalculator.com/love.php?name1={}&name2={}'.format(x.replace(" ", "+"),
y.replace(" ", "+"))
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
soup_object = BeautifulSoup(await response.text(), "html.parser")
try:
description = soup_object.find('div', attrs={'class': 'result score'}).get_text().strip()
except:
description = 'Dr. Love is busy right now'
try:
z = description[:2]
z = int(z)
if z > 50:
emoji = ''
else:
emoji = '💔'
title = 'Dr. Love says that the love percentage for {} and {} is:'.format(x, y)
except:
emoji = ''
title = 'Dr. Love has left a note for you.'
description = emoji + ' ' + description + ' ' + emoji
em = discord.Embed(title=title, description=description, color=discord.Color.red())
await ctx.send(embed=em)

@ -8,9 +8,9 @@
0 0
], ],
"description": "Keep track of when users were last seen online", "description": "Keep track of when users were last seen online",
"hidden": true, "hidden": false,
"install_msg": "Thank you for installing LastSeen. Get started with `[p]help LastSeen`", "install_msg": "Thank you for installing LastSeen. Get started with `[p]load lseen`, then `[p]help LastSeen`",
"requirements": [], "requirements": ["python-dateutil"],
"short": "Last seen tracker", "short": "Last seen tracker",
"tags": [ "tags": [
"bobloy", "bobloy",

@ -6,9 +6,12 @@ import discord
from redbot.core import Config from redbot.core import Config
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core import commands from redbot.core import commands
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class LastSeen:
class LastSeen(Cog):
""" """
Report when a user was last seen online Report when a user was last seen online
""" """
@ -71,19 +74,11 @@ class LastSeen:
# embed = discord.Embed( # embed = discord.Embed(
# description="{} was last seen at this date and time".format(member.display_name), # description="{} was last seen at this date and time".format(member.display_name),
# timestamp=self.get_date_time(last_seen)) # timestamp=last_seen)
embed = discord.Embed(timestamp=last_seen) embed = discord.Embed(timestamp=last_seen)
await ctx.send(embed=embed) await ctx.send(embed=embed)
# async def on_socket_raw_receive(self, data):
# try:
# if type(data) == str:
# raw = json.loads(data)
# print(data)
# except:
# print(data)
async def on_member_update(self, before: discord.Member, after: discord.Member): async def on_member_update(self, before: discord.Member, after: discord.Member):
if before.status != self.offline_status and after.status == self.offline_status: if before.status != self.offline_status and after.status == self.offline_status:
if not await self.config.guild(before.guild).enabled(): if not await self.config.guild(before.guild).enabled():

@ -9,10 +9,8 @@
], ],
"description": "Keep track of when users were last seen online", "description": "Keep track of when users were last seen online",
"hidden": true, "hidden": true,
"install_msg": "Thank you for installing LastSeen. Get started with `[p]help LastSeen`", "install_msg": "Thank you for installing Nudity. Get started with `[p]load nudity`, then `[p]help Nudity`",
"requirements": [ "requirements": ["nudepy"],
"nudepy"
],
"short": "Last seen tracker", "short": "Last seen tracker",
"tags": [ "tags": [
"bobloy", "bobloy",

@ -0,0 +1,5 @@
from .planttycoon import PlantTycoon
def setup(bot):
bot.add_cog(PlantTycoon(bot))

@ -0,0 +1,11 @@
{
"badges": {
"Flower Power": {},
"Fruit Brute": {},
"Sporadic": {},
"Odd-pod": {},
"Greenfingers": {},
"Nobel Peas Prize": {},
"Annualsary": {}
}
}

@ -0,0 +1,22 @@
{
"points": {
"buy": 5,
"add_health": 5,
"fertilize": 10,
"pruning": 20,
"pesticide": 25,
"growing": 5,
"damage": 25
},
"timers": {
"degradation": 1,
"completion": 1,
"notification": 5
},
"degradation": {
"base_degradation": 1.5
},
"notification": {
"max_health": 50
}
}

@ -0,0 +1,7 @@
{
"messages": [
"The soil seems dry, maybe you could give your plant some water?",
"Your plant seems a bit droopy. I would give it some fertilizer if I were you.",
"Your plant seems a bit too overgrown. You should probably trim it a bit."
]
}

@ -0,0 +1,690 @@
{
"plants": [
{
"name": "Poppy",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/S4hjyUX.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Dandelion",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/emqnQP2.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Daisy",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/lcFq4AB.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Chrysanthemum",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/5jLtqWL.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Pansy",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/f7TgD1b.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Lavender",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/g3OmOSK.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Lily",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/0hzy7lO.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Petunia",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/rJm8ISv.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Sunflower",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/AzgzQK9.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Daffodil",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/pnCCRsH.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Clover",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/jNTgirw.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Tulip",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/kodIFjE.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Rose",
"article": "a",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/sdTNiOH.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Aster",
"article": "an",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/1tN04Hl.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Aloe Vera",
"article": "an",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/WFAYIpx.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Orchid",
"article": "an",
"time": 3600,
"rarity": "common",
"image": "http://i.imgur.com/IQrQYDC.jpg",
"health": 100,
"degradation": 0.625,
"threshold": 110,
"badge": "Flower Power",
"reward": 600
},
{
"name": "Dragon Fruit Plant",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/pfngpDS.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Mango Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/ybR78Oc.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Lychee Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/w9LkfhX.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Durian Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/jh249fz.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Fig Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/YkhnpEV.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Jack Fruit Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/2D79TlA.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Prickly Pear Plant",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/GrcGAGj.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Pineapple Plant",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/VopYQtr.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Citron Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/zh7Dr23.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Cherimoya Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/H62gQK6.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Mangosteen Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/McNnMqa.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Guava Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/iy8WgPt.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Orange Tree",
"article": "an",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/lwjEJTm.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Apple Tree",
"article": "an",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/QI3UTR3.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Sapodilla Tree",
"article": "a",
"time": 5400,
"rarity": "uncommon",
"image": "http://i.imgur.com/6BvO5Fu.jpg",
"health": 100,
"degradation": 0.75,
"threshold": 110,
"badge": "Fruit Brute",
"reward": 1200
},
{
"name": "Franklin Tree",
"article": "a",
"time": 7200,
"rarity": "rare",
"image": "http://i.imgur.com/hoh17hp.jpg",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Sporadic",
"reward": 2400
},
{
"name": "Parrot's Beak",
"article": "a",
"time": 7200,
"rarity": "rare",
"image": "http://i.imgur.com/lhSjfQY.jpg",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Sporadic",
"reward": 2400
},
{
"name": "Koki'o",
"article": "a",
"time": 7200,
"rarity": "rare",
"image": "http://i.imgur.com/Dhw9ync.jpg",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Sporadic",
"reward": 2400
},
{
"name": "Jade Vine",
"article": "a",
"time": 7200,
"rarity": "rare",
"image": "http://i.imgur.com/h4fJo2R.jpg",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Sporadic",
"reward": 2400
},
{
"name": "Venus Fly Trap",
"article": "a",
"time": 7200,
"rarity": "rare",
"image": "http://i.imgur.com/NoSdxXh.jpg",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Sporadic",
"reward": 2400
},
{
"name": "Chocolate Cosmos",
"article": "a",
"time": 7200,
"rarity": "rare",
"image": "http://i.imgur.com/4ArSekX.jpg",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Sporadic",
"reward": 2400
},
{
"name": "Pizza Plant",
"article": "a",
"time": 9000,
"rarity": "super-rare",
"image": "http://i.imgur.com/ASZXr7C.png",
"health": 100,
"degradation": 1,
"threshold": 110,
"badge": "Odd-pod",
"reward": 3600
},
{
"name": "tba",
"article": "a",
"time": 9000,
"rarity": "super-rare",
"image": "tba",
"health": 100,
"degradation": 1.5,
"threshold": 110,
"badge": "Odd-pod",
"reward": 3600
},
{
"name": "Pirahna Plant",
"article": "a",
"time": 9000,
"rarity": "super-rare",
"image": "http://i.imgur.com/c03i9W7.jpg",
"health": 100,
"degradation": 1.5,
"threshold": 110,
"badge": "Odd-pod",
"reward": 3600
},
{
"name": "tba",
"article": "a",
"time": 9000,
"rarity": "super-rare",
"image": "tba",
"health": 100,
"degradation": 1.5,
"threshold": 110,
"badge": "Odd-pod",
"reward": 3600
},
{
"name": "Peashooter",
"article": "a",
"time": 9000,
"rarity": "super-rare",
"image": "https://i.imgur.com/Vo4v2Ry.png",
"health": 100,
"degradation": 1.5,
"threshold": 110,
"badge": "Odd-pod",
"reward": 3600
},
{
"name": "tba",
"article": "a",
"time": 10800,
"rarity": "epic",
"image": "tba",
"health": 100,
"degradation": 2,
"threshold": 110,
"badge": "Greenfingers",
"reward": 5400
},
{
"name": "Pikmin",
"article": "a",
"time": 10800,
"rarity": "epic",
"image": "http://i.imgur.com/sizf7hE.png",
"health": 100,
"degradation": 2,
"threshold": 110,
"badge": "Greenfingers",
"reward": 5400
},
{
"name": "Flora Colossus",
"article": "a",
"time": 10800,
"rarity": "epic",
"image": "http://i.imgur.com/9f5QzaW.jpg",
"health": 100,
"degradation": 2,
"threshold": 110,
"badge": "Greenfingers",
"reward": 5400
},
{
"name": "Plantera Bulb",
"article": "a",
"time": 10800,
"rarity": "epic",
"image": "https://i.imgur.com/ExqLLHO.png",
"health": 100,
"degradation": 2,
"threshold": 110,
"badge": "Greenfingers",
"reward": 5400
},
{
"name": "Chorus Tree",
"article": "an",
"time": 10800,
"rarity": "epic",
"image": "https://i.imgur.com/tv2B72j.png",
"health": 100,
"degradation": 2,
"threshold": 110,
"badge": "Greenfingers",
"reward": 5400
},
{
"name": "Money Tree",
"article": "a",
"time": 35400,
"rarity": "legendary",
"image": "http://i.imgur.com/MIJQDLL.jpg",
"health": 100,
"degradation": 3,
"threshold": 110,
"badge": "Nobel Peas Prize",
"reward": 10800
},
{
"name": "Truffula Tree",
"article": "a",
"time": 35400,
"rarity": "legendary",
"image": "http://i.imgur.com/cFSmaHH.png",
"health": 100,
"degradation": 3,
"threshold": 110,
"badge": "Nobel Peas Prize",
"reward": 10800
},
{
"name": "Whomping Willow",
"article": "a",
"time": 35400,
"rarity": "legendary",
"image": "http://i.imgur.com/Ibwm2xY.jpg",
"health": 100,
"degradation": 3,
"threshold": 110,
"badge": "Nobel Peas Prize",
"reward": 10800
}
],
"event": {
"January": {
"name": "Tanabata Tree",
"article": "a",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/FD38JJj.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
},
"February": {
"name": "Chocolate Rose",
"article": "a",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/Sqg6pcG.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
},
"March": {
"name": "Shamrock",
"article": "a",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/kVig04M.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
},
"April": {
"name": "Easter Egg Eggplant",
"article": "an",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/5jltGQa.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
},
"October": {
"name": "Jack O' Lantern",
"article": "a",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/efApsxG.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
},
"November": {
"name": "Mayflower",
"article": "a",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/nntNtoL.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
},
"December": {
"name": "Holly",
"article": "a",
"time": 70800,
"rarity": "event",
"image": "http://i.imgur.com/maDLmJC.jpg",
"health": 100,
"degradation": 9,
"threshold": 110,
"badge": "Annualsary",
"reward": 21600
}
}
}

@ -0,0 +1,42 @@
{
"water": {
"cost": 5,
"health": 10,
"damage": 45,
"modifier": 0,
"category": "water",
"uses": 1
},
"manure": {
"cost": 20,
"health": 20,
"damage": 55,
"modifier": -0.035,
"category": "fertilizer",
"uses": 1
},
"vermicompost": {
"cost": 35,
"health": 30,
"damage": 60,
"modifier": -0.5,
"category": "fertilizer",
"uses": 1
},
"nitrates": {
"cost": 70,
"health": 60,
"damage": 75,
"modifier": -0.08,
"category": "fertilizer",
"uses": 1
},
"pruner": {
"cost": 500,
"health": 40,
"damage": 90,
"modifier": -0.065,
"category": "tool",
"uses": 10
}
}

@ -0,0 +1,22 @@
{
"author": [
"Bobloy",
"SnappyDragon",
"PaddoInWonderland"
],
"bot_version": [
3,
0,
0
],
"description": "Grow your own plants! Be sure to take care of it. Do `[p]gardening` to get started",
"hidden": false,
"install_msg": "Thank you for installing PlantTycoon. Check out all the commands with `[p]help PlantTycoon`",
"requirements": [],
"short": "Grow your own plants! Do `[p]gardening` to get started.",
"tags": [
"bobloy",
"games",
"environment"
]
}

File diff suppressed because it is too large Load Diff

@ -8,8 +8,8 @@
0 0
], ],
"description": "Create a QR code invite for the server", "description": "Create a QR code invite for the server",
"hidden": true, "hidden": false,
"install_msg": "Thank you for installing QRInvite! Get started with `[p]help QRInvite`", "install_msg": "Thank you for installing QRInvite! Get started with `[p]load qrinvite`, then `[p]help QRInvite`",
"requirements": [ "requirements": [
"MyQR" "MyQR"
], ],

@ -2,17 +2,17 @@ import pathlib
import aiohttp import aiohttp
import discord import discord
from MyQR import myqr
from PIL import Image from PIL import Image
from redbot.core import Config, commands
from redbot.core import Config, checks, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from MyQR import myqr
from redbot.core.data_manager import cog_data_path from redbot.core.data_manager import cog_data_path
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class QRInvite: class QRInvite(Cog):
""" """
V3 Cog Template V3 Cog Template
""" """
@ -27,7 +27,7 @@ class QRInvite:
self.config.register_guild(**default_guild) self.config.register_guild(**default_guild)
@commands.command() @commands.command()
async def qrinvite(self, ctx: commands.Context, invite: str=None, colorized: bool=False, image_url: str=None): async def qrinvite(self, ctx: commands.Context, invite: str = None, colorized: bool = False, image_url: str = None):
""" """
Create a custom QR code invite for this server Create a custom QR code invite for this server
""" """
@ -46,10 +46,15 @@ class QRInvite:
if image_url is None: if image_url is None:
image_url = ctx.guild.icon_url image_url = ctx.guild.icon_url
extension = pathlib.Path(image_url).parts[-1].replace('.','?').split('?')[1] if image_url == "": # Still
await ctx.send(
"Could not get an image, please provide one. *(`{}help qrinvite` for details)*".format(ctx.prefix))
return
extension = pathlib.Path(image_url).parts[-1].replace('.', '?').split('?')[1]
path: pathlib.Path = cog_data_path(self) path: pathlib.Path = cog_data_path(self)
image_path = path / (ctx.guild.icon+"."+extension) image_path = path / (ctx.guild.icon + "." + extension)
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(image_url) as response: async with session.get(image_url) as response:
image = await response.read() image = await response.read()
@ -62,20 +67,21 @@ class QRInvite:
else: else:
new_path = str(image_path) new_path = str(image_path)
myqr.run(invite,picture=new_path,save_name=ctx.guild.icon+"_qrcode.png", myqr.run(invite, picture=new_path, save_name=ctx.guild.icon + "_qrcode.png",
save_dir=str(cog_data_path(self)),colorized=colorized,) save_dir=str(cog_data_path(self)), colorized=colorized, )
png_path: pathlib.Path = path / (ctx.guild.icon+"_qrcode.png") png_path: pathlib.Path = path / (ctx.guild.icon + "_qrcode.png")
with png_path.open("rb") as png_fp: with png_path.open("rb") as png_fp:
await ctx.send(file=discord.File(png_fp.read(), "qrcode.png")) await ctx.send(file=discord.File(png_fp.read(), "qrcode.png"))
def convert_png(path): def convert_png(path):
im = Image.open(path) im = Image.open(path)
im.load() im.load()
alpha = im.split()[-1] alpha = im.split()[-1]
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0) mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0)
im.paste(255, mask) im.paste(255, mask)
newPath = path.replace(".webp",".png") new_path = path.replace(".webp", ".png")
im.save(newPath, transparency=255) im.save(new_path, transparency=255)
return newPath return new_path

@ -2,7 +2,7 @@
"author" : ["Bobloy"], "author" : ["Bobloy"],
"bot_version" : [3,0,0], "bot_version" : [3,0,0],
"description" : "Cog to prevent reactions on specific messages from certain users", "description" : "Cog to prevent reactions on specific messages from certain users",
"hidden" : false, "hidden" : true,
"install_msg" : "Thank you for installing ReactRestrict.", "install_msg" : "Thank you for installing ReactRestrict.",
"requirements" : [], "requirements" : [],
"short" : "[Incomplete] Prevent reactions", "short" : "[Incomplete] Prevent reactions",

@ -4,6 +4,9 @@ import discord
from redbot.core import Config from redbot.core import Config
from redbot.core import commands from redbot.core import commands
from redbot.core.bot import Red from redbot.core.bot import Red
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class ReactRestrictCombo: class ReactRestrictCombo:
@ -31,7 +34,7 @@ class ReactRestrictCombo:
) )
class ReactRestrict: class ReactRestrict(Cog):
""" """
Prevent specific roles from reacting to specific messages Prevent specific roles from reacting to specific messages
""" """

@ -0,0 +1,9 @@
from redbot.core import data_manager
from .recyclingplant import RecyclingPlant
def setup(bot):
plant = RecyclingPlant(bot)
data_manager.load_bundled_data(plant, __file__)
bot.add_cog(plant)

@ -0,0 +1,204 @@
{
"can": [
{
"object": "Apple Core",
"action": "trash"
},
{
"object": "Paper Cup",
"action": "recycle"
},
{
"object": "Banana Peel",
"action": "trash"
},
{
"object": "Paper Bag",
"action": "recycle"
},
{
"object": "Old Taco",
"action": "trash"
},
{
"object": "Newspaper",
"action": "recycle"
},
{
"object": "Chewed Gum",
"action": "trash"
},
{
"object": "Polythene Bag",
"action": "recycle"
},
{
"object": "Rotten Eggs",
"action": "trash"
},
{
"object": "Outdated Telephone Directory",
"action": "recycle"
},
{
"object": "Stale Bread",
"action": "trash"
},
{
"object": "Used Notebook",
"action": "recycle"
},
{
"object": "Sour Milk",
"action": "trash"
},
{
"object": "Old Textbook",
"action": "recycle"
},
{
"object": "Week-Old Sandwich",
"action": "trash"
},
{
"object": "Paper Ball",
"action": "recycle"
},
{
"object": "Leftovers",
"action": "trash"
},
{
"object": "Toy Car",
"action": "recycle"
},
{
"object": "Fish Bones",
"action": "trash"
},
{
"object": "Superhero Costume",
"action": "recycle"
},
{
"object": "Dirty Diaper",
"action": "trash"
},
{
"object": "Silcone Mould",
"action": "recycle"
},
{
"object": "Mouldy Broccoli",
"action": "trash"
},
{
"object": "TV Remote",
"action": "recycle"
},
{
"object": "Withered Rose Bouquet",
"action": "trash"
},
{
"object": "Paper Plate",
"action": "recycle"
},
{
"object": "Slimy Bacon",
"action": "trash"
},
{
"object": "Folders",
"action": "recycle"
},
{
"object": "Fly Agaric Mushrooms",
"action": "trash"
},
{
"object": "Phone case",
"action": "recycle"
},
{
"object": "Napkins",
"action": "trash"
},
{
"object": "Broken Dualshock 4 Controller",
"action": "recycle"
},
{
"object": "Wax Paper",
"action": "trash"
},
{
"object": "iPad",
"action": "recycle"
},
{
"object": "Paint Can",
"action": "trash"
},
{
"object": "Glass Bottle",
"action": "recycle"
},
{
"object": "Light Bulb",
"action": "trash"
},
{
"object": "Nintendo 3DS",
"action": "recycle"
},
{
"object": "Styrofoam Container",
"action": "trash"
},
{
"object": "Flash Cards",
"action": "recycle"
},
{
"object": "Motor Oil Can",
"action": "trash"
},
{
"object": "Candy Wrapper",
"action": "recycle"
},
{
"object": "Waxed Cardboard",
"action": "trash"
},
{
"object": "Empty Bottle",
"action": "recycle"
},
{
"object": "Used Toilet Paper",
"action": "trash"
},
{
"object": "Outdated Calendar",
"action": "recycle"
},
{
"object": "Ceramic Mug",
"action": "trash"
},
{
"object": "Plastic Cup",
"action": "recycle"
},
{
"object": "Gift Wrapping",
"action": "trash"
},
{
"object": "Soda Bottle",
"action": "recycle"
}
]
}

@ -0,0 +1,21 @@
{
"author": [
"Bobloy",
"SnappyDragon"
],
"bot_version": [
3,
0,
0
],
"description": "Apply for a job at the recycling plant! Sort out the garbage!",
"hidden": false,
"install_msg": "Thank you for installing RecyclingPlant. Start recycling today with `[p]load recyclingplant`, then `[p]recyclingplant`",
"requirements": [],
"short": "Apply for a job at the recycling plant!",
"tags": [
"bobloy",
"environment",
"games"
]
}

@ -0,0 +1,70 @@
import asyncio
import json
import random
from redbot.core import bank
from redbot.core import commands
from redbot.core.data_manager import cog_data_path
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class RecyclingPlant(Cog):
"""Apply for a job at the recycling plant!"""
def __init__(self, bot):
self.bot = bot
self.path = str(cog_data_path(self)).replace('\\', '/')
self.junk_path = self.path + "/bundled_data/junk.json"
with open(self.junk_path) as json_data:
self.junk = json.load(json_data)
@commands.command(aliases=["recycle"])
async def recyclingplant(self, ctx: commands.Context):
"""Apply for a job at the recycling plant!"""
x = 0
reward = 0
await ctx.send(
'{0} has signed up for a shift at the Recycling Plant! Type ``exit`` to terminate it early.'.format(
ctx.author.display_name))
while x in range(0, 10):
used = random.choice(self.junk['can'])
if used['action'] == 'trash':
opp = 'recycle'
else:
opp = 'trash'
await ctx.send('``{}``! Will {} ``trash`` it or ``recycle`` it?'.format(used['object'],
ctx.author.display_name))
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
try:
answer = await self.bot.wait_for('message', timeout=120, check=check)
except asyncio.TimeoutError:
answer = None
if answer is None:
await ctx.send('``{}`` fell down the conveyor belt to be sorted again!'.format(used['object']))
elif answer.content.lower().strip() == used['action']:
await ctx.send(
'Congratulations! You put ``{}`` down the correct chute! (**+50**)'.format(used['object']))
reward = reward + 50
x += 1
elif answer.content.lower().strip() == opp:
await ctx.send('{}, you little brute, you put it down the wrong chute! (**-50**)'.format(
ctx.author.display_name))
reward = reward - 50
elif answer.content.lower().strip() == 'exit':
await ctx.send('{} has been relived of their duty.'.format(ctx.author.display_name))
break
else:
await ctx.send('``{}`` fell down the conveyor belt to be sorted again!'.format(used['object']))
else:
if reward > 0:
bank.deposit_credits(ctx.author, reward)
await ctx.send(
'{} been given **{} {}s** for your services.'.format(ctx.author.display_name, reward,
bank.get_currency_name(ctx.guild)))

@ -0,0 +1,5 @@
from .rpsls import RPSLS
def setup(bot):
bot.add_cog(RPSLS(bot))

@ -0,0 +1,21 @@
{
"author": [
"Bobloy",
"SnappyDragon"
],
"bot_version": [
3,
0,
0
],
"description": "Play Rock Papers Scissor Lizard Spock by Sam Kass in Discord!",
"hidden": false,
"install_msg": "Thank you for installing RPSLP. Get started with `[p]load rpsls`, then `[p]rpsls`",
"requirements": [],
"short": "Play Rock Papers Scissor Lizard Spock in Discord!",
"tags": [
"bobloy",
"star trek",
"games"
]
}

@ -0,0 +1,93 @@
import asyncio
import random
import discord
from redbot.core import commands
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class RPSLS(Cog):
"""Play Rock Paper Scissors Lizard Spock."""
weaknesses = {
"rock": [
"paper",
"spock"
],
"paper": [
"scissors",
"lizard"
],
"scissors": [
"spock",
"rock"
],
"lizard": [
"scissors",
"rock"
],
"spock": [
"paper",
"lizard"
]
}
def __init__(self, bot):
self.bot = bot
@commands.command()
async def rpsls(self, ctx: commands.Context, choice: str):
"""
Play Rock Paper Scissors Lizard Spock by Sam Kass in Discord!
Rules:
Scissors cuts Paper
Paper covers Rock
Rock crushes Lizard
Lizard poisons Spock
Spock smashes Scissors
Scissors decapitates Lizard
Lizard eats Paper
Paper disproves Spock
Spock vaporizes Rock
And as it has always Rock crushes Scissors
"""
player_choice = choice.lower()
player_emote = self.get_emote(player_choice)
if player_emote is None:
await ctx.maybe_send_embed("Invalid Choice")
return
bot_choice = random.choice(list(self.weaknesses.keys()))
bot_emote = self.get_emote(bot_choice)
message = '{} vs. {}, who will win?'.format(player_emote, bot_emote)
em = discord.Embed(description=message, color=discord.Color.blue())
await ctx.send(embed=em)
await asyncio.sleep(2)
if player_choice in self.weaknesses[bot_choice]:
message = 'You win! :sob:'
em_color = discord.Color.green()
elif bot_choice in self.weaknesses[player_choice]:
message = 'I win! :smile:'
em_color = discord.Color.red()
else:
message = 'It\'s a draw! :neutral_face:'
em_color = discord.Color.blue()
em = discord.Embed(description=message, color=em_color)
await ctx.send(embed=em)
def get_emote(self, choice):
if choice == 'rock':
emote = ':moyai:'
elif choice == 'spock':
emote = ':vulcan:'
elif choice == 'paper':
emote = ':page_facing_up:'
elif choice in ['scissors', 'lizard']:
emote = ':{}:'.format(choice)
else:
emote = None
return emote

@ -9,7 +9,7 @@
], ],
"description": "Convert any website into text and post it in chat", "description": "Convert any website into text and post it in chat",
"hidden": true, "hidden": true,
"install_msg": "Thank you for installing SayUrl", "install_msg": "Thank you for installing SayUrl! Get started with `[p]load forcemention`, then `[p]help SayUrl",
"requirements": ["html2text"], "requirements": ["html2text"],
"short": "Convert URL to text", "short": "Convert URL to text",
"tags": [ "tags": [

@ -4,16 +4,18 @@ import html2text
from redbot.core import Config, commands from redbot.core import Config, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.utils.chat_formatting import pagify from redbot.core.utils.chat_formatting import pagify
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
async def fetch_url(session, url): async def fetch_url(session, url):
with aiohttp.Timeout(20): async with session.get(url) as response:
async with session.get(url) as response: assert response.status == 200
assert response.status == 200 return await response.text()
return await response.text()
class SayUrl: class SayUrl(Cog):
""" """
V3 Cog Template V3 Cog Template
""" """

@ -0,0 +1,5 @@
from .scp import SCP
def setup(bot):
bot.add_cog(SCP(bot))

@ -0,0 +1,20 @@
{
"author": [
"Bobloy",
"SnappyDragon"
],
"bot_version": [
3,
0,
0
],
"description": "Look up SCP articles. Warning: Some of them may be too creepy or gruesome.",
"hidden": false,
"install_msg": "You are now connected to the SCP database. You may now proceed to access the data using `[p]load scp`, then `[p]help SCP`",
"requirements": [],
"short": "Look up SCP articles.",
"tags": [
"bobloy",
"gruesom"
]
}

@ -0,0 +1,119 @@
import discord
from redbot.core import commands
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class SCP(Cog):
"""Look up SCP articles. Warning: Some of them may be too creepy or gruesome."""
def __init__(self, bot):
self.bot = bot
@commands.command()
async def scp(self, ctx: commands.Context, num: int):
"""Look up SCP articles.
Warning: Some of them may be too creepy or gruesome.
Reminder: You must specify a number between 1 and 4999.
"""
# Thanks Shigbeard and Redjumpman for helping me!
if 0 < num <= 4999:
msg = "http://www.scp-wiki.net/scp-{:03}".format(num)
c = discord.Color.green()
else:
msg = "You must specify a number between 1 and 4999."
c = discord.Color.red()
if ctx.embed_requested():
await ctx.send(embed=discord.Embed(description=msg, color=c))
else:
await ctx.maybe_send_embed(msg)
@commands.command()
async def scpj(self, ctx: commands.Context, joke: str):
"""Look up SCP-Js.
Reminder: Enter the correct name or else the resultant page will be invalid.
Use 001, etc. in case of numbers less than 100.
"""
msg = "http://www.scp-wiki.net/scp-{}-j".format(joke)
await ctx.maybe_send_embed(msg)
@commands.command()
async def scparc(self, ctx: commands.Context, num: int):
"""Look up SCP archives.
Warning: Some of them may be too creepy or gruesome."""
valid_archive = (
13, 48, 51, 89, 91, 112, 132, 138, 157, 186, 232, 234,
244, 252, 257, 338, 356, 361, 400, 406, 503, 515, 517,
578, 728, 744, 776, 784, 837, 922, 987, 1023)
if num in valid_archive:
msg = "http://www.scp-wiki.net/scp-{:03}-arc".format(num)
c = discord.Color.green()
em = discord.Embed(description=msg, color=c)
else:
ttl = "You must specify a valid archive number."
msg = "{}".format(valid_archive)
c = discord.Color.red()
em = discord.Embed(title=ttl, description=msg, color=c)
if ctx.embed_requested():
await ctx.send(embed=em)
else:
await ctx.maybe_send_embed(msg)
@commands.command()
async def scpex(self, ctx: commands.Context, num: int):
"""Look up explained SCP articles.
Warning: Some of them may be too creepy or gruesome.
"""
valid_archive = (711, 920, 1841, 1851, 1974, 2600, 4023, 8900)
if num in valid_archive:
msg = "http://www.scp-wiki.net/scp-{:03}-ex".format(num)
c = discord.Color.green()
em = discord.Embed(description=msg, color=c)
else:
ttl = "You must specify a valid archive number."
msg = "{}".format(valid_archive)
c = discord.Color.red()
em = discord.Embed(title=ttl, description=msg, color=c)
if ctx.embed_requested():
await ctx.send(embed=em)
else:
await ctx.maybe_send_embed(msg)
@commands.command()
async def anomalousitems(self, ctx: commands.Context):
"""Look through the log of anomalous items."""
msg = "http://www.scp-wiki.net/log-of-anomalous-items"
await ctx.maybe_send_embed(msg)
@commands.command()
async def extranormalevents(self, ctx: commands.Context):
"""Look through the log of extranormal events."""
msg = "http://www.scp-wiki.net/log-of-extranormal-events"
await ctx.maybe_send_embed(msg)
@commands.command()
async def unexplainedlocations(self, ctx: commands.Context):
"""Look through the log of unexplained locations."""
msg = "http://www.scp-wiki.net/log-of-unexplained-locations"
await ctx.maybe_send_embed(msg)
def setup(bot):
bot.add_cog(SCP(bot))

@ -4,6 +4,9 @@ import discord
from redbot.core import Config, commands from redbot.core import Config, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
async def fetch_img(session, url): async def fetch_img(session, url):
@ -13,7 +16,7 @@ async def fetch_img(session, url):
return await response.read() return await response.read()
class StealEmoji: class StealEmoji(Cog):
""" """
This cog steals emojis and creates servers for them This cog steals emojis and creates servers for them
""" """

@ -9,7 +9,7 @@
], ],
"description": "Apply roles based on the # of days on server", "description": "Apply roles based on the # of days on server",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing timerole. Configure with [p]timerole", "install_msg": "Thank you for installing timerole.\nGet started with `[p]load timerole`. Configure with [p]timerole",
"requirements": [], "requirements": [],
"short": "Apply roles after # of days", "short": "Apply roles after # of days",
"tags": [ "tags": [

@ -5,9 +5,12 @@ import discord
from redbot.core import Config, checks, commands from redbot.core import Config, checks, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.utils.chat_formatting import pagify from redbot.core.utils.chat_formatting import pagify
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Timerole:
class Timerole(Cog):
"""Add roles to users based on time on server""" """Add roles to users based on time on server"""
def __init__(self, bot: Red): def __init__(self, bot: Red):

@ -9,7 +9,7 @@
], ],
"description": "Send Text2Speech messages as an uploaded mp3", "description": "Send Text2Speech messages as an uploaded mp3",
"hidden": true, "hidden": true,
"install_msg": "Thank you for installing TTS. Get started with `[p]tts`", "install_msg": "Thank you for installing TTS. Get started with `[p]load tts`, then `[p]help TTS`",
"requirements": [ "requirements": [
"gTTS" "gTTS"
], ],

@ -4,11 +4,14 @@ import discord
from gtts import gTTS from gtts import gTTS
from redbot.core import Config, commands from redbot.core import Config, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class TTS:
class TTS(Cog):
""" """
V3 Cog Template Send Text-to-Speech messages
""" """
def __init__(self, bot: Red): def __init__(self, bot: Red):
@ -24,9 +27,7 @@ class TTS:
@commands.command(aliases=["t2s", "text2"]) @commands.command(aliases=["t2s", "text2"])
async def tts(self, ctx: commands.Context, *, text: str): async def tts(self, ctx: commands.Context, *, text: str):
""" """
My custom cog Send Text to speech messages as an mp3
Extra information goes here
""" """
mp3_fp = io.BytesIO() mp3_fp = io.BytesIO()
tts = gTTS(text, 'en') tts = gTTS(text, 'en')

@ -0,0 +1,5 @@
from .unicode import Unicode
def setup(bot):
bot.add_cog(Unicode(bot))

@ -0,0 +1,21 @@
{
"author": [
"Bobloy",
"SnappyDragon"
],
"bot_version": [
3,
0,
0
],
"description": "Encode/Decode Unicode characters!",
"hidden": false,
"install_msg": "\u0048\u0065\u006c\u006c\u006f\u0021 \u0054\u0068\u0069\u0073 \u006d\u0065\u0073\u0073\u0061\u0067\u0065 \u0077\u0061\u0073 \u0077\u0072\u0069\u0074\u0074\u0065\u006e \u0069\u006e \u0055\u004e\u0049\u0043\u004f\u0044\u0045\u002e",
"requirements": [],
"short": "Encode/Decode Unicode characters!",
"tags": [
"bobloy",
"utility",
"tools"
]
}

@ -0,0 +1,52 @@
import codecs as c
import discord
from redbot.core import commands
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Unicode(Cog):
"""Encode/Decode Unicode characters!"""
def __init__(self, bot):
self.bot = bot
@commands.group(name='unicode', pass_context=True)
async def unicode(self, ctx):
"""Encode/Decode a Unicode character."""
if ctx.invoked_subcommand is None:
pass
@unicode.command()
async def decode(self, ctx: commands.Context, character):
"""Decode a Unicode character."""
try:
data = 'U+{:04X}'.format(ord(character[0]))
color = discord.Color.green()
except ValueError:
data = '<unknown>'
color = discord.Color.red()
em = discord.Embed(title=character, description=data, color=color)
await ctx.send(embed=em)
@unicode.command()
async def encode(self, ctx:commands.Context, character):
"""Encode an Unicode character."""
try:
if character[:2] == '\\u':
data = repr(c.decode(character, 'unicode-escape'))
data = data.strip("'")
color = discord.Color.green()
elif character[:2] == 'U+':
data = chr(int(character.lstrip('U+'), 16))
color = discord.Color.green()
else:
data = '<unknown>'
color = discord.Color.red()
except ValueError:
data = '<unknown>'
color = discord.Color.red()
em = discord.Embed(title=character, description=data, color=color)
await ctx.send(embed=em)

@ -318,7 +318,7 @@ class GameBuilder:
pass pass
if page >= len(ROLE_LIST): if page >= len(ROLE_LIST):
self.rand_roles.append(CATEGORY_COUNT[page-len(ROLE_LIST)]) self.rand_roles.append(CATEGORY_COUNT[page - len(ROLE_LIST)])
else: else:
self.code.append(page) self.code.append(page)

@ -1,17 +1,23 @@
import asyncio import asyncio
import random import random
from typing import List, Any, Dict, Set, Union
import discord import discord
from redbot.core import commands from redbot.core import commands
from werewolf.builder import parse_code from werewolf.builder import parse_code
from werewolf.player import Player from werewolf.player import Player
from werewolf.role import Role
from werewolf.votegroup import VoteGroup
class Game: class Game:
""" """
Base class to run a single game of Werewolf Base class to run a single game of Werewolf
""" """
vote_groups: Dict[str, VoteGroup]
roles: List[Role]
players: List[Player]
default_secret_channel = { default_secret_channel = {
"channel": None, "channel": None,

@ -9,7 +9,7 @@
], ],
"description": "Customizable Werewolf Game", "description": "Customizable Werewolf Game",
"hidden": false, "hidden": false,
"install_msg": "Thank you for installing Werewolf! Use [p]wwset to run inital setup", "install_msg": "Thank you for installing Werewolf! Get started with `[p]load werewolf`\n Use `[p]wwset` to run inital setup",
"requirements": [], "requirements": [],
"short": "Werewolf Game", "short": "Werewolf Game",
"tags": [ "tags": [

@ -3,3 +3,21 @@ from werewolf.role import Role
def night_immune(role: Role): def night_immune(role: Role):
role.player.alive = True role.player.alive = True
async def pick_target(role: Role, ctx, data):
if not role.player.alive: # FixMe: Game handles this?
await role.player.send_dm("You're already dead!")
return None
target_id = int(data)
try:
target = role.game.players[target_id]
except IndexError:
target = None
if target is None:
await ctx.send("Not a valid ID")
return None
return target_id, target

@ -1,3 +1,4 @@
from werewolf.night_powers import pick_target
from werewolf.role import Role from werewolf.role import Role
@ -61,7 +62,7 @@ class Seer(Role):
return return
self.see_target = None self.see_target = None
await self.game.generate_targets(self.player.member) await self.game.generate_targets(self.player.member)
await self.player.send_dm("**Pick a target to see tonight**\n") await self.player.send_dm("**Pick a target to see tonight**")
async def _at_night_end(self, data=None): async def _at_night_end(self, data=None):
if self.see_target is None: if self.see_target is None:
@ -83,19 +84,7 @@ class Seer(Role):
async def choose(self, ctx, data): async def choose(self, ctx, data):
"""Handle night actions""" """Handle night actions"""
if not self.player.alive: # FixMe: Game handles this? await super().choose(ctx, data)
await self.player.send_dm("You're already dead!")
return
target_id = int(data)
try:
target = self.game.players[target_id]
except IndexError:
target = None
if target is None:
await ctx.send("Not a valid ID")
return
self.see_target = target_id self.see_target, target = await pick_target(self, ctx, data)
await ctx.send("**You will attempt to see the role of {} tonight...**".format(target.member.display_name)) await ctx.send("**You will attempt to see the role of {} tonight...**".format(target.member.display_name))

@ -1,3 +1,4 @@
from werewolf.night_powers import pick_target
from werewolf.role import Role from werewolf.role import Role
@ -59,6 +60,7 @@ class Shifter(Role):
def __init__(self, game): def __init__(self, game):
super().__init__(game) super().__init__(game)
self.shift_target = None
self.action_list = [ self.action_list = [
(self._at_game_start, 1), # (Action, Priority) (self._at_game_start, 1), # (Action, Priority)
(self._at_day_start, 0), (self._at_day_start, 0),
@ -74,7 +76,7 @@ class Shifter(Role):
async def see_alignment(self, source=None): async def see_alignment(self, source=None):
""" """
Interaction for investigative roles attempting Interaction for investigative roles attempting
to see alignment (Village, Werewolf Other) to see alignment (Village, Werewolf, Other)
""" """
return "Other" return "Other"
@ -90,14 +92,38 @@ class Shifter(Role):
Interaction for investigative roles. Interaction for investigative roles.
More common to be able to deceive this action More common to be able to deceive this action
""" """
return "MyRole" return "Shifter"
async def _at_night_start(self, data=None): async def _at_night_start(self, data=None):
await super()._at_night_start(data) await super()._at_night_start(data)
self.shift_target = None
await self.game.generate_targets(self.player.member)
await self.player.send_dm("**Pick a target to shift into**")
async def _at_night_end(self, data=None): async def _at_night_end(self, data=None):
await super()._at_night_end(data) await super()._at_night_end(data)
if self.shift_target is None:
if self.player.alive:
await self.player.send_dm("You will not use your powers tonight...")
return
target = await self.game.visit(self.shift_target, self.player)
if target and target.player.alive:
await target.role.assign_player(self.player)
await self.assign_player(target)
# Roles have now been swapped
await self.player.send_dm("Your role has been stolen...\n"
"You are now a **Shifter**.")
await self.player.send_dm(self.game_start_message)
await target.send_dm(target.role.game_start_message)
else:
await self.player.send_dm("**Your shift failed...**")
async def choose(self, ctx, data): async def choose(self, ctx, data):
"""Handle night actions""" """Handle night actions"""
await super().choose(ctx, data) await super().choose(ctx, data)
self.shift_target, target = await pick_target(self, ctx, data)
await ctx.send("**You will attempt to see the role of {} tonight...**".format(target.member.display_name))

@ -8,9 +8,12 @@ from redbot.core import commands
from werewolf.builder import GameBuilder, role_from_name, role_from_alignment, role_from_category, role_from_id from werewolf.builder import GameBuilder, role_from_name, role_from_alignment, role_from_category, role_from_id
from werewolf.game import Game from werewolf.game import Game
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS from redbot.core.utils.menus import menu, DEFAULT_CONTROLS
from typing import Any
Cog: Any = getattr(commands, "Cog", object)
class Werewolf:
class Werewolf(Cog):
""" """
Base to host werewolf on a guild Base to host werewolf on a guild
""" """
@ -389,4 +392,3 @@ class Werewolf:
return False, None, None, None, None return False, None, None, None, None
return True, role, category, channel, log_channel return True, role, category, channel, log_channel

Loading…
Cancel
Save