orochi-discord/orochi/bot.py

313 lines
12 KiB
Python
Raw Normal View History

2021-10-26 19:05:45 +00:00
import disnake
2021-10-26 21:08:55 +00:00
from disnake import CategoryChannel, PermissionOverwrite, TextChannel
2021-10-26 19:05:45 +00:00
from disnake.ext import commands
import logging
from orochi import http
2021-10-26 19:05:45 +00:00
from orochi.config import Config
2021-11-08 20:18:48 +00:00
from orochi.models import Game, GameState, Player, RoundVote, Vote
2021-10-26 19:05:45 +00:00
bot = commands.Bot(command_prefix='!')
@bot.event
2021-10-26 21:08:55 +00:00
async def on_ready():
config: Config = bot.config
logger = bot.logger
if config.guild is None:
config.save()
logger.error("The guild ID is missing")
exit(1)
guild = await bot.fetch_guild(config.guild)
if not guild:
logger.error("Unknown guild.")
exit(1)
if config.vote_category is None:
category = await guild.create_category("Votes")
config.vote_category = category.id
config.save()
if config.secret_category is None:
category = await guild.create_category("Conversation⋅s secrète⋅s")
config.secret_category = category.id
config.save()
vote_category: CategoryChannel = await guild.fetch_channel(config.vote_category)
if vote_category is None:
config.vote_category = None
return await on_ready()
secret_category: CategoryChannel = await guild.fetch_channel(config.secret_category)
if secret_category is None:
config.secret_category = None
return await on_ready()
await vote_category.set_permissions(
guild.default_role, overwrite=PermissionOverwrite(read_message_history=False, read_messages=False)
)
await secret_category.set_permissions(
guild.default_role, overwrite=PermissionOverwrite(read_message_history=False, read_messages=False)
)
for i, player in enumerate(Config.PLAYERS):
player_id = player.lower()
if player_id not in config.vote_channels:
channel: TextChannel = await vote_category.create_text_channel(player_id)
config.vote_channels[player_id] = channel.id
config.save()
channel: TextChannel = await guild.fetch_channel(config.vote_channels[player_id])
if channel is None:
del config.vote_channels[player_id]
return await on_ready()
await channel.edit(name=player_id, category=vote_category, position=i)
await channel.set_permissions(
guild.default_role, overwrite=PermissionOverwrite(read_message_history=False, read_messages=False)
)
if player_id not in config.player_roles:
role = await guild.create_role(name=player)
config.player_roles[player_id] = role.id
config.save()
guild = await bot.fetch_guild(guild.id) # update roles
role = guild.get_role(config.player_roles[player_id])
if role is None:
del config.player_roles[player_id]
config.save()
return await on_ready()
await channel.set_permissions(
role, overwrite=PermissionOverwrite(read_message_history=True, read_messages=True)
)
2021-11-08 14:44:03 +00:00
game = Game.load('game.save')
if not game:
game = Game()
2021-11-05 10:12:02 +00:00
for player in config.PLAYERS:
2021-11-08 14:44:03 +00:00
game.register_player(player, config.vote_channels[player.lower()])
game.save('game.save')
2021-11-05 10:12:02 +00:00
# Update private channel id if necessary
2021-11-08 14:44:03 +00:00
for player in list(game.players.values()):
2021-11-05 10:12:02 +00:00
if player.private_channel_id != config.vote_channels[player.name.lower()]:
2021-11-08 14:44:03 +00:00
game.register_player(player.name, config.vote_channels[player.name.lower()])
game.save('game.save')
2021-11-05 10:12:02 +00:00
2021-11-08 14:13:51 +00:00
# Setup first round if not exists
2021-11-08 14:44:03 +00:00
if not game.rounds:
game.rounds.append(game.default_first_round())
game.save('game.save')
2021-11-08 14:13:51 +00:00
2021-10-26 21:08:55 +00:00
if not config.telepathy_channel:
channel: TextChannel = await secret_category.create_text_channel("bigbrain")
config.telepathy_channel = channel.id
config.save()
telepathy_channel: TextChannel = await guild.fetch_channel(config.telepathy_channel)
if not telepathy_channel:
config.telepathy_channel = None
return await on_ready()
await telepathy_channel.edit(name="bigbrain", category=secret_category, position=0,
topic="Échanges télépathiques")
await telepathy_channel.set_permissions(
guild.default_role, overwrite=PermissionOverwrite(read_message_history=False, read_messages=False)
)
delphine = guild.get_role(config.player_roles['delphine'])
philia = guild.get_role(config.player_roles['philia'])
await telepathy_channel.set_permissions(
delphine, overwrite=PermissionOverwrite(read_message_history=True, read_messages=True)
)
await telepathy_channel.set_permissions(
philia, overwrite=PermissionOverwrite(read_message_history=True, read_messages=True)
)
2021-11-08 13:01:43 +00:00
if not config.brother_channel:
channel: TextChannel = await secret_category.create_text_channel("doliprane")
config.brother_channel = channel.id
2021-10-26 21:08:55 +00:00
config.save()
2021-11-08 13:01:43 +00:00
brother_channel: TextChannel = await guild.fetch_channel(config.brother_channel)
if not brother_channel:
config.brother_channel = None
2021-10-26 21:08:55 +00:00
return await on_ready()
2021-11-08 13:01:43 +00:00
await brother_channel.edit(name="doliprane", category=secret_category, position=1,
topic="Des voix dans la tête ...")
await brother_channel.set_permissions(
2021-10-26 21:08:55 +00:00
guild.default_role, overwrite=PermissionOverwrite(read_message_history=False, read_messages=False)
)
2021-11-08 13:01:43 +00:00
await brother_channel.set_permissions(
2021-10-26 21:08:55 +00:00
philia, overwrite=PermissionOverwrite(read_message_history=True, read_messages=True)
)
2021-11-08 13:01:43 +00:00
brother_channel_webhook = None
if config.brother_channel_webhook is not None:
try:
brother_channel_webhook = await bot.fetch_webhook(config.brother_channel_webhook)
except disnake.HTTPException | disnake.NotFound | disnake.Forbidden:
pass
if brother_channel_webhook is None:
brother_channel_webhook = await brother_channel.create_webhook(name="???")
config.brother_channel_webhook = brother_channel_webhook.id
config.save()
2021-10-26 21:08:55 +00:00
if not config.backdoor_channel:
channel: TextChannel = await secret_category.create_text_channel("backdoor")
config.backdoor_channel = channel.id
config.save()
backdoor_channel: TextChannel = await guild.fetch_channel(config.backdoor_channel)
if not backdoor_channel:
config.backdoor_channel = None
return await on_ready()
await backdoor_channel.edit(name="backdoor", category=secret_category, position=2,
topic="Panel d'administrati0n du jeu")
await backdoor_channel.set_permissions(
guild.default_role, overwrite=PermissionOverwrite(read_message_history=False, read_messages=False)
)
dan = guild.get_role(config.player_roles['dan'])
await backdoor_channel.set_permissions(
dan, overwrite=PermissionOverwrite(read_message_history=True, read_messages=True)
)
config.save()
2021-10-26 19:05:45 +00:00
2021-11-08 20:18:48 +00:00
@bot.command(help="Sauvegarde la partie")
@commands.has_permissions(administrator=True)
async def save(ctx: commands.Context):
Game.INSTANCE.save('game.save')
await ctx.reply("La partie a été sauvegardée.")
@bot.command(help="Recharger la partie")
@commands.has_permissions(administrator=True)
async def load(ctx: commands.Context):
Game.load('game.save')
await ctx.reply("La partie a été rechargée.")
2021-11-08 13:01:43 +00:00
@bot.command(help="Envoyer un message en tant qu'Orochi.")
2021-10-26 21:18:53 +00:00
@commands.has_permissions(administrator=True)
async def send(ctx: commands.Context, *, message: str):
await ctx.message.delete()
await ctx.send(message)
2021-11-08 13:01:43 +00:00
@bot.command(help="Envoyer un message à Philia par la pensée en tant que Brother.")
@commands.has_permissions(administrator=True)
async def brother(ctx: commands.Context, *, message: str):
webhook = await bot.fetch_webhook(bot.config.brother_channel_webhook)
await webhook.send(message)
await ctx.message.reply("Message envoyé.")
2021-11-08 20:18:48 +00:00
@bot.command(help="Ouvrir les votes")
async def open(ctx: commands.Context):
game: Game = Game.INSTANCE
current_round = game.rounds[-1]
if game.state == GameState.VOTING:
await ctx.reply("Les votes sont déjà ouverts.")
return
elif game.state == GameState.RESULTS:
await ctx.reply("Les votes viennent d'être fermés, merci de démarrer un nouveau tour avec !prepare.")
return
# Ensure that each room is configured
for room in current_round.rooms:
if room is None:
await ctx.reply("Les salles ne sont pas configurées.")
if len(list(room.players)) != 3:
await ctx.reply(f"La salle {room.room.value} ne contient pas trois joueurs, merci de la reconfigurer.")
# Send messages to players
for room in current_round.rooms:
votes = list(room.votes)
for i, vote in enumerate(votes):
players = list(vote.players)
other_vote = votes[1 - i]
for j, player in enumerate(players):
other_player = players[1 - j] if len(players) == 2 else None
view = VoteView(timeout=3600)
channel_id = player.private_channel_id
channel = bot.get_channel(channel_id)
message = "Les votes sont ouverts.\n"
message += f"Vous devez aller voter en salle **{room.room.value}**.\n"
if other_player:
message += f"Vous êtes allié⋅e avec **{other_player.name}**.\n"
message += f"Vous affrontez {' et '.join(f'**{adv.name}**' for adv in other_vote.players)}.\n"
message += "Bonne chance !"
await channel.send(message)
await channel.send("Pour voter, utilisez l'un des boutons ci-dessous. Vous pouvez appuyer "
"sur le bouton plusieurs fois, mais seul le premier vote sera enregistré.",
view=view)
game.state = GameState.VOTING
await ctx.reply("Les salles de vote sont ouvertes, les joueur⋅se⋅s peuvent désormais voter.")
class VoteView(disnake.ui.View):
2021-10-26 19:05:45 +00:00
@disnake.ui.button(label="S'allier", style=disnake.ButtonStyle.green)
async def confirm(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
2021-11-08 20:18:48 +00:00
await interaction.response.send_message("Votre vote a bien été pris en compte.", ephemeral=True)
self.vote(interaction, Vote.ALLY)
2021-10-26 19:05:45 +00:00
@disnake.ui.button(label="Trahir", style=disnake.ButtonStyle.red)
async def cancel(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
2021-11-08 20:18:48 +00:00
await interaction.response.send_message("Votre vote a bien été pris en compte.", ephemeral=True)
self.vote(interaction, Vote.BETRAY)
def vote(self, interaction: disnake.MessageInteraction, vote: Vote) -> None:
game = Game.INSTANCE
current_round = game.rounds[-1]
current_player: Player | None = None
for player in game.players.values():
if player.private_channel_id == interaction.channel_id:
current_player = player
break
current_vote: RoundVote | None = None
for room in current_round.rooms:
for v in room.votes:
if current_player in v.players:
current_vote = v
break
else:
continue
break
if current_vote.vote is None:
current_vote.vote = vote
game.save('game.save')
2021-10-26 19:05:45 +00:00
def run():
2021-10-26 21:08:55 +00:00
config = Config.load()
2021-10-26 19:05:45 +00:00
http.run_web_server()
2021-10-26 19:05:45 +00:00
logger = logging.getLogger('discord')
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(filename='../discord.log', encoding='utf-8', mode='w')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
logger.addHandler(handler)
bot.config = config
bot.logger = logger
bot.run(config.discord_token)