import pygame
import random
import sys
import math
 
# --- CONFIGURATION ---
WIDTH, HEIGHT = 1280, 800
FPS = 60
 
# Couleurs
WHITE      = (245, 245, 245)
BLACK      = (20, 20, 25)
GREEN      = (46, 204, 113)
YELLOW     = (241, 196, 15)
RED        = (231, 76, 60)
BLUE       = (52, 152, 219)
PURPLE     = (155, 89, 182)
DARK_GRAY  = (44, 62, 80)
GOLD       = (255, 215, 0)
GOLD_DARK  = (180, 140, 0)
SKIN       = (255, 220, 180)
BROWN      = (101, 67, 33)
LIGHT_BLUE = (173, 216, 230)
 
# Brawlhalla palette
BW_BG      = (15, 12, 30)
BW_STONE   = (35, 28, 55)
BW_ACCENT  = (80, 60, 120)
BW_TORCH   = (255, 140, 40)
BW_TORCH2  = (255, 80, 20)
BW_PANEL   = (22, 17, 40)
BW_BORDER  = (200, 160, 60)
BW_BORDER2 = (120, 90, 20)
BW_TEXT    = (235, 220, 180)
BW_GREEN   = (60, 200, 80)
BW_BLUE    = (60, 140, 230)
BW_RED     = (210, 50, 40)
 
pygame.init()
info = pygame.display.Info()
SW, SH = info.current_w, info.current_h
screen = pygame.display.set_mode((SW, SH), pygame.FULLSCREEN)
WIDTH, HEIGHT = SW, SH
pygame.display.set_caption("Duel de Légendes : Arena Edition")
clock = pygame.time.Clock()
 
# Fonts
try:
    font_title  = pygame.font.SysFont("Courier New", int(HEIGHT*0.048), bold=True)
    font_big    = pygame.font.SysFont("Courier New", int(HEIGHT*0.036), bold=True)
    font_med    = pygame.font.SysFont("Courier New", int(HEIGHT*0.026), bold=True)
    font_small  = pygame.font.SysFont("Courier New", int(HEIGHT*0.019), bold=True)
    font_tiny   = pygame.font.SysFont("Courier New", int(HEIGHT*0.016), bold=True)
except:
    font_title  = pygame.font.SysFont("Verdana", int(HEIGHT*0.048), bold=True)
    font_big    = pygame.font.SysFont("Verdana", int(HEIGHT*0.036), bold=True)
    font_med    = pygame.font.SysFont("Verdana", int(HEIGHT*0.026), bold=True)
    font_small  = pygame.font.SysFont("Verdana", int(HEIGHT*0.019), bold=True)
    font_tiny   = pygame.font.SysFont("Verdana", int(HEIGHT*0.016), bold=True)
 
# --- MATRICES PIXEL ART ---
SPRITE_DATA = {
    "Chevalier": ([
        [0,0,0,2,2,2,2,2,0,0,0],
        [0,0,2,1,1,1,1,1,2,0,0],
        [0,2,1,1,1,1,1,1,1,2,0],
        [2,1,1,2,2,2,2,2,1,1,2],
        [2,1,2,4,2,4,2,4,2,1,2],
        [2,1,2,2,2,2,2,2,2,1,2],
        [2,1,1,1,2,2,2,1,1,1,2],
        [0,2,1,1,1,1,1,1,1,2,0],
        [0,0,2,5,5,5,5,5,2,0,0],
        [0,2,1,1,1,1,1,1,1,2,0],
        [2,1,1,1,1,1,1,1,1,1,2],
    ], {1: (180,180,190), 2: (40,40,50), 4: (200,0,0), 5: GOLD}),
 
    "Magicien": ([
        [0,0,0,0,1,1,1,0,0,0,0],
        [0,0,0,1,1,1,1,1,0,0,0],
        [0,0,1,1,1,1,1,1,1,0,0],
        [0,1,1,1,1,1,1,1,1,1,0],
        [0,2,2,3,3,3,3,3,2,2,0],
        [0,2,3,3,4,3,4,3,3,2,0],
        [0,2,3,3,3,3,3,3,3,2,0],
        [0,0,2,2,3,2,3,2,2,0,0],
        [0,1,1,1,1,1,1,1,1,1,0],
        [1,1,1,1,1,5,5,1,1,1,1],
    ], {1: PURPLE, 2: BLACK, 3: SKIN, 4: LIGHT_BLUE, 5: GOLD}),
 
    "Ogre": ([
        [0,0,1,1,1,1,1,1,1,0,0],
        [0,1,1,1,1,1,1,1,1,1,0],
        [1,1,1,1,1,1,1,1,1,1,1],
        [1,1,4,1,1,1,1,1,4,1,1],
        [1,1,1,1,1,1,1,1,1,1,1],
        [1,1,2,2,2,2,2,2,2,1,1],
        [0,1,2,1,1,1,1,1,2,1,0],
        [0,1,1,1,1,1,1,1,1,1,0],
        [0,5,5,5,0,0,0,5,5,5,0],
    ], {1: GREEN, 2: (20,80,20), 4: YELLOW, 5: BROWN}),
 
    "Pretre": ([
        [0,0,0,5,5,5,5,5,0,0,0],
        [0,0,5,5,5,5,5,5,5,0,0],
        [0,5,5,5,3,3,3,5,5,5,0],
        [0,5,3,3,3,4,3,3,3,5,0],
        [0,5,3,3,3,3,3,3,3,5,0],
        [0,0,5,1,1,1,1,1,5,0,0],
        [0,1,1,1,1,1,1,1,1,1,0],
        [1,1,1,1,5,5,5,1,1,1,1],
    ], {1: WHITE, 3: SKIN, 4: BLUE, 5: GOLD}),
 
    "Necromancien": ([
        [0,0,2,2,2,2,2,2,2,0,0],
        [0,2,2,2,2,2,2,2,2,2,0],
        [2,2,2,1,1,1,1,1,2,2,2],
        [2,2,1,1,4,1,4,1,1,2,2],
        [2,2,1,1,1,1,1,1,1,2,2],
        [0,2,2,1,1,1,1,1,2,2,0],
        [0,0,2,2,1,1,1,2,2,0,0],
        [0,2,2,2,2,2,2,2,2,2,0],
    ], {1: (50,50,50), 2: BLACK, 4: (0,255,0)}),
}
 
# --- AFFLICTIONS (référence centralisée) ---
# Peur      : la cible perd son prochain tour (skip automatique)
# Paralysé  : la cible perd son prochain tour (skip automatique)
# Assommé   : la cible perd son prochain tour (skip automatique)
# Note : tous les états font perdre UN tour, puis se dissipent.
#        Un état peut être purgé avec une action de purge.
 
AFFLICTION_DESC = {
    "Peur":     "PEUR — Fait perdre le prochain tour à la cible. Se dissipe ensuite.",
    "Paralysé": "PARALYSIE — Fait perdre le prochain tour à la cible. Se dissipe ensuite.",
    "Assommé":  "ASSOMMÉ — Fait perdre le prochain tour à la cible. Se dissipe ensuite.",
}
 
# --- CLASSES PERSONNAGES ---
class Personnage:
    def __init__(self, nom, hp, mp, force, sprite_key):
        self.nom = nom; self.hp_max=hp; self.hp=hp
        self.mp_max=mp; self.mp=mp//2
        self.force=force; self.sprite_key=sprite_key
        self.etat_actuel=None; self.shake=0
        self.bloque = False
 
class Chevalier(Personnage):
    def __init__(self, n): super().__init__(n, 150, 60, 1.3, "Chevalier")
    def get_actions(self): return [
        {"nom":"Tranchage","cout":0,"type":"dmg","val":"15-22","anim":"slash",
         "desc":"Fend l'air d'un geste rageur. La lame siffle.",
         "mecanique":"Inflige 15-22 dégâts physiques. Gratuit.","degats":"15-22 DMG"},
        {"nom":"Parer","cout":0,"type":"parer","anim":"purge_shield",
         "desc":"Bouclier levé, pieds ancrés dans le sol.",
         "mecanique":"Réduit de moitié les dégâts du prochain coup reçu.","degats":"Bloc 50%"},
        {"nom":"Reprendre Souffle","cout":0,"type":"recuperer","val_mp":8,"anim":"purge_shield",
         "desc":"Un instant de calme. L'énergie reflue.",
         "mecanique":"Restaure 8 points de mana. Aucun coût.","degats":"+8 MANA"},
        {"nom":"Détermination","cout":5,"type":"purge","anim":"purge_shield",
         "desc":"Aura dorée. Les entraves se brisent.",
         "mecanique":"Supprime l'état négatif actif (Peur, Paralysie, Assommé). Coûte 5 mana.","degats":"Purge état"},
        {"nom":"Cri de Guerre","cout":20,"type":"spec","proc":"Peur","chance":45,"anim":"warcry",
         "desc":"Rugissement bestial. L'ennemi chancelle.",
         "mecanique":"45% de chance d'infliger PEUR.\nPeur : la cible perd son prochain tour.\nCoûte 20 mana.","degats":"Peur 45%"},
        {"nom":"Coup d'Estoc","cout":12,"type":"dmg","val":"22-35","anim":"slash",
         "desc":"Plonge en avant, pointe tendue. Brutal.",
         "mecanique":"Inflige 22-35 dégâts perçants. Coûte 12 mana.","degats":"22-35 DMG"},
    ]
 
