Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
9 changed files
with
376 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,67 @@ | ||
# chatbot | ||
ChatBot for Discord | ||
# Discord ChatBot | ||
|
||
Download this, check README | ||
https://github.com/Rapptz/discord.py | ||
|
||
|
||
Get PyCharm, get pip and the rest of the libraries, PYTHON 3.6.6 (3.7 has problems with discord lib) | ||
|
||
**main.py** will be the file you run in order to start the bot. | ||
|
||
In order to make things easier to understand, we'll divide the features of the chatbot into more functions that are located in different modules (files). | ||
|
||
For example: in order for the bot to respond to your "!hello", the main.py file imports the function named | ||
*basicFunctions* from the basicFunctionsFile module. | ||
|
||
This way, not only won't we have an endless main.py module but we will also be able to work individually on various | ||
features within our own modules and once completed, simply import them in main.py with a single line of code. | ||
|
||
|
||
|
||
|
||
**botClient.py** is required for the bot to run, it basically makes the variable *client* (which happens to be used | ||
literally everywhere in our code) connect our code to Discord (or something like that I guess). | ||
|
||
So for every new module/file you create, don't forget to add ``from botClient import client``. | ||
|
||
|
||
|
||
|
||
https://www.digitaltrends.com/gaming/how-to-make-a-discord-bot/ | ||
|
||
https://www.devdungeon.com/content/make-discord-bot-python | ||
|
||
https://www.devdungeon.com/content/make-discord-bot-python-part-2 | ||
|
||
# Requirements: | ||
|
||
Get PyCharm, get pip and the rest of the libraries, **PYTHON 3.6.6** (3.7 has problems with discord lib) | ||
https://github.com/Rapptz/discord.py (Download it, also check the README, it has instructions on how to install) | ||
|
||
### Update to the new discord.py 1.0 lib (rewrite ver.) | ||
|
||
Make sure you get the latest version of discord.py! Not 0.16, but 1.0 (REWRITE) | ||
In order to do this, upgrade your pip from 10 to 18 using ``python -m pip install --upgrade pip`` in command prompt. | ||
|
||
After that, use the command ``python -m pip install -U git+https://github.com/Rapptz/discord.py@rewrite#egg=discord.py[voice]`` in PyCharm Terminal. | ||
|
||
Note that the latest version of discord.py (rewrite) has some changes, it's almost like an entirely different library. | ||
Even so, it's better if we make the change now while we will learn than later. | ||
|
||
Here is the documentation: | ||
https://discordpy.readthedocs.io/en/rewrite/migrating.html | ||
|
||
Basically you're gonna have this open in a tab at all times, it's pretty much a manual | ||
Even the way you send messages has been changed: | ||
https://discordpy.readthedocs.io/en/rewrite/migrating.html#migrating-1-0-sending-messages | ||
|
||
Also, the discord.py 1.0 REWRITE library is new, it's been scheduled to fully release on 2018/11/01. This means that most video guides on YouTube will require most of the commands to be converted to discord.py 1.0 (from 0.16). | ||
|
||
Important Links: | ||
----------------------------------------------------------------------- | ||
https://discordpy.readthedocs.io/en/rewrite/migrating.html | ||
https://discordpy.readthedocs.io/en/latest/faq.html | ||
https://discordpy.readthedocs.io/en/rewrite/ext/commands/commands.html | ||
https://discordpy.readthedocs.io/en/rewrite/api.html | ||
----------------------------------------------------------------------- | ||
Tutorials: | ||
----------------------------------------------------------------------- | ||
https://www.digitaltrends.com/gaming/how-to-make-a-discord-bot \ | ||
https://www.devdungeon.com/content/make-discord-bot-python \ | ||
https://www.devdungeon.com/content/make-discord-bot-python-part-2 \ | ||
https://www.devdungeon.com/content/ai-chat-bot-python-aiml | ||
|
||
https://www.devdungeon.com/content/ai-chat-bot-python-aiml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import asyncio | ||
from discord.ext import commands | ||
from botClient import client | ||
|
||
class BasicFunctions: | ||
def __init__(self, client): | ||
self.client = client | ||
|
||
@commands.command() | ||
async def test(self, ctx): | ||
counter = 0 | ||
tmp = await ctx.message.channel.send('Calcuating messages...') | ||
async for log in ctx.message.channel.history(limit = int(100)): | ||
if log.author == ctx.message.author: | ||
counter += 1 | ||
await tmp.edit(content=f'You have {counter} messages.') | ||
|
||
@commands.command() | ||
async def sleep(self, ctx): | ||
await ctx.message.channel.send('Going to sleep for 10 seconds.') | ||
await asyncio.sleep(10) | ||
await ctx.message.channel.send('Done sleeping, thanks.') | ||
|
||
@commands.command() | ||
async def hello(self, ctx): | ||
await ctx.message.channel.send(f'Hello, {ctx.message.author.mention}!') | ||
|
||
@commands.command() | ||
async def uok(self, ctx): | ||
await ctx.message.channel.send('Yes I am.') | ||
|
||
def setup(client): | ||
client.add_cog(BasicFunctions(client)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import discord | ||
from discord.ext import commands | ||
|
||
botToken = "NTA1ODE5NDgxNTY2NjA5NDE4.DraAUg.Zkf31aGXgR0kt6WRkj_XcSaPSF0" | ||
client = commands.Bot(command_prefix='$') |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import discord | ||
from botClient import client | ||
import random | ||
from discord.ext import commands | ||
|
||
guessAttemptsRight = 0 | ||
guessAttemptsTotal = 0 | ||
guessAttemptsTimeout = 0 | ||
|
||
class GuessGame: | ||
def __init__(self, client): | ||
self.client = client | ||
|
||
@commands.command() | ||
async def gstats(self, ctx): | ||
if guessAttemptsTotal == 0: | ||
await ctx.message.channel.send("You haven't attempted the guess game yet.") | ||
return | ||
if guessAttemptsRight == 0: | ||
guessRate = str(0) + '%' | ||
else: | ||
guessRate = str(round((guessAttemptsRight * 100) / guessAttemptsTotal, 1)) + '%.' | ||
|
||
embed = discord.Embed(title="Stats", description="Letter guess game statistics", color=0x17e6f0) | ||
embed.add_field(name="Successful attempts: ", value=str(guessAttemptsRight), inline=True) | ||
embed.add_field(name="Total attempts: ", value=str(guessAttemptsTotal), inline=True) | ||
embed.add_field(name="Attempt success rate: ", value=str(guessRate), inline=True) | ||
embed.add_field(name="Timeouts: ", value=str(guessAttemptsTimeout), inline=True) | ||
await ctx.message.channel.send(embed=embed) | ||
|
||
@commands.command() | ||
async def greset(self, ctx): | ||
global guessAttemptsRight | ||
global guessAttemptsTotal | ||
global guessAttemptsTimeout | ||
guessAttemptsRight = 0 | ||
guessAttemptsTotal = 0 | ||
guessAttemptsTimeout = 0 | ||
await ctx.message.channel.send('Guess game results history has been cleared.') | ||
|
||
@commands.command() | ||
async def guess(self, ctx): | ||
global guessAttemptsRight | ||
global guessAttemptsTotal | ||
global guessAttemptsTimeout | ||
await ctx.message.channel.send('Guess a lowercase letter from the English alphabet.') | ||
|
||
letterList = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', | ||
't', | ||
'u', 'v', 'w', 'x', 'y', 'z'] | ||
letterPosition = random.randint(0, 25) | ||
answer = letterList[letterPosition] | ||
|
||
maxAttempts = 3 | ||
counter = 1 | ||
# answer = 'z' #testing purposes | ||
# letterPosition = 25 #testing purposes | ||
while counter <= maxAttempts: | ||
|
||
def pred(m): | ||
return m.author == ctx.message.author and m.channel == ctx.message.channel | ||
|
||
guess = await client.wait_for('message', check=pred, timeout=7) | ||
|
||
if guess is None: | ||
await ctx.message.channel.send(f'Sorry, you took too long. It was "{answer}".') | ||
guessAttemptsTimeout += 1 | ||
if counter != 1: | ||
guessAttemptsTotal += 1 | ||
await ctx.message.channel.send( | ||
'Player quit while game was in progress. Added as a loss.') | ||
else: | ||
await ctx.message.channel.send( | ||
"Player didn't start the game. Not counted as a loss.") | ||
return | ||
|
||
if guess.content == '$guess': | ||
if counter != 1: | ||
guessAttemptsTotal += 1 | ||
await ctx.message.channel.send("**Started new game.** (Old game counted as loss.)") | ||
else: | ||
await ctx.message.channel.send("**Started new game.**") | ||
return | ||
|
||
try: | ||
# print (answer) #for testing purposes | ||
guessPosition = letterList.index(str(guess.content)) # saves the position of the guess letter | ||
except ValueError: | ||
await ctx.message.channel.send( | ||
'That is not a valid input (single lowercase English letters only).') | ||
if counter != 1: | ||
guessAttemptsTotal += 1 | ||
await ctx.message.channel.send('Game reset.') | ||
return | ||
|
||
if str(guess.content) == answer: | ||
if counter == 1: | ||
await ctx.message.channel.send(f'LUCKY! The answer is indeed "{answer}".') | ||
else: | ||
await ctx.message.channel.send(f'You are right! The answer is indeed "{answer}".') | ||
await ctx.message.channel.send('Guessed correctly after ' + str(counter) + ' attempt(s).') | ||
guessAttemptsRight += 1 | ||
guessAttemptsTotal += 1 | ||
return | ||
|
||
else: | ||
if maxAttempts - counter == 0: | ||
await ctx.message.channel.send( | ||
f'Max attempts reached. Sorry. It was actually "{answer}".') | ||
guessAttemptsTotal += 1 | ||
return | ||
else: | ||
await ctx.message.channel.send('Wrong. You have {} attempt(s) left.' | ||
.format(maxAttempts - counter)) | ||
|
||
if abs(guessPosition - letterPosition) > 12: # these 4 lines took me 2 hours fml | ||
answerDistance = 26 - abs(guessPosition - letterPosition) | ||
else: | ||
answerDistance = abs(letterPosition - guessPosition) | ||
|
||
await ctx.message.channel.send(f'Hint: The letter you are looking for is {answerDistance} positions away.') | ||
|
||
counter += 1 | ||
|
||
|
||
def setup(client): | ||
client.add_cog(GuessGame(client)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import discord | ||
from botClient import client | ||
from discord.ext import commands | ||
|
||
class BasicFunctionsHelp: | ||
def __init__(self, client): | ||
client.self = client | ||
|
||
@commands.command() | ||
async def comhelp(self, ctx): | ||
embed = discord.Embed(title='Commands List', description= | ||
"Use **$** in front of the command name \n" | ||
"Example: $hello" | ||
, color=0x17e6f0) | ||
|
||
embed.add_field(name="Chat", value= | ||
"``hello`` - Greet Simon \n " | ||
"``uok`` - Check if Simon is okay \n" | ||
"``test`` - Counts recent messages" | ||
,inline=False) | ||
|
||
embed.add_field(name="Games", value= | ||
"``guess`` - Start playing a letter guessing game \n" | ||
"``ghelp`` - Letter guessing game explanation \n" | ||
"``gstats`` - See your guessing game statistics \n" | ||
"``greset`` - Reset your guessing game statistics" | ||
,inline=False) | ||
embed.set_thumbnail(url=ctx.message.author.avatar_url) | ||
embed.set_footer(text='Requested by ' + ctx.message.author.name + '.', icon_url=ctx.message.author.avatar_url) | ||
await ctx.message.channel.send(embed=embed) | ||
|
||
@commands.command() | ||
async def comlist(self, ctx): | ||
embed = discord.Embed(title='Commands List', description= | ||
"Use **$** in front of the command name \n" | ||
"Example: $hello" | ||
, color=0x17e6f0) | ||
|
||
embed.add_field(name="Chat", value= | ||
"``hello`` - Greet Simon \n " | ||
"``uok`` - Check if Simon is okay \n" | ||
"``test`` - Counts recent messages" | ||
,inline=False) | ||
|
||
embed.add_field(name="Games", value= | ||
"``guess`` - Start playing a letter guessing game \n" | ||
"``guesshelp`` - Letter guessing game explanation \n" | ||
"``gstats`` - See your guessing game statistics \n" | ||
"``greset`` - Reset your guessing game statistics" | ||
,inline=False) | ||
embed.set_thumbnail(url=ctx.message.author.avatar_url) | ||
embed.set_footer(text='Requested by ' + ctx.message.author.name + '.', icon_url=ctx.message.author.avatar_url) | ||
await ctx.message.channel.send(embed=embed) | ||
|
||
@commands.command() | ||
async def guesshelp(self, ctx): | ||
embed = discord.Embed(title = 'Guessing Game - How to Play', description = | ||
"Letter Guessing Game Tutorial and Explanation", color=0x17e6f0) | ||
|
||
embed.add_field(name="Objective", value= | ||
"The objective is to find the correct letter from the alphabet. \n" | ||
"You have 3 attempts. You win if you manage to guess the letter. \n" | ||
"If you inputted 3 letters and none of them were the one chosen by the bot, you lose." | ||
, inline=False) | ||
|
||
embed.add_field(name="How do I play?", value= | ||
"Start the game using the command ``$guess``. \n" | ||
"The bot will ask you for a letter. You have 7 seconds to input a lowercase English alphabet letter" | ||
" or the game will timeout and reset. \n" | ||
"If you manage to score in the first try, you will get a ``LUCKY``. \n" | ||
"If you don't, that's okay. You still have 2 attempts. Make sure you use the hints explained below. \n" | ||
"After playing, you can check your stats using ``$gstats``. You can also reset them using ``$greset``" | ||
, inline=False) | ||
|
||
embed.add_field(name="How do I increase my chances?", value= | ||
"The game will give hints in the form of distance to the correct letter " | ||
"from your currently selected one. \n" | ||
"**Example1:** If 'd' is the correct answer and you've chosen 'a', " | ||
"you will get ``Hint: The letter you are looking for is 3 positions away.`` \n" | ||
"Going 3 spots to the right will net you the correct answer. \n" | ||
"The hints go in both directions: \n" | ||
"**Example2** If 'z' is the correct answer and you've chosen 'b', you will get " | ||
"``Hint: The letter you are looking for is 2 positions away.`` and not 24 positions. \n" | ||
"Imagine the beginning and end of the alphabet connected, like this: `` ... w, x, y, z, a, b, c, d, e ...`` \n" | ||
"So whether you go to the right or to the left is up to you. \nKeep in mind that it is possible to get every " | ||
"answer right as long as you start with 3 attempts (including the initial guess)." | ||
, inline=False) | ||
|
||
embed.set_footer(text = "Requested by " + ctx.message.author.name + '.', icon_url= ctx.message.author.avatar_url) | ||
|
||
await ctx.message.channel.send(embed=embed) | ||
|
||
|
||
def setup(client): | ||
client.add_cog(BasicFunctionsHelp(client)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import asyncio | ||
import discord | ||
from discord.ext import commands | ||
import sys, traceback | ||
from botClient import client | ||
from botClient import botToken | ||
import guessFile | ||
|
||
extensions = ['test', 'basicFunctionsFile', 'helpFile', 'guessFile'] #Extensions list | ||
|
||
@client.event | ||
async def on_ready(): | ||
print('Logged in as') | ||
print(client.user.name) | ||
print('CID: ' + str(client.user.id)) | ||
print('-----------------------') | ||
|
||
if __name__ == '__main__': #Load extensions from other modules | ||
for extension in extensions: | ||
try: | ||
client.load_extension(extension) | ||
except Exception as error: | ||
print(f'{extension} cannot be loaded [{error}]') | ||
|
||
|
||
@client.event | ||
async def on_message(message): | ||
if message.author == client.user: | ||
return | ||
|
||
if message.content == 'hai': | ||
await message.channel.send('YES') | ||
|
||
await client.process_commands(message) #So that events don't disable commands | ||
|
||
@client.event | ||
async def on_member_join(member): | ||
# print(ctx.author.guild.name) testing | ||
await message.channel.send(f'Welcome {member.mention} to {member.guild.name}!') | ||
await client.process_commands(message) #So that events don't disable commands | ||
|
||
@client.command() | ||
async def ctest(ctx): | ||
await ctx.send('I heard you! {}'.format(ctx.author.mention)) | ||
|
||
|
||
client.run(botToken) | ||
|
Oops, something went wrong.