Merge branch 'master' into werewolf_develop
# Conflicts: # werewolf/builder.py # werewolf/game.py # werewolf/werewolf.py
This commit is contained in:
		
						commit
						3296c03de2
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,2 +1,5 @@ | |||||||
| .idea/ | .idea/ | ||||||
| *.pyc | *.pyc | ||||||
|  | venv/ | ||||||
|  | v-data/ | ||||||
|  | database.sqlite3 | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @ -3,19 +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> | | ||||||
|  | | 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 | **Incomplete** | <details><summary>Create temporary marks on users that expire after specified time</summary>Not yet ported to v3</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> | | ||||||
| | 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>Create temporary marks on users that expire after specified time</summary>Not yet ported to v3</details> | | | howdoi | **Incomplete** | <details><summary>Ask coding questions and get results from StackExchange</summary>Not yet functional</details> | | ||||||
| | leaver | **Incomplete** | <details><summary>Send a message in a channel when a user leaves the server</summary>Not yet ported to v3</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> | | ||||||
|  | | 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> | | ||||||
| | werewolf | **Alpha** | <details><summary>Play the classic party game Werewolf within discord</summary>Another massive project currently being developed, will be fully customizable</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 | **Beta** | <details><summary>Send a Text-to-Speech message as an uploaded mp3</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 | **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) | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								announcedaily/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								announcedaily/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -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()) | ||||||
							
								
								
									
										253
									
								
								announcedaily/announcedaily.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								announcedaily/announcedaily.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										18
									
								
								announcedaily/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								announcedaily/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								audiotrivia/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								audiotrivia/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -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)) | ||||||
							
								
								
									
										74
									
								
								audiotrivia/audiosession.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								audiotrivia/audiosession.py
									
									
									
									
									
										Normal file
									
								
							| @ -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() | ||||||
							
								
								
									
										212
									
								
								audiotrivia/audiotrivia.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								audiotrivia/audiotrivia.py
									
									
									
									
									
										Normal file
									
								
							| @ -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")) | ||||||
							
								
								
									
										106
									
								
								audiotrivia/data/lists/csgo.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								audiotrivia/data/lists/csgo.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										5183
									
								
								audiotrivia/data/lists/games-plab.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5183
									
								
								audiotrivia/data/lists/games-plab.yaml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										304
									
								
								audiotrivia/data/lists/games.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								audiotrivia/data/lists/games.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										4
									
								
								audiotrivia/data/lists/guitar.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								audiotrivia/data/lists/guitar.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | https://www.youtube.com/watch?v=hfyE220BsD0: | ||||||
|  | - holiday | ||||||
|  | https://www.youtube.com/watch?v=Hh3U9iPKeXQ: | ||||||
|  | - sultans of swing | ||||||
							
								
								
									
										4
									
								
								audiotrivia/data/lists/league.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								audiotrivia/data/lists/league.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | https://www.youtube.com/watch?v=Hi1kUdreiWk: | ||||||
|  | - Jinx | ||||||
|  | https://www.youtube.com/watch?v=PNYHFluhOGI: | ||||||
|  | - Teemo | ||||||
							
								
								
									
										20
									
								
								audiotrivia/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								audiotrivia/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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 discord.ext import commands |  | ||||||
| from redbot.core import Config, checks | from redbot.core import Config, checks | ||||||
|  | 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,13 +26,14 @@ 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 | ||||||
| 
 | 
 | ||||||
|         Highly customizable custom commands with role management.""" |         Highly customizable custom commands with role management.""" | ||||||
|         if not ctx.invoked_subcommand: |         if not ctx.invoked_subcommand: | ||||||
|             await ctx.send_help() |             pass | ||||||
| 
 | 
 | ||||||
|     @ccrole.command(name="add") |     @ccrole.command(name="add") | ||||||
|     @checks.mod_or_permissions(administrator=True) |     @checks.mod_or_permissions(administrator=True) | ||||||
| @ -105,7 +109,7 @@ class CCRole: | |||||||
|                 return |                 return | ||||||
| 
 | 
 | ||||||
|         # Selfrole |         # Selfrole | ||||||
|         await ctx.send('Is this a targeted command?(yes/no)\nNo will make this a selfrole command') |         await ctx.send('Is this a targeted command?(yes//no)\nNo will make this a selfrole command') | ||||||
| 
 | 
 | ||||||
|         try: |         try: | ||||||
|             answer = await self.bot.wait_for('message', timeout=120, check=check) |             answer = await self.bot.wait_for('message', timeout=120, check=check) | ||||||
| @ -190,7 +194,7 @@ class CCRole: | |||||||
|         """Shows custom commands list""" |         """Shows custom commands list""" | ||||||
|         guild = ctx.guild |         guild = ctx.guild | ||||||
|         cmd_list = await self.config.guild(guild).cmdlist() |         cmd_list = await self.config.guild(guild).cmdlist() | ||||||
|         cmd_list = {k: v for k,v in cmd_list.items() if v} |         cmd_list = {k: v for k, v in cmd_list.items() if v} | ||||||
|         if not cmd_list: |         if not cmd_list: | ||||||
|             await ctx.send( |             await ctx.send( | ||||||
|                 "There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format( |                 "There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format( | ||||||
|  | |||||||
| @ -1,10 +1,22 @@ | |||||||
| { | { | ||||||
|     "author" : ["Bobloy"], |   "author": [ | ||||||
|     "bot_version" : [3,0,0], |     "Bobloy" | ||||||
|     "description" : "[Incomplete] Creates custom commands to adjust roles and send custom messages", |   ], | ||||||
|     "hidden" : false, |   "bot_version": [ | ||||||
|     "install_msg" : "Thank you for installing Custom Commands w/ Roles.", |     3, | ||||||
|     "requirements" : [], |     0, | ||||||
|     "short" : "[Incomplete] Creates commands that adjust roles", |     0 | ||||||
|     "tags" : ["fox", "bobloy", "utility", "tools", "roles"] |   ], | ||||||
|  |   "description": "[Incomplete] Creates custom commands to adjust roles and send custom messages", | ||||||
|  |   "hidden": false, | ||||||
|  |   "install_msg": "Thank you for installing Custom Commands w/ Roles. Get started with `[p]load ccrole` and `[p]help CCRole`", | ||||||
|  |   "requirements": [], | ||||||
|  |   "short": "[Incomplete] Creates commands that adjust roles", | ||||||
|  |   "tags": [ | ||||||
|  |     "fox", | ||||||
|  |     "bobloy", | ||||||
|  |     "utility", | ||||||
|  |     "tools", | ||||||
|  |     "roles" | ||||||
|  |   ] | ||||||
| } | } | ||||||
| @ -1,16 +1,22 @@ | |||||||
| import asyncio | import asyncio | ||||||
|  | import pathlib | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
| 
 | 
 | ||||||
| import discord | import discord | ||||||
| from discord.ext import commands |  | ||||||
| from redbot.core import Config | from redbot.core import Config | ||||||
|  | from redbot.core import commands | ||||||
|  | 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.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(Cog): | ||||||
| class Chatter: |  | ||||||
|     """ |     """ | ||||||
|     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 | ||||||
|     """ |     """ | ||||||
| @ -23,11 +29,23 @@ class Chatter: | |||||||
|             "whitelist": None, |             "whitelist": None, | ||||||
|             "days": 1 |             "days": 1 | ||||||
|         } |         } | ||||||
|  |         path: pathlib.Path = cog_data_path(self) | ||||||
|  |         data_path = path / ("database.sqlite3") | ||||||
| 
 | 
 | ||||||
|         self.chatbot = ChatBot( |         self.chatbot = ChatBot( | ||||||
|             "ChatterBot", |             "ChatterBot", | ||||||
|             storage_adapter='chatter.chatterbot.storage.SQLStorageAdapter', |             storage_adapter='chatter.chatterbot.storage.SQLStorageAdapter', | ||||||
|             database='./database.sqlite3' |             database=str(data_path), | ||||||
|  |             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) | ||||||
| 
 | 
 | ||||||
| @ -42,21 +60,42 @@ class Chatter: | |||||||
|         Currently takes a stupid long time |         Currently takes a stupid long time | ||||||
|         Returns a list of text |         Returns a list of text | ||||||
|         """ |         """ | ||||||
|         out = [] |         out = [[]] | ||||||
|         after = datetime.today() - timedelta(days=(await self.config.guild(ctx.guild).days())) |         after = datetime.today() - timedelta(days=(await self.config.guild(ctx.guild).days())) | ||||||
| 
 | 
 | ||||||
|  |         def new_message(msg, sent, out_in): | ||||||
|  |             if sent is None: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |             if len(out_in) < 2: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |             return msg.created_at - sent >= timedelta(hours=3)  # This should be configurable perhaps | ||||||
|  | 
 | ||||||
|         for channel in ctx.guild.text_channels: |         for channel in ctx.guild.text_channels: | ||||||
|             if in_channel: |             if in_channel: | ||||||
|                 channel = in_channel |                 channel = in_channel | ||||||
|             await ctx.send("Gathering {}".format(channel.mention)) |             await ctx.send("Gathering {}".format(channel.mention)) | ||||||
|             user = None |             user = None | ||||||
|  |             i = 0 | ||||||
|  |             send_time = None | ||||||
|             try: |             try: | ||||||
|  | 
 | ||||||
|                 async for message in channel.history(limit=None, reverse=True, after=after): |                 async for message in channel.history(limit=None, reverse=True, after=after): | ||||||
|  |                     # if message.author.bot:  # Skip bot messages | ||||||
|  |                     #     continue | ||||||
|  |                     if new_message(message, send_time, out[i]): | ||||||
|  |                         out.append([]) | ||||||
|  |                         i += 1 | ||||||
|  |                         user = None | ||||||
|  |                     else: | ||||||
|  |                         send_time = message.created_at + timedelta(seconds=1) | ||||||
|                     if user == message.author: |                     if user == message.author: | ||||||
|                         out[-1] += "\n" + message.clean_content |                         out[i][-1] += "\n" + message.clean_content | ||||||
|                     else: |                     else: | ||||||
|                         user = message.author |                         user = message.author | ||||||
|                         out.append(message.clean_content) |                         out[i].append(message.clean_content) | ||||||
|  | 
 | ||||||
|             except discord.Forbidden: |             except discord.Forbidden: | ||||||
|                 pass |                 pass | ||||||
|             except discord.HTTPException: |             except discord.HTTPException: | ||||||
| @ -69,21 +108,22 @@ class Chatter: | |||||||
| 
 | 
 | ||||||
|     def _train(self, data): |     def _train(self, data): | ||||||
|         try: |         try: | ||||||
|             self.chatbot.train(data) |             for convo in data: | ||||||
|  |                 self.chatbot.train(convo) | ||||||
|         except: |         except: | ||||||
|             return False |             return False | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
|     @commands.group() |     @commands.group(invoke_without_command=False) | ||||||
|     async def chatter(self, ctx: RedContext): |     async def chatter(self, ctx: commands.Context): | ||||||
|         """ |         """ | ||||||
|         Base command for this cog. Check help for the commands list. |         Base command for this cog. Check help for the commands list. | ||||||
|         """ |         """ | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
| 
 | 
 | ||||||
|     @chatter.command() |     @chatter.command() | ||||||
|     async def age(self, ctx: RedContext, days: int): |     async def age(self, ctx: commands.Context, days: int): | ||||||
|         """ |         """ | ||||||
|         Sets the number of days to look back |         Sets the number of days to look back | ||||||
|         Will train on 1 day otherwise |         Will train on 1 day otherwise | ||||||
| @ -98,7 +138,8 @@ class Chatter: | |||||||
|         Backup your training data to a json for later use |         Backup your training data to a json for later use | ||||||
|         """ |         """ | ||||||
|         await ctx.send("Backing up data, this may take a while") |         await ctx.send("Backing up data, this may take a while") | ||||||
|         future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training, './{}.json'.format(backupname)) |         future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training, | ||||||
|  |                                                  './{}.json'.format(backupname)) | ||||||
| 
 | 
 | ||||||