class Magicien(Personnage):
    def __init__(self, n): super().__init__(n, 90, 150, 1.8, "Magicien")
    def get_actions(self): return [
        {"nom":"Baguette Arcane","cout":0,"type":"dmg","val":"10-18","anim":"slash",
         "desc":"Rayon concentré d'énergie brute. Simple.",
         "mecanique":"Inflige 10-18 dégâts magiques. Gratuit.","degats":"10-18 DMG"},
        {"nom":"Parer","cout":0,"type":"parer","anim":"purge_runes",
         "desc":"Bouclier de runes tissé à toute vitesse.",
         "mecanique":"Réduit de moitié les dégâts du prochain coup reçu.","degats":"Bloc 50%"},
        {"nom":"Méditation","cout":0,"type":"recuperer","val_mp":20,"anim":"purge_runes",
         "desc":"Les flux arcaniques traversent le corps.",
         "mecanique":"Restaure 20 points de mana. Aucun coût.","degats":"+20 MANA"},
        {"nom":"Boule de Feu","cout":15,"type":"dmg","val":"25-40","anim":"fireball",
         "desc":"Sphère de feu pur. L'impact explose.",
         "mecanique":"Inflige 25-40 dégâts de feu. Coûte 15 mana.","degats":"25-40 DMG"},
        {"nom":"Dissipation","cout":8,"type":"purge","anim":"purge_runes",
         "desc":"Runes tourbillonnantes dissolvent les sorts.",
         "mecanique":"Supprime l'état négatif actif (Peur, Paralysie, Assommé). Coûte 8 mana.","degats":"Purge état"},
        {"nom":"Éclair","cout":20,"type":"spec","proc":"Paralysé","chance":60,"anim":"lightning",
         "desc":"CRACK ! La foudre frappe. Le corps se fige.",
         "mecanique":"60% de chance d'infliger PARALYSIE.\nParalysie : la cible perd son prochain tour.\nCoûte 20 mana.","degats":"Paralysie 60%"},
    ]
 
class Ogre(Personnage):
    def __init__(self, n): super().__init__(n, 250, 50, 1.6, "Ogre")
    def get_actions(self): return [
        {"nom":"Claque","cout":0,"type":"dmg","val":"20-30","anim":"slam",
         "desc":"Bras abattu comme un tronc d'arbre.",
         "mecanique":"Inflige 20-30 dégâts bruts. Gratuit.","degats":"20-30 DMG"},
        {"nom":"Parer","cout":0,"type":"parer","anim":"purge_roar",
         "desc":"Grogne et encaisse la frappe dans la masse.",
         "mecanique":"Réduit de moitié les dégâts du prochain coup reçu.","degats":"Bloc 50%"},
        {"nom":"Mâcher un Os","cout":0,"type":"recuperer","val_mp":6,"anim":"purge_roar",
         "desc":"Croque bruyamment. Énergie primitive.",
         "mecanique":"Restaure 6 points de mana. Aucun coût.","degats":"+6 MANA"},
        {"nom":"Secousse","cout":5,"type":"purge","anim":"purge_roar",
         "desc":"Rugissement qui brise les sortilèges.",
         "mecanique":"Supprime l'état négatif actif (Peur, Paralysie, Assommé). Coûte 5 mana.","degats":"Purge état"},
        {"nom":"Fracas","cout":25,"type":"spec","proc":"Assommé","chance":40,"anim":"groundsmash",
         "desc":"Deux poings joints. Le sol tremble.",
         "mecanique":"40% de chance d'infliger ASSOMMÉ.\nAssommé : la cible perd son prochain tour.\nCoûte 25 mana.","degats":"KO 40%"},
        {"nom":"Piétinement","cout":15,"type":"dmg","val":"30-45","anim":"groundsmash",
         "desc":"Plaqué au sol. Coups de pieds implacables.",
         "mecanique":"Inflige 30-45 dégâts écrasants. Coûte 15 mana.","degats":"30-45 DMG"},
    ]
 
class Pretre(Personnage):
    def __init__(self, n): super().__init__(n, 120, 120, 1.2, "Pretre")
    def get_actions(self): return [
        {"nom":"Châtiment Sacré","cout":0,"type":"dmg","val":"8-15","anim":"holybeam",
         "desc":"Lumière aveuglante jaillit de la paume.",
         "mecanique":"Inflige 8-15 dégâts sacrés. Gratuit.","degats":"8-15 DMG"},
        {"nom":"Parer","cout":0,"type":"parer","anim":"purge_light",
         "desc":"Bulle de lumière absorbe le prochain coup.",
         "mecanique":"Réduit de moitié les dégâts du prochain coup reçu.","degats":"Bloc 50%"},
        {"nom":"Prière Ardente","cout":0,"type":"recuperer","val_mp":15,"anim":"purge_light",
         "desc":"La foi afflue. Grâce divine rechargée.",
         "mecanique":"Restaure 15 points de mana. Aucun coût.","degats":"+15 MANA"},
        {"nom":"Lumière","cout":12,"type":"dmg","val":"15-25","anim":"holybeam",
         "desc":"Rayon sacré descendant du firmament.",
         "mecanique":"Inflige 15-25 dégâts sacrés. Coûte 12 mana.","degats":"15-25 DMG"},
        {"nom":"Purification","cout":5,"type":"purge","anim":"purge_light",
         "desc":"Onde blanche dissipe venin et malédiction.",
         "mecanique":"Supprime l'état négatif actif (Peur, Paralysie, Assommé). Coûte 5 mana.","degats":"Purge état"},
        {"nom":"Soin","cout":15,"type":"soin","val":50,"anim":"heal",
         "desc":"Mains posées. La chair se referme, dorée.",
         "mecanique":"Restaure 50 PV à soi-même. Coûte 15 mana.","degats":"+50 HP"},
    ]
 
class Necro(Personnage):
    def __init__(self, n): super().__init__(n, 110, 100, 1.5, "Necromancien")
    def get_actions(self): return [
        {"nom":"Toucher Fétide","cout":0,"type":"dmg","val":"12-20","anim":"plague",
         "desc":"Caresse froide. La peau noircit et craque.",
         "mecanique":"Inflige 12-20 dégâts nécrotiques. Gratuit.","degats":"12-20 DMG"},
        {"nom":"Parer","cout":0,"type":"parer","anim":"purge_shadow",
         "desc":"Spectre convoqué absorbe le coup à sa place.",
         "mecanique":"Réduit de moitié les dégâts du prochain coup reçu.","degats":"Bloc 50%"},
        {"nom":"Drain d'Âme","cout":0,"type":"recuperer","val_mp":12,"anim":"purge_shadow",
         "desc":"Absorbe les échos d'âmes flottant dans l'arène.",
         "mecanique":"Restaure 12 points de mana. Aucun coût.","degats":"+12 MANA"},
        {"nom":"Peste","cout":15,"type":"dmg","val":"20-35","anim":"plague",
         "desc":"Nuage de miasmes verdâtres. Chaque souffle brûle.",
         "mecanique":"Inflige 20-35 dégâts toxiques. Coûte 15 mana.","degats":"20-35 DMG"},
        {"nom":"Éveil Sombre","cout":7,"type":"purge","anim":"purge_shadow",
         "desc":"Ténèbres vivantes absorbent les malédictions.",
         "mecanique":"Supprime l'état négatif actif (Peur, Paralysie, Assommé). Coûte 7 mana.","degats":"Purge état"},
        {"nom":"Cauchemar","cout":20,"type":"spec","proc":"Peur","chance":50,"anim":"nightmare",
         "desc":"Plonge dans l'âme. Les pires visions se matérialisent.",
         "mecanique":"50% de chance d'infliger PEUR.\nPeur : la cible perd son prochain tour.\nCoûte 20 mana.","degats":"Peur 50%"},
    ]
 
