import pygame
import sys
import math
import random
import time as pytime

# ── 初始化 ──────────────────────────────────────
pygame.init()
pygame.mixer.init()
WIDTH, HEIGHT = 1024, 720
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("015. 俯视角射击 — 捡装备版")
clock = pygame.time.Clock()

# ── 颜色 ─────────────────────────────────────────
WHITE   = (255, 255, 255)
BLACK   = (0, 0, 0)
RED     = (220, 50, 50)
GREEN   = (50, 200, 80)
BLUE    = (60, 120, 220)
GRAY    = (180, 180, 185)
DARK    = (20, 20, 30)
YELLOW  = (255, 220, 50)
ORANGE  = (255, 140, 20)
PURPLE  = (180, 80, 220)
CYAN    = (50, 220, 220)

# ── 点阵数字 ─────────────────────────────────────
DIGITS_MAP = {
    '0': [0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110],
    '1': [0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110],
    '2': [0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111],
    '3': [0b01110, 0b10001, 0b00001, 0b00110, 0b00001, 0b10001, 0b01110],
    '4': [0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010],
    '5': [0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110],
    '6': [0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110],
    '7': [0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000],
    '8': [0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110],
    '9': [0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100],
    ':': [0b00000, 0b00100, 0b00000, 0b00000, 0b00000, 0b00100, 0b00000],
    '-': [0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000],
}

def make_text(text, size=40, color=WHITE):
    text = str(text)
    scale = size // 8
    char_w = 5 * scale
    char_h = 7 * scale
    gap = 2
    total_w = len(text) * (char_w + gap)
    img = pygame.Surface((total_w, char_h), pygame.SRCALPHA)
    for idx, ch in enumerate(text):
        pat = DIGITS_MAP.get(ch, DIGITS_MAP['0'])
        for row in range(7):
            bits = pat[row]
            for col in range(5):
                if bits & (1 << (4 - col)):
                    px = idx * (char_w + gap) + col * scale
                    py = row * scale
                    for dx in range(scale):
                        for dy in range(scale):
                            if 0 <= px+dx < total_w and 0 <= py+dy < char_h:
                                img.set_at((px+dx, py+dy), color)
    return img

# ════════════════════════════════════════════════
# 装备系统
# ════════════════════════════════════════════════
EQUIP_TYPES = {
    'heal':     {'name':'治疗','color':GREEN, 'icon':'♥'},
    'shield':   {'name':'护盾','color':BLUE,  'icon':'♦'},
    'speed':    {'name':'加速','color':CYAN,  'icon':'▶'},
    'damage':   {'name':'强攻','color':RED,   'icon':'★'},
    'spread':   {'name':'散射','color':PURPLE,'icon':'✿'},
}

class Equipment:
    def __init__(self, x, y, etype=None):
        self.x, self.y = x, y
        self.type = etype if etype else random.choice(list(EQUIP_TYPES.keys()))
        self.info = EQUIP_TYPES[self.type]
        self.r = 16
        self.alive = True
        self.bob_offset = random.uniform(0, math.pi * 2)
        self.lifetime = 600  # 帧数后消失
        self.age = 0

    def update(self):
        self.age += 1
        self.bob_offset += 0.05
        if self.age > self.lifetime:
            self.alive = False

    def draw(self, surf):
        if not self.alive: return
        bob_y = math.sin(self.bob_offset) * 4
        x, y = int(self.x), int(self.y + bob_y)
        r = self.r
        
        # 发光效果
        glow_r = r + 4 + int(math.sin(self.bob_offset * 2) * 2)
        pygame.draw.circle(surf, (*self.info['color'][:3], 60), (x, y), glow_r)
        
        # 外圈
        pygame.draw.circle(surf, WHITE, (x, y), r, 2)
        pygame.draw.circle(surf, self.info['color'], (x, y), r - 2)
        
        # 图标
        icon = make_text(self.info['icon'], 20, WHITE)
        surf.blit(icon, (x - icon.get_width()//2, y - icon.get_height()//2))
        
        # 名字标签
        name = make_text(self.info['name'], 14, self.info['color'])
        surf.blit(name, (x - name.get_width()//2, y - r - 14))

    def rect(self):
        return pygame.Rect(self.x - self.r, self.y - self.r, self.r*2, self.r*2)

    def apply(self, tank):
        """对坦克应用装备效果"""
        if self.type == 'heal':
            tank.hp = min(tank.max_hp, tank.hp + 2)
            tank.equip_effect = ('治疗 +2 HP', GREEN, 60)
        elif self.type == 'shield':
            tank.shield = min(3, tank.shield + 1)
            tank.equip_effect = ('护盾 +1', BLUE, 60)
        elif self.type == 'speed':
            tank.speed_bonus = min(3, tank.speed_bonus + 0.5)
            tank.equip_effect = ('加速 +0.5', CYAN, 60)
        elif self.type == 'damage':
            tank.damage_bonus = min(3, tank.damage_bonus + 1)
            tank.equip_effect = ('伤害 +1', RED, 60)
        elif self.type == 'spread':
            tank.spread_level = min(3, tank.spread_level + 1)
            tank.equip_effect = ('散射 +1', PURPLE, 60)

# ════════════════════════════════════════════════
# 玩家坦克（增强版）
# ════════════════════════════════════════════════
class Tank:
    def __init__(self):
        self.x, self.y = WIDTH//2, HEIGHT//2
        self.size = 26; self.base_speed = 4.5; self.angle = 0
        self.hp = 6; self.max_hp = 6
        self.shield = 0
        self.speed_bonus = 0
        self.damage_bonus = 0
        self.spread_level = 0
        self.cooldown = 0; self.cd_max = 14
        
        self.equip_effect = None  # (text, color, timer)
        self.invincible_timer = 0

    @property
    def speed(self):
        return self.base_speed + self.speed_bonus * 0.8

    def move(self, dx, dy):
        self.x = max(self.size, min(WIDTH-self.size, self.x+dx))
        self.y = max(self.size, min(HEIGHT-self.size, self.y+dy))

    def aim(self, mx, my): self.angle = math.atan2(my-self.y, mx-self.x)

    def shoot(self):
        if self.cooldown > 0: return []
        self.cooldown = self.cd_max
        
        bullets = []
        base_dmg = 1 + self.damage_bonus
        
        if self.spread_level == 0:
            bullets.append(Bullet(self.x, self.y, self.angle, base_dmg))
        elif self.spread_level == 1:
            for ang in [self.angle - 0.12, self.angle, self.angle + 0.12]:
                bullets.append(Bullet(self.x, self.y, ang, base_dmg))
        elif self.spread_level == 2:
            for ang in [self.angle - 0.2, self.angle - 0.07, self.angle, self.angle + 0.07, self.angle + 0.2]:
                bullets.append(Bullet(self.x, self.y, ang, base_dmg))
        else:
            for ang in [self.angle - 0.25, self.angle - 0.12, self.angle, self.angle + 0.12, self.angle + 0.25]:
                bullets.append(Bullet(self.x, self.y, ang, base_dmg + 1))
        
        return bullets

    def take_damage(self, dmg=1):
        if self.invincible_timer > 0: return False
        if self.shield > 0:
            self.shield -= 1
            self.invincible_timer = 15
            self.equip_effect = ('护盾抵消!', BLUE, 30)
            return False
        self.hp -= dmg
        self.invincible_timer = 20
        if self.hp <= 0: return True
        return False

    def update(self):
        if self.cooldown > 0: self.cooldown -= 1
        if self.invincible_timer > 0: self.invincible_timer -= 1
        if self.equip_effect:
            t, c, dur = self.equip_effect
            if dur > 0:
                self.equip_effect = (t, c, dur - 1)
            else:
                self.equip_effect = None

    def draw(self, surf):
        x, y, s = int(self.x), int(self.y), self.size
        
        # 闪烁（无敌时）
        if self.invincible_timer > 0 and self.invincible_timer % 4 < 2:
            return
        
        # 底盘
        pygame.draw.circle(surf, (50, 120, 50), (x, y), s)
        
        # 护盾光环
        if self.shield > 0:
            pygame.draw.circle(surf, (60, 140, 255, 80), (x, y), s + 6, 3)
        
        # 炮管
        ex = x + math.cos(self.angle) * s * 1.6
        ey = y + math.sin(self.angle) * s * 1.6
        pygame.draw.line(surf, DARK, (x, y), (ex, ey), 7)
        
        # 炮塔
        pygame.draw.circle(surf, GREEN, (x, y), s - 6)
        
        # 装备标记
        if self.spread_level > 0:
            pygame.draw.circle(surf, PURPLE, (x, y), s - 10, 2)
        if self.damage_bonus > 0:
            pygame.draw.circle(surf, RED, (x, y), s - 14, 2)
        
        # 血条
        bw, bh = 44, 6
        bx, by = x - bw//2, y - s - 14
        pygame.draw.rect(surf, RED, (bx, by, bw, bh))
        pygame.draw.rect(surf, GREEN, (bx, by, bw * self.hp // self.max_hp, bh))
        
        # 护盾条
        if self.shield > 0:
            sw = 44 * self.shield // 3
            pygame.draw.rect(surf, BLUE, (bx, by - 8, sw, 4))
        
        # 装备效果文字
        if self.equip_effect:
            t, c, _ = self.equip_effect
            txt = make_text(t, 16, c)
            surf.blit(txt, (x - txt.get_width()//2, y - s - 28))

    def rect(self):
        return pygame.Rect(self.x - self.size, self.y - self.size, self.size*2, self.size*2)

# ════════════════════════════════════════════════
# 子弹
# ════════════════════════════════════════════════
class Bullet:
    def __init__(self, x, y, angle, damage=1):
        self.x, self.y = x, y
        self.vx = math.cos(angle) * 12
        self.vy = math.sin(angle) * 12
        self.r = 6; self.alive = True; self.damage = damage

    def update(self):
        self.x += self.vx; self.y += self.vy
        if self.x < -30 or self.x > WIDTH+30 or self.y < -30 or self.y > HEIGHT+30:
            self.alive = False

    def draw(self, surf):
        pygame.draw.circle(surf, YELLOW, (int(self.x), int(self.y)), self.r)
        pygame.draw.circle(surf, WHITE, (int(self.x), int(self.y)), self.r - 2)
        if self.damage > 1:
            pygame.draw.circle(surf, RED, (int(self.x), int(self.y)), self.r - 4)

    def rect(self):
        return pygame.Rect(self.x - self.r, self.y - self.r, self.r*2, self.r*2)

# ════════════════════════════════════════════════
# 敌人
# ════════════════════════════════════════════════
class Enemy:
    def __init__(self, lv=1):
        sd = random.randint(0, 3)
        if sd == 0: self.x, self.y = random.randint(0, WIDTH), -35
        elif sd == 1: self.x, self.y = WIDTH+35, random.randint(0, HEIGHT)
        elif sd == 2: self.x, self.y = random.randint(0, WIDTH), HEIGHT+35
        else: self.x, self.y = -35, random.randint(0, HEIGHT)
        
        self.size = 20; self.speed = 1.8 + lv * 0.3
        self.hp = 1 + lv // 3; self.max_hp = self.hp
        self.alive = True; self.level = lv
        self.color = (180, 40, 40) if lv < 3 else (200, 60, 180)
        self.drop_chance = 0.15 + lv * 0.02

    def update(self, tx, ty):
        dx, dy = tx - self.x, ty - self.y
        d = math.hypot(dx, dy)
        if d > 0:
            self.x += dx / d * self.speed
            self.y += dy / d * self.speed

    def hit(self, d=1):
        self.hp -= d
        if self.hp <= 0: self.alive = False

    def draw(self, surf):
        x, y = int(self.x), int(self.y)
        pygame.draw.circle(surf, self.color, (x, y), self.size)
        # 眼睛
        eo = self.size // 3
        pygame.draw.circle(surf, WHITE, (x - eo, y - eo), 5)
        pygame.draw.circle(surf, WHITE, (x + eo, y - eo), 5)
        pygame.draw.circle(surf, BLACK, (x - eo, y - eo), 2)
        pygame.draw.circle(surf, BLACK, (x + eo, y - eo), 2)
        # 等级标记
        if self.level >= 3:
            pygame.draw.circle(surf, YELLOW, (x, y), self.size + 3, 2)
        # 血条
        bw, bh = 32, 4
        bx, by = x - bw//2, y - self.size - 8
        pygame.draw.rect(surf, RED, (bx, by, bw, bh))
        pygame.draw.rect(surf, GREEN, (bx, by, bw * self.hp // self.max_hp, bh))

    def rect(self):
        return pygame.Rect(self.x - self.size, self.y - self.size, self.size*2, self.size*2)

# ════════════════════════════════════════════════
# 爆炸粒子
# ════════════════════════════════════════════════
class Explosion:
    def __init__(self, x, y, color=ORANGE, cnt=20):
        self.parts = []
        for _ in range(cnt):
            a = random.uniform(0, math.pi * 2)
            sp = random.uniform(1, 6)
            self.parts.append({
                'x': x, 'y': y,
                'vx': math.cos(a) * sp, 'vy': math.sin(a) * sp,
                'life': random.randint(15, 35), 'color': color
            })

    def update(self):
        for p in self.parts[:]:
            p['x'] += p['vx']; p['y'] += p['vy']
            p['vx'] *= 0.96; p['vy'] *= 0.96
            p['life'] -= 1
            if p['life'] <= 0: self.parts.remove(p)

    def draw(self, surf):
        for p in self.parts:
            a = min(255, p['life'] * 8)
            c = tuple(min(255, int(v * a // 255)) for v in p['color'])
            sz = max(1, p['life'] // 8)
            pygame.draw.circle(surf, c, (int(p['x']), int(p['y'])), sz)

    @property
    def alive(self): return len(self.parts) > 0

# ════════════════════════════════════════════════
# 装备掉落提示
# ════════════════════════════════════════════════
class FloatingText:
    def __init__(self, x, y, text, color=WHITE, size=18):
        self.x, self.y = x, y
        self.text = text
        self.color = color
        self.size = size
        self.life = 50
        self.alive = True

    def update(self):
        self.y -= 1.2
        self.life -= 1
        if self.life <= 0: self.alive = False

    def draw(self, surf):
        a = min(255, self.life * 5)
        c = tuple(v * a // 255 for v in self.color)
        txt = make_text(self.text, self.size, c)
        surf.blit(txt, (int(self.x - txt.get_width()//2), int(self.y)))

# ════════════════════════════════════════════════
# 主游戏循环
# ════════════════════════════════════════════════
def run_shooter():
    tank = Tank()
    bullets = []; enemies = []; explosions = []
    equipments = []; floating_texts = []
    score = 0; level = 1; kills = 0; spawn_timer = 0

    while True:
        keys = pygame.key.get_pressed()
        mx, my = pygame.mouse.get_pos()
        mb = pygame.mouse.get_pressed()

        for e in pygame.event.get():
            if e.type == pygame.QUIT: pygame.quit(); sys.exit()
            if e.type == pygame.KEYDOWN and e.key == pygame.K_ESCAPE: return score

        # ── 移动 ──
        dx, dy = 0, 0
        if keys[pygame.K_a] or keys[pygame.K_LEFT]: dx -= 1
        if keys[pygame.K_d] or keys[pygame.K_RIGHT]: dx += 1
        if keys[pygame.K_w] or keys[pygame.K_UP]: dy -= 1
        if keys[pygame.K_s] or keys[pygame.K_DOWN]: dy += 1
        if dx != 0 and dy != 0: dx *= 0.707; dy *= 0.707
        tank.move(dx * tank.speed, dy * tank.speed)

        tank.aim(mx, my)
        if mb[0]:
            new_bullets = tank.shoot()
            bullets.extend(new_bullets)

        tank.update()

        # ── 子弹更新 ──
        for b in bullets[:]:
            b.update()
            if not b.alive: bullets.remove(b)

        # ── 生成敌人 ──
        spawn_timer += 1
        si = max(15, 50 - level * 2)
        if spawn_timer >= si and len(enemies) < 15 + level * 2:
            enemies.append(Enemy(level)); spawn_timer = 0

        # ── 敌人更新 ──
        for e in enemies[:]:
            e.update(tank.x, tank.y)
            if not e.alive:
                enemies.remove(e)
                explosions.append(Explosion(e.x, e.y))
                
                # 掉落装备
                if random.random() < e.drop_chance:
                    eq = Equipment(e.x, e.y)
                    equipments.append(eq)
                    ft = FloatingText(e.x, e.y - 20, f"+{eq.info['name']}", eq.info['color'])
                    floating_texts.append(ft)
                
                score += 10 * level; kills += 1
                continue
            
            if tank.rect().colliderect(e.rect()):
                if tank.take_damage():
                    return score
                enemies.remove(e)
                explosions.append(Explosion(e.x, e.y, RED))

        # ── 子弹碰撞敌人 ──
        for b in bullets[:]:
            br = b.rect()
            for e in enemies[:]:
                if br.colliderect(e.rect()):
                    e.hit(b.damage)
                    bullets.remove(b)
                    break

        # ── 捡装备 ──
        tr = tank.rect()
        for eq in equipments[:]:
            eq.update()
            if not eq.alive:
                equipments.remove(eq)
                continue
            if tr.colliderect(eq.rect()):
                eq.apply(tank)
                ft = FloatingText(eq.x, eq.y - 20, f"拾取 {eq.info['name']}", eq.info['color'], 20)
                floating_texts.append(ft)
                equipments.remove(eq)

        # ── 升级 ──
        if kills >= level * 6:
            level += 1; kills = 0
            ft = FloatingText(WIDTH//2, HEIGHT//2, f"LEVEL UP! Lv.{level}", YELLOW, 28)
            floating_texts.append(ft)

        # ── 粒子更新 ──
        for ex in explosions[:]:
            ex.update()
            if not ex.alive: explosions.remove(ex)

        for ft in floating_texts[:]:
            ft.update()
            if not ft.alive: floating_texts.remove(ft)

        # ── 绘制 ──
        screen.fill(DARK)
        for gx in range(0, WIDTH, 40):
            pygame.draw.line(screen, (35, 35, 45), (gx, 0), (gx, HEIGHT), 1)
        for gy in range(0, HEIGHT, 40):
            pygame.draw.line(screen, (35, 35, 45), (0, gy), (WIDTH, gy), 1)

        tank.draw(screen)
        for b in bullets: b.draw(screen)
        for e in enemies: e.draw(screen)
        for eq in equipments: eq.draw(screen)
        for ex in explosions: ex.draw(screen)
        for ft in floating_texts: ft.draw(screen)

        # HUD
        si = make_text(str(score), 28, YELLOW); screen.blit(si, (14, 14))
        li = make_text(f"Lv.{level}", 22, BLUE); screen.blit(li, (14, 50))
        ki = make_text(f"击杀:{kills}/{level*6}", 18, GRAY); screen.blit(ki, (14, 78))
        
        hi = make_text(f"HP:{tank.hp}", 22, GREEN if tank.hp > 2 else RED)
        screen.blit(hi, (WIDTH - hi.get_width() - 14, 14))
        
        if tank.shield > 0:
            shi = make_text(f"护盾:{tank.shield}", 18, BLUE)
            screen.blit(shi, (WIDTH - shi.get_width() - 14, 42))
        
        if tank.spread_level > 0:
            spi = make_text(f"散射:{tank.spread_level}", 16, PURPLE)
            screen.blit(spi, (WIDTH - spi.get_width() - 14, 66))
        
        if tank.damage_bonus > 0:
            dmi = make_text(f"伤害:+{tank.damage_bonus}", 16, RED)
            screen.blit(dmi, (WIDTH - dmi.get_width() - 14, 86))
        
        if tank.speed_bonus > 0:
            spi2 = make_text(f"速度:+{tank.speed_bonus:.1f}", 16, CYAN)
            screen.blit(spi2, (WIDTH - spi2.get_width() - 14, 104))

        # 装备图例
        legend_y = HEIGHT - 30
        for i, (key, info) in enumerate(EQUIP_TYPES.items()):
            lx = 20 + i * 196
            ic = make_text(info['icon'], 16, info['color'])
            screen.blit(ic, (lx, legend_y))
            nm = make_text(info['name'], 14, info['color'])
            screen.blit(nm, (lx + 20, legend_y + 1))

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

# ════════════════════════════════════════════════
# 启动
# ════════════════════════════════════════════════
if __name__ == "__main__":
    while True:
        result = run_shooter()
        wait = True
        while wait:
            for e in pygame.event.get():
                if e.type == pygame.QUIT: pygame.quit(); sys.exit()
                if e.type == pygame.KEYDOWN: wait = False
            screen.fill(DARK)
            go = make_text("GAME OVER", 56, RED)
            sc = make_text(f"最终得分: {result}", 36, WHITE)
            tip = make_text("按任意键重新开始  |  ESC 退出", 22, GRAY)
            screen.blit(go, (WIDTH//2 - go.get_width()//2, HEIGHT//2 - 60))
            screen.blit(sc, (WIDTH//2 - sc.get_width()//2, HEIGHT//2 + 10))
            screen.blit(tip, (WIDTH//2 - tip.get_width()//2, HEIGHT//2 + 60))
            pygame.display.flip(); clock.tick(30)