import pygame
import sys
import math
import random

# ===== 初始化 =====
pygame.init()
WIDTH, HEIGHT = 1000, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Radish Defense - 10 Levels")

# ===== 颜色 =====
BG = (35, 55, 35)
PATH_COLOR = (175, 155, 95)
GRASS = (65, 135, 65)
TOWER_COLORS = {
    "basic":   (170, 170, 190),
    "sniper":  (90, 190, 90),
    "machine": (190, 95, 95),
    "cannon":  (195, 145, 45),
    "freeze":  (90, 170, 250),
}
BULLET = (255, 200, 0)
ENEMY_C = (215, 75, 75)
HP_GREEN = (75, 215, 75)
HP_RED = (215, 75, 75)
UI_BG = (40, 40, 60)
UI_TEXT = (215, 215, 250)
BTN_COLOR = (65, 95, 145)
BTN_HOVER = (85, 125, 185)
RADISH_BODY = (235, 115, 155)
RADISH_LVS = (95, 215, 95)
SLOW_CLR = (95, 195, 250)
EXPLODE = (255, 145, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
YELLOW = (255, 210, 30)
PURPLE = (180, 80, 220)
ORANGE = (255, 140, 40)
DARK_RED = (160, 40, 40)
CYAN = (0, 200, 255)
TREE_GREEN = (34, 139, 34)
TREE_DARK = (25, 100, 25)
ROCK_GRAY = (130, 130, 130)
FOCUS_CLR = (255, 50, 50)      # 集火标记颜色
FOCUS_LINE = (255, 80, 80, 120)  # 炮塔→目标连线

FPS = 60
clock = pygame.time.Clock()
font = pygame.font.Font(None, 24)
big_font = pygame.font.Font(None, 48)
title_font = pygame.font.Font(None, 72)

# ===== 10个关卡路径 =====
LEVELS = [
    [(50, 350), (250, 350), (250, 200), (500, 200),
     (500, 500), (750, 500), (750, 300), (920, 300)],
    [(50, 200), (300, 200), (300, 450), (550, 450),
     (550, 250), (800, 250), (800, 500), (920, 500)],
    [(50, 100), (350, 100), (350, 350), (650, 350), (650, 150), (920, 150)],
    [(50, 400), (200, 400), (200, 150), (700, 150), (700, 500), (920, 500)],
    [(50, 350), (350, 350), (350, 150), (650, 150),
     (650, 550), (450, 550), (450, 250), (920, 250)],
    [(50, 300), (300, 300), (300, 100), (700, 100),
     (700, 500), (300, 500), (300, 350), (920, 350)],
    [(50, 250), (250, 250), (450, 100), (450, 400),
     (650, 250), (850, 500), (920, 500)],
    [(50, 180), (200, 180), (200, 350), (400, 350), (400, 180),
     (600, 180), (600, 500), (850, 500), (850, 300), (920, 300)],
    [(50, 300), (200, 100), (400, 500), (600, 100), (800, 500), (920, 300)],
    [(50, 350), (200, 350), (200, 200), (400, 200), (400, 500),
     (600, 500), (600, 150), (800, 150), (800, 400), (920, 400)],
]

LEVEL_NAMES = [
    "新手村", "蜿蜒小径", "锯齿峡谷", "马蹄弯道",
    "螺旋迷宫", "回环之路", "闪电突袭", "蛇行险道",
    "群山峻岭", "终极决战",
]

# ===== 关卡状态 =====
current_level = 0
path = list(LEVELS[0])

# ===== 网格系统 =====
CELL = 50
cols = WIDTH // CELL
rows = (HEIGHT - 150) // CELL


def point_to_cell(px, py):
    return px // CELL, py // CELL


def cell_center(cx, cy):
    return cx * CELL + CELL // 2, cy * CELL + CELL // 2


def is_on_path(px, py, margin=28):
    for i in range(len(path) - 1):
        x1, y1 = path[i]
        x2, y2 = path[i+1]
        seg_len = math.sqrt((x2-x1)**2 + (y2-y1)**2)
        if seg_len == 0:
            continue
        t = max(0.0, min(1.0, ((px-x1)*(x2-x1) + (py-y1)*(y2-y1)) / (seg_len**2)))
        proj_x = x1 + t * (x2 - x1)
        proj_y = y1 + t * (y2 - y1)
        d = math.sqrt((px - proj_x)**2 + (py - proj_y)**2)
        if d < margin:
            return True
    return False


def is_near_radish(px, py, margin=45):
    rx, ry = path[-1]
    return math.sqrt((px - rx)**2 + (py - ry)**2) < margin


def is_near_tower(px, py, towers, margin=45):
    for t in towers:
        if math.sqrt((px - t.x)**2 + (py - t.y)**2) < margin:
            return True
    return False


def is_on_obstacle(px, py, obstacles, margin=25):
    for obs in obstacles:
        if not obs.active:
            continue
        if math.sqrt((px - obs.x)**2 + (py - obs.y)**2) < margin + obs.size:
            return True
    return False


def build_grid(towers, obstacles):
    grid = {}
    for cy in range(rows):
        for cx in range(cols):
            px, py = cell_center(cx, cy)
            if py >= HEIGHT - 150:
                grid[(cx, cy)] = "no"
                continue
            if is_on_path(px, py):
                grid[(cx, cy)] = "no"
            elif is_near_radish(px, py):
                grid[(cx, cy)] = "no"
            elif is_near_tower(px, py, towers):
                grid[(cx, cy)] = "no"
            elif is_on_obstacle(px, py, obstacles):
                grid[(cx, cy)] = "no"
            else:
                grid[(cx, cy)] = "ok"
    return grid


def draw_placement_grid(surface, grid, mouse_pos):
    mx, my = mouse_pos
    mouse_cell = (mx // CELL, my // CELL)
    for (cx, cy), status in grid.items():
        x = cx * CELL
        y = cy * CELL
        if status == "ok":
            s = pygame.Surface((CELL-2, CELL-2), pygame.SRCALPHA)
            s.fill((60, 140, 60, 70))
            surface.blit(s, (x+1, y+1))
            pygame.draw.rect(surface, (80, 180, 80, 120),
                             (x+1, y+1, CELL-2, CELL-2), 1)
            pygame.draw.circle(surface, (80, 220, 80),
                               (x+CELL//2, y+CELL//2), 3)
        else:
            s = pygame.Surface((CELL-2, CELL-2), pygame.SRCALPHA)
            s.fill((180, 60, 60, 40))
            surface.blit(s, (x+1, y+1))
            pygame.draw.rect(surface, (200, 80, 80, 80),
                             (x+1, y+1, CELL-2, CELL-2), 1)
        if mouse_cell == (cx, cy):
            if status == "ok":
                pygame.draw.rect(surface, YELLOW, (x, y, CELL, CELL), 3)
            else:
                pygame.draw.rect(surface, (255, 60, 60), (x, y, CELL, CELL), 3)


# ===== 游戏状态 =====
money = 150
health = 10
game_over = False
game_won = False
wave = 1
enemies_defeated = 0
enemies_per_wave = 15
spawn_timer = 0
spawn_delay = 40
selected_tower_type = None
tower_info_visible = False
info_tower = None
level_complete = False
total_score = 0
show_level_select = False

# ===== 集火系统 =====
focused_enemy = None  # 当前集火目标


def set_focus_enemy(enemy):
    """设置集火目标"""
    global focused_enemy
    focused_enemy = enemy


def clear_focus():
    """清除集火目标"""
    global focused_enemy
    focused_enemy = None


def get_focused_enemy():
    """获取当前有效的集火目标，无效则清除并返回None"""
    global focused_enemy
    if focused_enemy is None:
        return None
    # 目标已死、不活跃、或不在敌人列表中
    if (not focused_enemy.active or
        not hasattr(focused_enemy, 'health') or
        focused_enemy.health <= 0 or
            focused_enemy not in enemies):
        focused_enemy = None
        return None
    return focused_enemy


# ===== 炮塔类型 =====
TOWER_TYPES = {
    "basic":   {"name": "Basic",   "cost": 60,  "range": 150, "damage": 1,   "cooldown": 30, "color": TOWER_COLORS["basic"]},
    "sniper":  {"name": "Sniper",  "cost": 120, "range": 300, "damage": 3,   "cooldown": 60, "color": TOWER_COLORS["sniper"]},
    "machine": {"name": "Machine", "cost": 100, "range": 120, "damage": 0.5, "cooldown": 10, "color": TOWER_COLORS["machine"]},
    "cannon":  {"name": "Cannon",  "cost": 150, "range": 130, "damage": 2,   "cooldown": 40, "color": TOWER_COLORS["cannon"]},
    "freeze":  {"name": "Freeze",  "cost": 130, "range": 140, "damage": 0.2, "cooldown": 50, "color": TOWER_COLORS["freeze"]},
}

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


class Obstacle:
    def __init__(self, x, y, obs_type=None):
        self.x = x
        self.y = y
        if obs_type is None:
            r = random.random()
            if r < 0.5:
                obs_type = "small_tree"
            elif r < 0.8:
                obs_type = "big_tree"
            else:
                obs_type = "rock"
        self.obs_type = obs_type
        if obs_type == "small_tree":
            self.max_hp = 3
            self.reward = 10
            self.size = 18
            self.color = TREE_GREEN
        elif obs_type == "big_tree":
            self.max_hp = 6
            self.reward = 25
            self.size = 24
            self.color = TREE_DARK
        else:
            self.max_hp = 5
            self.reward = 15
            self.size = 20
            self.color = ROCK_GRAY
        self.hp = self.max_hp
        self.active = True

    def take_damage(self, dmg):
        self.hp -= dmg
        if self.hp <= 0:
            self.active = False
            return self.reward
        return 0

    def draw(self, s):
        if not self.active:
            return
        if self.obs_type == "small_tree":
            pygame.draw.line(
                s, (80, 50, 30), (self.x, self.y+10), (self.x, self.y-5), 4)
            pygame.draw.circle(s, self.color, (self.x, self.y-8), 14)
            pygame.draw.circle(s, (25, 110, 25), (self.x-5, self.y-12), 8)
            pygame.draw.circle(s, (25, 110, 25), (self.x+5, self.y-12), 8)
        elif self.obs_type == "big_tree":
            pygame.draw.line(
                s, (90, 55, 30), (self.x, self.y+14), (self.x, self.y-6), 6)
            pygame.draw.circle(s, self.color, (self.x, self.y-10), 20)
            pygame.draw.circle(s, (20, 90, 20), (self.x-8, self.y-16), 12)
            pygame.draw.circle(s, (20, 90, 20), (self.x+8, self.y-16), 12)
            pygame.draw.circle(s, (20, 90, 20), (self.x, self.y-22), 10)
        else:
            pygame.draw.circle(s, self.color, (self.x, self.y), self.size)
            pygame.draw.circle(s, (100, 100, 100),
                               (self.x-5, self.y-5), self.size-6)
            pygame.draw.circle(s, (160, 160, 160), (self.x-3, self.y-3), 4)
        if self.hp < self.max_hp:
            bw = 30
            pygame.draw.rect(s, HP_RED, (self.x-15, self.y-self.size-8, bw, 4))
            pygame.draw.rect(s, HP_GREEN, (self.x-15, self.y -
                             self.size-8, int(bw*self.hp/self.max_hp), 4))

# ===== Tower =====


class Tower:
    def __init__(self, x, y, tower_type):
        self.x = x
        self.y = y
        self.type = tower_type
        self.stats = TOWER_TYPES[tower_type]
        self.range = self.stats["range"]
        self.damage = self.stats["damage"]
        self.cooldown = 0
        self.cooldown_max = self.stats["cooldown"]
        self.cost = self.stats["cost"]
        self.level = 1
        self.color = self.stats["color"]
        self.gun_clr = (
            max(0, self.color[0]-50), max(0, self.color[1]-50), max(0, self.color[2]-50))
        self.total_invested = self.cost

    def upgrade_cost(self):
        return int(self.cost * 0.8 * self.level)

    def upgrade(self):
        self.level += 1
        self.damage *= 1.5
        self.range *= 1.08
        self.cooldown_max = max(5, int(self.cooldown_max * 0.92))

    def draw(self, s):
        pygame.draw.circle(s, self.color, (self.x, self.y), 20)
        darker = (max(0, self.color[0]-30), max(0,
                  self.color[1]-30), max(0, self.color[2]-30))
        pygame.draw.circle(s, darker, (self.x, self.y), 15)
        for i in range(self.level):
            sx = self.x - 8 + i * 8
            sy = self.y - 22
            pygame.draw.circle(s, YELLOW, (sx, sy), 3)
        if self.type == "basic":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-5, 25, 10))
        elif self.type == "sniper":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-3, 35, 6))
            pygame.draw.circle(s, (50, 50, 50), (self.x+40, self.y), 5)
        elif self.type == "machine":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-8, 25, 6))
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y+2, 25, 6))
        elif self.type == "cannon":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-7, 30, 14))
        elif self.type == "freeze":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-5, 25, 10))
            pygame.draw.circle(s, (195, 225, 255), (self.x+15, self.y), 8, 2)

    def find_target(self, enemies, obstacles):
        """
        核心AI：优先打集火目标（如果在射程内），否则正常选最近敌人。
        返回 (target, is_focus) 或 (None, False)
        """
        # 1. 检查集火目标
        focus = get_focused_enemy()
        if focus is not None:
            d = math.sqrt((self.x - focus.x)**2 + (self.y - focus.y)**2)
            if d <= self.range:
                # 集火目标在射程内 → 优先打
                return focus, True
            # 集火目标存在但不在射程 → 不打，等它走进来
            # 返回None让炮塔等（不浪费子弹打别的）
            return None, False

        # 2. 没有集火目标 → 正常逻辑：先打射程内障碍物，再打最近敌人
        for obs in obstacles:
            if not obs.active:
                continue
            d = math.sqrt((self.x - obs.x)**2 + (self.y - obs.y)**2)
            if d <= self.range:
                return obs, False

        best = None
        best_d = self.range + 1
        for e in enemies:
            if not e.active:
                continue
            if hasattr(e, 'stealth') and e.stealth and e.stealth_timer % 120 < 60:
                continue
            d = math.sqrt((self.x - e.x)**2 + (self.y - e.y)**2)
            if d < best_d:
                best_d = d
                best = e
        return best, False

    def update(self, enemies, obstacles):
        if self.cooldown > 0:
            self.cooldown -= 1
            return None

        target, is_focus = self.find_target(enemies, obstacles)
        if target is None:
            return None

        self.cooldown = self.cooldown_max

        # 判断目标是障碍物还是敌人
        if hasattr(target, 'take_damage'):
            return ObstacleBullet(self.x, self.y, target, self.damage, self.type)
        else:
            return Bullet(self.x, self.y, target, self.damage, self.type, is_focus)