|         if future: |         if future: | ||||||
|             await ctx.send("Backup successful!") |             await ctx.send("Backup successful!") | ||||||
| @ -133,17 +174,21 @@ class Chatter: | |||||||
|         else: |         else: | ||||||
|             await ctx.send("Error occurred :(") |             await ctx.send("Error occurred :(") | ||||||
| 
 | 
 | ||||||
|     async def on_message(self, message): |     async def on_message(self, message: discord.Message): | ||||||
|         """ |         """ | ||||||
|         Credit to https://github.com/Twentysix26/26-Cogs/blob/master/cleverbot/cleverbot.py |         Credit to https://github.com/Twentysix26/26-Cogs/blob/master/cleverbot/cleverbot.py | ||||||
|         for on_message recognition of @bot |         for on_message recognition of @bot | ||||||
|         """ |         """ | ||||||
|         author = message.author |         author = message.author | ||||||
|         channel = message.channel |         try: | ||||||
|  |             guild: discord.Guild = message.guild | ||||||
|  |         except AttributeError:  # Not a guild message | ||||||
|  |             return | ||||||
| 
 | 
 | ||||||
|  |         channel: discord.TextChannel = message.channel | ||||||
| 
 | 
 | ||||||
|         if message.author.id != self.bot.user.id: |         if author.id != self.bot.user.id: | ||||||
|             to_strip = "@" + author.guild.me.display_name + " " |             to_strip = "@" + guild.me.display_name + " " | ||||||
|             text = message.clean_content |             text = message.clean_content | ||||||
|             if not text.startswith(to_strip): |             if not text.startswith(to_strip): | ||||||
|                 return |                 return | ||||||
| @ -151,7 +196,7 @@ class Chatter: | |||||||
|             async with channel.typing(): |             async with channel.typing(): | ||||||
|                 future = await self.loop.run_in_executor(None, self.chatbot.get_response, text) |                 future = await self.loop.run_in_executor(None, self.chatbot.get_response, text) | ||||||
| 
 | 
 | ||||||
|                 if future: |                 if future and str(future): | ||||||
|                     await channel.send(str(future)) |                     await channel.send(str(future)) | ||||||
|                 else: |                 else: | ||||||
|                     await channel.send(':thinking:') |                     await channel.send(':thinking:') | ||||||
|  | |||||||
| @ -2,10 +2,7 @@ from __future__ import unicode_literals | |||||||
| 
 | 
 | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| from . import utils | from chatter.chatterbot import utils | ||||||
| from .input import InputAdapter |  | ||||||
| from .output import OutputAdapter |  | ||||||
| from .storage import StorageAdapter |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ChatBot(object): | class ChatBot(object): | ||||||
| @ -14,7 +11,7 @@ class ChatBot(object): | |||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, name, **kwargs): |     def __init__(self, name, **kwargs): | ||||||
|         from .logic import MultiLogicAdapter |         from chatter.chatterbot.logic import MultiLogicAdapter | ||||||
| 
 | 
 | ||||||
|         self.name = name |         self.name = name | ||||||
|         kwargs['name'] = name |         kwargs['name'] = name | ||||||
| @ -33,9 +30,9 @@ class ChatBot(object): | |||||||
|         output_adapter = kwargs.get('output_adapter', 'chatter.chatterbot.output.OutputAdapter') |         output_adapter = kwargs.get('output_adapter', 'chatter.chatterbot.output.OutputAdapter') | ||||||
| 
 | 
 | ||||||
|         # Check that each adapter is a valid subclass of it's respective parent |         # Check that each adapter is a valid subclass of it's respective parent | ||||||
|         utils.validate_adapter_class(storage_adapter, StorageAdapter) |         # utils.validate_adapter_class(storage_adapter, StorageAdapter) | ||||||
|         utils.validate_adapter_class(input_adapter, InputAdapter) |         # utils.validate_adapter_class(input_adapter, InputAdapter) | ||||||
|         utils.validate_adapter_class(output_adapter, OutputAdapter) |         # utils.validate_adapter_class(output_adapter, OutputAdapter) | ||||||
| 
 | 
 | ||||||
|         self.logic = MultiLogicAdapter(**kwargs) |         self.logic = MultiLogicAdapter(**kwargs) | ||||||
|         self.storage = utils.initialize_class(storage_adapter, **kwargs) |         self.storage = utils.initialize_class(storage_adapter, **kwargs) | ||||||
| @ -139,7 +136,7 @@ class ChatBot(object): | |||||||
|         """ |         """ | ||||||
|         Learn that the statement provided is a valid response. |         Learn that the statement provided is a valid response. | ||||||
|         """ |         """ | ||||||
|         from .conversation import Response |         from chatter.chatterbot.conversation import Response | ||||||
| 
 | 
 | ||||||
