syncro modif prod

This commit is contained in:
ArcElewyn 2025-08-26 15:02:34 +02:00
parent d1540c816d
commit 4533180ef0
8 changed files with 89 additions and 82 deletions

View file

@ -12,7 +12,7 @@ COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# Copy source code # Copy source code
COPY bot.py . COPY . .
# Create required folders # Create required folders
RUN mkdir -p screenshots/hydra/normal screenshots/hydra/hard screenshots/hydra/brutal screenshots/hydra/nightmare \ RUN mkdir -p screenshots/hydra/normal screenshots/hydra/hard screenshots/hydra/brutal screenshots/hydra/nightmare \

21
bot.py
View file

@ -1,9 +1,8 @@
import os import os
import asyncio
import discord import discord
from discord.ext import commands from discord.ext import commands
from config import DISCORD_TOKEN from config import DISCORD_TOKEN
# Import des managers
from utils.DatabaseManager_class import DatabaseManager from utils.DatabaseManager_class import DatabaseManager
from utils.ScreenshotManager_class import ScreenshotManager from utils.ScreenshotManager_class import ScreenshotManager
@ -11,11 +10,9 @@ intents = discord.Intents.default()
intents.message_content = True intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents) bot = commands.Bot(command_prefix="!", intents=intents)
# Initialisation unique des managers
db_manager = DatabaseManager() db_manager = DatabaseManager()
screenshot_manager = ScreenshotManager() screenshot_manager = ScreenshotManager()
# Liste des Cogs à charger
initial_cogs = [ initial_cogs = [
"cogs.guide", "cogs.guide",
"cogs.pbhydra", "cogs.pbhydra",
@ -26,12 +23,22 @@ initial_cogs = [
"cogs.mercy", "cogs.mercy",
] ]
for cog in initial_cogs: async def load_all_cogs():
bot.load_extension(cog) for cog in initial_cogs:
try:
await bot.load_extension(cog)
print(f"[OK] Cog {cog} chargé")
except Exception as e:
print(f"[ERREUR] Impossible de charger {cog}: {e}")
@bot.event @bot.event
async def on_ready(): async def on_ready():
print(f"{bot.user.name} est connecté !") print(f"{bot.user.name} est connecté !")
bot.run(DISCORD_TOKEN) async def main():
await load_all_cogs()
await bot.start(DISCORD_TOKEN)
if __name__ == "__main__":
asyncio.run(main())

View file

@ -8,19 +8,19 @@ class Guide(commands.Cog):
@commands.command(name="guide") @commands.command(name="guide")
async def guide(self, ctx): async def guide(self, ctx):
"""Affiche la liste des commandes disponibles avec les nouvelles difficultés""" """Affiche la liste des commandes disponibles avec les nouvelles difficultés"""
if ctx.channel.id != AUTHORIZED_CHANNEL_ID: if ctx.channel.id != AUTHORIZED_CHANNEL_ID:
return return
embed = discord.Embed( embed = discord.Embed(
title="🤖 RTF Bot - Commands Guide", title="🤖 RTF Bot - Commands Guide",
description="Here are all available commands for tracking your Personal Bests!", description="Here are all available commands for tracking your Personal Bests!",
color=0x00bfff color=0x00bfff
) )
# Info sur les formats de dégâts # Info sur les formats de dégâts
embed.add_field( embed.add_field(
name="💰 Damage Formats", name="💰 Damage Formats",
value="**Accepted formats:** `1500000`, `1.5M`, `500K`, `2B`\n" + value="**Accepted formats:** `1500000`, `1.5M`, `500K`, `2B`\n" +
"**Suffixes:** K = thousands, M = millions, B = billions\n" + "**Suffixes:** K = thousands, M = millions, B = billions\n" +
"**Shortcuts:** `nm` = Nightmare, `unm` = Ultra Nightmare", "**Shortcuts:** `nm` = Nightmare, `unm` = Ultra Nightmare",
@ -29,7 +29,7 @@ class Guide(commands.Cog):
# Commandes PB Hydra # Commandes PB Hydra
embed.add_field( embed.add_field(
name="🐍 Hydra Commands", name="🐍 Hydra Commands",
value="**Difficulties:** Normal | Hard | Brutal | Nightmare (nm)\n" + value="**Difficulties:** Normal | Hard | Brutal | Nightmare (nm)\n" +
"`!pbhydra <difficulty> <damage>` - Submit PB + screenshot\n" + "`!pbhydra <difficulty> <damage>` - Submit PB + screenshot\n" +
"`!pbhydra <difficulty>` - Show your PB\n" + "`!pbhydra <difficulty>` - Show your PB\n" +
@ -39,7 +39,7 @@ class Guide(commands.Cog):
# Commandes PB Chimera # Commandes PB Chimera
embed.add_field( embed.add_field(
name="🦁 Chimera Commands", name="🦁 Chimera Commands",
value="**Difficulties:** Easy | Normal | Hard | Brutal | Nightmare (nm) | Ultra (unm)\n" + value="**Difficulties:** Easy | Normal | Hard | Brutal | Nightmare (nm) | Ultra (unm)\n" +
"`!pbchimera <difficulty> <damage>` - Submit PB + screenshot\n" + "`!pbchimera <difficulty> <damage>` - Submit PB + screenshot\n" +
"`!pbchimera <difficulty>` - Show your PB\n" + "`!pbchimera <difficulty>` - Show your PB\n" +
@ -49,7 +49,7 @@ class Guide(commands.Cog):
# Commandes PB CvC # Commandes PB CvC
embed.add_field( embed.add_field(
name="⚔️ CvC Commands", name="⚔️ CvC Commands",
value="`!pbcvc <damage>` - Submit PB + screenshot\n" + value="`!pbcvc <damage>` - Submit PB + screenshot\n" +
"`!pbcvc` - Show your PB\n" + "`!pbcvc` - Show your PB\n" +
"`!pbcvc <username>` - Show user's PB", "`!pbcvc <username>` - Show user's PB",
@ -58,7 +58,7 @@ class Guide(commands.Cog):
# Commandes Mercy # Commandes Mercy
embed.add_field( embed.add_field(
name="🎲 Mercy Commands", name="🎲 Mercy Commands",
value="`!mercy show` - Show your current mercy pulls\n" + value="`!mercy show` - Show your current mercy pulls\n" +
"`!mercy add <nb> <type>` - Add pulls to a shard type\n" + "`!mercy add <nb> <type>` - Add pulls to a shard type\n" +
"`!mercy reset <type>` - Reset pulls for a shard type\n" + "`!mercy reset <type>` - Reset pulls for a shard type\n" +
@ -68,7 +68,7 @@ class Guide(commands.Cog):
# Classements globaux # Classements globaux
embed.add_field( embed.add_field(
name="🌍 Global Leaderboards", name="🌍 Global Leaderboards",
value="`!top10hydra <difficulty>` - Global Hydra rankings\n" + value="`!top10hydra <difficulty>` - Global Hydra rankings\n" +
"`!top10chimera <difficulty>` - Global Chimera rankings\n" + "`!top10chimera <difficulty>` - Global Chimera rankings\n" +
"`!top10cvc` - Global CvC rankings", "`!top10cvc` - Global CvC rankings",
@ -77,7 +77,7 @@ class Guide(commands.Cog):
# Classements par clan # Classements par clan
embed.add_field( embed.add_field(
name="🏛️ Clan Leaderboards", name="🏛️ Clan Leaderboards",
value="**RTF:** `!rtfhydra <diff>` `!rtfchimera <diff>` `!rtfcvc`\n" + value="**RTF:** `!rtfhydra <diff>` `!rtfchimera <diff>` `!rtfcvc`\n" +
"**RTFC:** `!rtfchydra <diff>` `!rtfcchimera <diff>` `!rtfccvc`\n" + "**RTFC:** `!rtfchydra <diff>` `!rtfcchimera <diff>` `!rtfccvc`\n" +
"**RTFR:** `!rtfrhydra <diff>` `!rtfrchimera <diff>` `!rtfrcvc`", "**RTFR:** `!rtfrhydra <diff>` `!rtfrchimera <diff>` `!rtfrcvc`",
@ -86,7 +86,7 @@ class Guide(commands.Cog):
# Stats et aide # Stats et aide
embed.add_field( embed.add_field(
name="📈 Stats & Info", name="📈 Stats & Info",
value="`!mystats` - View all your PBs\n" + value="`!mystats` - View all your PBs\n" +
"`!mystats <username>` - View someone's PBs\n" + "`!mystats <username>` - View someone's PBs\n" +
"`!guide` - Show this help message", "`!guide` - Show this help message",
@ -95,7 +95,7 @@ class Guide(commands.Cog):
# Instructions # Instructions
embed.add_field( embed.add_field(
name="💡 Examples", name="💡 Examples",
value="`!pbhydra brutal 1.5M` - Submit Brutal Hydra PB\n" + value="`!pbhydra brutal 1.5M` - Submit Brutal Hydra PB\n" +
"`!pbchimera unm 500K` - Submit Ultra Nightmare PB\n" + "`!pbchimera unm 500K` - Submit Ultra Nightmare PB\n" +
"`!pbcvc 2.3M` - Submit CvC PB\n" + "`!pbcvc 2.3M` - Submit CvC PB\n" +
@ -106,7 +106,7 @@ class Guide(commands.Cog):
inline=False inline=False
) )
embed.set_footer(text="🎮 Old screenshots are automatically deleted when you set new PBs!") embed.set_footer(text="🎮 Old screenshots are automatically deleted when you set new PBs!")
await ctx.send(embed=embed) await ctx.send(embed=embed)

View file

@ -21,10 +21,10 @@ class Mercy(commands.Cog):
if action == "show": if action == "show":
pulls_dict = self.mercy_manager.get_all_pulls(user_id) pulls_dict = self.mercy_manager.get_all_pulls(user_id)
if not pulls_dict: if not pulls_dict:
await ctx.send(" You don't have any mercy data yet.") await ctx.send("❌ You don't have any mercy data yet.")
return return
embed = discord.Embed(title=f"🎲 Mercy Status for {ctx.author.display_name}", color=0x00bfff) embed = discord.Embed(title=f"🎲 Mercy Status for {ctx.author.display_name}", color=0x00bfff)
for shard_type, pulls in pulls_dict.items(): for shard_type, pulls in pulls_dict.items():
if shard_type == "primal": if shard_type == "primal":
@ -33,7 +33,7 @@ class Mercy(commands.Cog):
guaranteed_text = f" (Guaranteed at {int(guaranteed_at)} pulls)" if guaranteed_at else "" guaranteed_text = f" (Guaranteed at {int(guaranteed_at)} pulls)" if guaranteed_at else ""
embed.add_field( embed.add_field(
name=sub_type.replace("_", " ").title(), name=sub_type.replace("_", " ").title(),
value=f"Pulled: **{pulls} shards** {chance:.1f}% chance{guaranteed_text}", value=f"Pulled: **{pulls} shards** → {chance:.1f}% chance{guaranteed_text}",
inline=False inline=False
) )
else: else:
@ -41,7 +41,7 @@ class Mercy(commands.Cog):
guaranteed_text = f" (Guaranteed at {int(guaranteed_at)} pulls)" if guaranteed_at else "" guaranteed_text = f" (Guaranteed at {int(guaranteed_at)} pulls)" if guaranteed_at else ""
embed.add_field( embed.add_field(
name=shard_type.replace("_", " ").title(), name=shard_type.replace("_", " ").title(),
value=f"Pulled: **{pulls} shards** {chance:.1f}% chance{guaranteed_text}", value=f"Pulled: **{pulls} shards** → {chance:.1f}% chance{guaranteed_text}",
inline=False inline=False
) )
@ -51,28 +51,28 @@ class Mercy(commands.Cog):
try: try:
pulls_to_add = int(arg1) pulls_to_add = int(arg1)
except ValueError: except ValueError:
await ctx.send(" Number of pulls must be an integer.") await ctx.send("❌ Number of pulls must be an integer.")
return return
shard_type = arg2.lower() shard_type = arg2.lower()
if shard_type not in VALID_SHARDS: if shard_type not in VALID_SHARDS:
await ctx.send(f" Invalid shard type. Available: {', '.join(VALID_SHARDS)}") await ctx.send(f"❌ Invalid shard type. Available: {', '.join(VALID_SHARDS)}")
return return
new_pulls = self.mercy_manager.add_pulls(user_id, shard_type, pulls_to_add) new_pulls = self.mercy_manager.add_pulls(user_id, shard_type, pulls_to_add)
await ctx.send(f" Added {pulls_to_add} pulls to **{shard_type}** mercy. Total: {new_pulls}") await ctx.send(f"✅ Added {pulls_to_add} pulls to **{shard_type}** mercy. Total: {new_pulls}")
elif action == "reset" and arg1: elif action == "reset" and arg1:
shard_type = arg1.lower() shard_type = arg1.lower()
if shard_type not in VALID_SHARDS: if shard_type not in VALID_SHARDS:
await ctx.send(f" Invalid shard type. Available: {', '.join(VALID_SHARDS)}") await ctx.send(f"❌ Invalid shard type. Available: {', '.join(VALID_SHARDS)}")
return return
self.mercy_manager.reset_pulls(user_id, shard_type) self.mercy_manager.reset_pulls(user_id, shard_type)
await ctx.send(f"🔄 Mercy for **{shard_type}** has been reset.") await ctx.send(f"🔄 Mercy for **{shard_type}** has been reset.")
else: else:
await ctx.send(" Usage: `!mercy add <nb> <type>`, `!mercy reset <type>`, `!mercy show`") await ctx.send("❌ Usage: `!mercy add <nb> <type>`, `!mercy reset <type>`, `!mercy show`")
async def setup(bot): async def setup(bot):
await bot.add_cog(Mercy(bot)) await bot.add_cog(Mercy(bot))

View file

@ -2,7 +2,7 @@ import discord
from discord.ext import commands from discord.ext import commands
from config import AUTHORIZED_CHANNEL_ID, BOSS_CONFIG from config import AUTHORIZED_CHANNEL_ID, BOSS_CONFIG
from utils.helpers import format_damage_display, format_date_only from utils.helpers import format_damage_display, format_date_only
from utils.pb_handler import db_manager # ou set_db_manager si nécessaire from utils.pb_handler import db_manager # ou set_db_manager si nécessaire
class MyStats(commands.Cog): class MyStats(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
@ -10,7 +10,7 @@ class MyStats(commands.Cog):
@commands.command(name="mystats") @commands.command(name="mystats")
async def mystats(self, ctx, target_user: str = None): async def mystats(self, ctx, target_user: str = None):
"""Affiche tous les PB d'un utilisateur avec les nouvelles difficultés""" """Affiche tous les PB d'un utilisateur avec les nouvelles difficultés"""
if ctx.channel.id != AUTHORIZED_CHANNEL_ID: if ctx.channel.id != AUTHORIZED_CHANNEL_ID:
return return
@ -19,15 +19,15 @@ class MyStats(commands.Cog):
user_data = db_manager.get_user_all_pbs(username) user_data = db_manager.get_user_all_pbs(username)
if not user_data: if not user_data:
await ctx.send(f" No data found for **{username}**.") await ctx.send(f"❌ No data found for **{username}**.")
return return
embed = discord.Embed( embed = discord.Embed(
title=f"📊 {username}'s Complete Stats", title=f"📊 {username}'s Complete Stats",
color=0x00bfff color=0x00bfff
) )
# Hydra - toutes les difficultés # Hydra - toutes les difficultés
hydra_stats = [] hydra_stats = []
for difficulty in BOSS_CONFIG['hydra']['difficulties']: for difficulty in BOSS_CONFIG['hydra']['difficulties']:
pb_key = f'pb_hydra_{difficulty}' pb_key = f'pb_hydra_{difficulty}'
@ -36,13 +36,13 @@ class MyStats(commands.Cog):
if pb_key in user_data and user_data[pb_key] > 0: if pb_key in user_data and user_data[pb_key] > 0:
pb_value = user_data[pb_key] pb_value = user_data[pb_key]
pb_date = user_data.get(date_key) pb_date = user_data.get(date_key)
date_text = f" {format_date_only(pb_date)}" if pb_date else "" date_text = f" • {format_date_only(pb_date)}" if pb_date else ""
hydra_stats.append(f"**{difficulty.title()}:** {format_damage_display(pb_value)}{date_text}") hydra_stats.append(f"**{difficulty.title()}:** {format_damage_display(pb_value)}{date_text}")
hydra_text = "\n".join(hydra_stats) if hydra_stats else "No records" hydra_text = "\n".join(hydra_stats) if hydra_stats else "No records"
embed.add_field(name="🐍 Hydra PBs", value=hydra_text, inline=False) embed.add_field(name="🐍 Hydra PBs", value=hydra_text, inline=False)
# Chimera - toutes les difficultés # Chimera - toutes les difficultés
chimera_stats = [] chimera_stats = []
for difficulty in BOSS_CONFIG['chimera']['difficulties']: for difficulty in BOSS_CONFIG['chimera']['difficulties']:
pb_key = f'pb_chimera_{difficulty}' pb_key = f'pb_chimera_{difficulty}'
@ -51,12 +51,12 @@ class MyStats(commands.Cog):
if pb_key in user_data and user_data[pb_key] > 0: if pb_key in user_data and user_data[pb_key] > 0:
pb_value = user_data[pb_key] pb_value = user_data[pb_key]
pb_date = user_data.get(date_key) pb_date = user_data.get(date_key)
date_text = f" {format_date_only(pb_date)}" if pb_date else "" date_text = f" • {format_date_only(pb_date)}" if pb_date else ""
display_name = "Ultra Nightmare" if difficulty == "ultra" else difficulty.title() display_name = "Ultra Nightmare" if difficulty == "ultra" else difficulty.title()
chimera_stats.append(f"**{display_name}:** {format_damage_display(pb_value)}{date_text}") chimera_stats.append(f"**{display_name}:** {format_damage_display(pb_value)}{date_text}")
chimera_text = "\n".join(chimera_stats) if chimera_stats else "No records" chimera_text = "\n".join(chimera_stats) if chimera_stats else "No records"
embed.add_field(name="🦁 Chimera PBs", value=chimera_text, inline=False) embed.add_field(name="🦁 Chimera PBs", value=chimera_text, inline=False)
# CvC # CvC
cvc_pb = user_data.get('pb_cvc', 0) cvc_pb = user_data.get('pb_cvc', 0)
@ -65,10 +65,10 @@ class MyStats(commands.Cog):
if cvc_pb > 0 and cvc_date: if cvc_pb > 0 and cvc_date:
formatted_date = format_date_only(cvc_date) formatted_date = format_date_only(cvc_date)
if formatted_date: if formatted_date:
cvc_text += f" {formatted_date}" cvc_text += f" • {formatted_date}"
embed.add_field(name="⚔️ CvC PB", value=cvc_text, inline=False) embed.add_field(name="⚔️ CvC PB", value=cvc_text, inline=False)
# Total combiné # Total combiné
total_damage = 0 total_damage = 0
for difficulty in BOSS_CONFIG['hydra']['difficulties']: for difficulty in BOSS_CONFIG['hydra']['difficulties']:
total_damage += user_data.get(f'pb_hydra_{difficulty}', 0) total_damage += user_data.get(f'pb_hydra_{difficulty}', 0)
@ -76,12 +76,12 @@ class MyStats(commands.Cog):
total_damage += user_data.get(f'pb_chimera_{difficulty}', 0) total_damage += user_data.get(f'pb_chimera_{difficulty}', 0)
total_damage += user_data.get('pb_cvc', 0) total_damage += user_data.get('pb_cvc', 0)
embed.add_field(name="💯 Total Combined Damage", value=f"**{format_damage_display(total_damage)}**", inline=False) embed.add_field(name="💯 Total Combined Damage", value=f"**{format_damage_display(total_damage)}**", inline=False)
await ctx.send(embed=embed) await ctx.send(embed=embed)
except Exception as e: except Exception as e:
await ctx.send(f" Error: {e}") await ctx.send(f"❌ Error: {e}")
# Pour charger le Cog # Pour charger le Cog

View file

@ -8,11 +8,11 @@ services:
- .env - .env
volumes: volumes:
# Montre le code source pour hot-reload # Montre le code source pour hot-reload
- ./:/app-dev - ./:/app
# Montre les dossiers de stockage persistants # Montre les dossiers de stockage persistants
- ./screenshots:/app-dev/screenshots - ./screenshots:/app/screenshots
- ./bot_data.db:/app-dev/bot_data.db - ./bot_data.db:/app/bot_data.db
- ./logs:/app-dev/logs - ./logs:/app/logs
environment: environment:
- TZ=Europe/Paris - TZ=Europe/Paris
container_name: rtf-discord-bot container_name: rtf-discord-bot

View file

@ -11,17 +11,17 @@ def set_db_manager(db):
db_manager = db db_manager = db
async def show_leaderboard(ctx, boss_type, difficulty=None, clan=None): async def show_leaderboard(ctx, boss_type, difficulty=None, clan=None):
"""Fonction générique pour afficher les classements""" """Fonction générique pour afficher les classements"""
if ctx.channel.id != AUTHORIZED_CHANNEL_ID: if ctx.channel.id != AUTHORIZED_CHANNEL_ID:
return return
try: try:
# Normaliser la difficulté si spécifiée # Normaliser la difficulté si spécifiée
if difficulty: if difficulty:
difficulty = normalize_difficulty(difficulty) difficulty = normalize_difficulty(difficulty)
if difficulty not in BOSS_CONFIG[boss_type]['difficulties']: if difficulty not in BOSS_CONFIG[boss_type]['difficulties']:
difficulties = " | ".join(BOSS_CONFIG[boss_type]['difficulties']) difficulties = " | ".join(BOSS_CONFIG[boss_type]['difficulties'])
await ctx.send(f" Invalid difficulty. Available: {difficulties}") await ctx.send(f"❌ Invalid difficulty. Available: {difficulties}")
return return
boss_info = BOSS_CONFIG[boss_type] boss_info = BOSS_CONFIG[boss_type]
@ -30,15 +30,15 @@ async def show_leaderboard(ctx, boss_type, difficulty=None, clan=None):
if not leaderboard: if not leaderboard:
clan_text = f" for clan {clan}" if clan else "" clan_text = f" for clan {clan}" if clan else ""
difficulty_text = f" {get_difficulty_display_name(difficulty)}" if difficulty else "" difficulty_text = f" {get_difficulty_display_name(difficulty)}" if difficulty else ""
await ctx.send(f" No{difficulty_text} {boss_info['name']} records found{clan_text} yet!") await ctx.send(f"❌ No{difficulty_text} {boss_info['name']} records found{clan_text} yet!")
return return
# Titre avec clan et difficulté si spécifiés # Titre avec clan et difficulté si spécifiés
difficulty_name = get_difficulty_display_name(difficulty) if difficulty else "" difficulty_name = get_difficulty_display_name(difficulty) if difficulty else ""
title = f"🏆 {difficulty_name} {boss_info['name']} Leaderboard - Top 10" title = f"🏆 {difficulty_name} {boss_info['name']} Leaderboard - Top 10"
if clan: if clan:
clan_info = CLAN_CONFIG.get(clan, {'name': clan, 'emoji': '🏛️'}) clan_info = CLAN_CONFIG.get(clan, {'name': clan, 'emoji': '🏛️'})
title = f"{clan_info['emoji']} {clan_info['name']} - {difficulty_name} {boss_info['name']} Top 10" title = f"{clan_info['emoji']} {clan_info['name']} - {difficulty_name} {boss_info['name']} Top 10"
embed = discord.Embed( embed = discord.Embed(
@ -46,21 +46,21 @@ async def show_leaderboard(ctx, boss_type, difficulty=None, clan=None):
color=boss_info['color'] if not clan else CLAN_CONFIG.get(clan, {'color': boss_info['color']})['color'] color=boss_info['color'] if not clan else CLAN_CONFIG.get(clan, {'color': boss_info['color']})['color']
) )
medals = ["🥇", "🥈", "🥉"] + ["🏅"] * 7 medals = ["🥇", "🥈", "🥉"] + ["🏅"] * 7
for i, (username, damage, date) in enumerate(leaderboard): for i, (username, damage, date) in enumerate(leaderboard):
date_text = "" date_text = ""
if date: if date:
formatted_date = format_date_only(date) formatted_date = format_date_only(date)
if formatted_date: if formatted_date:
date_text = f" {formatted_date}" date_text = f" • {formatted_date}"
# Afficher le clan dans le nom si pas de filtre par clan # Afficher le clan dans le nom si pas de filtre par clan
display_name = username display_name = username
if not clan: if not clan:
user_clan = get_user_clan(username) user_clan = get_user_clan(username)
if user_clan: if user_clan:
clan_emoji = CLAN_CONFIG.get(user_clan, {'emoji': '🏛️'})['emoji'] clan_emoji = CLAN_CONFIG.get(user_clan, {'emoji': '🏛️'})['emoji']
display_name = f"{clan_emoji} {username}" display_name = f"{clan_emoji} {username}"
embed.add_field( embed.add_field(
@ -72,4 +72,4 @@ async def show_leaderboard(ctx, boss_type, difficulty=None, clan=None):
await ctx.send(embed=embed) await ctx.send(embed=embed)
except Exception as e: except Exception as e:
await ctx.send(f" Error: {e}") await ctx.send(f"❌ Error: {e}")

View file

@ -13,13 +13,13 @@ db_manager = None
screenshot_manager = None screenshot_manager = None
def set_managers(db, ss): def set_managers(db, ss):
"""Injection des managers (appelée une seule fois depuis bot.py)""" """Injection des managers (appelée une seule fois depuis bot.py)"""
global db_manager, screenshot_manager global db_manager, screenshot_manager
db_manager = db db_manager = db
screenshot_manager = ss screenshot_manager = ss
async def handle_pb_command(ctx, boss_type, arg1=None, arg2=None): async def handle_pb_command(ctx, boss_type, arg1=None, arg2=None):
"""Fonction générique pour gérer toutes les commandes PB avec difficultés""" """Fonction générique pour gérer toutes les commandes PB avec difficultés"""
if ctx.channel.id != AUTHORIZED_CHANNEL_ID: if ctx.channel.id != AUTHORIZED_CHANNEL_ID:
return return
@ -27,7 +27,7 @@ async def handle_pb_command(ctx, boss_type, arg1=None, arg2=None):
difficulties = boss_info['difficulties'] difficulties = boss_info['difficulties']
try: try:
# Pour CvC (pas de difficultés) # Pour CvC (pas de difficultés)
if not difficulties: if not difficulties:
# Utiliser l'ancienne logique pour CvC avec parsing des montants # Utiliser l'ancienne logique pour CvC avec parsing des montants
if arg1: if arg1:
@ -40,12 +40,12 @@ async def handle_pb_command(ctx, boss_type, arg1=None, arg2=None):
await show_user_pb(ctx, boss_type, None, ctx.author.display_name) await show_user_pb(ctx, boss_type, None, ctx.author.display_name)
return return
# Pour Hydra et Chimera (avec difficultés) # Pour Hydra et Chimera (avec difficultés)
if not arg1: if not arg1:
# !pbhydra sans arguments - montrer aide # !pbhydra sans arguments - montrer aide
difficulty_list = " | ".join([d.title() for d in difficulties]) difficulty_list = " | ".join([d.title() for d in difficulties])
await ctx.send( await ctx.send(
f" Please specify difficulty and damage!\n" f"❌ Please specify difficulty and damage!\n"
f"**Available difficulties:** {difficulty_list}\n" f"**Available difficulties:** {difficulty_list}\n"
f"**Shortcuts:** `nm` = Nightmare, `unm` = Ultra Nightmare\n" f"**Shortcuts:** `nm` = Nightmare, `unm` = Ultra Nightmare\n"
f"**Examples:**\n" f"**Examples:**\n"
@ -56,10 +56,10 @@ async def handle_pb_command(ctx, boss_type, arg1=None, arg2=None):
) )
return return
# Normaliser la difficulté (gérer les diminutifs) # Normaliser la difficulté (gérer les diminutifs)
normalized_difficulty = normalize_difficulty(arg1) normalized_difficulty = normalize_difficulty(arg1)
# Vérifier si arg1 est une difficulté valide # Vérifier si arg1 est une difficulté valide
if normalized_difficulty in difficulties: if normalized_difficulty in difficulties:
difficulty = normalized_difficulty difficulty = normalized_difficulty
@ -75,26 +75,26 @@ async def handle_pb_command(ctx, boss_type, arg1=None, arg2=None):
# !pbhydra normal - Voir son propre PB # !pbhydra normal - Voir son propre PB
await show_user_pb(ctx, boss_type, difficulty, ctx.author.display_name) await show_user_pb(ctx, boss_type, difficulty, ctx.author.display_name)
else: else:
# arg1 n'est pas une difficulté valide # arg1 n'est pas une difficulté valide
difficulty_list = " | ".join([d.title() for d in difficulties]) difficulty_list = " | ".join([d.title() for d in difficulties])
await ctx.send( await ctx.send(
f" Invalid difficulty: `{arg1}`\n" f"❌ Invalid difficulty: `{arg1}`\n"
f"**Available difficulties:** {difficulty_list}\n" f"**Available difficulties:** {difficulty_list}\n"
f"**Shortcuts:** `nm` = Nightmare, `unm` = Ultra Nightmare" f"**Shortcuts:** `nm` = Nightmare, `unm` = Ultra Nightmare"
) )
except Exception as e: except Exception as e:
await ctx.send(f" Error: {e}") await ctx.send(f"❌ Error: {e}")
async def handle_pb_submission(ctx, boss_type, difficulty, damage): async def handle_pb_submission(ctx, boss_type, difficulty, damage):
"""Gère la soumission d'un nouveau PB""" """Gère la soumission d'un nouveau PB"""
if not ctx.message.attachments: if not ctx.message.attachments:
await ctx.send(" Please attach a screenshot to validate your PB!") await ctx.send("❌ Please attach a screenshot to validate your PB!")
return return
attachment = ctx.message.attachments[0] attachment = ctx.message.attachments[0]
if not any(attachment.filename.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.webp']): if not any(attachment.filename.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.webp']):
await ctx.send(" Please attach a valid image file!") await ctx.send("❌ Please attach a valid image file!")
return return
username = ctx.author.display_name username = ctx.author.display_name
@ -107,7 +107,7 @@ async def handle_pb_submission(ctx, boss_type, difficulty, damage):
) )
if screenshot_filename: if screenshot_filename:
# Mettre à jour la base et récupérer l'ancien screenshot # Mettre à jour la base et récupérer l'ancien screenshot
old_screenshot = db_manager.update_user_pb( old_screenshot = db_manager.update_user_pb(
username, boss_type, damage, screenshot_filename, difficulty username, boss_type, damage, screenshot_filename, difficulty
) )
@ -121,20 +121,20 @@ async def handle_pb_submission(ctx, boss_type, difficulty, damage):
difficulty_name = get_difficulty_display_name(difficulty) if difficulty else "" difficulty_name = get_difficulty_display_name(difficulty) if difficulty else ""
embed = discord.Embed( embed = discord.Embed(
title=f"🎉 NEW {boss_info['name'].upper()} PB! 🎉", title=f"🎉 NEW {boss_info['name'].upper()} PB! 🎉",
description=f"**{username}** just hit **{format_damage_display(damage)} damage** on {difficulty_name} {boss_info['name']}!", description=f"**{username}** just hit **{format_damage_display(damage)} damage** on {difficulty_name} {boss_info['name']}!",
color=0x00ff00 color=0x00ff00
) )
embed.add_field(name="📈 Improvement", value=f"+{format_damage_display(improvement)} damage", inline=True) embed.add_field(name="📈 Improvement", value=f"+{format_damage_display(improvement)} damage", inline=True)
embed.set_image(url=attachment.url) embed.set_image(url=attachment.url)
await ctx.send(embed=embed) await ctx.send(embed=embed)
else: else:
await ctx.send(" Failed to save screenshot. Please try again.") await ctx.send("❌ Failed to save screenshot. Please try again.")
else: else:
difficulty_name = get_difficulty_display_name(difficulty) if difficulty else "" difficulty_name = get_difficulty_display_name(difficulty) if difficulty else ""
embed = discord.Embed( embed = discord.Embed(
title="💪 Nice attempt!", title="💪 Nice attempt!",
description=f"Your damage: **{format_damage_display(damage)}**\nCurrent PB: **{format_damage_display(current_pb)}**", description=f"Your damage: **{format_damage_display(damage)}**\nCurrent PB: **{format_damage_display(current_pb)}**",
color=0xffa500 color=0xffa500
) )
@ -161,7 +161,7 @@ async def show_user_pb(ctx, boss_type, difficulty, username):
color=0x666666 color=0x666666
) )
embed.add_field( embed.add_field(
name="💡 Get started!", name="💡 Get started!",
value=f"Use `!pb{boss_type} {difficulty} <damage>` with a screenshot to set your first record!\nAccepts K/M/B suffixes: `1.5M`, `500K`, etc.", value=f"Use `!pb{boss_type} {difficulty} <damage>` with a screenshot to set your first record!\nAccepts K/M/B suffixes: `1.5M`, `500K`, etc.",
inline=False inline=False
) )
@ -176,7 +176,7 @@ async def show_user_pb(ctx, boss_type, difficulty, username):
if pb_date: if pb_date:
formatted_date = format_datetime(pb_date) formatted_date = format_datetime(pb_date)
if formatted_date: if formatted_date:
embed.add_field(name="📅 Record Date", value=formatted_date, inline=False) embed.add_field(name="📅 Record Date", value=formatted_date, inline=False)
# Envoyer la screenshot si elle existe # Envoyer la screenshot si elle existe
if screenshot_filename: if screenshot_filename: