"""
Dragon Rider Adventure - A side-scrolling flight adventure game made with Pygame.
All graphics are procedurally drawn with Python/Pygame. No external assets needed.
"""

import pygame
import sys
import random
import math
import os

# --- Init ---
pygame.init()
pygame.mixer.init()

# --- Screen ---
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Dragon Rider Adventure")

# --- Colors ---
SKY_TOP    = (25, 25, 112)
SKY_MID    = (70, 130, 180)
SKY_BOT    = (135, 206, 235)
WHITE      = (255, 255, 255)
BLACK      = (0, 0, 0)
RED        = (220, 50, 50)
GOLD       = (255, 215, 0)
GREEN      = (50, 200, 50)
PURPLE     = (150, 50, 200)
ORANGE     = (255, 140, 0)
DARK_RED   = (180, 30, 30)
BROWN      = (139, 69, 19)
DARK_BROWN = (101, 67, 33)
GRAY       = (128, 128, 128)
LIGHT_GRAY = (200, 200, 200)
DARK_GRAY  = (80, 80, 80)
FIRE_ORANGE= (255, 100, 0)
FIRE_YELLOW= (255, 200, 0)
DRAGON_GREEN = (34, 139, 34)
DRAGON_DARK  = (0, 100, 0)
ARMOR      = (192, 192, 192)
BLUE       = (50, 50, 200)
CYAN       = (100, 200, 255)
MAGENTA    = (255, 100, 255)
YELLOW     = (255, 255, 0)

# --- Fonts (default font supports ASCII only) ---
font_small  = pygame.font.Font(None, 24)
font_medium = pygame.font.Font(None, 36)
font_large  = pygame.font.Font(None, 56)
font_title  = pygame.font.Font(None, 72)
font_huge   = pygame.font.Font(None, 100)

# --- Clock ---
clock = pygame.time.Clock()
FPS = 60


# ==================== Utility ====================

def draw_gradient_sky(surface, offset=0):
    for y in range(SCREEN_HEIGHT):
        ratio = y / SCREEN_HEIGHT
        if ratio < 0.33:
            r = int(SKY_TOP[0] + (SKY_MID[0] - SKY_TOP[0]) * ratio * 3)
            g = int(SKY_TOP[1] + (SKY_MID[1] - SKY_TOP[1]) * ratio * 3)
            b = int(SKY_TOP[2] + (SKY_MID[2] - SKY_TOP[2]) * ratio * 3)
        elif ratio < 0.66:
            local = (ratio - 0.33) / 0.33
            r = int(SKY_MID[0] + (SKY_BOT[0] - SKY_MID[0]) * local)
            g = int(SKY_MID[1] + (SKY_BOT[1] - SKY_MID[1]) * local)
            b = int(SKY_MID[2] + (SKY_BOT[2] - SKY_MID[2]) * local)
        else:
            local = (ratio - 0.66) / 0.34
            r = int(SKY_BOT[0] + (200 - SKY_BOT[0]) * local)
            g = int(SKY_BOT[1] + (230 - SKY_BOT[1]) * local)
            b = int(SKY_BOT[2] + (255 - SKY_BOT[2]) * local)
        pygame.draw.line(surface, (r, g, b), (0, y), (SCREEN_WIDTH, y))

