import pygame
import random
import sys
import math

# 初始化pygame
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("RPG冒险游戏【技能版】")
clock = pygame.time.Clock()

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (220, 50, 50)
GREEN = (50, 200, 50)
BLUE = (50, 100, 220)
GRAY = (80, 80, 80)
YELLOW = (255, 220, 0)
ORANGE = (255,140,0)
PURPLE = (160,60,220)
CYAN = (0,220,220)

# 默认字体，规避字体BUG
font = pygame.font.Font(None, 22)
small_font = pygame.font.Font(None, 18)

# ====================== 子弹类 ======================
class Bullet:
    def __init__(self, x, y, target_x, target_y, pierce=False):
        self.x = x
        self.y = y
        speed = 7
        angle = math.atan2(target_y - y, target_x - x)
        self.vx = math.cos(angle) * speed
        self.vy = math.sin(angle) * speed
        self.radius = 6
        self.damage = 12
        self.life = 120
        self.pierce = pierce    # 是否穿透
        self.hit_monster = False

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.life -= 1

    def draw(self):
        if self.pierce:
            pygame.draw.circle(screen, CYAN, (int(self.x), int(self.y)), self.radius)
        else:
            pygame.draw.circle(screen, ORANGE, (int(self.x), int(self.y)), self.radius)

    def is_out(self):
        return self.life <= 0 or self.x < 0 or self.x > WIDTH or self.y <0 or self.y>HEIGHT

# ====================== 冲击波特效 ======================
class ShockWave:
    def __init__(self, cx, cy):
        self.cx = cx
        self.cy = cy
        self.radius = 10
        self.max_radius = 120
        self.speed = 4
        self.damage = 25
        self.active = True

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

    def draw(self):
        pygame.draw.circle(screen, PURPLE, (int(self.cx), int(self.cy)), int(self.radius), 3)

# ====================== 玩家类 ======================
class Player:
    def __init__(self):
        self.x = WIDTH // 2
        self.y = HEIGHT // 2
        self.size = 32
        self.hp = 100
        self.max_hp = 100
        self.atk = 18
        self.speed = 4
        self.potion_count = 3

    def draw(self):
        pygame.draw.rect(screen, BLUE, (self.x, self.y, self.size, self.size))

    def move(self, keys):
        if keys[pygame.K_w] and self.y > 0:
            self.y -= self.speed
        if keys[pygame.K_s] and self.y < HEIGHT - self.size:
            self.y += self.speed
        if keys[pygame.K_a] and self.x > 0:
            self.x -= self.speed
        if keys[pygame.K_d] and self.x < WIDTH - self.size:
            self.x += self.speed

    def use_potion(self):
        if self.potion_count > 0 and self.hp < self.max_hp:
            self.potion_count -= 1
            self.hp = min(self.hp + 35, self.max_hp)

# ====================== 怪物类 ======================
class Monster:
    def __init__(self):
        self.x = random.randint(50, WIDTH - 80)
        self.y = random.randint(50, HEIGHT - 80)
        self.size = 30
        self.hp = 55
        self.atk = 8
        self.speed = 1.2

    def draw(self):
        pygame.draw.rect(screen, RED, (self.x, self.y, self.size, self.size))

    def chase(self, player):
        if self.x < player.x:
            self.x += self.speed
        elif self.x > player.x:
            self.x -= self.speed
        if self.y < player.y:
            self.y += self.speed
        elif self.y > player.y:
            self.y -= self.speed

    def reset(self):
        self.x = random.randint(50, WIDTH - 80)
        self.y = random.randint(50, HEIGHT - 80)
        self.hp = 55

# ====================== 游戏变量初始化 ======================
player = Player()
monster = Monster()
battle_log = []
game_over = False
attack_cd = 0
shoot_cd = 15
bullet_list = []
shockwave_list = []

# 技能冷却
skill_cd = {
    "shock": 0,      # Q冲击波
    "pierce": 0,     # F穿刺箭
    "dash": 0        # Shift闪现
}
SKILL_MAX_CD = {
    "shock": 180,
    "pierce": 90,
    "dash": 120
}

def add_log(text):
    battle_log.append(text)
    if len(battle_log) > 6:
        battle_log.pop(0)

