mirror of
https://gitlab.com/ddorn/tfjm-discord-bot.git
synced 2025-07-07 22:40:13 +02:00
Compare commits
26 Commits
924abea6c8
...
better-tir
Author | SHA1 | Date | |
---|---|---|---|
07d7d9be7a | |||
0fb3a3ca4a | |||
adcd719357 | |||
697f1caf91 | |||
53370fbcb6 | |||
ef8144a115 | |||
fc08c60230 | |||
56cf3f2f55 | |||
3551068a3f | |||
f7db834f3c | |||
860cbb563e | |||
5a402eaf09 | |||
8cba9db097 | |||
a632bdf088 | |||
d792a87be3 | |||
5c522f07e3 | |||
6815c33ea1 | |||
0f1bc903bf | |||
af1f2d1ae2 | |||
553d124b1a | |||
3dd50a75c3 | |||
a520abb90a | |||
a95c20c5b5 | |||
dfc8176084 | |||
cfdd55daa2 | |||
62256a98e8 |
5
bot.py
5
bot.py
@ -1,5 +1,4 @@
|
|||||||
from src import bot
|
from src import start
|
||||||
from src.constants import TOKEN
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
bot.run(TOKEN)
|
start()
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
```
|
|
||||||
- Quelle est votre principale qualité ?
|
|
||||||
- Je suis très rapide en calcul mental.
|
|
||||||
- 23 x 547 ?
|
|
||||||
- 56
|
|
||||||
- Mais c'est faux !
|
|
||||||
- Oui mais c'est rapide !
|
|
||||||
```
|
|
||||||
---
|
|
||||||
Why did the chicken cross the mobius strip?
|
Why did the chicken cross the mobius strip?
|
||||||
|| To get to the same side. ||
|
|| To get to the same side. ||
|
||||||
---
|
---
|
||||||
|
@ -1 +1 @@
|
|||||||
from src.tfjm_discord_bot import bot
|
from src.tfjm_discord_bot import start
|
||||||
|
334
src/base_tirage.py
Normal file
334
src/base_tirage.py
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
import asyncio
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
from functools import wraps
|
||||||
|
from pathlib import Path
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
from io import StringIO
|
||||||
|
from typing import Type, Union, Dict, List
|
||||||
|
|
||||||
|
import discord
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from src.constants import *
|
||||||
|
|
||||||
|
|
||||||
|
class Event(asyncio.Event):
|
||||||
|
def __init__(self, team: str, value: Union[bool, int, str]):
|
||||||
|
super(Event, self).__init__()
|
||||||
|
self.value = value
|
||||||
|
self.team = team
|
||||||
|
self.response = None
|
||||||
|
|
||||||
|
|
||||||
|
class Team:
|
||||||
|
yaml_tag = "Team"
|
||||||
|
|
||||||
|
def __init__(self, team_role):
|
||||||
|
self.name = team_role.name
|
||||||
|
self.mention = team_role.mention
|
||||||
|
|
||||||
|
self.accepted_problems = [None, None]
|
||||||
|
self.rejected = [set(), set()]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = StringIO()
|
||||||
|
pprint(self.__dict__, stream=s)
|
||||||
|
s.seek(0)
|
||||||
|
return s.read()
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
def coeff(self, round):
|
||||||
|
if len(self.rejected[round]) <= MAX_REFUSE:
|
||||||
|
return 2
|
||||||
|
else:
|
||||||
|
return 2 - 0.5 * (len(self.rejected[round]) - MAX_REFUSE)
|
||||||
|
|
||||||
|
def details(self, round):
|
||||||
|
|
||||||
|
info = {
|
||||||
|
# "Accepté": self.accepted_problems[round],
|
||||||
|
"Refusés": ", ".join(p[0] for p in self.rejected[round])
|
||||||
|
if self.rejected[round]
|
||||||
|
else "aucun",
|
||||||
|
"Coefficient": self.coeff(round),
|
||||||
|
# "Ordre passage": self.passage_order[round],
|
||||||
|
}
|
||||||
|
|
||||||
|
width = max(map(len, info))
|
||||||
|
|
||||||
|
return "\n".join(f"`{n.rjust(width)}`: {v}" for n, v in info.items())
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# return f""" - Accepté: {self.accepted_problems[round]}
|
||||||
|
# - Refusés: {", ".join(p[0] for p in self.rejected[round]) if self.rejected[round] else "aucun"}
|
||||||
|
# - Coefficient: {self.coeff(round)}
|
||||||
|
# - Ordre au tirage: {self.tirage_order[round]}
|
||||||
|
# - Ordre de passage: {self.passage_order[round]}
|
||||||
|
# """
|
||||||
|
|
||||||
|
|
||||||
|
class Poule(yaml.YAMLObject):
|
||||||
|
yaml_tag = "Poule"
|
||||||
|
|
||||||
|
def __init__(self, poule, rnd):
|
||||||
|
self.poule = poule
|
||||||
|
self.rnd = rnd
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.poule}{self.rnd + 1}"
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTirage(yaml.YAMLObject):
|
||||||
|
yaml_tag = "Tirage"
|
||||||
|
|
||||||
|
def __init__(self, *teams: discord.Role, fmt=(3, 3)):
|
||||||
|
assert sum(fmt) == len(teams), "Different number of teams and format"
|
||||||
|
|
||||||
|
self.teams: Dict[str, Team] = {t.name: Team(t) for t in teams}
|
||||||
|
self.format = fmt
|
||||||
|
self.queue = asyncio.Queue()
|
||||||
|
self.poules: Dict[Poule, List[str]] = {}
|
||||||
|
"""A mapping between the poule and the list of teams in this poule."""
|
||||||
|
|
||||||
|
def availaible(self, pb, poule):
|
||||||
|
pbs = [
|
||||||
|
self.teams[team].accepted_problems[poule.rnd] for team in self.poules[poule]
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(self.poules[poule]) < 5:
|
||||||
|
return pb not in pbs
|
||||||
|
else:
|
||||||
|
return pbs.count(pb) < 2
|
||||||
|
|
||||||
|
async def event(self, event: Event):
|
||||||
|
event.set()
|
||||||
|
await self.queue.put(event)
|
||||||
|
await event.wait()
|
||||||
|
return event.response
|
||||||
|
|
||||||
|
async def dice(self, trigram):
|
||||||
|
return await self.event(Event(trigram, random.randint(1, 100)))
|
||||||
|
|
||||||
|
async def rproblem(self, trigram):
|
||||||
|
team = self.teams[trigram]
|
||||||
|
rnd = 0 if team.accepted_problems[0] is None else 1
|
||||||
|
for poule, teams in self.poules.items():
|
||||||
|
if trigram in teams and poule.rnd == rnd:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return await self.warn_wrong_team(None, trigram)
|
||||||
|
|
||||||
|
available = [
|
||||||
|
pb
|
||||||
|
for pb in PROBLEMS
|
||||||
|
if pb not in team.accepted_problems and self.availaible(pb, poule)
|
||||||
|
]
|
||||||
|
return await self.event(Event(trigram, random.choice(available)))
|
||||||
|
|
||||||
|
async def accept(self, trigram, yes: bool):
|
||||||
|
return await self.event(Event(trigram, yes))
|
||||||
|
|
||||||
|
async def next(self, typ, team=None):
|
||||||
|
while True:
|
||||||
|
event = await self.queue.get()
|
||||||
|
if team is not None and event.team != team:
|
||||||
|
await self.warn_wrong_team(team, event.team)
|
||||||
|
elif not isinstance(event.value, typ):
|
||||||
|
await self.warn_unwanted(typ, event.value)
|
||||||
|
else:
|
||||||
|
event.clear()
|
||||||
|
return event
|
||||||
|
event.clear()
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
|
||||||
|
await self.info_start()
|
||||||
|
|
||||||
|
self.poules = await self.make_poules()
|
||||||
|
|
||||||
|
for poule in self.poules:
|
||||||
|
await self.draw_poule(poule)
|
||||||
|
|
||||||
|
await self.info_finish()
|
||||||
|
|
||||||
|
async def get_dices(self, teams):
|
||||||
|
dices = {t: None for t in teams}
|
||||||
|
collisions = list(teams)
|
||||||
|
while collisions:
|
||||||
|
|
||||||
|
for t in collisions:
|
||||||
|
dices[t] = None
|
||||||
|
|
||||||
|
while None in dices.values():
|
||||||
|
event = await self.next(int)
|
||||||
|
|
||||||
|
if event.team not in dices:
|
||||||
|
await self.warn_wrong_team(None, event.team)
|
||||||
|
elif dices[event.team] is None:
|
||||||
|
dices[event.team] = event.value
|
||||||
|
await self.info_dice(event.team, event.value)
|
||||||
|
else:
|
||||||
|
await self.warn_twice(int)
|
||||||
|
|
||||||
|
collisions = [t for t in teams if list(dices.values()).count(dices[t]) > 1]
|
||||||
|
if collisions:
|
||||||
|
await self.warn_colisions(collisions)
|
||||||
|
|
||||||
|
return dices
|
||||||
|
|
||||||
|
async def make_poules(self):
|
||||||
|
poules = {}
|
||||||
|
for rnd in (0, 1):
|
||||||
|
await self.start_make_poule(rnd)
|
||||||
|
|
||||||
|
dices = await self.get_dices(self.teams)
|
||||||
|
sorted_teams = sorted(self.teams, key=lambda t: dices[t])
|
||||||
|
|
||||||
|
idx = 0
|
||||||
|
for i, qte in enumerate(self.format):
|
||||||
|
letter = chr(ord("A") + i)
|
||||||
|
poules[Poule(letter, rnd)] = sorted_teams[idx : idx + qte]
|
||||||
|
idx += qte
|
||||||
|
|
||||||
|
await self.annonce_poules(poules)
|
||||||
|
return poules
|
||||||
|
|
||||||
|
async def draw_poule(self, poule):
|
||||||
|
|
||||||
|
await self.start_draw_poule(poule)
|
||||||
|
|
||||||
|
# Trigrams in draw order
|
||||||
|
trigrams = await self.draw_order(poule)
|
||||||
|
|
||||||
|
# Teams in draw order
|
||||||
|
teams = [self.teams[tri] for tri in trigrams]
|
||||||
|
current = 0
|
||||||
|
while not all(team.accepted_problems[poule.rnd] for team in teams):
|
||||||
|
team = teams[current]
|
||||||
|
if team.accepted_problems[poule.rnd] is not None:
|
||||||
|
# The team already accepted a problem
|
||||||
|
current += 1
|
||||||
|
current %= len(teams)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Choose problem
|
||||||
|
await self.start_select_pb(team)
|
||||||
|
pevent = await self.next(str, team.name)
|
||||||
|
# TODO: Add check for already selected / taken by someone else
|
||||||
|
# This is not a bug for now, since it cannot happen yet
|
||||||
|
await self.info_draw_pb(team, pevent.value, poule.rnd)
|
||||||
|
|
||||||
|
# Accept it
|
||||||
|
accept = await self.next(bool, team.name)
|
||||||
|
if accept.value:
|
||||||
|
team.accepted_problems[poule.rnd] = pevent.value
|
||||||
|
await self.info_accepted(
|
||||||
|
team, pevent.value, self.availaible(pevent.value, poule)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self.info_rejected(team, pevent.value, rnd=poule.rnd)
|
||||||
|
team.rejected[poule.rnd].add(pevent.value)
|
||||||
|
|
||||||
|
current += 1
|
||||||
|
current %= len(teams)
|
||||||
|
|
||||||
|
if len(teams) == 5:
|
||||||
|
# We can determine the passage order only once problems are drawn.
|
||||||
|
order = [self.teams[tri] for tri in self.poules[poule]]
|
||||||
|
pbs = [team.accepted_problems[poule.rnd] for team in order]
|
||||||
|
|
||||||
|
doubles = []
|
||||||
|
i = 0
|
||||||
|
while i < len(order):
|
||||||
|
team = order[i]
|
||||||
|
if pbs.count(team.accepted_problems[poule.rnd]) == 2:
|
||||||
|
# We pop the two with the same pb and add them to the doubles
|
||||||
|
doubles.append(order.pop(i))
|
||||||
|
other = next(
|
||||||
|
filter(
|
||||||
|
lambda t: team.accepted_problems[poule.rnd]
|
||||||
|
== t.accepted_problems[poule.rnd],
|
||||||
|
order,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
doubles.append(other)
|
||||||
|
order.remove(other)
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
# The conflicts
|
||||||
|
order = doubles + order
|
||||||
|
self.poules[poule] = order
|
||||||
|
|
||||||
|
await self.annonce_poule(poule)
|
||||||
|
|
||||||
|
async def draw_order(self, poule):
|
||||||
|
await self.start_draw_order(poule)
|
||||||
|
|
||||||
|
teams = self.poules[poule]
|
||||||
|
dices = await self.get_dices(teams)
|
||||||
|
|
||||||
|
order = sorted(teams, key=lambda t: dices[t], reverse=True)
|
||||||
|
|
||||||
|
await self.annonce_draw_order(order)
|
||||||
|
return order
|
||||||
|
|
||||||
|
async def warn_unwanted(self, wanted: Type, got: Type):
|
||||||
|
"""Called when a event of an unwanted type occurs."""
|
||||||
|
|
||||||
|
async def warn_wrong_team(self, expected, got):
|
||||||
|
"""Called when a team that should not play now put an event"""
|
||||||
|
|
||||||
|
async def warn_colisions(self, collisions: List[str]):
|
||||||
|
"""Called when there are collisions in a dice tirage."""
|
||||||
|
|
||||||
|
async def warn_twice(self, typ: Type):
|
||||||
|
"""Called when an event appears once again and not wanted."""
|
||||||
|
|
||||||
|
async def start_make_poule(self, rnd):
|
||||||
|
"""Called when it starts drawing the poules for round `rnd`"""
|
||||||
|
|
||||||
|
async def start_draw_poule(self, poule):
|
||||||
|
"""Called when we start a poule."""
|
||||||
|
|
||||||
|
async def start_draw_order(self, poule):
|
||||||
|
"""Called when we start to draw the order."""
|
||||||
|
|
||||||
|
async def start_select_pb(self, team):
|
||||||
|
"""Called when a team needs to select a problem."""
|
||||||
|
|
||||||
|
async def annonce_poules(self, poules):
|
||||||
|
"""Called when all poules are defined."""
|
||||||
|
|
||||||
|
async def annonce_draw_order(self, order):
|
||||||
|
"""Called when the drawing order is defined."""
|
||||||
|
|
||||||
|
async def annonce_poule(self, poule):
|
||||||
|
"""Called when the problems and order for a poule is known."""
|
||||||
|
|
||||||
|
async def info_start(self):
|
||||||
|
"""Called at the start of the tirage."""
|
||||||
|
|
||||||
|
async def info_finish(self):
|
||||||
|
"""Called when the tirage has ended."""
|
||||||
|
|
||||||
|
async def info_dice(self, team, dice):
|
||||||
|
"""Called on a dice roll."""
|
||||||
|
|
||||||
|
async def info_draw_pb(self, team, pb, rnd):
|
||||||
|
"""Called when a team draws a problem."""
|
||||||
|
|
||||||
|
async def info_accepted(self, team, pb, still_available):
|
||||||
|
"""Called when a team accepts a problem."""
|
||||||
|
|
||||||
|
async def info_rejected(self, team, pb, rnd):
|
||||||
|
"""Called when a team rejects a problem,
|
||||||
|
before it is added to the rejected set."""
|
||||||
|
|
||||||
|
|
||||||
|
def setup(_):
|
||||||
|
pass
|
@ -2,7 +2,7 @@ import asyncio
|
|||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import TextChannel, PermissionOverwrite, Message
|
from discord import TextChannel, PermissionOverwrite, Message, ChannelType
|
||||||
from discord.ext.commands import (
|
from discord.ext.commands import (
|
||||||
command,
|
command,
|
||||||
has_role,
|
has_role,
|
||||||
@ -16,8 +16,10 @@ from ptpython.repl import embed
|
|||||||
|
|
||||||
from src.constants import *
|
from src.constants import *
|
||||||
from src.core import CustomBot
|
from src.core import CustomBot
|
||||||
|
from src.utils import fg
|
||||||
|
|
||||||
COGS_SHORTCUTS = {
|
COGS_SHORTCUTS = {
|
||||||
|
"bt": "src.base_tirage",
|
||||||
"c": "src.constants",
|
"c": "src.constants",
|
||||||
"d": "tirages",
|
"d": "tirages",
|
||||||
"e": "errors",
|
"e": "errors",
|
||||||
@ -53,7 +55,7 @@ class DevCog(Cog, name="Dev tools"):
|
|||||||
|
|
||||||
def send(msg, channel=None):
|
def send(msg, channel=None):
|
||||||
if isinstance(channel, int):
|
if isinstance(channel, int):
|
||||||
channel = get(ctx.guild.channels, id=channel)
|
channel = self.bot.get_channel(channel)
|
||||||
|
|
||||||
channel = channel or ctx.channel
|
channel = channel or ctx.channel
|
||||||
asyncio.create_task(channel.send(msg))
|
asyncio.create_task(channel.send(msg))
|
||||||
@ -202,6 +204,15 @@ class DevCog(Cog, name="Dev tools"):
|
|||||||
await channel.delete_messages(to_delete)
|
await channel.delete_messages(to_delete)
|
||||||
await ctx.message.delete()
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@Cog.listener()
|
||||||
|
async def on_message(self, msg: Message):
|
||||||
|
ch: TextChannel = msg.channel
|
||||||
|
if ch.type == ChannelType.private:
|
||||||
|
m = f"""{fg(msg.author.name)}: {msg.content}
|
||||||
|
MSG_ID: {fg(msg.id, 0x03A678)}
|
||||||
|
CHA_ID: {fg(msg.channel.id, 0x03A678)}"""
|
||||||
|
print(m)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: CustomBot):
|
def setup(bot: CustomBot):
|
||||||
bot.add_cog(DevCog(bot))
|
bot.add_cog(DevCog(bot))
|
||||||
|
221
src/cogs/misc.py
221
src/cogs/misc.py
@ -1,16 +1,18 @@
|
|||||||
|
import asyncio
|
||||||
import datetime
|
import datetime
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
import random
|
import random
|
||||||
|
import urllib
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from time import time
|
from time import time
|
||||||
from typing import List, Set
|
from typing import List, Set, Union
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import discord
|
||||||
import yaml
|
import yaml
|
||||||
from discord import Guild
|
from discord import Guild, Member
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from discord.ext.commands import (
|
from discord.ext.commands import (
|
||||||
Cog,
|
Cog,
|
||||||
@ -20,11 +22,16 @@ from discord.ext.commands import (
|
|||||||
CommandError,
|
CommandError,
|
||||||
Group,
|
Group,
|
||||||
group,
|
group,
|
||||||
|
MemberConverter,
|
||||||
|
BadArgument,
|
||||||
|
RoleConverter,
|
||||||
)
|
)
|
||||||
|
from discord.utils import get
|
||||||
|
|
||||||
from src.constants import *
|
from src.constants import *
|
||||||
from src.constants import Emoji
|
from src.constants import Emoji
|
||||||
from src.core import CustomBot
|
from src.core import CustomBot
|
||||||
|
from src.errors import TfjmError
|
||||||
from src.utils import has_role, start_time, send_and_bin
|
from src.utils import has_role, start_time, send_and_bin
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +44,7 @@ class Joke(yaml.YAMLObject):
|
|||||||
joker: int
|
joker: int
|
||||||
likes: Set[int] = field(default_factory=set)
|
likes: Set[int] = field(default_factory=set)
|
||||||
dislikes: Set[int] = field(default_factory=set)
|
dislikes: Set[int] = field(default_factory=set)
|
||||||
|
file: str = None
|
||||||
|
|
||||||
|
|
||||||
class MiscCog(Cog, name="Divers"):
|
class MiscCog(Cog, name="Divers"):
|
||||||
@ -44,6 +52,7 @@ class MiscCog(Cog, name="Divers"):
|
|||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.show_hidden = False
|
self.show_hidden = False
|
||||||
self.verify_checks = True
|
self.verify_checks = True
|
||||||
|
self.computing = False
|
||||||
|
|
||||||
@command(
|
@command(
|
||||||
name="choose",
|
name="choose",
|
||||||
@ -94,15 +103,128 @@ class MiscCog(Cog, name="Divers"):
|
|||||||
|
|
||||||
@command(hidden=True)
|
@command(hidden=True)
|
||||||
async def fractal(self, ctx: Context):
|
async def fractal(self, ctx: Context):
|
||||||
await ctx.message.add_reaction(Emoji.CHECK)
|
|
||||||
|
|
||||||
seed = random.randint(0, 1_000_000_000)
|
if self.computing:
|
||||||
async with aiohttp.ClientSession() as session:
|
return await ctx.send("Il y a déjà une fractale en cours de calcul...")
|
||||||
async with session.get(FRACTAL_URL.format(seed=seed)) as resp:
|
|
||||||
if resp.status != 200:
|
try:
|
||||||
return await ctx.send("Could not download file...")
|
self.computing = True
|
||||||
data = io.BytesIO(await resp.read())
|
|
||||||
await ctx.send(file=discord.File(data, "cool_image.png"))
|
await ctx.message.add_reaction(Emoji.CHECK)
|
||||||
|
msg: discord.Message = ctx.message
|
||||||
|
seed = msg.content[len("!fractal ") :]
|
||||||
|
seed = seed or str(random.randint(0, 1_000_000_000))
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(
|
||||||
|
FRACTAL_URL.format(seed=urllib.parse.quote(seed)), timeout=120
|
||||||
|
) as resp:
|
||||||
|
if resp.status != 200:
|
||||||
|
return await ctx.send(
|
||||||
|
"Il y a un problème pour calculer/télécharger l'image..."
|
||||||
|
)
|
||||||
|
data = io.BytesIO(await resp.read())
|
||||||
|
await ctx.send(
|
||||||
|
f"Seed: {seed}", file=discord.File(data, f"{seed}.png")
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
self.computing = False
|
||||||
|
|
||||||
|
@command(hidden=True, aliases=["bang", "pan"])
|
||||||
|
async def pew(self, ctx):
|
||||||
|
await ctx.send("Tu t'es raté ! Kwaaack :duck:")
|
||||||
|
|
||||||
|
@command(aliases=["<3"])
|
||||||
|
async def hug(self, ctx, who="everyone"):
|
||||||
|
"""Fait un câlin à quelqu'un."""
|
||||||
|
|
||||||
|
if who != "everyone":
|
||||||
|
try:
|
||||||
|
who = await RoleConverter().convert(ctx, who)
|
||||||
|
except BadArgument:
|
||||||
|
try:
|
||||||
|
who = await MemberConverter().convert(ctx, who)
|
||||||
|
except BadArgument:
|
||||||
|
return await ctx.send(f'Il n\'y a pas de "{who}". :man_shrugging:')
|
||||||
|
else:
|
||||||
|
who = ctx.guild.default_role
|
||||||
|
who: Union[discord.Role, Member]
|
||||||
|
|
||||||
|
bonuses = [
|
||||||
|
"C'est trop meuuuugnon !",
|
||||||
|
"Ça remonte le moral ! :D",
|
||||||
|
":hugging:",
|
||||||
|
":smiling_face_with_3_hearts:",
|
||||||
|
"Oh wiiii",
|
||||||
|
"Iel se sent désormais prêt à travailler à fond sur les solutions de AQT",
|
||||||
|
f"{who.mention} en redemande un !",
|
||||||
|
"Le·a pauvre, iel est tout·e rouge !",
|
||||||
|
"Hihi, il gratte ton pull en laine ! :sheep:",
|
||||||
|
]
|
||||||
|
|
||||||
|
if (
|
||||||
|
isinstance(who, discord.Member)
|
||||||
|
and has_role(who, Role.JURY)
|
||||||
|
and has_role(ctx.author, Role.PARTICIPANT)
|
||||||
|
):
|
||||||
|
bonuses += ["Il s'agit surement là d'une tentative de corruption !"]
|
||||||
|
|
||||||
|
if who == ctx.author:
|
||||||
|
msg = f"{who.mention} se fait un auto-calin !"
|
||||||
|
bonuses += [
|
||||||
|
"Mais c'est un peu ridicule...",
|
||||||
|
"Mais iel a les bras trop courts ! :cactus:",
|
||||||
|
"Il en faut peu pour être heureux :wink:",
|
||||||
|
]
|
||||||
|
elif who == ctx.guild.default_role:
|
||||||
|
msg = f"{ctx.author.mention} fait un câlin a touuuut le monde !"
|
||||||
|
bonuses += [
|
||||||
|
"Ça fait beaucoup de gens pour un câlin !",
|
||||||
|
"Plus on est, plus on est calins !",
|
||||||
|
"C'est pas très COVID-19 tout ça !",
|
||||||
|
"Tout le monde est heureux maintenant !",
|
||||||
|
]
|
||||||
|
elif who == self.bot.user:
|
||||||
|
bonuses += ["Je trouve ça très bienveillant <3"]
|
||||||
|
else:
|
||||||
|
msg = f"{ctx.author.mention} fait un gros câlin à {who.mention} !"
|
||||||
|
bonuses += [
|
||||||
|
f"Mais {who.mention} n'apprécie pas...",
|
||||||
|
"Et ils s'en vont chasser des canards ensemble :wink:",
|
||||||
|
"Oh ! Iel sent bon...",
|
||||||
|
f"{who.mention} a serré tellment fort qu'iel vous a coupé en deux :scream:",
|
||||||
|
f"{who.mention} propose à {ctx.author.mention} de se revoir autour d'une :pizza: !",
|
||||||
|
"Les drones du commissaire Winston passent par là et vous ordonnent d'arrêter.",
|
||||||
|
"Après ce beau moment de tendresse, ils décident d'aller discuter en créant des puzzles.",
|
||||||
|
f"{who.mention} se réfugie dans l'entrepôt d'Animath et bloque l'entrée avec un meuble.",
|
||||||
|
]
|
||||||
|
|
||||||
|
bonus = random.choice(bonuses)
|
||||||
|
|
||||||
|
await ctx.send(f"{msg} {bonus}")
|
||||||
|
|
||||||
|
@command(aliases=["pong"])
|
||||||
|
async def ping(self, ctx):
|
||||||
|
"""Affiche la latence avec le bot."""
|
||||||
|
ping = time()
|
||||||
|
msg: discord.Message = await ctx.send("Pong !")
|
||||||
|
pong = time()
|
||||||
|
|
||||||
|
await msg.edit(content=f"Pong ! Ça a pris {int(1000 * (pong - ping))}ms")
|
||||||
|
|
||||||
|
@command(name="fan", aliases=["join", "adhere"], hidden=True)
|
||||||
|
async def fan_club_cmd(self, ctx: Context, who: Member):
|
||||||
|
"""Permet de rejoindre le fan-club d'Ananas ou Citron Vert."""
|
||||||
|
role_id = FAN_CLUBS.get(who.id, None)
|
||||||
|
role = get(ctx.guild.roles, id=role_id)
|
||||||
|
|
||||||
|
if role is not None:
|
||||||
|
await ctx.author.add_roles(role)
|
||||||
|
await ctx.send(f"Bienvenue au {role.mention} !! :tada:")
|
||||||
|
else:
|
||||||
|
await ctx.send(
|
||||||
|
f"{who.mention} n'a pas encore de fan club. Peut-être qu'un jour "
|
||||||
|
f"iel sera un membre influent du CNO ?"
|
||||||
|
)
|
||||||
|
|
||||||
# ---------------- Jokes ---------------- #
|
# ---------------- Jokes ---------------- #
|
||||||
|
|
||||||
@ -119,35 +241,58 @@ class MiscCog(Cog, name="Divers"):
|
|||||||
with open(File.JOKES_V2, "w") as f:
|
with open(File.JOKES_V2, "w") as f:
|
||||||
yaml.safe_dump_all(jokes, f)
|
yaml.safe_dump_all(jokes, f)
|
||||||
|
|
||||||
@group(name="joke", hidden=True, invoke_without_command=True)
|
@group(name="joke", invoke_without_command=True)
|
||||||
async def joke(self, ctx):
|
async def joke(self, ctx: Context, id: int = None):
|
||||||
await ctx.message.delete()
|
|
||||||
|
m: discord.Message = ctx.message
|
||||||
|
await m.delete()
|
||||||
|
|
||||||
jokes = self.load_jokes()
|
jokes = self.load_jokes()
|
||||||
joke_id = random.randrange(len(jokes))
|
if id is not None:
|
||||||
joke = jokes[joke_id]
|
joke_id = id
|
||||||
|
jokes = sorted(
|
||||||
|
jokes, key=lambda j: len(j.likes) - len(j.dislikes), reverse=True
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
joke_id = random.randrange(len(jokes))
|
||||||
|
|
||||||
message: discord.Message = await ctx.send(joke.joke)
|
try:
|
||||||
|
joke = jokes[joke_id]
|
||||||
|
except IndexError:
|
||||||
|
raise TfjmError("Il n'y a pas de blague avec cet ID.")
|
||||||
|
|
||||||
|
if joke.file:
|
||||||
|
file = discord.File(File.MEMES / joke.file)
|
||||||
|
else:
|
||||||
|
file = None
|
||||||
|
|
||||||
|
message: discord.Message = await ctx.send(joke.joke, file=file)
|
||||||
|
|
||||||
await message.add_reaction(Emoji.PLUS_1)
|
await message.add_reaction(Emoji.PLUS_1)
|
||||||
await message.add_reaction(Emoji.MINUS_1)
|
await message.add_reaction(Emoji.MINUS_1)
|
||||||
await self.wait_for_joke_reactions(joke_id, message)
|
await self.wait_for_joke_reactions(joke_id, message)
|
||||||
|
|
||||||
@joke.command(name="new", hidden=True)
|
@joke.command(name="new")
|
||||||
@send_and_bin
|
@send_and_bin
|
||||||
async def new_joke(self, ctx: Context):
|
async def new_joke(self, ctx: Context):
|
||||||
|
"""Ajoute une blague pour le concours de blague."""
|
||||||
|
jokes = self.load_jokes()
|
||||||
|
joke_id = len(jokes)
|
||||||
|
|
||||||
author: discord.Member = ctx.author
|
author: discord.Member = ctx.author
|
||||||
message: discord.Message = ctx.message
|
message: discord.Message = ctx.message
|
||||||
|
|
||||||
start = "!joke new "
|
msg = message.content[len("!joke new ") :]
|
||||||
msg = message.content[len(start) :]
|
|
||||||
|
|
||||||
joke = Joke(msg, ctx.author.id, set())
|
joke = Joke(msg, ctx.author.id, set())
|
||||||
|
|
||||||
jokes = self.load_jokes()
|
if message.attachments:
|
||||||
|
file: discord.Attachment = message.attachments[0]
|
||||||
|
joke.file = str(f"{joke_id}-{file.filename}")
|
||||||
|
await file.save(File.MEMES / joke.file)
|
||||||
|
|
||||||
jokes.append(joke)
|
jokes.append(joke)
|
||||||
self.save_jokes(jokes)
|
self.save_jokes(jokes)
|
||||||
joke_id = len(jokes) - 1
|
|
||||||
await message.add_reaction(Emoji.PLUS_1)
|
await message.add_reaction(Emoji.PLUS_1)
|
||||||
await message.add_reaction(Emoji.MINUS_1)
|
await message.add_reaction(Emoji.MINUS_1)
|
||||||
|
|
||||||
@ -163,9 +308,13 @@ class MiscCog(Cog, name="Divers"):
|
|||||||
start = time()
|
start = time()
|
||||||
end = start + 24 * 60 * 60
|
end = start + 24 * 60 * 60
|
||||||
while time() < end:
|
while time() < end:
|
||||||
reaction, user = await self.bot.wait_for(
|
|
||||||
"reaction_add", check=check, timeout=end - time()
|
try:
|
||||||
)
|
reaction, user = await self.bot.wait_for(
|
||||||
|
"reaction_add", check=check, timeout=end - time()
|
||||||
|
)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
return
|
||||||
|
|
||||||
if user.id == BOT:
|
if user.id == BOT:
|
||||||
continue
|
continue
|
||||||
@ -178,6 +327,28 @@ class MiscCog(Cog, name="Divers"):
|
|||||||
|
|
||||||
self.save_jokes(jokes)
|
self.save_jokes(jokes)
|
||||||
|
|
||||||
|
@joke.command(name="top", hidden=True)
|
||||||
|
async def best_jokes(self, ctx: Context):
|
||||||
|
"""Affiche le palmares des blagues."""
|
||||||
|
|
||||||
|
jokes = self.load_jokes()
|
||||||
|
|
||||||
|
s = sorted(jokes, key=lambda j: len(j.likes) - len(j.dislikes), reverse=True)
|
||||||
|
|
||||||
|
embed = discord.Embed(title="Palmares des blagues.")
|
||||||
|
for i, joke in enumerate(s[:10]):
|
||||||
|
who = get(ctx.guild.members, id=joke.joker)
|
||||||
|
|
||||||
|
text = joke.joke
|
||||||
|
if joke.file:
|
||||||
|
text += " - image non inclue - "
|
||||||
|
|
||||||
|
embed.add_field(
|
||||||
|
name=f"{i} - {who.display_name} - {len(joke.likes)}", value=text
|
||||||
|
)
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
# ----------------- Help ---------------- #
|
# ----------------- Help ---------------- #
|
||||||
|
|
||||||
@command(name="help", aliases=["h"])
|
@command(name="help", aliases=["h"])
|
||||||
@ -231,7 +402,7 @@ class MiscCog(Cog, name="Divers"):
|
|||||||
return await ctx.send(embed=embed)
|
return await ctx.send(embed=embed)
|
||||||
|
|
||||||
async def send_command_help(self, ctx, args):
|
async def send_command_help(self, ctx, args):
|
||||||
name = " ".join(args)
|
name = " ".join(args).strip("!")
|
||||||
comm: Command = self.bot.get_command(name)
|
comm: Command = self.bot.get_command(name)
|
||||||
if comm is None:
|
if comm is None:
|
||||||
return await ctx.send(
|
return await ctx.send(
|
||||||
|
@ -9,7 +9,7 @@ from discord.utils import get, find
|
|||||||
|
|
||||||
from src.constants import *
|
from src.constants import *
|
||||||
from src.core import CustomBot
|
from src.core import CustomBot
|
||||||
from src.utils import has_role, send_and_bin
|
from src.utils import has_role, send_and_bin, french_join
|
||||||
|
|
||||||
Team = namedtuple("Team", ["name", "trigram", "tournoi", "secret", "status"])
|
Team = namedtuple("Team", ["name", "trigram", "tournoi", "secret", "status"])
|
||||||
|
|
||||||
@ -90,33 +90,30 @@ class TeamsCog(Cog, name="Teams"):
|
|||||||
return "C'est fait !"
|
return "C'est fait !"
|
||||||
|
|
||||||
@commands.command(name="tourist")
|
@commands.command(name="tourist")
|
||||||
@commands.has_any_role(*Role.ORGAS)
|
|
||||||
@send_and_bin
|
@send_and_bin
|
||||||
async def touriste_cmd(self, ctx: Context, poule, member: Member):
|
async def touriste_cmd(self, ctx: Context, tournoi):
|
||||||
"""
|
"""
|
||||||
(orga) Accepte quelqu'un comme touriste pour une certaine poule.
|
Permet de voir et ecouter dans les salons d'un certain tournoi.
|
||||||
|
|
||||||
Exemple:
|
Exemple:
|
||||||
`!tourist A Diego` - Ajoute Diego comme touriste dans la Poule A
|
`!tourist Bordeaux-Nancy` - Donne les droits de spectateurs pour Bordeaux-Nancy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
poule = f"Poule {poule}"
|
if ctx.author.top_role != ctx.guild.default_role:
|
||||||
tournoi = find(lambda r: r.name.startswith("Orga"), ctx.author.roles)
|
return f"{ctx.author.mention} tu as déjà un role, devenir spéctateur t'enlèverait des droits."
|
||||||
tournoi_name = tournoi.name.partition(" ")[2]
|
|
||||||
|
if tournoi not in TOURNOIS:
|
||||||
|
return f"{tournoi} n'est pas un nom de tournoi. Possibilités: {french_join(TOURNOIS)}"
|
||||||
|
|
||||||
guild: discord.Guild = ctx.guild
|
guild: discord.Guild = ctx.guild
|
||||||
|
tournoi_role = get(guild.roles, name=tournoi)
|
||||||
poule_channel: VoiceChannel = get(
|
|
||||||
guild.voice_channels, name=poule, category__name=tournoi_name
|
|
||||||
)
|
|
||||||
if poule_channel is None:
|
|
||||||
return f"La poule '{poule}' n'existe pas à {tournoi_name}"
|
|
||||||
|
|
||||||
touriste_role = get(guild.roles, name=Role.TOURIST)
|
touriste_role = get(guild.roles, name=Role.TOURIST)
|
||||||
region = get(guild.roles, name=tournoi_name)
|
|
||||||
await member.add_roles(touriste_role, region)
|
|
||||||
|
|
||||||
await poule_channel.set_permissions(member, view_channel=True, connect=True)
|
await ctx.author.add_roles(
|
||||||
return f"{member.mention} à été ajouté comme spectateur dans la {poule} de {tournoi_name}"
|
touriste_role, tournoi_role, reason="Demande via le bot."
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"{ctx.author.mention} à été ajouté comme spectateur dans à {tournoi}."
|
||||||
|
|
||||||
@group(name="team", invoke_without_command=True)
|
@group(name="team", invoke_without_command=True)
|
||||||
async def team(self, ctx):
|
async def team(self, ctx):
|
||||||
@ -279,7 +276,9 @@ class TeamsCog(Cog, name="Teams"):
|
|||||||
channel_name,
|
channel_name,
|
||||||
overwrites={
|
overwrites={
|
||||||
guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
||||||
team_role: discord.PermissionOverwrite(read_messages=True),
|
team_role: discord.PermissionOverwrite(
|
||||||
|
read_messages=True, manage_channels=True
|
||||||
|
),
|
||||||
},
|
},
|
||||||
category=team_channel_category,
|
category=team_channel_category,
|
||||||
reason=f"{ctx.author.name} à demandé une channel pour son équipe.",
|
reason=f"{ctx.author.name} à demandé une channel pour son équipe.",
|
||||||
|
1055
src/cogs/tirages.py
1055
src/cogs/tirages.py
File diff suppressed because it is too large
Load Diff
@ -3,25 +3,31 @@ from pathlib import Path
|
|||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"TOKEN",
|
"DISCORD_TOKEN",
|
||||||
|
"TFJM_TOKEN",
|
||||||
"Role",
|
"Role",
|
||||||
"PROBLEMS",
|
"PROBLEMS",
|
||||||
"MAX_REFUSE",
|
"MAX_REFUSE",
|
||||||
"ROUND_NAMES",
|
"ROUND_NAMES",
|
||||||
"TEAMS_CHANNEL_CATEGORY",
|
"TEAMS_CHANNEL_CATEGORY",
|
||||||
"DIEGO",
|
"DIEGO",
|
||||||
|
"ANANAS",
|
||||||
|
"FAN_CLUBS",
|
||||||
"BOT",
|
"BOT",
|
||||||
"TOURNOIS",
|
"TOURNOIS",
|
||||||
"EMBED_COLOR",
|
"EMBED_COLOR",
|
||||||
"FRACTAL_URL",
|
"FRACTAL_URL",
|
||||||
|
"FRACTAL_COOLDOWN",
|
||||||
"File",
|
"File",
|
||||||
"Emoji",
|
"Emoji",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
TOKEN = os.environ.get("TFJM_DISCORD_TOKEN")
|
DISCORD_TOKEN = os.environ.get("TFJM_DISCORD_TOKEN")
|
||||||
|
TFJM_TOKEN = os.environ.get("TFJM_ORG_TOKEN")
|
||||||
|
|
||||||
if TOKEN is None:
|
|
||||||
|
if DISCORD_TOKEN is None:
|
||||||
print("No token for the bot were found.")
|
print("No token for the bot were found.")
|
||||||
print("You need to set the TFJM_DISCORD_TOKEN variable in your environement")
|
print("You need to set the TFJM_DISCORD_TOKEN variable in your environement")
|
||||||
print("Or just run:")
|
print("Or just run:")
|
||||||
@ -32,10 +38,16 @@ if TOKEN is None:
|
|||||||
|
|
||||||
GUILD = "690934836696973404"
|
GUILD = "690934836696973404"
|
||||||
DIEGO = 430566197868625920 # Mon id
|
DIEGO = 430566197868625920 # Mon id
|
||||||
|
ANANAS = 619132180408303616
|
||||||
|
FAN_CLUBS = {
|
||||||
|
DIEGO: 706586020841259078,
|
||||||
|
ANANAS: 706586027535368223,
|
||||||
|
}
|
||||||
BOT = 703305132300959754
|
BOT = 703305132300959754
|
||||||
TEAMS_CHANNEL_CATEGORY = "Channels d'équipes"
|
TEAMS_CHANNEL_CATEGORY = "Channels d'équipes 2"
|
||||||
EMBED_COLOR = 0xFFA500
|
EMBED_COLOR = 0xFFA500
|
||||||
FRACTAL_URL = "https://thefractal.space/img/{seed}.png?size=1500"
|
FRACTAL_URL = "https://thefractal.space/img/{seed}.png?size=1000"
|
||||||
|
FRACTAL_COOLDOWN = 30 # seconds
|
||||||
|
|
||||||
ROUND_NAMES = ["premier tour", "deuxième tour"]
|
ROUND_NAMES = ["premier tour", "deuxième tour"]
|
||||||
TOURNOIS = [
|
TOURNOIS = [
|
||||||
@ -44,8 +56,7 @@ TOURNOIS = [
|
|||||||
"Paris-Saclay",
|
"Paris-Saclay",
|
||||||
"Paris-Avignon-Est",
|
"Paris-Avignon-Est",
|
||||||
"Tours",
|
"Tours",
|
||||||
"Bordeaux",
|
"Bordeaux-Nancy",
|
||||||
"Nancy",
|
|
||||||
"Rennes",
|
"Rennes",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -55,6 +66,7 @@ class Role:
|
|||||||
DEV = "dev"
|
DEV = "dev"
|
||||||
ORGA = "Orga"
|
ORGA = "Orga"
|
||||||
ORGAS = tuple(f"Orga {t}" for t in TOURNOIS)
|
ORGAS = tuple(f"Orga {t}" for t in TOURNOIS)
|
||||||
|
JURY = tuple(f"Jury {t}" for t in TOURNOIS)
|
||||||
BENEVOLE = "Bénévole"
|
BENEVOLE = "Bénévole"
|
||||||
CAPTAIN = "Capitaine"
|
CAPTAIN = "Capitaine"
|
||||||
PARTICIPANT = "Participant"
|
PARTICIPANT = "Participant"
|
||||||
@ -77,6 +89,7 @@ class File:
|
|||||||
TEAMS = TOP_LEVEL / "data" / "teams"
|
TEAMS = TOP_LEVEL / "data" / "teams"
|
||||||
JOKES = TOP_LEVEL / "data" / "jokes"
|
JOKES = TOP_LEVEL / "data" / "jokes"
|
||||||
JOKES_V2 = TOP_LEVEL / "data" / "jokesv2"
|
JOKES_V2 = TOP_LEVEL / "data" / "jokesv2"
|
||||||
|
MEMES = TOP_LEVEL / "data" / "memes"
|
||||||
|
|
||||||
|
|
||||||
with open(File.TOP_LEVEL / "data" / "problems") as f:
|
with open(File.TOP_LEVEL / "data" / "problems") as f:
|
||||||
|
14
src/core.py
14
src/core.py
@ -2,7 +2,7 @@ import asyncio
|
|||||||
import sys
|
import sys
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
|
|
||||||
from discord import User, Message, Reaction, NotFound
|
from discord import User, Message, Reaction, NotFound, Forbidden
|
||||||
from discord.ext.commands import Bot
|
from discord.ext.commands import Bot
|
||||||
|
|
||||||
__all__ = ["CustomBot"]
|
__all__ = ["CustomBot"]
|
||||||
@ -60,8 +60,12 @@ class CustomBot(Bot):
|
|||||||
reaction, u = await bot.wait_for(
|
reaction, u = await bot.wait_for(
|
||||||
"reaction_add", check=check, timeout=timeout
|
"reaction_add", check=check, timeout=timeout
|
||||||
)
|
)
|
||||||
the_msg = get(msgs, id=reaction.message.id)
|
|
||||||
await the_msg.delete()
|
the_msg: Message = get(msgs, id=reaction.message.id)
|
||||||
|
try:
|
||||||
|
await the_msg.delete()
|
||||||
|
except NotFound:
|
||||||
|
pass # message was deleted
|
||||||
msgs.remove(the_msg)
|
msgs.remove(the_msg)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
pass
|
pass
|
||||||
@ -69,6 +73,6 @@ class CustomBot(Bot):
|
|||||||
for m in msgs:
|
for m in msgs:
|
||||||
try:
|
try:
|
||||||
await m.clear_reaction(Emoji.BIN)
|
await m.clear_reaction(Emoji.BIN)
|
||||||
except NotFound:
|
except (NotFound, Forbidden):
|
||||||
# Message or reaction deleted
|
# Message or reaction deleted / in dm channel
|
||||||
pass
|
pass
|
||||||
|
@ -5,7 +5,8 @@ from src.core import CustomBot
|
|||||||
|
|
||||||
# We allow "! " to catch people that put a space in their commands.
|
# We allow "! " to catch people that put a space in their commands.
|
||||||
# It must be in first otherwise "!" always match first and the space is not recognised
|
# It must be in first otherwise "!" always match first and the space is not recognised
|
||||||
bot = CustomBot(("! ", "!"))
|
from src.utils import fg
|
||||||
|
|
||||||
|
|
||||||
# Global variable to hold the tirages.
|
# Global variable to hold the tirages.
|
||||||
# We *want* it to be global so we can reload the tirages cog without
|
# We *want* it to be global so we can reload the tirages cog without
|
||||||
@ -13,19 +14,23 @@ bot = CustomBot(("! ", "!"))
|
|||||||
tirages = {}
|
tirages = {}
|
||||||
|
|
||||||
|
|
||||||
@bot.event
|
def start():
|
||||||
async def on_ready():
|
bot = CustomBot(("! ", "!"))
|
||||||
print(f"{bot.user} has connected to Discord!")
|
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
print(f"{bot.user} has connected to Discord!")
|
||||||
|
|
||||||
bot.remove_command("help")
|
bot.remove_command("help")
|
||||||
bot.load_extension("src.cogs.dev")
|
bot.load_extension("src.cogs.dev")
|
||||||
bot.load_extension("src.cogs.errors")
|
bot.load_extension("src.cogs.errors")
|
||||||
bot.load_extension("src.cogs.misc")
|
bot.load_extension("src.cogs.misc")
|
||||||
bot.load_extension("src.cogs.teams")
|
bot.load_extension("src.cogs.teams")
|
||||||
bot.load_extension("src.cogs.tirages")
|
bot.load_extension("src.cogs.tirages")
|
||||||
bot.load_extension("src.utils")
|
bot.load_extension("src.utils")
|
||||||
|
|
||||||
|
bot.run(DISCORD_TOKEN)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
bot.run(TOKEN)
|
start()
|
||||||
|
13
src/utils.py
13
src/utils.py
@ -4,6 +4,19 @@ import psutil
|
|||||||
from discord.ext.commands import Bot
|
from discord.ext.commands import Bot
|
||||||
|
|
||||||
|
|
||||||
|
def fg(text, color: int = 0xFFA500):
|
||||||
|
r = color >> 16
|
||||||
|
g = color >> 8 & 0xFF
|
||||||
|
b = color & 0xFF
|
||||||
|
return f"\033[38;2;{r};{g};{b}m{text}\033[m"
|
||||||
|
|
||||||
|
|
||||||
|
def french_join(l):
|
||||||
|
l = list(l)
|
||||||
|
start = ", ".join(l[:-1])
|
||||||
|
return f"{start} et {l[-1]}"
|
||||||
|
|
||||||
|
|
||||||
def has_role(member, role: str):
|
def has_role(member, role: str):
|
||||||
"""Return whether the member has a role with this name."""
|
"""Return whether the member has a role with this name."""
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user