Code source de lgrez.features.informations

"""lg-rez / features / Commandes informatives

Commandes donnant aux joueurs des informations sur le jeu, leurs
actions, les joueurs en vie et morts...

"""

from discord.ext import commands

from lgrez import config
from lgrez.blocs import tools
from lgrez.bdd import (Joueur, Role, Camp, Action, BaseAction,
                       ActionTrigger, Vote)
from lgrez.features import gestion_actions


def _roles_list(roles):
    return "\n".join(
        str(role.camp.discord_emoji_or_none or "")
        + tools.code(f"{role.nom.ljust(25)} {role.description_courte}")
        for role in roles if not role.nom.startswith("(")
    )


[docs]class Informations(commands.Cog): """Commandes pour en savoir plus sur soi et les autres""" @commands.command(aliases=["role", "rôles", "rôle"]) async def roles(self, ctx, *, role=None): """Affiche la liste des rôles / des informations sur un rôle Args: role: le nom d'un rôle, pour les informations sur ce rôle. Sans argument, liste tous les rôles existants. Voir aussi la commande `!camps`. """ if role: role = tools.remove_accents(role.lower()) role = role.strip("<>[](){}") if not role: roles = Role.query.filter_by(actif=True).order_by(Role.nom).all() else: roles = Role.find_nearest(role, col=Role.nom) if not roles: await ctx.send(f"Rôle \"{role}\" non trouvé.") return await ctx.send(embed=roles[0][0].embed) return await tools.send_blocs( ctx, f"Rôles trouvés :\n{_roles_list(roles)}" + "\n" + tools.ital(f"({tools.code('!role <role>')} " "pour plus d'informations sur un rôle.)") ) @commands.command(aliases=["camp"]) async def camps(self, ctx, *, camp=None): """Affiche la liste des camps / les rôles d'un camp Args: camp: le nom d'un camp, pour les informations sur ce camp. Sans argument, liste tous les camps existants. Voir aussi la commande `!role`. """ if camp: camp = tools.remove_accents(camp.lower()) camp = camp.strip("<>[](){}") if not camp: camps = Camp.query.filter_by(public=True).order_by(Camp.nom).all() else: camps = Camp.find_nearest(camp, col=Camp.nom) if not camps: await ctx.send(f"Camp \"{camp}\" non trouvé.") return await ctx.send(embed=camps[0][0].embed) await tools.send_blocs( ctx, f"Rôles dans ce camp :\n{_roles_list(camps[0][0].roles)}" + "\n" + tools.ital(f"({tools.code('!role <role>')} " "pour plus d'informations sur un rôle.)") ) return await tools.send_blocs( ctx, "Camps trouvés :\n" + "\n".join(str(camp.discord_emoji_or_none or "") + " " + camp.nom for camp in camps if not camp.nom.startswith("(")) + "\n" + tools.ital(f"({tools.code('!camp <camp>')} " "pour plus d'informations sur un camp.)") ) @commands.command() @tools.mjs_only async def rolede(self, ctx, *, cible=None): """Donne le rôle d'un joueur (COMMANDE MJ) Args: cible: le joueur dont on veut connaître le rôle """ joueur = await tools.boucle_query_joueur(ctx, cible, "Qui ?") if joueur: await ctx.send(joueur.role.nom_complet) @commands.command() @tools.mjs_only async def quiest(self, ctx, *, nomrole): """Liste les joueurs ayant un rôle donné (COMMANDE MJ) Args: nomrole: le rôle qu'on cherche (doit être un slug ou un nom de rôle valide) """ roles = Role.find_nearest(nomrole) if roles: role = roles[0][0] else: roles = Role.find_nearest(nomrole, col=Role.nom) if roles: role = roles[0][0] else: await ctx.send("Connais pas") return joueurs = Joueur.query.filter_by(role=role).\ filter(Joueur.est_vivant).all() await ctx.send( f"{role.nom_complet} : " + (", ".join(joueur.nom for joueur in joueurs) if joueurs else "Personne.") ) @commands.command() @tools.vivants_only @tools.private async def menu(self, ctx): """Affiche des informations et boutons sur les votes / actions en cours Le menu a une place beaucoup moins importante ici que sur Messenger, vu que tout est accessible par commandes. """ member = ctx.author joueur = Joueur.from_member(member) reacts = [] r = "––– MENU –––\n\n" try: vaction = joueur.action_vote(Vote.cond) except RuntimeError: await ctx.send("Minute papillon, le jeu n'est pas encore lancé !") return if vaction.is_open: r += (f" - {config.Emoji.bucher} Vote pour le bûcher en cours – " f"vote actuel : {tools.code(vaction.decision)}\n") reacts.append(config.Emoji.bucher) vaction = joueur.action_vote(Vote.maire) if vaction.is_open: r += (f" - {config.Emoji.maire} Vote pour le maire en cours – " f"vote actuel : {tools.code(vaction.decision)}\n") reacts.append(config.Emoji.maire) vaction = joueur.action_vote(Vote.loups) if vaction.is_open: r += (f" - {config.Emoji.lune} Vote des loups en cours – " f"vote actuel : {tools.code(vaction.decision)}\n") reacts.append(config.Emoji.lune) if not reacts: r += "Aucun vote en cours.\n" actions = [ac for ac in joueur.actions_actives if ac.is_open] if actions: for action in actions: r += (f" - {config.Emoji.action} Action en cours : " f"{tools.code(action.base.slug)} (id {action.id}) – " f"décision : {tools.code(action.decision)}\n") reacts.append(config.Emoji.action) else: r += "Aucune action en cours.\n" message = await ctx.send( r + f"\n{tools.code('!infos')} pour voir ton rôle et tes " f"actions, {tools.code('@MJ')} en cas de problème" ) for react in reacts: await message.add_reaction(react) @commands.command() @tools.vivants_only @tools.private async def infos(self, ctx): """Affiche tes informations de rôle / actions Toutes les actions liées à ton rôle (et parfois d'autres) sont indiquées, même celles que tu ne peux pas utiliser pour l'instant (plus de charges, déclenchées automatiquement...) """ member = ctx.author joueur = Joueur.from_member(member) r = "" r += f"Ton rôle actuel : {tools.bold(joueur.role.nom_complet)}\n" r += tools.ital(f"({tools.code(f'!roles {joueur.role.slug}')} " "pour tout savoir sur ce rôle)") if joueur.actions_actives: r += "\n\nActions :" r += tools.code_bloc("\n".join(( f" - {action.base.slug.ljust(20)} " + (f"Cooldown : {action.cooldown}" if action.cooldown else action.base.temporalite).ljust(22) + (f" {action.charges} charge(s)" + (" pour cette semaine" if "weekends" in action.base.refill else "") if isinstance(action.charges, int) else "Illimitée") ) for action in joueur.actions_actives)) # Vraiment désolé pour cette immondice j'ai la flemme else: r += "\n\nAucune action disponible." await ctx.send( f"{r}\n{tools.code('!menu')} pour voir les votes et " f"actions en cours, {tools.code('@MJ')} en cas de problème" ) @commands.command() @tools.mjs_only async def actions(self, ctx, *, cible=None): """Affiche et modifie les actions d'un joueur (COMMANDE MJ) Args: cible: le joueur dont on veut voir ou modifier les actions Warning: Commande expérimentale, non testée. """ joueur = await tools.boucle_query_joueur(ctx, cible, "Qui ?") actions = [ac for ac in joueur.actions if not ac.vote] r = f"Rôle : {joueur.role.nom_complet or joueur.role}\n" # if not actions: # r += "Aucune action pour ce joueur." # await ctx.send(r) # return r += "Actions :" r += tools.code_bloc( "#️⃣ id active baseaction début" " fin cd charges refill \n" "---------------------------------------------" "---------------------------------------------\n" + "\n".join([( tools.emoji_chiffre(i + 1) + " " + str(action.id).ljust(5) + str(action.active).ljust(8) + action.base.slug.ljust(25) + str(action.base.heure_debut if action.base.trigger_debut == ActionTrigger.temporel else action.base.trigger_debut.name).ljust(10) + str(action.base.heure_fin if action.base.trigger_fin == ActionTrigger.temporel else action.base.trigger_fin.name).ljust(10) + str(action.cooldown).ljust(5) + str(action.charges).ljust(10) + str(action.base.refill) ) for i, action in enumerate(actions)]) ) r += "Modifier/ajouter/stop :" message = await ctx.send(r) i = await tools.choice(message, len(actions), additionnal={"🆕": -1, "⏹": 0}) if i < 0: # ajouter await ctx.send("Slug de la baseaction à ajouter ? " "(voir Gsheet Rôles et actions)") base = await tools.boucle_query(ctx, BaseAction) await ctx.send("Cooldown ? (nombre entier)") mess = await tools.wait_for_message_here(ctx) cooldown = int(mess.content) await ctx.send(f"Charges ? ({tools.code('None')} pour illimité)") mess = await tools.wait_for_message_here(ctx) charges = int(mess.content) if mess.content.isdigit() else None gestion_actions.add_action( joueur=joueur, base=base, cooldown=cooldown, charges=charges, ) await ctx.send(f"Action ajoutée (id {action.id}).") return elif i == 0: await ctx.send("Au revoir.") return # Modifier action = actions[i - 1] stop = False while not stop: await ctx.send( "Modifier : (parmi `active, cd, charges`}) ; `valider` pour " "finir ; `supprimer` pour supprimer l'action.\n(Pour modifier " "les attributs de la baseaction, modifier le Gsheet et " "utiliser `!fillroles` ; pour ouvrir/fermer l'action, " f"utiliser `!open {action.id}` / `!close {action.id}`.)" ) mess = await tools.wait_for_message_here(ctx) modif = mess.content.lower() if modif == "active": mess = await ctx.send("Action active ?") action.active = await tools.yes_no(mess) elif modif in ["cd", "cooldown"]: await ctx.send("Combien ?") mess = await tools.wait_for_message_here(ctx) action.cooldown = int(mess.content) elif modif == "charges": await ctx.send("Combien ? (`None` pour illimité)") mess = await tools.wait_for_message_here(ctx) action.charges = (int(mess.content) if mess.content.isdigit() else None) elif modif == "valider": action.update() await ctx.send("Fait.") stop = True elif modif == "supprimer": mess = await ctx.send("Supprimer l'action ? (privilégier " "l'archivage `active = False`)") if await tools.yes_no(mess): action.delete() await ctx.send("Fait.") stop = True else: await ctx.send("Valeur incorrecte") @commands.command(aliases=["joueurs", "vivant"]) async def vivants(self, ctx): """Affiche la liste des joueurs vivants Aussi dite : « liste des joueurs qui seront bientôt morts » """ joueurs = Joueur.query.filter(Joueur.est_vivant).\ order_by(Joueur.nom).all() mess = " Joueur en chambre\n" mess += "––––––––––––––––––––––––––––––––––––––––––––––\n" if config.demande_chambre: for joueur in joueurs: mess += f" {joueur.nom.ljust(25)} {joueur.chambre}\n" else: for joueur in joueurs: mess += f" {joueur.nom}\n" await tools.send_code_blocs( ctx, mess, prefixe=f"Les {len(joueurs)} joueurs vivants sont :" ) @commands.command(aliases=["mort"]) async def morts(self, ctx): """Affiche la liste des joueurs morts Aussi dite : « liste des joueurs qui mangent leurs morts » """ joueurs = Joueur.query.filter(Joueur.est_mort).\ order_by(Joueur.nom).all() if joueurs: mess = "" for joueur in joueurs: mess += f" {joueur.nom}\n" else: mess = "Toi (mais tu ne le sais pas encore)" await tools.send_code_blocs( ctx, mess, prefixe=f"Les {len(joueurs) or ''} morts sont :" )