# ====================== 主循环 ======================
def main():
    global game_over, attack_cd, shoot_cd
    while True:
        screen.fill((30, 30, 40))
        keys = pygame.key.get_pressed()
        mouse_x, mouse_y = pygame.mouse.get_pos()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and attack_cd <= 0 and not game_over:
                    dist = ((player.x - monster.x)**2 + (player.y - monster.y)**2)**0.5
                    if dist < 60:
                        monster.hp -= player.atk
                        add_log(f"You attack, deal {player.atk} damage!")
                        attack_cd = 30
                        if monster.hp <= 0:
                            add_log("Monster defeated!")
                            monster.reset()
                            player.potion_count += 1
                            add_log("Get potion!")
                if event.key == pygame.K_e:
                    player.use_potion()
                    add_log("Use potion, recover HP!")
                if event.key == pygame.K_r and game_over:
                    player.hp = player.max_hp
                    monster.reset()
                    battle_log.clear()
                    game_over = False

                # ===== 技能按键 =====
                if not game_over:
                    # Q 冲击波
                    if event.key == pygame.K_q and skill_cd["shock"] <= 0:
                        cx = player.x + player.size//2
                        cy = player.y + player.size//2
                        shockwave_list.append(ShockWave(cx, cy))
                        skill_cd["shock"] = SKILL_MAX_CD["shock"]
                        add_log("Skill: Shock Wave!")
                    # F 穿刺箭
                    if event.key == pygame.K_f and skill_cd["pierce"] <= 0:
                        px = player.x + player.size//2
                        py = player.y + player.size//2
                        bullet = Bullet(px, py, mouse_x, mouse_y, pierce=True)
                        bullet_list.append(bullet)
                        skill_cd["pierce"] = SKILL_MAX_CD["pierce"]
                        add_log("Skill: Piercing Shot!")
                    # Shift 闪现
                    if event.key == pygame.K_LSHIFT and skill_cd["dash"] <= 0:
                        player.x = mouse_x - player.size//2
                        player.y = mouse_y - player.size//2
                        # 边界限制
                        player.x = max(0, min(player.x, WIDTH-player.size))
                        player.y = max(0, min(player.y, HEIGHT-player.size))
                        skill_cd["dash"] = SKILL_MAX_CD["dash"]
                        add_log("Skill: Dash!")

            # 鼠标左键普通射击
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1 and shoot_cd <= 0 and not game_over:
                    px = player.x + player.size//2
                    py = player.y + player.size//2
                    bullet = Bullet(px, py, mouse_x, mouse_y)
                    bullet_list.append(bullet)
                    shoot_cd = 15

        if not game_over:
            player.move(keys)
            monster.chase(player)

            dist = ((player.x - monster.x)**2 + (player.y - monster.y)**2)**0.5
            if dist < 40 and attack_cd <= 0:
                player.hp -= monster.atk
                add_log(f"Monster attacks you, take {monster.atk} damage!")
                attack_cd = 40
                if player.hp <= 0:
                    add_log("You were defeated...")
                    game_over = True

        # 冷却倒计时
        if attack_cd > 0:
            attack_cd -= 1
        if shoot_cd > 0:
            shoot_cd -= 1
        for key in skill_cd:
            if skill_cd[key] > 0:
                skill_cd[key] -= 1

        # 更新子弹 & 碰撞
        for bullet in bullet_list[:]:
            bullet.update()
            mx = monster.x + monster.size//2
            my = monster.y + monster.size//2
            d = math.hypot(bullet.x - mx, bullet.y - my)
            if d < bullet.radius + monster.size//2:
                monster.hp -= bullet.damage
                add_log(f"Bullet hit monster, {bullet.damage} damage!")
                if not bullet.pierce:
                    bullet_list.remove(bullet)
                if monster.hp <= 0:
                    add_log("Monster defeated!")
                    monster.reset()
                    player.potion_count += 1
                    add_log("Get potion!")
                continue
            if bullet.is_out():
                bullet_list.remove(bullet)

        # 更新冲击波 & 伤害判定
        for wave in shockwave_list[:]:
            wave.update()
            mx = monster.x + monster.size//2
            my = monster.y + monster.size//2
            d = math.hypot(wave.cx - mx, wave.cy - my)
            if d < wave.radius and wave.radius - wave.speed < d:
                monster.hp -= wave.damage
                add_log(f"Shockwave hit monster, {wave.damage} damage!")
                if monster.hp <= 0:
                    add_log("Monster defeated!")
                    monster.reset()
                    player.potion_count += 1
                    add_log("Get potion!")
            if not wave.active:
                shockwave_list.remove(wave)

        # 绘制
        player.draw()
        monster.draw()
        for b in bullet_list:
            b.draw()
        for w in shockwave_list:
            w.draw()

        # ========== UI绘制 ==========
        # 血条
        pygame.draw.rect(screen, GRAY, (20, 20, 204, 24))
        hp_width = (player.hp / player.max_hp) * 200
        pygame.draw.rect(screen, GREEN, (22, 22, hp_width, 20))
        hp_text = font.render(f"HP: {player.hp}/{player.max_hp}", True, WHITE)
        screen.blit(hp_text, (25, 20))

        item_text = font.render(f"Potion x{player.potion_count} [E Use]", True, YELLOW)
        screen.blit(item_text, (20, 55))

        # 技能栏UI
        skill_y = 85
        skill_info = [
            ("Q ShockWave", skill_cd["shock"], SKILL_MAX_CD["shock"]),
            ("F PierceShot", skill_cd["pierce"], SKILL_MAX_CD["pierce"]),
            ("Shift Dash", skill_cd["dash"], SKILL_MAX_CD["dash"])
        ]
        for idx, (name, cd, maxcd) in enumerate(skill_info):
            color = GREEN if cd <= 0 else RED
            cd_text = f"{name} Ready" if cd <= 0 else f"{name} CD:{cd//60}"
            txt = font.render(cd_text, True, color)
            screen.blit(txt, (20, skill_y + idx*26))

        # 操作提示
        hint_text = small_font.render("WASD Move | SPACE Melee | LMB Shoot", True, WHITE)
        screen.blit(hint_text, (WIDTH - 380, 22))

        # 战斗日志面板
        log_y = HEIGHT - 160
        pygame.draw.rect(screen, (40, 40, 50), (10, log_y, 420, 150))
        pygame.draw.rect(screen, WHITE, (10, log_y, 420, 150), 2)
        for i, msg in enumerate(battle_log):
            log_render = small_font.render(msg, True, WHITE)
            screen.blit(log_render, (20, log_y + 10 + i * 22))

        if game_over:
            over_text = font.render("Game Over! Press R to Restart", True, RED)
            screen.blit(over_text, (WIDTH//2 - 160, HEIGHT//2))

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

if __name__ == "__main__":
    main()