import pygame
import sys
import random

# ---------- 初始化 ----------
pygame.init()
pygame.font.init()

# ---------- 常量 ----------
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
TILE_SIZE = 40
MAP_WIDTH = 20          # 地图列数
MAP_HEIGHT = 15         # 地图行数
FPS = 30

# 颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GRAY = (200, 200, 200)
DARK_GRAY = (100, 100, 100)
YELLOW = (255, 255, 0)

# 屏幕与时钟
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("简易 RPG")
clock = pygame.time.Clock()

# 字体
font_small = pygame.font.Font(None, 24)
font_medium = pygame.font.Font(None, 32)
font_large = pygame.font.Font(None, 48)

# ---------- 地图生成 ----------
def generate_map():
    """生成随机地图，0=空地，1=墙壁"""
    map_data = [[0 for _ in range(MAP_WIDTH)] for _ in range(MAP_HEIGHT)]
    # 边界围墙
    for x in range(MAP_WIDTH):
        map_data[0][x] = 1
        map_data[MAP_HEIGHT-1][x] = 1
    for y in range(MAP_HEIGHT):
        map_data[y][0] = 1
        map_data[y][MAP_WIDTH-1] = 1
    # 内部随机墙（15%概率）
    for y in range(2, MAP_HEIGHT-2):
        for x in range(2, MAP_WIDTH-2):
            if random.random() < 0.15:
                map_data[y][x] = 1
    # 保证出生点为空地
    for y in range(1, 3):
        for x in range(1, 3):
            map_data[y][x] = 0
    return map_data