# ===== Bullet =====


class Bullet:
    def __init__(self, x, y, target, damage, btype, is_focus=False):
        self.x = x
        self.y = y
        self.target = target
        self.speed = 8
        self.damage = damage
        self.active = True
        self.type = btype
        self.effect = None
        self.size = 5
        self.is_focus = is_focus
        if btype == "freeze":
            self.color = (100, 200, 255)
            self.effect = "slow"
            self.effect_duration = 180
        elif btype == "cannon":
            self.color = (255, 150, 0)
            self.size = 8
        elif btype == "machine":
            self.color = BULLET
            self.size = 3
        elif btype == "sniper":
            self.color = (150, 255, 150)
            self.size = 3
        else:
            self.color = BULLET

    def update(self):
        if not self.active:
            return False
        if not self.target or not self.target.active:
            self.active = False
            return False
        # 如果目标是集火目标但已超出射程，子弹继续追踪直到命中或丢失
        dx = self.target.x - self.x
        dy = self.target.y - self.y
        dist = math.sqrt(dx*dx + dy*dy)
        if dist < self.speed:
            if hasattr(self.target, 'take_damage'):
                reward = self.target.take_damage(self.damage)
                if reward > 0:
                    global money
                    money += reward
            else:
                self.target.health -= self.damage
                if hasattr(self.target, 'slow_duration') and self.effect == "slow":
                    self.target.slow_duration = self.effect_duration
                    self.target.speed = self.target.original_speed * 0.5
            self.active = False
            return True
        self.x += dx / dist * self.speed
        self.y += dy / dist * self.speed
        return False

    def draw(self, s):
        if self.type == "cannon":
            pygame.draw.circle(
                s, self.color, (int(self.x), int(self.y)), self.size)
            pygame.draw.circle(s, (255, 200, 100), (int(
                self.x), int(self.y)), max(1, self.size-3))
        else:
            pygame.draw.circle(
                s, self.color, (int(self.x), int(self.y)), self.size)
            pygame.draw.circle(s, (255, 255, 200), (int(
                self.x), int(self.y)), max(1, self.size-2))
        # 集火子弹画红色尾迹
        if self.is_focus:
            pygame.draw.circle(s, (255, 100, 100), (int(
                self.x), int(self.y)), self.size+2, 1)

# ===== ObstacleBullet =====


class ObstacleBullet(Bullet):
    def __init__(self, x, y, target, damage, btype):
        super().__init__(x, y, target, damage, btype, False)
        self.color = (200, 200, 200)

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


class Enemy:
    def __init__(self, p, wave, special=None):
        self.path = p
        self.path_index = 0
        self.x = p[0][0] if p else 50
        self.y = p[0][1] if p else 350
        self.wave = wave
        self.slow_duration = 0
        self.active = True
        self.max_health = 5
        self.health = 5
        self.speed = 1.0
        self.original_speed = 1.0
        self.reward = 10
        self.color = ENEMY_C
        self.type = "normal"
        self.boss = False

        try:
            base_hp = 5 + (wave - 1) * 2
            base_speed = 1.0 + (wave - 1) * 0.08
            base_reward = 10 + (wave - 1) * 2
            level_mult = 1.0 + current_level * 0.12

            if special == "boss" or (wave >= 10 and random.random() < 0.3):
                self.type = "boss"
                self.boss = True
                self.max_health = int(base_hp * 8 * level_mult)
                self.speed = max(0.35, base_speed * 0.5)
                self.reward = int(base_reward * 6)
                self.color = DARK_RED
                self.summon_timer = 0
            elif special == "stealth" and wave >= 4:
                self.type = "stealth"
                self.max_health = int(base_hp * 0.8 * level_mult)
                self.speed = base_speed * 1.3
                self.reward = int(base_reward * 1.5)
                self.color = PURPLE
                self.stealth = True
                self.stealth_timer = 0
            elif special == "bomber" and wave >= 5:
                self.type = "bomber"
                self.max_health = int(base_hp * 1.5 * level_mult)
                self.speed = base_speed * 0.9
                self.reward = int(base_reward * 2)
                self.color = ORANGE
                self.bomb_range = 80
            elif special == "flyer" and wave >= 6:
                self.type = "flyer"
                self.max_health = int(base_hp * 0.6 * level_mult)
                self.speed = base_speed * 2.0
                self.reward = int(base_reward * 1.8)
                self.color = CYAN
                self.fly_target = p[-1] if p else (920, 350)
            else:
                r = random.random()
                if r < 0.25:
                    self.type = "fast"
                    self.max_health = int(base_hp * 0.7 * level_mult)
                    self.speed = base_speed * 1.8
                    self.reward = int(base_reward * 1.3)
                    self.color = (220, 120, 120)
                elif r < 0.45:
                    self.type = "tank"
                    self.max_health = int(base_hp * 3.5 * level_mult)
                    self.speed = base_speed * 0.7
                    self.reward = int(base_reward * 1.8)
                    self.color = (180, 80, 80)
                else:
                    self.type = "normal"
                    self.max_health = int(base_hp * level_mult)
                    self.speed = base_speed
                    self.reward = base_reward
                    self.color = ENEMY_C
        except Exception:
            self.type = "normal"
            self.max_health = 5 + (wave - 1) * 2
            self.speed = 1.0 + (wave - 1) * 0.08
            self.reward = 10 + (wave - 1) * 2
            self.color = ENEMY_C
            self.boss = False

        # 终极兜底
        try:
            self.max_health = int(self.max_health)
        except Exception:
            self.max_health = 5
        self.health = self.max_health
        try:
            self.speed = float(self.speed)
        except Exception:
            self.speed = 1.0
        self.original_speed = self.speed
        try:
            self.reward = int(self.reward)
        except Exception:
            self.reward = 10
        self.active = True

    def update(self):
        if not self.active:
            return False
        if self.slow_duration > 0:
            self.slow_duration -= 1
            if self.slow_duration == 0 and hasattr(self, 'original_speed'):
                self.speed = self.original_speed

        if self.boss:
            self.summon_timer += 1

        if hasattr(self, 'stealth') and self.stealth:
            self.stealth_timer += 1

        if self.type == "flyer" and hasattr(self, 'fly_target'):
            tx, ty = self.fly_target
            dx = tx - self.x
            dy = ty - self.y
            dist = math.sqrt(dx*dx + dy*dy)
            if dist < self.speed:
                self.active = False
                return True
            self.x += dx / dist * self.speed
            self.y += dy / dist * self.speed
            return False

        if self.path_index >= len(self.path):
            self.active = False
            return True

        tx, ty = self.path[self.path_index]
        dx = tx - self.x
        dy = ty - self.y
        dist = math.sqrt(dx*dx + dy*dy)
        if dist < self.speed:
            self.path_index += 1
            if self.path_index >= len(self.path):
                self.active = False
                return True
            tx, ty = self.path[self.path_index]
            dx = tx - self.x
            dy = ty - self.y
            dist = math.sqrt(dx*dx + dy*dy)
        if dist > 0:
            self.x += dx / dist * self.speed
            self.y += dy / dist * self.speed
        return False

    def draw(self, s):
        # 集火标记：头顶红色靶心
        if get_focused_enemy() is not None and get_focused_enemy() is self:
            # 闪烁效果
            blink = (pygame.time.get_ticks() // 150) % 2 == 0
            if blink:
                pygame.draw.circle(
                    s, FOCUS_CLR, (int(self.x), int(self.y - 25)), 8, 2)
                pygame.draw.line(
                    s, FOCUS_CLR, (self.x-10, self.y-25), (self.x+10, self.y-25), 2)
                pygame.draw.line(
                    s, FOCUS_CLR, (self.x, self.y-35), (self.x, self.y-15), 2)

        if hasattr(self, 'stealth') and self.stealth:
            visible = (self.stealth_timer % 120) < 60
            if not visible:
                alpha_surf = pygame.Surface((30, 30), pygame.SRCALPHA)
                pygame.draw.circle(alpha_surf, (*self.color, 50), (15, 15), 15)
                s.blit(alpha_surf, (int(self.x)-15, int(self.y)-15))
                return

        pygame.draw.circle(s, self.color, (int(self.x), int(self.y)), 15)
        darker = (max(0, self.color[0]-40), max(0,
                  self.color[1]-40), max(0, self.color[2]-40))
        if self.type == "fast":
            pygame.draw.circle(s, darker, (int(self.x), int(self.y)), 10)
            pygame.draw.line(s, (255, 255, 200),
                             (self.x, self.y-15), (self.x, self.y-25), 2)
        elif self.type == "tank":
            pygame.draw.rect(s, darker, (self.x-12, self.y-5, 24, 10))
            pygame.draw.rect(s, darker, (self.x-5, self.y-12, 10, 24))
        elif self.type == "stealth":
            pygame.draw.circle(s, (200, 100, 240),
                               (int(self.x), int(self.y)), 10, 2)
        elif self.type == "bomber":
            pygame.draw.circle(s, (255, 200, 50),
                               (int(self.x), int(self.y)), 8)
            pygame.draw.circle(s, ORANGE, (int(self.x), int(self.y)), 12, 2)
        elif self.type == "flyer":
            pygame.draw.circle(s, (100, 220, 255),
                               (int(self.x)-5, int(self.y)-8), 5)
            pygame.draw.circle(s, (100, 220, 255),
                               (int(self.x)+5, int(self.y)-8), 5)
        elif self.type == "boss":
            pygame.draw.circle(
                s, (200, 50, 50), (int(self.x), int(self.y)), 18, 3)
            pygame.draw.polygon(s, YELLOW, [(self.x-8, self.y-20), (self.x-5, self.y-28),
                                (self.x, self.y-24), (self.x+5, self.y-28), (self.x+8, self.y-20)])
            pygame.draw.line(s, (80, 80, 80), (self.x-10,
                             self.y-15), (self.x-18, self.y-25), 3)
            pygame.draw.line(s, (80, 80, 80), (self.x+10,
                             self.y-15), (self.x+18, self.y-25), 3)
        else:
            pygame.draw.circle(s, darker, (int(self.x), int(self.y)), 10)

        # 血条
        bw = 60 if self.boss else 40
        by = self.y - 35 if self.boss else self.y - 30
        pygame.draw.rect(s, HP_RED, (self.x - bw//2, by, bw, 5))
        hp_w = max(0, int(bw * self.health / self.max_health))
        pygame.draw.rect(s, HP_GREEN, (self.x - bw//2, by, hp_w, 5))

        if self.slow_duration > 0:
            pygame.draw.circle(s, SLOW_CLR, (int(self.x), int(self.y)), 18, 2)

# ===== Explosion =====


class Explosion:
    def __init__(self, x, y, radius=30, color=None):
        self.x = x
        self.y = y
        self.radius = 5
        self.max_radius = radius
        self.growth = 2.0 if radius > 30 else 1.5
        self.active = True
        self.color = color if color else EXPLODE

    def update(self):
        self.radius += self.growth
        if self.radius > self.max_radius:
            self.active = False

    def draw(self, s):
        a = int(255 * (1 - self.radius / self.max_radius))
        surf = pygame.Surface(
            (self.max_radius*2, self.max_radius*2), pygame.SRCALPHA)
        pygame.draw.circle(
            surf, (*self.color, a), (self.max_radius, self.max_radius), int(self.radius), 3)
        pygame.draw.circle(surf, (255, 255, 200, a//2),
                           (self.max_radius, self.max_radius), int(self.radius/2), 2)
        s.blit(surf, (int(self.x - self.max_radius),
               int(self.y - self.max_radius)))


# ===== 游戏对象列表 =====
towers = []
bullets = []
enemies = []
explosions = []
obstacles = []

# ===== 生成障碍物 =====


def spawn_obstacles():
    global obstacles
    obstacles = []
    random.seed(current_level * 7 + 42)
    num_obstacles = 8 + current_level * 2
    attempts = 0
    while len(obstacles) < num_obstacles and attempts < 200:
        attempts += 1
        ox = random.randint(2, cols-2) * CELL + CELL//2
        oy = random.randint(1, rows-2) * CELL + CELL//2
        if is_on_path(ox, oy, margin=35):
            continue
        if is_near_radish(ox, oy, margin=60):
            continue
        too_close = False
        for o in obstacles:
            if math.sqrt((ox-o.x)**2 + (oy-o.y)**2) < 60:
                too_close = True
                break
        if too_close:
            continue
        obstacles.append(Obstacle(ox, oy))
    random.seed()

# ===== 绘图函数 =====


def draw_path_line():
    for i in range(len(path) - 1):
        pygame.draw.line(screen, PATH_COLOR, path[i], path[i+1], 40)
    pygame.draw.circle(screen, (115, 85, 55), path[0], 20)
    pygame.draw.circle(screen, (140, 110, 75), path[0], 14)


def draw_grass_bg():
    random.seed(42)
    for i in range(0, WIDTH, 40):
        for j in range(0, HEIGHT - 150, 40):
            if random.random() > 0.35:
                pygame.draw.line(screen, GRASS, (i, j), (i, j-14), 2)
    random.seed()


def draw_radish():
    x, y = path[-1]
    pygame.draw.ellipse(screen, RADISH_LVS, (x-24, y-68, 48, 38))
    ld = (max(0, RADISH_LVS[0]-20),
          max(0, RADISH_LVS[1]-20), max(0, RADISH_LVS[2]-20))
    pygame.draw.ellipse(screen, ld, (x-30, y-58, 28, 28))
    pygame.draw.ellipse(screen, ld, (x+2, y-58, 28, 28))
    pygame.draw.circle(screen, RADISH_BODY, (x, y), 30)
    rd = (max(0, RADISH_BODY[0]-40), max(0,
          RADISH_BODY[1]-40), max(0, RADISH_BODY[2]-40))
    pygame.draw.ellipse(screen, rd, (x-19, y-14, 38, 28))
    pygame.draw.circle(screen, WHITE, (x-10, y-5), 8)
    pygame.draw.circle(screen, WHITE, (x+10, y-5), 8)
    pygame.draw.circle(screen, BLACK, (x-10, y-5), 4)
    pygame.draw.circle(screen, BLACK, (x+10, y-5), 4)
    pygame.draw.arc(screen, (195, 75, 115), (x-10, y+2, 20, 14), 0, math.pi, 3)
    pygame.draw.rect(screen, HP_RED, (x-30, y-95, 60, 8))
    pygame.draw.rect(screen, HP_GREEN, (x-30, y-95, int(60 * health / 10), 8))


def draw_ui():
    ui_y = HEIGHT - 150
    pygame.draw.rect(screen, UI_BG, (0, 0, WIDTH, 48))
    pygame.draw.rect(screen, (50, 50, 70), (0, ui_y, WIDTH, 150))
    pygame.draw.line(screen, (80, 80, 100), (0, ui_y), (WIDTH, ui_y), 3)

    items = [
        f"Gold: {money}",
        f"HP: {health}",
        f"Level: {current_level+1}/10",
        f"Wave: {wave}",
        f"Killed: {enemies_defeated}",
    ]
    xs = [20, 150, 320, 530, 700]
    for txt, xp in zip(items, xs):
        t = font.render(txt, True, UI_TEXT)
        screen.blit(t, (xp, 14))

    # 集火状态显示
    focus = get_focused_enemy()
    if focus is not None:
        ft = font.render("FOCUS: " + focus.type.upper(), True, FOCUS_CLR)
        screen.blit(ft, (WIDTH//2 - ft.get_width()//2, 35))
        # 提示按右键取消
        ht = font.render("Right-click to cancel focus", True, (200, 200, 200))
        screen.blit(ht, (WIDTH//2 - ht.get_width()//2, 55))

    # 炮塔按钮
    label = font.render("Towers:", True, UI_TEXT)
    screen.blit(label, (20, ui_y + 15))
    bw, bh, sp = 145, 100, 18
    sx = 20
    for i, (tid, td) in enumerate(TOWER_TYPES.items()):
        x = sx + i * (bw + sp)
        y = ui_y + 42
        r = pygame.Rect(x, y, bw, bh)
        mp = pygame.mouse.get_pos()
        if selected_tower_type == tid:
            c = (max(0, td["color"][0]//2), max(0, td["color"]
                 [1]//2), max(0, td["color"][2]//2))
        elif r.collidepoint(mp):
            c = (max(0, int(td["color"][0]/1.2)), max(0,
                 int(td["color"][1]/1.2)), max(0, int(td["color"][2]/1.2)))
        else:
            c = td["color"]
        pygame.draw.rect(screen, c, r)
        bc = (max(0, c[0]//2), max(0, c[1]//2), max(0, c[2]//2))
        pygame.draw.rect(screen, bc, r, 3)
        nt = font.render(td["name"], True, WHITE)
        screen.blit(nt, (x + bw//2 - nt.get_width()//2, y + 8))
        ct = font.render(f"${td['cost']}", True, (255, 255, 180))
        screen.blit(ct, (x + bw//2 - ct.get_width()//2, y + 38))
        ic = (max(0, c[0]-50), max(0, c[1]-50), max(0, c[2]-50))
        pygame.draw.circle(screen, ic, (x + bw//2, y + 75), 14)
        if tid == "sniper":
            pygame.draw.rect(screen, (50, 50, 50),
                             (x + bw//2 + 4, y + 75 - 3, 18, 5))
        elif tid == "machine":
            pygame.draw.rect(screen, (50, 50, 50),
                             (x + bw//2 + 4, y + 75 - 7, 18, 5))
            pygame.draw.rect(screen, (50, 50, 50),
                             (x + bw//2 + 4, y + 75 + 2, 18, 5))
        elif tid == "cannon":
            pygame.draw.rect(screen, (50, 50, 50),
                             (x + bw//2 + 4, y + 75 - 6, 22, 12))
        elif tid == "freeze":
            pygame.draw.circle(screen, (195, 225, 255),
                               (x + bw//2, y + 75), 9, 2)


def draw_tower_info_panel():
    if not tower_info_visible or not info_tower:
        return
    pw, ph = 340, 300
    px, py = WIDTH//2 - pw//2, HEIGHT//2 - ph//2
    surf = pygame.Surface((pw, ph), pygame.SRCALPHA)
    surf.fill((30, 30, 55, 235))
    pygame.draw.rect(surf, (100, 100, 150), (0, 0, pw, ph), 3)

    t = font.render(
        f"{TOWER_TYPES[info_tower.type]['name']} Lv.{info_tower.level}", True, (255, 255, 200))
    surf.blit(t, (pw//2 - t.get_width()//2, 15))

    stats = [
        f"Damage:  {info_tower.damage:.1f}",
        f"Range:   {info_tower.range:.0f}",
        f"Speed:   {60/(max(1,info_tower.cooldown_max)/60):.1f}/s",
        f"Invested: ${info_tower.total_invested}",
    ]
    for i, s in enumerate(stats):
        lt = font.render(s, True, UI_TEXT)
        surf.blit(lt, (25, 50 + i * 28))

    up_cost = info_tower.upgrade_cost()
    if info_tower.level < 5 and money >= up_cost:
        pygame.draw.rect(surf, (60, 140, 60), (40, 180, 120, 35))
        ut = font.render(f"Upgrade ${up_cost}", True, WHITE)
        surf.blit(ut, (100 - ut.get_width()//2, 190))
    elif info_tower.level >= 5:
        ut = font.render("MAX LEVEL", True, YELLOW)
        surf.blit(ut, (100 - ut.get_width()//2, 195))
    else:
        pygame.draw.rect(surf, (80, 80, 80), (40, 180, 120, 35))
        ut = font.render(f"Need ${up_cost}", True, (150, 150, 150))
        surf.blit(ut, (100 - ut.get_width()//2, 190))

    refund = int(info_tower.total_invested * 0.6)
    pygame.draw.rect(surf, (160, 60, 60), (180, 180, 120, 35))
    dt = font.render(f"Sell +${refund}", True, WHITE)
    surf.blit(dt, (240 - dt.get_width()//2, 190))

    pygame.draw.rect(surf, (180, 75, 75), (pw - 50, 10, 40, 22))
    xt = font.render("X", True, WHITE)
    surf.blit(xt, (pw - 37, 13))

    screen.blit(surf, (px, py))


def draw_level_select():
    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
    overlay.fill((0, 0, 0, 200))
    screen.blit(overlay, (0, 0))

    t = title_font.render("选择关卡", True, (100, 220, 100))
    screen.blit(t, (WIDTH//2 - t.get_width()//2, 80))

    t2 = font.render(f"Total Score: {total_score}", True, YELLOW)
    screen.blit(t2, (WIDTH//2 - t2.get_width()//2, 160))

    card_w, card_h = 160, 100
    cols_per_row = 5
    start_x = WIDTH//2 - (cols_per_row * (card_w + 20)) // 2
    start_y = 220

    for i in range(10):
        row = i // cols_per_row
        col = i % cols_per_row
        cx = start_x + col * (card_w + 20)
        cy = start_y + row * (card_h + 20)
        r = pygame.Rect(cx, cy, card_w, card_h)
        mp = pygame.mouse.get_pos()
        if r.collidepoint(mp):
            c = (80, 120, 80)
        else:
            c = (60, 90, 60)
        pygame.draw.rect(screen, c, r)
        pygame.draw.rect(screen, (100, 200, 100), r, 3)
        nt = font.render(f"Lv.{i+1} {LEVEL_NAMES[i]}", True, WHITE)
        screen.blit(nt, (cx + card_w//2 - nt.get_width()//2, cy + 20))
        waves = 5 + i
        wt = font.render(f"{waves} waves", True, (200, 200, 200))
        screen.blit(wt, (cx + card_w//2 - wt.get_width()//2, cy + 50))
        monsters = "Normal"
        if i >= 1:
            monsters += "+Fast"
        if i >= 2:
            monsters += "+Tank"
        if i >= 3:
            monsters += "+Stealth"
        if i >= 4:
            monsters += "+Bomber"
        if i >= 5:
            monsters += "+Flyer"
        if i >= 6:
            monsters += "+Boss"
        mt = font.render(monsters[:20], True, (180, 220, 180))
        screen.blit(mt, (cx + card_w//2 - mt.get_width()//2, cy + 75))

    bx, by = WIDTH//2 - 100, HEIGHT - 100
    br = pygame.Rect(bx, by, 200, 50)
    mp = pygame.mouse.get_pos()
    if br.collidepoint(mp):
        pygame.draw.rect(screen, BTN_HOVER, br)
    else:
        pygame.draw.rect(screen, BTN_COLOR, br)
    pygame.draw.rect(screen, BTN_HOVER, br, 2)
    bt = font.render("返回标题", True, WHITE)
    screen.blit(bt, (bx + 100 - bt.get_width()//2, by + 15))


def draw_level_complete():
    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
    overlay.fill((0, 0, 0, 160))
    screen.blit(overlay, (0, 0))
    if current_level >= 9:
        txt = big_font.render("YOU WIN! 终极胜利!", True, (100, 255, 100))
    else:
        txt = big_font.render(
            f"Level {current_level+1} Clear!", True, (100, 255, 100))
    screen.blit(txt, (WIDTH//2 - txt.get_width()//2, HEIGHT//2 - 80))
    st = font.render(
        f"Score: {total_score + enemies_defeated * 10 + money}", True, YELLOW)
    screen.blit(st, (WIDTH//2 - st.get_width()//2, HEIGHT//2 - 20))
    if current_level >= 9:
        rt = font.render("Press R to Play Again", True, (200, 200, 255))
    else:
        rt = font.render("Press N for Next Level", True, (200, 200, 255))
    screen.blit(rt, (WIDTH//2 - rt.get_width()//2, HEIGHT//2 + 30))


def draw_game_over_screen():
    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
    overlay.fill((0, 0, 0, 185))
    screen.blit(overlay, (0, 0))
    txt = big_font.render("Game Over! Radish eaten!", True, (250, 95, 95))
    screen.blit(txt, (WIDTH//2 - txt.get_width()//2, HEIGHT//2 - 60))
    rt = font.render("Press R to Restart Level", True, (195, 200, 250))
    screen.blit(rt, (WIDTH//2 - rt.get_width()//2, HEIGHT//2 + 10))
    lt = font.render("Press L for Level Select", True, (195, 200, 250))
    screen.blit(lt, (WIDTH//2 - lt.get_width()//2, HEIGHT//2 + 50))


def draw_start_screen():
    screen.fill((20, 38, 20))
    tt = title_font.render("Radish Defense", True, (95, 215, 95))
    screen.blit(tt, (WIDTH//2 - tt.get_width()//2, 130))

    pygame.draw.circle(screen, RADISH_BODY, (WIDTH//2, 280), 60)
    rd = (max(0, RADISH_BODY[0]-40), max(0,
          RADISH_BODY[1]-40), max(0, RADISH_BODY[2]-40))
    pygame.draw.ellipse(screen, rd, (WIDTH//2-40, 330, 80, 50))
    pygame.draw.circle(screen, WHITE, (WIDTH//2-20, 340), 15)
    pygame.draw.circle(screen, WHITE, (WIDTH//2+20, 345), 15)
    pygame.draw.circle(screen, BLACK, (WIDTH//2-20, 342), 7)
    pygame.draw.circle(screen, BLACK, (WIDTH//2+20, 352), 7)
    pygame.draw.arc(screen, (195, 75, 115),
                    (WIDTH//2-20, 370, 40, 30), 0, math.pi, 5)
    pygame.draw.ellipse(screen, RADISH_LVS, (WIDTH//2-40, 268, 80, 60))
    ld = (max(0, RADISH_LVS[0]-20),
          max(0, RADISH_LVS[1]-20), max(0, RADISH_LVS[2]-20))
    pygame.draw.ellipse(screen, ld, (WIDTH//2-60, 298, 40, 40))
    pygame.draw.ellipse(screen, ld, (WIDTH//2+20, 328, 40, 40))

    # Start按钮
    bx, by, bw, bh = WIDTH//2-100, 450, 200, 60
    br = pygame.Rect(bx, by, bw, bh)
    mp = pygame.mouse.get_pos()
    if br.collidepoint(mp):
        pygame.draw.rect(screen, BTN_HOVER, br)
    else:
        pygame.draw.rect(screen, BTN_COLOR, br)
    pygame.draw.rect(screen, BTN_HOVER, br, 3)
    stxt = big_font.render("Start", True, WHITE)
    screen.blit(stxt, (WIDTH//2 - stxt.get_width()//2, by + 13))

    # 选关按钮
    bx2, by2 = WIDTH//2-100, 530
    br2 = pygame.Rect(bx2, by2, 200, 50)
    if br2.collidepoint(mp):
        pygame.draw.rect(screen, (80, 130, 80), br2)
    else:
        pygame.draw.rect(screen, (60, 110, 60), br2)
    pygame.draw.rect(screen, (100, 200, 100), br2, 2)
    lt = font.render("选择关卡", True, WHITE)
    screen.blit(lt, (WIDTH//2 - lt.get_width()//2, by2 + 14))

    tips = [
        "10个关卡全部开放，自由选择！",
        "左键点怪物 → 所有炮塔集火！",
        "右键点击 → 取消集火目标",
        "左键点炮塔 → 升级/出售",
        "打掉树木障碍物 → 获得金币+空位",
    ]
    for i, tip in enumerate(tips):
        t = font.render(tip, True, (195, 215, 195))
        screen.blit(t, (WIDTH//2 - t.get_width()//2, 610 + i * 24))


def draw_focus_lines():
    """绘制炮塔→集火目标的红色连线"""
    focus = get_focused_enemy()
    if focus is None:
        return
    for t in towers:
        d = math.sqrt((t.x - focus.x)**2 + (t.y - focus.y)**2)
        if d <= t.range:
            # 在射程内 → 红色实线
            alpha_surf = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            pygame.draw.line(alpha_surf, (255, 50, 50, 80),
                             (t.x, t.y), (focus.x, focus.y), 2)
            screen.blit(alpha_surf, (0, 0))
            # 瞄准圈
            pygame.draw.circle(screen, (255, 80, 80),
                               (int(focus.x), int(focus.y)), 18, 1)
        else:
            # 不在射程 → 灰色虚线提示
            alpha_surf = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            pygame.draw.line(alpha_surf, (150, 150, 150, 50),
                             (t.x, t.y), (focus.x, focus.y), 1)
            screen.blit(alpha_surf, (0, 0))


def reset_level():
    global money, health, wave, enemies_defeated, towers, bullets
    global enemies, explosions, obstacles, spawn_timer
    global tower_info_visible, info_tower, level_complete, game_over, game_won
    global focused_enemy
    money = 150 + current_level * 30
    health = 10
    wave = 1
    enemies_defeated = 0
    towers = []
    bullets = []
    enemies = []
    explosions = []
    obstacles = []
    spawn_timer = 0
    tower_info_visible = False
    info_tower = None
    level_complete = False
    game_over = False
    game_won = False
    focused_enemy = None
    path = list(LEVELS[current_level])
    spawn_obstacles()


def next_level():
    global current_level, total_score
    total_score += enemies_defeated * 10 + money
    if current_level < 9:
        current_level += 1
    reset_level()


def restart_game():
    global current_level, total_score
    current_level = 0
    total_score = 0
    reset_level()


def go_to_level(lv):
    global current_level
    current_level = max(0, min(9, lv))
    reset_level()


# ===== 主循环 =====
running = True
start_screen = True

while running:
    mouse_pos = pygame.mouse.get_pos()

    for ev in pygame.event.get():
        if ev.type == pygame.QUIT:
            running = False

        elif ev.type == pygame.MOUSEBUTTONDOWN:
            mx, my = ev.pos

            if start_screen:
                bx, by, bw, bh = WIDTH//2-100, 450, 200, 60
                if bx <= mx <= bx+bw and by <= my <= by+bh:
                    start_screen = False
                    go_to_level(0)
                    continue
                bx2, by2, bw2, bh2 = WIDTH//2-100, 530, 200, 50
                if bx2 <= mx <= bx2+bw2 and by2 <= my <= by2+bh2:
                    start_screen = False
                    show_level_select = True
                    continue

            elif show_level_select:
                card_w, card_h = 160, 100
                cols_per_row = 5
                start_x = WIDTH//2 - (cols_per_row * (card_w + 20)) // 2
                start_y = 220
                for i in range(10):
                    row = i // cols_per_row
                    col = i % cols_per_row
                    cx = start_x + col * (card_w + 20)
                    cy = start_y + row * (card_h + 20)
                    if cx <= mx <= cx+card_w and cy <= my <= cy+card_h:
                        show_level_select = False
                        go_to_level(i)
                        break
                bx, by = WIDTH//2-100, HEIGHT-100
                if bx <= mx <= bx+200 and by <= my <= by+50:
                    show_level_select = False
                    start_screen = True
                continue

            if game_over:
                continue

            if level_complete:
                if current_level < 9:
                    next_level()
                else:
                    restart_game()
                continue

            # ===== 右键：取消集火 =====
            if ev.button == 3:
                if get_focused_enemy() is not None:
                    clear_focus()
                    continue
                # 右键点击炮塔 → 快速出售
                for t in towers:
                    if math.sqrt((mx - t.x)**2 + (my - t.y)**2) < 22:
                        refund = int(t.total_invested * 0.6)
                        money += refund
                        towers.remove(t)
                        if info_tower is t:
                            tower_info_visible = False
                            info_tower = None
                        break
                continue

            # ===== 左键 =====
            if ev.button == 1:
                # 关闭信息面板
                if tower_info_visible:
                    px, py = WIDTH//2-170, HEIGHT//2-150
                    if px+290 <= mx <= px+330 and py+10 <= my <= py+32:
                        tower_info_visible = False
                        continue
                    if px+40 <= mx <= px+160 and py+180 <= my <= py+215:
                        if info_tower and money >= info_tower.upgrade_cost() and info_tower.level < 5:
                            money -= info_tower.upgrade_cost()
                            info_tower.upgrade()
                        continue
                    if px+180 <= mx <= px+300 and py+180 <= my <= py+215:
                        refund = int(info_tower.total_invested * 0.6)
                        money += refund
                        towers.remove(info_tower)
                        tower_info_visible = False
                        info_tower = None
                        continue

                ui_y = HEIGHT - 150

                # 点击UI炮塔按钮
                if my >= ui_y:
                    bw2, sp = 145, 18
                    sx = 20
                    for i, tid in enumerate(TOWER_TYPES.keys()):
                        bx2 = sx + i * (bw2 + sp)
                        by2 = ui_y + 42
                        if bx2 <= mx <= bx2+bw2 and by2 <= my <= by2+100:
                            if money >= TOWER_TYPES[tid]["cost"]:
                                selected_tower_type = tid
                            break
                    continue

                # ===== 核心：左键点击怪物 → 设为集火目标 =====
                hit_enemy = None
                for e in enemies:
                    if not e.active:
                        continue
                    d = math.sqrt((mx - e.x)**2 + (my - e.y)**2)
                    if d < 18:  # 点击容差
                        hit_enemy = e
                        break

                if hit_enemy is not None:
                    set_focus_enemy(hit_enemy)
                    selected_tower_type = None  # 取消放置模式
                    tower_info_visible = False
                    continue

                # 点击已有炮塔 → 信息面板
                tower_clicked = False
                for t in towers:
                    if math.sqrt((mx - t.x)**2 + (my - t.y)**2) < 22:
                        tower_info_visible = True
                        info_tower = t
                        selected_tower_type = None
                        tower_clicked = True
                        break
                if tower_clicked:
                    continue

                # 点击地图放置炮塔
                if selected_tower_type and my < ui_y:
                    grid = build_grid(towers, obstacles)
                    cell = point_to_cell(mx, my)
                    if grid.get(cell) == "ok":
                        cx, cy = cell_center(*cell)
                        if (not is_on_path(cx, cy) and
                            not is_near_radish(cx, cy) and
                            not is_near_tower(cx, cy, towers) and
                                not is_on_obstacle(cx, cy, obstacles)):
                            cost = TOWER_TYPES[selected_tower_type]["cost"]
                            if money >= cost:
                                towers.append(
                                    Tower(cx, cy, selected_tower_type))
                                money -= cost
                                selected_tower_type = None

        elif ev.type == pygame.KEYDOWN:
            if ev.key == pygame.K_r:
                if game_over or (current_level >= 9 and level_complete):
                    restart_game()
                else:
                    reset_level()
            if ev.key == pygame.K_n and level_complete and current_level < 9:
                next_level()
            if ev.key == pygame.K_l:
                show_level_select = True
                game_over = False
                level_complete = False
            if ev.key == pygame.K_ESCAPE:
                if tower_info_visible:
                    tower_info_visible = False
                elif selected_tower_type:
                    selected_tower_type = None
                elif get_focused_enemy() is not None:
                    clear_focus()
                elif show_level_select:
                    show_level_select = False
                    start_screen = True
                else:
                    show_level_select = True

    # ===== 更新逻辑 =====
    if start_screen:
        draw_start_screen()
        pygame.display.flip()
        clock.tick(FPS)
        continue

    if show_level_select:
        draw_level_select()
        pygame.display.flip()
        clock.tick(FPS)
        continue

    if not game_over and not level_complete:
        # 刷怪
        spawn_timer += 1
        total_this_wave = wave * enemies_per_wave
        max_on_screen = 8 + wave * 2

        if spawn_timer >= spawn_delay and len(enemies) < max_on_screen and enemies_defeated < total_this_wave:
            special = None
            r = random.random()
            if current_level >= 6 and wave >= 5 and r < 0.15:
                special = "boss"
            elif current_level >= 3 and wave >= 4 and r < 0.3:
                available = []
                if wave >= 4:
                    available.append("stealth")
                if wave >= 5:
                    available.append("bomber")
                if wave >= 6:
                    available.append("flyer")
                if available:
                    special = random.choice(available)
            enemies.append(Enemy(path, wave, special))
            spawn_timer = 0

        # 敌人更新
        for e in enemies[:]:
            if not hasattr(e, 'health') or not hasattr(e, 'active'):
                enemies.remove(e)
                continue
            if not e.active:
                enemies.remove(e)
                continue
            try:
                reached = e.update()
            except Exception:
                e.active = False
                enemies.remove(e)
                continue

            if reached:
                health -= 1
                enemies.remove(e)
                if health <= 0:
                    game_over = True
            elif hasattr(e, 'health') and e.health <= 0:
                if e.type == "bomber":
                    for t in towers[:]:
                        if math.sqrt((e.x - t.x)**2 + (e.y - t.y)**2) < e.bomb_range:
                            towers.remove(t)
                            money = max(0, money - 20)
                            explosions.append(Explosion(t.x, t.y, 40, ORANGE))
                    explosions.append(Explosion(e.x, e.y, 60, (255, 100, 0)))
                else:
                    explosions.append(Explosion(e.x, e.y))
                money += e.reward
                enemies_defeated += 1
                enemies.remove(e)
                if hasattr(e, 'boss') and e.boss:
                    money += 200
                    explosions.append(Explosion(e.x, e.y, 100, DARK_RED))

            # Boss召唤
            if hasattr(e, 'boss') and e.boss and hasattr(e, 'summon_timer'):
                if e.summon_timer >= 180:
                    e.summon_timer = 0
                    for _ in range(2):
                        minion = Enemy(path, wave, None)
                        minion.x = e.x + random.randint(-30, 30)
                        minion.y = e.y + random.randint(-30, 30)
                        minion.max_health = max(2, minion.max_health // 3)
                        minion.health = minion.max_health
                        minion.reward = max(5, minion.reward // 3)
                        minion.type = "fast"
                        minion.color = (180, 80, 80)
                        enemies.append(minion)

        # 集火目标死亡/失效 → 自动清除（炮塔恢复自行射击）
        get_focused_enemy()  # 内部会自动清除无效目标

        # 炮塔射击
        for t in towers:
            b = t.update(enemies, obstacles)
            if b:
                bullets.append(b)

        # 子弹更新
        for b in bullets[:]:
            try:
                b.update()
            except Exception:
                pass
            if not b.active and b in bullets:
                bullets.remove(b)

        # 障碍物清理
        for obs in obstacles[:]:
            if not obs.active:
                obstacles.remove(obs)

        # 爆炸更新
        for ex in explosions[:]:
            ex.update()
            if not ex.active:
                explosions.remove(ex)

        # 波次/关卡推进
        total_this_wave = wave * enemies_per_wave
        if enemies_defeated >= total_this_wave and len(enemies) == 0:
            wave += 1
            money += 80 + current_level * 20
            if wave > (5 + current_level):
                level_complete = True

    # ===== 绘制 =====
    screen.fill(BG)

    grid = build_grid(towers, obstacles)
    draw_placement_grid(screen, grid, mouse_pos)

    draw_grass_bg()
    draw_path_line()

    for obs in obstacles:
        obs.draw(screen)

    draw_radish()

    # 选中炮塔预览
    if selected_tower_type:
        mx, my = mouse_pos
        cell = point_to_cell(mx, my)
        cx, cy = cell_center(*cell)
        gstatus = grid.get(cell, "no")
        if gstatus == "ok":
            r = TOWER_TYPES[selected_tower_type]["range"]
            s2 = pygame.Surface((r*2, r*2), pygame.SRCALPHA)
            pygame.draw.circle(s2, (80, 200, 80, 40), (r, r), r, 0)
            pygame.draw.circle(s2, (80, 255, 80, 100), (r, r), r, 2)
            screen.blit(s2, (cx - r, cy - r))
            tc = TOWER_TYPES[selected_tower_type]["color"]
            pygame.draw.circle(screen, tc, (cx, cy), 20)
            pygame.draw.circle(
                screen, (max(0, tc[0]-30), max(0, tc[1]-30), max(0, tc[2]-30)), (cx, cy), 15)
        else:
            pygame.draw.line(screen, (255, 60, 60),
                             (cx-12, cy-12), (cx+12, cy+12), 4)
            pygame.draw.line(screen, (255, 60, 60),
                             (cx+12, cy-12), (cx-12, cy+12), 4)

    # 集火连线（炮塔→目标）
    draw_focus_lines()

    # 炮塔
    for t in towers:
        t.draw(screen)
        if math.sqrt((mouse_pos[0]-t.x)**2 + (mouse_pos[1]-t.y)**2) < 25:
            s3 = pygame.Surface((t.range*2, t.range*2), pygame.SRCALPHA)
            pygame.draw.circle(s3, (80, 130, 255, 25),
                               (t.range, t.range), t.range, 0)
            pygame.draw.circle(s3, (80, 160, 255, 80),
                               (t.range, t.range), t.range, 1)
            screen.blit(s3, (t.x - t.range, t.y - t.range))

    # 子弹
    for b in bullets:
        b.draw(screen)

    # 敌人
    for e in enemies:
        try:
            e.draw(screen)
        except Exception:
            pass

    # 爆炸
    for ex in explosions:
        ex.draw(screen)

    # UI
    draw_ui()
    draw_tower_info_panel()

    if level_complete:
        draw_level_complete()
    elif game_over:
        draw_game_over_screen()

    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()
sys.exit()