# =====================================================
# --- SYSTÈME D'ANIMATIONS DE COMBAT ---
# =====================================================
class AnimationManager:
    def __init__(self):
        self.active = []
 
    def play(self, anim_key, attacker_rect, target_rect):
        self.active = []
        self.active.append({
            'key': anim_key,
            'prog': 0.0,
            'attacker': attacker_rect,
            'target': target_rect,
            'particles': self._init_particles(anim_key, target_rect),
        })
 
    def _init_particles(self, key, trect):
        parts = []
        cx = trect[0] + trect[2]//2
        cy = trect[1] + trect[3]//2
        if key == 'fireball':
            for _ in range(28):
                a = random.uniform(0, math.pi*2); spd = random.uniform(2,7)
                parts.append({'x':cx,'y':cy,'vx':math.cos(a)*spd,'vy':math.sin(a)*spd,
                              'life':1.0,'col':(255,random.randint(80,200),0),'sz':random.randint(4,10)})
        elif key == 'lightning':
            for _ in range(20):
                parts.append({'x':cx+random.randint(-60,60),'y':cy+random.randint(-60,60),
                              'vx':random.uniform(-1,1),'vy':random.uniform(-3,0),
                              'life':1.0,'col':(180,220,255),'sz':random.randint(3,7)})
        elif key == 'slash':
            for _ in range(15):
                parts.append({'x':cx+random.randint(-40,40),'y':cy+random.randint(-40,40),
                              'vx':random.uniform(-2,4),'vy':random.uniform(-4,1),
                              'life':1.0,'col':(220,220,255),'sz':random.randint(2,6)})
        elif key == 'slam':
            for _ in range(25):
                a = random.uniform(0, math.pi); spd = random.uniform(1,5)
                parts.append({'x':cx,'y':trect[1]+trect[3],
                              'vx':math.cos(a)*spd,'vy':-abs(math.sin(a)*spd)-1,
                              'life':1.0,'col':(139,90,43),'sz':random.randint(4,12)})
        elif key == 'plague':
            for _ in range(22):
                a = random.uniform(0, math.pi*2); spd = random.uniform(1,4)
                parts.append({'x':cx,'y':cy,'vx':math.cos(a)*spd,'vy':math.sin(a)*spd,
                              'life':1.0,'col':(0,random.randint(180,255),0),'sz':random.randint(3,8)})
        elif key == 'holybeam':
            for _ in range(20):
                parts.append({'x':cx+random.randint(-30,30),'y':cy-random.randint(0,80),
                              'vx':random.uniform(-0.5,0.5),'vy':random.uniform(1,3),
                              'life':1.0,'col':(255,255,180),'sz':random.randint(3,8)})
        elif key in ('heal',):
            for _ in range(18):
                a = random.uniform(0, math.pi*2); r = random.uniform(20,70)
                parts.append({'x':cx+math.cos(a)*r,'y':cy+math.sin(a)*r,
                              'vx':math.cos(a)*0.5,'vy':-random.uniform(0.5,2),
                              'life':1.0,'col':(100,255,150),'sz':random.randint(4,9)})
        elif key == 'groundsmash':
            for _ in range(30):
                a = random.uniform(0, math.pi*2); spd = random.uniform(2,8)
                parts.append({'x':cx,'y':cy,'vx':math.cos(a)*spd,'vy':math.sin(a)*spd,
                              'life':1.0,'col':(200,160,80),'sz':random.randint(5,14)})
        elif key == 'nightmare':
            for _ in range(20):
                a = random.uniform(0, math.pi*2); r = random.uniform(10,80)
                parts.append({'x':cx+math.cos(a)*r,'y':cy+math.sin(a)*r,
                              'vx':math.cos(a)*-0.5,'vy':-random.uniform(0.3,1.5),
                              'life':1.0,'col':(random.randint(100,180),0,random.randint(150,255)),'sz':random.randint(3,9)})
        elif key == 'warcry':
            for _ in range(20):
                a = random.uniform(0, math.pi*2); spd = random.uniform(2,6)
                parts.append({'x':cx,'y':cy,'vx':math.cos(a)*spd,'vy':math.sin(a)*spd,
                              'life':1.0,'col':(255,80,30),'sz':random.randint(4,10)})
        return parts
 
    def update(self, dt):
        for a in self.active:
            a['prog'] = min(1.0, a['prog'] + dt * 0.8)
            for p in a['particles']:
                p['x'] += p['vx']; p['y'] += p['vy']
                p['vy'] += 0.15
                p['life'] -= dt * 1.4
        self.active = [a for a in self.active if a['prog'] < 1.0]
 
    def draw(self, surface):
        for a in self.active:
            t = a['prog']
            key = a['key']
            ar = a['attacker']
            tr = a['target']
            ax = ar[0]+ar[2]//2; ay = ar[1]+ar[3]//2
            tx = tr[0]+tr[2]//2; ty = tr[1]+tr[3]//2
 
            if key == 'slash':
                self._draw_slash(surface, tx, ty, t)
            elif key == 'fireball':
                self._draw_fireball(surface, ax, ay, tx, ty, t)
            elif key == 'lightning':
                self._draw_lightning(surface, tx, ty, t)
            elif key == 'slam':
                self._draw_slam(surface, tx, ty, t)
            elif key == 'plague':
                self._draw_plague(surface, ax, ay, tx, ty, t)
            elif key == 'holybeam':
                self._draw_holybeam(surface, tx, ty, t)
            elif key == 'heal':
                self._draw_heal(surface, ax, ay, t)
            elif key == 'groundsmash':
                self._draw_groundsmash(surface, tx, ty, t)
            elif key == 'nightmare':
                self._draw_nightmare(surface, tx, ty, t)
            elif key == 'warcry':
                self._draw_warcry(surface, ax, ay, tx, ty, t)
            elif key == 'purge_shield':
                self._draw_purge_shield(surface, ax, ay, t)
            elif key == 'purge_runes':
                self._draw_purge_runes(surface, ax, ay, t)
            elif key == 'purge_roar':
                self._draw_purge_roar(surface, ax, ay, t)
            elif key == 'purge_light':
                self._draw_purge_light(surface, ax, ay, t)
            elif key == 'purge_shadow':
                self._draw_purge_shadow(surface, ax, ay, t)
 
            for p in a['particles']:
                if p['life'] > 0:
                    alpha = int(255 * max(0, p['life']))
                    sz = max(1, int(p['sz'] * max(0, p['life'])))
                    ps = pygame.Surface((sz*2, sz*2), pygame.SRCALPHA)
                    pygame.draw.circle(ps, (*p['col'], alpha), (sz, sz), sz)
                    surface.blit(ps, (int(p['x'])-sz, int(p['y'])-sz))
 
    def _draw_slash(self, surface, tx, ty, t):
        if t < 0.7:
            prog = t / 0.7
            alpha = int(255 * (1 - prog))
            for i in range(3):
                offset = (i-1)*22
                length = int(120 * prog)
                sx1 = tx - 60 + offset; sy1 = ty - 60 + offset
                sx2 = sx1 + length;     sy2 = sy1 + length
                line_surf = pygame.Surface((abs(sx2-sx1)+4, abs(sy2-sy1)+4), pygame.SRCALPHA)
                col = (220, 220, 255, alpha)
                pygame.draw.line(line_surf, col, (0,0), (abs(sx2-sx1), abs(sy2-sy1)), 4-i)
                surface.blit(line_surf, (min(sx1,sx2), min(sy1,sy2)))
            flash_alpha = int(180 * (1-prog))
            fs = pygame.Surface((100, 100), pygame.SRCALPHA)
            pygame.draw.circle(fs, (255,255,255,flash_alpha), (50,50), int(50*prog))
            surface.blit(fs, (tx-50, ty-50))
 
    def _draw_fireball(self, surface, ax, ay, tx, ty, t):
        if t < 0.55:
            prog = t / 0.55
            bx = ax + (tx - ax) * prog
            by = ay + (ty - ay) * prog
            for r in range(30, 0, -4):
                alpha = int(200 * (r/30))
                col_r = 255; col_g = int(80 + 120*(1-r/30))
                fs = pygame.Surface((r*2, r*2), pygame.SRCALPHA)
                pygame.draw.circle(fs, (col_r, col_g, 0, alpha), (r, r), r)
                surface.blit(fs, (int(bx)-r, int(by)-r))
            for i in range(6):
                trail_t = max(0, prog - i*0.06)
                tbx = ax + (tx-ax)*trail_t; tby = ay + (ty-ay)*trail_t
                ts = pygame.Surface((16,16), pygame.SRCALPHA)
                a2 = int(100 * (1-i/6))
                pygame.draw.circle(ts, (255, 120, 0, a2), (8,8), 8-i)
                surface.blit(ts, (int(tbx)-8, int(tby)-8))
        else:
            prog = (t - 0.55) / 0.45
            for r in range(int(80*(1-prog)), 0, -8):
                alpha = int(200 * (1-prog))
                es = pygame.Surface((r*2, r*2), pygame.SRCALPHA)
                pygame.draw.circle(es, (255, int(200*(1-prog)), 0, alpha), (r,r), r)
                surface.blit(es, (tx-r, ty-r))
 
    def _draw_lightning(self, surface, tx, ty, t):
        if t < 0.6:
            num_segs = 10
            sx = tx; sy = 0
            ex = tx; ey = ty
            seg_h = (ey - sy) / num_segs
            alpha = int(255 * (1 - t/0.6))
            pts = [(sx, sy)]
            for i in range(1, num_segs+1):
                jitter = random.randint(-30, 30) if i < num_segs else 0
                pts.append((sx + jitter, sy + seg_h*i))
            for i in range(len(pts)-1):
                p1, p2 = pts[i], pts[i+1]
                ls = pygame.Surface((abs(p2[0]-p1[0])+8, abs(p2[1]-p1[1])+8), pygame.SRCALPHA)
                pygame.draw.line(ls, (200, 230, 255, alpha), (0, 0), (abs(p2[0]-p1[0]), abs(p2[1]-p1[1])), 4)
                surface.blit(ls, (min(p1[0],p2[0])-2, min(p1[1],p2[1])-2))
            if t > 0.35:
                fa = int(200 * (0.6-t)/0.25)
                fs = pygame.Surface((120,120), pygame.SRCALPHA)
                pygame.draw.circle(fs, (180,210,255,fa), (60,60), 60)
                surface.blit(fs, (tx-60, ty-60))
 
    def _draw_slam(self, surface, tx, ty, t):
        if t < 0.4:
            prog = t / 0.4
            arm_top = int(ty - 250 + 250*prog)
            arm_surf = pygame.Surface((60, 260), pygame.SRCALPHA)
            alpha = int(220*(1-prog*0.3))
            pygame.draw.rect(arm_surf, (20,80,20,alpha), (10, 0, 40, 260), border_radius=8)
            pygame.draw.rect(arm_surf, (0,50,0,alpha), (0, 200, 60, 60), border_radius=6)
            surface.blit(arm_surf, (tx-30, arm_top-260))
        if t > 0.35:
            prog = (t - 0.35) / 0.65
            r = int(120 * prog)
            alpha = int(180 * (1-prog))
            ws = pygame.Surface((r*2+4, r*2+4), pygame.SRCALPHA)
            pygame.draw.circle(ws, (200,160,80,alpha), (r+2,r+2), r, 4)
            surface.blit(ws, (tx-r-2, ty-r-2))
            r2 = int(70*prog)
            ws2 = pygame.Surface((r2*2+4, r2*2+4), pygame.SRCALPHA)
            pygame.draw.circle(ws2, (255,200,100,int(alpha*0.7)), (r2+2,r2+2), r2, 3)
            surface.blit(ws2, (tx-r2-2, ty-r2-2))
 
    def _draw_plague(self, surface, ax, ay, tx, ty, t):
        if t < 0.5:
            prog = t/0.5
            bx = ax + (tx-ax)*prog; by = ay + (ty-ay)*prog
        else:
            prog = 1.0; bx = tx; by = ty
        for i in range(6):
            cx2 = bx + math.sin(t*4+i*1.1)*20
            cy2 = by + math.cos(t*3+i*0.8)*15
            r = int(35 + math.sin(t*5+i)*8)
            alpha = int(160*(1-max(0,t-0.7)/0.3))
            cs = pygame.Surface((r*2, r*2), pygame.SRCALPHA)
            pygame.draw.circle(cs, (0, 200+i*8, 30, alpha), (r,r), r)
            surface.blit(cs, (int(cx2)-r, int(cy2)-r))
        if t > 0.4:
            for i in range(4):
                bub_x = tx + math.sin(t*6+i*1.6)*30
                bub_y = ty - int(50*(t-0.4)/0.6) + i*10
                bs = pygame.Surface((14,14), pygame.SRCALPHA)
                pygame.draw.circle(bs, (0, 255, 80, int(120*(1-t))), (7,7), 7)
                surface.blit(bs, (int(bub_x)-7, int(bub_y)-7))
 
    def _draw_holybeam(self, surface, tx, ty, t):
        if t < 0.65:
            prog = t/0.65
            beam_h = int(600*prog)
            alpha = int(200*(1-t*0.6))
            bs = pygame.Surface((50, beam_h+1), pygame.SRCALPHA)
            for bx2 in range(50):
                dist_c = abs(bx2-25)/25
                a2 = int(alpha*(1-dist_c**2))
                pygame.draw.line(bs, (255,255,200,a2), (bx2,0),(bx2,beam_h))
            surface.blit(bs, (tx-25, ty-beam_h))
            hr = int(60*prog)
            hs = pygame.Surface((hr*2+4, hr*2+4), pygame.SRCALPHA)
            pygame.draw.circle(hs, (255,255,150,int(alpha*0.7)),(hr+2,hr+2),hr)
            surface.blit(hs, (tx-hr-2, ty-hr-2))
 
    def _draw_heal(self, surface, ax, ay, t):
        for i in range(3):
            delay = i * 0.2
            if t > delay:
                prog = min(1.0, (t-delay)/0.6)
                r = int(90*prog)
                alpha = int(160*(1-prog))
                hs = pygame.Surface((r*2+4,r*2+4), pygame.SRCALPHA)
                pygame.draw.circle(hs, (80,255,140,alpha),(r+2,r+2),r,3)
                surface.blit(hs, (ax-r-2, ay-r-2))
        if t < 0.7:
            alpha = int(200*(1-t/0.7))
            arm_len = int(50*t/0.7)
            for dx2,dy2 in [(arm_len,0),(-arm_len,0),(0,arm_len),(0,-arm_len)]:
                ls = pygame.Surface((abs(dx2)+4, abs(dy2)+4), pygame.SRCALPHA)
                pygame.draw.line(ls, (180,255,180,alpha),(0,0),(abs(dx2),abs(dy2)),4)
                surface.blit(ls, (ax+min(0,dx2)-2, ay+min(0,dy2)-2))
 
    def _draw_groundsmash(self, surface, tx, ty, t):
        if t < 0.35:
            prog = t/0.35
            for i in range(2):
                fist_x = tx + (i*2-1)*35
                fist_y = ty - int(180*(1-prog))
                fs2 = pygame.Surface((48,48), pygame.SRCALPHA)
                pygame.draw.ellipse(fs2, (20,80,20,220),(0,0,48,48))
                pygame.draw.ellipse(fs2, (0,50,0,180),(6,6,36,36))
                surface.blit(fs2, (fist_x-24, fist_y-24))
        if t > 0.3:
            prog = (t-0.3)/0.7
            for i in range(6):
                angle = i * (math.pi/3) + math.pi/6
                length = int(100*prog)
                ex2 = tx + math.cos(angle)*length
                ey2 = ty + math.sin(angle)*length*0.4
                alpha = int(200*(1-prog))
                ls = pygame.Surface((abs(int(ex2-tx))+4, abs(int(ey2-ty))+4), pygame.SRCALPHA)
                pygame.draw.line(ls, (180,120,40,alpha),(0,0),(abs(int(ex2-tx)),abs(int(ey2-ty))),3)
                surface.blit(ls, (min(tx,int(ex2))-2, min(ty,int(ey2))-2))
            r3 = int(140*prog)
            cs2 = pygame.Surface((r3*2+4,r3*2+4), pygame.SRCALPHA)
            pygame.draw.ellipse(cs2, (200,150,60,int(150*(1-prog))),(0,0,r3*2+4,int(r3*0.5)+4),4)
            surface.blit(cs2, (tx-r3-2, ty-int(r3*0.25)-2))
 
    def _draw_nightmare(self, surface, tx, ty, t):
        for i in range(12):
            angle = t*6 + i*(math.pi*2/12)
            r_sp = int(80*(1-t*0.5))
            spx = tx + math.cos(angle)*r_sp
            spy = ty + math.sin(angle)*r_sp*0.5
            sz2 = int(12*(1-t*0.3))
            alpha = int(180*(1-t))
            col = (random.randint(80,160), 0, random.randint(160,240))
            ss = pygame.Surface((sz2*2+2,sz2*2+2), pygame.SRCALPHA)
            pygame.draw.circle(ss, (*col, alpha), (sz2+1,sz2+1), sz2)
            surface.blit(ss, (int(spx)-sz2-1, int(spy)-sz2-1))
        if t > 0.5:
            fa2 = int(120*(t-0.5)/0.5)
            ds = pygame.Surface((160,160), pygame.SRCALPHA)
            pygame.draw.circle(ds, (40,0,80,fa2), (80,80), 80)
            surface.blit(ds, (tx-80, ty-80))
 
    def _draw_warcry(self, surface, ax, ay, tx, ty, t):
        for i in range(4):
            delay = i*0.15
            if t > delay:
                prog = min(1.0,(t-delay)/0.7)
                bx2 = ax + (tx-ax)*prog; by2 = ay + (ty-ay)*prog
                r4 = int(40*prog)
                alpha = int(180*(1-prog))
                ws3 = pygame.Surface((r4*2+4,r4*2+4), pygame.SRCALPHA)
                pygame.draw.circle(ws3,(255,80,30,alpha),(r4+2,r4+2),r4,3)
                surface.blit(ws3,(int(bx2)-r4-2,int(by2)-r4-2))
 
    def _draw_purge_shield(self, surface, ax, ay, t):
        prog = min(1.0, t*2)
        r5 = int(100*prog)
        alpha = int(200*(1-t))
        for i in range(3):
            r6 = r5 - i*15
            if r6 > 0:
                ss2 = pygame.Surface((r6*2+4,r6*2+4), pygame.SRCALPHA)
                pygame.draw.circle(ss2,(255,215,0,int(alpha*(1-i*0.3))),(r6+2,r6+2),r6,3)
                surface.blit(ss2,(ax-r6-2,ay-r6-2))
        for i in range(6):
            angle2 = t*8 + i*(math.pi/3)
            ex3 = ax+math.cos(angle2)*70; ey3 = ay+math.sin(angle2)*70
            ls2 = pygame.Surface((abs(int(ex3-ax))+4,abs(int(ey3-ay))+4), pygame.SRCALPHA)
            pygame.draw.line(ls2,(255,215,0,int(alpha*0.7)),(0,0),(abs(int(ex3-ax)),abs(int(ey3-ay))),2)
            surface.blit(ls2,(min(ax,int(ex3))-2,min(ay,int(ey3))-2))
 
    def _draw_purge_runes(self, surface, ax, ay, t):
        for i in range(8):
            angle3 = t*5 + i*(math.pi*2/8)
            r7 = 75
            rx = ax+math.cos(angle3)*r7; ry = ay+math.sin(angle3)*r7*0.6
            alpha = int(220*(1-t))
            rs = pygame.Surface((20,20), pygame.SRCALPHA)
            pygame.draw.rect(rs,(LIGHT_BLUE[0],LIGHT_BLUE[1],LIGHT_BLUE[2],alpha),(0,0,20,20),2)
            pygame.draw.line(rs,(LIGHT_BLUE[0],LIGHT_BLUE[1],LIGHT_BLUE[2],alpha),(0,10),(20,10),2)
            pygame.draw.line(rs,(LIGHT_BLUE[0],LIGHT_BLUE[1],LIGHT_BLUE[2],alpha),(10,0),(10,20),2)
            surface.blit(rs,(int(rx)-10,int(ry)-10))
 
    def _draw_purge_roar(self, surface, ax, ay, t):
        for i in range(5):
            delay2 = i*0.1
            if t > delay2:
                prog2 = min(1.0,(t-delay2)/0.6)
                r8 = int(120*prog2)
                alpha2 = int(160*(1-prog2))
                ws4 = pygame.Surface((r8*2+4,r8*2+4), pygame.SRCALPHA)
                pygame.draw.ellipse(ws4,(100,200,80,alpha2),(0,0,r8*2+4,int(r8*0.4)+4),3)
                surface.blit(ws4,(ax-r8-2,ay-int(r8*0.2)-2))
 
    def _draw_purge_light(self, surface, ax, ay, t):
        alpha3 = int(220*(1-t))
        r9 = int(130*t)
        ls3 = pygame.Surface((r9*2+4,r9*2+4), pygame.SRCALPHA)
        pygame.draw.circle(ls3,(255,255,220,int(alpha3*0.4)),(r9+2,r9+2),r9)
        pygame.draw.circle(ls3,(255,255,180,alpha3),(r9+2,r9+2),r9,4)
        surface.blit(ls3,(ax-r9-2,ay-r9-2))
        for i in range(8):
            angle4 = i*(math.pi/4)
            rl = int(110*t)
            rx2 = ax+math.cos(angle4)*rl; ry2 = ay+math.sin(angle4)*rl
            lsurf = pygame.Surface((abs(int(rx2-ax))+4,abs(int(ry2-ay))+4), pygame.SRCALPHA)
            pygame.draw.line(lsurf,(255,255,180,int(alpha3*0.8)),(0,0),(abs(int(rx2-ax)),abs(int(ry2-ay))),3)
            surface.blit(lsurf,(min(ax,int(rx2))-2,min(ay,int(ry2))-2))
 
    def _draw_purge_shadow(self, surface, ax, ay, t):
        for i in range(10):
            angle5 = t*(-4) + i*(math.pi*2/10)
            r10 = int(90*(1-t*0.4))
            spx2 = ax+math.cos(angle5)*r10; spy2 = ay+math.sin(angle5)*r10*0.5
            alpha4 = int(200*(1-t))
            ss3 = pygame.Surface((22,22), pygame.SRCALPHA)
            pygame.draw.circle(ss3,(40,0,60,alpha4),(11,11),11)
            surface.blit(ss3,(int(spx2)-11,int(spy2)-11))
        if t < 0.5:
            prog3 = t/0.5
            rs2 = int(40*prog3)
            bs2 = pygame.Surface((rs2*2+4,rs2*2+4), pygame.SRCALPHA)
            pygame.draw.circle(bs2,(0,0,0,int(200*prog3)),(rs2+2,rs2+2),rs2)
            surface.blit(bs2,(ax-rs2-2,ay-rs2-2))
 
 