# ---------- 玩家类 ----------
class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.hp = 100
        self.max_hp = 100
        self.atk = 10
        self.defense = 5
        self.level = 1
        self.exp = 0
        self.exp_to_next = 20
        self.color = BLUE

    def move(self, dx, dy, map_data):
        """尝试移动，成功返回True"""
        nx, ny = self.x + dx, self.y + dy
        if 0 <= nx < MAP_WIDTH and 0 <= ny < MAP_HEIGHT and map_data[ny][nx] == 0:
            self.x, self.y = nx, ny
            return True
        return False

    def attack(self, enemy):
        """攻击敌人，返回造成伤害"""
        damage = max(1, self.atk - enemy.defense // 2 + random.randint(-2, 2))
        enemy.hp -= damage
        return damage

    def take_damage(self, damage):
        self.hp -= damage
        if self.hp < 0:
            self.hp = 0

    def gain_exp(self, amount):
        self.exp += amount
        while self.exp >= self.exp_to_next:
            self.exp -= self.exp_to_next
            self.level += 1
            self.exp_to_next = int(self.exp_to_next * 1.5)
            self.max_hp += 10
            self.hp = self.max_hp
            self.atk += 3
            self.defense += 2

    def is_alive(self):
        return self.hp > 0

# ---------- 敌人类 ----------
class Enemy:
    def __init__(self, x, y, name, hp, atk, defense, exp_reward):
        self.x = x
        self.y = y
        self.name = name
        self.hp = hp
        self.max_hp = hp
        self.atk = atk
        self.defense = defense
        self.exp_reward = exp_reward
        self.color = RED

    def attack(self, player):
        damage = max(1, self.atk - player.defense // 2 + random.randint(-2, 2))
        player.take_damage(damage)
        return damage

    def is_alive(self):
        return self.hp > 0

# ---------- 生成敌人 ----------
def generate_enemies(map_data, num_enemies=8):
    enemies = []
    enemy_types = [
        ("史莱姆", 20, 5, 2, 5),
        ("哥布林", 30, 8, 3, 8),
        ("蝙蝠", 15, 6, 1, 4),
        ("骷髅", 25, 10, 4, 10),
    ]
    placed = 0
    attempts = 0
    while placed < num_enemies and attempts < 1000:
        x = random.randint(1, MAP_WIDTH-2)
        y = random.randint(1, MAP_HEIGHT-2)
        if map_data[y][x] == 0:
            # 避开出生点
            if (x, y) in [(1,1), (1,2), (2,1)]:
                attempts += 1
                continue
            # 避免重叠
            overlap = any(e.x == x and e.y == y for e in enemies)
            if not overlap:
                name, hp, atk, defense, exp = random.choice(enemy_types)
                enemies.append(Enemy(x, y, name, hp, atk, defense, exp))
                placed += 1
        attempts += 1
    return enemies

# ---------- 绘制地图 ----------
def draw_map(map_data, player, enemies, camera_x, camera_y):
    for y in range(MAP_HEIGHT):
        for x in range(MAP_WIDTH):
            tile_x = x * TILE_SIZE - camera_x
            tile_y = y * TILE_SIZE - camera_y
            if tile_x < -TILE_SIZE or tile_x > SCREEN_WIDTH or tile_y < -TILE_SIZE or tile_y > SCREEN_HEIGHT:
                continue
            if map_data[y][x] == 1:
                pygame.draw.rect(screen, DARK_GRAY, (tile_x, tile_y, TILE_SIZE, TILE_SIZE))
            else:
                pygame.draw.rect(screen, GRAY, (tile_x, tile_y, TILE_SIZE, TILE_SIZE))
                pygame.draw.rect(screen, BLACK, (tile_x, tile_y, TILE_SIZE, TILE_SIZE), 1)

    # 绘制敌人
    for enemy in enemies:
        if enemy.is_alive():
            ex = enemy.x * TILE_SIZE - camera_x
            ey = enemy.y * TILE_SIZE - camera_y
            if -TILE_SIZE < ex < SCREEN_WIDTH and -TILE_SIZE < ey < SCREEN_HEIGHT:
                pygame.draw.circle(screen, enemy.color, (ex + TILE_SIZE//2, ey + TILE_SIZE//2), TILE_SIZE//2 - 4)
                name_surf = font_small.render(enemy.name, True, WHITE)
                screen.blit(name_surf, (ex + 2, ey - 10))

    # 绘制玩家
    px = player.x * TILE_SIZE - camera_x
    py = player.y * TILE_SIZE - camera_y
    pygame.draw.rect(screen, player.color, (px + 4, py + 4, TILE_SIZE-8, TILE_SIZE-8))
    # HP 条
    pygame.draw.rect(screen, RED, (px, py - 10, TILE_SIZE, 5))
    hp_width = TILE_SIZE * (player.hp / player.max_hp)
    pygame.draw.rect(screen, GREEN, (px, py - 10, hp_width, 5))

# ---------- 探索界面 UI ----------
def draw_ui_explore(player):
    hp_text = font_medium.render(f"HP: {player.hp}/{player.max_hp}", True, WHITE)
    lv_text = font_medium.render(f"等级: {player.level}", True, WHITE)
    exp_text = font_medium.render(f"经验: {player.exp}/{player.exp_to_next}", True, WHITE)
    atk_text = font_medium.render(f"攻击: {player.atk}  防御: {player.defense}", True, WHITE)
    screen.blit(hp_text, (10, SCREEN_HEIGHT - 80))
    screen.blit(lv_text, (10, SCREEN_HEIGHT - 55))
    screen.blit(exp_text, (10, SCREEN_HEIGHT - 30))
    screen.blit(atk_text, (200, SCREEN_HEIGHT - 55))
    tip = font_small.render("方向键移动 | 走到敌人身上自动战斗", True, WHITE)
    screen.blit(tip, (SCREEN_WIDTH//2 - 160, SCREEN_HEIGHT - 20))

# ---------- 战斗系统 ----------
def battle_loop(player, enemy):
    """战斗循环，返回 'win' / 'flee' / 'lose'"""
    action = None
    while True:
        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_a:
                    action = "attack"
                elif event.key == pygame.K_f:
                    action = "flee"

        # 执行行动
        if action == "attack":
            dmg = player.attack(enemy)
            if not enemy.is_alive():
                return "win"
            enemy.attack(player)
            if not player.is_alive():
                return "lose"
            action = None
        elif action == "flee":
            if random.random() < 0.5:   # 50% 逃跑成功
                return "flee"
            else:
                enemy.attack(player)
                if not player.is_alive():
                    return "lose"
                action = None

        # 绘制战斗界面
        screen.fill(BLACK)
        p_hp = font_medium.render(f"玩家 HP: {player.hp}/{player.max_hp}", True, GREEN)
        e_hp = font_medium.render(f"{enemy.name} HP: {enemy.hp}/{enemy.max_hp}", True, RED)
        screen.blit(p_hp, (50, 50))
        screen.blit(e_hp, (50, 100))
        instruct = font_large.render("按 A 攻击  按 F 逃跑", True, WHITE)
        screen.blit(instruct, (SCREEN_WIDTH//2 - 150, SCREEN_HEIGHT//2 - 30))
        pygame.display.flip()
        clock.tick(FPS)

# ---------- 主函数 ----------
def main():
    map_data = generate_map()
    player = Player(1, 1)
    enemies = generate_enemies(map_data, 8)
    state = "explore"   # explore / battle / gameover
    current_enemy = None
    camera_x = camera_y = 0

    running = True
    while running:
        # ---- 事件处理 ----
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                break
            if state == "explore" and event.type == pygame.KEYDOWN:
                dx = dy = 0
                if event.key == pygame.K_LEFT:
                    dx = -1
                elif event.key == pygame.K_RIGHT:
                    dx = 1
                elif event.key == pygame.K_UP:
                    dy = -1
                elif event.key == pygame.K_DOWN:
                    dy = 1
                if dx or dy:
                    player.move(dx, dy, map_data)

        if not running:
            break

        # ---- 逻辑更新 ----
        if state == "explore":
            # 检查是否踩到敌人
            for enemy in enemies:
                if enemy.is_alive() and enemy.x == player.x and enemy.y == player.y:
                    current_enemy = enemy
                    state = "battle"
                    break

        elif state == "battle":
            if current_enemy and player.is_alive() and current_enemy.is_alive():
                result = battle_loop(player, current_enemy)
                if result == "win":
                    player.gain_exp(current_enemy.exp_reward)
                    current_enemy.hp = 0   # 标记死亡
                    state = "explore"
                elif result == "flee":
                    # 逃跑后尝试移动到相邻空地
                    dirs = [(0,1), (0,-1), (1,0), (-1,0)]
                    random.shuffle(dirs)
                    moved = False
                    for dx, dy in dirs:
                        if player.move(dx, dy, map_data):
                            moved = True
                            break
                    if not moved:   # 无路可走则敌人消失（避免卡死）
                        current_enemy.hp = 0
                    state = "explore"
                elif result == "lose":
                    state = "gameover"
                current_enemy = None
            else:
                state = "explore"

        # ---- 渲染 ----
        screen.fill(BLACK)

        if state == "explore":
            # 相机跟随玩家
            camera_x = player.x * TILE_SIZE - SCREEN_WIDTH//2 + TILE_SIZE//2
            camera_y = player.y * TILE_SIZE - SCREEN_HEIGHT//2 + TILE_SIZE//2
            camera_x = max(0, min(camera_x, MAP_WIDTH * TILE_SIZE - SCREEN_WIDTH))
            camera_y = max(0, min(camera_y, MAP_HEIGHT * TILE_SIZE - SCREEN_HEIGHT))
            draw_map(map_data, player, enemies, camera_x, camera_y)
            draw_ui_explore(player)

        elif state == "gameover":
            over = font_large.render("游戏结束", True, RED)
            restart = font_medium.render("按 R 重新开始  按 Q 退出", True, WHITE)
            screen.blit(over, (SCREEN_WIDTH//2 - 100, SCREEN_HEIGHT//2 - 50))
            screen.blit(restart, (SCREEN_WIDTH//2 - 150, SCREEN_HEIGHT//2 + 10))
            # 处理重新开始/退出
            for ev in pygame.event.get():
                if ev.type == pygame.KEYDOWN:
                    if ev.key == pygame.K_r:
                        main()      # 递归重启（简单处理）
                        return
                    elif ev.key == pygame.K_q:
                        running = False

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

    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()