|         if previous_statement: |         if previous_statement: | ||||||
|             statement.add_response( |             statement.add_response( | ||||||
|  | |||||||
| @ -92,7 +92,7 @@ class SynsetDistance(Comparator): | |||||||
|         """ |         """ | ||||||
|         Download required NLTK corpora if they have not already been downloaded. |         Download required NLTK corpora if they have not already been downloaded. | ||||||
|         """ |         """ | ||||||
|         from .utils import nltk_download_corpus |         from chatter.chatterbot.utils import nltk_download_corpus | ||||||
| 
 | 
 | ||||||
|         nltk_download_corpus('corpora/wordnet') |         nltk_download_corpus('corpora/wordnet') | ||||||
| 
 | 
 | ||||||
| @ -100,7 +100,7 @@ class SynsetDistance(Comparator): | |||||||
|         """ |         """ | ||||||
|         Download required NLTK corpora if they have not already been downloaded. |         Download required NLTK corpora if they have not already been downloaded. | ||||||
|         """ |         """ | ||||||
|         from .utils import nltk_download_corpus |         from chatter.chatterbot.utils import nltk_download_corpus | ||||||
| 
 | 
 | ||||||
|         nltk_download_corpus('tokenizers/punkt') |         nltk_download_corpus('tokenizers/punkt') | ||||||
| 
 | 
 | ||||||
| @ -108,7 +108,7 @@ class SynsetDistance(Comparator): | |||||||
|         """ |         """ | ||||||
|         Download required NLTK corpora if they have not already been downloaded. |         Download required NLTK corpora if they have not already been downloaded. | ||||||
|         """ |         """ | ||||||
|         from .utils import nltk_download_corpus |         from chatter.chatterbot.utils import nltk_download_corpus | ||||||
| 
 | 
 | ||||||
|         nltk_download_corpus('corpora/stopwords') |         nltk_download_corpus('corpora/stopwords') | ||||||
| 
 | 
 | ||||||
| @ -177,7 +177,7 @@ class SentimentComparison(Comparator): | |||||||
|         Download the NLTK vader lexicon for sentiment analysis |         Download the NLTK vader lexicon for sentiment analysis | ||||||
|         that is required for this algorithm to run. |         that is required for this algorithm to run. | ||||||
|         """ |         """ | ||||||
|         from .utils import nltk_download_corpus |         from chatter.chatterbot.utils import nltk_download_corpus | ||||||
| 
 | 
 | ||||||
|         nltk_download_corpus('sentiment/vader_lexicon') |         nltk_download_corpus('sentiment/vader_lexicon') | ||||||
| 
 | 
 | ||||||
| @ -252,7 +252,7 @@ class JaccardSimilarity(Comparator): | |||||||
|         Download the NLTK wordnet corpora that is required for this algorithm |         Download the NLTK wordnet corpora that is required for this algorithm | ||||||
|         to run only if the corpora has not already been downloaded. |         to run only if the corpora has not already been downloaded. | ||||||
|         """ |         """ | ||||||
|         from .utils import nltk_download_corpus |         from chatter.chatterbot.utils import nltk_download_corpus | ||||||
| 
 | 
 | ||||||
|         nltk_download_corpus('corpora/wordnet') |         nltk_download_corpus('corpora/wordnet') | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ class StatementMixin(object): | |||||||
|     This class has shared methods used to |     This class has shared methods used to | ||||||
|     normalize different statement models. |     normalize different statement models. | ||||||
|     """ |     """ | ||||||
|  |     tags = [] | ||||||
| 
 | 
 | ||||||
|     def get_tags(self): |     def get_tags(self): | ||||||
|         """ |         """ | ||||||
| @ -148,11 +149,7 @@ class Statement(StatementMixin): | |||||||
|         :returns: A dictionary representation of the statement object. |         :returns: A dictionary representation of the statement object. | ||||||
|         :rtype: dict |         :rtype: dict | ||||||
|         """ |         """ | ||||||
|         data = {} |         data = {'text': self.text, 'in_response_to': [], 'extra_data': self.extra_data} | ||||||
| 
 |  | ||||||
|         data['text'] = self.text |  | ||||||
|         data['in_response_to'] = [] |  | ||||||
|         data['extra_data'] = self.extra_data |  | ||||||
| 
 | 
 | ||||||
|         for response in self.in_response_to: |         for response in self.in_response_to: | ||||||
|             data['in_response_to'].append(response.serialize()) |             data['in_response_to'].append(response.serialize()) | ||||||
| @ -211,11 +208,6 @@ class Response(object): | |||||||
|         return self.text == other |         return self.text == other | ||||||
| 
 | 
 | ||||||
|     def serialize(self): |     def serialize(self): | ||||||
|         data = {} |         data = {'text': self.text, 'created_at': self.created_at.isoformat(), 'occurrence': self.occurrence} | ||||||
| 
 |  | ||||||
|         data['text'] = self.text |  | ||||||
|         data['created_at'] = self.created_at.isoformat() |  | ||||||
| 
 |  | ||||||
|         data['occurrence'] = self.occurrence |  | ||||||
| 
 | 
 | ||||||
|         return data |         return data | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| from .best_match import BestMatch |  | ||||||
| from .logic_adapter import LogicAdapter | from .logic_adapter import LogicAdapter | ||||||
|  | from .best_match import BestMatch | ||||||
| from .low_confidence import LowConfidenceAdapter | from .low_confidence import LowConfidenceAdapter | ||||||
| from .mathematical_evaluation import MathematicalEvaluation | from .mathematical_evaluation import MathematicalEvaluation | ||||||
| from .multi_adapter import MultiLogicAdapter | from .multi_adapter import MultiLogicAdapter | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from .logic_adapter import LogicAdapter | from chatter.chatterbot.logic import LogicAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BestMatch(LogicAdapter): | class BestMatch(LogicAdapter): | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from chatter.chatterbot.conversation import Statement | from chatter.chatterbot.conversation import Statement | ||||||
| from .best_match import BestMatch | from chatter.chatterbot.logic import BestMatch | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class LowConfidenceAdapter(BestMatch): | class LowConfidenceAdapter(BestMatch): | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ from __future__ import unicode_literals | |||||||
| from collections import Counter | from collections import Counter | ||||||
| 
 | 
 | ||||||
| from chatter.chatterbot import utils | from chatter.chatterbot import utils | ||||||
| from .logic_adapter import LogicAdapter | from chatter.chatterbot.logic import LogicAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MultiLogicAdapter(LogicAdapter): | class MultiLogicAdapter(LogicAdapter): | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from .logic_adapter import LogicAdapter | from chatter.chatterbot.logic import LogicAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class NoKnowledgeAdapter(LogicAdapter): | class NoKnowledgeAdapter(LogicAdapter): | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from .logic_adapter import LogicAdapter | from chatter.chatterbot.logic import LogicAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class SpecificResponseAdapter(LogicAdapter): | class SpecificResponseAdapter(LogicAdapter): | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ from __future__ import unicode_literals | |||||||
| 
 | 
 | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 | 
 | ||||||
| from .logic_adapter import LogicAdapter | from chatter.chatterbot.logic import LogicAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TimeLogicAdapter(LogicAdapter): | class TimeLogicAdapter(LogicAdapter): | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
|  | from .output_adapter import OutputAdapter | ||||||
| from .gitter import Gitter | from .gitter import Gitter | ||||||
| from .hipchat import HipChat | from .hipchat import HipChat | ||||||
| from .mailgun import Mailgun | from .mailgun import Mailgun | ||||||
| from .microsoft import Microsoft | from .microsoft import Microsoft | ||||||
| from .output_adapter import OutputAdapter |  | ||||||
| from .terminal import TerminalAdapter | from .terminal import TerminalAdapter | ||||||
| 
 | 
 | ||||||
| __all__ = ( | __all__ = ( | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from .output_adapter import OutputAdapter | from chatter.chatterbot.output import OutputAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Gitter(OutputAdapter): | class Gitter(OutputAdapter): | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ from __future__ import unicode_literals | |||||||
| 
 | 
 | ||||||
| import json | import json | ||||||
| 
 | 
 | ||||||
| from .output_adapter import OutputAdapter | from chatter.chatterbot.output import OutputAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HipChat(OutputAdapter): | class HipChat(OutputAdapter): | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from .output_adapter import OutputAdapter | from chatter.chatterbot.output import OutputAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Mailgun(OutputAdapter): | class Mailgun(OutputAdapter): | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ from __future__ import unicode_literals | |||||||
| 
 | 
 | ||||||
| import json | import json | ||||||
| 
 | 
 | ||||||
| from .output_adapter import OutputAdapter | from chatter.chatterbot.output import OutputAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Microsoft(OutputAdapter): | class Microsoft(OutputAdapter): | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from .output_adapter import OutputAdapter | from chatter.chatterbot.output import OutputAdapter | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TerminalAdapter(OutputAdapter): | class TerminalAdapter(OutputAdapter): | ||||||
|  | |||||||
| @ -611,6 +611,7 @@ def date_from_duration(base_date, number_as_string, unit, duration, base_time=No | |||||||
|     if base_time is not None: |     if base_time is not None: | ||||||
|         base_date = date_from_adverb(base_date, base_time) |         base_date = date_from_adverb(base_date, base_time) | ||||||
|     num = convert_string_to_number(number_as_string) |     num = convert_string_to_number(number_as_string) | ||||||
|  |     args = {} | ||||||
|     if unit in day_variations: |     if unit in day_variations: | ||||||
|         args = {'days': num} |         args = {'days': num} | ||||||
|     elif unit in minute_variations: |     elif unit in minute_variations: | ||||||
|  | |||||||
| @ -183,7 +183,7 @@ class SQLStorageAdapter(StorageAdapter): | |||||||
|                     if isinstance(_filter, list): |                     if isinstance(_filter, list): | ||||||
|                         if len(_filter) == 0: |                         if len(_filter) == 0: | ||||||
|                             _query = _response_query.filter( |                             _query = _response_query.filter( | ||||||
|                                 Statement.in_response_to == None  # NOQA Here must use == instead of is |                                 Statement.in_response_to is None  # NOQA Here must use == instead of is | ||||||
|                             ) |                             ) | ||||||
|                         else: |                         else: | ||||||
|                             for f in _filter: |                             for f in _filter: | ||||||
| @ -193,7 +193,7 @@ class SQLStorageAdapter(StorageAdapter): | |||||||
|                         if fp == 'in_response_to__contains': |                         if fp == 'in_response_to__contains': | ||||||
|                             _query = _response_query.join(Response).filter(Response.text == _filter) |                             _query = _response_query.join(Response).filter(Response.text == _filter) | ||||||
|                         else: |                         else: | ||||||
|                             _query = _response_query.filter(Statement.in_response_to == None)  # NOQA |                             _query = _response_query.filter(Statement.in_response_to is None)  # NOQA | ||||||
|                 else: |                 else: | ||||||
|                     if _query: |                     if _query: | ||||||
|                         _query = _query.filter(Response.statement_text.like('%' + _filter + '%')) |                         _query = _query.filter(Response.statement_text.like('%' + _filter + '%')) | ||||||
|  | |||||||
| @ -158,7 +158,9 @@ class StorageAdapter(object): | |||||||
|     class EmptyDatabaseException(Exception): |     class EmptyDatabaseException(Exception): | ||||||
| 
 | 
 | ||||||
|         def __init__(self, |         def __init__(self, | ||||||
|                      value='The database currently contains no entries. At least one entry is expected. You may need to train your chat bot to populate your database.'): |                      value='The database currently contains no entries. ' | ||||||
|  |                            'At least one entry is expected. ' | ||||||
|  |                            'You may need to train your chat bot to populate your database.'): | ||||||
|             self.value = value |             self.value = value | ||||||
| 
 | 
 | ||||||
|         def __str__(self): |         def __str__(self): | ||||||
|  | |||||||
| @ -2,8 +2,8 @@ import logging | |||||||
| import os | import os | ||||||
| import sys | import sys | ||||||
| 
 | 
 | ||||||
| from . import utils | from chatter.chatterbot import utils | ||||||
| from .conversation import Statement, Response | from chatter.chatterbot.conversation import Statement, Response | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Trainer(object): | class Trainer(object): | ||||||
| @ -127,7 +127,7 @@ class ChatterBotCorpusTrainer(Trainer): | |||||||
| 
 | 
 | ||||||
|     def __init__(self, storage, **kwargs): |     def __init__(self, storage, **kwargs): | ||||||
|         super(ChatterBotCorpusTrainer, self).__init__(storage, **kwargs) |         super(ChatterBotCorpusTrainer, self).__init__(storage, **kwargs) | ||||||
|         from .corpus import Corpus |         from chatter.chatterbot.corpus import Corpus | ||||||
| 
 | 
 | ||||||
|         self.corpus = Corpus() |         self.corpus = Corpus() | ||||||
| 
 | 
 | ||||||
| @ -225,7 +225,7 @@ class TwitterTrainer(Trainer): | |||||||
| 
 | 
 | ||||||
|             for word in tweet_words: |             for word in tweet_words: | ||||||
|                 # If the word contains only letters with a length from 4 to 9 |                 # If the word contains only letters with a length from 4 to 9 | ||||||
|                 if word.isalpha() and len(word) > 3 and len(word) <= 9: |                 if word.isalpha() and 3 < len(word) <= 9: | ||||||
|                     words.add(word) |                     words.add(word) | ||||||
| 
 | 
 | ||||||
|         return words |         return words | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ def validate_adapter_class(validate_class, adapter_class): | |||||||
| 
 | 
 | ||||||
|     :raises: Adapter.InvalidAdapterTypeException |     :raises: Adapter.InvalidAdapterTypeException | ||||||
|     """ |     """ | ||||||
|     from .adapters import Adapter |     from chatter.chatterbot.adapters import Adapter | ||||||
| 
 | 
 | ||||||
|     # If a dictionary was passed in, check if it has an import_path attribute |     # If a dictionary was passed in, check if it has an import_path attribute | ||||||
|     if isinstance(validate_class, dict): |     if isinstance(validate_class, dict): | ||||||
|  | |||||||
| @ -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", | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								coglint/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								coglint/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .coglint import CogLint | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(CogLint(bot)) | ||||||
							
								
								
									
										89
									
								
								coglint/coglint.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								coglint/coglint.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | |||||||
|  | import discord | ||||||
|  | from pylint import epylint as lint | ||||||
|  | from redbot.core import Config | ||||||
|  | from redbot.core import commands | ||||||
|  | from redbot.core.bot import Red | ||||||
|  | from redbot.core.data_manager import cog_data_path | ||||||
|  | from typing import Any | ||||||
|  | 
 | ||||||
|  | Cog: Any = getattr(commands, "Cog", object) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CogLint(Cog): | ||||||
|  |     """ | ||||||
|  |     Automatically lint code in python codeblocks | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, bot: Red): | ||||||
|  |         self.bot = bot | ||||||
|  |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|  |         default_global = { | ||||||
|  |             "lint": True | ||||||
|  |         } | ||||||
|  |         default_guild = {} | ||||||
|  | 
 | ||||||
|  |         self.path = str(cog_data_path(self)).replace('\\', '/') | ||||||
|  | 
 | ||||||
|  |         self.do_lint = None | ||||||
|  |         self.counter = 0 | ||||||
|  | 
 | ||||||
|  |         # self.answer_path = self.path + "/tmpfile.py" | ||||||
|  | 
 | ||||||
|  |         self.config.register_global(**default_global) | ||||||
|  |         self.config.register_guild(**default_guild) | ||||||
|  | 
 | ||||||
|  |     @commands.command() | ||||||
|  |     async def autolint(self, ctx: commands.Context): | ||||||
|  |         """Toggles automatically linting code""" | ||||||
|  |         curr = await self.config.lint() | ||||||
|  | 
 | ||||||
|  |         self.do_lint = not curr | ||||||
|  |         await self.config.lint.set(not curr) | ||||||
|  |         await ctx.send("Autolinting is now set to {}".format(not curr)) | ||||||
|  | 
 | ||||||
|  |     @commands.command() | ||||||
|  |     async def lint(self, ctx: commands.Context, *, code): | ||||||
|  |         """Lint python code | ||||||
|  | 
 | ||||||
|  |         Toggle autolinting with `[p]autolint` | ||||||
|  |         """ | ||||||
|  |         await self.lint_message(ctx.message) | ||||||
|  |         await ctx.send("Hello World") | ||||||
|  | 
 | ||||||
|  |     async def lint_code(self, code): | ||||||
|  |         self.counter += 1 | ||||||
|  |         path = self.path + "/{}.py".format(self.counter) | ||||||
|  |         with open(path, 'w') as codefile: | ||||||
|  |             codefile.write(code) | ||||||
|  | 
 | ||||||
|  |         future = await self.bot.loop.run_in_executor(None, lint.py_run, path, 'return_std=True') | ||||||
|  | 
 | ||||||
|  |         if future: | ||||||
|  |             (pylint_stdout, pylint_stderr) = future | ||||||
|  |         else: | ||||||
|  |             (pylint_stdout, pylint_stderr) = None, None | ||||||
|  | 
 | ||||||
|  |         # print(pylint_stderr) | ||||||
|  |         # print(pylint_stdout) | ||||||
|  | 
 | ||||||
|  |         return pylint_stdout, pylint_stderr | ||||||
|  | 
 | ||||||
|  |     async def lint_message(self, message): | ||||||
|  |         if self.do_lint is None: | ||||||
|  |             self.do_lint = await self.config.lint() | ||||||
|  |         if not self.do_lint: | ||||||
|  |             return | ||||||
|  |         code_blocks = message.content.split('```')[1::2] | ||||||
|  | 
 | ||||||
|  |         for c in code_blocks: | ||||||
|  |             is_python, code = c.split(None, 1) | ||||||
|  |             is_python = is_python.lower() == 'python' | ||||||
|  |             if is_python:  # Then we're in business | ||||||
|  |                 linted, errors = await self.lint_code(code) | ||||||
|  |                 linted = linted.getvalue() | ||||||
|  |                 errors = errors.getvalue() | ||||||
|  |                 await message.channel.send(linted) | ||||||
|  |                 # await message.channel.send(errors) | ||||||
|  | 
 | ||||||
|  |     async def on_message(self, message: discord.Message): | ||||||
|  |         await self.lint_message(message) | ||||||
							
								
								
									
										20
									
								
								coglint/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								coglint/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Lint python code posted in chat", | ||||||
|  |   "hidden": true, | ||||||
|  |   "install_msg": "Thank you for installing CogLint! Get started with `[p]load coglint` and `[p]help CogLint`", | ||||||
|  |   "requirements": [], | ||||||
|  |   "short": "Python cog linter", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "utils", | ||||||
|  |     "tools" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								dad/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								dad/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .dad import Dad | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(Dad(bot)) | ||||||
							
								
								
									
										112
									
								
								dad/dad.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								dad/dad.py
									
									
									
									
									
										Normal file
									
								
							| @ -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())) | ||||||
							
								
								
									
										20
									
								
								dad/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								dad/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								exclusiverole/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								exclusiverole/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .exclusiverole import ExclusiveRole | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(ExclusiveRole(bot)) | ||||||
							
								
								
									
										92
									
								
								exclusiverole/exclusiverole.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								exclusiverole/exclusiverole.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										22
									
								
								exclusiverole/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								exclusiverole/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @ -1,10 +1,11 @@ | |||||||
|  | import asyncio | ||||||
| import os | import os | ||||||
| import math | import math | ||||||
| 
 | 
 | ||||||
| # from typing import Union | # from typing import Union | ||||||
| 
 | 
 | ||||||
| import discord | import discord | ||||||
| from discord.ext import commands | from redbot.core import commands | ||||||
| 
 | 
 | ||||||
| from redbot.core.utils.chat_formatting import pagify | from redbot.core.utils.chat_formatting import pagify | ||||||
| from redbot.core.utils.chat_formatting import box | from redbot.core.utils.chat_formatting import box | ||||||
| @ -102,7 +103,7 @@ class Fight: | |||||||
|             await ctx.send("Current tournament ID: " + await self._activefight(ctx)) |             await ctx.send("Current tournament ID: " + await self._activefight(ctx)) | ||||||
| 
 | 
 | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
|             # await ctx.send("I can do stuff!") |             # await ctx.send("I can do stuff!") | ||||||
| 
 | 
 | ||||||
|     @fight.command(name="join") |     @fight.command(name="join") | ||||||
| @ -198,10 +199,10 @@ class Fight: | |||||||
|     async def fadmin(self, ctx): |     async def fadmin(self, ctx): | ||||||
|         """Admin command for managing the current tournament""" |         """Admin command for managing the current tournament""" | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
|              |              | ||||||
|     @fadmin.command(name="score") |     @fadmin.command(name="score") | ||||||
|     async def fadmin_score(self, ctx, mID, score1, score2): |     async def fadmin_score(self, ctx: commands.Context, mID, score1, score2): | ||||||
|         """Set's the score for matchID and clears disputes""" |         """Set's the score for matchID and clears disputes""" | ||||||
|         currFight = await self._getcurrentfight(ctx) |         currFight = await self._getcurrentfight(ctx) | ||||||
|         tID = await self._activefight(ctx) |         tID = await self._activefight(ctx) | ||||||
| @ -213,11 +214,11 @@ class Fight: | |||||||
|             await ctx.send("Tournament currently not accepting new players") |             await ctx.send("Tournament currently not accepting new players") | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         if await self._infight(ctx, tID, user.id): |         if await self._infight(ctx, tID, ctx.user.id): | ||||||
|             await ctx.send("You are already in this tournament!") |             await ctx.send("You are already in this tournament!") | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         currFight["PLAYERS"].append(user.id) |         currFight["PLAYERS"].append(ctx.user.id) | ||||||
| 
 | 
 | ||||||
|         await self._save_fight(ctx, tID, currFight) |         await self._save_fight(ctx, tID, currFight) | ||||||
| 
 | 
 | ||||||
| @ -256,7 +257,7 @@ class Fight: | |||||||
|             # self.save_data() |             # self.save_data() | ||||||
| 
 | 
 | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
|         # await ctx.send("I can do stuff!") |         # await ctx.send("I can do stuff!") | ||||||
|      |      | ||||||
|     @fightset.command(name="emoji") |     @fightset.command(name="emoji") | ||||||
| @ -548,7 +549,7 @@ class Fight: | |||||||
|     async def fightset_guild(self, ctx): |     async def fightset_guild(self, ctx): | ||||||
|         """Adjust guild wide settings""" |         """Adjust guild wide settings""" | ||||||
|         if ctx.invoked_subcommand is None or isinstance(ctx.invoked_subcommand, commands.Group): |         if ctx.invoked_subcommand is None or isinstance(ctx.invoked_subcommand, commands.Group): | ||||||
|             await ctx.send_help() |             pass | ||||||
|      |      | ||||||
|     @fightset_guild.command(name="selfreport") |     @fightset_guild.command(name="selfreport") | ||||||
|     async def fightset_guild_selfreport(self, ctx): |     async def fightset_guild_selfreport(self, ctx): | ||||||
| @ -711,11 +712,13 @@ class Fight: | |||||||
| 
 | 
 | ||||||
|     async def _embed_tourney(self, ctx, tID): |     async def _embed_tourney(self, ctx, tID): | ||||||
|         """Prints a pretty embed of the tournament""" |         """Prints a pretty embed of the tournament""" | ||||||
|         await ctx.send("_placeholder Todo") |         #_placeholder Todo | ||||||
|  |         pass | ||||||
| 
 | 
 | ||||||
|     async def _comparescores(self): |     async def _comparescores(self): | ||||||
|         """Checks user submitted scores for inconsistancies""" |         """Checks user submitted scores for inconsistancies""" | ||||||
|         await ctx.send("_comparescores Todo") |         # _comparescores Todo | ||||||
|  |         pass | ||||||
| 
 | 
 | ||||||
|     async def _parseuser(self, guild: discord.Guild, tID, userid): |     async def _parseuser(self, guild: discord.Guild, tID, userid): | ||||||
|         """Finds user in the tournament""" |         """Finds user in the tournament""" | ||||||
| @ -821,8 +824,8 @@ class Fight: | |||||||
|         """Reports a win for member in match""" |         """Reports a win for member in match""" | ||||||
|         theT = await self._getfight(guild, tID) |         theT = await self._getfight(guild, tID) | ||||||
| 
 | 
 | ||||||
|         if member.id not in theT["PLAYERS"]:  # Shouldn't happen |         # if member.id not in theT["PLAYERS"]:  # Shouldn't happen | ||||||
|             return False |         #     return False | ||||||
| 
 | 
 | ||||||
|         if theT["RULES"]["TYPE"] == 0: |         if theT["RULES"]["TYPE"] == 0: | ||||||
|             return await self._rr_report_dispute(guild, tID, mID) |             return await self._rr_report_dispute(guild, tID, mID) | ||||||
| @ -833,13 +836,16 @@ class Fight: | |||||||
|         |         | ||||||
| # **********************Single Elimination*************************** | # **********************Single Elimination*************************** | ||||||
|     async def _elim_setup(self, tID): |     async def _elim_setup(self, tID): | ||||||
|         await ctx.send("Elim setup todo") |         # ToDo Elim setup | ||||||
|  |         pass | ||||||
| 
 | 
 | ||||||
|     async def _elim_start(self, tID): |     async def _elim_start(self, tID): | ||||||
|         await ctx.send("Elim start todo") |         # ToDo Elim start | ||||||
|  |         pass | ||||||
| 
 | 
 | ||||||
|     async def _elim_update(self, matchID): |     async def _elim_update(self, matchID): | ||||||
|         await ctx.send("Elim update todo") |         # ToDo Elim update | ||||||
|  |         pass | ||||||
| 
 | 
 | ||||||
| # **********************Round-Robin********************************** | # **********************Round-Robin********************************** | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|     "author" : ["Bobloy"], |     "author" : ["Bobloy"], | ||||||
| 	"bot_version" : [3,0,0], | 	"bot_version" : [3,0,0], | ||||||
|     "description" : "[Incomplete] Cog to organize tournaments within Discord", |     "description" : "[Incomplete] Cog to organize tournaments within Discord", | ||||||
|     "hidden" : false, |     "hidden" : true, | ||||||
|     "install_msg" : "Thank you for installing Fight. Run with [p]fight or [p]fightset", |     "install_msg" : "Thank you for installing Fight. Run with [p]fight or [p]fightset", | ||||||
| 	"requirements" : [], | 	"requirements" : [], | ||||||
|     "short" : "[Incomplete] Cog to organize tournaments", |     "short" : "[Incomplete] Cog to organize tournaments", | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								flag/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								flag/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .flag import Flag | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(Flag(bot)) | ||||||
							
								
								
									
										191
									
								
								flag/flag.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								flag/flag.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,191 @@ | |||||||
|  | from datetime import date, timedelta | ||||||
|  | 
 | ||||||
|  | import discord | ||||||
|  | from redbot.core import Config, checks, commands | ||||||
|  | from redbot.core.bot import Red | ||||||
|  | from redbot.core.utils.chat_formatting import pagify | ||||||
|  | from typing import Any | ||||||
|  | 
 | ||||||
|  | Cog: Any = getattr(commands, "Cog", object) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Flag(Cog): | ||||||
|  |     """ | ||||||
|  |     Set expiring flags on members | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, bot: Red): | ||||||
|  |         self.bot = bot | ||||||
|  |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|  |         default_global = {} | ||||||
|  |         default_guild = { | ||||||
|  |             "days": 31, | ||||||
|  |             "dm": True, | ||||||
|  |             "flags": {} | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         self.config.register_global(**default_global) | ||||||
|  |         self.config.register_guild(**default_guild) | ||||||
|  | 
 | ||||||
|  |     @checks.is_owner() | ||||||
|  |     @commands.guild_only() | ||||||
|  |     @commands.command() | ||||||
|  |     async def clearallflag(self, ctx: commands.Context): | ||||||
|  |         """Clears all flags for all members in this server""" | ||||||
|  | 
 | ||||||
|  |         await self.config.guild(ctx.guild).flags.clear() | ||||||
|  |         await ctx.send("Done") | ||||||
|  | 
 | ||||||
|  |     @checks.mod_or_permissions(manage_roles=True) | ||||||
|  |     @commands.guild_only() | ||||||
|  |     @commands.group() | ||||||
|  |     async def flagset(self, ctx: commands.Context): | ||||||
|  |         """ | ||||||
|  |         My custom cog | ||||||
|  |         | ||||||
|  |         Extra information goes here | ||||||
|  |         """ | ||||||
|  |         if ctx.invoked_subcommand is None: | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|  |     @flagset.command(name="expire") | ||||||
|  |     async def flagset_expire(self, ctx: commands.Context, days: int): | ||||||
|  |         """ | ||||||
|  |         Set the number of days for flags to expire after for server | ||||||
|  |         """ | ||||||
|  |         await self.config.guild(ctx.guild).days.set(days) | ||||||
|  |         await ctx.send("Number of days for new flags to expire is now {} days".format(days)) | ||||||
|  | 
 | ||||||
|  |     @flagset.command(name="dm") | ||||||
|  |     async def flagset_dm(self, ctx: commands.Context): | ||||||
|  |         """Toggles DM-ing the flags""" | ||||||
|  | 
 | ||||||
|  |         dm = await self.config.guild(ctx.guild).dm() | ||||||
|  |         await self.config.guild(ctx.guild).dm.set(not dm) | ||||||
|  | 
 | ||||||
|  |         await ctx.send("DM-ing members when they get a flag is now set to **{}**".format(not dm)) | ||||||
|  | 
 | ||||||
|  |     @staticmethod | ||||||
|  |     def _flag_template(): | ||||||
|  |         return { | ||||||
|  |             'reason': "", | ||||||
|  |             'expireyear': 0, | ||||||
|  |             'expiremonth': 0, | ||||||
|  |             'expireday': 0 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     @commands.guild_only() | ||||||
|  |     @checks.mod_or_permissions(manage_roles=True) | ||||||
|  |     @commands.command() | ||||||
|  |     async def flag(self, ctx: commands.Context, member: discord.Member, *, reason): | ||||||
|  |         """Flag a member""" | ||||||
|  |         guild = ctx.guild | ||||||
|  |         await self._check_flags(guild) | ||||||
|  |         # clashroyale = self.bot.get_cog('clashroyale') | ||||||
|  |         # if clashroyale is None: | ||||||
|  |         # await ctx.send("Requires clashroyale cog installed") | ||||||
|  |         # return | ||||||
|  | 
 | ||||||
|  |         flag = self._flag_template() | ||||||
|  |         expiredate = date.today() | ||||||
|  |         expiredate += timedelta(days=await self.config.guild(guild).days()) | ||||||
|  | 
 | ||||||
|  |         flag['reason'] = reason | ||||||
|  |         flag['expireyear'] = expiredate.year | ||||||
|  |         flag['expiremonth'] = expiredate.month | ||||||
|  |         flag['expireday'] = expiredate.day | ||||||
|  | 
 | ||||||
|  |         # flags = await self.config.guild(guild).flags.get_raw(str(member.id), default=[]) | ||||||
|  |         # flags.append(flag) | ||||||
|  |         # await self.config.guild(guild).flags.set_raw(str(member.id), value=flags) | ||||||
|  | 
 | ||||||
|  |         async with self.config.guild(guild).flags() as flags: | ||||||
|  |             flags[str(member.id)].append(flag) | ||||||
|  | 
 | ||||||
|  |         outembed = await self._list_flags(member) | ||||||
|  | 
 | ||||||
|  |         if outembed: | ||||||
|  |             await ctx.send(embed=outembed) | ||||||
|  |             if await self.config.guild(guild).dm(): | ||||||
|  |                 await member.send(embed=outembed) | ||||||
|  |         else: | ||||||
|  |             await ctx.send("This member has no flags.. somehow..") | ||||||
|  | 
 | ||||||
|  |     @commands.guild_only() | ||||||
|  |     @checks.mod_or_permissions(manage_roles=True) | ||||||
|  |     @commands.command(aliases=['flagclear']) | ||||||
|  |     async def clearflag(self, ctx: commands.Context, member: discord.Member): | ||||||
|  |         """Clears flags for a member""" | ||||||
|  |         guild = ctx.guild | ||||||
|  |         await self._check_flags(guild) | ||||||
|  | 
 | ||||||
|  |         await self.config.guild(guild).flags.set_raw(str(member.id), value=[]) | ||||||
|  | 
 | ||||||
|  |         await ctx.send("Success!") | ||||||
|  | 
 | ||||||
|  |     @commands.guild_only() | ||||||
|  |     @commands.command(aliases=['flaglist']) | ||||||
|  |     async def listflag(self, ctx: commands.Context, member: discord.Member): | ||||||
|  |         """Lists flags for a member""" | ||||||
|  |         server = ctx.guild | ||||||
|  |         await self._check_flags(server) | ||||||
|  | 
 | ||||||
|  |         outembed = await self._list_flags(member) | ||||||
|  | 
 | ||||||
|  |         if outembed: | ||||||
|  |             await ctx.send(embed=outembed) | ||||||
|  |         else: | ||||||
|  |             await ctx.send("This member has no flags!") | ||||||
|  | 
 | ||||||
|  |     @commands.guild_only() | ||||||
|  |     @commands.command(aliases=['flagall']) | ||||||
|  |     async def allflag(self, ctx: commands.Context): | ||||||
|  |         """Lists all flags for the server""" | ||||||
|  |         guild = ctx.guild | ||||||
|  |         await self._check_flags(guild) | ||||||
|  |         out = "All flags for {}\n".format(ctx.guild.name) | ||||||
|  | 
 | ||||||
|  |         flags = await self.config.guild(guild).flags() | ||||||
|  |         flag_d = {} | ||||||
|  |         for memberid, flag_data in flags.items(): | ||||||
|  |             if len(flag_data) > 0: | ||||||
|  |                 member = guild.get_member(int(memberid)) | ||||||
|  |                 flag_d[member.display_name + member.discriminator] = len(flag_data) | ||||||
|  | 
 | ||||||
|  |         for display_name, flag_count in sorted(flag_d.items()): | ||||||
|  |             out += "{} - **{}** flags".format(display_name, flag_count) | ||||||
|  | 
 | ||||||
|  |         for page in pagify(out): | ||||||
|  |             await ctx.send(page) | ||||||
|  | 
 | ||||||
|  |     async def _list_flags(self, member: discord.Member): | ||||||
|  |         """Returns a pretty embed of flags on a member""" | ||||||
|  |         flags = await self.config.guild(member.guild).flags.get_raw(str(member.id), default=[]) | ||||||
|  | 
 | ||||||
|  |         embed = discord.Embed(title="Flags for " + member.display_name, | ||||||
|  |                               description="User has {} active flags".format(len(flags)), color=0x804040) | ||||||
|  |         for flag in flags: | ||||||
|  |             embed.add_field(name="Reason: " + flag['reason'], | ||||||
|  |                             value="Expires on " + str(date(flag['expireyear'], flag['expiremonth'], flag['expireday'])), | ||||||
|  |                             inline=True) | ||||||
|  | 
 | ||||||
|  |         embed.set_thumbnail(url=member.avatar_url) | ||||||
|  | 
 | ||||||
|  |         return embed | ||||||
|  | 
 | ||||||
|  |     async def _check_flags(self, guild: discord.Guild): | ||||||
|  |         """Updates and removes expired flags""" | ||||||
|  |         flag_data = await self.config.guild(guild).flags() | ||||||
|  |         flag_d = {} | ||||||
|  |         for memberid, flags in flag_data.items(): | ||||||
|  |             # for member in guild.members: | ||||||
|  |             # flags = await self.config.guild(guild).flags.get_raw(str(member.id), default=[]) | ||||||
|  |             x = 0 | ||||||
|  |             while x < len(flags): | ||||||
|  |                 flag = flags[x] | ||||||
|  |                 if date.today() >= date(flag['expireyear'], flag['expiremonth'], flag['expireday']): | ||||||
|  |                     del flags[x] | ||||||
|  |                 else: | ||||||
|  |                     x += 1 | ||||||
|  | 
 | ||||||
|  |             await self.config.guild(guild).flags.set_raw(memberid, value=flags) | ||||||
							
								
								
									
										23
									
								
								flag/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								flag/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Add expiring flags on members to track warnings or incidents", | ||||||
|  |   "hidden": false, | ||||||
|  |   "install_msg": "Thank you for installing Flag! Get started with `[p]load flag` and `[p]help Flag`", | ||||||
|  |   "requirements": [], | ||||||
|  |   "short": "Add expiring flags to members", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "warning", | ||||||
|  |     "warn", | ||||||
|  |     "temp", | ||||||
|  |     "tools", | ||||||
|  |     "warning" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								forcemention/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								forcemention/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .forcemention import ForceMention | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(ForceMention(bot)) | ||||||
							
								
								
									
										41
									
								
								forcemention/forcemention.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								forcemention/forcemention.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | from discord.utils import get | ||||||
|  | 
 | ||||||
|  | from redbot.core import Config, checks, commands | ||||||
|  | 
 | ||||||
|  | from redbot.core.bot import Red | ||||||
|  | from typing import Any | ||||||
|  | 
 | ||||||
|  | Cog: Any = getattr(commands, "Cog", object) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ForceMention(Cog): | ||||||
|  |     """ | ||||||
|  |     Mention the unmentionables | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, bot: Red): | ||||||
|  |         self.bot = bot | ||||||
|  |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|  |         default_global = {} | ||||||
|  |         default_guild = {} | ||||||
|  | 
 | ||||||
|  |         self.config.register_global(**default_global) | ||||||
|  |         self.config.register_guild(**default_guild) | ||||||
|  | 
 | ||||||
|  |     @checks.admin_or_permissions(manage_roles=True) | ||||||
|  |     @commands.command() | ||||||
|  |     async def forcemention(self, ctx: commands.Context, role: str, *, message=''): | ||||||
|  |         """ | ||||||
|  |        Mentions that role, regardless if it's unmentionable | ||||||
|  |        """ | ||||||
|  |         role_obj = get(ctx.guild.roles, name=role) | ||||||
|  |         if role_obj is None: | ||||||
|  |             await ctx.maybe_send_embed("Couldn't find role named {}".format(role)) | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  |         if not role_obj.mentionable: | ||||||
|  |             await role_obj.edit(mentionable=True) | ||||||
|  |             await ctx.send("{}\n{}".format(role_obj.mention, message)) | ||||||
|  |             await role_obj.edit(mentionable=False) | ||||||
|  |         else: | ||||||
|  |             await ctx.send("{}\n{}".format(role_obj.mention, message)) | ||||||
							
								
								
									
										19
									
								
								forcemention/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								forcemention/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Mentions roles that are unmentionable", | ||||||
|  |   "hidden": false, | ||||||
|  |   "install_msg": "Thank you for installing ForceMention! Get started with `[p]load forcemention`, then `[p]forcemention`", | ||||||
|  |   "requirements": [], | ||||||
|  |   "short": "Mention unmentionables", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "utils" | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @ -6,4 +6,4 @@ def setup(bot): | |||||||
|     n = Hangman(bot) |     n = Hangman(bot) | ||||||
|     data_manager.load_bundled_data(n, __file__) |     data_manager.load_bundled_data(n, __file__) | ||||||
|     bot.add_cog(n) |     bot.add_cog(n) | ||||||
|     bot.add_listener(n._on_react, "on_reaction_add") |     bot.add_listener(n.on_react, "on_reaction_add") | ||||||
|  | |||||||
| @ -2,12 +2,14 @@ from collections import defaultdict | |||||||
| from random import randint | from random import randint | ||||||
| 
 | 
 | ||||||
| import discord | import discord | ||||||
| from discord.ext import commands | from redbot.core import Config, checks, commands | ||||||
| from redbot.core import Config, checks | from redbot.core.data_manager import cog_data_path | ||||||
| from redbot.core.data_manager import cog_data_path, load_basic_configuration | 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) | ||||||
| @ -25,7 +28,7 @@ class Hangman: | |||||||
|             lambda: {"running": False, "hangman": 0, "guesses": [], "trackmessage": False, "answer": ''}) |             lambda: {"running": False, "hangman": 0, "guesses": [], "trackmessage": False, "answer": ''}) | ||||||
|         self.path = str(cog_data_path(self)).replace('\\', '/') |         self.path = str(cog_data_path(self)).replace('\\', '/') | ||||||
| 
 | 
 | ||||||
|         self.answer_path = self.path+"/bundled_data/hanganswers.txt" |         self.answer_path = self.path + "/bundled_data/hanganswers.txt" | ||||||
| 
 | 
 | ||||||
|         self.winbool = defaultdict(lambda: False) |         self.winbool = defaultdict(lambda: False) | ||||||
| 
 | 
 | ||||||
| @ -127,11 +130,12 @@ class Hangman: | |||||||
|     @checks.mod_or_permissions(administrator=True) |     @checks.mod_or_permissions(administrator=True) | ||||||
|     async def hangset(self, ctx): |     async def hangset(self, ctx): | ||||||
|         """Adjust hangman settings""" |         """Adjust hangman settings""" | ||||||
|         if not ctx.invoked_subcommand: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
| 
 | 
 | ||||||
|     @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!""" | ||||||
| @ -245,7 +257,7 @@ class Hangman: | |||||||
| 
 | 
 | ||||||
|         await self._reprintgame(message) |         await self._reprintgame(message) | ||||||
| 
 | 
 | ||||||
|     async def _on_react(self, reaction, user): |     async def on_react(self, reaction, user): | ||||||
|         """ Thanks to flapjack reactpoll for guidelines |         """ Thanks to flapjack reactpoll for guidelines | ||||||
|             https://github.com/flapjax/FlapJack-Cogs/blob/master/reactpoll/reactpoll.py""" |             https://github.com/flapjax/FlapJack-Cogs/blob/master/reactpoll/reactpoll.py""" | ||||||
| 
 | 
 | ||||||
| @ -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 | ||||||
| @ -330,9 +354,3 @@ class Hangman: | |||||||
| 
 | 
 | ||||||
|         await self._reactmessage_menu(message) |         await self._reactmessage_menu(message) | ||||||
|         await self._checkdone(channel) |         await self._checkdone(channel) | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def setup(bot): |  | ||||||
|     n = Hangman(bot) |  | ||||||
|     bot.add_cog(n) |  | ||||||
|     bot.add_listener(n._on_react, "on_reaction_add") |  | ||||||
|  | |||||||
| @ -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": [ | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import discord | import discord | ||||||
| 
 | 
 | ||||||
| from discord.ext import commands | 
 | ||||||
| 
 | 
 | ||||||
| from .utils.chat_formatting import pagify | from .utils.chat_formatting import pagify | ||||||
| from .utils.chat_formatting import box | from .utils.chat_formatting import box | ||||||
| @ -33,7 +33,7 @@ class Howdoi: | |||||||
|         """Adjust howdoi settings |         """Adjust howdoi settings | ||||||
|         Settings are reset on reload""" |         Settings are reset on reload""" | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
|      |      | ||||||
|     @howdoiset.command(pass_context=True, name="answers") |     @howdoiset.command(pass_context=True, name="answers") | ||||||
|     async def howdoiset_answers(self, ctx, num_answers: int=1): |     async def howdoiset_answers(self, ctx, num_answers: int=1): | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| { | { | ||||||
| 	"AUTHOR": "Bobloy", | 	"AUTHOR": "Bobloy", | ||||||
| 	"INSTALL_MSG": "Thank you for installing Fox-Cogs by Bobloy", | 	"INSTALL_MSG": "Thank you for installing Fox-V3 by Bobloy", | ||||||
| 	"NAME": "Fox-Cogs", | 	"NAME": "Fox-V3", | ||||||
| 	"SHORT": "Cogs by Bobloy", | 	"SHORT": "Cogs by Bobloy", | ||||||
| 	"DESCRIPTION": "Cogs for RED Discord Bot by Bobloy" | 	"DESCRIPTION": "Cogs for RED Discord Bot by Bobloy" | ||||||
| } | } | ||||||
							
								
								
									
										5
									
								
								leaver/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								leaver/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .leaver import Leaver | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(Leaver(bot)) | ||||||
| @ -1,9 +1,20 @@ | |||||||
| { | { | ||||||
| 	"AUTHOR": "Bobloy", |   "author": [ | ||||||
| 	"INSTALL_MSG": "Thank you for installing leaver", |     "Bobloy" | ||||||
| 	"NAME": "Leaver", |   ], | ||||||
| 	"SHORT": "Sends message on leave", |   "bot_version": [ | ||||||
| 	"DESCRIPTION": "Keeps track of when people leave the server, and posts a message notifying", |     3, | ||||||
| 	"TAGS": ["fox", "bobloy", "utilities", "tools", "tool"], |     0, | ||||||
| 	"HIDDEN": false |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Keeps track of when people leave the server, and posts a message notifying", | ||||||
|  |   "hidden": false, | ||||||
|  |   "install_msg": "Thank you for installing Leaver. Get started with `[p]load leaver`, then `[p]help Leaver`", | ||||||
|  |   "requirements": [], | ||||||
|  |   "short": "Send message on leave", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "utils", | ||||||
|  |     "tools" | ||||||
|  |   ] | ||||||
| } | } | ||||||
| @ -1,78 +1,45 @@ | |||||||
| import discord | import discord | ||||||
| import os |  | ||||||
| from datetime import datetime |  | ||||||
| from discord.ext import commands |  | ||||||
| 
 | 
 | ||||||
| from .utils.dataIO import dataIO | from redbot.core import Config, checks, commands | ||||||
| from .utils import checks | 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 | ||||||
|  |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, bot): |     def __init__(self, bot): | ||||||
|         self.bot = bot |         self.bot = bot | ||||||
|         self.path = "data/Fox-Cogs/leaver" |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|         self.file_path = "data/Fox-Cogs/leaver/leaver.json" |         default_guild = { | ||||||
|         self.the_data = dataIO.load_json(self.file_path) |             "channel": '' | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|     def save_data(self): |         self.config.register_guild(**default_guild) | ||||||
|         """Saves the json""" |  | ||||||
|         dataIO.save_json(self.file_path, self.the_data) |  | ||||||
| 
 | 
 | ||||||
|     @commands.group(aliases=['setleaver'], pass_context=True, no_pm=True) |     @commands.group(aliases=['setleaver']) | ||||||
|     @checks.mod_or_permissions(administrator=True) |     @checks.mod_or_permissions(administrator=True) | ||||||
|     async def leaverset(self, ctx): |     async def leaverset(self, ctx): | ||||||
|         """Adjust leaver settings""" |         """Adjust leaver settings""" | ||||||
|          |  | ||||||
|         server = ctx.message.server |  | ||||||
|         if server.id not in self.the_data: |  | ||||||
|             self.the_data[server.id] = {} |  | ||||||
|             self.save_data() |  | ||||||
| 
 |  | ||||||
|          |  | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await self.bot.send_cmd_help(ctx) |             pass | ||||||
| 
 | 
 | ||||||
|     @leaverset.command(pass_context=True, no_pm=True) |     @leaverset.command() | ||||||
|     async def channel(self, ctx): |     async def channel(self, ctx: Context): | ||||||
|         server = ctx.message.server |         guild = ctx.guild | ||||||
|         if 'CHANNEL' not in self.the_data[server.id]: |         await self.config.guild(guild).channel.set(ctx.channel.id) | ||||||
|             self.the_data[server.id]['CHANNEL'] = '' |         await ctx.send("Channel set to " + ctx.channel.name) | ||||||
|          |  | ||||||
| 
 | 
 | ||||||
|         self.the_data[server.id]['CHANNEL'] = ctx.message.channel.id |     async def on_member_remove(self, member: discord.Member): | ||||||
|         self.save_data() |         guild = member.guild | ||||||
|         await self.bot.say("Channel set to "+ctx.message.channel.name) |         channel = await self.config.guild(guild).channel() | ||||||
| 
 | 
 | ||||||
|     async def when_leave(self, member): |         if channel != '': | ||||||
|         server = member.server |             channel = guild.get_channel(channel) | ||||||
|         if server.id in self.the_data: |             await channel.send(str(member) + "(*" + str(member.nick) + "*) has left the server!") | ||||||
|             await self.bot.send_message(server.get_channel(self.the_data[server.id]['CHANNEL']), |  | ||||||
|                                         str(member) + "(*" + str(member.nick) +"*) has left the server!") |  | ||||||
|         else: |         else: | ||||||
|             await self.bot.send_message(server.default_channel.id, str(member) + " (*" + str(member.nick) +"*) has left the server!") |             pass | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def check_folders(): |  | ||||||
|     if not os.path.exists("data/Fox-Cogs"): |  | ||||||
|         print("Creating data/Fox-Cogs folder...") |  | ||||||
|         os.makedirs("data/Fox-Cogs") |  | ||||||
| 
 |  | ||||||
|     if not os.path.exists("data/Fox-Cogs/leaver"): |  | ||||||
|         print("Creating data/Fox-Cogs/leaver folder...") |  | ||||||
|         os.makedirs("data/Fox-Cogs/leaver") |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def check_files(): |  | ||||||
|     if not dataIO.is_valid_json("data/Fox-Cogs/leaver/leaver.json"): |  | ||||||
|         dataIO.save_json("data/Fox-Cogs/leaver/leaver.json", {}) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def setup(bot): |  | ||||||
|     check_folders() |  | ||||||
|     check_files() |  | ||||||
|     q = Leaver(bot) |  | ||||||
|     bot.add_listener(q.when_leave, "on_member_remove") |  | ||||||
|     bot.add_cog(q) |  | ||||||
|      |  | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								lovecalculator/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lovecalculator/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .lovecalculator import LoveCalculator | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(LoveCalculator(bot)) | ||||||
							
								
								
									
										23
									
								
								lovecalculator/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lovecalculator/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								lovecalculator/lovecalculator.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lovecalculator/lovecalculator.py
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
							
								
								
									
										20
									
								
								lseen/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lseen/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Keep track of when users were last seen online", | ||||||
|  |   "hidden": false, | ||||||
|  |   "install_msg": "Thank you for installing LastSeen. Get started with `[p]load lseen`, then `[p]help LastSeen`", | ||||||
|  |   "requirements": ["python-dateutil"], | ||||||
|  |   "short": "Last seen tracker", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "utils", | ||||||
|  |     "tools" | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @ -2,14 +2,18 @@ from datetime import datetime | |||||||
| 
 | 
 | ||||||
| import dateutil.parser | import dateutil.parser | ||||||
| import discord | import discord | ||||||
| from discord.ext import commands | 
 | ||||||
| from redbot.core import Config, RedContext | from redbot.core import Config | ||||||
| from redbot.core.bot import Red | from redbot.core.bot import Red | ||||||
|  | from redbot.core import commands | ||||||
|  | from typing import Any | ||||||
|  | 
 | ||||||
|  | Cog: Any = getattr(commands, "Cog", object) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class LastSeen: | class LastSeen(Cog): | ||||||
|     """ |     """ | ||||||
|     V3 Cog Template |     Report when a user was last seen online | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     online_status = discord.Status.online |     online_status = discord.Status.online | ||||||
| @ -37,13 +41,13 @@ class LastSeen: | |||||||
|         return d |         return d | ||||||
| 
 | 
 | ||||||
|     @commands.group(aliases=['setlseen'], name='lseenset') |     @commands.group(aliases=['setlseen'], name='lseenset') | ||||||
|     async def lset(self, ctx: RedContext): |     async def lset(self, ctx: commands.Context): | ||||||
|         """Change settings for lseen""" |         """Change settings for lseen""" | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
| 
 | 
 | ||||||
|     @lset.command(name="toggle") |     @lset.command(name="toggle") | ||||||
|     async def lset_toggle(self, ctx: RedContext): |     async def lset_toggle(self, ctx: commands.Context): | ||||||
|         """Toggles tracking seen for this server""" |         """Toggles tracking seen for this server""" | ||||||
|         enabled = not await self.config.guild(ctx.guild).enabled() |         enabled = not await self.config.guild(ctx.guild).enabled() | ||||||
|         await self.config.guild(ctx.guild).enabled.set( |         await self.config.guild(ctx.guild).enabled.set( | ||||||
| @ -54,11 +58,9 @@ class LastSeen: | |||||||
|                 "Enabled" if enabled else "Disabled")) |                 "Enabled" if enabled else "Disabled")) | ||||||
| 
 | 
 | ||||||
|     @commands.command(aliases=['lastseen']) |     @commands.command(aliases=['lastseen']) | ||||||
|     async def lseen(self, ctx: RedContext, member: discord.Member): |     async def lseen(self, ctx: commands.Context, member: discord.Member): | ||||||
|         """ |         """ | ||||||
|         Just says the time the user was last seen |         Just says the time the user was last seen | ||||||
| 
 |  | ||||||
|         :param member: |  | ||||||
|         """ |         """ | ||||||
| 
 | 
 | ||||||
|         if member.status != self.offline_status: |         if member.status != self.offline_status: | ||||||
| @ -72,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(): | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								nudity/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								nudity/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .nudity import Nudity | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(Nudity(bot)) | ||||||
							
								
								
									
										20
									
								
								nudity/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								nudity/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Keep track of when users were last seen online", | ||||||
|  |   "hidden": true, | ||||||
|  |   "install_msg": "Thank you for installing LastSeen. Get started with `[p]load nudity`, then `[p]help Nudity`", | ||||||
|  |   "requirements": ["nudepy"], | ||||||
|  |   "short": "Last seen tracker", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "utils", | ||||||
|  |     "tools" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								nudity/nudity.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								nudity/nudity.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | from datetime import datetime | ||||||
|  | 
 | ||||||
|  | import discord | ||||||
|  | import nude | ||||||
|  | from nude import Nude | ||||||
|  | from redbot.core import Config | ||||||
|  | from redbot.core import commands | ||||||
|  | from redbot.core.bot import Red | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Nudity: | ||||||
|  |     """ | ||||||
|  |     V3 Cog Template | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     online_status = discord.Status.online | ||||||
|  | 
 | ||||||
|  |     offline_status = discord.Status.offline | ||||||
|  | 
 | ||||||
|  |     def __init__(self, bot: Red): | ||||||
|  |         self.bot = bot | ||||||
|  |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|  | 
 | ||||||
|  |         default_guild = { | ||||||
|  |             "enabled": False | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         self.config.register_guild(**default_guild) | ||||||
|  | 
 | ||||||
|  |     @commands.command(aliases=['togglenudity'], name='nudity') | ||||||
|  |     async def nudity(self, ctx: commands.Context): | ||||||
|  |         """Toggle nude-checking 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("Nude checking is now set to {}".format(not is_on)) | ||||||
|  | 
 | ||||||
|  |     async def on_message(self, message: discord.Message): | ||||||
|  |         is_on = await self.config.guild(message.guild).enabled() | ||||||
|  |         if not is_on: | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  |         if not message.attachments: | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										5
									
								
								planttycoon/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								planttycoon/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .planttycoon import PlantTycoon | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(PlantTycoon(bot)) | ||||||
							
								
								
									
										11
									
								
								planttycoon/data/badges.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								planttycoon/data/badges.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "badges": { | ||||||
|  |     "Flower Power": {}, | ||||||
|  |     "Fruit Brute": {}, | ||||||
|  |     "Sporadic": {}, | ||||||
|  |     "Odd-pod": {}, | ||||||
|  |     "Greenfingers": {}, | ||||||
|  |     "Nobel Peas Prize": {}, | ||||||
|  |     "Annualsary": {} | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								planttycoon/data/defaults.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								planttycoon/data/defaults.json
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								planttycoon/data/notifications.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								planttycoon/data/notifications.json
									
									
									
									
									
										Normal file
									
								
							| @ -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." | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										690
									
								
								planttycoon/data/plants.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										690
									
								
								planttycoon/data/plants.json
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								planttycoon/data/products.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								planttycoon/data/products.json
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								planttycoon/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								planttycoon/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										1378
									
								
								planttycoon/planttycoon.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1378
									
								
								planttycoon/planttycoon.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5
									
								
								qrinvite/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								qrinvite/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .qrinvite import QRInvite | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(QRInvite(bot)) | ||||||
							
								
								
									
										23
									
								
								qrinvite/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								qrinvite/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Create a QR code invite for the server", | ||||||
|  |   "hidden": false, | ||||||
|  |   "install_msg": "Thank you for installing QRInvite! Get started with `[p]load qrinvite`, then `[p]help QRInvite`", | ||||||
|  |   "requirements": [ | ||||||
|  |     "MyQR" | ||||||
|  |   ], | ||||||
|  |   "short": "Create a QR code invite", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "tools", | ||||||
|  |     "qr", | ||||||
|  |     "code" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								qrinvite/qrinvite.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								qrinvite/qrinvite.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | import pathlib | ||||||
|  | 
 | ||||||
|  | import aiohttp | ||||||
|  | import discord | ||||||
|  | from MyQR import myqr | ||||||
|  | from PIL import Image | ||||||
|  | from redbot.core import Config, commands | ||||||
|  | from redbot.core.bot import Red | ||||||
|  | from redbot.core.data_manager import cog_data_path | ||||||
|  | from typing import Any | ||||||
|  | 
 | ||||||
|  | Cog: Any = getattr(commands, "Cog", object) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class QRInvite(Cog): | ||||||
|  |     """ | ||||||
|  |     V3 Cog Template | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, bot: Red): | ||||||
|  |         self.bot = bot | ||||||
|  |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|  |         default_global = {} | ||||||
|  |         default_guild = {} | ||||||
|  | 
 | ||||||
|  |         self.config.register_global(**default_global) | ||||||
|  |         self.config.register_guild(**default_guild) | ||||||
|  | 
 | ||||||
|  |     @commands.command() | ||||||
|  |     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 | ||||||
|  |         """ | ||||||
|  |         if invite is None: | ||||||
|  |             try: | ||||||
|  |                 invite = await ctx.channel.create_invite() | ||||||
|  |             except discord.Forbidden: | ||||||
|  |                 try: | ||||||
|  |                     invite = await ctx.channel.invites() | ||||||
|  |                     invite = invite[0] | ||||||
|  |                 except discord.Forbidden: | ||||||
|  |                     await ctx.send("No permission to get an invite, please provide one") | ||||||
|  |                     return | ||||||
|  |             invite = invite.code | ||||||
|  | 
 | ||||||
|  |         if image_url is None: | ||||||
|  |             image_url = ctx.guild.icon_url | ||||||
|  | 
 | ||||||
|  |         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) | ||||||
|  |         image_path = path / (ctx.guild.icon + "." + extension) | ||||||
|  |         async with aiohttp.ClientSession() as session: | ||||||
|  |             async with session.get(image_url) as response: | ||||||
|  |                 image = await response.read() | ||||||
|  | 
 | ||||||
|  |         with image_path.open("wb") as file: | ||||||
|  |             file.write(image) | ||||||
|  | 
 | ||||||
|  |         if extension == "webp": | ||||||
|  |             new_path = convert_png(str(image_path)) | ||||||
|  |         else: | ||||||
|  |             new_path = str(image_path) | ||||||
|  | 
 | ||||||
|  |         myqr.run(invite, picture=new_path, save_name=ctx.guild.icon + "_qrcode.png", | ||||||
|  |                  save_dir=str(cog_data_path(self)), colorized=colorized, ) | ||||||
|  | 
 | ||||||
|  |         png_path: pathlib.Path = path / (ctx.guild.icon + "_qrcode.png") | ||||||
|  |         with png_path.open("rb") as png_fp: | ||||||
|  |             await ctx.send(file=discord.File(png_fp.read(), "qrcode.png")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def convert_png(path): | ||||||
|  |     im = Image.open(path) | ||||||
|  |     im.load() | ||||||
|  |     alpha = im.split()[-1] | ||||||
|  |     im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) | ||||||
|  |     mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) | ||||||
|  |     im.paste(255, mask) | ||||||
|  |     new_path = path.replace(".webp", ".png") | ||||||
|  |     im.save(new_path, transparency=255) | ||||||
|  |     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", | ||||||
|  | |||||||
| @ -1,11 +1,12 @@ | |||||||
| import asyncio |  | ||||||
| from typing import List, Union | from typing import List, Union | ||||||
| 
 | 
 | ||||||
| import discord | import discord | ||||||
| from discord.ext import commands |  | ||||||
| 
 |  | ||||||
| from redbot.core import Config | from redbot.core import Config | ||||||
|  | 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: | ||||||
| @ -15,8 +16,8 @@ class ReactRestrictCombo: | |||||||
| 
 | 
 | ||||||
|     def __eq__(self, other: "ReactRestrictCombo"): |     def __eq__(self, other: "ReactRestrictCombo"): | ||||||
|         return ( |         return ( | ||||||
|             self.message_id == other.message_id and |                 self.message_id == other.message_id and | ||||||
|             self.role_id == other.role_id |                 self.role_id == other.role_id | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def to_json(self): |     def to_json(self): | ||||||
| @ -33,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 | ||||||
|     """ |     """ | ||||||
| @ -79,14 +80,10 @@ class ReactRestrict: | |||||||
|     async def add_reactrestrict(self, message_id: int, role: discord.Role): |     async def add_reactrestrict(self, message_id: int, role: discord.Role): | ||||||
|         """ |         """ | ||||||
|         Adds a react|role combo. |         Adds a react|role combo. | ||||||
| 
 |  | ||||||
|         :param int message_id: |  | ||||||
|         :param str or int emoji: |  | ||||||
|         :param discord.Role role: |  | ||||||
|         """ |         """ | ||||||
|         # is_custom = True |         # is_custom = True | ||||||
|         # if isinstance(emoji, str): |         # if isinstance(emoji, str): | ||||||
|             # is_custom = False |         # is_custom = False | ||||||
| 
 | 
 | ||||||
|         combo = ReactRestrictCombo(message_id, role.id) |         combo = ReactRestrictCombo(message_id, role.id) | ||||||
| 
 | 
 | ||||||
| @ -98,10 +95,10 @@ class ReactRestrict: | |||||||
| 
 | 
 | ||||||
|     async def remove_react(self, message_id: int, role: discord.Role): |     async def remove_react(self, message_id: int, role: discord.Role): | ||||||
|         """ |         """ | ||||||
|         Removes a given reaction. |         Removes a given reaction | ||||||
| 
 | 
 | ||||||
|         :param int message_id: |         :param message_id: | ||||||
|         :param str or int emoji: |         :param role: | ||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         current_combos = await self.combo_list() |         current_combos = await self.combo_list() | ||||||
| @ -112,14 +109,13 @@ class ReactRestrict: | |||||||
|         if to_keep != current_combos: |         if to_keep != current_combos: | ||||||
|             await self.set_combo_list(to_keep) |             await self.set_combo_list(to_keep) | ||||||
| 
 | 
 | ||||||
|     async def has_reactrestrict_combo(self, message_id: int)\ |     async def has_reactrestrict_combo(self, message_id: int) \ | ||||||
|             -> (bool, List[ReactRestrictCombo]): |             -> (bool, List[ReactRestrictCombo]): | ||||||
|         """ |         """ | ||||||
|         Determines if there is an existing role combo for a given message |          Determines if there is an existing role combo for a given message | ||||||
|         and emoji ID. |         and emoji ID. | ||||||
| 
 | 
 | ||||||
|         :param int message_id: |         :param message_id: | ||||||
|         :param str or int emoji: |  | ||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         if not await self.is_registered(message_id): |         if not await self.is_registered(message_id): | ||||||
| @ -172,27 +168,23 @@ class ReactRestrict: | |||||||
|             raise LookupError("No role found.") |             raise LookupError("No role found.") | ||||||
| 
 | 
 | ||||||
|         return role |         return role | ||||||
|      | 
 | ||||||
|     async def _get_message_from_channel(self, channel_id: int, message_id: int)\ |     async def _get_message_from_channel(self, channel_id: int, message_id: int) \ | ||||||
|             -> Union[discord.Message, None]: |             -> Union[discord.Message, None]: | ||||||
|         """ |         """ | ||||||
|         Tries to find a message by ID in the current guild context. |         Tries to find a message by ID in the current guild context. | ||||||
| 
 |  | ||||||
|         :param ctx: |  | ||||||
|         :param message_id: |  | ||||||
|         :return: |  | ||||||
|         """ |         """ | ||||||
|         channel = self.bot.get_channel(channel_id) |         channel = self.bot.get_channel(channel_id) | ||||||
|         try: |         try: | ||||||
|             return await channel.get_message(message_id) |             return await channel.get_message(message_id) | ||||||
|         except discord.NotFound: |         except discord.NotFound: | ||||||
|             pass |             pass | ||||||
|         except AttributeError: # VoiceChannel object has no attribute 'get_message' |         except AttributeError:  # VoiceChannel object has no attribute 'get_message' | ||||||
|             pass |             pass | ||||||
| 
 | 
 | ||||||
|         return None |         return None | ||||||
|          | 
 | ||||||
|     async def _get_message(self, ctx: commands.Context, message_id: int)\ |     async def _get_message(self, ctx: commands.Context, message_id: int) \ | ||||||
|             -> Union[discord.Message, None]: |             -> Union[discord.Message, None]: | ||||||
|         """ |         """ | ||||||
|         Tries to find a message by ID in the current guild context. |         Tries to find a message by ID in the current guild context. | ||||||
| @ -206,12 +198,10 @@ class ReactRestrict: | |||||||
|                 return await channel.get_message(message_id) |                 return await channel.get_message(message_id) | ||||||
|             except discord.NotFound: |             except discord.NotFound: | ||||||
|                 pass |                 pass | ||||||
|             except AttributeError: # VoiceChannel object has no attribute 'get_message' |             except AttributeError:  # VoiceChannel object has no attribute 'get_message' | ||||||
|                 pass |                 pass | ||||||
|             except discord.Forbidden:  # No access to channel, skip |             except discord.Forbidden:  # No access to channel, skip | ||||||
|                 pass |                 pass | ||||||
|                  |  | ||||||
|                  |  | ||||||
| 
 | 
 | ||||||
|         return None |         return None | ||||||
| 
 | 
 | ||||||
| @ -221,7 +211,7 @@ class ReactRestrict: | |||||||
|         Base command for this cog. Check help for the commands list. |         Base command for this cog. Check help for the commands list. | ||||||
|         """ |         """ | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
| 
 | 
 | ||||||
|     @reactrestrict.command() |     @reactrestrict.command() | ||||||
|     async def add(self, ctx: commands.Context, message_id: int, *, role: discord.Role): |     async def add(self, ctx: commands.Context, message_id: int, *, role: discord.Role): | ||||||
| @ -235,18 +225,18 @@ class ReactRestrict: | |||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         # try: |         # try: | ||||||
|             # emoji, actual_emoji = await self._wait_for_emoji(ctx) |         #     emoji, actual_emoji = await self._wait_for_emoji(ctx) | ||||||
|         # except asyncio.TimeoutError: |         # except asyncio.TimeoutError: | ||||||
|             # await ctx.send("You didn't respond in time, please redo this command.") |         #     await ctx.send("You didn't respond in time, please redo this command.") | ||||||
|             # return |         #     return | ||||||
| 
 |         # | ||||||
|         # try: |         # try: | ||||||
|             # await message.add_reaction(actual_emoji) |         #     await message.add_reaction(actual_emoji) | ||||||
|         # except discord.HTTPException: |         # except discord.HTTPException: | ||||||
|             # await ctx.send("I can't add that emoji because I'm not in the guild that" |         #     await ctx.send("I can't add that emoji because I'm not in the guild that" | ||||||
|                            # " owns it.") |         #                    " owns it.") | ||||||
|             # return |         #     return | ||||||
| 
 |         # | ||||||
|         # noinspection PyTypeChecker |         # noinspection PyTypeChecker | ||||||
|         await self.add_reactrestrict(message_id, role) |         await self.add_reactrestrict(message_id, role) | ||||||
| 
 | 
 | ||||||
| @ -258,10 +248,10 @@ class ReactRestrict: | |||||||
|         Removes role associated with a given reaction. |         Removes role associated with a given reaction. | ||||||
|         """ |         """ | ||||||
|         # try: |         # try: | ||||||
|             # emoji, actual_emoji = await self._wait_for_emoji(ctx) |         #     emoji, actual_emoji = await self._wait_for_emoji(ctx) | ||||||
|         # except asyncio.TimeoutError: |         # except asyncio.TimeoutError: | ||||||
|             # await ctx.send("You didn't respond in time, please redo this command.") |         #     await ctx.send("You didn't respond in time, please redo this command.") | ||||||
|             # return |         #     return | ||||||
| 
 | 
 | ||||||
|         # noinspection PyTypeChecker |         # noinspection PyTypeChecker | ||||||
|         await self.remove_react(message_id, role) |         await self.remove_react(message_id, role) | ||||||
| @ -305,50 +295,50 @@ class ReactRestrict: | |||||||
|         for apprrole in roles: |         for apprrole in roles: | ||||||
|             if apprrole in member.roles: |             if apprrole in member.roles: | ||||||
|                 return |                 return | ||||||
|                  | 
 | ||||||
|         message = await self._get_message_from_channel(channel_id, message_id) |         message = await self._get_message_from_channel(channel_id, message_id) | ||||||
|         await message.remove_reaction(emoji, member) |         await message.remove_reaction(emoji, member) | ||||||
|          |  | ||||||
|         # try: |  | ||||||
|             # await member.add_roles(*roles) |  | ||||||
|         # except discord.Forbidden: |  | ||||||
|             # pass |  | ||||||
| 
 | 
 | ||||||
|  |     #     try: | ||||||
|  |     #         await member.add_roles(*roles) | ||||||
|  |     #     except discord.Forbidden: | ||||||
|  |     #         pass | ||||||
|  |     # | ||||||
|     # async def on_raw_reaction_remove(self, emoji: discord.PartialReactionEmoji, |     # async def on_raw_reaction_remove(self, emoji: discord.PartialReactionEmoji, | ||||||
|                                      # message_id: int, channel_id: int, user_id: int): |     #                                  message_id: int, channel_id: int, user_id: int): | ||||||
|         # """ |     #     """ | ||||||
|         # Event handler for long term reaction watching. |     #     Event handler for long term reaction watching. | ||||||
| 
 |     # | ||||||
|         # :param discord.PartialReactionEmoji emoji: |     #     :param discord.PartialReactionEmoji emoji: | ||||||
|         # :param int message_id: |     #     :param int message_id: | ||||||
|         # :param int channel_id: |     #     :param int channel_id: | ||||||
|         # :param int user_id: |     #     :param int user_id: | ||||||
|         # :return: |     #     :return: | ||||||
|         # """ |     #     """ | ||||||
|         # if emoji.is_custom_emoji(): |     #     if emoji.is_custom_emoji(): | ||||||
|             # emoji_id = emoji.id |     #         emoji_id = emoji.id | ||||||
|         # else: |     #     else: | ||||||
|             # emoji_id = emoji.name |     #         emoji_id = emoji.name | ||||||
| 
 |     # | ||||||
|         # has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id, emoji_id) |     #     has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id, emoji_id) | ||||||
| 
 |     # | ||||||
|         # if not has_reactrestrict: |     #     if not has_reactrestrict: | ||||||
|             # return |     #         return | ||||||
| 
 |     # | ||||||
|         # try: |     #     try: | ||||||
|             # member = self._get_member(channel_id, user_id) |     #         member = self._get_member(channel_id, user_id) | ||||||
|         # except LookupError: |     #     except LookupError: | ||||||
|             # return |     #         return | ||||||
| 
 |     # | ||||||
|         # if member.bot: |     #     if member.bot: | ||||||
|             # return |     #         return | ||||||
| 
 |     # | ||||||
|         # try: |     #     try: | ||||||
|             # roles = [self._get_role(member.guild, c.role_id) for c in combos] |     #         roles = [self._get_role(member.guild, c.role_id) for c in combos] | ||||||
|         # except LookupError: |     #     except LookupError: | ||||||
|             # return |     #         return | ||||||
| 
 |     # | ||||||
|         # try: |     #     try: | ||||||
|             # await member.remove_roles(*roles) |     #         await member.remove_roles(*roles) | ||||||
|         # except discord.Forbidden: |     #     except discord.Forbidden: | ||||||
|             # pass |     #         pass | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								recyclingplant/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								recyclingplant/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
							
								
								
									
										204
									
								
								recyclingplant/data/junk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								recyclingplant/data/junk.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								recyclingplant/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								recyclingplant/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								recyclingplant/recyclingplant.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								recyclingplant/recyclingplant.py
									
									
									
									
									
										Normal file
									
								
							| @ -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))) | ||||||
							
								
								
									
										5
									
								
								rpsls/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								rpsls/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .rpsls import RPSLS | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(RPSLS(bot)) | ||||||
							
								
								
									
										21
									
								
								rpsls/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								rpsls/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										93
									
								
								rpsls/rpsls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								rpsls/rpsls.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										5
									
								
								sayurl/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								sayurl/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .sayurl import SayUrl | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(SayUrl(bot)) | ||||||
							
								
								
									
										19
									
								
								sayurl/info..json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								sayurl/info..json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | { | ||||||
|  |   "author": [ | ||||||
|  |     "Bobloy" | ||||||
|  |   ], | ||||||
|  |   "bot_version": [ | ||||||
|  |     3, | ||||||
|  |     0, | ||||||
|  |     0 | ||||||
|  |   ], | ||||||
|  |   "description": "Convert any website into text and post it in chat", | ||||||
|  |   "hidden": true, | ||||||
|  |   "install_msg": "Thank you for installing SayUrl! Get started with `[p]load forcemention`, then `[p]help SayUrl", | ||||||
|  |   "requirements": ["html2text"], | ||||||
|  |   "short": "Convert URL to text", | ||||||
|  |   "tags": [ | ||||||
|  |     "bobloy", | ||||||
|  |     "tools" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								sayurl/sayurl.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								sayurl/sayurl.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | import aiohttp | ||||||
|  | import html2text | ||||||
|  | 
 | ||||||
|  | from redbot.core import Config, commands | ||||||
|  | from redbot.core.bot import Red | ||||||
|  | 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 with session.get(url) as response: | ||||||
|  |         assert response.status == 200 | ||||||
|  |         return await response.text() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class SayUrl(Cog): | ||||||
|  |     """ | ||||||
|  |     V3 Cog Template | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, bot: Red): | ||||||
|  |         self.bot = bot | ||||||
|  |         self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) | ||||||
|  |         default_global = {} | ||||||
|  |         default_guild = {} | ||||||
|  | 
 | ||||||
|  |         self.config.register_global(**default_global) | ||||||
|  |         self.config.register_guild(**default_guild) | ||||||
|  | 
 | ||||||
|  |     @commands.command() | ||||||
|  |     async def sayurl(self, ctx: commands.Context, url): | ||||||
|  |         """ | ||||||
|  |         Converts a URL to something readable | ||||||
|  | 
 | ||||||
|  |         Works better on smaller websites | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |         h = html2text.HTML2Text() | ||||||
|  |         h.ignore_links = True | ||||||
|  |         # h.ignore_images = True | ||||||
|  |         h.images_to_alt = True | ||||||
|  | 
 | ||||||
|  |         h.escape_snob = True | ||||||
|  |         h.skip_internal_links = True | ||||||
|  |         h.ignore_tables = True | ||||||
|  |         h.single_line_break = True | ||||||
|  |         h.mark_code = True | ||||||
|  |         h.wrap_links = True | ||||||
|  |         h.ul_item_mark = '-' | ||||||
|  | 
 | ||||||
|  |         async with aiohttp.ClientSession() as session: | ||||||
|  |             site = await fetch_url(session, url) | ||||||
|  | 
 | ||||||
|  |         for page in pagify(h.handle(site)): | ||||||
|  |             await ctx.send(page) | ||||||
							
								
								
									
										5
									
								
								scp/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								scp/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | from .scp import SCP | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def setup(bot): | ||||||
|  |     bot.add_cog(SCP(bot)) | ||||||
							
								
								
									
										20
									
								
								scp/info.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scp/info.json
									
									
									
									
									
										Normal file
									
								
							| @ -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" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								scp/scp.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								scp/scp.py
									
									
									
									
									
										Normal file
									
								
							| @ -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)) | ||||||
| @ -1,4 +1,4 @@ | |||||||
| from .werewolf import Werewolf | from .secrethitler import Werewolf | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def setup(bot): | def setup(bot): | ||||||
|  | |||||||
| @ -1,9 +1,9 @@ | |||||||
| import asyncio | import asyncio | ||||||
| 
 | 
 | ||||||
| import discord | import discord | ||||||
| from discord.ext import commands |  | ||||||
| 
 | 
 | ||||||
| from redbot.core import Config | 
 | ||||||
|  | from redbot.core import Config, commands | ||||||
| 
 | 
 | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
| 
 | 
 | ||||||
| @ -33,7 +33,7 @@ class Werewolf: | |||||||
|         Base command for this cog. Check help for the commands list. |         Base command for this cog. Check help for the commands list. | ||||||
|         """ |         """ | ||||||
|         if ctx.invoked_subcommand is None: |         if ctx.invoked_subcommand is None: | ||||||
|             await ctx.send_help() |             pass | ||||||
|      |      | ||||||
|     @ww.command() |     @ww.command() | ||||||
|     async def new(self, ctx, game_code): |     async def new(self, ctx, game_code): | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 bobloy
						bobloy