def create_cloud_surface(width, height):
    surf = pygame.Surface((width, height), pygame.SRCALPHA)
    circles = [
        (width//4, height//2, height//3),
        (width//2, height//2 - 5, height//2.5),
        (3*width//4, height//2, height//3),
        (width//3, height//2 + 5, height//4),
        (2*width//3, height//2 + 5, height//4),
    ]
    for cx, cy, r in circles:
        pygame.draw.circle(surf, (255, 255, 255, 200), (cx, cy), r)
    return surf


# ==================== Particle System ====================

class Particle:
    def __init__(self, x, y, color, speed_x, speed_y, life, size=3):
        self.x = x; self.y = y; self.color = color
        self.speed_x = speed_x; self.speed_y = speed_y
        self.life = life; self.max_life = life; self.size = size

    def update(self):
        self.x += self.speed_x
        self.y += self.speed_y
        self.life -= 1
        self.size = max(1, self.size * 0.98)

    def draw(self, surface):
        alpha = int(255 * (self.life / self.max_life))
        c = (*self.color[:3], alpha) if len(self.color) > 3 else self.color
        try:
            pygame.draw.circle(surface, c, (int(self.x), int(self.y)), int(self.size))
        except:
            pass

class ParticleSystem:
    def __init__(self):
        self.particles = []

    def emit(self, x, y, color, count=5, spread=2, speed_range=(1,3), life_range=(20,40), size_range=(2,5)):
        for _ in range(count):
            a = random.uniform(0, math.pi*2)
            s = random.uniform(*speed_range)
            self.particles.append(Particle(x, y, color,
                math.cos(a)*s*spread, math.sin(a)*s*spread,
                random.randint(*life_range), random.uniform(*size_range)))

    def emit_fire(self, x, y):
        colors = [(255,100,0),(255,150,0),(255,200,0),(255,50,0)]
        for _ in range(3):
            self.particles.append(Particle(x, y, random.choice(colors),
                random.uniform(-3,-1), random.uniform(-1,1),
                random.randint(15,30), random.uniform(3,7)))

    def update(self):
        for p in self.particles[:]:
            p.update()
            if p.life <= 0:
                self.particles.remove(p)

    def draw(self, surface):
        for p in self.particles:
            p.draw(surface)


# ==================== Dragon ====================

class Dragon:
    def __init__(self, x, y):
        self.x = x; self.y = y
        self.width = 120; self.height = 70
        self.speed_y = 0
        self.gravity = 0.5
        self.flap_power = -8
        self.angle = 0
        self.wing_angle = 0
        self.wing_direction = 1
        self.animation_timer = 0
        self.breathing = False
        self.fire_timer = 0
        self.invincible = 0
        self.alive = True

    def update(self):
        self.speed_y += self.gravity
        self.y += self.speed_y
        if self.y < 50:
            self.y = 50; self.speed_y = 0
        if self.y > SCREEN_HEIGHT - 80:
            self.y = SCREEN_HEIGHT - 80; self.speed_y = 0
        self.wing_angle += 0.15 * self.wing_direction
        if abs(self.wing_angle) > 0.8:
            self.wing_direction *= -1
        self.angle += (self.speed_y * 0.05 - self.angle) * 0.1
        if self.fire_timer > 0:
            self.fire_timer -= 1
        if self.invincible > 0:
            self.invincible -= 1
        self.animation_timer += 1

    def flap(self):
        self.speed_y = self.flap_power

    def breathe_fire(self):
        self.breathing = True
        self.fire_timer = 15

    def draw(self, surface):
        if self.invincible > 0 and self.animation_timer % 6 < 3:
            return
        sx, sy = int(self.x), int(self.y)

        # Tail
        for i in range(5):
            tx = sx - 30 - i*12
            ty = sy + math.sin(self.animation_timer*0.15 - i*0.5)*8
            pygame.draw.circle(surface, DRAGON_DARK, (int(tx), int(ty)), max(8-i,3))
        tip_x = sx - 30 - 5*12
        tip_y = sy + math.sin(self.animation_timer*0.15 - 5*0.5)*8
        pygame.draw.circle(surface, GOLD, (int(tip_x), int(tip_y)), 5)

        # Legs
        lw = math.sin(self.animation_timer*0.2)*5
        pygame.draw.line(surface, DRAGON_DARK, (sx-15,sy+20),(sx-25,sy+40+lw),4)
        pygame.draw.line(surface, DRAGON_DARK, (sx+5,sy+20),(sx+15,sy+40-lw),4)
        pygame.draw.circle(surface, GOLD, (sx-25,int(sy+40+lw)),4)
        pygame.draw.circle(surface, GOLD, (sx+15,int(sy+40-lw)),4)

        # Body
        pygame.draw.ellipse(surface, DRAGON_GREEN, (sx-35,sy-15,70,35))
        pygame.draw.ellipse(surface, DRAGON_DARK, (sx-30,sy-10,60,25))
        pygame.draw.ellipse(surface, (100,200,100), (sx-20,sy,40,15))

        # Wings
        wo = math.sin(self.wing_angle)*15
        # Left
        pts_l = [(sx-10,sy-10),(sx-40,sy-30-wo),(sx-55,sy-15-wo*0.5),(sx-30,sy-5)]
        pygame.draw.polygon(surface, DRAGON_DARK, pts_l)
        pygame.draw.polygon(surface, (20,100,20), pts_l, 2)
        # Right
        pts_r = [(sx+10,sy-10),(sx+35,sy-25-wo*0.8),(sx+50,sy-10-wo*0.3),(sx+25,sy-5)]
        pygame.draw.polygon(surface, DRAGON_DARK, pts_r)
        pygame.draw.polygon(surface, (20,100,20), pts_r, 2)

        # Neck & Head
        pygame.draw.line(surface, DRAGON_GREEN, (sx+25,sy-10),(sx+35,sy-23),10)
        pygame.draw.line(surface, DRAGON_DARK, (sx+25,sy-10),(sx+35,sy-23),6)
        hx, hy = sx+37, sy-27
        pygame.draw.circle(surface, DRAGON_GREEN, (hx,hy), 16)
        pygame.draw.circle(surface, DRAGON_DARK, (hx,hy), 12)

        # Mouth & teeth
        mx, my = hx+12, hy+2
        pygame.draw.polygon(surface, DRAGON_DARK, [(hx+10,hy-5),(mx+8,my),(hx+10,hy+5)])
        pygame.draw.polygon(surface, WHITE, [(hx+12,hy),(hx+16,hy+4),(hx+14,hy+2)])
        pygame.draw.polygon(surface, WHITE, [(hx+14,hy-2),(hx+18,hy-6),(hx+16,hy-3)])

        # Nostril smoke
        if self.animation_timer % 10 < 5:
            pygame.draw.circle(surface, GRAY, (hx+17,hy-8),3)
            pygame.draw.circle(surface, LIGHT_GRAY, (hx+20,hy-11),2)

        # Eye
        pygame.draw.circle(surface, WHITE, (hx+5,hy-5),6)
        pygame.draw.circle(surface, RED, (hx+7,hy-5),3)
        pygame.draw.circle(surface, (255,255,100), (hx+8,hy-6),1.5)

        # Horns
        pygame.draw.polygon(surface, GOLD, [(hx-5,hy-12),(hx-10,hy-25),(hx,hy-15)])
        pygame.draw.polygon(surface, GOLD, [(hx+2,hy-14),(hx+5,hy-28),(hx+8,hy-16)])

        # Fire breath
        if self.fire_timer > 0:
            for i in range(8):
                fx = mx+10+i*8+random.randint(-3,3)
                fy = my+random.randint(-4,4)
                sz = max(8-i+random.randint(0,3),2)
                pygame.draw.circle(surface, random.choice([FIRE_ORANGE,FIRE_YELLOW,RED]),(fx,fy),sz)

        # --- Rider ---
        kx, ky = sx-5, sy-35
        # Cape
        cw = math.sin(self.animation_timer*0.15)*5
        cape = [(kx-5,ky-5),(kx-20,ky+5+cw),(kx-15,ky+20+cw*0.5),(kx+5,ky+10)]
        pygame.draw.polygon(surface, RED, cape)
        pygame.draw.polygon(surface, DARK_RED, cape, 2)
        # Body armor
        pygame.draw.rect(surface, ARMOR, (kx-5,ky-5,14,20))
        pygame.draw.rect(surface, DARK_GRAY, (kx-5,ky-5,14,20),2)
        # Helmet
        pygame.draw.circle(surface, ARMOR, (kx+2,ky-10),10)
        pygame.draw.circle(surface, DARK_GRAY, (kx+2,ky-10),10,2)
        pygame.draw.line(surface, BLACK, (kx-2,ky-12),(kx+6,ky-8),2)
        pygame.draw.line(surface, BLACK, (kx-2,ky-8),(kx+6,ky-4),2)
        # Plume
        pygame.draw.line(surface, RED, (kx+2,ky-20),(kx+2,ky-30),3)
        pygame.draw.circle(surface, RED, (kx+2,ky-32),5)
        # Shield
        pygame.draw.circle(surface, BLUE, (kx+14,ky+2),8)
        pygame.draw.circle(surface, GOLD, (kx+14,ky+2),8,2)
        pygame.draw.line(surface, WHITE, (kx+14,ky-3),(kx+14,ky+7),2)
        # Sword
        pygame.draw.line(surface, LIGHT_GRAY, (kx+8,ky-15),(kx+25,ky-35),3)
        pygame.draw.line(surface, GOLD, (kx+6,ky-12),(kx+10,ky-16),4)
        # Legs
        pygame.draw.line(surface, DARK_GRAY, (kx,ky+15),(kx-8,ky+25),4)
        pygame.draw.line(surface, DARK_GRAY, (kx+5,ky+15),(kx+12,ky+25),4)


# ==================== Obstacle ====================

class Obstacle:
    def __init__(self, x, obs_type="mountain"):
        self.x = x; self.type = obs_type; self.passed = False
        if obs_type == "mountain":
            self.width = random.randint(60,120); self.height = random.randint(80,200)
            self.y = SCREEN_HEIGHT-50-self.height
        elif obs_type == "rock":
            self.width = random.randint(40,70); self.height = random.randint(30,60)
            self.y = SCREEN_HEIGHT-50-self.height
        elif obs_type == "floating_island":
            self.width = random.randint(80,150); self.height = random.randint(20,40)
            self.y = random.randint(100,300)
        elif obs_type == "lightning":
            self.width = 30; self.height = random.randint(100,250)
            self.y = 0; self.warning_timer = 60

    def update(self, speed):
        self.x -= speed
        if self.type == "lightning" and self.warning_timer > 0:
            self.warning_timer -= 1

    def draw(self, surface):
        if self.type == "mountain":
            pygame.draw.polygon(surface, DARK_GRAY, [(self.x,self.y+self.height),(self.x+self.width//2,self.y),(self.x+self.width,self.y+self.height)])
            pygame.draw.polygon(surface, GRAY, [(self.x+5,self.y+self.height),(self.x+self.width//2,self.y+10),(self.x+self.width-5,self.y+self.height)])
            pygame.draw.polygon(surface, WHITE, [(self.x+self.width//2-10,self.y+20),(self.x+self.width//2,self.y),(self.x+self.width//2+10,self.y+20)])
            pygame.draw.rect(surface, GREEN, (self.x,self.y+self.height-10,self.width,10))
        elif self.type == "rock":
            pygame.draw.polygon(surface, DARK_GRAY, [(self.x,self.y+self.height),(self.x+self.width//3,self.y+5),(self.x+2*self.width//3,self.y+10),(self.x+self.width,self.y+self.height)])
            pygame.draw.line(surface, GRAY, (self.x+10,self.y+self.height-10),(self.x+self.width-10,self.y+15),2)
        elif self.type == "floating_island":
            pygame.draw.ellipse(surface, BROWN, (self.x,self.y,self.width,self.height))
            pygame.draw.ellipse(surface, DARK_BROWN, (self.x,self.y+self.height-10,self.width,15))
            pygame.draw.ellipse(surface, GREEN, (self.x+5,self.y,self.width-10,10))
            for i in range(3):
                rx = self.x+self.width//4+i*(self.width//4)
                pygame.draw.line(surface, DARK_BROWN, (rx,self.y+self.height),(rx+random.randint(-5,5),self.y+self.height+20),2)
            tx = self.x+self.width//2; pygame.draw.line(surface, DARK_BROWN,(tx,self.y),(tx,self.y-15),3)
            pygame.draw.circle(surface, GREEN,(tx,self.y-20),12)
            pygame.draw.circle(surface,(34,180,34),(tx-5,self.y-18),8)
            pygame.draw.circle(surface,(34,180,34),(tx+5,self.y-18),8)
        elif self.type == "lightning":
            if self.warning_timer > 0:
                if self.warning_timer % 20 < 10:
                    wx = self.x+self.width//2
                    pygame.draw.polygon(surface, YELLOW, [(wx,10),(wx-12,40),(wx+12,40)])
                    surface.blit(font_small.render("!", True, RED), (wx-4,15))
            else:
                lx = self.x+self.width//2
                pts = [(lx,0),(lx-8,30),(lx+5,50),(lx-5,80),(lx+8,110),(lx-3,self.height)]
                for i in range(len(pts)-1):
                    pygame.draw.line(surface, YELLOW, pts[i], pts[i+1],4)
                    pygame.draw.line(surface, WHITE, pts[i], pts[i+1],2)

    def get_rect(self):
        if self.type == "lightning":
            return pygame.Rect(self.x, 0, self.width, self.height)
        return pygame.Rect(self.x, self.y, self.width, self.height)

    def is_off_screen(self):
        return self.x+self.width < -50


# ==================== Coin ====================

class Coin:
    def __init__(self, x, y):
        self.x = x; self.y = y; self.radius = 12
        self.collected = False; self.spin_angle = 0
        self.bob_offset = random.uniform(0, math.pi*2)

    def update(self, speed):
        self.x -= speed; self.spin_angle += 0.15

    def draw(self, surface):
        if self.collected: return
        bob = math.sin(self.spin_angle+self.bob_offset)*5
        dy = int(self.y+bob)
        gr = int(self.radius+4+math.sin(self.spin_angle*2)*2)
        pygame.draw.circle(surface, (255,255,150,100),(int(self.x),dy),gr)
        sc = abs(math.cos(self.spin_angle))
        w = max(int(self.radius*2*sc),2)
        pygame.draw.ellipse(surface, GOLD, (int(self.x)-w//2,dy-self.radius,w,self.radius*2))
        pygame.draw.ellipse(surface,(255,240,100),(int(self.x)-w//2+2,dy-self.radius+2,w-4,self.radius*2-4))
        if sc > 0.5:
            surface.blit(font_small.render("$",True,(200,150,0)),(int(self.x)-4,dy-8))

    def get_rect(self):
        return pygame.Rect(int(self.x)-self.radius,int(self.y)-self.radius,self.radius*2,self.radius*2)

    def is_off_screen(self):
        return self.x < -30


# ==================== Enemy ====================

class Enemy:
    def __init__(self, x, y, enemy_type="bat"):
        self.x=x; self.y=y; self.type=enemy_type; self.animation_timer=0
        self.hp=1; self.dead=False; self.death_timer=0
        if enemy_type=="bat":
            self.width=40; self.height=25; self.speed=random.uniform(2,4)
        elif enemy_type=="dark_dragon":
            self.width=70; self.height=45; self.speed=random.uniform(1.5,3); self.hp=2
        elif enemy_type=="gargoyle":
            self.width=50; self.height=50; self.speed=1

    def update(self, game_speed):
        self.x -= game_speed*0.5+self.speed
        self.animation_timer += 1
        if self.dead:
            self.death_timer += 1; self.y += 3

    def draw(self, surface):
        if self.dead and self.death_timer>30: return
        sx, sy = int(self.x), int(self.y)
        if self.type == "bat":
            w = math.sin(self.animation_timer*0.3)*10
            pygame.draw.ellipse(surface,(60,60,60),(sx-8,sy-5,16,12))
            pygame.draw.polygon(surface,(80,80,80),[(sx-5,sy),(sx-20,sy-10-w),(sx-15,sy+5)])
            pygame.draw.polygon(surface,(80,80,80),[(sx+5,sy),(sx+20,sy-10-w),(sx+15,sy+5)])
            pygame.draw.circle(surface,RED,(sx-3,sy-2),2)
            pygame.draw.circle(surface,RED,(sx+3,sy-2),2)
            pygame.draw.polygon(surface,WHITE,[(sx-4,sy+5),(sx-2,sy+8),(sx,sy+5)])
            pygame.draw.polygon(surface,WHITE,[(sx,sy+5),(sx+2,sy+8),(sx+4,sy+5)])
        elif self.type == "dark_dragon":
            wo = math.sin(self.animation_timer*0.15)*10
            pygame.draw.ellipse(surface,(80,20,80),(sx-20,sy-10,45,25))
            pygame.draw.polygon(surface,(100,30,100),[(sx-10,sy-5),(sx-30,sy-20-wo),(sx-5,sy)])
            pygame.draw.polygon(surface,(100,30,100),[(sx+10,sy-5),(sx+25,sy-15-wo*0.7),(sx+15,sy)])
            pygame.draw.circle(surface,(90,25,90),(sx+20,sy-3),12)
            pygame.draw.circle(surface,FIRE_YELLOW,(sx+23,sy-5),4)
            pygame.draw.circle(surface,RED,(sx+24,sy-5),2)
            for i in range(4):
                tx=sx-25-i*8; ty=sy+math.sin(self.animation_timer*0.1-i*0.5)*5
                pygame.draw.circle(surface,(80,20,80),(tx,int(ty)),5-i)
            if self.hp<2:
                pygame.draw.rect(surface,RED,(sx-10,sy-20,30,4))
                pygame.draw.rect(surface,GREEN,(sx-10,sy-20,15*self.hp,4))
        elif self.type == "gargoyle":
            pygame.draw.rect(surface,(100,100,110),(sx-15,sy-15,30,30))
            w = math.sin(self.animation_timer*0.1)*5
            pygame.draw.polygon(surface,(120,120,130),[(sx-15,sy-10),(sx-35,sy-25-w),(sx-20,sy+5)])
            pygame.draw.polygon(surface,(120,120,130),[(sx+15,sy-10),(sx+35,sy-25-w),(sx+20,sy+5)])
            pygame.draw.polygon(surface,GRAY,[(sx-5,sy-15),(sx-10,sy-30),(sx,sy-15)])
            pygame.draw.polygon(surface,GRAY,[(sx+5,sy-15),(sx+10,sy-30),(sx,sy-15)])
            pygame.draw.circle(surface,RED,(sx-5,sy-5),3)
            pygame.draw.circle(surface,RED,(sx+5,sy-5),3)

    def get_rect(self):
        return pygame.Rect(int(self.x)-self.width//2,int(self.y)-self.height//2,self.width,self.height)

    def is_off_screen(self): return self.x < -80

    def take_damage(self):
        self.hp -= 1
        if self.hp <= 0: self.dead = True
        return self.dead


# ==================== Treasure Chest ====================

class TreasureChest:
    def __init__(self, x, y):
        self.x=x; self.y=y; self.width=36; self.height=30
        self.collected=False; self.animation_timer=0
        self.bob_offset=random.uniform(0,math.pi*2)

    def update(self, speed):
        self.x -= speed; self.animation_timer += 1

    def draw(self, surface):
        if self.collected: return
        bob = math.sin(self.animation_timer*0.1+self.bob_offset)*5
        sx, sy = int(self.x), int(self.y+bob)
        pygame.draw.circle(surface,(255,255,100,80),(sx,sy-5),25+int(10+math.sin(self.animation_timer*0.15)*5))
        pygame.draw.rect(surface,BROWN,(sx-15,sy-5,30,20))
        pygame.draw.rect(surface,DARK_BROWN,(sx-15,sy-5,30,20),2)
        pygame.draw.arc(surface,BROWN,(sx-15,sy-18,30,20),math.pi,2*math.pi,3)
        pygame.draw.arc(surface,DARK_BROWN,(sx-15,sy-18,30,20),math.pi,2*math.pi,2)
        pygame.draw.circle(surface,GOLD,(sx,sy+2),4)
        pygame.draw.rect(surface,GOLD,(sx-2,sy+2,4,6))

    def get_rect(self):
        return pygame.Rect(int(self.x)-15,int(self.y)-15,30,30)

    def is_off_screen(self): return self.x < -50


# ==================== Cloud ====================

class Cloud:
    def __init__(self, x, y, scale=1.0):
        self.x=x; self.y=y; self.scale=scale
        self.speed=0.5*scale
        self.surface=create_cloud_surface(int(100*scale),int(50*scale))

    def update(self): self.x -= self.speed
    def draw(self, surface): surface.blit(self.surface,(int(self.x),int(self.y)))
    def is_off_screen(self): return self.x+self.surface.get_width() < -20


# ==================== Ground Decoration ====================

class GroundDecoration:
    def __init__(self, x):
        self.x=x; self.type=random.choice(["tree","bush","stone","flower"])
        self.y=SCREEN_HEIGHT-50

    def update(self, speed): self.x -= speed

    def draw(self, surface):
        sx, sy = int(self.x), self.y
        if self.type == "tree":
            pygame.draw.rect(surface,DARK_BROWN,(sx-3,sy-40,6,40))
            pygame.draw.circle(surface,(34,139,34),(sx,sy-50),18)
            pygame.draw.circle(surface,(50,160,50),(sx-8,sy-45),12)
            pygame.draw.circle(surface,(50,160,50),(sx+8,sy-45),12)
            pygame.draw.circle(surface,(34,120,34),(sx,sy-58),10)
        elif self.type == "bush":
            pygame.draw.circle(surface,(50,160,50),(sx,sy-10),12)
            pygame.draw.circle(surface,(34,139,34),(sx-8,sy-8),8)
            pygame.draw.circle(surface,(34,139,34),(sx+8,sy-8),8)
        elif self.type == "stone":
            pygame.draw.ellipse(surface,GRAY,(sx-10,sy-12,20,12))
            pygame.draw.ellipse(surface,LIGHT_GRAY,(sx-8,sy-10,16,8))
        elif self.type == "flower":
            pygame.draw.line(surface,GREEN,(sx,sy),(sx,sy-15),2)
            pygame.draw.circle(surface,random.choice([RED,YELLOW,PURPLE,WHITE]),(sx,sy-18),5)

    def is_off_screen(self): return self.x < -30


# ==================== Game States ====================

class GameState:
    MENU = 0; PLAYING = 1; GAME_OVER = 2; VICTORY = 3; PAUSED = 4


# ==================== Game ====================

class Game:
    def __init__(self):
        self.reset_game()
        self.state = GameState.MENU
        self.high_score = 0
        self.total_coins = 0
        self.clouds = []
        self.ground_decorations = []
        self.stars = [(random.randint(0,SCREEN_WIDTH),random.randint(0,200),random.uniform(0.5,1.5)) for _ in range(30)]
        for _ in range(8):
            self.clouds.append(Cloud(random.randint(0,SCREEN_WIDTH),random.randint(10,200),random.uniform(0.5,1.5)))
        for _ in range(15):
            self.ground_decorations.append(GroundDecoration(random.randint(0,SCREEN_WIDTH)))
        self.particles = ParticleSystem()
        self.flash_timer=0; self.shake_timer=0; self.shake_intensity=0

    def reset_game(self):
        self.dragon = Dragon(200, SCREEN_HEIGHT//2)
        self.obstacles=[]; self.coins=[]; self.enemies=[]
        self.treasure_chests=[]; self.score=0; self.distance=0
        self.game_speed=4; self.max_speed=10
        self.spawn_timer=0; self.coin_spawn_timer=0; self.enemy_spawn_timer=0
        self.weather_type="clear"; self.weather_timer=0
        self.raindrops=[]; self.powerups=[]
        self.shield_active=0; self.double_score=0; self.magnet_active=0
        self.combo=0; self.combo_timer=0
        self.level=1; self.boss_active=False; self.boss=None

    def spawn_obstacle(self):
        types = ["mountain","rock","floating_island"]
        weights = [5,3,2]
        if self.distance > 2000:
            types.append("lightning"); weights=[4,3,2,1]
        ot = random.choices(types,weights=weights)[0]
        x = SCREEN_WIDTH+50
        self.obstacles.append(Obstacle(x,ot))
        if ot != "lightning" and random.random()<0.6:
            for i in range(random.randint(1,4)):
                cx=x+random.randint(-30,50)
                cy=random.randint(50,SCREEN_HEIGHT-150)
                if ot=="floating_island":
                    cx=x+random.randint(20,80)
                    cy=SCREEN_HEIGHT//2-random.randint(50,200)
                self.coins.append(Coin(cx,cy))

    def spawn_enemy(self):
        types = ["bat","dark_dragon","gargoyle"]
        et = random.choices(types,weights=[5,2,1])[0]
        self.enemies.append(Enemy(SCREEN_WIDTH+50,random.randint(80,SCREEN_HEIGHT-150),et))

    def spawn_treasure(self):
        self.treasure_chests.append(TreasureChest(SCREEN_WIDTH+100,random.randint(100,SCREEN_HEIGHT-200)))

    def spawn_powerup(self):
        pt = random.choice(["shield","double_score","magnet","heal"])
        self.powerups.append({"type":pt,"x":SCREEN_WIDTH+50,"y":random.randint(80,SCREEN_HEIGHT-150),"radius":15,"bob":random.uniform(0,math.pi*2),"timer":0})

    def update_weather(self):
        self.weather_timer -= 1
        if self.weather_timer <= 0:
            self.weather_type = random.choice(["clear","clear","rain","storm"])
            self.weather_timer = random.randint(300,600)
        if self.weather_type in ["rain","storm"]:
            for _ in range(3 if self.weather_type=="rain" else 6):
                self.raindrops.append({"x":random.randint(0,SCREEN_WIDTH),"y":random.randint(-50,0),"speed":random.uniform(5,10) if self.weather_type=="rain" else random.uniform(8,15),"length":random.randint(5,15)})
        for d in self.raindrops[:]:
            d["y"]+=d["speed"]; d["x"]-=self.game_speed*0.3
            if d["y"]>SCREEN_HEIGHT: self.raindrops.remove(d)

    def draw_weather(self, surface):
        if self.weather_type=="clear": return
        if self.weather_type=="rain":
            ov=pygame.Surface((SCREEN_WIDTH,SCREEN_HEIGHT),pygame.SRCALPHA)
            ov.fill((100,100,120,40)); surface.blit(ov,(0,0))
        elif self.weather_type=="storm":
            ov=pygame.Surface((SCREEN_WIDTH,SCREEN_HEIGHT),pygame.SRCALPHA)
            ov.fill((50,50,70,80)); surface.blit(ov,(0,0))
            if random.random()<0.02:
                for _ in range(3):
                    lx=random.randint(100,SCREEN_WIDTH-100)
                    pts=[(lx,0)]
                    for i in range(5):
                        lx+=random.randint(-20,20)
                        pts.append((lx,(i+1)*SCREEN_HEIGHT//6))
                    for i in range(len(pts)-1):
                        pygame.draw.line(surface,YELLOW,pts[i],pts[i+1],3)
        for d in self.raindrops:
            c=(180,180,220) if self.weather_type=="rain" else (150,150,200)
            pygame.draw.line(surface,c,(int(d["x"]),int(d["y"])),(int(d["x"]-2),int(d["y"]+d["length"])),2)

    def update(self):
        if self.state != GameState.PLAYING: return
        self.distance += self.game_speed*0.1
        self.score += 0.1*(2 if self.double_score>0 else 1)
        if self.game_speed < self.max_speed: self.game_speed += 0.002
        nl = int(self.distance/1000)+1
        if nl > self.level:
            self.level=nl; self.flash_timer=60
            self.max_speed=min(12,self.max_speed+0.5)

        self.dragon.update()
        if self.dragon.fire_timer>0:
            self.particles.emit_fire(self.dragon.x+50,self.dragon.y-20)
        if random.random()<0.3:
            self.particles.emit(self.dragon.x+random.randint(-30,30),self.dragon.y+random.randint(-20,20),(255,255,random.randint(100,200)),count=1,spread=0.5,speed_range=(0.5,1.5),life_range=(10,20),size_range=(1,3))
        tx=self.dragon.x-80; ty=self.dragon.y+math.sin(pygame.time.get_ticks()*0.005)*8
        if random.random()<0.2:
            self.particles.emit(tx,ty,(100,255,100),count=1,spread=0.3,speed_range=(0.3,0.8),life_range=(15,25),size_range=(2,4))
        self.particles.update()
        self.update_weather()

        self.spawn_timer+=1
        if self.spawn_timer>=max(60,120-int(self.distance*0.01)):
            self.spawn_obstacle(); self.spawn_timer=0
        self.enemy_spawn_timer+=1
        if self.enemy_spawn_timer>=max(100,200-int(self.distance*0.005)):
            self.spawn_enemy(); self.enemy_spawn_timer=0
        if random.random()<0.003: self.spawn_treasure()
        if random.random()<0.002: self.spawn_powerup()

        for o in self.obstacles[:]:
            o.update(self.game_speed)
            if o.is_off_screen():
                self.obstacles.remove(o)
                if not o.passed and o.type!="lightning":
                    self.score+=10; o.passed=True
        for c in self.coins[:]:
            c.update(self.game_speed)
            if c.is_off_screen(): self.coins.remove(c)
        for e in self.enemies[:]:
            e.update(self.game_speed)
            if e.is_off_screen() or (e.dead and e.death_timer>30): self.enemies.remove(e)
        for ch in self.treasure_chests[:]:
            ch.update(self.game_speed)
            if ch.is_off_screen(): self.treasure_chests.remove(ch)
        for p in self.powerups[:]:
            p["x"]-=self.game_speed; p["timer"]+=1
            if p["x"]<-30: self.powerups.remove(p)
        for c in self.clouds[:]:
            c.update()
            if c.is_off_screen():
                self.clouds.remove(c)
                self.clouds.append(Cloud(SCREEN_WIDTH+50,random.randint(10,200),random.uniform(0.5,1.5)))
        for d in self.ground_decorations[:]:
            d.update(self.game_speed)
            if d.is_off_screen():
                self.ground_decorations.remove(d)
                self.ground_decorations.append(GroundDecoration(SCREEN_WIDTH+random.randint(50,200)))

        if self.shield_active>0: self.shield_active-=1
        if self.double_score>0: self.double_score-=1
        if self.magnet_active>0: self.magnet_active-=1
        if self.combo_timer>0:
            self.combo_timer-=1
            if self.combo_timer<=0: self.combo=0
        if self.magnet_active>0:
            for c in self.coins:
                dx,dy=self.dragon.x-c.x,self.dragon.y-c.y
                if math.sqrt(dx*dx+dy*dy)<150:
                    c.x+=dx*0.05; c.y+=dy*0.05

        self.check_collisions()
        if self.shake_timer>0: self.shake_timer-=1
        if self.flash_timer>0: self.flash_timer-=1
        if self.distance>=10000: self.state=GameState.VICTORY

    def check_collisions(self):
        dr = pygame.Rect(int(self.dragon.x)-20,int(self.dragon.y)-20,40,40)
        for o in self.obstacles:
            if o.type=="lightning" and o.warning_timer>0: continue
            r=o.get_rect()
            s=pygame.Rect(r.x+5,r.y+5,max(r.width-10,1),max(r.height-10,1))
            if dr.colliderect(s): self.handle_hit()
        for e in self.enemies:
            if e.dead: continue
            r=e.get_rect()
            s=pygame.Rect(r.x+5,r.y+5,max(r.width-10,1),max(r.height-10,1))
            if dr.colliderect(s):
                if self.dragon.fire_timer>0 and self.dragon.y<e.y:
                    if e.take_damage():
                        self.score+=50; self.combo+=1; self.combo_timer=120
                        for _ in range(15):
                            self.particles.emit(e.x,e.y,(150,50,150),count=1,spread=3,life_range=(20,40),size_range=(3,8))
                else:
                    self.handle_hit()
        for c in self.coins[:]:
            if not c.collected and dr.colliderect(c.get_rect()):
                c.collected=True; self.coins.remove(c)
                self.score+=int(10*(2 if self.double_score>0 else 1)*(1+self.combo*0.1))
                self.total_coins+=1; self.combo+=1; self.combo_timer=120
                for _ in range(8): self.particles.emit(c.x,c.y,GOLD,count=1,spread=2,life_range=(10,20),size_range=(2,5))
        for ch in self.treasure_chests[:]:
            if not ch.collected and dr.colliderect(ch.get_rect()):
                ch.collected=True; self.treasure_chests.remove(ch)
                self.score+=random.randint(100,500)*(2 if self.double_score>0 else 1)
                self.combo+=5; self.combo_timer=180
                for _ in range(20):
                    self.particles.emit(ch.x,ch.y,random.choice([GOLD,(255,100,0),PURPLE]),count=1,spread=4,life_range=(20,50),size_range=(3,8))
                self.shake_timer=10; self.shake_intensity=5
        for p in self.powerups[:]:
            pr=pygame.Rect(int(p["x"])-p["radius"],int(p["y"])-p["radius"],p["radius"]*2,p["radius"]*2)
            if dr.colliderect(pr):
                self.powerups.remove(p); self.activate_powerup(p["type"]); self.score+=30

    def activate_powerup(self, pt):
        if pt=="shield": self.shield_active=600
        elif pt=="double_score": self.double_score=600
        elif pt=="magnet": self.magnet_active=400
        elif pt=="heal": self.dragon.invincible=180
        cm = {"shield":(100,200,255),"double_score":MAGENTA,"magnet":(255,200,0),"heal":(100,255,100)}
        for _ in range(20): self.particles.emit(self.dragon.x,self.dragon.y,cm.get(pt,GOLD),count=1,spread=4,life_range=(20,40),size_range=(3,8))

    def handle_hit(self):
        if self.dragon.invincible>0 or self.shield_active>0: return
        self.dragon.invincible=120; self.shake_timer=15; self.shake_intensity=8; self.combo=0
        for _ in range(15): self.particles.emit(self.dragon.x,self.dragon.y,RED,count=1,spread=3,life_range=(20,40),size_range=(3,8))
        self.score=max(0,self.score-50)
        if self.score<=0 and self.distance>1000:
            self.state=GameState.GAME_OVER
            if self.high_score>0: self.high_score=max(self.high_score,int(self.score))

    # ========== DRAWING ==========

    def draw_hud(self, surface):
        surface.blit(font_medium.render(f"Score: {int(self.score)}",True,WHITE),(10,10))
        surface.blit(font_medium.render(f"Dist: {int(self.distance)}m",True,WHITE),(10,50))
        surface.blit(font_medium.render(f"Lv: {self.level}",True,GOLD),(10,90))
        surface.blit(font_medium.render(f"Coins: {self.total_coins}",True,GOLD),(250,10))
        surface.blit(font_small.render(f"Best: {int(max(self.high_score,self.score))}",True,LIGHT_GRAY),(250,50))
        if self.combo>1:
            cc=ORANGE if self.combo<5 else RED if self.combo<10 else MAGENTA
            ct=font_medium.render(f"Combo x{self.combo}!",True,cc)
            sc=1+math.sin(pygame.time.get_ticks()*0.01)*0.1
            cs=pygame.transform.scale(ct,(int(ct.get_width()*sc),int(ct.get_height()*sc)))
            surface.blit(cs,(400,10))
        ey=90; ex=400
        if self.shield_active>0:
            surface.blit(font_small.render(f"Shield ({self.shield_active//60}s)",True,CYAN),(ex,ey)); ey+=25
        if self.double_score>0:
            surface.blit(font_small.render(f"2x Score ({self.double_score//60}s)",True,MAGENTA),(ex,ey)); ey+=25
        if self.magnet_active>0:
            surface.blit(font_small.render(f"Magnet ({self.magnet_active//60}s)",True,(255,200,0)),(ex,ey))
        # Speed bar
        bx,by=SCREEN_WIDTH-200,15; bw,bh=150,12
        pygame.draw.rect(surface,DARK_GRAY,(bx,by,bw,bh),border_radius=5)
        pygame.draw.rect(surface,CYAN,(bx,by,int(bw*(self.game_speed-4)/(self.max_speed-4)),bh),border_radius=5)
        surface.blit(font_small.render("SPD",True,WHITE),(bx,by-20))
        # Weather icon
        wi={"clear":"Sunny","rain":"Rain","storm":"Storm"}
        if self.weather_type!="clear":
            surface.blit(font_small.render(wi[self.weather_type],True,WHITE),(SCREEN_WIDTH-80,40))

    def draw_powerups(self, surface):
        for p in self.powerups:
            px=int(p["x"]); py=int(p["y"]+math.sin(p["timer"]*0.1+p["bob"])*8)
            pygame.draw.circle(surface,(255,255,255,60),(px,py),20+int(math.sin(p["timer"]*0.15)*5))
            cm={"shield":CYAN,"double_score":MAGENTA,"magnet":(255,200,0),"heal":(100,255,100)}
            c=cm.get(p["type"],GOLD)
            pygame.draw.circle(surface,c,(px,py),p["radius"])
            pygame.draw.circle(surface,WHITE,(px,py),p["radius"],2)
            ic={"shield":"S","double_score":"2x","magnet":"M","heal":"+"}
            surface.blit(font_small.render(ic.get(p["type"],"?"),True,WHITE),(px-6,py-8))

    def draw_shield(self, surface):
        if self.shield_active<=0: return
        sa=80+int(math.sin(pygame.time.get_ticks()*0.01)*40)
        ss=pygame.Surface((100,100),pygame.SRCALPHA)
        pygame.draw.circle(ss,(100,200,255,sa),(50,50),45,3)
        pygame.draw.circle(ss,(100,200,255,sa//2),(50,50),40,2)
        surface.blit(ss,(int(self.dragon.x)-50,int(self.dragon.y)-50))

    def draw_background(self, surface):
        draw_gradient_sky(surface)
        for sx,sy,b in self.stars:
            pygame.draw.circle(surface,(255,255,200),((sx+int(self.distance*0.05))%SCREEN_WIDTH,sy),max(1,int(b)))
        # Far mountains (parallax)
        moff=int(self.distance*0.1)%SCREEN_WIDTH
        for i in range(-1,3):
            bx=i*SCREEN_WIDTH-moff*0.5
            pts=[(bx,SCREEN_HEIGHT-50)]
            for mx in range(0,SCREEN_WIDTH+100,100):
                pts.append((bx+mx,SCREEN_HEIGHT-50-(100+math.sin(mx*0.01+i)*50)))
            pts.append((bx+SCREEN_WIDTH+100,SCREEN_HEIGHT-50))
            pygame.draw.polygon(surface,(60,80,100,180),pts)
        # Mid mountains
        moff2=int(self.distance*0.2)%SCREEN_WIDTH
        for i in range(-1,3):
            bx=i*SCREEN_WIDTH-moff2*0.7
            pts=[(bx,SCREEN_HEIGHT-50)]
            for mx in range(0,SCREEN_WIDTH+100,80):
                pts.append((bx+mx,SCREEN_HEIGHT-50-(60+math.sin(mx*0.015+i*2)*30)))
            pts.append((bx+SCREEN_WIDTH+100,SCREEN_HEIGHT-50))
            pygame.draw.polygon(surface,(80,100,80),pts)
        for c in self.clouds: c.draw(surface)
        # Ground
        gy=SCREEN_HEIGHT-50
        pygame.draw.rect(surface,(60,140,60),(0,gy,SCREEN_WIDTH,50))
        for i in range(0,SCREEN_WIDTH,20):
            h=5+math.sin(i*0.1+self.distance*0.1)*3
            pygame.draw.line(surface,(50,120,50),(i,gy),(i,gy+h),2)
        for d in self.ground_decorations: d.draw(surface)

    def draw_flash(self, surface):
        if self.flash_timer<=0: return
        a=int(100*self.flash_timer/60)
        fs=pygame.Surface((SCREEN_WIDTH,SCREEN_HEIGHT),pygame.SRCALPHA)
        fs.fill((255,255,255,a)); surface.blit(fs,(0,0))
        if self.flash_timer>30:
            lt=font_huge.render(f"LEVEL {self.level}!",True,GOLD)
            surface.blit(lt,lt.get_rect(center=(SCREEN_WIDTH//2,SCREEN_HEIGHT//2)))

    def draw(self, surface):
        sx=sy=0
        if self.shake_timer>0:
            sx=random.randint(-self.shake_intensity,self.shake_intensity)
            sy=random.randint(-self.shake_intensity,self.shake_intensity)
        self.draw_background(surface)
        self.draw_weather(surface)
        for o in self.obstacles: o.draw(surface)
        for c in self.coins: c.draw(surface)
        for ch in self.treasure_chests: ch.draw(surface)
        self.draw_powerups(surface)
        for e in self.enemies: e.draw(surface)
        self.draw_shield(surface)
        self.dragon.draw(surface)
        self.particles.draw(surface)
        self.draw_hud(surface)
        self.draw_flash(surface)
        if sx or sy:
            tmp=surface.copy(); surface.fill(BLACK); surface.blit(tmp,(sx,sy))

    def draw_menu(self, surface):
        draw_gradient_sky(surface)
        for c in self.clouds: c.draw(surface); c.update()
        # Title
        t1=font_title.render("Dragon Rider",True,GOLD)
        t2=font_title.render("Dragon Rider",True,DARK_RED)
        r1=t1.get_rect(center=(SCREEN_WIDTH//2,140))
        surface.blit(t2,(r1.x+3,r1.y+3)); surface.blit(t1,r1)
        st=font_medium.render("Adventure",True,(200,200,255))
        surface.blit(st,st.get_rect(center=(SCREEN_WIDTH//2,210)))
        pygame.draw.line(surface,GOLD,(SCREEN_WIDTH//2-200,240),(SCREEN_WIDTH//2+200,240),2)

        # Menu text
        lines=[
            ("Press [SPACE] or [CLICK] to Start",WHITE),
            ("",None),
            ("--- Controls ---",GOLD),
            ("SPACE / UP / W / Click - Flap",LIGHT_GRAY),
            ("DOWN / S - Dive",LIGHT_GRAY),
            ("F - Fire Breath (attack enemies)",LIGHT_GRAY),
            ("P - Pause",LIGHT_GRAY),
            ("",None),
            ("Collect coins & chests for score!",GREEN),
            ("Avoid obstacles and enemies!",RED),
            ("Grab power-ups for special abilities!",ORANGE),
        ]
        for i,(t,c) in enumerate(lines):
            if not t: continue
            r=font_small.render(t,True,c).get_rect(center=(SCREEN_WIDTH//2,275+i*28))
            surface.blit(font_small.render(t,True,c),r)

        # Demo dragon
        dd=Dragon(SCREEN_WIDTH//2-60,420)
        dd.animation_timer=pygame.time.get_ticks()//16
        dd.draw(surface)

        # Blinking tip
        a=abs(math.sin(pygame.time.get_ticks()*0.003))*255
        ts=pygame.Surface((420,34),pygame.SRCALPHA)
        ts.fill((255,255,255,int(a*0.15)))
        pygame.draw.rect(ts,(255,255,255,int(a*0.4)),(0,0,420,34),2,border_radius=10)
        ttx=font_small.render("Click or Press Any Key to Begin!",True,(255,255,255,int(a)))
        ts.blit(ttx,(210-ttx.get_width()//2,7))
        surface.blit(ts,(SCREEN_WIDTH//2-210,SCREEN_HEIGHT-65))

        surface.blit(font_small.render("v1.0 Pygame Edition",True,LIGHT_GRAY),(SCREEN_WIDTH-210,SCREEN_HEIGHT-30))

    def draw_game_over(self, surface):
        ov=pygame.Surface((SCREEN_WIDTH,SCREEN_HEIGHT),pygame.SRCALPHA)
        ov.fill((0,0,0,180)); surface.blit(ov,(0,0))
        go=font_huge.render("GAME OVER",True,RED)
        surface.blit(font_huge.render("GAME OVER",True,DARK_RED),(go.get_rect(center=(SCREEN_WIDTH//2+4,204)).x,204))
        surface.blit(go,go.get_rect(center=(SCREEN_WIDTH//2,200)))
        surface.blit(font_large.render(f"Final Score: {int(self.score)}",True,GOLD),(SCREEN_WIDTH//2-180,290))
        surface.blit(font_medium.render(f"Distance: {int(self.distance)}m",True,WHITE),(SCREEN_WIDTH//2-120,355))
        surface.blit(font_medium.render(f"Coins: {self.total_coins}",True,GOLD),(SCREEN_WIDTH//2-80,395))
        if self.score>=self.high_score:
            nr=font_medium.render("New Record!",True,(255,200,0))
            surface.blit(nr,nr.get_rect(center=(SCREEN_WIDTH//2,435)))
        surface.blit(font_medium.render("Press [R] to Restart | [ESC] for Menu",True,LIGHT_GRAY),(SCREEN_WIDTH//2-240,520))

    def draw_victory(self, surface):
        ov=pygame.Surface((SCREEN_WIDTH,SCREEN_HEIGHT),pygame.SRCALPHA)
        ov.fill((255,215,0,60)); surface.blit(ov,(0,0))
        if random.random()<0.1:
            for _ in range(5):
                fx=random.randint(100,SCREEN_WIDTH-100); fy=random.randint(100,SCREEN_HEIGHT-200)
                for _ in range(20):
                    self.particles.emit(fx,fy,random.choice([RED,GREEN,CYAN,GOLD,PURPLE,ORANGE]),count=1,spread=5,life_range=(30,60),size_range=(2,6))
        self.particles.draw(surface)
        vt=font_huge.render("VICTORY!",True,GOLD)
        surface.blit(font_huge.render("VICTORY!",True,DARK_RED),(vt.get_rect(center=(SCREEN_WIDTH//2+4,184)).x,184))
        surface.blit(vt,vt.get_rect(center=(SCREEN_WIDTH//2,180)))
        surface.blit(font_large.render("You completed the epic adventure!",True,WHITE),(SCREEN_WIDTH//2-260,275))
        surface.blit(font_medium.render(f"Final Score: {int(self.score)}",True,GOLD),(SCREEN_WIDTH//2-100,350))
        surface.blit(font_medium.render("Press [R] to Play Again | [ESC] for Menu",True,LIGHT_GRAY),(SCREEN_WIDTH//2-230,450))

    def draw_paused(self, surface):
        ov=pygame.Surface((SCREEN_WIDTH,SCREEN_HEIGHT),pygame.SRCALPHA)
        ov.fill((0,0,0,120)); surface.blit(ov,(0,0))
        pp=font_huge.render("PAUSED",True,WHITE)
        surface.blit(pp,pp.get_rect(center=(SCREEN_WIDTH//2,SCREEN_HEIGHT//2-30)))
        surface.blit(font_medium.render("Press [P] or [ESC] to Resume",True,LIGHT_GRAY),(SCREEN_WIDTH//2-180,SCREEN_HEIGHT//2+40))


# ==================== Main ====================

def main():
    game = Game()
    running = True
    key_delay = 0

    while running:
        clock.tick(FPS)
        key_delay = max(0, key_delay-1)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    if game.state==GameState.PLAYING: game.state=GameState.PAUSED
                    elif game.state==GameState.PAUSED: game.state=GameState.MENU
                    elif game.state in [GameState.GAME_OVER,GameState.VICTORY]: game.state=GameState.MENU
                elif event.key == pygame.K_p:
                    if game.state==GameState.PLAYING: game.state=GameState.PAUSED
                    elif game.state==GameState.PAUSED: game.state=GameState.PLAYING
                elif event.key == pygame.K_r:
                    if game.state in [GameState.GAME_OVER,GameState.VICTORY]:
                        game.reset_game(); game.state=GameState.PLAYING
                elif event.key == pygame.K_SPACE:
                    if game.state==GameState.MENU:
                        game.reset_game(); game.state=GameState.PLAYING
                    elif game.state==GameState.PLAYING: game.dragon.flap()
                elif event.key in (pygame.K_UP,pygame.K_w):
                    if game.state==GameState.PLAYING: game.dragon.flap()
                elif event.key in (pygame.K_DOWN,pygame.K_s):
                    if game.state==GameState.PLAYING: game.dragon.speed_y=5
                elif event.key == pygame.K_f:
                    if game.state==GameState.PLAYING: game.dragon.breathe_fire()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if game.state==GameState.MENU:
                    game.reset_game(); game.state=GameState.PLAYING
                elif game.state==GameState.PLAYING: game.dragon.flap()

        # Held keys
        keys=pygame.key.get_pressed()
        if game.state==GameState.PLAYING:
            if keys[pygame.K_SPACE] and key_delay==0:
                game.dragon.flap(); key_delay=8
            if keys[pygame.K_f] and key_delay==0:
                game.dragon.breathe_fire(); key_delay=15

        if game.state==GameState.PLAYING: game.update()

        screen.fill(BLACK)
        if game.state==GameState.MENU: game.draw_menu(screen)
        elif game.state==GameState.PLAYING: game.draw(screen)
        elif game.state==GameState.GAME_OVER:
            game.draw(screen); game.draw_game_over(screen)
        elif game.state==GameState.VICTORY:
            game.draw(screen); game.draw_victory(screen)
        elif game.state==GameState.PAUSED:
            game.draw(screen); game.draw_paused(screen)

        pygame.display.flip()

    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()