anim_manager = AnimationManager()
 
 
# --- BACKGROUND BRAWLHALLA ---
class BrawlhallaBackground:
    def __init__(self):
        self.time = 0
        self.particles = []
        for _ in range(45):
            self.particles.append({
                'x': random.randint(0, WIDTH),
                'y': random.randint(0, HEIGHT),
                'vy': random.uniform(-0.3, -0.8),
                'size': random.randint(1, 3),
                'alpha': random.randint(80, 200),
            })
 
    def draw(self, surface):
        self.time += 1
        surface.fill(BW_BG)
 
        moon_surf = pygame.Surface((320, 320), pygame.SRCALPHA)
        for r in range(150, 0, -1):
            alpha = int(28*(r/150))
            pygame.draw.circle(moon_surf, (120,100,180,alpha), (160,160), r)
        surface.blit(moon_surf, (WIDTH//2-160, -70))
 
        floor_y = int(HEIGHT*0.70)
        for i in range(0, WIDTH, 40):
            shade = 30 + (i%80==0)*10
            pygame.draw.rect(surface, (shade,24,50), (i, floor_y, 40, HEIGHT-floor_y))
        pygame.draw.rect(surface, BW_BORDER, (0, floor_y, WIDTH, 3))
        pygame.draw.rect(surface, (80,60,20), (0, floor_y+3, WIDTH, 2))
 
        pillar_positions = [int(WIDTH*0.07), int(WIDTH*0.27), int(WIDTH*0.73), int(WIDTH*0.93)]
        for px in pillar_positions:
            pygame.draw.rect(surface, (45,35,70), (px-18, int(HEIGHT*0.22), 36, floor_y-int(HEIGHT*0.22)))
            for cy in range(int(HEIGHT*0.24), floor_y-10, 30):
                pygame.draw.rect(surface, (55,42,85), (px-16, cy, 32, 4))
            pygame.draw.rect(surface, (65,50,95), (px-24, int(HEIGHT*0.215), 48, 15))
            pygame.draw.rect(surface, BW_BORDER2, (px-24, int(HEIGHT*0.215), 48, 3))
            pygame.draw.rect(surface, (65,50,95), (px-24, floor_y-15, 48, 15))
 
        torch_positions = [int(WIDTH*0.13), int(WIDTH*0.87)]
        flicker = math.sin(self.time*0.15)*0.3
        for tx in torch_positions:
            pygame.draw.rect(surface, (90,70,30), (tx-3, floor_y-100, 6, 60))
            pygame.draw.rect(surface, (120,90,40), (tx-8, floor_y-115, 16, 20))
            for layer in range(3):
                offset = math.sin(self.time*0.2+layer*1.5)*6
                flame_h = int(35+flicker*15+layer*5)
                flame_col = [BW_TORCH,(255,180,30),(255,230,100)][layer]
                flame_surf = pygame.Surface((20,flame_h), pygame.SRCALPHA)
                for fy in range(flame_h):
                    a2 = int(220*(1-fy/flame_h)); w2 = int(10*(1-fy/flame_h)+3)
                    pygame.draw.rect(flame_surf, (*flame_col,a2), (10-w2//2, fy, w2, 1))
                surface.blit(flame_surf, (tx-10+offset, floor_y-115-flame_h+10))
            halo_surf = pygame.Surface((130,130), pygame.SRCALPHA)
            glow_r = int(55+flicker*10)
            for r in range(glow_r, 0, -2):
                pygame.draw.circle(halo_surf, (255,160,40,int(22*(r/glow_r))), (65,65), r)
            surface.blit(halo_surf, (tx-65, floor_y-155))
 
        for wx in [int(WIDTH*0.20), int(WIDTH*0.50), int(WIDTH*0.80)]:
            pygame.draw.rect(surface, (25,18,45), (wx-25, int(HEIGHT*0.28), 50, 80))
            pygame.draw.arc(surface, (25,18,45), (wx-25, int(HEIGHT*0.24), 50, 60), 0, math.pi, 5)
            glow = pygame.Surface((40,70), pygame.SRCALPHA)
            for r in range(20, 0, -1):
                pygame.draw.ellipse(glow, (40,80,160,int(15*(r/20))), (20-r,35-r,r*2,r*2))
            surface.blit(glow, (wx-20, int(HEIGHT*0.29)))
            pygame.draw.rect(surface, BW_ACCENT, (wx-25, int(HEIGHT*0.28), 50, 80), 2)
            pygame.draw.arc(surface, BW_ACCENT, (wx-25, int(HEIGHT*0.24), 50, 60), 0, math.pi, 2)
 
        for i in range(10):
            fog_x = (self.time*0.4+i*130)%(WIDTH+200)-100
            fog_surf = pygame.Surface((220,60), pygame.SRCALPHA)
            for r in range(30, 0, -3):
                pygame.draw.ellipse(fog_surf, (100,80,150,int(16*(r/30))), (110-r*3,30-r,r*6,r*2))
            surface.blit(fog_surf, (fog_x, floor_y-30))
 
        for p in self.particles:
            p['y'] += p['vy']
            p['x'] += math.sin(self.time*0.02+p['y']*0.01)*0.3
            if p['y'] < -5: p['y']=HEIGHT+5; p['x']=random.randint(0,WIDTH)
            ps = pygame.Surface((p['size']*2,p['size']*2), pygame.SRCALPHA)
            pygame.draw.circle(ps, (200,160,255,p['alpha']), (p['size'],p['size']), p['size'])
            surface.blit(ps, (p['x'], p['y']))
 
bg = BrawlhallaBackground()
 
 
# --- UI HELPERS ---
def draw_panel(surface, x, y, w, h, title=None, title_color=None, glow_col=None):
    panel = pygame.Surface((w, h), pygame.SRCALPHA)
    panel.fill((18, 13, 35, 220))
    surface.blit(panel, (x, y))
 
    if glow_col:
        hs = pygame.Surface((w+20, h+20), pygame.SRCALPHA)
        pygame.draw.rect(hs, (*glow_col, 30), (0, 0, w+20, h+20), border_radius=6)
        surface.blit(hs, (x-10, y-10))
 
    pygame.draw.rect(surface, BW_BORDER, (x, y, w, h), 3)
    pygame.draw.rect(surface, BW_BORDER2, (x+4, y+4, w-8, h-8), 1)
    pygame.draw.rect(surface, (*BW_BORDER, 80), (x+6, y+6, w-12, 1))
 
    corner_size = 18
    for cx2, cy2 in [(x,y),(x+w-corner_size,y),(x,y+h-corner_size),(x+w-corner_size,y+h-corner_size)]:
        pygame.draw.rect(surface, BW_BORDER2, (cx2, cy2, corner_size, corner_size))
        pygame.draw.rect(surface, GOLD, (cx2+1, cy2+1, corner_size-2, corner_size-2))
        mid = corner_size//2
        pts = [(cx2+mid, cy2+2), (cx2+corner_size-2, cy2+mid), (cx2+mid, cy2+corner_size-2), (cx2+2, cy2+mid)]
        pygame.draw.polygon(surface, BW_BORDER2, pts)
        pygame.draw.polygon(surface, (255,200,60), pts, 1)
        pygame.draw.circle(surface, BW_BORDER2, (cx2+mid, cy2+mid), 3)
        pygame.draw.circle(surface, GOLD, (cx2+mid, cy2+mid), 2)
 
    for bx2 in range(x+corner_size+10, x+w-corner_size-10, 22):
        pygame.draw.rect(surface, BW_BORDER, (bx2, y, 4, 3))
        pygame.draw.rect(surface, BW_BORDER, (bx2, y+h-3, 4, 3))
    for by2 in range(y+corner_size+10, y+h-corner_size-10, 22):
        pygame.draw.rect(surface, BW_BORDER, (x, by2, 3, 4))
        pygame.draw.rect(surface, BW_BORDER, (x+w-3, by2, 3, 4))
 
    if title:
        tw = font_small.size(title)[0]
        bx3 = x + w//2 - tw//2 - 12
        bw3 = tw + 24
        pygame.draw.rect(surface, BW_BORDER2, (bx3-3, y-13, bw3+6, 24))
        pygame.draw.rect(surface, (40,28,8), (bx3, y-12, bw3, 22))
        pygame.draw.rect(surface, BW_BORDER, (bx3, y-12, bw3, 22), 2)
        for bdx2 in [bx3-3, bx3+bw3-1]:
            pygame.draw.polygon(surface, GOLD, [(bdx2,y),(bdx2+6,y-6),(bdx2+12,y),(bdx2+6,y+6)])
        col = title_color or GOLD
        draw_text_outline(surface, title, font_small, col, x+w//2-tw//2, y-10)
 
 
def draw_bar(surface, x, y, w, h, val, max_val, col_fill, col_bg=(30,20,50)):
    pygame.draw.rect(surface, col_bg, (x, y, w, h), border_radius=4)
    fill_w = int(w * max(0, val) / max_val)
    if fill_w > 0:
        pygame.draw.rect(surface, col_fill, (x, y, fill_w, h), border_radius=4)
        pygame.draw.rect(surface, tuple(min(255,c+70) for c in col_fill), (x+2, y+2, fill_w-4, h//3), border_radius=3)
        pygame.draw.rect(surface, tuple(max(0,c-40) for c in col_fill), (x+2, y+h-h//4-1, fill_w-4, h//4), border_radius=2)
    pygame.draw.rect(surface, BW_BORDER, (x, y, w, h), 2, border_radius=4)
    pygame.draw.rect(surface, BW_BORDER2, (x+1, y+1, w-2, h-2), 1, border_radius=3)
 
 
def draw_text_outline(surface, text, font, col, x, y):
    shadow = font.render(text, True, (0,0,0))
    for dx2, dy2 in [(-1,-1),(1,-1),(-1,1),(1,1),(-2,0),(2,0),(0,-2),(0,2)]:
        surface.blit(shadow, (x+dx2, y+dy2))
    surface.blit(font.render(text, True, col), (x, y))
 
 
# --- JEU ---
class Game:
    def __init__(self):
        self.classes = [Chevalier, Magicien, Ogre, Pretre, Necro]
        self.class_descs = {
            "Chevalier": "⚔  Robuste guerrier en armure.\nForce brute et détermination de fer.\nResiste aux états avec Détermination.\nIdéal pour les joueurs agressifs.",
            "Magicien":  "✦  Maître des arcanes dévastateurs.\nFragile mais d'une puissance terrible.\nSes sorts électrisent et brûlent tout.\nPour les joueurs aimant le burst.",
            "Ogre":      "💪  Colosse brutal et indestructible.\nLe plus de PV de l'arène de loin.\nSes coups font vibrer le sol lui-même.\nPour les joueurs aimant tenir longtemps.",
            "Pretre":    "✝  Gardien sacré de la lumière divine.\nSe soigne en plein combat grâce à Soin.\nPunit les âmes impures de son rayon.\nPour les joueurs patients et tactiques.",
            "Necro":     "☠  Seigneur des ombres et des âmes.\nSes miasmes font des dégâts variables.\nCauchemar peut décider d'un combat.\nPour les joueurs aimant le chaos pur.",
        }
        self.state = "SELECT_P1"; self.sel_idx = 0
        self.p1 = None; self.p2 = None
        self.turn = None; self.target = None
        self.msg = ""; self.menu_idx = 0; self.anim_timer = 0
        self.tick = 0
        self.last_damage = 0
        self.show_credits = False
 
    def get_sprite_rect(self, char, base_x, base_y, scale=19):
        data = SPRITE_DATA[char.sprite_key][0]
        w = len(data[0]) * scale
        h = len(data) * scale
        return (base_x, base_y, w, h)
 
    def draw_sprite(self, char, x, y, scale=19):
        ox = x + random.randint(-char.shake, char.shake)
        oy = y + random.randint(-char.shake//2, char.shake//2)
        data, cols = SPRITE_DATA[char.sprite_key]
        for r, row in enumerate(data):
            for c, val in enumerate(row):
                if val != 0:
                    pygame.draw.rect(screen, cols[val], (ox+c*scale, oy+r*scale, scale, scale))
        if char.etat_actuel:
            p_col = PURPLE if char.etat_actuel=="Peur" else (0,255,255) if char.etat_actuel=="Paralysé" else YELLOW
            for _ in range(5):
                px2 = ox+random.randint(0, 11*scale)
                py2 = oy+random.randint(0, len(data)*scale)
                ps = pygame.Surface((8,8), pygame.SRCALPHA)
                pygame.draw.rect(ps, (*p_col,180), (0,0,8,8))
                screen.blit(ps, (px2, py2))
 
    def draw_hud(self, char, x, y):
        W = int(WIDTH*0.38); H = int(HEIGHT*0.195)
        draw_panel(screen, x, y, W, H, char.nom.upper())
        bw = int(W*0.68); bx = x+int(W*0.045)
 
        hp_pct = char.hp / char.hp_max
        bar_col = BW_GREEN if hp_pct>0.5 else YELLOW if hp_pct>0.25 else BW_RED
        screen.blit(font_tiny.render("❤ PV", True, BW_TEXT), (bx, y+int(H*0.17)))
        draw_bar(screen, bx, y+int(H*0.30), bw, int(H*0.16), char.hp, char.hp_max, bar_col)
        hp_txt = f"{max(0,char.hp)} / {char.hp_max}"
        screen.blit(font_small.render(hp_txt, True, WHITE), (bx+bw+8, y+int(H*0.29)))
 
        screen.blit(font_tiny.render("✦ MANA", True, BW_TEXT), (bx, y+int(H*0.52)))
        draw_bar(screen, bx, y+int(H*0.63), int(bw*0.65), int(H*0.12), char.mp, char.mp_max, BW_BLUE)
        mp_txt = f"{char.mp} / {char.mp_max}"
        screen.blit(font_tiny.render(mp_txt, True, LIGHT_BLUE), (bx+int(bw*0.65)+8, y+int(H*0.63)))
 
        if char.etat_actuel:
            etat_col = (255,80,80) if char.etat_actuel=="Peur" else (80,255,255) if char.etat_actuel=="Paralysé" else YELLOW
            draw_panel(screen, bx, y+int(H*0.78), int(W*0.55), int(H*0.17))
            screen.blit(font_tiny.render(f"⚠ {char.etat_actuel.upper()} — perd le prochain tour", True, etat_col), (bx+8, y+int(H*0.80)))
 
    def draw_action_menu(self, acts):
        MX = int(WIDTH*0.03); MY = int(HEIGHT*0.74)
        MW = int(WIDTH*0.56); MH = int(HEIGHT*0.24)
        draw_panel(screen, MX, MY, MW, MH, "◆ CHOISIR UNE ACTION ◆")
 
        act = acts[self.menu_idx]
        item_h = (MH-30)//len(acts)
        for i, a in enumerate(acts):
            is_sel = i == self.menu_idx
            item_y = MY + 28 + i*item_h
            if is_sel:
                sel = pygame.Surface((MW-22, item_h-4), pygame.SRCALPHA)
                sel.fill((255,200,50,35))
                screen.blit(sel, (MX+11, item_y))
                pygame.draw.rect(screen, BW_BORDER, (MX+11, item_y, MW-22, item_h-4), 2)
 
            arrow = "► " if is_sel else "  "
            nc = GOLD if is_sel else BW_TEXT
            draw_text_outline(screen, arrow+a['nom'], font_med, nc, MX+20, item_y+6)
            mp_col = LIGHT_BLUE if a['cout']>0 else (100,100,100)
            mp_t = f"[{a['cout']} MP]" if a['cout']>0 else "[Gratuit]"
            screen.blit(font_tiny.render(mp_t, True, mp_col), (MX+int(MW*0.42), item_y+9))
            dc = (255,160,80) if a['degats']!="--" else (100,100,100)
            screen.blit(font_tiny.render(a['degats'], True, dc), (MX+int(MW*0.65), item_y+9))
 
        # Panneau description — séparé en 2 zones
        DX = MX+MW+int(WIDTH*0.01); DY = MY
        DW = WIDTH - DX - int(WIDTH*0.02); DH = MH
        draw_panel(screen, DX, DY, DW, DH, "◆ DESCRIPTION ◆")
 
        # Zone 1 : flavour (italique / doré)
        desc_lines = act['desc'].split('\n')
        for li, line in enumerate(desc_lines[:2]):
            draw_text_outline(screen, line, font_small, (220, 200, 140), DX+14, DY+28+li*int(DH*0.145))
 
        # Séparateur
        sep_y = DY + int(DH*0.34)
        pygame.draw.rect(screen, BW_BORDER2, (DX+10, sep_y, DW-20, 1))
        pygame.draw.rect(screen, (*BW_BORDER, 60), (DX+10, sep_y+1, DW-20, 1))
 
        # Zone 2 : mécanique (couleur distincte, claire)
        mec_lines = act['mecanique'].split('\n')
        for li, line in enumerate(mec_lines[:4]):
            # Première ligne = effet principal (blanc brillant)
            col = WHITE if li == 0 else (160, 200, 255)
            screen.blit(font_small.render(line, True, col), (DX+14, sep_y+8+li*int(DH*0.155)))
 
    def draw_select_screen(self):
        txt = "JOUEUR 1" if "P1" in self.state else "JOUEUR 2"
        col = (100,200,255) if "P1" in self.state else (255,150,80)
        draw_panel(screen, int(WIDTH*0.04), int(HEIGHT*0.04), int(WIDTH*0.92), int(HEIGHT*0.085), "◆ ARÈNE DES LÉGENDES ◆")
        label = f"{txt} — CHOISIS TON CHAMPION"
        tw = font_big.size(label)[0]
        draw_text_outline(screen, label, font_big, col, WIDTH//2-tw//2, int(HEIGHT*0.062))
 
        LX = int(WIDTH*0.04); LY = int(HEIGHT*0.16)
        LW = int(WIDTH*0.28); LH = int(HEIGHT*0.60)
        draw_panel(screen, LX, LY, LW, LH, "CHAMPIONS")
        item_h = (LH-30)//len(self.classes)
        for i, cl in enumerate(self.classes):
            is_sel = i==self.sel_idx
            iy = LY+28+i*item_h
            if is_sel:
                sh = pygame.Surface((LW-22, item_h-4), pygame.SRCALPHA)
                sh.fill((255,200,50,45)); screen.blit(sh, (LX+11, iy))
                pygame.draw.rect(screen, BW_BORDER, (LX+11, iy, LW-22, item_h-4), 2)
            arrow = "► " if is_sel else "  "
            ccol = GOLD if is_sel else BW_TEXT
            draw_text_outline(screen, arrow+cl.__name__.upper(), font_med, ccol, LX+22, iy+10)
 
        cl = self.classes[self.sel_idx]
        PX = LX+LW+int(WIDTH*0.015); PY = LY
        PW = WIDTH-PX-int(WIDTH*0.04); PH = int(HEIGHT*0.38)
        draw_panel(screen, PX, PY, PW, PH, "PROFIL")
        dummy = cl("?"); dummy.shake=0
        self.draw_sprite(dummy, PX+PW-int(PW*0.3), PY+int(PH*0.12), scale=16)
        desc = self.class_descs.get(cl.__name__,"")
        for li, line in enumerate(desc.split("\n")):
            screen.blit(font_small.render(line, True, BW_TEXT), (PX+16, PY+28+li*int(PH*0.16)))
 
        SX = PX; SY = PY+PH+int(HEIGHT*0.015)
        SW2 = PW; SH = int(HEIGHT*0.18)
        draw_panel(screen, SX, SY, SW2, SH, "STATISTIQUES")
        dummy2 = cl("?")
        stats = [("PV MAX", dummy2.hp_max, 300, BW_GREEN),
                 ("MANA MAX", dummy2.mp_max, 180, BW_BLUE),
                 ("FORCE", int(dummy2.force*100), 200, (255,180,50))]
        for si, (lbl, val, maxv, sc) in enumerate(stats):
            ssx = SX+16+si*int(SW2*0.33)
            screen.blit(font_tiny.render(lbl, True, BW_TEXT), (ssx, SY+28))
            draw_bar(screen, ssx, SY+50, int(SW2*0.29), 16, val, maxv, sc)
            screen.blit(font_tiny.render(str(val), True, WHITE), (ssx+int(SW2*0.29)+6, SY+50))
 
        draw_panel(screen, LX, LY+LH+int(HEIGHT*0.015), LW, int(HEIGHT*0.085), "CONTRÔLES")
        ctrl = "↑↓ Naviguer  •  ENTRÉE Valider  •  ESC Quitter"
        tw2 = font_small.size(ctrl)[0]
        screen.blit(font_small.render(ctrl, True, BW_TEXT), (LX+(LW-tw2)//2, LY+LH+int(HEIGHT*0.04)))
        # Hint crédits
        hint = "[ C ] Crédits"
        htw = font_tiny.size(hint)[0]
        screen.blit(font_tiny.render(hint, True, (120,100,80)), (LX+(LW-htw)//2, LY+LH+int(HEIGHT*0.072)))
 
    def execute_move(self, act):
        p1_rect = self.get_sprite_rect(self.p1, int(WIDTH*0.09), int(HEIGHT*0.42))
        p2_rect = self.get_sprite_rect(self.p2, int(WIDTH*0.58), int(HEIGHT*0.40))
        att_rect = p1_rect if self.turn is self.p1 else p2_rect
        tgt_rect = p2_rect if self.turn is self.p1 else p1_rect
 
        if self.turn.etat_actuel in ["Paralysé","Assommé","Peur"] and act['type']!="purge":
            self.msg = f"{self.turn.nom} est figé sur place ! L'état se dissipe enfin..."
            self.turn.etat_actuel = None
            anim_manager.play('purge_shield', att_rect, att_rect)
        else:
            self.turn.mp -= act['cout']
            anim_manager.play(act.get('anim','slash'), att_rect, tgt_rect)
            if act['type']=="purge":
                self.msg = f"{self.turn.nom} brise ses entraves — l'âme est libre à nouveau !"
                self.turn.etat_actuel = None
            elif act['type']=="recuperer":
                gain = act.get('val_mp', 0)
                self.turn.mp = min(self.turn.mp_max, self.turn.mp + gain)
                self.msg = f"{self.turn.nom} récupère {gain} mana."
            elif act['type']=="parer":
                self.turn.bloque = True
                self.msg = f"{self.turn.nom} se prépare à parer le prochain coup !"
            elif act['type']=="dmg":
                v=act['val'].split('-'); d=random.randint(int(v[0]),int(v[1]))
                if self.target.bloque:
                    d = d // 2
                    self.target.bloque = False
                    self.msg = f"{act['nom']} — {self.target.nom} pare et subit seulement {d} dégâts !"
                else:
                    self.msg = f"{act['nom']} — {self.target.nom} subit {d} points de dégâts !"
                self.target.hp-=d; self.target.shake=22; self.last_damage=d
            elif act['type']=="spec":
                if self.target.bloque:
                    self.target.bloque = False
                    self.msg = f"{act['nom']} — {self.target.nom} dévie l'effet !"
                elif random.randint(1,100)<=act['chance']:
                    self.target.etat_actuel=act['proc']
                    self.msg = f"{act['nom']} fait effet ! {self.target.nom} est {act['proc']} !"
                else:
                    self.msg = f"{act['nom']} — {self.target.nom} résiste à l'effet !"
            elif act['type']=="soin":
                self.turn.hp=min(self.turn.hp_max,self.turn.hp+act['val'])
                self.msg = f"{self.turn.nom} récupère {act['val']} PV dans un halo de lumière !"
        self.state="ANIM"; self.anim_timer=pygame.time.get_ticks()
 
    def draw_result_panel(self):
        draw_panel(screen, int(WIDTH*0.03), int(HEIGHT*0.745), int(WIDTH*0.94), int(HEIGHT*0.23), "◆ RÉSULTAT ◆")
        tw2 = font_big.size(self.msg)[0]
        max_w = int(WIDTH*0.88)
        msg_x = int(WIDTH*0.06) + max(0, max_w-tw2)//2
        draw_text_outline(screen, self.msg[:70], font_big, GOLD, msg_x, int(HEIGHT*0.80))
        dots = "." * (1 + (self.tick//20)%3)
        screen.blit(font_small.render(f"Prochain tour{dots}", True, BW_TEXT), (int(WIDTH*0.44), int(HEIGHT*0.89)))
 
    def draw_battle(self):
        acts = self.turn.get_actions()
        self.draw_sprite(self.p1, int(WIDTH*0.09), int(HEIGHT*0.42))
        self.draw_sprite(self.p2, int(WIDTH*0.58), int(HEIGHT*0.40))
        anim_manager.draw(screen)
        self.draw_hud(self.p1, int(WIDTH*0.02), int(HEIGHT*0.02))
        self.draw_hud(self.p2, int(WIDTH*0.60), int(HEIGHT*0.02))
        turn_txt = f"TOUR DE {self.turn.nom.upper()}"
        tw = font_small.size(turn_txt)[0]
        draw_panel(screen, WIDTH//2-tw//2-14, int(HEIGHT*0.235), tw+28, int(HEIGHT*0.048))
        draw_text_outline(screen, turn_txt, font_small, GOLD, WIDTH//2-tw//2, int(HEIGHT*0.244))
        if self.state=="BATTLE":
            self.draw_action_menu(acts)
        else:
            self.draw_result_panel()
 
    def draw_game_over(self, winner):
        draw_panel(screen, int(WIDTH*0.22), int(HEIGHT*0.32), int(WIDTH*0.56), int(HEIGHT*0.26), "◆ VICTOIRE ! ◆", glow_col=GOLD)
        txt = f"⚔  {winner.nom}  TRIOMPHE !"
        tw = font_title.size(txt)[0]
        draw_text_outline(screen, txt, font_title, GOLD, WIDTH//2-tw//2, int(HEIGHT*0.40))
        sub = "Appuyez sur ENTRÉE pour quitter"
        ts = font_med.size(sub)[0]
        screen.blit(font_med.render(sub, True, BW_TEXT), (WIDTH//2-ts//2, int(HEIGHT*0.52)))
 
    def draw_credits(self):
        # Overlay semi-transparent
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((8, 5, 20, 210))
        screen.blit(overlay, (0, 0))
 
        CW = int(WIDTH*0.52); CH = int(HEIGHT*0.52)
        CX = WIDTH//2 - CW//2; CY = HEIGHT//2 - CH//2
        draw_panel(screen, CX, CY, CW, CH, "◆ CRÉDITS ◆", glow_col=GOLD)
 
        # Titre du jeu
        title_txt = "DUEL DE LÉGENDES"
        tw = font_title.size(title_txt)[0]
        draw_text_outline(screen, title_txt, font_title, GOLD, WIDTH//2 - tw//2, CY + int(CH*0.10))
 
        subtitle = "Arena Edition"
        sw = font_med.size(subtitle)[0]
        screen.blit(font_med.render(subtitle, True, BW_TEXT), (WIDTH//2 - sw//2, CY + int(CH*0.24)))
 
        # Séparateur
        pygame.draw.rect(screen, BW_BORDER, (CX+30, CY+int(CH*0.35), CW-60, 2))
        pygame.draw.rect(screen, BW_BORDER2, (CX+30, CY+int(CH*0.35)+2, CW-60, 1))
 
        # Auteurs
        par_txt = "Un jeu créé par"
        ptw = font_small.size(par_txt)[0]
        screen.blit(font_small.render(par_txt, True, BW_TEXT), (WIDTH//2 - ptw//2, CY + int(CH*0.42)))
 
        names = ["Jules MAROUVIN", "Dany GRAUWELS"]
        for i, name in enumerate(names):
            ntw = font_big.size(name)[0]
            draw_text_outline(screen, name, font_big, (255, 220, 100), WIDTH//2 - ntw//2, CY + int(CH*0.52) + i*int(CH*0.14))
 
        # Séparateur
        pygame.draw.rect(screen, BW_BORDER2, (CX+60, CY+int(CH*0.82), CW-120, 1))
 
        # Claude
        with_txt = "avec"
        wtw = font_small.size(with_txt)[0]
        screen.blit(font_small.render(with_txt, True, BW_TEXT), (WIDTH//2 - wtw//2, CY + int(CH*0.85)))
        claude_txt = "Claude (Anthropic)"
        ctw = font_med.size(claude_txt)[0]
        draw_text_outline(screen, claude_txt, font_med, LIGHT_BLUE, WIDTH//2 - ctw//2, CY + int(CH*0.91))
 
        # Fermer
        hint = "[ C ] Fermer"
        htw = font_tiny.size(hint)[0]
        screen.blit(font_tiny.render(hint, True, (120,100,80)), (WIDTH//2 - htw//2, CY + CH - int(CH*0.07)))
 
    def draw(self):
        bg.draw(screen)
        if "SELECT" in self.state:
            self.draw_select_screen()
        elif self.state in ["BATTLE","ANIM"]:
            if self.p1.hp<=0 or self.p2.hp<=0:
                self.draw_battle()
                self.draw_game_over(self.p2 if self.p1.hp<=0 else self.p1)
            else:
                self.draw_battle()
        if self.show_credits:
            self.draw_credits()
        pygame.display.flip()
 
    def handle_events(self):
        for event in pygame.event.get():
            if event.type==pygame.QUIT: pygame.quit(); sys.exit()
            if event.type==pygame.KEYDOWN:
                if event.key==pygame.K_ESCAPE: pygame.quit(); sys.exit()
                if event.key==pygame.K_c: self.show_credits = not self.show_credits
                if "SELECT" in self.state:
                    if event.key==pygame.K_UP:   self.sel_idx=(self.sel_idx-1)%len(self.classes)
                    if event.key==pygame.K_DOWN:  self.sel_idx=(self.sel_idx+1)%len(self.classes)
                    if event.key==pygame.K_RETURN:
                        c=self.classes[self.sel_idx]("J1" if "P1" in self.state else "J2")
                        if "P1" in self.state: self.p1=c; self.state="SELECT_P2"; self.sel_idx=0
                        else: self.p2=c; self.state="BATTLE"; self.turn,self.target=self.p1,self.p2; self.menu_idx=0
                elif self.state=="BATTLE":
                    acts=self.turn.get_actions()
                    if event.key==pygame.K_UP:    self.menu_idx=(self.menu_idx-1)%len(acts)
                    if event.key==pygame.K_DOWN:  self.menu_idx=(self.menu_idx+1)%len(acts)
                    if event.key==pygame.K_RETURN: self.execute_move(acts[self.menu_idx])
                if (self.p1 and self.p2) and (self.p1.hp<=0 or self.p2.hp<=0):
                    if event.key==pygame.K_RETURN: pygame.quit(); sys.exit()
 
    def update(self):
        self.tick += 1
        dt = clock.get_time()/1000.0
        anim_manager.update(dt)
        if self.state=="ANIM" and pygame.time.get_ticks()-self.anim_timer>2200:
            if self.p1.hp>0 and self.p2.hp>0:
                self.p1.shake=self.p2.shake=0
                self.turn,self.target=self.target,self.turn
                self.state="BATTLE"; self.menu_idx=0
 
    def run(self):
        while True:
            self.handle_events(); self.update(); self.draw(); clock.tick(FPS)
 
if __name__=="__main__":
    Game().run()





