|
@ -0,0 +1,13 @@
|
||||||
|
files/status.txt
|
||||||
|
files/readyMessage.txt
|
||||||
|
files/client.txt
|
||||||
|
files/lastTasks.json
|
||||||
|
files/c4.json
|
||||||
|
files/hangman.json
|
||||||
|
files/stats.json
|
||||||
|
files/lost.json
|
||||||
|
files/locked.json
|
||||||
|
files/database.json
|
||||||
|
.idea/
|
||||||
|
__pycache__
|
||||||
|
.env
|
|
@ -0,0 +1 @@
|
||||||
|
3.6.9
|
|
@ -0,0 +1,226 @@
|
||||||
|
from data import constants
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import timeFormatters, stringFormatters
|
||||||
|
from functions.database import birthdays
|
||||||
|
|
||||||
|
|
||||||
|
class Birthdays(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Birthday", aliases=["Bd", "Birthdays"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@help.Category(Category.Other)
|
||||||
|
async def birthday(self, ctx, member: discord.Member = None):
|
||||||
|
"""
|
||||||
|
Command to check the birthday of yourself/another person.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param member: The member to check
|
||||||
|
"""
|
||||||
|
if member is not None:
|
||||||
|
# A member was tagged
|
||||||
|
nameStr = "**{}**'s".format(member.display_name)
|
||||||
|
res = birthdays.get_user(member.id)
|
||||||
|
else:
|
||||||
|
# No member passed -> check the user's birthday
|
||||||
|
nameStr = "Jouw"
|
||||||
|
res = birthdays.get_user(ctx.author.id)
|
||||||
|
|
||||||
|
if not res:
|
||||||
|
# Nothing found in the db for this member
|
||||||
|
return await ctx.send("{} verjaardag zit nog niet in de database.".format(nameStr))
|
||||||
|
|
||||||
|
# Create a datetime object of the upcoming birthday,
|
||||||
|
# and a formatted string displaying the date
|
||||||
|
dayDatetime, timeString = self.dmToDatetime(res[0][0], res[0][1])
|
||||||
|
|
||||||
|
# Find the weekday related to this day
|
||||||
|
weekday = timeFormatters.intToWeekday(dayDatetime.weekday()).lower()
|
||||||
|
|
||||||
|
return await ctx.send("{} verjaardag staat ingesteld op **{} {}**.".format(
|
||||||
|
nameStr, weekday, timeString
|
||||||
|
))
|
||||||
|
|
||||||
|
@birthday.command(name="Today", aliases=["Now"])
|
||||||
|
async def today(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that lists all birthdays of the day.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
# Create a datetime object for today
|
||||||
|
dt = timeFormatters.dateTimeNow()
|
||||||
|
await ctx.send(self.getBirthdayOnDate(dt))
|
||||||
|
|
||||||
|
@birthday.command(name="Tomorrow", aliases=["Tm", "Tmw"])
|
||||||
|
async def tomorrow(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that lists all birthdays of tomorrow.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
# Create a datetime object for tomorrow
|
||||||
|
dt = timeFormatters.dateTimeNow() + datetime.timedelta(days=1)
|
||||||
|
await ctx.send(self.getBirthdayOnDate(dt).replace("Vandaag", "Morgen").replace("vandaag", "morgen"))
|
||||||
|
|
||||||
|
@birthday.command(name="Week")
|
||||||
|
async def week(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that lists all birthdays for the coming week.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
# Dict of all birthdays this week
|
||||||
|
this_week = {}
|
||||||
|
|
||||||
|
# Create a datetime object starting yesterday so the first line
|
||||||
|
# of the loop can add a day every time,
|
||||||
|
# as premature returning would prevent this from happening
|
||||||
|
# & get the day stuck
|
||||||
|
dt = timeFormatters.dateTimeNow() - datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
# Create an embed
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Verjaardagen deze week")
|
||||||
|
|
||||||
|
# Add all people of the coming week
|
||||||
|
for dayCounter in range(7):
|
||||||
|
dt += datetime.timedelta(days=1)
|
||||||
|
res = birthdays.get_users_on_date(dt.day, dt.month)
|
||||||
|
|
||||||
|
# No birthdays on this day
|
||||||
|
if not res:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add everyone from this day into the dict
|
||||||
|
this_week[str(dayCounter)] = {"day": dt.day, "month": dt.month, "users": []}
|
||||||
|
|
||||||
|
for user in res:
|
||||||
|
this_week[str(dayCounter)]["users"].append(user[0])
|
||||||
|
|
||||||
|
# No one found
|
||||||
|
if not this_week:
|
||||||
|
embed.description = "Deze week is er niemand jarig."
|
||||||
|
return await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
COC = self.client.get_guild(int(constants.CallOfCode))
|
||||||
|
|
||||||
|
# For every day, add the list of users into the embed
|
||||||
|
for day, value in this_week.items():
|
||||||
|
|
||||||
|
dayDatetime, timeString = self.dmToDatetime(int(value["day"]), int(value["month"]))
|
||||||
|
weekday = timeFormatters.intToWeekday(dayDatetime.weekday())
|
||||||
|
|
||||||
|
embed.add_field(name="{} {}".format(weekday, timeString),
|
||||||
|
value=", ".join(COC.get_member(user).mention for user in value["users"]),
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
def getBirthdayOnDate(self, dt):
|
||||||
|
"""
|
||||||
|
Function to get all birthdays on a certain date.
|
||||||
|
Returns a string right away to avoid more code duplication.
|
||||||
|
:param dt: the date (Python datetime instance)
|
||||||
|
:return: A formatted string containing all birthdays on [dt]
|
||||||
|
"""
|
||||||
|
res = birthdays.get_users_on_date(dt.day, dt.month)
|
||||||
|
|
||||||
|
# Nobody's birthday
|
||||||
|
if not res:
|
||||||
|
return "Vandaag is er niemand jarig."
|
||||||
|
|
||||||
|
COC = self.client.get_guild(int(constants.CallOfCode))
|
||||||
|
|
||||||
|
# Create a list of member objects of the people that have a birthday on this date
|
||||||
|
people = [COC.get_member(int(user[0])) for user in res]
|
||||||
|
|
||||||
|
if len(people) == 1:
|
||||||
|
return "Vandaag is **{}** jarig.".format(people[0].display_name)
|
||||||
|
return "Vandaag zijn {} en {} jarig.".format(
|
||||||
|
", ".join("**" + user.display_name + "**" for user in people[:-1]),
|
||||||
|
people[-1].display_name
|
||||||
|
)
|
||||||
|
|
||||||
|
def dmToDatetime(self, day, month):
|
||||||
|
"""
|
||||||
|
Converts a day + month to a datetime instance.
|
||||||
|
:param day: the day in the date
|
||||||
|
:param month: the month in the date
|
||||||
|
:return: a datetime instance representing the next time this date occurs,
|
||||||
|
and a formatted string for this date
|
||||||
|
"""
|
||||||
|
now = timeFormatters.dateTimeNow()
|
||||||
|
year = now.year
|
||||||
|
|
||||||
|
# Add an extra year to the date in case it has already passed
|
||||||
|
if month < now.month or (month == now.month and day < now.day):
|
||||||
|
year += 1
|
||||||
|
|
||||||
|
# Create a datetime object for this birthday
|
||||||
|
timeString = "{}/{}/{}".format(
|
||||||
|
stringFormatters.leadingZero(str(day)),
|
||||||
|
stringFormatters.leadingZero(str(month)),
|
||||||
|
year
|
||||||
|
)
|
||||||
|
|
||||||
|
dayDatetime = datetime.datetime.strptime(timeString, "%d/%m/%Y")
|
||||||
|
return dayDatetime, timeString
|
||||||
|
|
||||||
|
@birthday.command(name="Set", usage="[DD/MM/YYYY]")
|
||||||
|
async def set(self, ctx, date=None, member: discord.Member = None):
|
||||||
|
"""
|
||||||
|
Command to add your birthday into the database.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param date: the date of your birthday
|
||||||
|
:param member: another member whose birthday has to be added/changed
|
||||||
|
"""
|
||||||
|
# No date passed
|
||||||
|
if date is None:
|
||||||
|
return await ctx.send("Geef een datum op.")
|
||||||
|
|
||||||
|
# Invalid format used
|
||||||
|
if date.count("/") != 2:
|
||||||
|
return await ctx.send("Ongeldig formaat (gebruik DD/MM/YYYY).")
|
||||||
|
|
||||||
|
# Check if anything is wrong with the date
|
||||||
|
try:
|
||||||
|
day = int(date.split("/")[0])
|
||||||
|
month = int(date.split("/")[1])
|
||||||
|
year = int(date.split("/")[2])
|
||||||
|
|
||||||
|
# This is not used, but creating an invalid datetime object throws a ValueError
|
||||||
|
# so it prevents invalid dates like 69/420/360
|
||||||
|
dt = datetime.datetime(year=year, month=month, day=day)
|
||||||
|
|
||||||
|
# Assume no one in the Discord is more than 5 years younger, or 10 years older
|
||||||
|
# (which are also virtually impossible, but just to be sure)
|
||||||
|
if year >= timeFormatters.dateTimeNow().year - 15 or year < 1990:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
return await ctx.send("Dit is geen geldige datum.")
|
||||||
|
|
||||||
|
# A member was tagged, check if I did it
|
||||||
|
if member is not None:
|
||||||
|
if str(ctx.author.id) != str(constants.myId):
|
||||||
|
return await ctx.send("Je kan andere mensen hun verjaardag niet instellen, {}.".format(ctx.author.display_name))
|
||||||
|
else:
|
||||||
|
birthdays.add_user(member.id, day, month, year)
|
||||||
|
return await ctx.message.add_reaction("✅")
|
||||||
|
|
||||||
|
# Birthday is already added
|
||||||
|
if birthdays.get_user(ctx.author.id) and str(ctx.author.id) != constants.myId:
|
||||||
|
return await ctx.send("Je verjaardag zit al in de database.")
|
||||||
|
|
||||||
|
# Add into the db
|
||||||
|
birthdays.add_user(ctx.author.id, day, month, year)
|
||||||
|
return await ctx.send("Je verjaardag is toegevoegd aan de database.")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Birthdays(client))
|
|
@ -0,0 +1,149 @@
|
||||||
|
from converters.numbers import Abbreviated
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, timeFormatters
|
||||||
|
from functions.database import currency
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Bitcoin(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Bitcoin", aliases=["Bc"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def bc(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows your Bitcoin bank.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
price = self.getPrice()
|
||||||
|
bc = float(currency.getOrAddUser(ctx.author.id)[8])
|
||||||
|
|
||||||
|
currentTime = timeFormatters.dateTimeNow()
|
||||||
|
currentTimeFormatted = currentTime.strftime('%m/%d/%Y om %H:%M:%S')
|
||||||
|
|
||||||
|
# Create the embed
|
||||||
|
embed = discord.Embed(colour=discord.Colour.gold())
|
||||||
|
embed.set_author(name="Bitcoin Bank van {}".format(ctx.author.display_name))
|
||||||
|
embed.add_field(name="Aantal Bitcoins:", value="{:,}".format(round(bc, 8)), inline=False)
|
||||||
|
embed.add_field(name="Huidige waarde:", value="{:,} Didier Dink{}"
|
||||||
|
.format(round(bc * price, 8), checks.pluralS(bc * price)), inline=False)
|
||||||
|
embed.set_footer(text="Huidige Bitcoin prijs: €{:,} ({})".format(price, str(currentTimeFormatted)))
|
||||||
|
|
||||||
|
# Add the Bitcoin icon to the embed
|
||||||
|
file = discord.File("files/images/bitcoin.png", filename="icon.png")
|
||||||
|
embed.set_thumbnail(url="attachment://icon.png")
|
||||||
|
|
||||||
|
await ctx.send(embed=embed, file=file)
|
||||||
|
|
||||||
|
@bc.command(name="Price")
|
||||||
|
async def price(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the current Bitcoin price.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
price = self.getPrice()
|
||||||
|
currentTime = timeFormatters.dateTimeNow()
|
||||||
|
currentTimeFormatted = currentTime.strftime('%m/%d/%Y om %H:%M:%S')
|
||||||
|
await ctx.send(
|
||||||
|
"Huidige Bitcoin prijs: **€{:,}** ({}).".format(price, str(currentTimeFormatted)))
|
||||||
|
|
||||||
|
@bc.command(name="Buy", usage="[Aantal]")
|
||||||
|
async def buy(self, ctx, amount: Abbreviated):
|
||||||
|
"""
|
||||||
|
Command to buy Bitcoins.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param amount: the amount of Bitcoins the user wants to buy
|
||||||
|
"""
|
||||||
|
|
||||||
|
resp = checks.isValidAmount(ctx, amount)
|
||||||
|
|
||||||
|
# Not a valid amount: send the appropriate error message
|
||||||
|
if not resp[0]:
|
||||||
|
return await ctx.send(resp[1])
|
||||||
|
|
||||||
|
if amount == "all":
|
||||||
|
amount = resp[1]
|
||||||
|
|
||||||
|
# Calculate the amount of Bitcoins the user can buy with [amount] of Didier Dinks
|
||||||
|
price = self.getPrice()
|
||||||
|
purchased = round(float(amount) / price, 8)
|
||||||
|
|
||||||
|
# Update the db
|
||||||
|
currency.update(ctx.author.id, "dinks", float(currency.dinks(ctx.author.id)) - float(amount))
|
||||||
|
currency.update(ctx.author.id, "bitcoins",
|
||||||
|
float(currency.getOrAddUser(ctx.author.id)[8]) + float(purchased))
|
||||||
|
|
||||||
|
await ctx.send("**{}** heeft **{:,}** Bitcoin{} gekocht voor **{:,}** Didier Dink{}!"
|
||||||
|
.format(ctx.author.display_name, purchased, checks.pluralS(purchased),
|
||||||
|
round(float(amount)), checks.pluralS(amount)))
|
||||||
|
|
||||||
|
@bc.command(name="Sell", usage="[Aantal]")
|
||||||
|
async def sell(self, ctx, amount: Abbreviated):
|
||||||
|
"""
|
||||||
|
Command to sell Bitcoins.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param amount: the amount of Bitcoins the user wants to sell
|
||||||
|
"""
|
||||||
|
if amount == "all":
|
||||||
|
amount = float(currency.getOrAddUser(ctx.author.id)[8])
|
||||||
|
|
||||||
|
try:
|
||||||
|
amount = float(amount)
|
||||||
|
if amount <= 0:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
bc = float(currency.getOrAddUser(ctx.author.id)[8])
|
||||||
|
|
||||||
|
if bc == 0.0:
|
||||||
|
# User has no Bitcoins
|
||||||
|
await ctx.send("Je hebt geen Bitcoins, **{}**".format(ctx.author.display_name))
|
||||||
|
elif amount > bc:
|
||||||
|
# User is trying to sell more Bitcoins that he has
|
||||||
|
await ctx.send("Je hebt niet genoeg Bitcoins om dit te doen, **{}**"
|
||||||
|
.format(ctx.author.display_name))
|
||||||
|
else:
|
||||||
|
price = self.getPrice()
|
||||||
|
dinks = float(currency.dinks(ctx.author.id))
|
||||||
|
|
||||||
|
currency.update(ctx.author.id, "bitcoins", bc - amount)
|
||||||
|
currency.update(ctx.author.id, "dinks", dinks + (price * amount))
|
||||||
|
|
||||||
|
await ctx.send("**{}** heeft **{:,}** Bitcoin{} verkocht voor **{:,}** Didier Dink{}!"
|
||||||
|
.format(ctx.author.display_name, round(amount, 8), checks.pluralS(amount),
|
||||||
|
round((price * amount), 8), checks.pluralS(price * amount)))
|
||||||
|
except ValueError:
|
||||||
|
# Can't be parsed to float -> random string OR smaller than 0
|
||||||
|
await ctx.send("Geef een geldig bedrag op.")
|
||||||
|
|
||||||
|
@bc.command(aliases=["Lb", "Leaderboards"], hidden=True)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def leaderboard(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the Bitcoin Leaderboard.
|
||||||
|
Alias for Lb Bc.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
# Call the appropriate leaderboard function
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("bitcoin", ctx)
|
||||||
|
|
||||||
|
def getPrice(self):
|
||||||
|
"""
|
||||||
|
Function to get the current Bitcoin price.
|
||||||
|
:return: the current Bitcoin price (float)
|
||||||
|
"""
|
||||||
|
result = requests.get("https://api.coindesk.com/v1/bpi/currentprice.json").json()
|
||||||
|
currentPrice = result["bpi"]["EUR"]["rate_float"]
|
||||||
|
return float(currentPrice)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Bitcoin(client))
|
|
@ -0,0 +1,296 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, timeFormatters
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Corona(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
# Gets the information & calls other functions if necessary
|
||||||
|
@commands.group(name="Corona", usage="[Land]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def corona(self, ctx, country: str = "Belgium"):
|
||||||
|
"""
|
||||||
|
Command that shows the corona stats for a certain country.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param country: the country to show the stats for
|
||||||
|
"""
|
||||||
|
dic = await self.getCountryStats(country)
|
||||||
|
if dic is None:
|
||||||
|
# Country was not found
|
||||||
|
await self.sendError(ctx)
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.sendEmbed(ctx, dic)
|
||||||
|
|
||||||
|
@corona.command(aliases=["lb", "leaderboards"], hidden=True)
|
||||||
|
async def leaderboard(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the Corona Leaderboard.
|
||||||
|
Alias for Lb Corona.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:return: y
|
||||||
|
"""
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("corona", ctx)
|
||||||
|
|
||||||
|
async def sendEmbed(self, ctx, dic):
|
||||||
|
"""
|
||||||
|
Function that sends a Corona embed from a dictionary.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param dic: the dictionary corresponding to this country
|
||||||
|
"""
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red(), title="Coronatracker {}".format(dic["today"]["country"]))
|
||||||
|
embed.set_thumbnail(url="https://i.imgur.com/aWnDuBt.png")
|
||||||
|
|
||||||
|
# Total
|
||||||
|
embed.add_field(name="Totale Gevallen (Vandaag):",
|
||||||
|
value="{:,} **(+{:,})** {}".format(
|
||||||
|
dic["today"]["cases"],
|
||||||
|
dic["today"]["todayCases"],
|
||||||
|
self.trendIndicator(dic, "todayCases")
|
||||||
|
),
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
# Active
|
||||||
|
embed.add_field(name="Actieve Gevallen (Vandaag):",
|
||||||
|
value="{:,} **(+{:,})** {}".format(
|
||||||
|
dic["today"]["activeCases"],
|
||||||
|
dic["today"]["activeCases"] - dic["yesterday"]["activeCases"],
|
||||||
|
self.activeTrendIndicator(dic)
|
||||||
|
),
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
# Deaths
|
||||||
|
embed.add_field(name="Sterfgevallen (Vandaag):",
|
||||||
|
value="{:,} **(+{:,})** {}".format(
|
||||||
|
dic["today"]["deaths"],
|
||||||
|
dic["today"]["todayDeaths"],
|
||||||
|
self.trendIndicator(dic, "todayDeaths")
|
||||||
|
),
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
# Recovered
|
||||||
|
embed.add_field(name="Hersteld (Vandaag):",
|
||||||
|
value="{:,} **(+{:,}) {}**".format(
|
||||||
|
dic["today"]["recovered"],
|
||||||
|
dic["today"]["todayRecovered"],
|
||||||
|
self.trendIndicator(dic, "todayRecovered")
|
||||||
|
),
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
# Test Cases
|
||||||
|
embed.add_field(name="Aantal uitgevoerde tests:",
|
||||||
|
value="{:,}".format(dic["today"]["tests"]),
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
# Timestamp of last update
|
||||||
|
timeFormatted = timeFormatters.epochToDate(dic["today"]["updated"])
|
||||||
|
embed.set_footer(text="Laatst geüpdatet op {} ({} geleden)".format(
|
||||||
|
timeFormatted["date"], timeFormatted["timeAgo"]))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(name="Trends", aliases=["Ct"], usage="[Land]*")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def trends(self, ctx, country: str = "Belgium"):
|
||||||
|
"""
|
||||||
|
Command that gives more precise stats & changes.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param country: the country to get the stats for
|
||||||
|
"""
|
||||||
|
dic = await self.getCountryStats(country)
|
||||||
|
if dic is None:
|
||||||
|
await self.sendError(ctx)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the distribution for this country
|
||||||
|
distribution = self.distribution(dic)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red(), title="Coronatrends {}".format(dic["today"]["country"]))
|
||||||
|
embed.set_thumbnail(url="https://i.imgur.com/aWnDuBt.png")
|
||||||
|
|
||||||
|
# Calculate the trends & add them into the fields
|
||||||
|
embed.add_field(name="Totale Gevallen\n({:,})".format(dic["today"]["cases"]),
|
||||||
|
value=self.trend(dic, "cases"),
|
||||||
|
inline=True)
|
||||||
|
|
||||||
|
embed.add_field(name="Sterfgevallen\n({:,})".format(dic["today"]["deaths"]),
|
||||||
|
value=self.trend(dic, "deaths"),
|
||||||
|
inline=True)
|
||||||
|
|
||||||
|
embed.add_field(name="Hersteld\n({:,})".format(dic["today"]["recovered"]),
|
||||||
|
value=self.trend(dic, "recovered"))
|
||||||
|
|
||||||
|
embed.add_field(name="Totale Gevallen\nVandaag ({:,})".format(dic["today"]["todayCases"]),
|
||||||
|
value=self.trend(dic, "todayCases"),
|
||||||
|
inline=True)
|
||||||
|
|
||||||
|
embed.add_field(name="Sterfgevallen\nVandaag ({:,})".format(dic["today"]["todayDeaths"]),
|
||||||
|
value=self.trend(dic, "todayDeaths"),
|
||||||
|
inline=True)
|
||||||
|
|
||||||
|
embed.add_field(name="Hersteld\nVandaag ({:,})".format(dic["today"]["todayRecovered"]),
|
||||||
|
value=self.trend(dic, "todayRecovered"))
|
||||||
|
|
||||||
|
embed.add_field(name="Verdeling", value="Actief: {} | Overleden: {} | Hersteld: {}".format(
|
||||||
|
distribution[0], distribution[1], distribution[2]), inline=False)
|
||||||
|
|
||||||
|
# Timestamp of last update
|
||||||
|
timeFormatted = timeFormatters.epochToDate(dic["today"]["updated"])
|
||||||
|
embed.set_footer(text="Laatst geüpdatet op {} ({} geleden)".format(
|
||||||
|
timeFormatted["date"], timeFormatted["timeAgo"]))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
async def getCountryStats(self, country):
|
||||||
|
"""
|
||||||
|
Function that gets the stats for a specific country.
|
||||||
|
:param country: the country to get the stats for
|
||||||
|
:return: a dictionary containing the info for today & yesterday
|
||||||
|
"""
|
||||||
|
# Check if Global or a country was passed
|
||||||
|
if country.lower() == "global":
|
||||||
|
country = "all?"
|
||||||
|
else:
|
||||||
|
country = "countries/{}?strict=false&".format(country)
|
||||||
|
|
||||||
|
today = requests.get("https://disease.sh/v3/covid-19/{}yesterday=false&allowNull=false".format(country)).json()
|
||||||
|
|
||||||
|
# Send error message
|
||||||
|
if "message" in today:
|
||||||
|
return None
|
||||||
|
|
||||||
|
yesterday = requests.get("https://disease.sh/v3/covid-19/{}yesterday=true&allowNull=false".format(country)) \
|
||||||
|
.json()
|
||||||
|
|
||||||
|
# Divide into today & yesterday to be able to calculate the changes
|
||||||
|
dic = {
|
||||||
|
"today": {
|
||||||
|
"country": today["country"] if country != "all?" else "Global",
|
||||||
|
"cases": today["cases"],
|
||||||
|
"activeCases": today["active"],
|
||||||
|
"todayCases": today["todayCases"],
|
||||||
|
"deaths": today["deaths"],
|
||||||
|
"todayDeaths": today["todayDeaths"],
|
||||||
|
"recovered": today["recovered"],
|
||||||
|
"todayRecovered": today["todayRecovered"],
|
||||||
|
"tests": today["tests"],
|
||||||
|
"updated": today["updated"]
|
||||||
|
},
|
||||||
|
"yesterday": {
|
||||||
|
"cases": yesterday["cases"],
|
||||||
|
"activeCases": yesterday["active"],
|
||||||
|
"todayCases": yesterday["todayCases"],
|
||||||
|
"deaths": yesterday["deaths"],
|
||||||
|
"todayDeaths": yesterday["todayDeaths"],
|
||||||
|
"recovered": yesterday["recovered"],
|
||||||
|
"todayRecovered": yesterday["todayRecovered"],
|
||||||
|
"tests": yesterday["tests"],
|
||||||
|
"updated": yesterday["updated"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dic
|
||||||
|
|
||||||
|
def distribution(self, dic):
|
||||||
|
"""
|
||||||
|
Calculates the percentage distribution for every key & shows an indicator.
|
||||||
|
:param dic: the today/yesterday dictionary for this country
|
||||||
|
:return: a list containing the distribution + indicator for active, recovered & deaths
|
||||||
|
"""
|
||||||
|
totalToday = dic["today"]["cases"] if dic["today"]["cases"] != 0 else 1
|
||||||
|
totalYesterday = dic["yesterday"]["cases"] if dic["yesterday"]["cases"] != 0 else 1
|
||||||
|
|
||||||
|
tap = round(100 * dic["today"]["activeCases"]/totalToday, 2) # Today Active Percentage
|
||||||
|
trp = round(100 * dic["today"]["recovered"]/totalToday, 2) # Today Recovered Percentage
|
||||||
|
tdp = round(100 * dic["today"]["deaths"]/totalToday, 2) # Today Deaths Percentage
|
||||||
|
yap = round(100 * dic["yesterday"]["activeCases"] / totalYesterday, 2) # Yesterday Active Percentage
|
||||||
|
yrp = round(100 * dic["yesterday"]["recovered"] / totalYesterday, 2) # Yesterday Recovered Percentage
|
||||||
|
ydp = round(100 * dic["yesterday"]["deaths"] / totalYesterday, 2) # Yesterday Deaths Percentage
|
||||||
|
|
||||||
|
return ["{}% {}".format(tap, self.indicator(tap, yap)),
|
||||||
|
"{}% {}".format(tdp, self.indicator(tdp, ydp)),
|
||||||
|
"{}% {}".format(trp, self.indicator(trp, yrp))]
|
||||||
|
|
||||||
|
async def sendError(self, ctx):
|
||||||
|
"""
|
||||||
|
Function that sends an error embed when an invalid country was passed.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.add_field(name="Error", value="Dit land staat niet in de database.", inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
# Returns a number and a percentage of rise/decline
|
||||||
|
def trend(self, dic, key):
|
||||||
|
"""
|
||||||
|
Function that creates a string representing a number & percentage of
|
||||||
|
rise & decline for a certain key of the dict.
|
||||||
|
:param dic: the today/yesterday dictionary for this country
|
||||||
|
:param key: the key to compare
|
||||||
|
:return: a string showing the increase in numbers & percentages
|
||||||
|
"""
|
||||||
|
# Difference vs yesterday
|
||||||
|
change = dic["today"][key] - dic["yesterday"][key]
|
||||||
|
|
||||||
|
# Don't divide by 0
|
||||||
|
yesterday = dic["yesterday"][key] if dic["yesterday"][key] != 0 else 1
|
||||||
|
|
||||||
|
# Percentage
|
||||||
|
perc = round(100 * change/yesterday, 2)
|
||||||
|
|
||||||
|
# Sign to add to the number
|
||||||
|
sign = "+" if change >= 0 else ""
|
||||||
|
|
||||||
|
return "{}{:,} ({}{:,}%)".format(sign, change, sign, perc)
|
||||||
|
|
||||||
|
# Requires a bit of math so this is a separate function
|
||||||
|
def activeTrendIndicator(self, dic):
|
||||||
|
"""
|
||||||
|
Function that returns a rise/decline indicator for the active cases of the day.
|
||||||
|
This is a separate function as it requires some math to get right.
|
||||||
|
New cases have to take into account the deaths & recovered cases being
|
||||||
|
subtracted as well.
|
||||||
|
:param dic: the today/yesterday dictionary for this country
|
||||||
|
:return: a triangle emoji or empty string
|
||||||
|
"""
|
||||||
|
todayNew = dic["today"]["todayCases"] - dic["today"]["todayDeaths"] - dic["today"]["todayRecovered"]
|
||||||
|
yesterdayNew = dic["yesterday"]["todayCases"] - dic["yesterday"]["todayDeaths"] - dic["yesterday"]["todayRecovered"]
|
||||||
|
|
||||||
|
return ":small_red_triangle:" if todayNew > yesterdayNew else \
|
||||||
|
(":small_red_triangle_down:" if todayNew < yesterdayNew else "")
|
||||||
|
|
||||||
|
# Returns an arrow indicating rise or decline
|
||||||
|
def trendIndicator(self, dic, key):
|
||||||
|
"""
|
||||||
|
Function that returns a rise/decline indicator for the target key.
|
||||||
|
:param dic: the today/yesterday dictionary for this country
|
||||||
|
:param key: the key to get the indicator for
|
||||||
|
:return: a triangle emoji or empty string
|
||||||
|
"""
|
||||||
|
return ":small_red_triangle:" if dic["today"][key] > dic["yesterday"][key] else \
|
||||||
|
(":small_red_triangle_down:" if dic["today"][key] < dic["yesterday"][key] else "")
|
||||||
|
|
||||||
|
# Also returns an indicator, but compares instead of pulling it out of the dic (for custom numbers)
|
||||||
|
def indicator(self, today, yesterday):
|
||||||
|
"""
|
||||||
|
Function that also returns an indicator but for two numbers
|
||||||
|
instead of comparing values out of the dictionary.
|
||||||
|
:param today: the number representing today
|
||||||
|
:param yesterday: the number representing yesterday
|
||||||
|
:return: a triangle emoji or empty string
|
||||||
|
"""
|
||||||
|
return ":small_red_triangle:" if today > yesterday else \
|
||||||
|
(":small_red_triangle_down:" if yesterday > today else "")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Corona(client))
|
|
@ -0,0 +1,113 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Define(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Define", aliases=["UrbanDictionary", "Ud"], usage="[Woord]")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def define(self, ctx, *words):
|
||||||
|
"""
|
||||||
|
Command that looks up the definition of a word in the Urban Dictionary.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param words: Word(s) to look up
|
||||||
|
"""
|
||||||
|
words = list(words)
|
||||||
|
if len(words) == 0:
|
||||||
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
||||||
|
query = " ".join(words)
|
||||||
|
answer = self.lookup(query)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.from_rgb(220, 255, 0))
|
||||||
|
embed.set_author(name="Urban Dictionary")
|
||||||
|
|
||||||
|
embed.add_field(name="Woord", value=answer["word"], inline=True)
|
||||||
|
embed.add_field(name="Auteur", value=answer["author"], inline=True)
|
||||||
|
embed.add_field(name="Definitie", value=self.cleanString(answer["definition"]), inline=False)
|
||||||
|
embed.add_field(name="Voorbeeld", value=self.cleanString(answer["example"]), inline=False)
|
||||||
|
embed.add_field(name="Rating", value=str(round(self.ratio(answer), 2)) + "%")
|
||||||
|
embed.add_field(name="Link naar de volledige definitie",
|
||||||
|
value="[Urban Dictionary]({})".format(str(answer["link"])))
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
def lookup(self, word):
|
||||||
|
"""
|
||||||
|
Function that sends the API request to get the definition.
|
||||||
|
:param word: the woord to look up
|
||||||
|
:return: a dictionary representing the info of this word
|
||||||
|
"""
|
||||||
|
url = "https://mashape-community-urban-dictionary.p.rapidapi.com/define"
|
||||||
|
|
||||||
|
querystring = {"term": word}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'x-rapidapi-host': "mashape-community-urban-dictionary.p.rapidapi.com",
|
||||||
|
'x-rapidapi-key': os.getenv("URBANDICTIONARY")
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if word.lower() == "didier":
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
response = requests.request("GET", url, headers=headers, params=querystring).json()["list"]
|
||||||
|
|
||||||
|
if len(response) > 0:
|
||||||
|
return {"word": response[0]["word"], "definition": response[0]["definition"],
|
||||||
|
"example": response[0]["example"], "thumbs_up": response[0]["thumbs_up"],
|
||||||
|
"thumbs_down": response[0]["thumbs_down"], "link": response[0]["permalink"],
|
||||||
|
"author": response[0]["author"]}
|
||||||
|
|
||||||
|
# No valid response
|
||||||
|
return self.defineDidier()
|
||||||
|
except Exception:
|
||||||
|
return self.defineDidier()
|
||||||
|
|
||||||
|
def cleanString(self, text: str):
|
||||||
|
"""
|
||||||
|
Function that cuts off definitions that are too long & strips out UD markdown
|
||||||
|
from an input string.
|
||||||
|
:param text: the input string to clean up
|
||||||
|
:return: the edited version of the string
|
||||||
|
"""
|
||||||
|
text = text.replace("[", "")
|
||||||
|
text = text.replace("]", "")
|
||||||
|
return text if len(text) < 1024 else text[:1021] + "..."
|
||||||
|
|
||||||
|
def ratio(self, dic):
|
||||||
|
"""
|
||||||
|
Function that alculates the upvote/downvote ratio of the definition.
|
||||||
|
:param dic: the dictionary representing the definition
|
||||||
|
:return: the upvote/downvote ratio (float)
|
||||||
|
"""
|
||||||
|
return (100 * int(dic["thumbs_up"])) / (int(dic["thumbs_up"]) + int(dic["thumbs_down"])) \
|
||||||
|
if int(dic["thumbs_down"]) != 0 else 100.0
|
||||||
|
|
||||||
|
def defineDidier(self):
|
||||||
|
"""
|
||||||
|
Function that returns a stock dictionary to define Didier
|
||||||
|
in case people call it, or no definition was found.
|
||||||
|
:return: a dictionary that defines Didier
|
||||||
|
"""
|
||||||
|
return {"word": "Didier", "definition": "Didier", "example": "1: Didier\n2: Hmm?", "thumbs_up": 69420,
|
||||||
|
"thumbs_down": 0, "author": "Didier",
|
||||||
|
"link": "https://upload.wikimedia.org/wikipedia/commons/a/a5"
|
||||||
|
"/Didier_Reynders_in_Iranian_Parliament_02.jpg"}
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Define(client))
|
|
@ -0,0 +1,567 @@
|
||||||
|
from converters.numbers import Abbreviated, abbreviated
|
||||||
|
from data import constants
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from enums.numbers import Numbers
|
||||||
|
from functions import checks
|
||||||
|
from functions.database import currency, prison, stats
|
||||||
|
from functions.numbers import getRep
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def calcCapacity(level):
|
||||||
|
"""
|
||||||
|
Function that calculates the rob capacity for a given level.
|
||||||
|
:param level: the level of the user
|
||||||
|
:return: the capacity the user can rob (float)
|
||||||
|
"""
|
||||||
|
cap = 200
|
||||||
|
for x in range(level):
|
||||||
|
cap *= (math.pow(1.03, x))
|
||||||
|
return round(cap)
|
||||||
|
|
||||||
|
|
||||||
|
class Dinks(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Award", aliases=["Reward"], usage="[@Persoon] [Aantal]", hidden=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def award(self, ctx, user: discord.User, amount: Abbreviated):
|
||||||
|
"""
|
||||||
|
Command that awards a user a certain amount of Didier Dinks.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param user: the user to give the Didier Dinks to
|
||||||
|
:param amount: the amount of Didier Dinks to award [user]
|
||||||
|
"""
|
||||||
|
# No amount was passed
|
||||||
|
if amount is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update the db
|
||||||
|
currency.update(user.id, "dinks", float(currency.dinks(user.id)) + float(amount))
|
||||||
|
|
||||||
|
# Gets the abbreviated representation of the amount
|
||||||
|
rep = getRep(amount, Numbers.t.value)
|
||||||
|
|
||||||
|
await ctx.send("**{}** heeft **{}** zowaar **{}** Didier Dink{} beloond!"
|
||||||
|
.format(ctx.author.display_name, self.utilsCog.getDisplayName(ctx, user.id), rep, checks.pluralS(amount)))
|
||||||
|
|
||||||
|
@commands.group(name="Dinks", aliases=["Cash"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def dinks(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the user's Didier Dinks & Platinum Dinks
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
dinks = currency.dinksAll(ctx.author.id)
|
||||||
|
|
||||||
|
answer = "**{}** heeft **{:,}** Didier Dink{}"\
|
||||||
|
.format(ctx.author.display_name, math.floor(dinks["dinks"]), checks.pluralS(dinks["dinks"]))
|
||||||
|
|
||||||
|
if dinks["platinum"] > 0:
|
||||||
|
answer += " en **{}** Platinum Dink{}".format(dinks["platinum"], checks.pluralS(dinks["platinum"]))
|
||||||
|
|
||||||
|
await ctx.send(answer + "!")
|
||||||
|
|
||||||
|
@dinks.command(aliases=["Lb", "Leaderboards"], hidden=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
async def leaderboard(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the Didier Dinks Leaderboard.
|
||||||
|
Alias for Lb Dinks.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("dinks", ctx)
|
||||||
|
|
||||||
|
@commands.command(name="Nightly")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def nightly(self, ctx):
|
||||||
|
"""
|
||||||
|
Command to claim daily Didier Dinks.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
response = currency.nightly(int(ctx.author.id))
|
||||||
|
if response[0]:
|
||||||
|
# Claim successful
|
||||||
|
await ctx.send("Je hebt je dagelijkse **{:,}** Didier Dinks geclaimt. :fire:**{}**".format(
|
||||||
|
response[1], response[2]))
|
||||||
|
else:
|
||||||
|
# Already claimed today, react PIPO
|
||||||
|
await ctx.send("Je kan dit niet meerdere keren per dag doen.")
|
||||||
|
reactCog = self.client.get_cog("ReactWord")
|
||||||
|
await reactCog.react(ctx, "pipo")
|
||||||
|
|
||||||
|
@commands.command(name="Give", aliases=["Gift"], usage="[@Persoon] [Aantal]")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def give(self, ctx, person: discord.Member, amount: Abbreviated):
|
||||||
|
"""
|
||||||
|
Command that gives your Didier Dinks to another user.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param person: user to give the Didier Dinks to
|
||||||
|
:param amount: the amount of Didier Dinks to give
|
||||||
|
"""
|
||||||
|
# Invalid amount
|
||||||
|
if amount is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
valid = checks.isValidAmount(ctx, amount)
|
||||||
|
if not valid[0]:
|
||||||
|
return await ctx.send(valid[1])
|
||||||
|
|
||||||
|
authorDinks = float(currency.dinks(ctx.author.id))
|
||||||
|
if amount == "all":
|
||||||
|
amount = authorDinks
|
||||||
|
|
||||||
|
amount = float(amount)
|
||||||
|
|
||||||
|
currency.update(person.id, "dinks", float(currency.dinks(person.id)) + amount)
|
||||||
|
currency.update(ctx.author.id, "dinks", authorDinks - amount)
|
||||||
|
|
||||||
|
rep = getRep(math.floor(amount), Numbers.t.value)
|
||||||
|
|
||||||
|
await ctx.send("**{}** heeft **{}** zowaar **{}** Didier Dink{} geschonken!"
|
||||||
|
.format(ctx.author.display_name, person.display_name,
|
||||||
|
rep, checks.pluralS(amount)))
|
||||||
|
|
||||||
|
@commands.group(name="Bank", aliases=["B"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def bank(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the user's Didier Bank.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
# 0 1 2 3 4 5 6 7 8 9 10
|
||||||
|
# ID dinks level investedamount investeddays profit defense offense bc nightly streak
|
||||||
|
response = currency.getOrAddUser(ctx.author.id)
|
||||||
|
|
||||||
|
# Calculate the cost to level your bank
|
||||||
|
interestLevelPrice = round(math.pow(1.28, int(response[2])) * 300)
|
||||||
|
ratio = round(float(1 * (1 + (int(response[2]) * 0.01))), 4)
|
||||||
|
|
||||||
|
# Calculate the amount of levels the user can purchase
|
||||||
|
counter = 0
|
||||||
|
sumPrice = float(math.pow(1.28, int(response[2])) * 300)
|
||||||
|
while float(response[1]) + float(response[3]) + float(response[5]) > sumPrice:
|
||||||
|
counter += 1
|
||||||
|
sumPrice += round(float(math.pow(1.28, int(response[2]) + counter) * 300), 4)
|
||||||
|
maxLevels = "" if counter == 0 else " (+{})".format(str(counter))
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Bank van {}".format(ctx.author.display_name))
|
||||||
|
embed.set_thumbnail(url=str(ctx.author.avatar_url))
|
||||||
|
embed.add_field(name="Level:", value=str(response[2]) + maxLevels, inline=True)
|
||||||
|
embed.add_field(name="Ratio:", value=str(ratio), inline=True)
|
||||||
|
embed.add_field(name="Prijs voor volgend level:", value="{:,}".format(interestLevelPrice), inline=False)
|
||||||
|
embed.add_field(name="Momenteel geïnvesteerd:", value="{:,}".format(math.floor(float(response[3]))), inline=False)
|
||||||
|
embed.add_field(name="Aantal dagen geïnvesteerd:", value=str(response[4]), inline=True)
|
||||||
|
embed.add_field(name="Huidige winst na claim:", value="{:,}".format(math.floor(response[5])), inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@bank.command(name="Stats")
|
||||||
|
async def stats(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the user's bank stats.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
response = currency.getOrAddUser(ctx.author.id)
|
||||||
|
|
||||||
|
# Calculate the prices to level stats up
|
||||||
|
defense = int(response[6])
|
||||||
|
defenseLevelPrice = math.floor(math.pow(1.4, defense) * 365) if defense < 38 else 5 * calcCapacity(defense - 6)
|
||||||
|
offense = int(response[7])
|
||||||
|
capacity = calcCapacity(offense)
|
||||||
|
offenseLevelPrice = math.floor(math.pow(1.5, offense) * 369) if offense < 32 else 5 * capacity
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Bank van {}".format(ctx.author.display_name))
|
||||||
|
embed.add_field(name="Offense:", value=str(offense), inline=True)
|
||||||
|
embed.add_field(name="Prijs voor volgend level:", value="{:,}".format(int(offenseLevelPrice)), inline=True)
|
||||||
|
embed.add_field(name="Capaciteit:", value="{:,}".format(int(capacity)), inline=True)
|
||||||
|
embed.add_field(name="Security:", value=str(defense), inline=True)
|
||||||
|
embed.add_field(name="Prijs voor volgend level:", value="{:,}".format(int(defenseLevelPrice)), inline=True)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@bank.group(name="Upgrade", aliases=["U"], case_insensitive=True, usage="[Categorie]", invoke_without_command=True)
|
||||||
|
async def upgrade(self, ctx):
|
||||||
|
"""
|
||||||
|
Command group to upgrade bank stats,
|
||||||
|
calling the group itself does nothing.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@upgrade.command(name="Level", aliases=["L"], hidden=True)
|
||||||
|
async def level(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that upgrades the user's bank level,
|
||||||
|
increasing interest.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
response = currency.getOrAddUser(ctx.author.id)
|
||||||
|
interestLevelPrice = float(math.pow(1.28, int(response[2])) * 300)
|
||||||
|
|
||||||
|
# Check if user has enough Didier Dinks to do this
|
||||||
|
if float(response[1]) >= interestLevelPrice:
|
||||||
|
currency.update(ctx.author.id, "dinks", float(response[1]) - interestLevelPrice)
|
||||||
|
currency.update(ctx.author.id, "banklevel", int(response[2]) + 1)
|
||||||
|
await ctx.send("**{}** heeft zijn bank geüpgradet naar level **{}**!"
|
||||||
|
.format(ctx.author.display_name, str(int(response[2]) + 1)))
|
||||||
|
else:
|
||||||
|
await ctx.send("Je hebt niet genoeg Didier Dinks om dit te doen, **{}**."
|
||||||
|
.format(ctx.author.display_name))
|
||||||
|
|
||||||
|
@upgrade.command(aliases=["Cap", "Capacity", "O", "Offence"], hidden=True)
|
||||||
|
async def offense(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that upgrades the user's bank offense,
|
||||||
|
increasing capacity & rob chances.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
response = currency.getOrAddUser(ctx.author.id)
|
||||||
|
|
||||||
|
offense = int(response[7])
|
||||||
|
capacity = calcCapacity(offense)
|
||||||
|
offenseLevelPrice = math.floor(math.pow(1.5, offense) * 369) if offense < 32 else 5 * capacity
|
||||||
|
|
||||||
|
# Check if user has enough Didier Dinks to do this
|
||||||
|
if float(response[1]) >= offenseLevelPrice:
|
||||||
|
currency.update(ctx.author.id, "dinks", float(response[1]) - offenseLevelPrice)
|
||||||
|
currency.update(ctx.author.id, "offense", int(response[7]) + 1)
|
||||||
|
await ctx.send("**{}** heeft de offense van zijn bank geüpgradet naar level **{}**!"
|
||||||
|
.format(ctx.author.display_name, int(response[7]) + 1))
|
||||||
|
else:
|
||||||
|
await ctx.send("Je hebt niet genoeg Didier Dinks om dit te doen, **{}**."
|
||||||
|
.format(ctx.author.display_name))
|
||||||
|
|
||||||
|
@upgrade.command(aliases=["D", "Defence", "Def", "Security"], hidden=True)
|
||||||
|
async def defense(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that upgrades the user's bank defense,
|
||||||
|
increasing chance of failed robs by others.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
response = currency.getOrAddUser(ctx.author.id)
|
||||||
|
defense = int(response[6])
|
||||||
|
defenseLevelPrice = math.floor(math.pow(1.4, defense) * 365) if defense < 38 else 5 * calcCapacity(defense - 6)
|
||||||
|
|
||||||
|
# Check if user has enough Didier Dinks to do this
|
||||||
|
if float(response[1]) >= defenseLevelPrice:
|
||||||
|
currency.update(ctx.author.id, "dinks", float(response[1]) - defenseLevelPrice)
|
||||||
|
currency.update(ctx.author.id, "defense", int(response[6]) + 1)
|
||||||
|
await ctx.send("**{}** heeft de security van zijn bank geüpgradet naar level **{}**!"
|
||||||
|
.format(ctx.author.display_name, int(response[6]) + 1))
|
||||||
|
else:
|
||||||
|
await ctx.send("Je hebt niet genoeg Didier Dinks om dit te doen, **{}**."
|
||||||
|
.format(ctx.author.display_name))
|
||||||
|
|
||||||
|
@commands.command(name="Invest", aliases=["Deposit"], usage="[Aantal]")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def invest(self, ctx, *amount: Abbreviated):
|
||||||
|
"""
|
||||||
|
Command that invests Didier Dinks into the user's bank.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param amount: the amount of Didier Dinks to invest
|
||||||
|
"""
|
||||||
|
# Tuples don't support assignment
|
||||||
|
amount = list(amount)
|
||||||
|
|
||||||
|
if len(amount) != 1:
|
||||||
|
await ctx.send("Geef een geldig bedrag op.")
|
||||||
|
elif not checks.isValidAmount(ctx, amount[0])[0]:
|
||||||
|
await ctx.send(checks.isValidAmount(ctx, amount[0])[1])
|
||||||
|
else:
|
||||||
|
user = currency.getOrAddUser(ctx.author.id)
|
||||||
|
if amount[0] == "all":
|
||||||
|
amount[0] = user[1]
|
||||||
|
|
||||||
|
amount[0] = float(amount[0])
|
||||||
|
currency.update(ctx.author.id, "investedamount", float(user[3]) + amount[0])
|
||||||
|
currency.update(ctx.author.id, "dinks", float(user[1]) - amount[0])
|
||||||
|
await ctx.send("**{}** heeft **{:,}** Didier Dink{} geïnvesteerd!"
|
||||||
|
.format(ctx.author.display_name, math.floor(amount[0]), checks.pluralS(amount[0])))
|
||||||
|
|
||||||
|
@commands.command(name="Claim", usage="[Aantal]*")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def claim(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Command that claims profit out of the user's Didier Bank.
|
||||||
|
:param ctx:
|
||||||
|
:param args:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
user = currency.getOrAddUser(ctx.author.id)
|
||||||
|
args = list(args)
|
||||||
|
claimAll = False
|
||||||
|
|
||||||
|
if len(args) == 0:
|
||||||
|
args.append("all")
|
||||||
|
if args[0] == "all":
|
||||||
|
args[0] = float(user[5])
|
||||||
|
claimAll = True
|
||||||
|
|
||||||
|
if not claimAll:
|
||||||
|
args[0] = abbreviated(str(args[0]))
|
||||||
|
if args[0] is None:
|
||||||
|
return await ctx.send("Dit is geen geldig bedrag.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Checks if it can be parsed to int
|
||||||
|
_ = int(args[0])
|
||||||
|
args[0] = float(args[0])
|
||||||
|
# Can't claim more than you have (or negative amounts)
|
||||||
|
if args[0] < 0 or args[0] > float(user[5]):
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
currency.update(ctx.author.id, "profit", float(user[5]) - args[0])
|
||||||
|
currency.update(ctx.author.id, "dinks", float(user[1]) + args[0])
|
||||||
|
s = stats.getOrAddUser(ctx.author.id)
|
||||||
|
stats.update(ctx.author.id, "profit", float(s[7]) + args[0])
|
||||||
|
|
||||||
|
# If you claim everything, you get your invest back as well & your days reset
|
||||||
|
if claimAll:
|
||||||
|
currency.update(ctx.author.id, "dinks", float(user[1]) + float(user[3]) + float(user[5]))
|
||||||
|
currency.update(ctx.author.id, "investedamount", 0.0)
|
||||||
|
currency.update(ctx.author.id, "investeddays", 0)
|
||||||
|
await ctx.send("**{}** heeft **{:,}** Didier Dink{} geclaimt!"
|
||||||
|
.format(ctx.author.display_name, math.floor(args[0] + float(user[3])),
|
||||||
|
checks.pluralS(math.floor(args[0] + float(user[3])))))
|
||||||
|
else:
|
||||||
|
await ctx.send("**{}** heeft **{:,}** Didier Dink{} geclaimt!".format(
|
||||||
|
ctx.author.display_name, math.floor(args[0]), checks.pluralS(math.floor(args[0]))))
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
await ctx.send("Geef een geldig bedrag op.")
|
||||||
|
|
||||||
|
@commands.group(name="Rob", usage="[@Persoon]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def rob(self, ctx, target: discord.User):
|
||||||
|
"""
|
||||||
|
Command to rob another user.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param target: the target victim to be robbed
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
canRob, caller, target = await self.canRob(ctx, target)
|
||||||
|
|
||||||
|
if not canRob:
|
||||||
|
return
|
||||||
|
|
||||||
|
threshold = 50 + round(int(target[6]) * 0.7)
|
||||||
|
rg = random.randint(0 + int(caller[7]), 100)
|
||||||
|
stat = stats.getOrAddUser(ctx.author.id)
|
||||||
|
|
||||||
|
# Rob succeeded
|
||||||
|
if rg > threshold:
|
||||||
|
capacity = float(calcCapacity(caller[7]))
|
||||||
|
remaining = capacity
|
||||||
|
|
||||||
|
# Try robbing out of invest first, then Dinks pouch
|
||||||
|
amount = capacity if float(target[3]) >= capacity else float(target[3])
|
||||||
|
remaining -= amount
|
||||||
|
currency.update(target[0], "investedamount", float(target[3]) - amount)
|
||||||
|
|
||||||
|
# Rob out of Dinks pouch
|
||||||
|
if amount != capacity and not float(target[1]) < 1:
|
||||||
|
if float(target[1]) >= remaining:
|
||||||
|
amount += remaining
|
||||||
|
currency.update(target[0], "dinks", float(target[1]) - remaining)
|
||||||
|
else:
|
||||||
|
amount += float(target[1])
|
||||||
|
currency.update(target[0], "dinks", 0.0)
|
||||||
|
|
||||||
|
# Update db
|
||||||
|
currency.update(caller[0], "dinks", float(caller[1]) + amount)
|
||||||
|
await ctx.send("**{}** heeft **{:,}** Didier Dink{} gestolen van **{}**!".format(
|
||||||
|
ctx.author.display_name, math.floor(amount), checks.pluralS(math.floor(amount)),
|
||||||
|
self.utilsCog.getDisplayName(ctx, target[0])
|
||||||
|
))
|
||||||
|
|
||||||
|
stats.update(ctx.author.id, "robs_success", int(stat[2]) + 1)
|
||||||
|
stats.update(ctx.author.id, "robs_total", float(stat[4]) + amount)
|
||||||
|
else:
|
||||||
|
# Rob failed
|
||||||
|
|
||||||
|
# Calculate what happens
|
||||||
|
fate = random.randint(1, 10)
|
||||||
|
|
||||||
|
# Leave Dinks behind instead of robbing
|
||||||
|
if fate < 8:
|
||||||
|
punishment = float(calcCapacity(caller[7]))/2
|
||||||
|
prisoned = round(float(caller[1])) < round(punishment)
|
||||||
|
|
||||||
|
# Doesn't have enough Dinks -> prison
|
||||||
|
if prisoned:
|
||||||
|
diff = round(punishment - float(caller[1]))
|
||||||
|
punishment = round(float(caller[1]))
|
||||||
|
days = 1 + round(int(caller[7]) // 10)
|
||||||
|
prison.imprison(caller[0], diff, days,
|
||||||
|
round(round(diff)//days))
|
||||||
|
|
||||||
|
# Update db
|
||||||
|
currency.update(target[0], "dinks", float(target[1]) + punishment)
|
||||||
|
currency.update(caller[0], "dinks", float(caller[1]) - punishment)
|
||||||
|
await ctx.send("**{}** was zo vriendelijk om **{}** zowaar **{:,}** Didier Dink{} te geven!"
|
||||||
|
.format(ctx.author.display_name,
|
||||||
|
self.utilsCog.getDisplayName(ctx, target[0]),
|
||||||
|
math.floor(punishment), checks.pluralS(math.floor(punishment))))
|
||||||
|
|
||||||
|
# Can't put this in the previous if- because the value of Punishment changes
|
||||||
|
if prisoned:
|
||||||
|
await ctx.send("Je bent naar de gevangenis verplaatst omdat je niet genoeg Didier Dinks had.")
|
||||||
|
elif fate == 9:
|
||||||
|
# Prison
|
||||||
|
totalSum = round(calcCapacity(caller[7]))
|
||||||
|
days = 1 + (int(caller[7])//10)
|
||||||
|
|
||||||
|
prison.imprison(caller[0], totalSum, days, totalSum/days)
|
||||||
|
await ctx.send("**{}** niet stelen, **{}** niet stelen!\nJe bent naar de gevangenis verplaatst.".format(
|
||||||
|
ctx.author.display_name, ctx.author.display_name
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
# Escape
|
||||||
|
await ctx.send("Je poging is mislukt, maar je kon nog net op tijd vluchten, **{}**.".format(
|
||||||
|
ctx.author.display_name))
|
||||||
|
|
||||||
|
stats.update(ctx.author.id, "robs_failed", int(stat[3]) + 1)
|
||||||
|
|
||||||
|
@rob.command(name="Leaderboard", aliases=["Lb", "Leaderboards"], hidden=True)
|
||||||
|
async def rob_leaderboard(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the Rob Leaderboard.
|
||||||
|
Alias for Lb Rob.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("rob", ctx)
|
||||||
|
|
||||||
|
@rob.command(name="Stats", hidden=True)
|
||||||
|
async def rob_stats(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the user's rob stats.
|
||||||
|
Alias for Stats Rob.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
await self.client.get_cog("Stats").callStats("rob", ctx)
|
||||||
|
|
||||||
|
@commands.command(name="Prison", aliases=["Jail"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Currency)
|
||||||
|
async def prison(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows how long you have to sit in prison for.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
user = prison.getUser(ctx.author.id)
|
||||||
|
|
||||||
|
if len(user) == 0:
|
||||||
|
await ctx.send("Je zit niet in de gevangenis, **{}**.".format(ctx.author.display_name))
|
||||||
|
return
|
||||||
|
|
||||||
|
user = user[0]
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="De Gevangenis")
|
||||||
|
embed.add_field(name="Borgsom:", value="{:,}".format(math.floor(user[1])), inline=False)
|
||||||
|
embed.add_field(name="Resterende dagen:", value="{}".format((user[2])), inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(name="Bail")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Currency)
|
||||||
|
async def bail(self, ctx):
|
||||||
|
"""
|
||||||
|
Command to bail yourself out of prison.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
user = prison.getUser(ctx.author.id)
|
||||||
|
if len(user) == 0:
|
||||||
|
return await ctx.send("Je zit niet in de gevangenis, **{}**.".format(ctx.author.display_name))
|
||||||
|
|
||||||
|
user = user[0]
|
||||||
|
|
||||||
|
# Check if user can afford this
|
||||||
|
valid = checks.isValidAmount(ctx, math.floor(user[1]))
|
||||||
|
if not valid[0]:
|
||||||
|
return await ctx.send(valid[1])
|
||||||
|
|
||||||
|
dinks = currency.dinks(ctx.author.id)
|
||||||
|
prison.remove(ctx.author.id)
|
||||||
|
currency.update(ctx.author.id, "dinks", float(dinks) - float(user[1]))
|
||||||
|
await ctx.send("**{}** heeft zichzelf vrijgekocht!".format(ctx.author.display_name))
|
||||||
|
|
||||||
|
# Update the user's stats
|
||||||
|
s = stats.getOrAddUser(ctx.author.id)
|
||||||
|
stats.update(ctx.author.id, "bails", int(s[10]) + 1)
|
||||||
|
|
||||||
|
# Increase the bail in the stats file
|
||||||
|
with open("files/stats.json", "r") as fp:
|
||||||
|
s = json.load(fp)
|
||||||
|
|
||||||
|
s["rob"]["bail_paid"] += float(user[1])
|
||||||
|
|
||||||
|
with open("files/stats.json", "w") as fp:
|
||||||
|
json.dump(s, fp)
|
||||||
|
|
||||||
|
async def canRob(self, ctx, target):
|
||||||
|
"""
|
||||||
|
Function that performs checks to see if a user can rob another user.
|
||||||
|
In case the rob is not possible, it already sends an error message to show this.
|
||||||
|
Returns the database dictionaries corresponding to these two users as they are
|
||||||
|
needed in this function anyways, so it prevents an unnecessary database call
|
||||||
|
in the rob command.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param target: the target victim to be robbed
|
||||||
|
:return: success: boolean, user1 ("Caller"): tuple, user2 ("Target"): tuple
|
||||||
|
"""
|
||||||
|
# Can't rob in DM's
|
||||||
|
if str(ctx.channel.type) == "private":
|
||||||
|
await ctx.send("Dat doe je niet, {}.".format(ctx.author.display_name))
|
||||||
|
return False, None, None
|
||||||
|
|
||||||
|
# Can't rob bots
|
||||||
|
if str(ctx.author.id) in constants.botIDs:
|
||||||
|
await ctx.send("Nee.")
|
||||||
|
|
||||||
|
# Can't rob in prison
|
||||||
|
if len(prison.getUser(ctx.author.id)) != 0:
|
||||||
|
await ctx.send("Je kan niemand bestelen als je in de gevangenis zit.")
|
||||||
|
return False, None, None
|
||||||
|
|
||||||
|
# Check the database for these users
|
||||||
|
user1 = currency.getOrAddUser(ctx.author.id)
|
||||||
|
user2 = currency.getOrAddUser(target.id)
|
||||||
|
|
||||||
|
# Can't rob without Didier Dinks
|
||||||
|
if float(user1[1]) < 1.0:
|
||||||
|
await ctx.send("Mensen zonder Didier Dinks kunnen niet stelen.")
|
||||||
|
return False, None, None
|
||||||
|
|
||||||
|
# Target has no Didier Dinks to rob
|
||||||
|
if float(user2[1]) < 1.0 and float(user2[3]) < 1.0:
|
||||||
|
await ctx.send("Deze persoon heeft geen Didier Dinks om te stelen.")
|
||||||
|
return False, None, None
|
||||||
|
|
||||||
|
# Passed all tests
|
||||||
|
return True, user1, user2
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Dinks(client))
|
|
@ -0,0 +1,336 @@
|
||||||
|
from data import constants
|
||||||
|
import datetime
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from functions import checks, easterEggResponses
|
||||||
|
from functions.database import stats, muttn
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
|
class Events(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
self.failedChecksCog = self.client.get_cog("FailedChecks")
|
||||||
|
self.lastFeatureRequest = 0
|
||||||
|
self.lastBugReport = 0
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_connect(self):
|
||||||
|
"""
|
||||||
|
Function called when the bot connects to Discord.
|
||||||
|
"""
|
||||||
|
print("Connected")
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_ready(self):
|
||||||
|
"""
|
||||||
|
Function called when the bot is ready & done leading.
|
||||||
|
"""
|
||||||
|
# Change status
|
||||||
|
with open("files/status.txt", "r") as statusFile:
|
||||||
|
status = statusFile.readline()
|
||||||
|
|
||||||
|
await self.client.change_presence(status=discord.Status.online, activity=discord.Game(str(status)))
|
||||||
|
|
||||||
|
# Print a message in the terminal to show that he's ready
|
||||||
|
with open("files/readyMessage.txt", "r") as readyFile:
|
||||||
|
readyMessage = readyFile.readline()
|
||||||
|
|
||||||
|
print(readyMessage)
|
||||||
|
|
||||||
|
# Add constants to the client as a botvar
|
||||||
|
self.client.constants = constants.Live if "zandbak" not in readyMessage else constants.Zandbak
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message):
|
||||||
|
"""
|
||||||
|
Function called when someone sends a message the bot can see.
|
||||||
|
:param message: the discord.Message instance of the message
|
||||||
|
"""
|
||||||
|
# Check if the server is locked, if so only allow me (to unlock) & Didier (to send the message) to talk
|
||||||
|
if self.client.locked \
|
||||||
|
and message.guild is not None \
|
||||||
|
and str(message.author.id) != constants.myId \
|
||||||
|
and str(message.author.id) != constants.didierId:
|
||||||
|
# Auto unlock when someone sends a message past the current time
|
||||||
|
if time.time() > self.client.lockedUntil:
|
||||||
|
return await self.unlock(message.channel)
|
||||||
|
|
||||||
|
return await self.utilsCog.removeMessage(message)
|
||||||
|
|
||||||
|
# If FreeGamesCheck failed, remove the message & send the user a DM
|
||||||
|
if not checks.freeGamesCheck(message):
|
||||||
|
await self.failedChecksCog.freeGames(message)
|
||||||
|
|
||||||
|
# Log commands in terminal
|
||||||
|
if any(message.content.lower().startswith(pre) for pre in self.client.prefixes):
|
||||||
|
DM = message.guild is None
|
||||||
|
print("{} in {}: {}".format(message.author.display_name,
|
||||||
|
"DM" if DM else "{} ({})".format(message.channel.name, message.guild.name),
|
||||||
|
message.content))
|
||||||
|
|
||||||
|
# Boos React to people that call him Dider
|
||||||
|
if "dider" in message.content.lower() and str(message.author.id) not in [constants.myId, constants.didierId]:
|
||||||
|
await message.add_reaction("<:boos:629603785840263179>")
|
||||||
|
|
||||||
|
# Check for other easter eggs
|
||||||
|
eER = easterEggResponses.control(message)
|
||||||
|
if eER:
|
||||||
|
await message.channel.send(eER)
|
||||||
|
|
||||||
|
# Earn XP & Message count
|
||||||
|
stats.sentMessage(message)
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_command_error(self, ctx, err):
|
||||||
|
"""
|
||||||
|
Function called when a command throws an error.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param err: the error thrown
|
||||||
|
"""
|
||||||
|
# Don't handle commands that have their own custom error handler
|
||||||
|
if hasattr(ctx.command, 'on_error'):
|
||||||
|
return
|
||||||
|
# Someone just mentioned Didier without calling a real command,
|
||||||
|
# don't care about this error
|
||||||
|
if isinstance(err, (commands.CommandNotFound, commands.CheckFailure, commands.TooManyArguments), ):
|
||||||
|
pass
|
||||||
|
# Someone used a command that was on cooldown
|
||||||
|
elif isinstance(err, commands.CommandOnCooldown):
|
||||||
|
await ctx.send("Je kan dit commando niet (meer) spammen.", delete_after=10)
|
||||||
|
# Someone forgot an argument or passed an invalid argument
|
||||||
|
elif isinstance(err, (commands.BadArgument, commands.MissingRequiredArgument)):
|
||||||
|
await ctx.send("Controleer je argumenten.")
|
||||||
|
else:
|
||||||
|
# Remove the InvokeCommandError because it's useless information
|
||||||
|
x = traceback.format_exception(type(err), err, err.__traceback__)
|
||||||
|
errorString = ""
|
||||||
|
for line in x:
|
||||||
|
if "direct cause of the following" in line:
|
||||||
|
break
|
||||||
|
errorString += line.replace("*", "") + "\n" if line.strip() != "" else ""
|
||||||
|
await self.sendErrorEmbed(ctx, err, errorString)
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_raw_reaction_add(self, react):
|
||||||
|
"""
|
||||||
|
Function called when someone adds a reaction to a message.
|
||||||
|
:param react: the RawReactionEvent associated with the reaction
|
||||||
|
"""
|
||||||
|
# Ignore RPS adding reacts
|
||||||
|
if self.client.get_user(react.user_id).bot:
|
||||||
|
return
|
||||||
|
# Feature request
|
||||||
|
if str(react.emoji) == "➕":
|
||||||
|
await self.sendReactEmbed(react, "Feature Request")
|
||||||
|
# Bug report
|
||||||
|
elif str(react.emoji) == "🐛":
|
||||||
|
await self.sendReactEmbed(react, "Bug Report")
|
||||||
|
# Muttn react
|
||||||
|
elif str(react.emoji) == "<:Muttn:761551956346798111>":
|
||||||
|
await self.addMuttn(react)
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_raw_reaction_remove(self, react):
|
||||||
|
"""
|
||||||
|
Function called when someone removes a reaction from a message.
|
||||||
|
:param react: the RawReactionEvent associated with the reaction
|
||||||
|
"""
|
||||||
|
# Decrease Muttn counter
|
||||||
|
if str(react.emoji) == "<:Muttn:761551956346798111>":
|
||||||
|
await self.removeMuttn(react)
|
||||||
|
|
||||||
|
async def removeMuttn(self, react):
|
||||||
|
"""
|
||||||
|
Function that decreases the Muttn counter for someone.
|
||||||
|
:param react: the RawReactionEvent associated with the reaction
|
||||||
|
"""
|
||||||
|
# Get the Message instance of the message
|
||||||
|
channel = self.client.get_channel(react.channel_id)
|
||||||
|
message = await channel.fetch_message(react.message_id)
|
||||||
|
muttn.removeMuttn(message)
|
||||||
|
|
||||||
|
async def addMuttn(self, react):
|
||||||
|
"""
|
||||||
|
Function that checks the Muttn counter for a message.
|
||||||
|
:param react: the RawReactionEvent associated with the reaction
|
||||||
|
"""
|
||||||
|
count = -1
|
||||||
|
# Get the Message instance of the message
|
||||||
|
channel = self.client.get_channel(react.channel_id)
|
||||||
|
message = await channel.fetch_message(react.message_id)
|
||||||
|
|
||||||
|
# Get the amount of reacts on this message
|
||||||
|
for reaction in message.reactions:
|
||||||
|
if str(reaction.emoji) == "<:Muttn:761551956346798111>":
|
||||||
|
count = reaction.count
|
||||||
|
for user in await reaction.users().flatten():
|
||||||
|
# Remove bot reacts
|
||||||
|
if user.bot:
|
||||||
|
count -= 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# React was removed in the milliseconds the fetch_message needs to get the info
|
||||||
|
if count <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update the db
|
||||||
|
muttn.muttn(message.author.id, count, message.id)
|
||||||
|
|
||||||
|
def reactCheck(self, react, msg):
|
||||||
|
"""
|
||||||
|
Function that checks if feature requests/bug reports have been sent already.
|
||||||
|
:param react: the RawReactionEvent associated with the reaction
|
||||||
|
:param msg: the message this react was placed on
|
||||||
|
"""
|
||||||
|
# Blacklist NinjaJay after spamming
|
||||||
|
if react.user_id in [153162010576551946]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Don't spam DM's when something has already been reported
|
||||||
|
# Check if the react's count is 1
|
||||||
|
for reaction in msg.reactions:
|
||||||
|
if reaction.emoji == react.emoji.name:
|
||||||
|
return reaction.count == 1
|
||||||
|
|
||||||
|
async def sendReactEmbed(self, react, messageType):
|
||||||
|
"""
|
||||||
|
Function that sends a message in Zandbak with what's going on.
|
||||||
|
:param react: the RawReactionEvent associated with the reaction
|
||||||
|
:param messageType: the type of message to send
|
||||||
|
"""
|
||||||
|
channel = self.client.get_channel(react.channel_id)
|
||||||
|
msg = await channel.fetch_message(react.message_id)
|
||||||
|
|
||||||
|
# Didn't pass the check, ignore it
|
||||||
|
if not self.reactCheck(react, msg):
|
||||||
|
return
|
||||||
|
|
||||||
|
typeChannels = {"Feature Request": int(constants.FeatureRequests), "Bug Report": int(constants.BugReports)}
|
||||||
|
|
||||||
|
# Add a 10 second cooldown to requests/reports to avoid spam
|
||||||
|
# even tho apparently the people don't care
|
||||||
|
if round(time.time()) - (
|
||||||
|
self.lastFeatureRequest if messageType == "Feature Request" else self.lastBugReport) < 10:
|
||||||
|
await channel.send("Je moet even wachten vooraleer je nog een {} maakt.".format(messageType.lower()))
|
||||||
|
await msg.add_reaction("🕐")
|
||||||
|
return
|
||||||
|
# Report on an empty message
|
||||||
|
elif msg.content == "":
|
||||||
|
await channel.send("Dit bericht bevat geen tekst.")
|
||||||
|
await msg.add_reaction("❌")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update the variables
|
||||||
|
if messageType == "Feature Request":
|
||||||
|
self.lastFeatureRequest = round(time.time())
|
||||||
|
else:
|
||||||
|
self.lastBugReport = round(time.time())
|
||||||
|
|
||||||
|
# Ignore people reacting on Didier's messages
|
||||||
|
if str(msg.author.id) != constants.didierId:
|
||||||
|
# Get the user's User instance & the channel to send the message to
|
||||||
|
COC = self.client.get_guild(int(constants.CallOfCode))
|
||||||
|
user = COC.get_member(react.user_id)
|
||||||
|
targetChannel = self.client.get_channel(typeChannels[messageType])
|
||||||
|
|
||||||
|
await targetChannel.send("{} door **{}** in **#{}** ({}):\n``{}``\n{}".format(
|
||||||
|
messageType,
|
||||||
|
user.display_name,
|
||||||
|
channel.name if str(channel.type) != "private" else "DM",
|
||||||
|
channel.guild.name if str(channel.type) != "private" else "DM",
|
||||||
|
msg.content, msg.jump_url
|
||||||
|
))
|
||||||
|
await msg.add_reaction("✅")
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message_edit(self, before, after):
|
||||||
|
"""
|
||||||
|
Function called when a message is edited,
|
||||||
|
so people can't edit messages in FreeGames to cheat the system.
|
||||||
|
:param before: the message before it was edited
|
||||||
|
:param after: the message after it was edited
|
||||||
|
"""
|
||||||
|
# Run the message through the checks again
|
||||||
|
if not checks.freeGamesCheck(after):
|
||||||
|
await self.failedChecksCog.freeGames(after)
|
||||||
|
|
||||||
|
async def sendErrorEmbed(self, ctx, error: Exception, trace):
|
||||||
|
"""
|
||||||
|
Function that sends an error embed in #ErrorLogs.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param error: the error thrown
|
||||||
|
:param trace: the stacktrace of the error
|
||||||
|
"""
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Error")
|
||||||
|
embed.add_field(name="Command:", value="{} in {}: {}".format(ctx.author.display_name,
|
||||||
|
ctx.channel.name if str(
|
||||||
|
ctx.channel.type) != "private" else "DM",
|
||||||
|
ctx.message.content), inline=False)
|
||||||
|
embed.add_field(name="Error:", value=str(error)[:1024], inline=False)
|
||||||
|
embed.add_field(name="Message:", value=str(trace)[:1024], inline=False)
|
||||||
|
|
||||||
|
# Add remaining parts in extra fields
|
||||||
|
# (embed field limits)
|
||||||
|
if len(str(trace)) < 5500:
|
||||||
|
trace_split = [str(trace)[i:i + 1024] for i in range(1024, len(str(trace)), 1024)]
|
||||||
|
for spl in trace_split:
|
||||||
|
embed.add_field(name="\u200b", value=spl, inline=False)
|
||||||
|
|
||||||
|
errorChannel = self.client.get_channel(762668505455132722)
|
||||||
|
await errorChannel.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
async def lock(self, ctx, until=None):
|
||||||
|
"""
|
||||||
|
Command that locks the server during online exams.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param until: the timestamp until which to lock (HH:MM)
|
||||||
|
"""
|
||||||
|
# No timestamp passed
|
||||||
|
if until is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
until = until.split(":")
|
||||||
|
|
||||||
|
# Create timestamps
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
untilTimestamp = time.time()
|
||||||
|
|
||||||
|
# Gets the current amount of minutes into the day
|
||||||
|
nowMinuteCount = (now.hour * 60) + now.minute
|
||||||
|
|
||||||
|
# Gets the target amount of minutes into the day
|
||||||
|
untilMinuteCount = (int(until[0]) * 60) + int(until[1])
|
||||||
|
|
||||||
|
# Adds the remaining seconds onto the current time to calculate the end of the lock
|
||||||
|
untilTimestamp += (60 * (untilMinuteCount - nowMinuteCount)) - now.second
|
||||||
|
|
||||||
|
self.client.locked = True
|
||||||
|
self.client.lockedUntil = round(untilTimestamp)
|
||||||
|
|
||||||
|
await ctx.send("De server wordt gelocked tot **{}**.".format(
|
||||||
|
datetime.datetime.fromtimestamp(untilTimestamp,
|
||||||
|
pytz.timezone("Europe/Brussels")
|
||||||
|
).strftime('%H:%M:%S')))
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
async def unlock(self, ctx):
|
||||||
|
"""
|
||||||
|
Command to unlock the server manually before the timer is over.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
self.client.locked = False
|
||||||
|
self.client.lockedUntil = -1
|
||||||
|
await ctx.send("De server is niet langer gelocked.")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Events(client))
|
|
@ -0,0 +1,28 @@
|
||||||
|
from data import constants
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
|
||||||
|
# Cog that handles failure of checks
|
||||||
|
# Has to be a Cog to have access to the Client
|
||||||
|
class FailedChecks(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# User posted in #FreeGames without being allowed to do so
|
||||||
|
async def freeGames(self, ctx):
|
||||||
|
content = ctx.content
|
||||||
|
errorChannel = self.client.get_channel(int(constants.ErrorLogs))
|
||||||
|
|
||||||
|
await self.utilsCog.removeMessage(ctx)
|
||||||
|
await self.utilsCog.sendDm(ctx.author.id,
|
||||||
|
"Je bericht \n`{}`\n werd verwijderd uit #FreeGames omdat het geen link "
|
||||||
|
"bevatte.\nPost AUB enkel links in dit kanaal.\n*Als je bericht onterecht "
|
||||||
|
"verwijderd werd, stuur dan een DM naar DJ STIJN.*".format(content))
|
||||||
|
await errorChannel.send("`{}`\nDoor **{}** werd verwijderd uit #FreeGames.".format(content,
|
||||||
|
ctx.author.display_name))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(FailedChecks(client))
|
|
@ -0,0 +1,170 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import stringFormatters, checks
|
||||||
|
from functions.database import faq
|
||||||
|
|
||||||
|
|
||||||
|
class Faq(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="FAQ", usage="[Categorie]* [@Personen]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def faq(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Command group that controls the FAQ commands.
|
||||||
|
When this command is invoked, it sends a list of valid categories.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param args: args passed
|
||||||
|
"""
|
||||||
|
# A category was requested
|
||||||
|
# This is not the cleanest but 80 subcommands is a bit much
|
||||||
|
if len(args) != 0 and any("@" not in arg for arg in args):
|
||||||
|
return await self.faqCategory(ctx, args)
|
||||||
|
|
||||||
|
# List of all categories with the first letter capitalized
|
||||||
|
resp = [stringFormatters.titleCase(cat[0]) for cat in faq.getCategories()]
|
||||||
|
|
||||||
|
# Sort alphabetically
|
||||||
|
resp.sort()
|
||||||
|
|
||||||
|
# Create an embed with all the categories
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="FAQ Categorieën")
|
||||||
|
embed.description = "\n".join(resp)
|
||||||
|
|
||||||
|
# Check if the embed has to be sent to the user
|
||||||
|
# or if the user tagged anyone
|
||||||
|
if len(ctx.message.mentions) == 0:
|
||||||
|
await ctx.author.send(embed=embed)
|
||||||
|
else:
|
||||||
|
embed.set_footer(text="Doorgestuurd door {}".format(ctx.author.display_name))
|
||||||
|
# Send it to everyone that was mentioned
|
||||||
|
for person in ctx.message.mentions:
|
||||||
|
if not person.bot:
|
||||||
|
await person.send(embed=embed)
|
||||||
|
|
||||||
|
@faq.command(hidden=True, name="Add", usage="[Category] [Question]* [Answer]*")
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
async def add(self, ctx, category, question=None, answer=None, answer_markdown=None):
|
||||||
|
"""
|
||||||
|
Command to add a FAQ to the database
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param category: the category to add the FAQ to
|
||||||
|
:param question: the question
|
||||||
|
:param answer: the answer
|
||||||
|
:param answer_markdown: a version of the answer with markdown applied
|
||||||
|
"""
|
||||||
|
# Add a new category
|
||||||
|
if question is None or answer is None:
|
||||||
|
faq.addCategory(category)
|
||||||
|
await ctx.send("**{}** is toegevoegd.".format(category))
|
||||||
|
else:
|
||||||
|
# Add a new question/answer couple to a category
|
||||||
|
faq.addQuestion(category, question, answer, answer_markdown)
|
||||||
|
await ctx.send("``{}\n{}`` is toegevoegd in {}.".format(question, answer, category))
|
||||||
|
|
||||||
|
# Quotes a specific line of the fac instead of DM'ing the entire thing
|
||||||
|
@faq.command(name="Quote", aliases=["Q"], usage="[Categorie] [Index]")
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def quote(self, ctx, category, index):
|
||||||
|
"""
|
||||||
|
Command that quotes 1 line of the FAQ into the current channel.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param category: the category of the FAQ
|
||||||
|
:param index: the index in the list to quote
|
||||||
|
:return:y
|
||||||
|
"""
|
||||||
|
# Check if a (valid) number was passed
|
||||||
|
try:
|
||||||
|
index = int(index)
|
||||||
|
if index < 1:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError:
|
||||||
|
await ctx.send("Dit is geen geldig getal.")
|
||||||
|
|
||||||
|
# Create a list of categories
|
||||||
|
categories = [t[0] for t in faq.getCategories()]
|
||||||
|
|
||||||
|
# Check if a valid category was passed
|
||||||
|
if category.lower() not in categories:
|
||||||
|
return await ctx.send("Dit is geen geldige categorie.")
|
||||||
|
|
||||||
|
resp = faq.getCategory(category.lower())
|
||||||
|
|
||||||
|
# Check if this index exists in this category
|
||||||
|
if len(resp) < index:
|
||||||
|
return await ctx.send("Dit is geen geldig getal.")
|
||||||
|
|
||||||
|
# Sort by entry Id
|
||||||
|
resp.sort(key=lambda x: int(x[0]))
|
||||||
|
|
||||||
|
await ctx.send("**{}**\n{}".format(resp[index - 1][2], resp[index - 1][3]))
|
||||||
|
|
||||||
|
async def faqCategory(self, ctx, args):
|
||||||
|
"""
|
||||||
|
Function that sends everything from a category.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param args: the args passed
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Create a list of categories
|
||||||
|
categories = [t[0] for t in faq.getCategories()]
|
||||||
|
|
||||||
|
# Random word was passed as a category
|
||||||
|
if not any(arg.lower() in categories for arg in args):
|
||||||
|
return await self.sendErrorEmbed(ctx, "Dit is geen geldige categorie.")
|
||||||
|
elif len(args) - len(ctx.message.mentions) != 1:
|
||||||
|
# Multiple categories were requested, which is not allowed
|
||||||
|
return await self.sendErrorEmbed(ctx, "Controleer je argumenten.")
|
||||||
|
|
||||||
|
category = ""
|
||||||
|
|
||||||
|
# Find the category the user requested
|
||||||
|
for word in args:
|
||||||
|
if word.lower() in categories:
|
||||||
|
category = word
|
||||||
|
break
|
||||||
|
|
||||||
|
resp = faq.getCategory(category.lower())
|
||||||
|
|
||||||
|
# Sort by entry Id
|
||||||
|
resp.sort(key=lambda x: int(x[0]))
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="FAQ {}".format(stringFormatters.titleCase(category)))
|
||||||
|
|
||||||
|
# Add everything into the embed
|
||||||
|
for i, pair in enumerate(resp):
|
||||||
|
# Add custom markdown if it exists
|
||||||
|
embed.add_field(name="#{}: {}".format(str(i + 1), pair[2]), value=pair[3] if pair[4] is None else pair[4], inline=False)
|
||||||
|
|
||||||
|
# Check if anyone was tagged to send the embed to
|
||||||
|
if len(ctx.message.mentions) == 0:
|
||||||
|
await ctx.author.send(embed=embed)
|
||||||
|
else:
|
||||||
|
embed.set_footer(text="Doorgestuurd door {}".format(ctx.author.display_name))
|
||||||
|
# Author tagged some people to send it to
|
||||||
|
for person in ctx.message.mentions:
|
||||||
|
await person.send(embed=embed)
|
||||||
|
|
||||||
|
async def sendErrorEmbed(self, ctx, message: str):
|
||||||
|
"""
|
||||||
|
Function that sends an error embed.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param message: the message to put in the embed
|
||||||
|
"""
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Error")
|
||||||
|
embed.description = message
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Faq(client))
|
|
@ -0,0 +1,89 @@
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, config
|
||||||
|
import requests
|
||||||
|
import tabulate
|
||||||
|
|
||||||
|
|
||||||
|
class Football(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return checks.isMe(ctx) and not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Jpl", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Sports)
|
||||||
|
async def jpl(self, ctx, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@jpl.command(name="Matches", aliases=["M"], usage="[Week]*")
|
||||||
|
async def matches(self, ctx, *args):
|
||||||
|
args = list(args)
|
||||||
|
if not args:
|
||||||
|
args = [str(config.get("jpl_day"))]
|
||||||
|
if all(letter.isdigit() for letter in args[0]):
|
||||||
|
current_day = requests.get("https://api.sporza.be/web/soccer/matchdays/161733/{}".format(args[0])).json()
|
||||||
|
current_day = current_day["groupedMatches"][0]["matches"]
|
||||||
|
|
||||||
|
# Create dictionaries for every match
|
||||||
|
matches_formatted = {}
|
||||||
|
for i, match in enumerate(current_day):
|
||||||
|
matchDic = {"home": match["homeTeam"]["name"], "away": match["awayTeam"]["name"]}
|
||||||
|
|
||||||
|
# Add date
|
||||||
|
matchDate = datetime.datetime.strptime(match["startDateTime"].split("+")[0], "%Y-%m-%dT%H:%M:%S.%f")
|
||||||
|
matchDic["date"] = matchDate.strftime("%d/%m")
|
||||||
|
matchDic["day"] = self.get_weekday(matchDate.weekday())
|
||||||
|
|
||||||
|
# TODO check back when there's active games (to find the key in the dict) & add the current time if not over
|
||||||
|
# Add scores
|
||||||
|
if match["status"] == "END": # Status != [not_yet_started] whatever it is
|
||||||
|
matchDic["score"] = "{} - {}".format(match["homeScore"], match["awayScore"])
|
||||||
|
else:
|
||||||
|
# If there's no score, show when the match starts
|
||||||
|
matchDic["score"] = "{}:{}".format(
|
||||||
|
("" if len(str(matchDate.hour)) == 2 else "0") + str(matchDate.hour), # Leading Zero
|
||||||
|
("" if len(str(matchDate.minute)) == 2 else "0") + str(matchDate.minute)) # Leading Zero
|
||||||
|
|
||||||
|
matches_formatted[i] = matchDic
|
||||||
|
|
||||||
|
# Put every formatted version of the matches in a list
|
||||||
|
matchList = list([self.format_match(matches_formatted[match]) for match in matches_formatted])
|
||||||
|
await ctx.send("```Jupiler Pro League - Speeldag {}\n\n{}```".format(args[0], tabulate.tabulate(matchList, headers=["Dag", "Datum", "Thuis", "Stand", "Uit", "Tijd"])))
|
||||||
|
else:
|
||||||
|
return await ctx.send("Dit is geen geldige speeldag.")
|
||||||
|
|
||||||
|
# TODO check back when there's active games & add the timestamp instead of EINDE
|
||||||
|
def format_match(self, match):
|
||||||
|
return [match["day"], match["date"], match["home"], match["score"], match["away"], "Einde"]
|
||||||
|
|
||||||
|
def get_weekday(self, day: int):
|
||||||
|
days = ["Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"]
|
||||||
|
return days[day]
|
||||||
|
|
||||||
|
@jpl.command(name="Table", aliases=["Ranking", "Rankings", "Ranks", "T"])
|
||||||
|
async def table(self, ctx, *args):
|
||||||
|
page_html = requests.get("https://sporza.be/nl/categorie/voetbal/jupiler-pro-league/").text
|
||||||
|
bs_parsed = BeautifulSoup(page_html, "html.parser")
|
||||||
|
rows = bs_parsed.find(summary="algemeen klassement").find_all("tr")[1:]
|
||||||
|
rowsFormatted = []
|
||||||
|
for row in rows:
|
||||||
|
rowsFormatted.append(self.createRowList(row))
|
||||||
|
await ctx.send("```Jupiler Pro League Klassement\n\n{}```".format(tabulate.tabulate(rowsFormatted, headers=["#", "Ploeg", "Punten", "M", "M+", "M-", "M="])))
|
||||||
|
|
||||||
|
# Formats the row into an list that can be passed to Tabulate
|
||||||
|
def createRowList(self, row):
|
||||||
|
scoresArray = list([td.renderContents().decode("utf-8") for td in row.find_all("td")])[:6]
|
||||||
|
# Insert the team name into the list
|
||||||
|
scoresArray.insert(1, row.find_all("a")[0].renderContents().decode("utf-8").split("<!--")[0])
|
||||||
|
return scoresArray
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Football(client))
|
|
@ -0,0 +1,182 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, mock, stringFormatters
|
||||||
|
from functions.database import memes, trump, dadjoke
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Fun(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Dadjoke", aliases=["Dj", "Dad"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Fun)
|
||||||
|
async def dadjoke(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that sends a random dad joke.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
await ctx.send(dadjoke.getRandomJoke())
|
||||||
|
|
||||||
|
@commands.command(name="Stalin", aliases=["Ss", "StalinMotivation", "Motivate"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Quotes)
|
||||||
|
async def stalin(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that sends a random Stalin quote.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
with open("files/StalinMotivation.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
await ctx.send(file[random.randint(1, len(file))])
|
||||||
|
|
||||||
|
@commands.command(name="Satan", aliases=["S8n", "SatanQuote"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Quotes)
|
||||||
|
async def satan(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that sends a random Satan quote.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
with open("files/SatanQuotes.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
await ctx.send(file[random.randint(1, len(file))])
|
||||||
|
|
||||||
|
@commands.command(name="Trump")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Quotes)
|
||||||
|
async def trump(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that sends a random Trump quote.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
quote = trump.getRandomQuote()
|
||||||
|
await ctx.send("**\"{}**\"\n{} - {}".format(quote[1], quote[2], quote[3]))
|
||||||
|
|
||||||
|
@commands.command(name="8-Ball", aliases=["8b", "8Ball"], ignore_extra=True)
|
||||||
|
@help.Category(category=Category.Quotes)
|
||||||
|
async def eightball(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that sends a random 8-ball response.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
with open("files/eightball.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
await ctx.send(file[random.randint(0, len(file) - 1)])
|
||||||
|
|
||||||
|
@commands.command(name="Memegen", usage="[Meme] [Velden]")
|
||||||
|
@commands.cooldown(1, 5, commands.BucketType.guild)
|
||||||
|
@help.Category(category=Category.Fun)
|
||||||
|
async def memegen(self, ctx, name="", *fields):
|
||||||
|
"""
|
||||||
|
Command that generates memes.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param name: the name of the meme
|
||||||
|
:param fields: the fields to add to the meme
|
||||||
|
"""
|
||||||
|
if len(fields) == 0:
|
||||||
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
||||||
|
# Get the meme info that corresponds to this name
|
||||||
|
result = memes.getMeme(name)
|
||||||
|
|
||||||
|
# No meme found
|
||||||
|
if not result[0]:
|
||||||
|
return await ctx.send(result[1])
|
||||||
|
|
||||||
|
# Convert to list to support item assignment
|
||||||
|
fields = list(fields)
|
||||||
|
|
||||||
|
# If there's only one field, the user isn't required to use quotes
|
||||||
|
if result[1][2] == 1:
|
||||||
|
fields = [" ".join(fields)]
|
||||||
|
|
||||||
|
# Apply mock to mocking spongebob memes
|
||||||
|
if result[1][1] == "mocking spongebob":
|
||||||
|
fields = list(map(mock.mock, fields))
|
||||||
|
|
||||||
|
# X, X everywhere only takes X as an argument
|
||||||
|
if result[1][1] == "x, x everywhere":
|
||||||
|
fields[0] = " ".join(fields)
|
||||||
|
fields.append(fields[0] + " everywhere")
|
||||||
|
|
||||||
|
# List of fields to send to the API
|
||||||
|
boxes = [{"text": ""}, {"text": ""}, {"text": ""}, {"text": ""}]
|
||||||
|
|
||||||
|
# Add all fields required & ignore the excess ones
|
||||||
|
for i in range(len(fields)):
|
||||||
|
if i > 3:
|
||||||
|
break
|
||||||
|
boxes[i]["text"] = fields[i]
|
||||||
|
|
||||||
|
# Check server status
|
||||||
|
req = requests.get('https://api.imgflip.com/get_memes').json()
|
||||||
|
|
||||||
|
if req["success"]:
|
||||||
|
caption = {
|
||||||
|
"template_id": result[1][0],
|
||||||
|
"username": os.getenv("IMGFLIPNAME"),
|
||||||
|
"password": os.getenv("IMGFLIPPASSWORD"),
|
||||||
|
"boxes[0][text]": boxes[0]["text"],
|
||||||
|
"boxes[1][text]": boxes[1]["text"],
|
||||||
|
"boxes[2][text]": boxes[2]["text"],
|
||||||
|
"boxes[3][text]": boxes[3]["text"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send the POST to the API
|
||||||
|
memeReply = requests.post('https://api.imgflip.com/caption_image', caption).json()
|
||||||
|
|
||||||
|
if memeReply['success']:
|
||||||
|
await ctx.send(str(memeReply['data']['url']))
|
||||||
|
await self.utilsCog.removeMessage(ctx.message)
|
||||||
|
else:
|
||||||
|
await ctx.send(
|
||||||
|
"Error! Controleer of je de juiste syntax hebt gebruikt. Gebruik het commando "
|
||||||
|
"\"memes\" voor een lijst aan geaccepteerde meme-namen.")
|
||||||
|
else:
|
||||||
|
await ctx.send("Er is een fout opgetreden.")
|
||||||
|
|
||||||
|
@commands.command(name="Memes")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Fun)
|
||||||
|
async def memes(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows a list of memes in the database.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
memeList = memes.getAllMemes()
|
||||||
|
|
||||||
|
# Turn the list into a list of [Name: fields]
|
||||||
|
memeList = [": ".join([stringFormatters.titleCase(meme[1]),
|
||||||
|
str(meme[2])]) for meme in sorted(memeList, key=lambda x: x[1])]
|
||||||
|
|
||||||
|
# Add the fields into the embed
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.add_field(name="Meme: aantal velden", value="\n".join(memeList), inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(name="Pjoke")
|
||||||
|
@help.Category(category=Category.Fun)
|
||||||
|
async def pjoke(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that sends a random programming joke.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
r = requests.get("https://official-joke-api.appspot.com/jokes/programming/random").json()
|
||||||
|
await ctx.send(r[0]["setup"] + "\n" + r[0]["punchline"])
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Fun(client))
|
|
@ -0,0 +1,257 @@
|
||||||
|
from converters.numbers import Abbreviated, abbreviated
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, dinks
|
||||||
|
from functions.database import currency, stats
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class Games(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Coinflip", aliases=["Cf"], usage="[Inzet]* [Aantal]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Gamble)
|
||||||
|
async def coinflip(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Command to flip a coin, optionally for Didier Dinks.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param args: bet & wager
|
||||||
|
"""
|
||||||
|
args = list(args)
|
||||||
|
choices = ["Kop", "Munt"]
|
||||||
|
result = random.choice(choices)
|
||||||
|
|
||||||
|
# No choice made & no wager
|
||||||
|
if len(args) == 0:
|
||||||
|
await ctx.send("**{}**!".format(result))
|
||||||
|
self.updateStats("cf", "h" if result == "Kop" else "t")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for invalid args
|
||||||
|
if len(args) == 1 or args[0][0].lower() not in "kmht":
|
||||||
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
||||||
|
args[1] = abbreviated(args[1])
|
||||||
|
valid = checks.isValidAmount(ctx, args[1])
|
||||||
|
|
||||||
|
# Invalid amount
|
||||||
|
if not valid[0]:
|
||||||
|
return await ctx.send(valid[1])
|
||||||
|
|
||||||
|
# Allow full words, abbreviations, and English alternatives
|
||||||
|
args[0] = "k" if args[0][0].lower() == "k" or args[0][0].lower() == "h" else "m"
|
||||||
|
won = await self.gamble(ctx, args[0], result, valid[1], 2)
|
||||||
|
|
||||||
|
if won:
|
||||||
|
s = stats.getOrAddUser(ctx.author.id)
|
||||||
|
stats.update(ctx.author.id, "cf_wins", int(s[8]) + 1)
|
||||||
|
stats.update(ctx.author.id, "cf_profit", float(s[9]) + float(valid[1]))
|
||||||
|
|
||||||
|
self.updateStats("cf", "h" if result == "Kop" else "t")
|
||||||
|
|
||||||
|
@coinflip.command(name="Stats", hidden=True)
|
||||||
|
async def cf_stats(self, ctx):
|
||||||
|
return await self.client.get_cog("Stats").callStats("cf", ctx)
|
||||||
|
|
||||||
|
@commands.group(name="Dice", aliases=["Roll"], usage="[Inzet]* [Aantal]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Gamble)
|
||||||
|
async def dice(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Command to roll a dice, optionally for Didier Dinks.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param args: bet & wager
|
||||||
|
"""
|
||||||
|
args = list(args)
|
||||||
|
result = random.randint(1, 6)
|
||||||
|
|
||||||
|
# No choice made & no wager
|
||||||
|
if len(args) == 0:
|
||||||
|
self.updateStats("dice", result)
|
||||||
|
return await ctx.send(":game_die: **{}**!".format(result))
|
||||||
|
|
||||||
|
# Check for invalid args
|
||||||
|
if len(args) == 1 or not args[0].isdigit() or not 0 < int(args[0]) < 7:
|
||||||
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
||||||
|
args[1] = abbreviated(args[1])
|
||||||
|
valid = checks.isValidAmount(ctx, args[1])
|
||||||
|
|
||||||
|
# Invalid amount
|
||||||
|
if not valid[0]:
|
||||||
|
return await ctx.send(valid[1])
|
||||||
|
|
||||||
|
await self.gamble(ctx, args[0], str(result), valid[1], 6, ":game_die: ")
|
||||||
|
self.updateStats("dice", result)
|
||||||
|
|
||||||
|
@dice.command(name="Stats", hidden=True)
|
||||||
|
async def dice_stats(self, ctx):
|
||||||
|
await self.client.get_cog("Stats").callStats("dice", ctx)
|
||||||
|
|
||||||
|
async def gamble(self, ctx, bet, result, wager, factor, pre="", post=""):
|
||||||
|
"""
|
||||||
|
Function for gambling because it's the same thing every time.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param bet: the option the user bet on
|
||||||
|
:param result: randomly generated result
|
||||||
|
:param wager: size of the bet of the user
|
||||||
|
:param factor: the factor by which the person's wager is amplified
|
||||||
|
:param pre: any string that might have to be pre-pended to the output string
|
||||||
|
:param post: any string that might have to be appended to the output string
|
||||||
|
:return: a boolean indicating whether or not the user has won
|
||||||
|
"""
|
||||||
|
# Code no longer first removes your bet to then add profit,
|
||||||
|
# resulting in triple coinflip profit (@Clement).
|
||||||
|
# Subtract one off of the factor to compensate for the initial wager
|
||||||
|
factor -= 1
|
||||||
|
answer = "**{}**! ".format(result)
|
||||||
|
won = False
|
||||||
|
|
||||||
|
# Check if won
|
||||||
|
if result[0].lower() == bet[0].lower():
|
||||||
|
won = True
|
||||||
|
answer += "Je wint **{:,}** Didier Dink{}"
|
||||||
|
currency.update(ctx.author.id, "dinks", float(currency.dinks(ctx.author.id)) + (float(wager) * factor))
|
||||||
|
else:
|
||||||
|
answer += "Je hebt je inzet (**{:,}** Didier Dink{}) verloren"
|
||||||
|
currency.update(ctx.author.id, "dinks", float(currency.dinks(ctx.author.id)) - float(wager))
|
||||||
|
self.loseDinks(round(float(wager)))
|
||||||
|
|
||||||
|
# If won -> multiple dinkS, if lost, it's possible that the user only bet on 1 dinK
|
||||||
|
await ctx.send(pre + answer.format(round(float(wager) * factor if won else float(wager)),
|
||||||
|
checks.pluralS(float(wager) * factor if won else float(wager))) +
|
||||||
|
", **{}**!".format(ctx.author.display_name))
|
||||||
|
return won
|
||||||
|
|
||||||
|
@commands.group(name="Slots", usage="[Aantal]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Gamble)
|
||||||
|
async def slots(self, ctx, wager: Abbreviated = None):
|
||||||
|
"""
|
||||||
|
Command to play slot machines.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
:param wager: the amount of Didier Dinks to bet with
|
||||||
|
"""
|
||||||
|
valid = checks.isValidAmount(ctx, wager)
|
||||||
|
# Invalid amount
|
||||||
|
if not valid[0]:
|
||||||
|
return await ctx.send(valid[1])
|
||||||
|
|
||||||
|
ratios = dinks.getRatios()
|
||||||
|
|
||||||
|
def randomKey():
|
||||||
|
return random.choice(list(ratios.keys()))
|
||||||
|
|
||||||
|
def generateResults():
|
||||||
|
return [randomKey(), randomKey(), randomKey()]
|
||||||
|
|
||||||
|
# Generate the result
|
||||||
|
result = generateResults()
|
||||||
|
|
||||||
|
textFormatted = "{}\n{}\n:yellow_square:{}:yellow_square:\n:arrow_right:{}:arrow_left::part_alternation_mark:\n" \
|
||||||
|
":yellow_square:{}:yellow_square: :red_circle:\n{}\n{}".format(
|
||||||
|
dinks.slotsHeader, dinks.slotsEmptyRow,
|
||||||
|
"".join(generateResults()), "".join(result), "".join(generateResults()),
|
||||||
|
dinks.slotsEmptyRow, dinks.slotsFooter)
|
||||||
|
|
||||||
|
await ctx.send(textFormatted)
|
||||||
|
|
||||||
|
# Everything different -> no profit
|
||||||
|
if len(set(result)) == 3:
|
||||||
|
await ctx.send("Je hebt je inzet (**{:,}** Didier Dinks) verloren, **{}**.".format(
|
||||||
|
math.floor(float(valid[1])), ctx.author.display_name
|
||||||
|
))
|
||||||
|
currency.update(ctx.author.id, "dinks", float(currency.dinks(ctx.author.id)) - math.floor(float(valid[1])))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Calculate the profit multiplier
|
||||||
|
multiplier = 1.0
|
||||||
|
for symbol in set(result):
|
||||||
|
multiplier *= ratios[symbol][result.count(symbol) - 1]
|
||||||
|
|
||||||
|
await ctx.send(":moneybag: Je wint **{:,}** Didier Dinks, **{}**! :moneybag:".format(
|
||||||
|
round(float(valid[1]) * multiplier, 2), ctx.author.display_name
|
||||||
|
))
|
||||||
|
currency.update(ctx.author.id, "dinks",
|
||||||
|
float(currency.dinks(ctx.author.id)) + (float(valid[1]) * multiplier) - math.floor(
|
||||||
|
float(valid[1])))
|
||||||
|
# Current Dinks - wager + profit
|
||||||
|
|
||||||
|
# Returns list of profits
|
||||||
|
@slots.command(name="Chart", aliases=["Symbols", "Profit"])
|
||||||
|
async def chart(self, ctx):
|
||||||
|
"""
|
||||||
|
Command to show the profit distributions for the Didier Slotmachines.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Slots Profit Chart")
|
||||||
|
ratios = dinks.getRatios()
|
||||||
|
|
||||||
|
# Add every symbol into the embed
|
||||||
|
for ratio in ratios:
|
||||||
|
embed.add_field(name=ratio, value="1: x{}\n2: x{}\n3: x{}".format(
|
||||||
|
str(ratios[ratio][0]), str(ratios[ratio][1]), str(ratios[ratio][2])
|
||||||
|
))
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.group(name="Lost", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Gamble)
|
||||||
|
async def lost(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the amount of Didier Dinks that have been lost due to gambling.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
await ctx.send("Er zijn al **{:,}** Didier Dinks verloren sinds 13/03/2020."
|
||||||
|
.format(dinks.lost()))
|
||||||
|
|
||||||
|
@lost.command(name="Today")
|
||||||
|
async def today(self, ctx):
|
||||||
|
"""
|
||||||
|
Command that shows the amount of Didier Dinks lost today.
|
||||||
|
:param ctx: Discord Context
|
||||||
|
"""
|
||||||
|
await ctx.send("Er zijn vandaag al **{:,}** Didier Dinks verloren."
|
||||||
|
.format(dinks.lostToday()))
|
||||||
|
|
||||||
|
def updateStats(self, game, key):
|
||||||
|
"""
|
||||||
|
Function to update the stats file for a game.
|
||||||
|
:param game: the game to change the stats for
|
||||||
|
:param key: the key in the game's dict to update
|
||||||
|
"""
|
||||||
|
with open("files/stats.json", "r") as fp:
|
||||||
|
s = json.load(fp)
|
||||||
|
|
||||||
|
s[game][str(key)] += 1
|
||||||
|
|
||||||
|
with open("files/stats.json", "w") as fp:
|
||||||
|
json.dump(s, fp)
|
||||||
|
|
||||||
|
def loseDinks(self, amount):
|
||||||
|
"""
|
||||||
|
Function that adds Didier Dinks to the lost file.
|
||||||
|
:param amount: the amount of Didier Dinks lost
|
||||||
|
"""
|
||||||
|
with open("files/lost.json", "r") as fp:
|
||||||
|
fc = json.load(fp)
|
||||||
|
fc["lost"] = fc["lost"] + round(amount)
|
||||||
|
fc["today"] = fc["today"] + round(amount)
|
||||||
|
with open("files/lost.json", "w") as fp:
|
||||||
|
json.dump(fc, fp)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Games(client))
|
|
@ -0,0 +1,170 @@
|
||||||
|
from decorators import help
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def randomWord():
|
||||||
|
lineb = random.randrange(os.stat("files/words-dutch.txt").st_size)
|
||||||
|
with open("files/words-dutch.txt", encoding="latin-1") as file:
|
||||||
|
file.seek(lineb)
|
||||||
|
file.readline()
|
||||||
|
return file.readline().rstrip().upper()
|
||||||
|
|
||||||
|
|
||||||
|
class Hangman(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Hangman", aliases=["Hm"], usage="[Letter]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Games)
|
||||||
|
async def hangman(self, ctx, letter=None):
|
||||||
|
if letter and letter.strip():
|
||||||
|
greek = "αβΓγΔδεζηΘθικΛλμνΞξΠπρΣσςτυΦφχΨψΩω"
|
||||||
|
if len(letter) == 1 and (letter.isalpha() or letter.isdigit()) and letter not in greek:
|
||||||
|
await self.guessLetter(ctx, letter)
|
||||||
|
else:
|
||||||
|
await ctx.send("Dit is geen geldige letter.")
|
||||||
|
return
|
||||||
|
await self.gameStatus(ctx)
|
||||||
|
|
||||||
|
async def guessLetter(self, ctx, letter):
|
||||||
|
with open("files/hangman.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
|
||||||
|
if letter.upper() in file["guessed"]:
|
||||||
|
await ctx.send("Deze letter is al eens geprobeerd.")
|
||||||
|
return
|
||||||
|
|
||||||
|
file["guessed"] += letter.upper()
|
||||||
|
|
||||||
|
if letter.upper() not in file["word"]:
|
||||||
|
file["guesses"] += 1
|
||||||
|
|
||||||
|
if int(file["guesses"] >= 9):
|
||||||
|
await ctx.send(self.endGame(file["word"]))
|
||||||
|
return
|
||||||
|
|
||||||
|
with open("files/hangman.json", "w") as fp:
|
||||||
|
json.dump(file, fp)
|
||||||
|
|
||||||
|
await self.gameStatus(ctx)
|
||||||
|
|
||||||
|
@hangman.command(name="Start", usage="[Woord]*")
|
||||||
|
async def start(self, ctx, *, word=None):
|
||||||
|
with open("files/hangman.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
|
||||||
|
# Can't play two games at once
|
||||||
|
if file["word"]:
|
||||||
|
await ctx.send("Er is al een spel bezig.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if word:
|
||||||
|
if not all(letter.isalpha() or letter.isdigit() or letter in [" "] for letter in word):
|
||||||
|
await ctx.send("Dit is geen geldig woord.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Can only supply your own words in DM
|
||||||
|
if str(ctx.channel.type) != "private":
|
||||||
|
await ctx.message.delete()
|
||||||
|
await ctx.author.send("Het is niet slim om hangman games aan te maken waar iedereen het kan zien."
|
||||||
|
"\nGebruik dit commando hier zodat niemand het woord op voorhand weet.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Choose a random word when none were passed
|
||||||
|
if not word:
|
||||||
|
word = randomWord()
|
||||||
|
|
||||||
|
with open("files/hangman.json", "w") as fp:
|
||||||
|
json.dump({"guessed": [], "guesses": 0, "word": word}, fp)
|
||||||
|
|
||||||
|
await self.gameStatus(ctx)
|
||||||
|
|
||||||
|
async def gameStatus(self, ctx):
|
||||||
|
with open("files/hangman.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
|
||||||
|
if not file["word"]:
|
||||||
|
await ctx.send("Er is geen spel bezig.")
|
||||||
|
return
|
||||||
|
|
||||||
|
guessed = " ".join(letter for letter in file["guessed"] if letter not in file["word"])
|
||||||
|
filled = self.fillWord(file)
|
||||||
|
|
||||||
|
if filled.replace(" ", "") == file["word"]:
|
||||||
|
self.clearGame()
|
||||||
|
await ctx.send("**Het woord is geraden.**")
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
return
|
||||||
|
|
||||||
|
await ctx.send("{}\n{}\nFoute letters: {}".format(filled, self.hangManString(file["guesses"]), guessed))
|
||||||
|
|
||||||
|
@hangman.command(name="Guess", usage="[Woord]")
|
||||||
|
async def guess(self, ctx, *, word=None):
|
||||||
|
if not word:
|
||||||
|
await ctx.send("Geef een woord op.")
|
||||||
|
return
|
||||||
|
|
||||||
|
with open("files/hangman.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
|
||||||
|
if not file["word"]:
|
||||||
|
await ctx.send("Er is geen spel bezig.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if word.upper() == file["word"].upper():
|
||||||
|
self.clearGame()
|
||||||
|
await ctx.send("**Het woord is geraden**")
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
else:
|
||||||
|
file["guesses"] += 1
|
||||||
|
await ctx.send("**{}** is een foute gok.".format(word))
|
||||||
|
await ctx.message.add_reaction("❌")
|
||||||
|
if file["guesses"] >= 9:
|
||||||
|
await ctx.send(self.endGame(file["word"]))
|
||||||
|
else:
|
||||||
|
with open("files/hangman.json", "w") as fp:
|
||||||
|
json.dump(file, fp)
|
||||||
|
await self.gameStatus(ctx)
|
||||||
|
|
||||||
|
# Create a representation of the word by filling in letters that have been guessed, and dots otherwise
|
||||||
|
def fillWord(self, file):
|
||||||
|
return "**" + " ".join(
|
||||||
|
letter if letter in file["guessed"] else "." if letter.isalpha() or letter.isdigit() else letter for letter
|
||||||
|
in file["word"]) + "**"
|
||||||
|
|
||||||
|
def endGame(self, word):
|
||||||
|
self.clearGame()
|
||||||
|
return self.hangManString(9) + "\nHet woord was **{}**.".format(word)
|
||||||
|
|
||||||
|
def clearGame(self):
|
||||||
|
with open("files/hangman.json", "w") as fp:
|
||||||
|
json.dump({"guessed": [], "guesses": 0, "word": ""}, fp)
|
||||||
|
|
||||||
|
def hangManString(self, number):
|
||||||
|
dic = {
|
||||||
|
0: "\n \n \n \n",
|
||||||
|
1: "\n \n \n \n ===",
|
||||||
|
2: "\n |\n |\n |\n ===",
|
||||||
|
3: "--+---+\n |\n |\n |\n ===",
|
||||||
|
4: "--+---+\n | O\n |\n |\n ===",
|
||||||
|
5: "--+---+\n | O\n | |\n |\n ===",
|
||||||
|
6: "--+---+\n | O\n | /|\n |\n ===",
|
||||||
|
7: "--+---+\n | O\n | /|\\\n |\n ===",
|
||||||
|
8: "--+---+\n | O\n | /|\\\n | /\n ===",
|
||||||
|
9: "--+---+\n | O\n | /|\\\n | / \\\n ===",
|
||||||
|
}
|
||||||
|
return dic[number]
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Hangman(client))
|
|
@ -0,0 +1,197 @@
|
||||||
|
from data import constants
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import categories, getCategory, Category
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class HelpCommand(commands.MinimalHelpCommand):
|
||||||
|
def __init__(self, **options):
|
||||||
|
super().__init__(**options)
|
||||||
|
self.ctx = None
|
||||||
|
self.target = None
|
||||||
|
self.is_mod = False
|
||||||
|
|
||||||
|
# Slightly modifying the original callback in order to
|
||||||
|
# allow sending help to DM's & checking for Enums
|
||||||
|
# while removing cog help & checking for mentions
|
||||||
|
async def command_callback(self, ctx, *, command=None):
|
||||||
|
self.ctx = ctx
|
||||||
|
self.is_mod = str(ctx.author.id) == constants.myId
|
||||||
|
bot = ctx.bot
|
||||||
|
if ctx.bot.locked:
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(ctx.message.mentions) > 5:
|
||||||
|
return await ctx.send("Je kan Help maar naar maximaal 5 mensen doorsturen.")
|
||||||
|
|
||||||
|
# Send help categories
|
||||||
|
if command is None:
|
||||||
|
return await self.send_bot_help(self.get_bot_mapping())
|
||||||
|
|
||||||
|
# Check if command is a category
|
||||||
|
if command.lower() == "mod" and not self.is_mod:
|
||||||
|
return await self.send_error_message("Je hebt geen toegang tot deze commando's.")
|
||||||
|
category = getCategory(command, self.is_mod)
|
||||||
|
if category:
|
||||||
|
return await self.send_category_help(category)
|
||||||
|
|
||||||
|
# Cut the mentions out & split based on subcommand
|
||||||
|
spl = command.split(" ")
|
||||||
|
spl = spl[:len(spl) - len(self.ctx.message.mentions)]
|
||||||
|
|
||||||
|
# Turn dic to lowercase to allow proper name searching
|
||||||
|
all_commands = dict((k.lower(), v) for k, v in bot.all_commands.items())
|
||||||
|
|
||||||
|
if spl[0].lower() not in all_commands:
|
||||||
|
return await self.send_error_message(await self.command_not_found(spl[0]))
|
||||||
|
|
||||||
|
cmd = all_commands[spl[0].lower()]
|
||||||
|
|
||||||
|
# Check if the entered command path exists
|
||||||
|
for key in spl[1:]:
|
||||||
|
try:
|
||||||
|
all_commands = dict((k.lower(), v) for k, v in cmd.all_commands.items())
|
||||||
|
if key.lower() not in all_commands:
|
||||||
|
raise AttributeError
|
||||||
|
found = all_commands[key.lower()]
|
||||||
|
except AttributeError:
|
||||||
|
return await self.send_error_message(await self.subcommand_not_found(cmd, key))
|
||||||
|
cmd = found
|
||||||
|
|
||||||
|
# Subcommands should have the parent command's category
|
||||||
|
temp = cmd
|
||||||
|
while temp.parent is not None:
|
||||||
|
temp = temp.parent
|
||||||
|
|
||||||
|
# Don't allow non-mods to see mod commands
|
||||||
|
try:
|
||||||
|
if temp.callback.category == Category.Mod and not self.is_mod:
|
||||||
|
return await self.send_error_message("Je hebt geen toegang tot dit commando.")
|
||||||
|
except AttributeError:
|
||||||
|
return await self.send_error_message("Dit is geen (openbaar) commando.")
|
||||||
|
|
||||||
|
if isinstance(cmd, commands.Group):
|
||||||
|
return await self.send_group_help(cmd)
|
||||||
|
else:
|
||||||
|
return await self.send_command_help(cmd)
|
||||||
|
|
||||||
|
def get_bot_mapping(self):
|
||||||
|
return categories(self.is_mod)
|
||||||
|
|
||||||
|
# Sends list of commands in a category
|
||||||
|
async def send_category_help(self, category):
|
||||||
|
# Get a list of all commands in this category
|
||||||
|
category_commands = [command.name if not command.callback.unpack else command
|
||||||
|
for command in self.ctx.bot.commands
|
||||||
|
if hasattr(command.callback, "category") and command.callback.category == category]
|
||||||
|
|
||||||
|
# Unpack any groups that have to be unpacked
|
||||||
|
for command in list(category_commands):
|
||||||
|
if not isinstance(command, str):
|
||||||
|
category_commands.remove(command)
|
||||||
|
category_commands.extend([self.get_name(c) for c in self.unpack_group(command)])
|
||||||
|
|
||||||
|
embed = self.create_help_embed(category.value)
|
||||||
|
embed.add_field(name="Commands", value="\n".join(sorted(category_commands)))
|
||||||
|
for person in await self.get_destination():
|
||||||
|
await person.send(embed=embed)
|
||||||
|
|
||||||
|
async def send_bot_help(self, mapping):
|
||||||
|
embed = self.create_help_embed("Help")
|
||||||
|
embed.add_field(name="Categorieën", value="\n".join(sorted(mapping)))
|
||||||
|
await self.ctx.send(embed=embed)
|
||||||
|
|
||||||
|
async def send_command_help(self, command):
|
||||||
|
with open("files/help.json", "r") as fp:
|
||||||
|
helpFile = json.load(fp)
|
||||||
|
|
||||||
|
try:
|
||||||
|
helpDescription = helpFile[self.get_name(command).lower()]
|
||||||
|
except KeyError:
|
||||||
|
helpDescription = "Indien je dit leest is DJ STIJN vergeten om dit commando in de help page te zetten. Stuur hem een DM om hem eraan te herinneren."
|
||||||
|
|
||||||
|
embed = self.create_help_embed("Help")
|
||||||
|
embed.add_field(name=await self.get_command_signature(command),
|
||||||
|
value=await self.add_aliases_formatting(sorted(command.aliases)) + helpDescription)
|
||||||
|
for person in await self.get_destination():
|
||||||
|
await person.send(embed=embed)
|
||||||
|
|
||||||
|
async def send_group_help(self, group):
|
||||||
|
with open("files/help.json", "r") as fp:
|
||||||
|
helpFile = json.load(fp)
|
||||||
|
|
||||||
|
embed = self.create_help_embed(group.name + " Commando's")
|
||||||
|
|
||||||
|
try:
|
||||||
|
helpDescription = helpFile[self.get_name(group).lower()]
|
||||||
|
except KeyError:
|
||||||
|
helpDescription = "Indien je dit leest is DJ STIJN vergeten om dit commando in de help page te zetten. Stuur hem een DM om hem eraan te herinneren."
|
||||||
|
|
||||||
|
embed.add_field(name=await self.get_command_signature(group),
|
||||||
|
value=await self.add_aliases_formatting(sorted(group.aliases)) + helpDescription,
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
# Signature: Aliases - Usage
|
||||||
|
for subcommand in self.unpack_group(group):
|
||||||
|
embed.add_field(name=await self.get_command_signature(subcommand),
|
||||||
|
value=await self.add_aliases_formatting(sorted(subcommand.aliases)) +
|
||||||
|
helpFile[self.get_name(subcommand).lower()], inline=False)
|
||||||
|
|
||||||
|
for person in await self.get_destination():
|
||||||
|
await person.send(embed=embed)
|
||||||
|
|
||||||
|
# Allow mentioning people to send it to them instead
|
||||||
|
async def get_destination(self):
|
||||||
|
if self.ctx.message.mentions:
|
||||||
|
return set(mention for mention in self.ctx.message.mentions if not mention.bot)
|
||||||
|
return [self.ctx.author]
|
||||||
|
|
||||||
|
async def command_not_found(self, string):
|
||||||
|
return "Er bestaat geen commando met de naam **{}**".format(string)
|
||||||
|
|
||||||
|
async def subcommand_not_found(self, command, string):
|
||||||
|
return "**{}** heeft geen subcommando met de naam **{}**.".format(command.name, string)
|
||||||
|
|
||||||
|
async def get_command_signature(self, command):
|
||||||
|
return "{} {}".format(self.get_name(command), command.usage if command.usage is not None else "")
|
||||||
|
|
||||||
|
async def add_aliases_formatting(self, aliases):
|
||||||
|
return "*Alias: {}*\n".format(", ".join(aliases)) if aliases else ""
|
||||||
|
|
||||||
|
async def send_error_message(self, error):
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Help")
|
||||||
|
embed.add_field(name="Error", value=error)
|
||||||
|
await self.ctx.author.send(embed=embed)
|
||||||
|
|
||||||
|
def unpack_group(self, group):
|
||||||
|
# Create a list of all command objects in this group, in case they aren't hidden, sorted by name
|
||||||
|
subcommands = [group.all_commands.get(command) for command in group.all_commands]
|
||||||
|
subcommands.sort(key=lambda x: x.name)
|
||||||
|
subcommands = filter(lambda x: not x.hidden, subcommands)
|
||||||
|
return list(set(subcommands))
|
||||||
|
|
||||||
|
def get_name(self, command):
|
||||||
|
return command.qualified_name if command.parents else command.name
|
||||||
|
|
||||||
|
def create_help_embed(self, title):
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name=title)
|
||||||
|
embed.set_footer(text="Syntax: Didier Help [Categorie] of Didier Help [Commando]")
|
||||||
|
return embed
|
||||||
|
|
||||||
|
|
||||||
|
class Help(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self._original_help_command = client.help_command
|
||||||
|
client.help_command = HelpCommand(command_attrs={"aliases": ["rtfm"]})
|
||||||
|
client.help_command.cog = self
|
||||||
|
|
||||||
|
def cog_unload(self):
|
||||||
|
self.client.help_command = self._original_help_command
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Help(client))
|
|
@ -0,0 +1,54 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import pytz
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Launch(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Launch", aliases=["SpaceX"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def launch(self, ctx, *args):
|
||||||
|
resp = self.getNextLaunch()
|
||||||
|
resp: dict = resp[list(resp.keys())[0]]
|
||||||
|
embed = discord.Embed(
|
||||||
|
colour=discord.Colour.blue()
|
||||||
|
)
|
||||||
|
embed.set_author(name="🚀 Volgende SpaceX lancering 🚀")
|
||||||
|
embed.add_field(name="Naam:", value=resp["name"], inline=False)
|
||||||
|
embed.add_field(name="Tijdstip:", value=resp["time"])
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
def getNextLaunch(self):
|
||||||
|
resp = requests.get("https://launchlibrary.net/1.3/launch?next=1&name=falcon").json()
|
||||||
|
if "status" in resp and (resp["status"] == "fail" or resp["status"] == "error"):
|
||||||
|
return {"error": "fail" if resp["status"].lower() == "fail" else "none found"}
|
||||||
|
resp = resp["launches"]
|
||||||
|
ret = {}
|
||||||
|
for launch in resp:
|
||||||
|
ret[launch["id"]] = {
|
||||||
|
"name": launch["name"],
|
||||||
|
"time": self.parseDate(launch["net"][:-4]) if launch["tbdtime"] == 0 else "TBA",
|
||||||
|
"TBA": launch["tbdtime"] == "0"
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def parseDate(self, timestr):
|
||||||
|
d = datetime.strptime(timestr, "%B %d, %Y %H:%M:%S").timestamp()
|
||||||
|
return str(
|
||||||
|
datetime.fromtimestamp(int(d) + 7200, pytz.timezone("Europe/Brussels")).strftime('%B %d %Y om %H:%M:%S'))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Launch(client))
|
|
@ -0,0 +1,204 @@
|
||||||
|
from data import paginatedLeaderboard
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from enums.numbers import Numbers
|
||||||
|
from functions import checks, xp
|
||||||
|
from functions.database import currency, stats, poke, muttn
|
||||||
|
import math
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# TODO some sort of general leaderboard because all of them are the same
|
||||||
|
class Leaderboards(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Leaderboard", aliases=["Lb", "Leaderboards"], case_insensitive=True, usage="[Categorie]*",
|
||||||
|
invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def leaderboard(self, ctx):
|
||||||
|
categories = ["Bitcoin", "Corona", "Dinks", "Messages", "Poke", "Rob", "XP"]
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Leaderboard Categorieën")
|
||||||
|
embed.description = "\n".join(categories)
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
|
||||||
|
@leaderboard.command(name="Dinks", aliases=["Cash"], hidden=True)
|
||||||
|
async def dinks(self, ctx):
|
||||||
|
entries = currency.getAllRows()
|
||||||
|
platDinks = currency.getAllPlatDinks()
|
||||||
|
|
||||||
|
# Take platinum dinks into account
|
||||||
|
for i, user in enumerate(entries):
|
||||||
|
if str(user[0]) in platDinks:
|
||||||
|
# Tuples don't support assignment, cast to list
|
||||||
|
user = list(user)
|
||||||
|
user[1] += platDinks[str(user[0])] * Numbers.q.value
|
||||||
|
entries[i] = user
|
||||||
|
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(entries, key=lambda x: (float(x[1]) + float(x[3])), reverse=True)):
|
||||||
|
if i == 0 and float(user[1]) + float(user[3]) == 0.0:
|
||||||
|
return await self.emptyLeaderboard(ctx, "Dinks Leaderboard", "Er zijn nog geen personen met Didier Dinks.")
|
||||||
|
elif float(user[1]) + float(user[3]) > 0.0:
|
||||||
|
|
||||||
|
# Get the username in this guild
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} ({:,})**".format(name, math.floor(float(user[1]) + float(user[3]))))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} ({:,})".format(name, math.floor(float(user[1]) + float(user[3]))))
|
||||||
|
|
||||||
|
await self.startPaginated(ctx, boardTop, "Dinks Leaderboard")
|
||||||
|
|
||||||
|
@leaderboard.command(name="Corona", hidden=True)
|
||||||
|
async def corona(self, ctx):
|
||||||
|
result = requests.get("http://corona.lmao.ninja/v2/countries").json()
|
||||||
|
result.sort(key=lambda x: int(x["cases"]), reverse=True)
|
||||||
|
board = []
|
||||||
|
for land in result:
|
||||||
|
|
||||||
|
if land["country"] == "Belgium":
|
||||||
|
board.append("**{} ({:,})**".format(land["country"], land["cases"]))
|
||||||
|
else:
|
||||||
|
board.append("{} ({:,})".format(land["country"], land["cases"]))
|
||||||
|
|
||||||
|
await self.startPaginated(ctx, board, "Corona Leaderboard", discord.Colour.red())
|
||||||
|
|
||||||
|
@leaderboard.command(name="Bitcoin", aliases=["Bc"], hidden=True)
|
||||||
|
async def bitcoin(self, ctx):
|
||||||
|
users = currency.getAllRows()
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(users, key=lambda x: x[8], reverse=True)):
|
||||||
|
# Don't create an empty leaderboard
|
||||||
|
if i == 0 and float(user[8]) == 0.0:
|
||||||
|
return await self.emptyLeaderboard(ctx, "Bitcoin Leaderboard", "Er zijn nog geen personen met Bitcoins.")
|
||||||
|
elif float(user[8]) > 0.0:
|
||||||
|
# Only add people with more than 0
|
||||||
|
# Get the username in this guild
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} ({:,})**".format(name, round(user[8], 8)))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} ({:,})".format(name, round(user[8], 8)))
|
||||||
|
|
||||||
|
await self.startPaginated(ctx, boardTop, "Bitcoin Leaderboard")
|
||||||
|
|
||||||
|
@leaderboard.command(name="Rob", hidden=True)
|
||||||
|
async def rob(self, ctx):
|
||||||
|
users = list(stats.getAllRows())
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(users, key=lambda x: x[4], reverse=True)):
|
||||||
|
# Don't create an empty leaderboard
|
||||||
|
if i == 0 and float(user[4]) == 0.0:
|
||||||
|
return await self.emptyLeaderboard(ctx, "Rob Leaderboard", "Er heeft nog niemand Didier Dinks gestolen.")
|
||||||
|
elif float(user[4]) > 0.0:
|
||||||
|
# Only add people with more than 0
|
||||||
|
# Get the username in this guild
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} ({:,})**".format(name, math.floor(float(user[4]))))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} ({:,})".format(name, math.floor(float(user[4]))))
|
||||||
|
await self.startPaginated(ctx, boardTop, "Rob Leaderboard")
|
||||||
|
|
||||||
|
@leaderboard.command(name="Poke", hidden=True)
|
||||||
|
async def poke(self, ctx):
|
||||||
|
s = stats.getAllRows()
|
||||||
|
blacklist = poke.getAllBlacklistedUsers()
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(s, key=lambda x: x[1], reverse=True)):
|
||||||
|
if i == 0 and int(user[1]) == 0:
|
||||||
|
return await self.emptyLeaderboard(ctx, "Poke Leaderboard", "Er is nog niemand getikt.")
|
||||||
|
|
||||||
|
elif int(user[1]) == 0:
|
||||||
|
break
|
||||||
|
# Don't include blacklisted users
|
||||||
|
elif str(user[0]) not in blacklist:
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} ({:,})**".format(name, round(int(user[1]))))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} ({:,})".format(name, round(int(user[1]))))
|
||||||
|
await self.startPaginated(ctx, boardTop, "Poke Leaderboard")
|
||||||
|
|
||||||
|
@leaderboard.command(name="Xp", aliases=["Level"], hidden=True)
|
||||||
|
async def xp(self, ctx):
|
||||||
|
s = stats.getAllRows()
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(s, key=lambda x: x[12], reverse=True)):
|
||||||
|
if int(user[12]) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} (Level {:,} | {:,} XP)**".format(name,
|
||||||
|
xp.calculate_level(round(int(user[12]))),
|
||||||
|
round(int(user[12]))))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} (Level {:,} | {:,} XP)".format(name,
|
||||||
|
xp.calculate_level(round(int(user[12]))),
|
||||||
|
round(int(user[12]))))
|
||||||
|
await self.startPaginated(ctx, boardTop, "XP Leaderboard")
|
||||||
|
|
||||||
|
@leaderboard.command(name="Messages", aliases=["Mc", "Mess"], hidden=True)
|
||||||
|
async def messages(self, ctx):
|
||||||
|
s = stats.getAllRows()
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(s, key=lambda x: x[11], reverse=True)):
|
||||||
|
if int(user[11]) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} ({:,})**".format(name, round(int(user[11]))))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} ({:,})".format(name, round(int(user[11]))))
|
||||||
|
await self.startPaginated(ctx, boardTop, "Messages Leaderboard")
|
||||||
|
|
||||||
|
@leaderboard.command(name="Muttn", aliases=["M", "Mutn", "Mutten"], hidden=True)
|
||||||
|
async def muttn(self, ctx):
|
||||||
|
users = muttn.getAllRows()
|
||||||
|
boardTop = []
|
||||||
|
for i, user in enumerate(sorted(users, key=lambda x: x[1], reverse=True)):
|
||||||
|
if i == 0 and int(user[1]) == 0:
|
||||||
|
return await self.emptyLeaderboard(ctx, "Muttn Leaderboard", "Der zittn nog geen muttns in de server.")
|
||||||
|
|
||||||
|
if float(user[1]) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
name = self.utilsCog.getDisplayName(ctx, user[0])
|
||||||
|
if int(user[0]) == int(ctx.author.id):
|
||||||
|
boardTop.append("**{} ({})%**".format(name, round(float(user[1]), 2)))
|
||||||
|
else:
|
||||||
|
boardTop.append("{} ({}%)".format(name, round(float(user[1]), 2)))
|
||||||
|
await self.startPaginated(ctx, boardTop, "Muttn Leaderboard")
|
||||||
|
|
||||||
|
async def callLeaderboard(self, name, ctx):
|
||||||
|
await [command for command in self.leaderboard.commands if command.name.lower() == name.lower()][0](ctx)
|
||||||
|
|
||||||
|
async def startPaginated(self, ctx, source, name, colour=discord.Colour.blue()):
|
||||||
|
pages = paginatedLeaderboard.Pages(source=paginatedLeaderboard.Source(source, name, colour),
|
||||||
|
clear_reactions_after=True)
|
||||||
|
await pages.start(ctx)
|
||||||
|
|
||||||
|
async def emptyLeaderboard(self, ctx, name, message, colour=discord.Colour.blue()):
|
||||||
|
embed = discord.Embed(colour=colour)
|
||||||
|
embed.set_author(name=name)
|
||||||
|
embed.description = message
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Leaderboards(client))
|
|
@ -0,0 +1,156 @@
|
||||||
|
from decorators import help
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import itertools
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class Minesweeper(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Minesweeper", aliases=["Ms"], usage="[Niveau]*")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Games)
|
||||||
|
async def minesweeper(self, ctx, difficulty="m"):
|
||||||
|
if difficulty[0].lower() not in "emh":
|
||||||
|
await ctx.send("Geef een geldige moeilijkheidsgraad op.")
|
||||||
|
return
|
||||||
|
|
||||||
|
await ctx.send(self.createGame(difficulty[0].lower()))
|
||||||
|
|
||||||
|
def createGame(self, difficutly):
|
||||||
|
|
||||||
|
# [X, Y, BombCount]
|
||||||
|
dimensions = {
|
||||||
|
"e": [5, 5, 4],
|
||||||
|
"m": [10, 10, 20],
|
||||||
|
"h": [13, 13, 35]
|
||||||
|
}
|
||||||
|
|
||||||
|
numbers = {
|
||||||
|
0: "||:zero:||",
|
||||||
|
1: "||:one:||",
|
||||||
|
2: "||:two:||",
|
||||||
|
3: "||:three:||",
|
||||||
|
4: "||:four:||",
|
||||||
|
5: "||:five:||",
|
||||||
|
6: "||:six:||",
|
||||||
|
7: "||:seven:||",
|
||||||
|
8: "||:eight:||",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize an empty grid
|
||||||
|
grid = [[" " for _ in range(dimensions[difficutly][0])] for _ in range(dimensions[difficutly][1])]
|
||||||
|
|
||||||
|
# Generate every possible position on the grid
|
||||||
|
positions = set(itertools.product([x for x in range(len(grid))], repeat=2))
|
||||||
|
|
||||||
|
# Place the bombs in the grid randomly
|
||||||
|
for i in range(dimensions[difficutly][2]):
|
||||||
|
bombPosition = random.choice(list(positions))
|
||||||
|
positions.remove(bombPosition)
|
||||||
|
grid[bombPosition[0]][bombPosition[1]] = "||:boom:||"
|
||||||
|
|
||||||
|
# Add in the numbers representing the amount of bombs nearby
|
||||||
|
for i, row in enumerate(grid):
|
||||||
|
for j, cell in enumerate(row):
|
||||||
|
if cell == " ":
|
||||||
|
grid[i][j] = numbers[self.countBombs(grid, [i, j])]
|
||||||
|
|
||||||
|
# Reveal the biggest empty space to the player
|
||||||
|
self.revealSpaces(grid, self.findBiggestEmptySpace(grid))
|
||||||
|
|
||||||
|
# Join the grid into a string
|
||||||
|
li = [" ".join(row) for row in grid]
|
||||||
|
return "\n".join(li)
|
||||||
|
|
||||||
|
# Counts the amount of bombs near a given cell
|
||||||
|
def countBombs(self, grid, cell):
|
||||||
|
positions = [
|
||||||
|
[1, -1], [1, 0], [1, 1],
|
||||||
|
[0, -1], [0, 1],
|
||||||
|
[-1, -1], [-1, 0], [-1, 1]
|
||||||
|
]
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for position in positions:
|
||||||
|
if 0 <= cell[0] + position[0] < len(grid) and 0 <= cell[1] + position[1] < len(grid[0]):
|
||||||
|
if "boom" in grid[cell[0] + position[0]][cell[1] + position[1]]:
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
# Finds the biggest spot of 0's on the grid to reveal at the start
|
||||||
|
def findBiggestEmptySpace(self, grid):
|
||||||
|
spaces = []
|
||||||
|
biggest = []
|
||||||
|
|
||||||
|
# Floodfill
|
||||||
|
for i, row in enumerate(grid):
|
||||||
|
for j, cell in enumerate(row):
|
||||||
|
# Only check cells that aren't part of a space yet
|
||||||
|
if not any(cell in space for space in spaces) and "zero" in cell:
|
||||||
|
li = [[i, j]]
|
||||||
|
changed = True
|
||||||
|
while changed:
|
||||||
|
changed = False
|
||||||
|
for added in li:
|
||||||
|
neighb = self.neighbours(grid, added)
|
||||||
|
# Add all neighbours that have not yet been added to this space
|
||||||
|
for neighbour in neighb:
|
||||||
|
if neighbour not in li:
|
||||||
|
li.append(neighbour)
|
||||||
|
changed = True
|
||||||
|
spaces.append(li)
|
||||||
|
|
||||||
|
# If it's bigger than the current biggest, make it the new biggest
|
||||||
|
if len(li) > len(biggest):
|
||||||
|
biggest = li
|
||||||
|
return biggest
|
||||||
|
|
||||||
|
# Returns all neighbouring cells containing a 0
|
||||||
|
def neighbours(self, grid, cell):
|
||||||
|
positions = [
|
||||||
|
[1, 0],
|
||||||
|
[0, -1], [0, 1],
|
||||||
|
[-1, 0]
|
||||||
|
]
|
||||||
|
|
||||||
|
neighb = []
|
||||||
|
|
||||||
|
for position in positions:
|
||||||
|
if 0 <= cell[0] + position[0] < len(grid) and 0 <= cell[1] + position[1] < len(grid[0]):
|
||||||
|
if "zero" in grid[cell[0] + position[0]][cell[1] + position[1]]:
|
||||||
|
neighb.append([cell[0] + position[0], cell[1] + position[1]])
|
||||||
|
return neighb
|
||||||
|
|
||||||
|
# Take away the spoiler marks from the biggest empty space to help the player start
|
||||||
|
def revealSpaces(self, grid, emptySpaces):
|
||||||
|
positions = [
|
||||||
|
[1, -1], [1, 0], [1, 1],
|
||||||
|
[0, -1], [0, 1],
|
||||||
|
[-1, -1], [-1, 0], [-1, 1]
|
||||||
|
]
|
||||||
|
|
||||||
|
for space in emptySpaces:
|
||||||
|
grid[space[0]][space[1]] = ":zero:"
|
||||||
|
# Reveal all spaces around this one
|
||||||
|
for position in positions:
|
||||||
|
# Check if the space is not zero & is contained inside the grid & the space hasn't been cut before
|
||||||
|
if 0 <= space[0] + position[0] < len(grid) and \
|
||||||
|
0 <= space[1] + position[1] < len(grid[0]) and \
|
||||||
|
"zero" not in grid[space[0] + position[0]][space[1] + position[1]] and \
|
||||||
|
"||" in grid[space[0] + position[0]][space[1] + position[1]]:
|
||||||
|
# Cut the spoiler from this cell
|
||||||
|
grid[space[0] + position[0]][space[1] + position[1]] = grid[space[0] + position[0]][
|
||||||
|
space[1] + position[1]][2:-2]
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Minesweeper(client))
|
|
@ -0,0 +1,160 @@
|
||||||
|
from data import constants
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, config
|
||||||
|
from functions.database import memes, githubs, twitch, dadjoke
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class ModCommands(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog('Utils')
|
||||||
|
|
||||||
|
@commands.command(name="Remove", aliases=["Rm"], hidden=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def remove(self, ctx, message: str):
|
||||||
|
spl = message.split("/")
|
||||||
|
channel = self.client.get_channel(int(spl[-2]))
|
||||||
|
message = await channel.fetch_message(int(spl[-1]))
|
||||||
|
await message.delete()
|
||||||
|
|
||||||
|
# Load a cog
|
||||||
|
@commands.group(name="Load", usage="[Cog]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def load(self, ctx, extension: str):
|
||||||
|
try:
|
||||||
|
self.client.load_extension("cogs.{}".format(extension))
|
||||||
|
await self.sendDm(constants.myId, "Loaded **{}**".format(extension))
|
||||||
|
except discord.ext.commands.errors.ExtensionAlreadyLoaded:
|
||||||
|
await self.sendDm(constants.myId, "**{}** has already been loaded".format(extension))
|
||||||
|
|
||||||
|
@commands.command(name="Config", aliases=["Setup", "Set"], case_insensitive=True, usage="[Categorie] [Value]",
|
||||||
|
invoke_without_commands=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(Category.Mod)
|
||||||
|
async def set(self, ctx, category, value):
|
||||||
|
if config.config(category, value):
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
|
||||||
|
# Load all cogs except for modCommands
|
||||||
|
@load.command(name="All")
|
||||||
|
async def loadAll(self, ctx):
|
||||||
|
for file in os.listdir("./cogs"):
|
||||||
|
if file.endswith(".py") and not file == "modCommands.py":
|
||||||
|
await self.load(ctx, file[:-3])
|
||||||
|
|
||||||
|
# Unload a cog
|
||||||
|
@commands.group(name="Unload", usage="[Cog]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def unload(self, ctx, extension: str):
|
||||||
|
try:
|
||||||
|
self.client.unload_extension("cogs.{}".format(extension))
|
||||||
|
await self.sendDm(constants.myId, "Unloaded **{}**".format(extension))
|
||||||
|
except discord.ext.commands.errors.ExtensionNotLoaded:
|
||||||
|
await self.sendDm(constants.myId, "**{}** has already been unloaded".format(extension))
|
||||||
|
|
||||||
|
# Unload all cogs except for modCommands
|
||||||
|
@unload.command(name="All")
|
||||||
|
async def unloadAll(self, ctx):
|
||||||
|
for file in os.listdir("./cogs"):
|
||||||
|
if file.endswith(".py") and not file == "modCommands.py":
|
||||||
|
await self.unload(ctx, file[:-3])
|
||||||
|
|
||||||
|
# Reloads a cog
|
||||||
|
@commands.command(name="Reload", aliases=["Update"], usage="[Cog]")
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def reload(self, ctx, cog):
|
||||||
|
await self.unload(ctx, cog)
|
||||||
|
await self.load(ctx, cog)
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
|
||||||
|
# Repeat what was said
|
||||||
|
@commands.command(name="Repeat", usage="[Text]")
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def repeat(self, ctx, *text):
|
||||||
|
await self.utilsCog.removeMessage(ctx.message)
|
||||||
|
await ctx.send(" ".join(text))
|
||||||
|
|
||||||
|
# Add a reaction to a message
|
||||||
|
@commands.command(name="Reac", aliases=["Reacc"], usage="[Emoji] [Id]")
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def reac(self, ctx, emoji, messageId):
|
||||||
|
channel = ctx.channel
|
||||||
|
|
||||||
|
# Check if the URL or the Id was passed
|
||||||
|
if messageId.count("/") > 3:
|
||||||
|
spl = messageId.split("/")
|
||||||
|
channel = self.client.get_channel(int(spl[-2]))
|
||||||
|
if channel is None:
|
||||||
|
return await ctx.send("Ik kan geen kanaal zien met dit Id.")
|
||||||
|
messageId = int(spl[-1])
|
||||||
|
|
||||||
|
await self.utilsCog.removeMessage(ctx.message)
|
||||||
|
message = await channel.fetch_message(messageId)
|
||||||
|
if message is None:
|
||||||
|
return await ctx.send("Ik kan geen bericht zien met dit Id.")
|
||||||
|
await message.add_reaction(emoji)
|
||||||
|
|
||||||
|
# Adds stuff into their databases
|
||||||
|
@commands.group(name="Add", usage="[Category] [Args]", case_insensitive=True, invoke_without_command=False)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
@help.Category(category=Category.Mod)
|
||||||
|
async def add(self, ctx):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@add.command(name="Dadjoke", aliases=["Dj", "Dad"], usage="[Joke]")
|
||||||
|
async def dadjoke(self, ctx, *, joke):
|
||||||
|
dadjoke.addJoke(joke)
|
||||||
|
await ctx.send("Added ``{}``.".format(joke))
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
|
||||||
|
@add.command(name="8-Ball", aliases=["8b", "Eightball", "8Ball"], usage="[Response]")
|
||||||
|
async def eightball(self, ctx, message):
|
||||||
|
with open("files/eightball.json", "r") as fp:
|
||||||
|
file = json.load(fp)
|
||||||
|
file.append(message)
|
||||||
|
with open("files/eightball.json", "w") as fp:
|
||||||
|
json.dump(file, fp)
|
||||||
|
|
||||||
|
# Adds a meme into the database
|
||||||
|
@add.command(name="Meme", aliases=["Mem"], usage="[Id] [Name] [Aantal Velden]")
|
||||||
|
async def meme(self, ctx, memeid, meme, fields):
|
||||||
|
await ctx.send(memes.insert(memeid, meme, fields)[1])
|
||||||
|
|
||||||
|
# Adds a person's GitHub into the database
|
||||||
|
@add.command(name="GitHub", aliases=["Gh", "Git"], usage="[Id] [Link]")
|
||||||
|
async def github(self, ctx, userid, link):
|
||||||
|
# Allow tagging to work as well
|
||||||
|
if len(ctx.message.mentions) == 1:
|
||||||
|
userid = ctx.message.mentions[0].id
|
||||||
|
githubs.add(userid, link)
|
||||||
|
await ctx.send("{}'s GitHub is toegevoegd aan de database.".format(self.utilsCog.getDisplayName(ctx, userid)))
|
||||||
|
|
||||||
|
# Adds a person's Twitch into the database
|
||||||
|
@add.command(name="Twitch", aliases=["Stream", "Streamer", "Tw"])
|
||||||
|
async def twitch(self, ctx, userid, link):
|
||||||
|
# Allow tagging to work as well
|
||||||
|
if len(ctx.message.mentions) == 1:
|
||||||
|
userid = ctx.message.mentions[0].id
|
||||||
|
twitch.add(userid, link)
|
||||||
|
await ctx.send("{}'s Twitch is toegevoegd aan de database.".format(self.utilsCog.getDisplayName(ctx, userid)))
|
||||||
|
|
||||||
|
# Send a DM to a user -- Can't re-use Utils cog in (un)load because the cog might not be loaded
|
||||||
|
async def sendDm(self, userid, message: str):
|
||||||
|
user = self.client.get_user(int(userid))
|
||||||
|
await user.send(message)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(ModCommands(client))
|
|
@ -0,0 +1,37 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from decorators import help
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions.database import muttn
|
||||||
|
|
||||||
|
|
||||||
|
class Muttn(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Muttn", aliases=["HowMuttn", "M", "Mutn", "Mutten"], usage="[@Persoon]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@help.Category(Category.Fun)
|
||||||
|
async def muttn(self, ctx, member: discord.Member = None):
|
||||||
|
if member is None:
|
||||||
|
member = ctx.author
|
||||||
|
|
||||||
|
user = muttn.getOrAddUser(member.id)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue(), title=member.display_name)
|
||||||
|
embed.set_author(name="Muttn-O'-Meter")
|
||||||
|
embed.add_field(name="Percentage", value="{}%".format(round(float(user[1]), 2)))
|
||||||
|
|
||||||
|
embed.add_field(name="Aantal {}'s".format("<:Muttn:761551956346798111>"), value=str(user[2]))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@muttn.command(name="Leaderboard", aliases=["Lb"], hidden=True)
|
||||||
|
async def lb(self, ctx):
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("muttn", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Muttn(client))
|
|
@ -0,0 +1,153 @@
|
||||||
|
from data import constants
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, clap, mock, sunrise, timeFormatters
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
|
||||||
|
# Random things that are usually oneliners & don't belong in any other categories
|
||||||
|
class Oneliners(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog('Utils')
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Age", usage="[Formaat]*")
|
||||||
|
@help.Category(category=Category.Didier)
|
||||||
|
async def age(self, ctx, specification=None):
|
||||||
|
allowedSpecifications = ["d", "days", "m", "months", "w", "weeks", "y", "years"]
|
||||||
|
|
||||||
|
if specification is not None and specification.lower() not in allowedSpecifications:
|
||||||
|
await ctx.send("**{}** is geen geldig formaat.".format(specification))
|
||||||
|
return
|
||||||
|
|
||||||
|
if specification is None:
|
||||||
|
timeString = timeFormatters.diffYearBasisString(constants.creationDate)
|
||||||
|
else:
|
||||||
|
ageSeconds = round(time.time()) - constants.creationDate
|
||||||
|
timeFormat = timeFormatters.getFormat(specification)
|
||||||
|
timeString = str(timeFormatters.timeIn(ageSeconds, timeFormat)[0])
|
||||||
|
timeString += " " + timeFormatters.getPlural(int(timeString), timeFormat)
|
||||||
|
await ctx.send("Didier is **{}** oud.".format(timeString))
|
||||||
|
|
||||||
|
@commands.command(name="Clap", usage="[Tekst]")
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def clap(self, ctx, *args):
|
||||||
|
await ctx.send(clap.clap("".join(args)))
|
||||||
|
await self.utilsCog.removeMessage(ctx.message)
|
||||||
|
|
||||||
|
@commands.command(name="Reverse", aliases=["Rev"], usage="[Tekst]")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def reverse(self, ctx, *args):
|
||||||
|
await ctx.send(" ".join(args)[::-1])
|
||||||
|
|
||||||
|
@commands.command(name="Government", aliases=["Gov", "Regering"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def government(self, ctx):
|
||||||
|
now = timeFormatters.dateTimeNow()
|
||||||
|
newGov = datetime.datetime.fromtimestamp(1601539200, tz=pytz.timezone("Europe/Brussels"))
|
||||||
|
delta = now - newGov
|
||||||
|
zin = "Na **494** dagen is er weer een regering, **47** dagen te vroeg om het record te breken. Very sad times.\nMAAR hoelang denk je dat de nieuwe regering het gaat volhouden? Place your bets! Momenteel zitten we aan **{}** dag{}.".format(
|
||||||
|
delta.days, "en" if delta.days != 1 else ""
|
||||||
|
)
|
||||||
|
# now = int(time.time())
|
||||||
|
# valVorige = 1545350400
|
||||||
|
# verkiezingen = 1558828800
|
||||||
|
# valDiff = now - valVorige
|
||||||
|
# verkiezingenDiff = now - verkiezingen
|
||||||
|
# zin = (
|
||||||
|
# "We zitten al **%d** dagen zonder regering, en proberen al **%d** dagen een nieuwe te vormen.\nHet "
|
||||||
|
# "huidige wereldrecord is "
|
||||||
|
# "**541** dagen, dus nog **%d** dagen tot we het gebroken hebben." %
|
||||||
|
# (valDiff // 86400, verkiezingenDiff // 86400, 541 - int(verkiezingenDiff // 86400)))
|
||||||
|
await ctx.send(zin)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def inject(self, ctx):
|
||||||
|
await ctx.send("**{}** heeft wat code geïnjecteerd.".format(ctx.author.display_name))
|
||||||
|
|
||||||
|
@commands.command(name="Mock", usage="[Tekst]")
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def mock(self, ctx, *text):
|
||||||
|
await ctx.channel.send("{} - **{}**".format(mock.mock(" ".join(text)), ctx.author.display_name))
|
||||||
|
await self.utilsCog.removeMessage(ctx.message)
|
||||||
|
|
||||||
|
@commands.command(name="Molest", usage="[@Persoon]")
|
||||||
|
async def molest(self, ctx):
|
||||||
|
if constants.didierId in ctx.message.content:
|
||||||
|
await ctx.send("Nee.")
|
||||||
|
elif str(ctx.author.id) in ctx.message.content or ctx.message.content == "molest me":
|
||||||
|
await ctx.send("I didn't know you swing that way, " + ctx.author.display_name)
|
||||||
|
elif "171671190631481345" in ctx.message.content:
|
||||||
|
await ctx.send("Nee")
|
||||||
|
else:
|
||||||
|
await ctx.send("https://imgur.com/a/bwA6Exn")
|
||||||
|
|
||||||
|
@commands.command(name="Changelog", aliases=["Cl", "Change", "Changes"])
|
||||||
|
@help.Category(category=Category.Didier)
|
||||||
|
async def changelog(self, ctx, *args):
|
||||||
|
await ctx.send("V2.0: <https://docs.google.com/document/d/1oa-9oc9yFnZ0X5sLJTWfdahtaL0vF8acLl-xMXA3a40/edit#>\n"
|
||||||
|
"V2.1: https://docs.google.com/document/d/1ezdJBTnKWoog4q9yJrgwfF4iGOn-PZMoBZgSNVYPtqg/edit#")
|
||||||
|
|
||||||
|
@commands.command(name="Todo", aliases=["List", "Td"])
|
||||||
|
@help.Category(category=Category.Didier)
|
||||||
|
async def todo(self, ctx, *args):
|
||||||
|
await ctx.send("https://trello.com/b/PdtsAJea/didier-to-do-list")
|
||||||
|
|
||||||
|
@commands.command(name="LMGTFY", aliases=["Dsfr", "Gtfm", "Google"], usage="[Query]")
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def lmgtfy(self, ctx, *, query=None):
|
||||||
|
if query:
|
||||||
|
await ctx.send("https://lmgtfy.com/?q={}&iie=1".format(urllib.parse.quote(query)))
|
||||||
|
|
||||||
|
@commands.command(name="Neck", aliases=["Necc"], usage="[Lengte]*")
|
||||||
|
@help.Category(category=Category.Fun)
|
||||||
|
async def neck(self, ctx, size=None):
|
||||||
|
if not size:
|
||||||
|
size = 1
|
||||||
|
try:
|
||||||
|
size = int(size)
|
||||||
|
if not 0 < size < 16:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError:
|
||||||
|
return await ctx.send("Geef een geldig getal op.")
|
||||||
|
|
||||||
|
await ctx.send("<:WhatDidYou:744476950654877756>" + ("<:DoTo:744476965951504414>" * size) + "<:MyDrink:744476979939508275>")
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def open(self, ctx):
|
||||||
|
# await ctx.send(file=discord.File("files/images/open_source_bad.jpg"))
|
||||||
|
await ctx.send("Soon:tm:")
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def sc(self, ctx, *args):
|
||||||
|
await ctx.send("http://take-a-screenshot.org/")
|
||||||
|
|
||||||
|
@commands.command(aliases=["src", "os"])
|
||||||
|
async def source(self, ctx):
|
||||||
|
# await ctx.send("<https://bit.ly/31z3BuH>")
|
||||||
|
await ctx.send("Soon:tm:")
|
||||||
|
|
||||||
|
@commands.command(aliases=["sunrise", "sunshine"])
|
||||||
|
async def sun(self, ctx):
|
||||||
|
s = sunrise.Sun()
|
||||||
|
await ctx.send(":sunny:: **{}**\n:crescent_moon:: **{}**".format(s.sunrise(), s.sunset()))
|
||||||
|
|
||||||
|
@commands.command(name="Tias", aliases=["TryIt"])
|
||||||
|
async def tias(self, ctx, *args):
|
||||||
|
await ctx.send("***Try it and see***")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Oneliners(client))
|
|
@ -0,0 +1,113 @@
|
||||||
|
from data import constants
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, timeFormatters
|
||||||
|
from functions.database import poke, stats
|
||||||
|
|
||||||
|
|
||||||
|
class Poke(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Poke", usage="[@Persoon]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Games)
|
||||||
|
async def poke(self, ctx, member=None):
|
||||||
|
if not await self.pokeChecks(ctx):
|
||||||
|
return
|
||||||
|
|
||||||
|
member = ctx.message.mentions[0]
|
||||||
|
await ctx.send("**{}** heeft **{}** getikt. **{}** is hem!".format(
|
||||||
|
ctx.author.display_name, member.display_name, member.display_name))
|
||||||
|
|
||||||
|
# Add into the database
|
||||||
|
poke.update(ctx.author.id, member.id)
|
||||||
|
stats.update(member.id, "poked", int(stats.getOrAddUser(member.id)[1]) + 1)
|
||||||
|
|
||||||
|
@poke.command(name="Blacklist", aliases=["Bl"])
|
||||||
|
async def blacklist(self, ctx):
|
||||||
|
if poke.blacklisted(ctx.author.id):
|
||||||
|
await ctx.send("Je hebt jezelf al geblacklisted, {}.".format(ctx.author.display_name))
|
||||||
|
return
|
||||||
|
if str(poke.get()[0]) == str(ctx.author.id):
|
||||||
|
await ctx.send("Je kan jezelf niet blacklisten als je aan de beurt bent, {}.".format(
|
||||||
|
ctx.author.display_name))
|
||||||
|
return
|
||||||
|
poke.blacklist(ctx.author.id)
|
||||||
|
await ctx.send("**{}** heeft zichzelf geblacklisted en kan niet meer getikt worden.".format(
|
||||||
|
ctx.author.display_name))
|
||||||
|
|
||||||
|
@poke.command(aliases=["wl"], hidden=True)
|
||||||
|
async def whitelist(self, ctx, *user):
|
||||||
|
user = ctx.message.mentions[0].id
|
||||||
|
if not poke.blacklisted(user):
|
||||||
|
await ctx.send("Deze persoon is niet geblacklisted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
poke.blacklist(user, False)
|
||||||
|
await ctx.send("**{}** heeft {} gewhitelisted.".format(
|
||||||
|
ctx.author.display_name, self.utilsCog.getDisplayName(ctx, user)))
|
||||||
|
|
||||||
|
@poke.command(name="Current")
|
||||||
|
async def current(self, ctx):
|
||||||
|
p = poke.get()
|
||||||
|
pokedTimeStamp = datetime.datetime.fromtimestamp(int(p[1]))
|
||||||
|
timeString = timeFormatters.diffDayBasisString(pokedTimeStamp)
|
||||||
|
|
||||||
|
await ctx.send("Het is al **{}** aan **{}**.".format(timeString, self.utilsCog.getDisplayName(ctx, p[0])))
|
||||||
|
|
||||||
|
@poke.command(hidden=True)
|
||||||
|
async def me(self, ctx):
|
||||||
|
await ctx.send("Liever niet.")
|
||||||
|
|
||||||
|
@poke.command(hidden=True)
|
||||||
|
@commands.check(checks.isMe)
|
||||||
|
async def reset(self, ctx):
|
||||||
|
new = poke.reset()
|
||||||
|
await ctx.send("Poke is gereset. <@!{}> is hem!".format(str(new)))
|
||||||
|
|
||||||
|
@poke.command(aliases=["Lb", "Leaderboards"], hidden=True)
|
||||||
|
async def leaderboard(self, ctx):
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("poke", ctx)
|
||||||
|
|
||||||
|
async def pokeChecks(self, ctx):
|
||||||
|
if len(ctx.message.mentions) == 0:
|
||||||
|
await ctx.send("Dit is geen geldige persoon.")
|
||||||
|
return False
|
||||||
|
if len(ctx.message.mentions) > 1:
|
||||||
|
await ctx.send("Je kan maar 1 persoon tegelijk tikken.")
|
||||||
|
return False
|
||||||
|
if ctx.message.mentions[0].id == ctx.author.id:
|
||||||
|
await ctx.send("Je kan jezelf niet tikken, {}.".format(ctx.author.display_name))
|
||||||
|
return False
|
||||||
|
if str(ctx.message.mentions[0].id) == constants.didierId:
|
||||||
|
await ctx.send("Je kan me niet tikken, {}.".format(ctx.author.display_name))
|
||||||
|
return False
|
||||||
|
if str(ctx.message.mentions[0].id) in constants.botIDs:
|
||||||
|
await ctx.send("Je kan geen bots tikken, {}.".format(ctx.author.display_name))
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check database things
|
||||||
|
p = poke.get()
|
||||||
|
if str(p[0]) != str(ctx.author.id):
|
||||||
|
await ctx.send("Het is niet jouw beurt, {}.".format(ctx.author.display_name))
|
||||||
|
return False
|
||||||
|
if str(ctx.message.mentions[0].id) == str(p[2]):
|
||||||
|
await ctx.send("Je mag niet terugtikken, {}.".format(ctx.author.display_name))
|
||||||
|
return False
|
||||||
|
if poke.blacklisted(ctx.message.mentions[0].id):
|
||||||
|
await ctx.send("Deze persoon heeft zichzelf geblacklisted en kan niet meer getikt worden.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Poke(client))
|
|
@ -0,0 +1,44 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import requests
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
|
||||||
|
class QR(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="QR", usage="[Tekst]")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def QR(self, ctx, *link):
|
||||||
|
if len(link) != 1:
|
||||||
|
await ctx.send(file=discord.File("files/images/ngguuqr.png"))
|
||||||
|
await self.client.get_cog("Utils").removeMessage(ctx.message)
|
||||||
|
else:
|
||||||
|
self.generate("".join(link))
|
||||||
|
await ctx.send(file=discord.File("files/images/qrcode.png"))
|
||||||
|
self.remove()
|
||||||
|
await self.client.get_cog("Utils").removeMessage(ctx.message)
|
||||||
|
|
||||||
|
def generate(self, link):
|
||||||
|
fileContent = requests.get(
|
||||||
|
"https://image-charts.com/chart?chs=999x999&cht=qr&chl={}&choe=UTF-8&chof=.png".format(
|
||||||
|
urllib.parse.quote(link))).content
|
||||||
|
with open("files/images/qrcode.png", "wb+") as fp:
|
||||||
|
fp.write(fileContent)
|
||||||
|
|
||||||
|
def remove(self):
|
||||||
|
import os
|
||||||
|
os.remove("files/images/qrcode.png")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(QR(client))
|
|
@ -0,0 +1,139 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import colours
|
||||||
|
import random
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class Random(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
# Creates an alias
|
||||||
|
@commands.command(name="Choice", aliases=["Choose"], usage="[Argumenten]")
|
||||||
|
async def choose(self, ctx, *options):
|
||||||
|
await self.choice(ctx, options)
|
||||||
|
|
||||||
|
@commands.command(name="Shuffle", usage="[Argumenten]")
|
||||||
|
async def _shuffle(self, ctx, *options):
|
||||||
|
await self.shuffle(ctx, options)
|
||||||
|
|
||||||
|
@commands.group(name="Random", aliases=["R", "Rand", "RNG"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@help.Category(category=Category.Random, unpack=True)
|
||||||
|
async def random(self, ctx):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@random.command(name="Choice", usage="[Argumenten]")
|
||||||
|
async def choice(self, ctx, *options):
|
||||||
|
if not options:
|
||||||
|
await ctx.send("Geef een geldige reeks op.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Allows choose alias to pass in it's args too
|
||||||
|
if isinstance(options[0], tuple):
|
||||||
|
options = options[0]
|
||||||
|
|
||||||
|
await ctx.send(random.choice(options))
|
||||||
|
|
||||||
|
@random.command(name="Number", aliases=["Int"], usage="[Van]* [Tot]*")
|
||||||
|
async def number(self, ctx, to=100, start=1):
|
||||||
|
# This allows number(to) to work, as well as number(start, to)
|
||||||
|
if start > to:
|
||||||
|
start, to = to, start
|
||||||
|
|
||||||
|
await ctx.send(random.randint(start, to))
|
||||||
|
|
||||||
|
@number.error
|
||||||
|
async def on_number_error(self, ctx, error):
|
||||||
|
if isinstance(error, discord.ext.commands.BadArgument):
|
||||||
|
await ctx.send("Dit is geen geldig getal.")
|
||||||
|
else:
|
||||||
|
raise error
|
||||||
|
|
||||||
|
@random.command(name="Name")
|
||||||
|
async def name(self, ctx, *args):
|
||||||
|
try:
|
||||||
|
name = requests.get("https://randomuser.me/api/").json()
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
await ctx.send("Er ging iets mis. Probeer het opnieuw.")
|
||||||
|
return
|
||||||
|
|
||||||
|
name = name["results"][0]["name"]
|
||||||
|
await ctx.send("{} {} {}".format(name["title"], name["first"], name["last"]))
|
||||||
|
|
||||||
|
@random.command(name="Identity", aliases=["Id"])
|
||||||
|
async def identity(self, ctx, *args):
|
||||||
|
try:
|
||||||
|
identity = requests.get("https://randomuser.me/api/").json()
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
await ctx.send("Er ging iets mis. Probeer het opnieuw.")
|
||||||
|
return
|
||||||
|
|
||||||
|
identity = identity["results"][0]
|
||||||
|
name = identity["name"]
|
||||||
|
name = "{} {} {}".format(name["title"], name["first"], name["last"])
|
||||||
|
|
||||||
|
gender = identity["gender"]
|
||||||
|
street = "{} {}".format(identity["location"]["street"]["number"], identity["location"]["street"]["name"])
|
||||||
|
location = "{}, {}, {}, {}".format(street, identity["location"]["city"],
|
||||||
|
identity["location"]["state"], identity["location"]["country"])
|
||||||
|
age = identity["dob"]["age"]
|
||||||
|
|
||||||
|
await ctx.send("{}\n{}, {}\n{}".format(name, age, gender, location))
|
||||||
|
|
||||||
|
@random.command(name="Shuffle", aliases=["Order"], usage="[Argumenten]")
|
||||||
|
async def shuffle(self, ctx, *args):
|
||||||
|
if not args:
|
||||||
|
await ctx.send("Geef een geldige reeks op.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Allows shuffle alias to pass in it's args too
|
||||||
|
if isinstance(args[0], tuple):
|
||||||
|
args = args[0]
|
||||||
|
|
||||||
|
args = list(args)
|
||||||
|
|
||||||
|
random.shuffle(args)
|
||||||
|
|
||||||
|
await ctx.send(" - ".join(args))
|
||||||
|
|
||||||
|
@random.command(name="Colour", aliases=["Color"])
|
||||||
|
async def colour(self, ctx, *args):
|
||||||
|
r, g, b = colours.randomRGB()
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.from_rgb(r, g, b))
|
||||||
|
embed.set_author(name="Random Colour")
|
||||||
|
embed.add_field(name="RGB", value="{}, {}, {}".format(r, g, b), inline=False)
|
||||||
|
embed.add_field(name="HEX", value=colours.RGBToHEX(r, g, b), inline=False)
|
||||||
|
embed.add_field(name="HSL", value="{}°, {}%, {}%".format(*colours.RGBToHSL(r, g, b)), inline=False)
|
||||||
|
embed.add_field(name="HSV", value="{}°, {}%, {}%".format(*colours.RGBToHSV(r, g, b)), inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@random.command(name="Timestamp", aliases=["Time", "Ts"])
|
||||||
|
async def timestamp(self, ctx, *args):
|
||||||
|
hour = str(random.randint(0, 23))
|
||||||
|
hour = ("0" if len(hour) == 1 else "") + hour
|
||||||
|
minutes = str(random.randint(0, 23))
|
||||||
|
minutes = ("0" if len(minutes) == 1 else "") + minutes
|
||||||
|
await ctx.send("{}:{}".format(hour, minutes))
|
||||||
|
|
||||||
|
@random.command(name="Fact", aliases=["Knowledge"])
|
||||||
|
async def fact(self, ctx, *args):
|
||||||
|
randomFact = requests.get("https://uselessfacts.jsph.pl/random.json?language=en").json()
|
||||||
|
await ctx.send(randomFact["text"])
|
||||||
|
|
||||||
|
@commands.command(name="Yes/No", aliases=["Yn"])
|
||||||
|
@help.Category(Category.Random)
|
||||||
|
async def yesno(self, ctx, *args):
|
||||||
|
await ctx.send(random.choice(["Ja.", "Nee."]))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Random(client))
|
|
@ -0,0 +1,56 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import reactWord
|
||||||
|
|
||||||
|
|
||||||
|
class ReactWord(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="React", usage="[Tekst] [Message id/url]*")
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def react(self, ctx, *words):
|
||||||
|
words = list(words)
|
||||||
|
target = False
|
||||||
|
channel = ctx.channel
|
||||||
|
|
||||||
|
# Check if the URL or the Id was passed
|
||||||
|
if str(words[-1]).count("/") > 3:
|
||||||
|
spl = str(words[-1]).split("/")
|
||||||
|
channel = self.client.get_channel(int(spl[-2]))
|
||||||
|
if channel is None:
|
||||||
|
return await ctx.send("Ik kan geen kanaal zien met dit id.")
|
||||||
|
words[-1] = spl[-1]
|
||||||
|
|
||||||
|
# Get the message object if an Id was passed, otherwise react to the message itself
|
||||||
|
try:
|
||||||
|
message = await channel.fetch_message(words[-1])
|
||||||
|
if message is None:
|
||||||
|
return await ctx.send("Ik kan geen bericht zien met dit id.")
|
||||||
|
target = True
|
||||||
|
except discord.HTTPException:
|
||||||
|
message = ctx.message
|
||||||
|
|
||||||
|
# Reactions that were added before this command was executed
|
||||||
|
previousReactions = ([x.emoji for x in message.reactions]) if len(message.reactions) != 0 else []
|
||||||
|
eligible, arr = reactWord.check(list(words), previousReactions)
|
||||||
|
|
||||||
|
if not eligible:
|
||||||
|
await ctx.send(arr[0])
|
||||||
|
else:
|
||||||
|
if target:
|
||||||
|
await self.utilsCog.removeMessage(ctx.message)
|
||||||
|
for reac in arr:
|
||||||
|
await message.add_reaction(reac)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(ReactWord(client))
|
|
@ -0,0 +1,138 @@
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
class Release(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
# Gets upcoming game releases
|
||||||
|
@commands.group(name="Releases", usage="[Pagina]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Games)
|
||||||
|
async def releases(self, ctx, page="1"):
|
||||||
|
for char in page:
|
||||||
|
if not char.isdigit():
|
||||||
|
await ctx.send("Geef een geldige pagina op.")
|
||||||
|
return
|
||||||
|
|
||||||
|
dates = self.getDates()
|
||||||
|
resp = requests.get("https://api.rawg.io/api/games?dates={},{}&page_size=25&page={}&ordering=released".format(
|
||||||
|
dates[0], dates[1], page
|
||||||
|
)).json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Volgende Game Releases | Pagina {}".format(page))
|
||||||
|
|
||||||
|
embed.description = "\n".join(
|
||||||
|
["{} (#{}): {}".format(result["name"], result["id"], self.rewriteDate(result["released"]))
|
||||||
|
for result in resp["results"]])
|
||||||
|
embed.set_footer(text="Voor gedetailleerde info: Didier Game Info [id]")
|
||||||
|
except KeyError:
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Game Releases")
|
||||||
|
embed.add_field(name="Error", value="Er ging iets fout.")
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
def getDates(self):
|
||||||
|
today = datetime.datetime.fromtimestamp(time.time())
|
||||||
|
nextMonth = datetime.datetime.fromtimestamp(time.time() + 2629743)
|
||||||
|
return ["-".join([str(today.year), self.leadingZero(str(today.month)), self.leadingZero(str(today.day))]),
|
||||||
|
"-".join([str(nextMonth.year),
|
||||||
|
self.leadingZero(str(nextMonth.month)), self.leadingZero(str(nextMonth.day))])]
|
||||||
|
|
||||||
|
def leadingZero(self, num):
|
||||||
|
return num if len(num) == 2 else "0" + num
|
||||||
|
|
||||||
|
# Shows more detailed information for a game
|
||||||
|
@releases.command(name="Info", aliases=["Details"], usage="[Game Id]")
|
||||||
|
async def info(self, ctx, *, game_id):
|
||||||
|
game_id = self.create_slug(game_id)
|
||||||
|
resp = requests.get("https://api.rawg.io/api/games/{}".format(str(game_id))).json()
|
||||||
|
if "redirect" in resp:
|
||||||
|
resp = requests.get("https://api.rawg.io/api/games/{}".format(resp["slug"])).json()
|
||||||
|
if "Not found." in resp.values():
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Game Info")
|
||||||
|
embed.description = "Er is geen game gevonden met deze id of naam."
|
||||||
|
else:
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Game Info")
|
||||||
|
embed.add_field(name="Naam", value=resp["name"])
|
||||||
|
embed.add_field(name="Id", value=resp["id"])
|
||||||
|
embed.add_field(name="Datum", value="TBA" if resp["tba"] else self.rewriteDate(resp["released"]))
|
||||||
|
embed.add_field(name="Platforms", value=", ".join(self.getPlatforms(resp)))
|
||||||
|
embed.add_field(name="Stores", value=", ".join(self.getStores(resp)))
|
||||||
|
embed.add_field(name="Genres", value=", ".join(self.getGenres(resp)))
|
||||||
|
embed.add_field(name="Tags", value=self.getTags(resp), inline=False)
|
||||||
|
embed.add_field(name="Description", value=self.writeDescription(resp["description_raw"]), inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
# Turns name into a slug
|
||||||
|
def create_slug(self, game_id):
|
||||||
|
try:
|
||||||
|
# Check if it's a number
|
||||||
|
game_id = int(game_id)
|
||||||
|
return str(game_id)
|
||||||
|
except ValueError:
|
||||||
|
game_id = game_id.lower().replace(" ", "-").replace(":", "").replace("'", "")
|
||||||
|
return game_id
|
||||||
|
|
||||||
|
def rewriteDate(self, date):
|
||||||
|
date = date.split("-")
|
||||||
|
return "-".join(reversed(date))
|
||||||
|
|
||||||
|
def getGenres(self, release):
|
||||||
|
return sorted([genre["name"] for genre in release["genres"]])
|
||||||
|
|
||||||
|
# Returns a list of all platforms this game is available on
|
||||||
|
def getPlatforms(self, release):
|
||||||
|
return sorted([platform["platform"]["name"] for platform in release["platforms"]])
|
||||||
|
|
||||||
|
# Returns a list of all stores this game is available on
|
||||||
|
def getStores(self, release):
|
||||||
|
return sorted(store["store"]["name"] for store in release["stores"])
|
||||||
|
|
||||||
|
# Returns a list of all tags associated with this game
|
||||||
|
def getTags(self, release):
|
||||||
|
if len(release["tags"]) == 0:
|
||||||
|
return "N/A"
|
||||||
|
li = sorted([tag["name"] for tag in release["tags"]])
|
||||||
|
st = li[0]
|
||||||
|
for tag in li[1:]:
|
||||||
|
if len(st) + 2 + len(tag) > 1024:
|
||||||
|
break
|
||||||
|
st += ", " + tag
|
||||||
|
return st if st else "N/A"
|
||||||
|
|
||||||
|
# Truncates the description if necessary
|
||||||
|
def writeDescription(self, description):
|
||||||
|
if len(description) > 700:
|
||||||
|
return description[:697] + "..."
|
||||||
|
return description if description else "N/A"
|
||||||
|
|
||||||
|
@info.error
|
||||||
|
async def info_on_error(self, ctx, error):
|
||||||
|
if isinstance(error, commands.BadArgument):
|
||||||
|
await ctx.send("Geef een geldig getal op.")
|
||||||
|
elif isinstance(error, commands.MissingRequiredArgument):
|
||||||
|
await ctx.send("Controleer je argumenten.")
|
||||||
|
else:
|
||||||
|
raise error
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Release(client))
|
|
@ -0,0 +1,304 @@
|
||||||
|
from data import constants
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.courses import years
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, eten, timeFormatters, config, stringFormatters
|
||||||
|
from functions.numbers import clamp
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class School(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Eten", aliases=["Food", "Menu"], usage="[Dag]*")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.School)
|
||||||
|
async def eten(self, ctx, *day):
|
||||||
|
day = self.getWeekDay(None if len(day) == 0 else day)[1]
|
||||||
|
|
||||||
|
# Create embed
|
||||||
|
menu = eten.etenScript(day)
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Menu voor {}".format(day))
|
||||||
|
if "gesloten" in menu[0].lower():
|
||||||
|
embed.description = "Restaurant gesloten"
|
||||||
|
else:
|
||||||
|
embed.add_field(name="Soep:", value=menu[0], inline=False)
|
||||||
|
embed.add_field(name="Hoofdgerechten:", value=menu[1], inline=False)
|
||||||
|
|
||||||
|
if menu[2]:
|
||||||
|
embed.add_field(name="Groenten:", value=menu[2], inline=False)
|
||||||
|
|
||||||
|
embed.set_footer(text="Omwille van de coronamaatregelen is er een beperkter aanbod, en kan je enkel nog eten afhalen. Ter plaatse eten is niet meer mogelijk.")
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(name="Les", aliases=["Sched", "Schedule", "Class"], usage="[Jaargang]* [Dag]*")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.School)
|
||||||
|
async def les(self, ctx, *day):
|
||||||
|
semester = int(config.get("semester"))
|
||||||
|
year = int(config.get("year"))
|
||||||
|
years_counter = int(config.get("years"))
|
||||||
|
# Check if a schedule or a day was called
|
||||||
|
if len(day) == 0:
|
||||||
|
day = []
|
||||||
|
else:
|
||||||
|
# Only either of them was passed
|
||||||
|
if len(day) == 1:
|
||||||
|
# Called a schedule
|
||||||
|
if day[0].isdigit():
|
||||||
|
if 0 < int(day[0]) < years_counter + 1:
|
||||||
|
year = int(day[0])
|
||||||
|
day = []
|
||||||
|
else:
|
||||||
|
return await ctx.send("Dit is geen geldige jaargang.")
|
||||||
|
# elif: calling a weekday is automatically handled below,
|
||||||
|
# so checking is obsolete
|
||||||
|
else:
|
||||||
|
# Both were passed
|
||||||
|
if day[0].isdigit():
|
||||||
|
if 0 < int(day[0]) < years_counter + 1:
|
||||||
|
year = int(day[0])
|
||||||
|
day = []
|
||||||
|
else:
|
||||||
|
return await ctx.send("Dit is geen geldige jaargang.")
|
||||||
|
# Cut the schedule from the string
|
||||||
|
day = day[1:]
|
||||||
|
|
||||||
|
day = self.getWeekDay(None if len(day) == 0 else day)[1]
|
||||||
|
dayDatetime = self.findDate(timeFormatters.weekdayToInt(day))
|
||||||
|
|
||||||
|
schedule = self.customizeSchedule(ctx, year, semester)
|
||||||
|
|
||||||
|
# Create a date object to check the current week
|
||||||
|
startDate = 1600041600
|
||||||
|
currentTime = dayDatetime.timestamp()
|
||||||
|
week = clamp(timeFormatters.timeIn(currentTime - startDate, "weeks")[0], 1, 13)
|
||||||
|
|
||||||
|
title, week = self.getTitle(day, dayDatetime, week)
|
||||||
|
|
||||||
|
# Add all courses & their corresponding times + locations of today
|
||||||
|
courses, extras, prev, online = self.getCourses(schedule, day, week)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue(), title=title)
|
||||||
|
embed.set_author(name="Lessenrooster voor {}{} Bachelor".format(year, "ste" if year == 1 else "de"))
|
||||||
|
|
||||||
|
if len(courses) == 0:
|
||||||
|
embed.add_field(name="Geen Les", value="Geen Les", inline=False)
|
||||||
|
else:
|
||||||
|
courseString = self.createCourseString(courses)
|
||||||
|
courseString += "\nGroep {} heeft vandaag online les.".format(1 if week % 2 == 0 else 2)
|
||||||
|
embed.description = courseString
|
||||||
|
|
||||||
|
if prev:
|
||||||
|
embed.add_field(name="Vakken uit vorige jaren", value=self.createCourseString(prev), inline=False)
|
||||||
|
|
||||||
|
if extras:
|
||||||
|
embed.add_field(name="Extra", value="\n".join(self.getExtras(extra) for extra in extras), inline=False)
|
||||||
|
|
||||||
|
# Add online links if not commnet
|
||||||
|
if online:
|
||||||
|
embed.add_field(name="Online Links", value="\n".join(self.getLink(onlineClass) for onlineClass in online))
|
||||||
|
|
||||||
|
embed.set_footer(text="Semester {} | Lesweek {}".format(semester, round(week)))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
def getLink(self, onlineClass):
|
||||||
|
return "{}: **[{}]({})**".format(onlineClass["course"], onlineClass["online"], onlineClass["link"])
|
||||||
|
|
||||||
|
def createCourseString(self, courses):
|
||||||
|
courseString = ""
|
||||||
|
for course in sorted(courses, key=lambda item: item["slot"]["time"][1]):
|
||||||
|
# Add a ":" to the hour + add a leading "0" if needed
|
||||||
|
start = timeFormatters.timeFromInt(course["slot"]["time"][1])
|
||||||
|
end = timeFormatters.timeFromInt(course["slot"]["time"][2])
|
||||||
|
courseString += "{} - {}: {} {}\n".format(start, end,
|
||||||
|
str(course["course"]), self.getLocation(course["slot"]))
|
||||||
|
return courseString
|
||||||
|
|
||||||
|
# Returns the day of the week, while keeping track of weekends
|
||||||
|
def getWeekDay(self, day=None):
|
||||||
|
weekDays = ["maandag", "dinsdag", "woensdag", "donderdag", "vrijdag"]
|
||||||
|
|
||||||
|
# Get current day of the week
|
||||||
|
dayNumber = datetime.datetime.today().weekday()
|
||||||
|
# If a day or a modifier was passed, show that day instead
|
||||||
|
if day is not None:
|
||||||
|
if day[0] == "morgen":
|
||||||
|
dayNumber += 1
|
||||||
|
elif day[0] == "overmorgen":
|
||||||
|
dayNumber += 2
|
||||||
|
else:
|
||||||
|
for i in range(5):
|
||||||
|
if weekDays[i].startswith(day):
|
||||||
|
dayNumber = i
|
||||||
|
# Weekends should be skipped
|
||||||
|
dayNumber = dayNumber % 7
|
||||||
|
if dayNumber > 4:
|
||||||
|
dayNumber = 0
|
||||||
|
|
||||||
|
# Get daystring
|
||||||
|
return dayNumber, weekDays[dayNumber]
|
||||||
|
|
||||||
|
def getLocation(self, slot):
|
||||||
|
if "canceled" in slot:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if "online" in slot:
|
||||||
|
return "online @ **[{}]({})**".format(slot["online"], slot["zoom"] if slot["online"] == "ZOOM" else slot["bongo"])
|
||||||
|
|
||||||
|
# Check for courses in multiple locations
|
||||||
|
if "locations" in slot:
|
||||||
|
# Language - 'en' for the last one
|
||||||
|
return ", ".join(self.getLocation(location) for location in slot["locations"][:-1]) \
|
||||||
|
+ " en " + self.getLocation(slot["locations"][-1])
|
||||||
|
return "in {} {} {}".format(slot["campus"], slot["building"], slot["room"])
|
||||||
|
|
||||||
|
def getCourses(self, schedule, day, week):
|
||||||
|
# Add all courses & their corresponding times + locations of today
|
||||||
|
courses = []
|
||||||
|
|
||||||
|
extras = []
|
||||||
|
|
||||||
|
prev = []
|
||||||
|
|
||||||
|
onlineLinks = []
|
||||||
|
|
||||||
|
for course in schedule:
|
||||||
|
for slot in course["slots"]:
|
||||||
|
if day in slot["time"]:
|
||||||
|
classDic = {"course": course["course"], "slot": slot}
|
||||||
|
|
||||||
|
# Class was canceled
|
||||||
|
if "canceled" in slot and "weeks" in slot and week in slot["weeks"]:
|
||||||
|
extras.append(classDic)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add online links for those at home
|
||||||
|
if not any(el["course"] == course["course"] for el in onlineLinks):
|
||||||
|
if "bongo" in course:
|
||||||
|
onlineDic = {"course": course["course"], "online": "Bongo Virtual Classroom", "link": course["bongo"]}
|
||||||
|
onlineLinks.append(onlineDic)
|
||||||
|
elif "zoom" in course:
|
||||||
|
onlineDic = {"course": course["course"], "online": "Zoom", "link": course["zoom"]}
|
||||||
|
onlineLinks.append(onlineDic)
|
||||||
|
|
||||||
|
# Add this class' bongo & zoom links
|
||||||
|
if "bongo" in course:
|
||||||
|
classDic["slot"]["bongo"] = course["bongo"]
|
||||||
|
|
||||||
|
if "zoom" in course:
|
||||||
|
classDic["slot"]["zoom"] = course["zoom"]
|
||||||
|
|
||||||
|
if "custom" in course:
|
||||||
|
prev.append(classDic)
|
||||||
|
|
||||||
|
# Check for special classes
|
||||||
|
if "weeks" in slot and "online" not in slot:
|
||||||
|
if week in slot["weeks"]:
|
||||||
|
if "custom" not in course:
|
||||||
|
courses.append(classDic)
|
||||||
|
extras.append(classDic)
|
||||||
|
elif "weeks" in slot and "online" in slot and "group" not in slot:
|
||||||
|
if week in slot["weeks"]:
|
||||||
|
if "custom" not in course:
|
||||||
|
courses.append(classDic)
|
||||||
|
extras.append(classDic)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if "custom" not in course:
|
||||||
|
courses.append(classDic)
|
||||||
|
|
||||||
|
# Filter out normal courses that are replaced with special courses
|
||||||
|
for extra in extras:
|
||||||
|
for course in courses:
|
||||||
|
if course["slot"]["time"] == extra["slot"]["time"] and course != extra:
|
||||||
|
courses.remove(course)
|
||||||
|
break
|
||||||
|
|
||||||
|
# Sort online links alphabetically
|
||||||
|
onlineLinks.sort(key=lambda x: x["course"])
|
||||||
|
|
||||||
|
# Remove links of canceled classes
|
||||||
|
for element in onlineLinks:
|
||||||
|
if not any(c["course"] == element["course"] for c in courses):
|
||||||
|
onlineLinks.remove(element)
|
||||||
|
|
||||||
|
return courses, extras, prev, onlineLinks
|
||||||
|
|
||||||
|
def getTitle(self, day, dayDT, week):
|
||||||
|
# now = timeFormatters.dateTimeNow()
|
||||||
|
# if timeFormatters.weekdayToInt(day) < now.weekday():
|
||||||
|
# week += 1
|
||||||
|
|
||||||
|
day = day[0].upper() + day[1:].lower()
|
||||||
|
|
||||||
|
titleString = "{} {}/{}/{}".format(day, stringFormatters.leadingZero(dayDT.day),
|
||||||
|
stringFormatters.leadingZero(dayDT.month), dayDT.year)
|
||||||
|
return titleString, week
|
||||||
|
|
||||||
|
def getExtras(self, extra):
|
||||||
|
start = timeFormatters.timeFromInt(extra["slot"]["time"][1])
|
||||||
|
end = timeFormatters.timeFromInt(extra["slot"]["time"][2])
|
||||||
|
|
||||||
|
location = self.getLocation(extra["slot"])
|
||||||
|
|
||||||
|
if "canceled" in extra["slot"]:
|
||||||
|
return "De les **{}** van **{}** tot **{}** gaat vandaag uitzonderlijk **niet** door.".format(
|
||||||
|
extra["course"], start, end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "group" in extra["slot"]:
|
||||||
|
return "**Groep {}** heeft vandaag uitzonderlijk **{}** **{}** van **{} tot {}**.".format(
|
||||||
|
extra["slot"]["group"], extra["course"], location,
|
||||||
|
start, end
|
||||||
|
)
|
||||||
|
elif "online" in extra["slot"]:
|
||||||
|
return "**{}** gaat vandaag uitzonderlijk online door {} van **{} tot {}**.".format(
|
||||||
|
extra["course"], location[7:],
|
||||||
|
start, end
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return "**{}** vindt vandaag uitzonderlijk plaats **{}** van **{} tot {}**.".format(
|
||||||
|
extra["course"], location,
|
||||||
|
start, end
|
||||||
|
)
|
||||||
|
|
||||||
|
def findDate(self, targetWeekday):
|
||||||
|
now = timeFormatters.dateTimeNow()
|
||||||
|
while now.weekday() != targetWeekday:
|
||||||
|
now = now + datetime.timedelta(days=1)
|
||||||
|
return now
|
||||||
|
|
||||||
|
# Add all the user's courses
|
||||||
|
def customizeSchedule(self, ctx, year, semester):
|
||||||
|
with open("files/schedules/{}{}.json".format(year, semester), "r") as fp:
|
||||||
|
schedule = json.load(fp)
|
||||||
|
return schedule
|
||||||
|
member = self.client.get_guild(int(constants.CallOfCode)).get_member(ctx.author.id)
|
||||||
|
for role in member.roles:
|
||||||
|
for univYear in years:
|
||||||
|
for course in univYear:
|
||||||
|
if course.value["year"] < year and course.value["id"] == role.id and course.value["semester"] == semester:
|
||||||
|
with open("files/schedules/{}{}.json".format(course.value["year"], course.value["semester"]),
|
||||||
|
"r") as fp:
|
||||||
|
sched2 = json.load(fp)
|
||||||
|
|
||||||
|
for val in sched2:
|
||||||
|
if val["course"] == course.value["name"]:
|
||||||
|
val["custom"] = course.value["year"]
|
||||||
|
schedule.append(val)
|
||||||
|
return schedule
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(School(client))
|
|
@ -0,0 +1,102 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
from functions.database import githubs, twitch
|
||||||
|
|
||||||
|
|
||||||
|
class SelfPromo(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.utilsCog = self.client.get_cog("Utils")
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="GitHub", aliases=["Git", "GitHubs", "Gh"], case_insensitive=True, usage="[@Persoon]*", invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def github(self, ctx, member: discord.Member = None):
|
||||||
|
# Get a specific member's GitHub
|
||||||
|
if member:
|
||||||
|
user_git = githubs.get_user(member.id)
|
||||||
|
if not user_git:
|
||||||
|
return await ctx.send("**{}** heeft zijn GitHub link nog niet doorgegeven.".format(member.display_name))
|
||||||
|
|
||||||
|
return await self.createPersonalPromo(ctx, member, user_git[0][0], discord.Colour.from_rgb(250, 250, 250), "GitHub")
|
||||||
|
|
||||||
|
l = githubs.getAll()
|
||||||
|
await self.createPromoEmbed(ctx, l, discord.Colour.from_rgb(250, 250, 250), "GitHub", "files/images/github.png")
|
||||||
|
|
||||||
|
@github.command(name="Add", aliases=["Insert", "Register", "Set"], usage="[Link]")
|
||||||
|
async def githubadd(self, ctx, link):
|
||||||
|
if "github.com" not in link.lower() and "github.ugent.be" not in link.lower() and "gitlab.com" not in link.lower():
|
||||||
|
link = "https://github.com/{}".format(link)
|
||||||
|
|
||||||
|
githubs.add(ctx.author.id, link)
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
|
||||||
|
@commands.group(name="Twitch", aliases=["Streams"], case_insensitive=True, usage="[@Persoon]", invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def twitch(self, ctx, member: discord.Member = None):
|
||||||
|
# Get a specific member's GitHub
|
||||||
|
if member:
|
||||||
|
user_twitch = twitch.get_user(member.id)
|
||||||
|
if not user_twitch:
|
||||||
|
return await ctx.send("**{}** heeft zijn Twitch link nog niet doorgegeven.".format(member.display_name))
|
||||||
|
|
||||||
|
return await self.createPersonalPromo(ctx, member, user_twitch[0][0], discord.Colour.from_rgb(100, 65, 165), "Twitch")
|
||||||
|
|
||||||
|
l = twitch.getAll()
|
||||||
|
await self.createPromoEmbed(ctx, l, discord.Colour.from_rgb(100, 65, 165), "Twitch", "files/images/twitch.png")
|
||||||
|
|
||||||
|
@twitch.command(name="Add", aliases=["Insert", "Register", "Set"], usage="[Link]")
|
||||||
|
async def twitchadd(self, ctx, link):
|
||||||
|
if "twitch.tv" not in link.lower():
|
||||||
|
link = "https://www.twitch.tv/{}".format(link)
|
||||||
|
|
||||||
|
twitch.add(ctx.author.id, link)
|
||||||
|
await ctx.message.add_reaction("✅")
|
||||||
|
|
||||||
|
# Creates embed with everyone's links & a fancy image
|
||||||
|
async def createPromoEmbed(self, ctx, users, colour, type, imageUrl=None):
|
||||||
|
# Image file
|
||||||
|
file = None
|
||||||
|
|
||||||
|
# Sort users by Discord name
|
||||||
|
users = [[self.utilsCog.getMember(ctx, user[0]), user[1]] for user in users if self.utilsCog.getMember(ctx, user[0]) is not None]
|
||||||
|
users.sort(key=lambda x: x[0].name)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=colour)
|
||||||
|
if imageUrl is not None:
|
||||||
|
# Link
|
||||||
|
if "https" in imageUrl:
|
||||||
|
embed.set_thumbnail(url=imageUrl)
|
||||||
|
else:
|
||||||
|
# Local file
|
||||||
|
file = discord.File(imageUrl, filename="icon.png")
|
||||||
|
embed.set_thumbnail(url="attachment://icon.png")
|
||||||
|
embed.set_author(name="{} Links".format(type))
|
||||||
|
for user in users:
|
||||||
|
embed.add_field(name="{} ({})".format(
|
||||||
|
user[0].display_name, user[0].name
|
||||||
|
), value=user[1], inline=False)
|
||||||
|
embed.set_footer(text="Wil je je eigen {0} hierin? Gebruik {0} Add [Link] of stuur een DM naar DJ STIJN.".format(type))
|
||||||
|
if file is not None:
|
||||||
|
await ctx.send(embed=embed, file=file)
|
||||||
|
else:
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
async def createPersonalPromo(self, ctx, user, link, colour, type):
|
||||||
|
embed = discord.Embed(colour=colour)
|
||||||
|
embed.set_author(name="{} Links".format(type), icon_url=user.avatar_url)
|
||||||
|
embed.add_field(name="{} link van {}".format(type, user.display_name), value=link)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(SelfPromo(client))
|
|
@ -0,0 +1,128 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
from functions.database import stats
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class Stats(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Stats", usage="[Categorie]*", case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(category=Category.Other)
|
||||||
|
async def stats(self, ctx):
|
||||||
|
s = stats.getOrAddUser(ctx.author.id)
|
||||||
|
|
||||||
|
# Calculate the percentages
|
||||||
|
robAttempts = int(s[2]) + int(s[3]) if int(s[2]) + int(s[3]) != 0 else 1
|
||||||
|
robSuccessPercent = round(100 * int(s[2]) / robAttempts, 2)
|
||||||
|
robFailedPercent = round(100 * int(s[3]) / robAttempts, 2)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="{}'s Stats".format(ctx.author.display_name))
|
||||||
|
embed.add_field(name="Geslaagde Rob Pogingen", value="{} ({})%".format(s[2], robSuccessPercent))
|
||||||
|
embed.add_field(name="Gefaalde Rob Pogingen", value="{} ({})%".format(s[3], robFailedPercent))
|
||||||
|
embed.add_field(name="Aantal Dinks Gestolen", value="{:,}".format(round(s[4])))
|
||||||
|
embed.add_field(name="Aantal Nightlies", value=str(s[6]))
|
||||||
|
embed.add_field(name="Langste Nightly Streak", value=str(s[5]))
|
||||||
|
embed.add_field(name="Totale Profit", value="{:,}".format(round(s[7])))
|
||||||
|
embed.add_field(name="Aantal keer gepoked", value=str(s[1]))
|
||||||
|
embed.add_field(name="Aantal Gewonnen Coinflips", value=str(s[8]))
|
||||||
|
embed.add_field(name="Totale winst uit Coinflips", value="{:,}".format(round(s[9])))
|
||||||
|
embed.add_field(name="Aantal Bails", value="{:,}".format(int(s[10])))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@stats.command(aliases=["Coinflip"], hidden=True)
|
||||||
|
async def cf(self, ctx):
|
||||||
|
with open("files/stats.json", "r") as fp:
|
||||||
|
s = json.load(fp)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Coinflip Stats")
|
||||||
|
embed.description = "**Kop**: {:,} ({}%)\n**Munt**: {:,} ({}%)".format(
|
||||||
|
s["cf"]["h"], self.percent(s["cf"], "h"), s["cf"]["t"], self.percent(s["cf"], "t"))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@stats.command(aliases=["Roll"], hidden=True)
|
||||||
|
async def dice(self, ctx):
|
||||||
|
with open("files/stats.json", "r") as fp:
|
||||||
|
s = json.load(fp)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Dice Stats")
|
||||||
|
embed.description = "\n".join(["**{}**: {:,} ({}%)".format(
|
||||||
|
i, s["dice"][i], self.percent(s["dice"], i)) for i in sorted(s["dice"].keys())])
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@stats.command(hidden=True)
|
||||||
|
async def rob(self, ctx):
|
||||||
|
with open("files/stats.json", "r") as fp:
|
||||||
|
s = json.load(fp)["rob"]
|
||||||
|
totalAttempts = s["robs_success"] + s["robs_failed"]
|
||||||
|
successPercent = round(100 * s["robs_success"] / totalAttempts, 2)
|
||||||
|
failedPercent = round(100 * s["robs_failed"] / totalAttempts, 2)
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Rob Stats")
|
||||||
|
embed.description = "**Geslaagd**: {:,} ({}%)\n**Gefaald**: {:,} ({}%)\n**Borg betaald**: {:,}".format(
|
||||||
|
s["robs_success"], successPercent, s["robs_failed"], failedPercent, round(s["bail_paid"])
|
||||||
|
)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@stats.command(name="Channels", aliases=["C", "CA"], usage="[#Channel]*", hidden=True)
|
||||||
|
@commands.check(checks.isMod)
|
||||||
|
async def channels(self, ctx, channel: discord.TextChannel = None):
|
||||||
|
res = stats.channel_activity(channel)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
|
||||||
|
if channel:
|
||||||
|
embed.set_author(name="Channel Activity - {}".format(channel.name))
|
||||||
|
channel_instance = self.client.get_channel(int(res[0][0]))
|
||||||
|
embed.add_field(name="Aantal berichten", value="{:,}".format(round(float(res[0][1]), 2)), inline=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
last_message = await channel_instance.fetch_message(channel_instance.last_message_id)
|
||||||
|
except discord.NotFound:
|
||||||
|
last_message = None
|
||||||
|
|
||||||
|
if last_message is None:
|
||||||
|
embed.add_field(name="Laatste bericht", value="[Verwijderd]", inline=False)
|
||||||
|
else:
|
||||||
|
embed.add_field(name="Laatste bericht", value="[Jump URL]({})".format(last_message.jump_url), inline=False)
|
||||||
|
elif ctx.guild:
|
||||||
|
embed.set_author(name="Channel Activity - {}".format(ctx.guild))
|
||||||
|
|
||||||
|
description = ""
|
||||||
|
for c in res:
|
||||||
|
channel_instance = self.client.get_channel(int(c[0]))
|
||||||
|
|
||||||
|
description += "{}: {:,}\n".format(channel_instance.mention, round(float(c[1]), 2))
|
||||||
|
|
||||||
|
embed.description = description
|
||||||
|
else:
|
||||||
|
return await ctx.send("Dit commando werkt niet in DM's.")
|
||||||
|
|
||||||
|
return await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
async def callStats(self, name, ctx):
|
||||||
|
await [command for command in self.stats.commands if command.name == name][0](ctx)
|
||||||
|
|
||||||
|
def percent(self, dic, stat):
|
||||||
|
total = sum([int(dic[s]) for s in dic])
|
||||||
|
if total == 0:
|
||||||
|
total = 1
|
||||||
|
|
||||||
|
return round(100 * int(dic[stat]) / total, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Stats(client))
|
|
@ -0,0 +1,120 @@
|
||||||
|
from converters.numbers import Abbreviated
|
||||||
|
from data import storePages
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from enums.numbers import Numbers
|
||||||
|
from functions import checks
|
||||||
|
from functions.database import store, currency
|
||||||
|
from functions.numbers import getRep
|
||||||
|
|
||||||
|
|
||||||
|
class Store(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.group(name="Store", aliases=["Shop"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Currency)
|
||||||
|
async def store(self, ctx):
|
||||||
|
entries = store.getAllItems()
|
||||||
|
await storePages.Pages(source=storePages.Source(entries), clear_reactions_after=True).start(ctx)
|
||||||
|
|
||||||
|
@store.command(name="Buy", aliases=["Get"], hidden=True)
|
||||||
|
async def storeBuy(self, ctx, item, amount: Abbreviated = 1):
|
||||||
|
if amount is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.buy(ctx, item, amount)
|
||||||
|
|
||||||
|
@commands.command(name="Buy", aliases=["Get"], usage="[Item id] [Aantal]*")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Currency)
|
||||||
|
async def buy(self, ctx, item, amount: Abbreviated = 1):
|
||||||
|
if amount is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
item = int(item)
|
||||||
|
except ValueError:
|
||||||
|
return await ctx.send("Dit is geen geldig id.")
|
||||||
|
|
||||||
|
success, message = store.buy(ctx, ctx.author.id, item, amount)
|
||||||
|
if not success:
|
||||||
|
return await ctx.send(message)
|
||||||
|
|
||||||
|
rep = getRep(message["price"], Numbers.t.value)
|
||||||
|
|
||||||
|
return await ctx.send("**{}** heeft **{} {}{}** gekocht voor **{}** Didier Dink{}.".format(
|
||||||
|
ctx.author.display_name, amount, message["name"], checks.pluralS(amount),
|
||||||
|
rep, checks.pluralS(message["price"])
|
||||||
|
))
|
||||||
|
|
||||||
|
@store.command(name="Sell", hidden=True)
|
||||||
|
async def storeSell(self, ctx, itemid, amount: Abbreviated = 1):
|
||||||
|
if amount is None:
|
||||||
|
return
|
||||||
|
await self.sell(ctx, itemid, amount)
|
||||||
|
|
||||||
|
@commands.command(name="Sell", usage="[Item id] [Aantal]")
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Currency)
|
||||||
|
async def sell(self, ctx, itemid, amount: Abbreviated = 1):
|
||||||
|
if amount is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
itemid = int(itemid)
|
||||||
|
except ValueError:
|
||||||
|
return await ctx.send("Dit is geen geldig id.")
|
||||||
|
|
||||||
|
inv = store.inventory(ctx.author.id)
|
||||||
|
|
||||||
|
if not inv or not any(int(item[0]) == itemid for item in inv):
|
||||||
|
return await ctx.send("Je hebt geen item met dit id.")
|
||||||
|
|
||||||
|
item_tuple = None
|
||||||
|
for item in inv:
|
||||||
|
if item[0] == itemid:
|
||||||
|
item_tuple = item
|
||||||
|
break
|
||||||
|
|
||||||
|
if int(item_tuple[2]) < amount:
|
||||||
|
return await ctx.send("Je hebt niet zoveel {}s.".format(item_tuple[1]))
|
||||||
|
|
||||||
|
store.sell(int(ctx.author.id), itemid, int(amount), int(item_tuple[2]))
|
||||||
|
price = int(store.getItemPrice(itemid)[0])
|
||||||
|
returnValue = round(0.8 * (price * amount))
|
||||||
|
|
||||||
|
currency.update(ctx.author.id, "dinks", currency.dinks(ctx.author.id) + returnValue)
|
||||||
|
|
||||||
|
await ctx.send("**{}** heeft **{} {}{}** verkocht voor **{}** Didier Dinks!".format(
|
||||||
|
ctx.author.display_name, amount, item_tuple[1], "s" if amount != 1 else "",
|
||||||
|
getRep(returnValue, Numbers.t.value)
|
||||||
|
))
|
||||||
|
|
||||||
|
@commands.command(name="Inventory", aliases=["Inv", "Items"])
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Currency)
|
||||||
|
async def inventory(self, ctx, *args):
|
||||||
|
inv = store.inventory(ctx.author.id)
|
||||||
|
inv = sorted(inv, key=lambda x: x[1])
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Inventory van {}".format(ctx.author.display_name))
|
||||||
|
embed.set_thumbnail(url=str(ctx.author.avatar_url))
|
||||||
|
if len(inv) == 0:
|
||||||
|
embed.description = "Je hebt nog niets gekocht!\n" \
|
||||||
|
"Koop iets in de Store wanneer DJ STIJN niet langer te lui is om er iets in te steken."
|
||||||
|
else:
|
||||||
|
embed.description = "\n".join("#{} {}: {}".format(item[0], item[1], item[2]) for item in inv)
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Store(client))
|
|
@ -0,0 +1,167 @@
|
||||||
|
from data import constants
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
from enums.numbers import Numbers
|
||||||
|
from functions import timeFormatters
|
||||||
|
from functions.database import currency, poke, prison, birthdays, stats
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
class Tasks(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.bankInterest.start()
|
||||||
|
self.resetPrison.start()
|
||||||
|
self.resetLost.start()
|
||||||
|
# self.resetPoke.start()
|
||||||
|
self.checkBirthdays.start()
|
||||||
|
self.updateMessageCounts.start()
|
||||||
|
|
||||||
|
@tasks.loop(hours=1.0)
|
||||||
|
async def bankInterest(self):
|
||||||
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
|
lastTasks = json.load(fp)
|
||||||
|
if int(self.getCurrentHour()) == 0 and int(time.time()) - int(lastTasks["interest"]) > 10000:
|
||||||
|
users = currency.getAllRows()
|
||||||
|
bitcoinPrice = self.getCurrentBitcoinPrice()
|
||||||
|
for user in users:
|
||||||
|
# People in prison don't get interest
|
||||||
|
if len(prison.getUser(int(user[0]))) != 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if float(user[3]) != 0.0:
|
||||||
|
currency.update(user[0], "investeddays", int(user[4]) + 1)
|
||||||
|
profit = ((float(user[3]) + float(user[5])) * (1 + (float(user[2]) * 0.01))) - float(user[3])
|
||||||
|
# Can't exceed 1 quadrillion
|
||||||
|
# Check BC as well so they can't put everything into BC to cheat the system
|
||||||
|
if float(user[1]) + float(user[3]) + float(user[5]) + profit + (float(user[8]) * bitcoinPrice) > Numbers.q.value:
|
||||||
|
# In case adding profit would exceed 1q, only add the difference
|
||||||
|
profit = Numbers.q.value - float(user[1]) - float(user[3]) - float(user[5]) - (float(user[8]) * bitcoinPrice)
|
||||||
|
# Don't reduce the current profit if Dinks were gained some other way (rob, bc, ...)
|
||||||
|
if profit > 0:
|
||||||
|
currency.update(user[0], "profit", float(user[5]) + profit)
|
||||||
|
|
||||||
|
await self.client.get_user(int(user[0])).send("Je hebt de invest-limiet van 1Q Didier Dinks bereikt.\nIndien je nog meer Didier Dinks wil sparen, kan je 1q Didier Dinks omruilen voor een Platinum Dink in de shop.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
currency.update(user[0], "profit", float(user[5]) + profit)
|
||||||
|
lastTasks["interest"] = int(round(time.time()))
|
||||||
|
with open("files/lastTasks.json", "w") as fp:
|
||||||
|
json.dump(lastTasks, fp)
|
||||||
|
|
||||||
|
@bankInterest.before_loop
|
||||||
|
async def beforeBankInterest(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
@tasks.loop(hours=1.0)
|
||||||
|
async def resetLost(self):
|
||||||
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
|
lastTasks = json.load(fp)
|
||||||
|
|
||||||
|
if int(self.getCurrentHour()) == 0 and int(time.time()) - int(lastTasks["lost"]) > 10000:
|
||||||
|
with open("files/lost.json", "r") as fp:
|
||||||
|
fc = json.load(fp)
|
||||||
|
fc["today"] = 0
|
||||||
|
with open("files/lost.json", "w") as fp:
|
||||||
|
json.dump(fc, fp)
|
||||||
|
|
||||||
|
lastTasks["lost"] = round(time.time())
|
||||||
|
with open("files/lastTasks.json", "w") as fp:
|
||||||
|
json.dump(lastTasks, fp)
|
||||||
|
|
||||||
|
@resetLost.before_loop
|
||||||
|
async def beforeResetLost(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
@tasks.loop(hours=6.0)
|
||||||
|
async def resetPoke(self):
|
||||||
|
if int(time.time()) - int(poke.get()[1]) > 259200:
|
||||||
|
await self.client.get_guild(int(self.client.constants.CallOfCode))\
|
||||||
|
.get_channel(int(self.client.constants.DidierPosting))\
|
||||||
|
.send("Poke is gereset door inactiviteit. <@!{}> is hem!".format(int(poke.reset())))
|
||||||
|
|
||||||
|
@resetPoke.before_loop
|
||||||
|
async def beforeResetPoke(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
@tasks.loop(hours=1.0)
|
||||||
|
async def resetPrison(self):
|
||||||
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
|
lastTasks = json.load(fp)
|
||||||
|
|
||||||
|
if int(self.getCurrentHour()) == 0 and int(time.time()) - int(lastTasks["prison"]) > 10000:
|
||||||
|
prison.dailyLowers()
|
||||||
|
|
||||||
|
with open("files/lastTasks.json", "w") as fp:
|
||||||
|
lastTasks["prison"] = round(time.time())
|
||||||
|
json.dump(lastTasks, fp)
|
||||||
|
|
||||||
|
@resetPrison.before_loop
|
||||||
|
async def beforeResetPrison(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
@tasks.loop(hours=1.0)
|
||||||
|
async def checkBirthdays(self):
|
||||||
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
|
lastTasks = json.load(fp)
|
||||||
|
if int(self.getCurrentHour()) == 6 and int(time.time()) - int(lastTasks["birthdays"]) > 10000:
|
||||||
|
dt = timeFormatters.dateTimeNow()
|
||||||
|
res = birthdays.get_users_on_date(dt.day, dt.month)
|
||||||
|
|
||||||
|
COC = self.client.get_guild(int(constants.CallOfCode))
|
||||||
|
people = [COC.get_member(int(user[0])) for user in res]
|
||||||
|
general = COC.get_channel(int(constants.CoCGeneral))
|
||||||
|
|
||||||
|
lastTasks["birthdays"] = round(time.time())
|
||||||
|
with open("files/lastTasks.json", "w") as fp:
|
||||||
|
json.dump(lastTasks, fp)
|
||||||
|
|
||||||
|
if not people:
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(people) == 1:
|
||||||
|
return await general.send("Gelukkige verjaardag {}!".format(people[0].mention))
|
||||||
|
return await general.send("Gelukkige verjaardag {} en {}!".format(
|
||||||
|
", ".join(user.mention for user in people[:-1]),
|
||||||
|
people[-1].mention
|
||||||
|
))
|
||||||
|
|
||||||
|
@checkBirthdays.before_loop
|
||||||
|
async def beforecheckBirthdays(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
@tasks.loop(hours=1.0)
|
||||||
|
async def updateMessageCounts(self):
|
||||||
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
|
lastTasks = json.load(fp)
|
||||||
|
if int(self.getCurrentHour()) == 0 and int(time.time()) - int(lastTasks["channels"]) > 10000:
|
||||||
|
channels = stats.channel_activity()
|
||||||
|
for channel in channels:
|
||||||
|
stats.lower_channel(int(channel[0]), 0.95 * float(channel[1]))
|
||||||
|
|
||||||
|
with open("files/lastTasks.json", "w") as fp:
|
||||||
|
lastTasks["channels"] = round(time.time())
|
||||||
|
json.dump(lastTasks, fp)
|
||||||
|
|
||||||
|
@updateMessageCounts.before_loop
|
||||||
|
async def beforeupdateMessageCounts(self):
|
||||||
|
await self.client.wait_until_ready()
|
||||||
|
|
||||||
|
def getCurrentHour(self):
|
||||||
|
return timeFormatters.dateTimeNow().hour
|
||||||
|
|
||||||
|
def getCurrentBitcoinPrice(self):
|
||||||
|
result = requests.get("https://api.coindesk.com/v1/bpi/currentprice.json").json()
|
||||||
|
currentPrice = result["bpi"]["EUR"]["rate_float"]
|
||||||
|
return float(currentPrice)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Tasks(client))
|
|
@ -0,0 +1,20 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
from functions import checks
|
||||||
|
|
||||||
|
|
||||||
|
class TestCog(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# All commands in this Cog should only be accessible to me
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return checks.isMe(ctx)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def test(self, ctx):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(TestCog(client))
|
|
@ -0,0 +1,128 @@
|
||||||
|
from data import paginatedLeaderboard
|
||||||
|
import datetime
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands, menus
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Train(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Train", aliases=["Trein"], usage="[Vertrek]* [Bestemming]")
|
||||||
|
@help.Category(category=Category.School)
|
||||||
|
async def train(self, ctx, *args):
|
||||||
|
if not args or len(args) > 2:
|
||||||
|
await ctx.send("Controleer je argumenten.")
|
||||||
|
return
|
||||||
|
destination = args[-1]
|
||||||
|
departure = args[0] if len(args) > 1 else "Gent Sint-Pieters"
|
||||||
|
|
||||||
|
req = requests.get(
|
||||||
|
"http://api.irail.be/connections/?from={}&to={}&alerts=true&lang=nl&format=json".format(departure,
|
||||||
|
destination)).json()
|
||||||
|
if "error" in req:
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Treinen van {} naar {}".format(
|
||||||
|
self.formatCity(departure), self.formatCity(destination)))
|
||||||
|
embed.add_field(name="Error", value="Er ging iets fout, probeer het later opnieuw.", inline=False)
|
||||||
|
await self.sendEmbed(ctx, embed)
|
||||||
|
return
|
||||||
|
|
||||||
|
pages = paginatedLeaderboard.Pages(source=TrainPagination(self.formatConnections(req["connection"]),
|
||||||
|
self.formatCity(departure),
|
||||||
|
self.formatCity(destination)),
|
||||||
|
clear_reactions_after=True)
|
||||||
|
await pages.start(ctx)
|
||||||
|
|
||||||
|
def formatConnections(self, connections):
|
||||||
|
response = []
|
||||||
|
for connection in sorted(connections, key=lambda con: con["departure"]["time"]):
|
||||||
|
conn = {}
|
||||||
|
if connection["departure"]["canceled"] != "0" or connection["arrival"]["canceled"] != "0":
|
||||||
|
conn = {"Canceled": "Afgeschaft"}
|
||||||
|
dep = connection["departure"]
|
||||||
|
arr = connection["arrival"]
|
||||||
|
conn["depStation"] = self.formatCity(dep["station"])
|
||||||
|
conn["depTime"] = self.formatTime(dep["time"])
|
||||||
|
conn["delay"] = self.formatDelay(dep["delay"])
|
||||||
|
conn["track"] = dep["platform"]
|
||||||
|
conn["arrStation"] = self.formatCity(arr["station"])
|
||||||
|
conn["direction"] = self.formatCity(dep["direction"]["name"])
|
||||||
|
conn["arrTime"] = self.formatTime(arr["time"])
|
||||||
|
conn["duration"] = self.formatTime(connection["duration"])
|
||||||
|
response.append(conn)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def formatTime(self, timestamp):
|
||||||
|
if int(timestamp) <= 86400:
|
||||||
|
minutes = int(timestamp) // 60
|
||||||
|
if minutes < 60:
|
||||||
|
return str(minutes) + "m"
|
||||||
|
return "{}h{:02}m".format(minutes // 60, minutes % 60)
|
||||||
|
else:
|
||||||
|
return datetime.datetime.fromtimestamp(int(timestamp)).strftime("%H:%M")
|
||||||
|
|
||||||
|
def formatDelay(self, seconds):
|
||||||
|
seconds = int(seconds)
|
||||||
|
return self.sign(seconds) + self.formatTime(abs(seconds)) if seconds != 0 else ""
|
||||||
|
|
||||||
|
def sign(self, number):
|
||||||
|
return "-" if int(number) < 0 else "+"
|
||||||
|
|
||||||
|
def formatCity(self, city):
|
||||||
|
city = city[0].upper() + city[1:]
|
||||||
|
arr = []
|
||||||
|
for i, letter in enumerate(city):
|
||||||
|
if (i > 0 and (city[i - 1] == " " or city[i - 1] == "-")) or i == 0:
|
||||||
|
arr.append(letter.upper())
|
||||||
|
else:
|
||||||
|
arr.append(letter.lower())
|
||||||
|
return "".join(arr)
|
||||||
|
|
||||||
|
async def sendEmbed(self, ctx, embed):
|
||||||
|
if checks.allowedChannels(ctx):
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
else:
|
||||||
|
await ctx.author.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
class TrainPagination(menus.ListPageSource):
|
||||||
|
def __init__(self, data, departure, destination):
|
||||||
|
super().__init__(data, per_page=3)
|
||||||
|
self.departure = departure
|
||||||
|
self.destination = destination
|
||||||
|
|
||||||
|
async def format_page(self, menu: menus.MenuPages, entries):
|
||||||
|
offset = menu.current_page * self.per_page
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Treinen van {} naar {}".format(self.departure, self.destination))
|
||||||
|
embed.set_footer(text="{}/{}".format(menu.current_page + 1, self.get_max_pages()))
|
||||||
|
|
||||||
|
for i, connection in enumerate(entries, start=offset):
|
||||||
|
afgeschaft = "Canceled" in connection
|
||||||
|
embed.add_field(name="Van", value=str(connection["depStation"]), inline=True)
|
||||||
|
embed.add_field(name="Om", value=str(connection["depTime"]), inline=True)
|
||||||
|
embed.add_field(name="Spoor", value=str(connection["track"]), inline=True)
|
||||||
|
embed.add_field(name="Richting", value=str(connection["direction"]), inline=True)
|
||||||
|
embed.add_field(name="Aankomst", value=(str(connection["arrTime"])
|
||||||
|
if not afgeschaft else "**AFGESCHAFT**"), inline=True)
|
||||||
|
embed.add_field(name="Vertraging", value=str(connection["delay"]) if connection["delay"] != "" else "0",
|
||||||
|
inline=True)
|
||||||
|
|
||||||
|
# White space
|
||||||
|
if i - offset < 2:
|
||||||
|
embed.add_field(name="\u200b", value="\u200b", inline=False)
|
||||||
|
return embed
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Train(client))
|
|
@ -0,0 +1,114 @@
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions.stringFormatters import titleCase as tc
|
||||||
|
from googletrans import Translator, LANGUAGES
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class Translate(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Translate", aliases=["Tl", "Trans"], usage="[Tekst] [Van]* [Naar]*")
|
||||||
|
@help.Category(Category.Words)
|
||||||
|
async def translate(self, ctx, query=None, to="nl", fr="auto"):
|
||||||
|
if query is None:
|
||||||
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
||||||
|
success, query = await self.getQuery(ctx, query)
|
||||||
|
if not success:
|
||||||
|
return await ctx.send(query)
|
||||||
|
|
||||||
|
translator = Translator()
|
||||||
|
|
||||||
|
# From & To were provided, swap them
|
||||||
|
if fr != "auto":
|
||||||
|
temp = fr
|
||||||
|
fr = to
|
||||||
|
to = temp
|
||||||
|
|
||||||
|
try:
|
||||||
|
translation = translator.translate(query, to, fr)
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Didier Translate")
|
||||||
|
|
||||||
|
if fr == "auto":
|
||||||
|
language = translation.extra_data["original-language"]
|
||||||
|
embed.add_field(name="Gedetecteerde taal", value=tc(LANGUAGES[language]))
|
||||||
|
embed.add_field(name="Zekerheid", value="{}%".format(translation.extra_data["confidence"] * 100))
|
||||||
|
|
||||||
|
embed.add_field(name="Origineel ({})".format(translation.src.upper()), value=query, inline=False)
|
||||||
|
embed.add_field(name="Vertaling ({})".format(to.upper()), value=translation.text)
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
except ValueError as e:
|
||||||
|
message = str(e)
|
||||||
|
if "destination" in message:
|
||||||
|
return await ctx.send("{} is geen geldige taal.".format(tc(to)))
|
||||||
|
|
||||||
|
if "source" in message:
|
||||||
|
return await ctx.send("{} is geen geldige taal.".format(tc(fr)))
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
@commands.command(name="Detect", aliases=["Ld"], usage="[Tekst]")
|
||||||
|
@help.Category(Category.Words)
|
||||||
|
async def detect(self, ctx, query=None):
|
||||||
|
if query is None:
|
||||||
|
return await ctx.send("Controleer je argumenten.")
|
||||||
|
|
||||||
|
success, query = await self.getQuery(ctx, query)
|
||||||
|
if not success:
|
||||||
|
return await ctx.send(query)
|
||||||
|
|
||||||
|
translator = Translator()
|
||||||
|
language = translator.detect(query)
|
||||||
|
|
||||||
|
confidence = language.confidence * 100
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Language Detection")
|
||||||
|
embed.add_field(name="Zin", value=query, inline=False)
|
||||||
|
embed.add_field(name="Gedetecteerde taal", value=tc(LANGUAGES[language.lang]))
|
||||||
|
embed.add_field(name="Zekerheid", value="{}%".format(confidence))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
async def getQuery(self, ctx, query):
|
||||||
|
# Check if it's a link to a message
|
||||||
|
if re.match(r"^https://discord.com/channels/[0-9A-Za-z@]+/[0-9]+/[0-9]+$", query):
|
||||||
|
spl = query.split("/")
|
||||||
|
channel = self.client.get_channel(int(spl[-2]))
|
||||||
|
if channel is None:
|
||||||
|
return False, "Ik kan geen kanaal zien met dit id."
|
||||||
|
|
||||||
|
message = await channel.fetch_message(spl[-1])
|
||||||
|
if message is None:
|
||||||
|
return False, "Ik kan geen bericht zien met dit id."
|
||||||
|
|
||||||
|
query = message.content
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# An id was passed instead
|
||||||
|
query = int(query)
|
||||||
|
message = await ctx.channel.fetch_message(query)
|
||||||
|
if message is None:
|
||||||
|
return False, "Ik kan geen bericht zien met dit id."
|
||||||
|
query = message.content
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not query:
|
||||||
|
return False, "Dit is geen geldig bericht."
|
||||||
|
|
||||||
|
return True, query
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Translate(client))
|
|
@ -0,0 +1,67 @@
|
||||||
|
from data import constants
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from decorators import help
|
||||||
|
from enums.help_categories import Category
|
||||||
|
|
||||||
|
|
||||||
|
class Utils(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
self.client.locked = False
|
||||||
|
self.client.lockedUntil = -1
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
# Marco Polo to check if bot is running & delay
|
||||||
|
@commands.command(name="Marco")
|
||||||
|
@help.Category(category=Category.Didier)
|
||||||
|
async def marco(self, ctx):
|
||||||
|
await ctx.send("Polo! {}ms".format(round(self.client.latency * 1000)))
|
||||||
|
|
||||||
|
async def removeMessage(self, message):
|
||||||
|
try:
|
||||||
|
await message.delete()
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Send a DM to a user
|
||||||
|
async def sendDm(self, userid, message: str):
|
||||||
|
user = self.client.get_user(int(userid))
|
||||||
|
await user.send(message)
|
||||||
|
|
||||||
|
# Send an Embed to a user
|
||||||
|
async def sendEmbed(self, userid, embed):
|
||||||
|
await discord.utils.get(self.client.get_all_members(), id=int(userid)).send(embed=embed)
|
||||||
|
|
||||||
|
# Returns a member object of a user
|
||||||
|
def getMember(self, ctx, memberid):
|
||||||
|
if str(ctx.channel.type) == "private" or ctx.guild.get_member(int(memberid)) is None:
|
||||||
|
if str(memberid) == str(ctx.author.id):
|
||||||
|
return ctx.author
|
||||||
|
COC = self.client.get_guild(int(constants.CallOfCode))
|
||||||
|
return COC.get_member(int(memberid))
|
||||||
|
|
||||||
|
return ctx.guild.get_member(int(memberid))
|
||||||
|
|
||||||
|
# Returns a user's display name if he's in this server, else COC
|
||||||
|
def getDisplayName(self, ctx, memberid):
|
||||||
|
# Checks if this is a DM, or the user is not in the guild
|
||||||
|
if str(ctx.channel.type) == "private" or ctx.guild.get_member(int(memberid)) is None:
|
||||||
|
if str(memberid) == str(ctx.author.id):
|
||||||
|
return ctx.author.display_name
|
||||||
|
COC = self.client.get_guild(int(constants.CallOfCode))
|
||||||
|
member = COC.get_member(int(memberid))
|
||||||
|
if member is not None:
|
||||||
|
return member.display_name
|
||||||
|
return "[Persoon die de server misschien geleaved is]"
|
||||||
|
|
||||||
|
mem = ctx.guild.get_member(int(memberid))
|
||||||
|
return mem.display_name
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Utils(client))
|
|
@ -0,0 +1,52 @@
|
||||||
|
from decorators import help
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Words(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
# Don't allow any commands to work when locked
|
||||||
|
def cog_check(self, ctx):
|
||||||
|
return not self.client.locked
|
||||||
|
|
||||||
|
@commands.command(name="Adjective", aliases=["Adj", "Adjectives"], usage="[Woord]")
|
||||||
|
@help.Category(category=Category.Words)
|
||||||
|
async def adjective(self, ctx, word=None):
|
||||||
|
await self.getData(ctx, word, "rel_jjb")
|
||||||
|
|
||||||
|
@commands.command(name="Synonym", aliases=["Syn", "Synonyms"], usage="[Woord]")
|
||||||
|
@help.Category(category=Category.Words)
|
||||||
|
async def synonym(self, ctx, word=None):
|
||||||
|
await self.getData(ctx, word, "rel_syn")
|
||||||
|
|
||||||
|
@commands.command(name="Antonym", aliases=["Ant", "Antonyms", "Opp", "Opposite"], usage="[Woord]")
|
||||||
|
@help.Category(category=Category.Words)
|
||||||
|
async def antonym(self, ctx, word=None):
|
||||||
|
await self.getData(ctx, word, "rel_ant")
|
||||||
|
|
||||||
|
@commands.command(name="Rhyme", aliases=["Rhymes"], usage="[Woord]")
|
||||||
|
@help.Category(category=Category.Words)
|
||||||
|
async def rhyme(self, ctx, word=None):
|
||||||
|
await self.getData(ctx, word, "rel_rhy")
|
||||||
|
|
||||||
|
# Contacts the API & returns the response, as these commands all do the same anyways
|
||||||
|
async def getData(self, ctx, word, relation):
|
||||||
|
if not word:
|
||||||
|
await ctx.send("Geef een woord op.")
|
||||||
|
return
|
||||||
|
|
||||||
|
res = requests.get("https://api.datamuse.com/words?{}={}".format(relation, word)).json()
|
||||||
|
|
||||||
|
# Only show top 20 results
|
||||||
|
res = res if len(res) <= 15 else res[:15]
|
||||||
|
|
||||||
|
# Pull the words out of the dicts
|
||||||
|
res = [word["word"] for word in res]
|
||||||
|
await ctx.send(", ".join(res) if len(res) > 0 else "Geen resultaten gevonden.")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Words(client))
|
|
@ -0,0 +1,41 @@
|
||||||
|
from data import constants
|
||||||
|
from decorators import help
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from enums.help_categories import Category
|
||||||
|
from functions import checks, xp
|
||||||
|
from functions.database import stats
|
||||||
|
|
||||||
|
|
||||||
|
class Xp(commands.Cog):
|
||||||
|
def __init__(self, client):
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
@commands.group(name="Xp", aliases=["Level", "Mc", "Mess", "Messages"], case_insensitive=True, invoke_without_command=True)
|
||||||
|
@commands.check(checks.allowedChannels)
|
||||||
|
@help.Category(Category.Other)
|
||||||
|
async def xp(self, ctx, user: discord.Member = None):
|
||||||
|
if user is not None and str(ctx.author.id) != constants.myId:
|
||||||
|
return await ctx.send("Je hebt geen toegang tot dit commando.")
|
||||||
|
|
||||||
|
target = user if user is not None else ctx.author
|
||||||
|
|
||||||
|
target_stats = stats.getOrAddUser(target.id)
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name=target.display_name, icon_url=target.avatar_url)
|
||||||
|
embed.add_field(name="Aantal Berichten", value="{}".format(int(target_stats[11])))
|
||||||
|
embed.add_field(name="Level", value=str(xp.calculate_level(target_stats[12])))
|
||||||
|
embed.add_field(name="XP", value="{:,}".format(int(target_stats[12])))
|
||||||
|
embed.set_footer(text="*Sinds Didier 2.0 Launch")
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@xp.command(name="Leaderboard", aliases=["Lb"], hidden=True)
|
||||||
|
async def xpleaderboard(self, ctx, *args):
|
||||||
|
if any(alias in ctx.message.content for alias in ["mc", "mess", "messages"]):
|
||||||
|
return await self.client.get_cog("Leaderboards").callLeaderboard("Messages", ctx)
|
||||||
|
await self.client.get_cog("Leaderboards").callLeaderboard("Xp", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client):
|
||||||
|
client.add_cog(Xp(client))
|
|
@ -0,0 +1,67 @@
|
||||||
|
import re
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
|
||||||
|
# Gets the numerical value of a string representation like 1.6k
|
||||||
|
def abbreviated(rep):
|
||||||
|
if rep.lower() == "all":
|
||||||
|
return rep
|
||||||
|
|
||||||
|
validMatch = r"^-?[0-9]+\.?[0-9]*[A-Za-z]*$"
|
||||||
|
numericalValue = r"^-?[0-9]+\.?[0-9]*"
|
||||||
|
indicator = r"[A-Za-z]*$"
|
||||||
|
|
||||||
|
valid = re.match(validMatch, rep)
|
||||||
|
|
||||||
|
# Invalid representation
|
||||||
|
if not valid:
|
||||||
|
return None
|
||||||
|
|
||||||
|
numerical = re.search(numericalValue, rep)
|
||||||
|
|
||||||
|
# Invalid number
|
||||||
|
if float(numerical[0]) == 0.0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
indic = re.search(indicator, rep)
|
||||||
|
if not indic[0]:
|
||||||
|
try:
|
||||||
|
return int(rep)
|
||||||
|
except ValueError:
|
||||||
|
# If no indicator was passed, it has to be a whole number
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Invalid indicator
|
||||||
|
if indic[0] not in exponents() and not any(exp.lower() == indic[0].lower() for exp in exponents()):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if indic[0] in exponents():
|
||||||
|
try:
|
||||||
|
return int(float(numerical[0]) * int("1" + ("0" * (exponents().index(indic[0]) + 1) * 3)))
|
||||||
|
except ValueError:
|
||||||
|
# Can't be cast to int
|
||||||
|
return None
|
||||||
|
|
||||||
|
for i, exponent in enumerate(exponents()):
|
||||||
|
if exponent.lower() == indic[0].lower():
|
||||||
|
try:
|
||||||
|
return int(float(numerical[0]) * int("1" + ("0" * (i + 1) * 3)))
|
||||||
|
except ValueError:
|
||||||
|
# Can't be cast to int
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Abbreviated(commands.Converter):
|
||||||
|
async def convert(self, ctx, argument):
|
||||||
|
if argument is None:
|
||||||
|
return None
|
||||||
|
converted = abbreviated(argument)
|
||||||
|
if converted is None:
|
||||||
|
await ctx.send("Dit is geen geldig getal.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return converted
|
||||||
|
|
||||||
|
|
||||||
|
def exponents():
|
||||||
|
return ["K", "M", "B", "t", "q", "Q", "s", "S", "o", "n", "d", "U", "D", "T", "Qt", "Qd", "Sd", "St", "O", "N", "v"]
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Creating Commands
|
||||||
|
|
||||||
|
The following document shows you how to create new commands, which kwargs to add, and what they do.
|
||||||
|
|
||||||
|
Make sure to properly register the appropriate help decorator to each command. More info on help decorators in `readme.md`.
|
||||||
|
|
||||||
|
Do _NOT_ create commands outside of `Cogs`!
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
Commands require a set list of kwargs in order to work correctly, and show up in the help page.
|
||||||
|
|
||||||
|
- Name: The name of the command, with only the first letter capitalised.
|
||||||
|
- Aliases: Optional, a list of all aliases the command can have. Make sure to check if the alias already exists (if not, Discord will throw an error when starting the bot.)
|
||||||
|
|
||||||
|
Aliases should only have the first letter capitalised, and be placed in alphabetical order.
|
||||||
|
- Usage: Optional, only required when the command takes arguments. Show how the command has to be used. Arguments should be placed between \[square brackets\], and optional arguments need an asterisk* after the brackets.
|
||||||
|
- Hidden: Optional, should only be added when you _don't_ want the command to show up in the help page.
|
||||||
|
- Ignore_Extra: Optional, should only be used when you want to ignore extra arguments passed into the function.
|
||||||
|
|
||||||
|
##### Checks
|
||||||
|
Further, checks can be added to commands to make sure the function only executes in certain situations. There are already a few [built-in checks](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html?highlight=checks#checks) to do commonly-used things, but you can easily create your own functions to do this.
|
||||||
|
|
||||||
|
New checks should be added to `/functions/checks.py`. Checks are just a basic function that returns `True` or `False`, and takes `ctx` as a parameter.
|
||||||
|
|
||||||
|
The example below shows how to create a command that only takes 1 required argument, 1 optional argument, and does not show up in the help page. The `check` makes sure the command does not work in DM's.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def check(ctx):
|
||||||
|
return ctx.guild is not None
|
||||||
|
|
||||||
|
@commands.command(name="Name", aliases=["N"], usage=["[Arg], [Arg2]*"], hidden=True, ignore_extra=True)
|
||||||
|
@commands.check(check=check)
|
||||||
|
async def name(ctx, arg, arg2=None):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Groups
|
||||||
|
|
||||||
|
It's possible that you might want to create subcommands for a certain command. At first glance, you might want to do something like this:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@commands.command()
|
||||||
|
async def parent_command(ctx, arg):
|
||||||
|
if arg == "sub1":
|
||||||
|
await sub1()
|
||||||
|
elif arg == "sub2":
|
||||||
|
await sub2()
|
||||||
|
...
|
||||||
|
|
||||||
|
async def sub1():
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def sub2():
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Looking at this you might think that there must be a better way to do this, and there is. The only situation where this type of code will be accepted, is when there are too many possible subcommands to the point where it's not really doable to create all of them (think help & faq categories).
|
||||||
|
Discord.py has implemented [Command Groups](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html?highlight=group#discord.ext.commands.Group) for this purpose. Groups allow you to register commands to other commands in order to create subcommands (or even subgroups!).
|
||||||
|
|
||||||
|
Groups _do_ have a few extra kwargs on top of the usual `Command Kwargs` mentioned above:
|
||||||
|
|
||||||
|
- case_insensitive: Indicates whether or not subcommands should be case-insensitive (think `lb dinks` and `lb DINKS`). You are *required* to set this parameter to `True` so Didier will always work case-insensitively.
|
||||||
|
- invoke_without_command: Indicates whether or not the group command should only execute if no subcommand was found. In most cases, this will be `True`.
|
||||||
|
|
||||||
|
The example below shows how to create a group so that `Didier A B D` will execute `b("D")`, but `Didier A C` will execute `a("C")`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@commands.group(name="A", usage="[Args]", case_insensitive=True, invoke_without_command=True)
|
||||||
|
async def a(ctx, args):
|
||||||
|
print(args)
|
||||||
|
# Prints "C"
|
||||||
|
|
||||||
|
@a.command(name="B")
|
||||||
|
async def b(ctx, args):
|
||||||
|
print(args)
|
||||||
|
# Prints "D"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unpacking Groups
|
||||||
|
|
||||||
|
It's possible that you want to create a group to organise subcommands, but want the subcommands to be listed in the category instead of under the group (or when the Cog and Group have the same name). An example is Didier's `Random` module.
|
||||||
|
|
||||||
|
When creating a group without doing anything, the help page will look like this:
|
||||||
|
|
||||||
|
Categories:
|
||||||
|
Currency
|
||||||
|
...
|
||||||
|
Random (category)
|
||||||
|
...
|
||||||
|
|
||||||
|
Help Random (category):
|
||||||
|
Random (group)
|
||||||
|
|
||||||
|
Help Random (group):
|
||||||
|
Random Choice
|
||||||
|
...
|
||||||
|
|
||||||
|
This requires an unnecessary step to get to the commands (as there's only 1 result), and it would be nicer to have all subcommands list in the category instead. Seeing as the Cog & Group both have the same name, it also feels weird to do this (and would be near impossible to code in a user-friendly way). When the Cog has the same name, you expect all the commands to be right there immediately.
|
||||||
|
|
||||||
|
The `Help Decorator` has an optional argument that can do this for you. When registering a group to a category, you can add `unpack=True` in order to accomplish this.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@commands.group(name="Random")
|
||||||
|
@help.Category(Category.Random, unpack=True)
|
||||||
|
async def random(self, ctx):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
This way, the help page will look like this:
|
||||||
|
|
||||||
|
Random (category):
|
||||||
|
Random Choice
|
||||||
|
...
|
||||||
|
|
||||||
|
### Testing & Messing Around
|
||||||
|
In case you want to quickly test 1 line of code, or test a quick idea, you'd have to create an entire Cog just to use once. With the Cog Template this is not _that_ bad, but it's still a bit cumbersome.
|
||||||
|
|
||||||
|
For this purpose, there is a Cog called `testCog.py`, with 1 command (`Test()`). Slap your code in there, and use `Didier Test` in Discord. Just remember to never commit these changes (right click in the file manager -> `Git` -> `Rollback`).
|
|
@ -0,0 +1,55 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
myId = "171671190631481345"
|
||||||
|
didierId = "680510935164911730"
|
||||||
|
botIDs = [
|
||||||
|
"155149108183695360",
|
||||||
|
"234395307759108106",
|
||||||
|
"239631525350604801",
|
||||||
|
"408785106942164992",
|
||||||
|
"679679176466235399",
|
||||||
|
"680510935164911730",
|
||||||
|
"706148003949314069",
|
||||||
|
"728361496874057812"
|
||||||
|
]
|
||||||
|
BugReports = "762668401960812554"
|
||||||
|
CallOfCode = "626699611192688641"
|
||||||
|
CoCGeneral = "626699611813314561"
|
||||||
|
DeZandbak = "728361030404538488"
|
||||||
|
ErrorLogs = "762668505455132722"
|
||||||
|
FeatureRequests = "762668473313787964"
|
||||||
|
|
||||||
|
mods = {
|
||||||
|
626699611192688641: [384457911377854467, 171671190631481345],
|
||||||
|
728361030404538488: [171671190631481345],
|
||||||
|
689200072268841106: [332948151226990614, 171671190631481345, 280025474485321729, 237239312385703951],
|
||||||
|
710515840566427721: [171671190631481345, 140186024075722752, 296197359539585024]
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedChannels = {
|
||||||
|
"bot-games": 634327239361691658,
|
||||||
|
"bot-commands": 629034637955694602,
|
||||||
|
"bot-testing": 679701786189103106,
|
||||||
|
"shitposting": 676713433567199232,
|
||||||
|
"didier-testings": 689202224437395573,
|
||||||
|
"freegames": 705745297908826113,
|
||||||
|
"bot-commandsCOCGI": 714170653124722738,
|
||||||
|
"generalZandbak": 728361031008780422,
|
||||||
|
"freegamesZandbak": 728545397127118898
|
||||||
|
}
|
||||||
|
|
||||||
|
creationDate = 1582243200
|
||||||
|
|
||||||
|
holidayAPIKey = "af4e1ebe-465d-4b93-a828-b95df18e6424"
|
||||||
|
|
||||||
|
|
||||||
|
class Live(Enum):
|
||||||
|
CallOfCode = "626699611192688641"
|
||||||
|
DidierPosting = "728361031008780422"
|
||||||
|
General = "626699611813314561"
|
||||||
|
|
||||||
|
|
||||||
|
class Zandbak(Enum):
|
||||||
|
CallOfCode = "728361030404538488"
|
||||||
|
DidierPosting = "728361031008780422"
|
||||||
|
General = "728361031008780422"
|
|
@ -0,0 +1,31 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import menus
|
||||||
|
|
||||||
|
|
||||||
|
# https://github.com/Rapptz/discord-ext-menus
|
||||||
|
class Source(menus.ListPageSource):
|
||||||
|
def __init__(self, data, name, colour=discord.Colour.blue()):
|
||||||
|
super().__init__(data, per_page=10)
|
||||||
|
self.name = name
|
||||||
|
self.colour = colour
|
||||||
|
|
||||||
|
async def format_page(self, menu: menus.MenuPages, entries):
|
||||||
|
offset = menu.current_page * self.per_page
|
||||||
|
|
||||||
|
description = ""
|
||||||
|
for i, v in enumerate(entries, start=offset):
|
||||||
|
# Check if the person's name has to be highlighted
|
||||||
|
if v.startswith("**") and v.endswith("**"):
|
||||||
|
description += "**"
|
||||||
|
v = v[2:]
|
||||||
|
description += "{}: {}\n".format(i + 1, v)
|
||||||
|
embed = discord.Embed(colour=self.colour)
|
||||||
|
embed.set_author(name=self.name)
|
||||||
|
embed.description = description
|
||||||
|
embed.set_footer(text="{}/{}".format(menu.current_page + 1, self.get_max_pages()))
|
||||||
|
return embed
|
||||||
|
|
||||||
|
|
||||||
|
class Pages(menus.MenuPages):
|
||||||
|
def __init__(self, source, clear_reactions_after, timeout=30.0):
|
||||||
|
super().__init__(source, timeout=timeout, delete_message_after=True, clear_reactions_after=clear_reactions_after)
|
|
@ -0,0 +1,28 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import menus
|
||||||
|
|
||||||
|
|
||||||
|
# https://github.com/Rapptz/discord-ext-menus
|
||||||
|
class Source(menus.ListPageSource):
|
||||||
|
def __init__(self, data):
|
||||||
|
super().__init__(data, per_page=10)
|
||||||
|
self.name = "Didier Store"
|
||||||
|
self.colour = discord.Colour.blue()
|
||||||
|
|
||||||
|
async def format_page(self, menu: menus.MenuPages, entries):
|
||||||
|
offset = menu.current_page * self.per_page
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=self.colour)
|
||||||
|
embed.set_author(name=self.name)
|
||||||
|
embed.description = "Heb je een idee voor een item? DM DJ STIJN met je idee!"
|
||||||
|
embed.set_footer(text="{}/{}".format(menu.current_page + 1, self.get_max_pages()))
|
||||||
|
|
||||||
|
for i, v in enumerate(entries, start=offset):
|
||||||
|
embed.add_field(name="#{} - {}".format(v[0], v[1]), value="{:,} Didier Dinks".format(v[2]))
|
||||||
|
|
||||||
|
return embed
|
||||||
|
|
||||||
|
|
||||||
|
class Pages(menus.MenuPages):
|
||||||
|
def __init__(self, source, clear_reactions_after, timeout=30.0):
|
||||||
|
super().__init__(source, timeout=timeout, delete_message_after=True, clear_reactions_after=clear_reactions_after)
|
|
@ -0,0 +1,166 @@
|
||||||
|
# Databases
|
||||||
|
|
||||||
|
The following file contains a list of all PSQL tables Didier uses. Every table has a description on when/where it is used, which columns it contains, and what type of value those columns hold.
|
||||||
|
|
||||||
|
The schemes below can also help you figure out which index corresponds to which column.
|
||||||
|
|
||||||
|
This should be enough for you to set up a local PSQL database to test your code in.
|
||||||
|
|
||||||
|
Keep in mind that you can create and edit SQL databases in PyCharm, so that you don't have to write any SQL statements yourself. This also makes it _a lot_ easier to change the behaviour of a column.
|
||||||
|
|
||||||
|
### birthdays
|
||||||
|
|
||||||
|
Used in birthdays.py - Birthay commands & the daily Task that checks if it's anyone's birthday.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The Discord id of the user
|
||||||
|
1 day: integer | The day of the user's birthday
|
||||||
|
2 month: integer | The month of the user's birthday
|
||||||
|
3 year: integer | The year of the user's birthday
|
||||||
|
|
||||||
|
### channel_activity
|
||||||
|
|
||||||
|
Used in stats.py - Stats.Channels & the daily task that updates the message count. Keeps track of the amount of messages sent in every channel.
|
||||||
|
|
||||||
|
0 channel_id: bigint, unique, primary key | The channel id of this channel
|
||||||
|
1 message_count: numeric | The amount of messages sent in this channel
|
||||||
|
|
||||||
|
### currencytable
|
||||||
|
|
||||||
|
Used in all Currency commands (Dinks, Bank, Bitcoin, Gambling, ...)
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The Discord id of the user
|
||||||
|
1 dinks: numeric, default 0.0 | The amount of Didier Dinks the user has
|
||||||
|
2 banklevel: integer, default 1 | The user's bank level
|
||||||
|
3 investedamount: numeric, default 0.0 | The amount of Didier Dinks the user has currently invested
|
||||||
|
4 investeddays: integer, default 0 | The amount of days the user has invested in their bank
|
||||||
|
5 profit: numeric, default 0.0 | The current amount of profit the user has gained from interest
|
||||||
|
6 defense: integer, default 1 | The user's bank's defense level
|
||||||
|
7 offense: integer, default 1 | The user's bank's offense level
|
||||||
|
8 bitcoins: numeric, default 0.0 | The amount of Bitcoins the user currently has
|
||||||
|
9 nightly: integer, default 0 | The timestamp when the user last claimed their Nightly
|
||||||
|
10 nightly_streak: integer, default 0 | The user's current Nightly Streak
|
||||||
|
|
||||||
|
### dad_jokes
|
||||||
|
|
||||||
|
Used in fun.py - Dadjoke command.
|
||||||
|
|
||||||
|
0 id: integer, auto-increment, unique, primary key | The id of the joke
|
||||||
|
1 joke: text | The joke itself
|
||||||
|
|
||||||
|
### faq_categories
|
||||||
|
|
||||||
|
Used in faq.py - FAQ commands, provides a list of valid categories.
|
||||||
|
|
||||||
|
0 id: integer, auto-increment, unique, primary key | The id of the category
|
||||||
|
1 name: text | The name of the category
|
||||||
|
|
||||||
|
### faq_entries
|
||||||
|
|
||||||
|
Used in faq.py - FAQ commands, provides a list of entries for every category.
|
||||||
|
|
||||||
|
0 id: integer, auto-increment, unique, primary key | The id of this entry
|
||||||
|
1 category_id: integer | The id of the category this entry belongs to
|
||||||
|
2 question: text | The question of this entry
|
||||||
|
3 answer: text | The answer for this entry
|
||||||
|
4 answer_markdown: text, default null | A variant of the answer supporting markdown which are possible in embeds, but not normal messages (like hyperlinks).
|
||||||
|
|
||||||
|
### githubs
|
||||||
|
|
||||||
|
Used in selfpromo.py - Github commands.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The user's Discord id
|
||||||
|
1 githublink: text | A string containing the links to the user's Git pages, separated by newlines
|
||||||
|
|
||||||
|
### info
|
||||||
|
|
||||||
|
Used in poke.py - Poke commands. Used to store specific info for users, currently only whether or not they've blacklisted themselves.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The user's Discord id
|
||||||
|
1 poke_blacklist: boolean, default false | A boolean indicating whether or not the user has blacklisted themself
|
||||||
|
|
||||||
|
### inventory
|
||||||
|
|
||||||
|
Used in store.py - Store commands, and dinks.py - Dinks commands. Holds a list of all items a user has, the item's id's & counts
|
||||||
|
|
||||||
|
0 userid: bigint | The user's Discord id
|
||||||
|
1 itemid: integer | The id of the item the user has bought
|
||||||
|
2 amount: integer, default 0 | The amount of this item the user possesses
|
||||||
|
|
||||||
|
### memes
|
||||||
|
|
||||||
|
Used in fun.py - Meme commands. Contains all info about a certain meme to generate it via the API.
|
||||||
|
|
||||||
|
0 id: bigint | The id of the meme
|
||||||
|
1 name: text | The name of the meme, lowercase
|
||||||
|
2 fields: integer | The amount of fields the meme has
|
||||||
|
|
||||||
|
### muttn
|
||||||
|
|
||||||
|
Used in events.py - Reaction events, and muttn.py - Muttn commands.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The user's Discord id
|
||||||
|
1 stats: numeric | The user's muttn percentage
|
||||||
|
2 count: integer | The amount of muttn reacts the user has received
|
||||||
|
3 message: bigint | The id of the last message the user got an increase by
|
||||||
|
4 highest: integer, default 0 | The highest amount of reacts the user's last message had, avoiding spam abuse
|
||||||
|
|
||||||
|
### personalstats
|
||||||
|
|
||||||
|
Used in stats.py - Stats commands. Tracks the user's personal stats to award achievements.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The user's Discord id
|
||||||
|
1 poked: integer, default 0 | The amount of times the user has been poked
|
||||||
|
2 robs_success: integer, default 0 | The user's amount of successful robs
|
||||||
|
3 robs_failed: integer, default 0 | The user's amount of failed robs
|
||||||
|
4 robs_total: numeric, default 0.0 | The total amount of Didier Dinks the user has robbed
|
||||||
|
5 longest_streak: integer, default 0 | The longest nightly streak the user has achieved
|
||||||
|
6 nightlies_count: integer, default 0 | The total amount of Nightlies the user has claimed
|
||||||
|
7 profit: numeric, default 0.0 | The total amount of profit the user has claimed
|
||||||
|
8 cf_wins: integer, default 0 | The amount of coinflips the user has won
|
||||||
|
9 cf_profit: numeric, default 0.0 | The amount of profit the user has made with coinflips
|
||||||
|
10 bails: integer, default 0 | The amount of times the user has bailed themselves out
|
||||||
|
11 messages: integer, default 0 | The amount of messages the user has sent
|
||||||
|
12 xp: bigint, default 0 | The amount of message xp the user has gained
|
||||||
|
13 last_message: bigint, default 0 | The timestamp of the user's last message that awarded xp
|
||||||
|
|
||||||
|
### poke
|
||||||
|
|
||||||
|
Used in poke.py - Poke commands. Keeps track of the currently poked person.
|
||||||
|
|
||||||
|
0 current: bigint | The Discord id of the person that is currently poked
|
||||||
|
1 poketime: bigint | The timestamp of when the user was poked
|
||||||
|
2 previous: bigint | The Discord id of the previously poked user
|
||||||
|
|
||||||
|
### prison
|
||||||
|
|
||||||
|
Used in dinks.py - Prison commands. Contains information on who is in prison.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The user's Discord id
|
||||||
|
1 bail: numeric | The cost to bail this user out of prison
|
||||||
|
2 days: integer | The remaining days this user has to spend in prison
|
||||||
|
3 daily: numeric | The amount of Didier Dinks that [daily] decreases by every day
|
||||||
|
|
||||||
|
### store
|
||||||
|
|
||||||
|
Used in store.py - Store commands. Contains info on items that are available for purchase.
|
||||||
|
|
||||||
|
0 itemid: integer, auto-increment, primary key | The item's id
|
||||||
|
1 name: text | The name of the item
|
||||||
|
2 price: bigint | The price of the item
|
||||||
|
3 limit: integer | The item's buy limit
|
||||||
|
|
||||||
|
### trump
|
||||||
|
|
||||||
|
Used in oneliners.py - Trump command. Stores a list of Trump quotes.
|
||||||
|
|
||||||
|
0 id: integer, auto-increment, primary key | The quote's id
|
||||||
|
1 quote: text | The quote itself
|
||||||
|
2 date: text | The date on which the quote was said
|
||||||
|
3 location: text | The location and/or event where the quote was said
|
||||||
|
|
||||||
|
### twitch
|
||||||
|
|
||||||
|
Used in selfpromo.py - Twitch commands. Contains a list of everyone's Twitch links.
|
||||||
|
|
||||||
|
0 userid: bigint, unique, primary key | The user's Discord id
|
||||||
|
1 link: text | The link to the user's Twitch channel
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Decorator that assigns a help category to a function
|
||||||
|
def Category(category, unpack=False):
|
||||||
|
def decorator(func):
|
||||||
|
setattr(func, "category", category)
|
||||||
|
setattr(func, "unpack", unpack)
|
||||||
|
return func
|
||||||
|
return decorator
|
|
@ -0,0 +1,38 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
load_dotenv(verbose=True)
|
||||||
|
|
||||||
|
|
||||||
|
# All possible prefixes
|
||||||
|
# When_mentioned_or doesn't count for spaces so can't use that
|
||||||
|
prefixes = ["didier ", "Didier ", "DIDIER ", "big d ", "<@!680510935164911730> ",
|
||||||
|
"didier", "Didier", "DIDIER", "big d", "<@!680510935164911730>"]
|
||||||
|
|
||||||
|
# Configure intents (1.5.0)
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.members = True
|
||||||
|
|
||||||
|
client = commands.Bot(command_prefix=prefixes, case_insensitive=True, intents=intents)
|
||||||
|
client.prefixes = prefixes
|
||||||
|
|
||||||
|
# Remove default help because it sucks & I made my own
|
||||||
|
client.remove_command("help")
|
||||||
|
|
||||||
|
# Load utils first so it can be used in other places & it's not None
|
||||||
|
client.load_extension("cogs.utils")
|
||||||
|
client.load_extension("cogs.failedchecks")
|
||||||
|
client.load_extension("cogs.events")
|
||||||
|
|
||||||
|
# Load all remaining cogs
|
||||||
|
for file in os.listdir("./cogs"):
|
||||||
|
if file.endswith(".py") and not (file.startswith(("utils", "failedchecks", "events"),)):
|
||||||
|
client.load_extension("cogs.{}".format(file[:-3]))
|
||||||
|
|
||||||
|
# Get the token out of the file & run the bot
|
||||||
|
with open("files/client.txt", "r") as fp:
|
||||||
|
token = fp.readline()
|
||||||
|
client.run(token)
|
|
@ -0,0 +1,25 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class Ba1(Enum):
|
||||||
|
Computergebruik = {"year": 1, "semester": 1, "id": 727820944478961685, "name": "Computergebruik"}
|
||||||
|
Databanken = {"year": 1, "semester": 1, "id": 727823858660540466, "name": "Databanken"}
|
||||||
|
Diwi = {"year": 1, "semester": 1, "id": 727824165989777478, "name": "Discrete Wiskunde"}
|
||||||
|
Programmeren = {"year": 1, "semester": 1, "id": 727824450409594900, "name": "Programmeren"}
|
||||||
|
RAF = {"year": 1, "semester": 1, "id": 727824527882715138, "name": "RAF"}
|
||||||
|
AD1 = {"year": 1, "semester": 2, "id": 727828011407245322, "name": "AD 1"}
|
||||||
|
Calculus = {"year": 1, "semester": 2, "id": 727827760566763601, "name": "Calculus"}
|
||||||
|
LAM = {"year": 1, "semester": 2, "id": 727827533881409589, "name": "LAM"}
|
||||||
|
OGProg = {"year": 1, "semester": 2, "id": 727827620548444160, "name": "Objectgericht Programmeren"}
|
||||||
|
Scriptingtalen = {"year": 1, "semester": 2, "id": 727823849034350623, "name": "Scriptingtalen"}
|
||||||
|
|
||||||
|
|
||||||
|
class Ba2(Enum):
|
||||||
|
AD2 = {"year": 2, "semester": 1, "id": 727877341539205190, "name": "AD 2"}
|
||||||
|
CommNet = {"year": 2, "semester": 1, "id": 727879794892734531, "name": "Communicatienetwerken"}
|
||||||
|
FuncProg = {"year": 2, "semester": 1, "id": 727879279622225920, "name": "Functioneel Programmeren"}
|
||||||
|
StatProb = {"year": 2, "semester": 1, "id": 727879946458103880, "name": "Statistiek en Probabiliteit"}
|
||||||
|
SysProg = {"year": 2, "semester": 1, "id": 727880036644028517, "name": "Systeemprogrammeren"}
|
||||||
|
|
||||||
|
|
||||||
|
years = [Ba1, Ba2]
|
|
@ -0,0 +1,36 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class Category(Enum):
|
||||||
|
Currency = "Currency"
|
||||||
|
Didier = "Didier"
|
||||||
|
Fun = "Fun"
|
||||||
|
Gamble = "Gamble"
|
||||||
|
Games = "Games"
|
||||||
|
Mod = "Mod"
|
||||||
|
Other = "Other"
|
||||||
|
Quotes = "Quotes"
|
||||||
|
Random = "Random"
|
||||||
|
School = "School"
|
||||||
|
Sports = "Sports"
|
||||||
|
Words = "Words"
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a list of all categories (names)
|
||||||
|
def categories(is_mod=False):
|
||||||
|
cat = [e.value for e in Category]
|
||||||
|
# Don't show mod commands to random people
|
||||||
|
if is_mod:
|
||||||
|
return cat
|
||||||
|
cat.remove(Category.Mod.value)
|
||||||
|
return cat
|
||||||
|
|
||||||
|
|
||||||
|
# Gets the Enum associated with a term
|
||||||
|
def getCategory(term, is_mod=False):
|
||||||
|
for category in Category:
|
||||||
|
if category.value.lower() == term.lower():
|
||||||
|
# Check if user is trying to access mod commands
|
||||||
|
if category != Category.Mod or (category == Category.Mod and is_mod):
|
||||||
|
return category
|
||||||
|
return None
|
|
@ -0,0 +1,24 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class Numbers(Enum):
|
||||||
|
K = 1000
|
||||||
|
M = 1000000
|
||||||
|
B = 1000000000
|
||||||
|
t = 1000000000000
|
||||||
|
q = 1000000000000000
|
||||||
|
Q = 1000000000000000000
|
||||||
|
s = 1000000000000000000000
|
||||||
|
S = 1000000000000000000000000
|
||||||
|
|
||||||
|
|
||||||
|
def getRep(number):
|
||||||
|
number = int(number)
|
||||||
|
best = None
|
||||||
|
for entry in Numbers:
|
||||||
|
if entry.value <= number:
|
||||||
|
best = entry
|
||||||
|
else:
|
||||||
|
return str(round(number//best.value)) + best.name
|
||||||
|
|
||||||
|
return number
|
|
@ -0,0 +1,5 @@
|
||||||
|
# FAQ
|
||||||
|
Answers to Frequently Asked Questions.
|
||||||
|
|
||||||
|
### Table of Contents
|
||||||
|
A list of all questions (in order) so you can easily find what you're looking for.
|
|
@ -0,0 +1,35 @@
|
||||||
|
[
|
||||||
|
"It's all fun and games until you hail Satan, then it's a party.",
|
||||||
|
"Sinning is winning.",
|
||||||
|
"Hell is filled with billions of people yet I feel so alone.",
|
||||||
|
"If you ever feel alone; watch a horror movie late at night with the lights off. You won't feel so alone anymore.",
|
||||||
|
"Someone sacrifice a pizza or something I'm getting bored of goats.",
|
||||||
|
"I miss you, son @realDonaldTrump",
|
||||||
|
"I keep getting christmas lists from dyslexic kids.",
|
||||||
|
"You're adopted",
|
||||||
|
"Suicide is never the answer. You gotta outlive your enemies.",
|
||||||
|
"The recommended age to have an Ouija Board is 8 years old. So, you need to be 21 years old to drink alcohol, but 8 to summon me.",
|
||||||
|
"If people can believe that not vaccinating their kids is a good idea then you can believe in yourself.",
|
||||||
|
"Stop hating yourself, that's my job.",
|
||||||
|
"Hell may be bad but at least we don't have Donald Trump and Hilary Clinton.",
|
||||||
|
"Hell is full of pull/push doors but the first way you try will always be the wrong way.",
|
||||||
|
"I don't hate you, I just don't like the fact that you're alive.",
|
||||||
|
"If you ever feel bad, just remember that Jesus hears his dads name every time he has sex.",
|
||||||
|
"Drink water you fuckers.",
|
||||||
|
"If it's 1 or 1.000 sins you're still getting sent to Hell. So why not go for 1.000.000 sins and come down here a legend?",
|
||||||
|
"Fuck.",
|
||||||
|
"If Satan needs someone's consent to enter their body then so do you.",
|
||||||
|
"Stop killing eachother, it's getting a little crowded down here.",
|
||||||
|
"Being immortal sucks when you're spending it alone.",
|
||||||
|
"Come to Hell, I've got the new Super Smash Bros.",
|
||||||
|
"Can't wait for y'all to storm Area 51 and find there's only pictures of my asshole in there.",
|
||||||
|
"Are you Hell? 'Cause you're hot as fuck!",
|
||||||
|
"Stop trying to summon me, @IGGYAZALEA!",
|
||||||
|
"Hell has infinite Pizza. Heaven has Broccoli. Make your choice.",
|
||||||
|
"Come to hell, we know Obama's last name.",
|
||||||
|
"Why fall in love when you can fall into the fiery pits of Hell?",
|
||||||
|
"LADIES imagine this: it's 15 years from now. You're dead, you're in Hell. You're constantly tanned from the flames, you have no kids to look after. Life is good.",
|
||||||
|
"I don't care who you worship, just make sure you worship yourself first.",
|
||||||
|
"Stop living your life trying to please God and start living to please yourself.",
|
||||||
|
"Why is 'boring as hell' an expression? Hell is always lit 24/7."
|
||||||
|
]
|
|
@ -0,0 +1,60 @@
|
||||||
|
[
|
||||||
|
"When you are at your worst, remember: Your comrade Stalin suffers with you",
|
||||||
|
"Do you make money in bed? No? Then get out (or start doing porn)",
|
||||||
|
"If you don't fight for what you want, don't cry for what you lost (she was a hoe anyway)",
|
||||||
|
"You think someone will help you while you are broke? Think again",
|
||||||
|
"You'll be rich one day. You know it. I know it. But that day comes after many days of hustle",
|
||||||
|
"Do not, but absolutely do NOT! forget the lifestyle you promised to yourself",
|
||||||
|
"PUBG and TV will not give you the life of your dreams",
|
||||||
|
"They told me I changed. As if I worked so hard just to stay the same",
|
||||||
|
"You want a different tomorrow? Push harder than yesterday",
|
||||||
|
"Excellence is not a skill. It's an attitude",
|
||||||
|
"Want to do great work? Start loving what you do",
|
||||||
|
"Work, until you get paid for your value, not your time",
|
||||||
|
"I tried to chill out and be normal once. Worst two minutes of my life",
|
||||||
|
"When people say \"Impossible\" remember: impossible for them, not for you",
|
||||||
|
"They laugh at you, then they ask if you are hiring.",
|
||||||
|
"You. Will. Fucking. Kill. It.",
|
||||||
|
"Win in silence. Only speak when it's time to say \"Checkmate\". Let them think you are losing",
|
||||||
|
"Every morning, you have two options: Sleep with your dreams. Get up and chase them",
|
||||||
|
"You never know how strong you are, until being strong is your only choice",
|
||||||
|
"Best teacher? Your last mistake",
|
||||||
|
"All of this pain, long hours and hard work... it will pay off",
|
||||||
|
"Be brave. Take risks. Nothing can substitute the experience",
|
||||||
|
"Average? Please. You're born to be great!",
|
||||||
|
"Appreciate what you have. Then double it, by hard work",
|
||||||
|
"It takes 50 years of hard work to build an empire that stays after you pass away. It takes 5 years of hard work to build something that's worthwhile. If you can't stick with this dream of yours for even 5 days, you deserve a shitty life",
|
||||||
|
"What are you doing here? What are you asking me? To motivate you to infinity? You don't need motivation, you need to get off that fat ass and *start* **working**",
|
||||||
|
"Hustle, until your name no longer needs an introduction",
|
||||||
|
"A dream? I call it a plan",
|
||||||
|
"Never forget how you started. Reflect where you are now. Focus on what you are going to achieve",
|
||||||
|
"Times go faster than you think. Don't waste it",
|
||||||
|
"When you feel low, when you feel like you can't go on anymore, when every thing seems to be against you, that's when your greatness can start to shine",
|
||||||
|
"Every master was once a beginner",
|
||||||
|
"One day, the late nights and early mornings *will* pay off",
|
||||||
|
"A year from now, everything you are stressing about won't mean shit",
|
||||||
|
"Do what you *have* to do, so you can do what you *want* to do",
|
||||||
|
"Three months from now, you will be in a completely different space, mentally, emotionally, financially. Hustle!",
|
||||||
|
"First they laughed, now they ask if I'm hiring.",
|
||||||
|
"The biggest risk? Not taking any",
|
||||||
|
"If you can dream about it, you can achieve it",
|
||||||
|
"Excuses sound best to the one that's making them up. Recognize that the excuses are *not* valid",
|
||||||
|
"Here's a reminder: You are amazing. You can do it. God is with you. You'll be succesful",
|
||||||
|
"Stop doubting yourself!",
|
||||||
|
"The days that break you = the days that make you",
|
||||||
|
"The pain is the best teacher",
|
||||||
|
"You're a gamer, I'm a gamer. We both know that we are on the right path if we encounter enemies.",
|
||||||
|
"One day, all that will remain of you is a memory. Make sure it's a good one",
|
||||||
|
"If you don't fight for what you want, don't cry for what you lost",
|
||||||
|
"For every minute you spent not working on your dream, you'll pay in minutes not spent enjoying it",
|
||||||
|
"You want it? You gotta go get it",
|
||||||
|
"I'm working on myself, for myself, by myself. I'm not gonna help you to transform yourself. That's your task",
|
||||||
|
"Nobody is going to help you work on yourself. Everybody is too busy with working on themselves. This fight is yours alone",
|
||||||
|
"Think success is a given? That it will just come to you? Think again",
|
||||||
|
"Success is earned!",
|
||||||
|
"Pain is temporary. Regret is forever",
|
||||||
|
"Dreams require sacrifices. You're not entitled to your dream. You have to fuckin bleed for your dream",
|
||||||
|
"I don't care how you feel. You either push, or you fall behind",
|
||||||
|
"Stop caring about your feelings, start caring about your results",
|
||||||
|
"Shit's not half bad"
|
||||||
|
]
|
|
@ -0,0 +1 @@
|
||||||
|
{"semester": "1", "year": "2", "years": 2, "jpl": 161733, "jpl_day": 4}
|
|
@ -0,0 +1,25 @@
|
||||||
|
[
|
||||||
|
"Ik zeg niet ja, ik zeg niet neen. Integendeel!",
|
||||||
|
"Ik ga ervandoor. Dat kan ik nu niet oplossen.",
|
||||||
|
"Zekerst niet!",
|
||||||
|
"Het antwoord zit achter deze boom: :evergreen_tree:",
|
||||||
|
"Ja",
|
||||||
|
"Jazeker",
|
||||||
|
"Perhaps",
|
||||||
|
"ربما",
|
||||||
|
"~~Ja~~ Nee",
|
||||||
|
"Mijn bronnen zeggen nee, maar ze zeiden ook dat LAM dit jaar beter ging zijn",
|
||||||
|
"Do what Jesus would do: die at the age of 33",
|
||||||
|
"Je bent toch oud en wijs genoeg om dat zelf uit te vogelen?\n.\n.\n.\n*Ja*",
|
||||||
|
"Help mij ik word gegijzeld in een 8-Ball-fabriek!",
|
||||||
|
"Wacht, ik versta je niet. *Kcchrr* Euhh ik rij net een tunnel in *kkcchrr*",
|
||||||
|
"Not this shit again...",
|
||||||
|
"Vraag het aan OwO",
|
||||||
|
"Traceback (most recent call last):\n\tFile \"botwoehoe.py\", line 118, in <module>\n",
|
||||||
|
"ValueError: invalid literal for int() with base 10: responses.json",
|
||||||
|
"Screw you! I'll make my own 8-Ball!\nWith blackjack... and hookers!\nhttps://i.imgflip.com/enk81.jpg",
|
||||||
|
"https://tenor.com/view/peter-griffin-perhaps-family-guy-thinking-gif-13587558",
|
||||||
|
"https://media1.tenor.com/images/55197e959d2824c452ed8a6af99bcf39/tenor.gif?itemid=14697557",
|
||||||
|
"THE CONCH HAS SPOKEN!\nhttps://giphy.com/gifs/no-spongebob-squarepants-magic-conch-shell-NcsEoyGjuLUYg",
|
||||||
|
"https://i.redd.it/zm4s3pakhgax.jpg"
|
||||||
|
]
|
|
@ -0,0 +1,113 @@
|
||||||
|
{
|
||||||
|
"8ball": "Magic 8-Ball Didier beantwoordt ja/nee vragen.",
|
||||||
|
"add": "Voegt [Args] toe aan [Categorie].",
|
||||||
|
"add 8-ball": "Voegt een 8-Ball response toe aan de database.",
|
||||||
|
"add dadjoke": "Voegt een Dadjoke toe aan de database.",
|
||||||
|
"add github": "Voegt iemand's GitHub link toe aan de database.",
|
||||||
|
"add meme": "Voegt een meme toe aan de database.",
|
||||||
|
"add twitch": "Voegt iemand's Twitch link toe aan de database.",
|
||||||
|
"adjective": "Stuurt de 15 beste suggesties voor adjectieven voor [Woord].",
|
||||||
|
"age": "Toont hoe oud Didier is (Jaar-Maand-Week-Dag).\nJe kan een formaat opgeven om de leeftijd in [formaat] uit te drukken (Years, Months, Weeks, Days, Y, M, W, D).",
|
||||||
|
"antonym": "Stuurt de 15 beste suggesties voor antoniemen voor [Woord].",
|
||||||
|
"award": "Beloont [Persoon] met [Aantal] Didier Dinks.",
|
||||||
|
"bail": "Betaal jouw borgsom & koop jezelf vrij uit de gevangenis.",
|
||||||
|
"bank": "Bekijk jouw Didier Bank.",
|
||||||
|
"bank stats": "Bekijk de aanvallende & verdedigende levels van jouw Didier Bank.",
|
||||||
|
"bank upgrade": "Categorieën: Defense/Security, Level, Offense/Capacity\nUpgrade de [Categorie] stat van jouw Didier Bank.",
|
||||||
|
"birthday": "Kijk of jouw verjaardag al in de database zit.",
|
||||||
|
"birthday set": "Voeg jouw verjaardag toe aan de database.\n**Je kan dit maar 1 keer doen om abuse te vermijden, dus doe het deftig.**",
|
||||||
|
"birthday today": "Kijk of er vandaag iemand jarig is.",
|
||||||
|
"birthday tomorrow": "Kijk of er morgen iemand jarig is.",
|
||||||
|
"birthday week": "Toont alle verjaardagen van de komende 7 dagen.",
|
||||||
|
"bitcoin": "Bekijk jouw Bitcoin Bank.",
|
||||||
|
"bitcoin price": "Bekijk de huidige prijs van Bitcoins.",
|
||||||
|
"bitcoin buy": "Koop [Aantal] Didier Dinks aan Bitcoins.",
|
||||||
|
"bitcoin sell": "Verkoop [Aantal] Bitcoins.",
|
||||||
|
"buy": "Koop [Aantal] van [Item id] uit de Store.\nIndien je geen aantal opgeeft, is dit standaard 1.",
|
||||||
|
"changelog": "Stuurt links naar de Didier Changelogs.",
|
||||||
|
"clap": "Zet \"Tekst\" om naar :clap: \uD83C\uDDF9 :clap: \uD83C\uDDEA :clap: \uD83C\uDDF0 :clap: \uD83C\uDDF8 :clap: \uD83C\uDDF9 :clap:",
|
||||||
|
"coinflip": "Gooi een muntje, indien je Didier Dinks inzet kan je je inzet verdubbelen (of verliezen).",
|
||||||
|
"config": "Past constanten in het config bestand aan.",
|
||||||
|
"corona": "Coronatracker voor [Land].\nIndien je geen land opgeeft is dit standaard België.\nCorona Global voor wereldwijde cijfers.",
|
||||||
|
"dadjoke": "Didier vertelt een dad joke.",
|
||||||
|
"define": "Geeft de definitie van [Woord] zoals het in de Urban Dictionary staat.\nZoektermen met spaties moeten **niet** tussen aanhalingstekens staan.",
|
||||||
|
"detect": "Didier probeert de taal van [Tekst] te detecteren.",
|
||||||
|
"dice": "Gok op de uitkomst van een dobbelsteen.",
|
||||||
|
"dinks": "Bekijk jouw huidige aantal Dinks.",
|
||||||
|
"faq": "Stuurt een lijst van alle FAQ's in [Categorie] naar jouw DM's.\nGeef geen categorie op om een lijst van categorieën te krijgen.\nIndien je een of meerdere personen tagt, wordt de lijst naar hun DM's gestuurd in plaats van de jouwe.",
|
||||||
|
"faq add": "Voegt een vraag & antwoord toe aan FAQ [Categorie].\nIndien je geen vraag & antwoord opgeeft, maakt het een categorie aan.",
|
||||||
|
"faq quote": "Stuurt een specifieke entry uit de FAQ in het huidige channel in plaats van de hele lijst naar iemand's DM's.",
|
||||||
|
"github": "Stuurt de GitHub link van [Persoon] indien je iemand tagt, zoniet een lijst van GitHubs van mensen uit deze Discord.\nIndien je jouw eigen GitHub hier graag bij zou zetten, gebruik je ``GitHub Add`` of kan ke een DM sturen naar DJ STIJN.",
|
||||||
|
"github add": "Voegt jouw eigen GitHub toe aan de lijst.\nZowel ``github.com/username`` als ``username`` werken.",
|
||||||
|
"give": "Geef [Persoon] [Aantal] van jouw eigen Didier Dinks.",
|
||||||
|
"hangman": "Raad [Letter]. Indien je geen letter opgeeft, toont het de status van de huidige Hangman game indien er een bezig is.",
|
||||||
|
"hangman start": "Start een nieuwe Hangman game indien er nog geen bezig is. Indien je geen woord opgeeft, wordt er een willekeurig woord gekozen.\n**Indien je wel een woord opgeeft, werkt dit enkel in DM.**",
|
||||||
|
"hangman guess": "Probeer het woord te raden.",
|
||||||
|
"claim": "Claim [Aantal] Didier Dinks uit je profit.\nIndien je geen aantal opgeeft (of \"all\"), claim je alles, inclusief je investering.",
|
||||||
|
"inventory": "Bekijk de items in jouw inventory.",
|
||||||
|
"invest": "Investeer [Aantal] Didier Dinks in jouw Didier Bank om rente te vergaren.",
|
||||||
|
"jpl": "Informatie over de Jupiler Pro League.",
|
||||||
|
"jpl matches": "Bekijk de wedstrijden die gespeeld worden op [Week]. Default naar de huidige speeldag.",
|
||||||
|
"jpl table": "De huidige stand van het klassement.",
|
||||||
|
"launch": "Tijdstip van de volgende SpaceX lancering.",
|
||||||
|
"leaderboard": "Bekijk de Top 10 van [Categorie].\nIndien je geen categorie opgeeft krijg je een lijst van categorieën.",
|
||||||
|
"les": "Bekijk het lessenrooster voor [Dag] in het [Jaargang]-de jaar.\nIndien je geen dag opgeeft, is dit standaard vandaag. De jaargang is standaard 2.\nLes Morgen/Overmorgen werkt ook.",
|
||||||
|
"lmgtfy": "Stuur iemand een LMGTFY link wanneer ze je een domme vraag stellen in plaats van het zelf op te zoeken.\nQueries met spaties moeten **niet** tussen aanhalingstekens staan.",
|
||||||
|
"load": "Laadt [Cog] in.",
|
||||||
|
"load all": "Laadt alle cogs in.",
|
||||||
|
"lost": "Bekijk het aantal Didier Dinks die al verloren zijn door gambling.",
|
||||||
|
"lost today": "Geeft het aantal Didier Dinks die *vandaag* al verloren zijn.",
|
||||||
|
"marco": "Stuurt Didier's latency.",
|
||||||
|
"memegen": "Maakt memes.\nVelden met spaties moeten tussen aanhalingstekens staan, anders hoeft het niet (mag wel).",
|
||||||
|
"memes": "Toont een lijst van geldige meme-namen & het aantal velden dat nodig is voor die meme.",
|
||||||
|
"menu": "Toont de menu voor [Dag] in Resto S5.\nIndien je geen dag opgeeft, is dit standaard vandaag.\nGebaseerd op een script van Pieter De Clercq (https://github.com/thepieterdc/ugent-food).",
|
||||||
|
"minesweeper": "Speel MineSweeper. Indien je geen difficulty opgeeft is dit automatisch medium.",
|
||||||
|
"mock": "Verandert tekst in MoCk1nG Sp0nGeBoB T3kSt.\nAls je niet de volledige zin wil veranderen moet het betreffende stuk tussen [[ ]] staan.",
|
||||||
|
"muttn": "Kiekt oeveel van ne muttn da [@Persoon] wel nie es aje eenen tagt, anders ist uzelf.",
|
||||||
|
"neck": "<:WhatDidYou:744476950654877756><:DoTo:744476965951504414><:MyDrink:744476979939508275>",
|
||||||
|
"nightly": "Daily is overrated.\nClaim jouw dagelijkse bonus Didier Dinks.",
|
||||||
|
"pjoke": "Didier vertelt een programming joke.",
|
||||||
|
"poke": "Tik [Persoon].",
|
||||||
|
"poke blacklist": "Indien je liever niet aan Poke wil deelnemen, kan je jezelf op deze manier blacklisten.\nIndien je jezelf wil ont-blacklisten stuur je een DM naar DJ STIJN (om misbruik tegen te gaan).",
|
||||||
|
"poke current": "Bekijk wie er momenteel aan beurt is.",
|
||||||
|
"prison": "Bekijk hoelang je nog in de Didier Gevangenis zit, en hoeveel borg je moet betalen om jezelf vrij te kopen.",
|
||||||
|
"qr": "Didier genereert een QR-code voor je opgegeven link/string.",
|
||||||
|
"random choice": "Kiest een optie uit [Argumenten].",
|
||||||
|
"random colour": "Genereert een random kleur.",
|
||||||
|
"random fact": "Stuurt een random fact om je algemene kennis te verrijken.",
|
||||||
|
"random identity": "Genereert een random identiteit.",
|
||||||
|
"random name": "Genereert een random naam.",
|
||||||
|
"random number": "Kiest een getal tussen [Van] en [Tot] (default 1 en 100).",
|
||||||
|
"random shuffle": "Verandert de volgorde van [Argumenten].",
|
||||||
|
"random timestamp": "Genereert een random tijdstip.",
|
||||||
|
"regering": "Aantal dagen dat we al zonder regering zitten.",
|
||||||
|
"reac": "Reageert [Emoji] op het bericht met opgegeven Id.",
|
||||||
|
"react": "Didier react [Tekst] op de opgegeven message.\nIndien je geen message opgeeft, wordt het gereageerd op het bericht dat het commando callet.\nDe url naar het bericht werkt **ook**.\nWanneer je het message *id* gebruikt, moet het bericht in hetzelfde channel staan. Anders gebruik je de url.",
|
||||||
|
"releases": "Lijst van de games die in de volgende 30 dagen uitkomen.\nGeef een getal op om volgende/vorige pagina's te bekijken (standaard pagina 1).",
|
||||||
|
"releases info": "Geeft gedetailleerde informatie over de game met de opgegeven id.",
|
||||||
|
"reload": "Verwijdert [Cog] & voegt hem daarna terug toe.",
|
||||||
|
"remind": "Krijg een dagelijkse herinnering om Didier Nightly te doen.\nMeer categorieën en usages komen later:tm:.",
|
||||||
|
"reverse": "Returnt tekst achterstevoren.",
|
||||||
|
"rhyme": "Stuurt de 15 beste suggesties voor woorden die rijmen op [Woord].",
|
||||||
|
"rob": "Probeer Didier Dinks te stelen van [Persoon].",
|
||||||
|
"satan": "Stuurt een quote van Satan.",
|
||||||
|
"sell": "Verkoop [Aantal] van [Item id]. Je krijgt maar 80% van je aankoop terugbetaald.",
|
||||||
|
"slots": "Speel met een Gokautomaat.",
|
||||||
|
"slots chart": "Bekijk de winstverdeling van Didier Slots.",
|
||||||
|
"stalin": "Stuurt een motivational quote van Stalin.",
|
||||||
|
"stats": "Bekijk de verhoudingen voor jouw gekozen categorie.\nIndien je geen categorie opgeeft, krijg je je persoonlijke stats.",
|
||||||
|
"stats channels": "Bekijk de stats van [Channel].\nIndien je geen channel opgeeft, krijg je een lijst van alle channels in deze server.",
|
||||||
|
"store": "Bekijk de Didier Store om items te kopen.",
|
||||||
|
"synonym": "Stuurt de 15 beste suggesties voor synoniemen voor [Woord].",
|
||||||
|
"todo": "Stuurt de link naar de To-Do lijst voor Didier (Trello Board).",
|
||||||
|
"train": "Stuurt de volgende treinen van [vertrek] naar [bestemming].\nIndien je geen vertrek opgeeft is dit standaard Gent Sint-Pieters.\nSteden met typfouten worden geautocorrect, dus controleer of de bestemming juist is.\nSteden met spaties moeten tussen \" \" gezet worden.",
|
||||||
|
"translate": "Vertaalt [Tekst] van [Van] naar [Naar].\nIndien je geen vertrektaal opgeeft is dit default autodetect. De doeltaal is default NL.",
|
||||||
|
"trends": "Toont meer gedetailleerde Corona-cijfers in vergelijking met de dag ervoor.",
|
||||||
|
"trump": "Stuurt wijsheden van the man himself.",
|
||||||
|
"twitch": "Stuurt de Twitch link van [Persoon] indien je iemand tagt, zoniet een lijst van Twitch kanalen van mensen uit deze Discord.\nIndien je jouw eigen Twitch hier graag bij zou zetten, gebruik je ``Twitch Add`` of kan ke een DM sturen naar DJ STIJN.",
|
||||||
|
"twitch add": "Voegt jouw eigen Twitch toe aan de lijst.\nZowel ``twitch.tv/username`` als ``username`` werken.",
|
||||||
|
"unload": "Verwijdert [Cog].",
|
||||||
|
"unload all": "Verwijdert alle cogs.",
|
||||||
|
"xp": "Bekijk je huidige aantal berichten en xp.",
|
||||||
|
"yes/no": "Didier helpt je met keuzes maken."
|
||||||
|
}
|
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,205 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"course": "Programmeren",
|
||||||
|
"icon": "laptop-code",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": [
|
||||||
|
"maandag",
|
||||||
|
1430,
|
||||||
|
1700
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Resto 1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["dinsdag", 1430, 1700]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Databanken",
|
||||||
|
"icon": "database",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"donderdag",
|
||||||
|
1000,
|
||||||
|
1100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"vrijdag",
|
||||||
|
1430,
|
||||||
|
1530
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Resto 1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": [
|
||||||
|
"donderdag",
|
||||||
|
1130,
|
||||||
|
1230
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Resto 1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": [
|
||||||
|
"vrijdag",
|
||||||
|
1300,
|
||||||
|
1400
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Computergebruik",
|
||||||
|
"icon": "linux",
|
||||||
|
"icon_type": "fab",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"dinsdag",
|
||||||
|
1130,
|
||||||
|
1230
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Resto 1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": [
|
||||||
|
"donderdag",
|
||||||
|
1430,
|
||||||
|
1700
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"vrijdag",
|
||||||
|
1000,
|
||||||
|
1100
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "RAF",
|
||||||
|
"icon": "brain",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"dinsdag",
|
||||||
|
1000,
|
||||||
|
1100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S25",
|
||||||
|
"room": "Emmy Noether",
|
||||||
|
"time": [
|
||||||
|
"woensdag",
|
||||||
|
830,
|
||||||
|
1000
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"woensdag",
|
||||||
|
1430,
|
||||||
|
1700
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Discrete Wiskunde",
|
||||||
|
"icon": "square-root-alt",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": [
|
||||||
|
"maandag",
|
||||||
|
1000,
|
||||||
|
1230
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S25",
|
||||||
|
"room": "Emmy Noether",
|
||||||
|
"time": [
|
||||||
|
"woensdag",
|
||||||
|
1000,
|
||||||
|
1230
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,106 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"course": "Objectgericht Programmeren",
|
||||||
|
"icon": "java",
|
||||||
|
"icon_type": "fab",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["woensdag", 1130, 1300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper",
|
||||||
|
"time": ["woensdag", 1430, 1730]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["donderdag", 830, 1000]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "AD 1",
|
||||||
|
"icon": "brain",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper",
|
||||||
|
"time": ["dinsdag", 1000, 1300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["donderdag", 1000, 1300]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Calculus",
|
||||||
|
"icon": "calculator",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["maandag", 1430, 1730]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["woensdag", 830, 1130]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Scriptingtalen",
|
||||||
|
"icon": "python",
|
||||||
|
"icon_type": "fab",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["maandag", 1130, 1300]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": ["dinsdag", 830, 1000]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S5",
|
||||||
|
"room": "Grace Hopper",
|
||||||
|
"time": ["dinsdag", 1430, 1730]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "LAM",
|
||||||
|
"icon": "vector-square",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["maandag", 830, 1130]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S12",
|
||||||
|
"room": "AUD Kelder",
|
||||||
|
"time": ["donderdag", 1430, 1730]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,203 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"course": "Functioneel Programmeren",
|
||||||
|
"zoom": "https://ufora.ugent.be/d2l/ext/rp/236396/lti/framedlaunch/556e197e-e87b-4c27-be5d-53adc7a41826",
|
||||||
|
"bongo": "https://ufora.ugent.be/d2l/ext/rp/236396/lti/framedlaunch/7f4120b3-8827-44ad-8b02-a79066c396cf",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"online": "Bongo Virtual Classroom",
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 3.1",
|
||||||
|
"time": ["maandag", 1000, 1230]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"online": "ZOOM",
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 2.4",
|
||||||
|
"time": ["vrijdag", 1300, 1530]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Systeemprogrammeren",
|
||||||
|
"bongo": "https://ufora.ugent.be/d2l/ext/rp/222035/lti/framedlaunch/7f4120b3-8827-44ad-8b02-a79066c396cf",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 2.1",
|
||||||
|
"time": ["donderdag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"online": "Bongo Virtual Classroom",
|
||||||
|
"weeks": [1],
|
||||||
|
"group": 1,
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S4",
|
||||||
|
"room": "LES 0.1",
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"online": "Bongo Virtual Classroom",
|
||||||
|
"weeks": [1],
|
||||||
|
"time": ["donderdag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [2],
|
||||||
|
"group": 2,
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S4",
|
||||||
|
"room": "LES 0.1",
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [3],
|
||||||
|
"canceled": true,
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [4],
|
||||||
|
"group": 2,
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 0.1 Victor Van Straelen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [5],
|
||||||
|
"group": 1,
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 0.1 Victor Van Straelen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "AD 2",
|
||||||
|
"bongo": "https://ufora.ugent.be/d2l/ext/rp/222018/lti/framedlaunch/7f4120b3-8827-44ad-8b02-a79066c396cf",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": ["dinsdag", 1300, 1530]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": ["vrijdag", 830, 930]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "Victor Van Straelen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["vrijdag", 1000, 1100]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Communicatienetwerken",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "Locus",
|
||||||
|
"room": "Resto Locus",
|
||||||
|
"time": ["woensdag", 1000, 1230]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "Locus",
|
||||||
|
"room": "Resto Locus",
|
||||||
|
"time": ["woensdag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [4, 7],
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "iGent",
|
||||||
|
"room": "0.1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "iGent",
|
||||||
|
"room": "0.1 PRA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "iGent",
|
||||||
|
"room": "0.2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["woensdag", 1430, 1700]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Statistiek en Probabiliteit",
|
||||||
|
"bongo": "https://ufora.ugent.be/d2l/ext/rp/236398/lti/framedlaunch/7f4120b3-8827-44ad-8b02-a79066c396cf",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"online": "Bongo Virtual Classroom",
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S12",
|
||||||
|
"room": "Auditorium 1",
|
||||||
|
"time": ["dinsdag", 1600, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "1.1 Alan Turing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"online": "Bongo Virtual Classroom",
|
||||||
|
"time": ["donderdag", 830, 1100]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"online": "Bongo Virtual Classroom",
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["donderdag", 1300, 1400]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,182 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"course": "Functioneel Programmeren",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 3.1",
|
||||||
|
"time": ["maandag", 1000, 1230]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 2.4",
|
||||||
|
"time": ["vrijdag", 1300, 1530]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Systeemprogrammeren",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 2.1",
|
||||||
|
"time": ["donderdag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [1],
|
||||||
|
"group": 1,
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S4",
|
||||||
|
"room": "LES 0.1",
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [2],
|
||||||
|
"group": 2,
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S4",
|
||||||
|
"room": "LES 0.1",
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [4],
|
||||||
|
"group": 2,
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 0.1 Victor Van Straelen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [5],
|
||||||
|
"group": 1,
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "LES 0.1 Victor Van Straelen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["maandag", 1430, 1700]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "AD 2",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": ["dinsdag", 1300, 1530]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A3",
|
||||||
|
"time": ["vrijdag", 830, 930]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S8",
|
||||||
|
"room": "Victor Van Straelen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["vrijdag", 1000, 1100]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Communicatienetwerken",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "Locus",
|
||||||
|
"room": "Resto Locus",
|
||||||
|
"time": ["woensdag", 1000, 1230]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "Locus",
|
||||||
|
"room": "Resto Locus",
|
||||||
|
"time": ["woensdag", 1430, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"weeks": [4, 7],
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "iGent",
|
||||||
|
"room": "0.1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "iGent",
|
||||||
|
"room": "0.1 PRA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Ardoyen",
|
||||||
|
"building": "iGent",
|
||||||
|
"room": "0.2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["woensdag", 1430, 1700]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"course": "Statistiek en Probabiliteit",
|
||||||
|
"slots": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S12",
|
||||||
|
"room": "Auditorium 1",
|
||||||
|
"time": ["dinsdag", 1600, 1700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "1.1 Alan Turing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "3.1 Konrad Zuse"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": ["donderdag", 830, 1100]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campus": "Sterre",
|
||||||
|
"building": "S9",
|
||||||
|
"room": "A2",
|
||||||
|
"time": ["donderdag", 1300, 1400]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,72 @@
|
||||||
|
import math
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord import utils, Member, User
|
||||||
|
from discord.ext import commands
|
||||||
|
from data import constants
|
||||||
|
import requests
|
||||||
|
from functions.database import currency
|
||||||
|
|
||||||
|
|
||||||
|
# Checks if caller of a command is me
|
||||||
|
def isMe(ctx):
|
||||||
|
return str(ctx.author.id) == constants.myId
|
||||||
|
|
||||||
|
|
||||||
|
# Checks if the caller of a command is an admin
|
||||||
|
def isMod(ctx):
|
||||||
|
if ctx.guild is None:
|
||||||
|
return isMe(ctx)
|
||||||
|
|
||||||
|
return ctx.author.id in constants.mods[ctx.guild.id]
|
||||||
|
|
||||||
|
|
||||||
|
# Checks if a command is allowed to be used in this channel
|
||||||
|
def allowedChannels(ctx):
|
||||||
|
return isMe(ctx) or ctx.channel.type == discord.ChannelType.private or int(ctx.channel.id) in constants.allowedChannels.values()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO find a better way to check for legit links because reddit posts return a 502
|
||||||
|
def freeGamesCheck(ctx):
|
||||||
|
if str(ctx.channel.id) != str(constants.allowedChannels["freegames"]):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Replace newlines with spaces
|
||||||
|
noNewLines = ctx.content.replace("\n", " ")
|
||||||
|
|
||||||
|
link = ""
|
||||||
|
for word in noNewLines.split(" "):
|
||||||
|
if "http" in word and "://" in word:
|
||||||
|
link = word.strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
if link == "":
|
||||||
|
return False
|
||||||
|
request = requests.get(link)
|
||||||
|
if request.status_code != 200:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# Checks if a user can invest/gamble/... [amount]
|
||||||
|
def isValidAmount(ctx, amount):
|
||||||
|
if not amount:
|
||||||
|
return [False, "Geef een geldig bedrag op."]
|
||||||
|
dinks = float(currency.dinks(ctx.author.id))
|
||||||
|
if amount == "all":
|
||||||
|
if dinks > 0:
|
||||||
|
return [True, dinks]
|
||||||
|
else:
|
||||||
|
return [False, "Je hebt niet genoeg Didier Dinks om dit te doen."]
|
||||||
|
# Check if it's a number <= 0 or text != all
|
||||||
|
if (all(char.isalpha() for char in str(amount)) and amount != "all") or \
|
||||||
|
(all(char.isdigit() for char in str(abs(int(amount)))) and int(amount) <= 0):
|
||||||
|
return [False, "Geef een geldig bedrag op."]
|
||||||
|
if int(amount) > dinks:
|
||||||
|
return [False, "Je hebt niet genoeg Didier Dinks om dit te doen."]
|
||||||
|
return [True, amount]
|
||||||
|
|
||||||
|
|
||||||
|
def pluralS(amount):
|
||||||
|
return "s" if round(float(amount)) != 1 else ""
|
|
@ -0,0 +1,62 @@
|
||||||
|
def clap(content: str):
|
||||||
|
if content == "":
|
||||||
|
return "Dit is geen geldig bericht"
|
||||||
|
text = "".join([str(s).lower() if s.isdigit() or s.isalpha() else "" for s in content])
|
||||||
|
newStr = ":clap: " + " :clap: ".join(fetch("regional_indicator_{}".format(char) if char.isalpha() else char) for char in text) + " :clap:"
|
||||||
|
return newStr if 0 < len(newStr) <= 1100 else "Dit is geen geldig bericht."
|
||||||
|
|
||||||
|
|
||||||
|
def fetch(char):
|
||||||
|
dic = {
|
||||||
|
"regional_indicator_a": "🇦",
|
||||||
|
"regional_indicator_b": "🇧",
|
||||||
|
"regional_indicator_c": "🇨",
|
||||||
|
"regional_indicator_d": "🇩",
|
||||||
|
"regional_indicator_e": "🇪",
|
||||||
|
"regional_indicator_f": "🇫",
|
||||||
|
"regional_indicator_g": "🇬",
|
||||||
|
"regional_indicator_h": "🇭",
|
||||||
|
"regional_indicator_i": "🇮",
|
||||||
|
"regional_indicator_j": "🇯",
|
||||||
|
"regional_indicator_k": "🇰",
|
||||||
|
"regional_indicator_l": "🇱",
|
||||||
|
"regional_indicator_m": "🇲",
|
||||||
|
"regional_indicator_n": "🇳",
|
||||||
|
"regional_indicator_o": "🇴",
|
||||||
|
"regional_indicator_p": "🇵",
|
||||||
|
"regional_indicator_q": "🇶",
|
||||||
|
"regional_indicator_r": "🇷",
|
||||||
|
"regional_indicator_s": "🇸",
|
||||||
|
"regional_indicator_t": "🇹",
|
||||||
|
"regional_indicator_u": "🇺",
|
||||||
|
"regional_indicator_v": "🇻",
|
||||||
|
"regional_indicator_w": "🇼",
|
||||||
|
"regional_indicator_x": "🇽",
|
||||||
|
"regional_indicator_y": "🇾",
|
||||||
|
"regional_indicator_z": "🇿",
|
||||||
|
"zero": "0⃣",
|
||||||
|
"one": "1️⃣",
|
||||||
|
"two": "2️⃣",
|
||||||
|
"three": "3️⃣",
|
||||||
|
"four": "4️⃣",
|
||||||
|
"five": "5️⃣",
|
||||||
|
"six": "6️⃣",
|
||||||
|
"seven": "7️⃣",
|
||||||
|
"eight": "8️⃣",
|
||||||
|
"nine": "9️⃣"
|
||||||
|
}
|
||||||
|
|
||||||
|
nums = {
|
||||||
|
"0": "zero",
|
||||||
|
"1": "one",
|
||||||
|
"2": "two",
|
||||||
|
"3": "three",
|
||||||
|
"4": "four",
|
||||||
|
"5": "five",
|
||||||
|
"6": "six",
|
||||||
|
"7": "seven",
|
||||||
|
"8": "eight",
|
||||||
|
"9": "nine"
|
||||||
|
}
|
||||||
|
|
||||||
|
return dic[str(char)] if char[-1].isalpha() else dic[nums[str(char)]]
|
|
@ -0,0 +1,67 @@
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def randomRGB():
|
||||||
|
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
|
||||||
|
|
||||||
|
|
||||||
|
def RGBToHEX(r, g, b):
|
||||||
|
return "#" + str(hex(r))[2:] + str(hex(g))[2:] + str(hex(b))[2:]
|
||||||
|
|
||||||
|
|
||||||
|
def RGBToHSL(r, g, b):
|
||||||
|
r /= 255
|
||||||
|
g /= 255
|
||||||
|
b /= 255
|
||||||
|
Cmax = max(r, g, b)
|
||||||
|
Cmin = min(r, g, b)
|
||||||
|
delta = Cmax - Cmin
|
||||||
|
|
||||||
|
# Hue
|
||||||
|
h = RGBHue(r, g, b)
|
||||||
|
|
||||||
|
# Lightness
|
||||||
|
l = (Cmax + Cmin)/2
|
||||||
|
|
||||||
|
# Saturation
|
||||||
|
s = 0 if delta == 0 else delta / (1 - abs(((2 * l) - 1)))
|
||||||
|
|
||||||
|
return round(h), round(s * 100, 2), round(l * 100, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def RGBToHSV(r, g, b):
|
||||||
|
r /= 255
|
||||||
|
g /= 255
|
||||||
|
b /= 255
|
||||||
|
Cmax = max(r, g, b)
|
||||||
|
Cmin = min(r, g, b)
|
||||||
|
delta = Cmax - Cmin
|
||||||
|
|
||||||
|
# Hue
|
||||||
|
h = RGBHue(r, g, b)
|
||||||
|
|
||||||
|
# Saturation
|
||||||
|
s = 0 if Cmax == 0 else delta / Cmax
|
||||||
|
|
||||||
|
# Value
|
||||||
|
v = Cmax
|
||||||
|
|
||||||
|
return round(h), round(s * 100, 2), round(v * 100, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def RGBHue(r, g, b):
|
||||||
|
Cmax = max(r, g, b)
|
||||||
|
Cmin = min(r, g, b)
|
||||||
|
delta = Cmax - Cmin
|
||||||
|
|
||||||
|
h = -1
|
||||||
|
if delta == 0:
|
||||||
|
h = 0
|
||||||
|
elif Cmax == r:
|
||||||
|
h = 60 * (((g - b) / delta) % 6)
|
||||||
|
elif Cmax == g:
|
||||||
|
h = 60 * (((b - r) / delta) + 2)
|
||||||
|
elif Cmax == b:
|
||||||
|
h = 60 * (((r - g) / delta) + 4)
|
||||||
|
|
||||||
|
return h
|
|
@ -0,0 +1,23 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def config(category: str, value):
|
||||||
|
try:
|
||||||
|
with open("files/config.json", "r") as fp:
|
||||||
|
configFile = json.load(fp)
|
||||||
|
|
||||||
|
configFile[category] = value
|
||||||
|
|
||||||
|
with open("files/config.json", "w") as fp:
|
||||||
|
json.dump(configFile, fp)
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
|
||||||
|
def get(category):
|
||||||
|
with open("files/config.json", "r") as fp:
|
||||||
|
configFile = json.load(fp)
|
||||||
|
|
||||||
|
return configFile[category] if category in configFile else None
|
|
@ -0,0 +1,27 @@
|
||||||
|
from functions.database import utils
|
||||||
|
|
||||||
|
|
||||||
|
def get_user(userid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT day, month, year FROM birthdays WHERE userid = %s", (int(userid),))
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def get_users_on_date(day, month):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT userid FROM birthdays WHERE day = %s AND month = %s", (int(day), int(month),))
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def add_user(userid, day, month, year):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
if get_user(userid):
|
||||||
|
cursor.execute("UPDATE birthdays SET day = %s, month = %s, year = %s WHERE userid = %s",
|
||||||
|
(int(day), int(month), int(year), int(userid),))
|
||||||
|
else:
|
||||||
|
cursor.execute("INSERT INTO birthdays(userid, day, month, year) VALUES (%s, %s, %s, %s)",
|
||||||
|
(int(userid), int(day), int(month), int(year),))
|
||||||
|
connection.commit()
|
|
@ -0,0 +1,107 @@
|
||||||
|
import datetime
|
||||||
|
from functions.database import utils, stats
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def dinks(userid):
|
||||||
|
return getOrAddUser(userid)[1]
|
||||||
|
|
||||||
|
|
||||||
|
def dinksAll(userid):
|
||||||
|
platinumDinks = 0
|
||||||
|
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT amount FROM inventory WHERE userid = %s AND itemid = %s", (int(userid), 1,))
|
||||||
|
result = cursor.fetchall()
|
||||||
|
|
||||||
|
if result:
|
||||||
|
platinumDinks = result[0][0]
|
||||||
|
|
||||||
|
return {"dinks": dinks(userid), "platinum": platinumDinks}
|
||||||
|
|
||||||
|
|
||||||
|
def getAllRows():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"""SELECT * FROM currencytable"""
|
||||||
|
)
|
||||||
|
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def getAllPlatDinks():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT userid, amount FROM inventory WHERE itemid = 1")
|
||||||
|
result = cursor.fetchall()
|
||||||
|
dic = {}
|
||||||
|
for user in result:
|
||||||
|
dic[str(user[0])] = user[1]
|
||||||
|
return dic
|
||||||
|
|
||||||
|
|
||||||
|
def getOrAddUser(userid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "SELECT * FROM currencytable WHERE userid = %s"
|
||||||
|
cursor.execute(
|
||||||
|
query, (int(userid),)
|
||||||
|
)
|
||||||
|
result = cursor.fetchall()
|
||||||
|
# User didn't exist yet, so create a new default file
|
||||||
|
if len(result) == 0:
|
||||||
|
createNewUser(userid, connection)
|
||||||
|
return getOrAddUser(userid)
|
||||||
|
return result[0]
|
||||||
|
|
||||||
|
|
||||||
|
# TODO check for nightly bonus & add+return that instead of 420
|
||||||
|
def nightly(userid):
|
||||||
|
user = getOrAddUser(userid)
|
||||||
|
today = datetime.datetime.today().date()
|
||||||
|
lastNightly = datetime.datetime.fromtimestamp(user[9]).date()
|
||||||
|
streak = int(user[10])
|
||||||
|
if lastNightly < today:
|
||||||
|
update(userid, "dinks", float(user[1]) + 420.0)
|
||||||
|
update(userid, "nightly", int(time.time()))
|
||||||
|
|
||||||
|
# Update the streak
|
||||||
|
if (today - lastNightly).days > 1:
|
||||||
|
update(userid, "nightly_streak", 1)
|
||||||
|
streak = 1
|
||||||
|
else:
|
||||||
|
update(userid, "nightly_streak", streak + 1)
|
||||||
|
streak += 1
|
||||||
|
|
||||||
|
s = stats.getOrAddUser(userid)
|
||||||
|
|
||||||
|
if streak > int(s[5]):
|
||||||
|
stats.update(userid, "longest_streak", streak)
|
||||||
|
|
||||||
|
stats.update(userid, "nightlies_count", int(s[6]) + 1)
|
||||||
|
|
||||||
|
return [True, 420, streak]
|
||||||
|
return [False, 0, -1]
|
||||||
|
|
||||||
|
|
||||||
|
def createNewUser(userid, connection=None):
|
||||||
|
if connection is None:
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "INSERT INTO currencytable(userid, dinks, banklevel, investedamount, investeddays, profit, defense, offense, bitcoins, nightly) " \
|
||||||
|
"VALUES (%s, 0.0, 1, 0.0, 0, 0, 1, 1, 0.0, 0)"
|
||||||
|
cursor.execute(query, (int(userid),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def update(userid, column, value):
|
||||||
|
_ = getOrAddUser(userid)
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "UPDATE currencytable " \
|
||||||
|
"SET {} = %s " \
|
||||||
|
"WHERE userid = %s".format(column)
|
||||||
|
cursor.execute(query, (value, userid,))
|
||||||
|
connection.commit()
|
|
@ -0,0 +1,16 @@
|
||||||
|
from functions.database import utils
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def getRandomJoke():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM dad_jokes")
|
||||||
|
return random.choice(cursor.fetchall())[1]
|
||||||
|
|
||||||
|
|
||||||
|
def addJoke(joke):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("INSERT INTO dad_jokes(joke) VALUES (%s)", (str(joke),))
|
||||||
|
connection.commit()
|
|
@ -0,0 +1,60 @@
|
||||||
|
from functions.database import utils
|
||||||
|
|
||||||
|
|
||||||
|
def getCategories():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"""SELECT name FROM faq_categories"""
|
||||||
|
)
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def addCategory(name):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"""INSERT INTO faq_categories(name) VALUES (%s)""", (name.lower(),)
|
||||||
|
)
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def addQuestion(category: str, question: str, answer: str, answer_markdown: str = None):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# Find the Id of this category
|
||||||
|
cursor.execute(
|
||||||
|
"""SELECT id FROM faq_categories WHERE name = %s""", (category.lower(),)
|
||||||
|
)
|
||||||
|
categoryId = cursor.fetchall()[0]
|
||||||
|
|
||||||
|
if not categoryId:
|
||||||
|
return
|
||||||
|
|
||||||
|
categoryId = categoryId[0]
|
||||||
|
|
||||||
|
# Check if a markdown string has to be added
|
||||||
|
if answer_markdown is None:
|
||||||
|
cursor.execute(
|
||||||
|
"""INSERT INTO faq_entries(category_id, question, answer) VALUES (%s, %s, E%s)""",
|
||||||
|
(categoryId, question, answer,)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cursor.execute(
|
||||||
|
"""INSERT INTO faq_entries(category_id, question, answer, answer_markdown) VALUES (%s, %s, E%s, E%s)""", (categoryId, question, answer, answer_markdown)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def getCategory(category):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"""SELECT *
|
||||||
|
FROM faq_entries INNER JOIN faq_categories fc on faq_entries.category_id = fc.id
|
||||||
|
WHERE %s = fc.name""",
|
||||||
|
(category.lower(),)
|
||||||
|
)
|
||||||
|
return cursor.fetchall()
|
|
@ -0,0 +1,27 @@
|
||||||
|
from functions.database import utils
|
||||||
|
|
||||||
|
|
||||||
|
def add(userid, link):
|
||||||
|
user = get_user(userid)
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
if len(user) == 0:
|
||||||
|
cursor.execute("INSERT INTO githubs(userid, githublink) VALUES (%s, %s)", (int(userid), str(link),))
|
||||||
|
else:
|
||||||
|
cursor.execute("""UPDATE githubs SET githublink = %s WHERE userid = %s""", (user[0][0] + "\n" + link, int(userid),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def getAll():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM githubs")
|
||||||
|
result = cursor.fetchall()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_user(userid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT githublink FROM githubs WHERE userid = %s", (int(userid),))
|
||||||
|
return cursor.fetchall()
|
|
@ -0,0 +1,29 @@
|
||||||
|
from functions.database import utils
|
||||||
|
|
||||||
|
|
||||||
|
def insert(id, name, fields):
|
||||||
|
if getMeme(name)[0]:
|
||||||
|
return [False, "Deze meme staat al in de database."]
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("INSERT INTO memes(id, name, fields) VALUES (%s, %s, %s)", [int(id), name.lower(), int(fields)])
|
||||||
|
connection.commit()
|
||||||
|
return [True, "{} is toegevoegd aan de database.".format(name[0].upper() + name[1:].lower())]
|
||||||
|
|
||||||
|
|
||||||
|
def getMeme(name):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM memes WHERE name like %s", ["%" + name.lower() + "%"])
|
||||||
|
result = cursor.fetchall()
|
||||||
|
if len(result) == 0:
|
||||||
|
return [False, "Deze meme staat niet in de database."]
|
||||||
|
return [True, result[0]]
|
||||||
|
|
||||||
|
|
||||||
|
def getAllMemes():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM memes")
|
||||||
|
result = cursor.fetchall()
|
||||||
|
return result
|
|
@ -0,0 +1,76 @@
|
||||||
|
from data import constants
|
||||||
|
from functions.database import utils
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def getOrAddUser(userid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "SELECT * FROM muttn WHERE userid = %s"
|
||||||
|
cursor.execute(
|
||||||
|
query, (int(userid),)
|
||||||
|
)
|
||||||
|
result = cursor.fetchall()
|
||||||
|
# User didn't exist yet, so create a new default file
|
||||||
|
if len(result) == 0:
|
||||||
|
createNewUser(userid, connection)
|
||||||
|
return getOrAddUser(userid)
|
||||||
|
return result[0]
|
||||||
|
|
||||||
|
|
||||||
|
def getAllRows():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM muttn")
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def createNewUser(userid, connection):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("INSERT INTO muttn(userid, stats, count, message) VALUES (%s, %s, %s, %s)", (
|
||||||
|
int(userid), random.randint(0, 50) + (random.randint(0, 100)/100), 0, 0,
|
||||||
|
))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def muttn(userid, count, messageid):
|
||||||
|
if str(userid) == constants.didierId:
|
||||||
|
return
|
||||||
|
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
user = getOrAddUser(userid)
|
||||||
|
|
||||||
|
# Dont' allow earlier messages to be spammed to avoid abuse
|
||||||
|
if messageid < user[3]:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 5 or more = percentage increase
|
||||||
|
if count >= 5:
|
||||||
|
# React was removed & added again: don't do anything
|
||||||
|
# New count is smaller than or equal to old max for this message
|
||||||
|
if count <= user[4] and messageid == user[3]:
|
||||||
|
return
|
||||||
|
|
||||||
|
cursor.execute("UPDATE muttn SET stats = %s, message = %s, highest = %s WHERE userid = %s",
|
||||||
|
(float(user[1]) + (random.randint(2, 50) * count/1000), int(messageid), count, int(userid)))
|
||||||
|
connection.commit()
|
||||||
|
cursor.execute("UPDATE muttn SET count = %s WHERE userid = %s",
|
||||||
|
(int(user[2]) + 1, int(userid),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def removeMuttn(message):
|
||||||
|
if str(message.author.id) == constants.didierId:
|
||||||
|
return
|
||||||
|
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
user = getOrAddUser(message.author.id)
|
||||||
|
|
||||||
|
cursor.execute("UPDATE muttn SET count = %s WHERE userid = %s",
|
||||||
|
(int(user[2]) - 1, int(message.author.id),))
|
||||||
|
connection.commit()
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
from functions.database import utils, stats
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def get():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM poke")
|
||||||
|
return cursor.fetchall()[0]
|
||||||
|
|
||||||
|
|
||||||
|
def update(user, new):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"UPDATE poke "
|
||||||
|
"SET current = %s, poketime = %s, previous = %s",
|
||||||
|
(int(new), int(time.time()), int(user))
|
||||||
|
)
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def blacklisted(user):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT poke_blacklist FROM info WHERE userid = %s", (int(user),))
|
||||||
|
res = cursor.fetchall()
|
||||||
|
if len(res) == 0:
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("INSERT INTO info(userid, poke_blacklist) VALUES(%s, False)", (int(user),))
|
||||||
|
connection.commit()
|
||||||
|
return False
|
||||||
|
return res[0][0]
|
||||||
|
|
||||||
|
|
||||||
|
# Changes the poke blacklist state to true or false
|
||||||
|
def blacklist(user, bl=True):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("UPDATE info "
|
||||||
|
"SET poke_blacklist = %s WHERE userid = %s", (bl, int(user),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a list of all blacklisted users
|
||||||
|
def getAllBlacklistedUsers():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT userid FROM info WHERE poke_blacklist = True")
|
||||||
|
return [str(user[0]) for user in cursor.fetchall()]
|
||||||
|
|
||||||
|
|
||||||
|
def reset():
|
||||||
|
current = get()[0]
|
||||||
|
new = stats.pokeResetCandidate(current, [int(user) for user in getAllBlacklistedUsers()])
|
||||||
|
update(current, new)
|
||||||
|
return new
|
|
@ -0,0 +1,44 @@
|
||||||
|
from functions.database import utils
|
||||||
|
|
||||||
|
|
||||||
|
def getUser(userId):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM prison WHERE userid = %s", (int(userId),))
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def remove(userId):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("DELETE FROM prison WHERE userid = %s", (int(userId),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def imprison(userid, bailsum, days, daily):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("INSERT INTO prison(userid, bail, days, daily) VALUES (%s, %s, %s, %s)",
|
||||||
|
(int(userid), float(bailsum), int(days), float(daily),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def dailyLowers():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# Release people from prison on their last day
|
||||||
|
cursor.execute("DELETE FROM prison WHERE days = 1")
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
# Get all remaining users
|
||||||
|
cursor.execute("SELECT * FROM prison")
|
||||||
|
prisoners = cursor.fetchall()
|
||||||
|
|
||||||
|
for prisoner in prisoners:
|
||||||
|
cursor.execute("UPDATE prison "
|
||||||
|
"SET bail = %s, days = %s "
|
||||||
|
"WHERE userid = %s",
|
||||||
|
(float(prisoner[1]) - float(prisoner[3]), int(prisoner[2]) - 1,
|
||||||
|
int(prisoner[0]),))
|
||||||
|
connection.commit()
|
|
@ -0,0 +1,154 @@
|
||||||
|
from functions import xp
|
||||||
|
from functions.database import utils
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def getOrAddUser(userid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "SELECT * FROM personalstats WHERE userid = %s"
|
||||||
|
cursor.execute(
|
||||||
|
query, (int(userid),)
|
||||||
|
)
|
||||||
|
result = cursor.fetchall()
|
||||||
|
# User didn't exist yet, so create a new default file
|
||||||
|
if len(result) == 0:
|
||||||
|
createNewUser(userid, connection)
|
||||||
|
return getOrAddUser(userid)
|
||||||
|
return result[0]
|
||||||
|
|
||||||
|
|
||||||
|
def createNewUser(userid, connection=None):
|
||||||
|
if connection is None:
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "INSERT INTO personalstats(userid, poked, robs_success, robs_failed, robs_total, longest_streak) " \
|
||||||
|
"VALUES (%s, 0, 0, 0, 0, 0)"
|
||||||
|
cursor.execute(query, (int(userid),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def getAllRows():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"""SELECT * FROM personalstats"""
|
||||||
|
)
|
||||||
|
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def update(userid, column, value):
|
||||||
|
_ = getOrAddUser(userid)
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
query = "UPDATE personalstats " \
|
||||||
|
"SET {} = %s " \
|
||||||
|
"WHERE userid = %s".format(column)
|
||||||
|
cursor.execute(query, (value, userid,))
|
||||||
|
connection.commit()
|
||||||
|
statsTracker(column)
|
||||||
|
|
||||||
|
|
||||||
|
# Automatically change global stats
|
||||||
|
def statsTracker(column):
|
||||||
|
if column in stats()["rob"]:
|
||||||
|
with open("files/stats.json", "r") as fp:
|
||||||
|
s = json.load(fp)
|
||||||
|
|
||||||
|
s["rob"][column] += 1
|
||||||
|
|
||||||
|
with open("files/stats.json", "w") as fp:
|
||||||
|
json.dump(s, fp)
|
||||||
|
|
||||||
|
|
||||||
|
def stats():
|
||||||
|
return {"rob": ["robs_failed", "robs_success"]}
|
||||||
|
|
||||||
|
|
||||||
|
# Gets a random person that has been poked before & has not blacklisted themself
|
||||||
|
def pokeResetCandidate(current, blacklisted):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM personalstats WHERE poked != 0 and userid != %s and userid not in %s",
|
||||||
|
(int(current), tuple(blacklisted)))
|
||||||
|
return random.choice(cursor.fetchall())[0]
|
||||||
|
|
||||||
|
|
||||||
|
def sentMessage(message):
|
||||||
|
user = message.author
|
||||||
|
|
||||||
|
# Ignore bots
|
||||||
|
if user.bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ignore dm's
|
||||||
|
if message.guild is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Don't give xp for bot commands
|
||||||
|
if message.content.lower().startswith(("didier", "owo", "?", "rps", "p!", "-")):
|
||||||
|
return
|
||||||
|
|
||||||
|
user_db = getOrAddUser(user.id)
|
||||||
|
|
||||||
|
update(user.id, "messages", user_db[11] + 1)
|
||||||
|
update_channel(message.channel.id)
|
||||||
|
|
||||||
|
# Only gain xp every minute
|
||||||
|
if round(time.time()) - user_db[13] > 30:
|
||||||
|
gainXp(user.id, user_db)
|
||||||
|
|
||||||
|
|
||||||
|
def gainXp(user, user_db):
|
||||||
|
update(user, "xp", user_db[12] + random.randint(5, 15) + (xp.calculate_level(user_db[12]) * 3))
|
||||||
|
update(user, "last_message", round(time.time()))
|
||||||
|
|
||||||
|
|
||||||
|
def getOrAddChannel(channelid: int):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SELECT * FROM channel_activity WHERE channel_id = %s", (channelid,))
|
||||||
|
|
||||||
|
res = cursor.fetchall()
|
||||||
|
|
||||||
|
if not res:
|
||||||
|
cursor.execute("INSERT INTO channel_activity(channel_id, message_count) VALUES (%s, 0)", (channelid,))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
return getOrAddChannel(channelid)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def channel_activity(channel=None):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# All channels
|
||||||
|
if channel is None:
|
||||||
|
cursor.execute("SELECT * FROM channel_activity")
|
||||||
|
return cursor.fetchall()
|
||||||
|
return getOrAddChannel(channel.id)
|
||||||
|
|
||||||
|
|
||||||
|
def update_channel(channelid: int):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
channel = getOrAddChannel(channelid)[0]
|
||||||
|
cursor.execute("UPDATE channel_activity SET message_count = %s WHERE channel_id = %s",
|
||||||
|
(float(channel[1]) + 1, channelid))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def lower_channel(channelid: int, message_count):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("UPDATE channel_activity SET message_count = %s WHERE channel_id = %s",
|
||||||
|
(float(message_count), channelid,))
|
||||||
|
connection.commit()
|
|
@ -0,0 +1,87 @@
|
||||||
|
from functions import checks
|
||||||
|
from functions.database import utils, currency
|
||||||
|
|
||||||
|
|
||||||
|
def buy(ctx, userid, itemid, amount):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
dinks = currency.dinks(userid)
|
||||||
|
cursor.execute("SELECT * FROM store WHERE itemid = %s", (int(itemid),))
|
||||||
|
result = cursor.fetchall()
|
||||||
|
if not result:
|
||||||
|
return False, "Er is geen item met dit id."
|
||||||
|
|
||||||
|
# Not an empty list, no IndexError.
|
||||||
|
result = result[0]
|
||||||
|
|
||||||
|
cursor.execute("SELECT amount FROM inventory WHERE userid = %s AND itemid = %s", (int(userid), int(itemid),))
|
||||||
|
inv = cursor.fetchall()
|
||||||
|
# Check if user already owns this
|
||||||
|
limit = result[3]
|
||||||
|
if limit is not None \
|
||||||
|
and inv \
|
||||||
|
and inv[0][0] + amount > limit:
|
||||||
|
return False, "Je kan dit item maar {} keer kopen.".format(limit)
|
||||||
|
|
||||||
|
isValid = checks.isValidAmount(ctx, result[2] * amount)
|
||||||
|
|
||||||
|
if not isValid[0]:
|
||||||
|
return isValid
|
||||||
|
|
||||||
|
currency.update(userid, "dinks", dinks - (result[2] * amount))
|
||||||
|
addItem(userid, itemid, amount, inv)
|
||||||
|
return True, {"id": result[0], "name": result[1], "price": result[2] * amount}
|
||||||
|
|
||||||
|
|
||||||
|
def addItem(userid, itemid, amount, inv):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# It's already in there, add more to the counter
|
||||||
|
if inv:
|
||||||
|
amount += inv[0][0]
|
||||||
|
cursor.execute("UPDATE inventory SET amount = %s WHERE userid = %s AND itemid = %s", (amount, userid, itemid))
|
||||||
|
connection.commit()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Doesn't own this item yet, add a new row
|
||||||
|
cursor.execute("INSERT INTO inventory(userid, itemid, amount) VALUES (%s, %s, %s)", (userid, itemid, amount))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def getAllItems():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SELECT * FROM store")
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def getItemPrice(itemid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SELECT price FROM store WHERE itemid = %s", (itemid,))
|
||||||
|
return cursor.fetchone()
|
||||||
|
|
||||||
|
|
||||||
|
def inventory(userid):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SELECT inventory.itemid, name, amount FROM inventory INNER JOIN store on inventory.itemid = store.itemid WHERE userid = %s", (int(userid),))
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
# Amount = amount of item before sell
|
||||||
|
def sell(userid, itemid, sold, amount):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# Don't store amount: 0
|
||||||
|
if sold == amount:
|
||||||
|
cursor.execute("DELETE FROM inventory WHERE userid = %s AND itemid = %s", (userid, itemid,))
|
||||||
|
return connection.commit()
|
||||||
|
|
||||||
|
cursor.execute("UPDATE inventory SET amount = %s WHERE userid = %s AND itemid = %s", (amount - sold, userid, itemid))
|
||||||
|
return connection.commit()
|
|
@ -0,0 +1,17 @@
|
||||||
|
from functions.database import utils
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def add(quote, date, location):
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("INSERT INTO trump(quote, date, location) VALUES (%s, %s, %s)", (str(quote), str(date), str(location),))
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def getRandomQuote():
|
||||||
|
connection = utils.connect()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT * FROM trump")
|
||||||
|
result = cursor.fetchall()
|
||||||
|
return random.choice(result)
|