import pygame
import sys
import random

# ---------------- 基础设置 ----------------
WIDTH, HEIGHT = 480, 720
FPS = 60

pygame.init()

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("是男人上一百层")

clock = pygame.time.Clock()
font = pygame.font.SysFont("simhei", 28)
big_font = pygame.font.SysFont("simhei", 64)

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BG_TOP = (15, 20, 45)
BG_BOTTOM = (40, 60, 100)

# 平台颜色
COLOR_NORMAL = (120, 180, 230)
COLOR_SPRING = (100, 220, 120)
COLOR_MOVING = (240, 180, 80)
COLOR_BREAK  = (220, 100, 100)

PLAYER_COLOR = (240, 80, 80)
PLAYER_OUTLINE = (180, 40, 40)

# 物理参数
GRAVITY = 0.55
JUMP_VY = -12.5
SPRING_VY = -19
MOVE_SPEED = 5.5

# 平台尺寸
PLAT_W = 80
PLAT_H = 12

# 玩家尺寸
PLAYER_W = 32
PLAYER_H = 40

# 生成参数
TARGET_FLOOR = 100
PLAT_GAP_MIN = 70
PLAT_GAP_MAX = 110


# ---------------- 背景 ----------------
def draw_background():
    for y in range(HEIGHT):
        ratio = y / HEIGHT
        r = int(BG_TOP[0] + (BG_BOTTOM[0] - BG_TOP[0]) * ratio)
        g = int(BG_TOP[1] + (BG_BOTTOM[1] - BG_TOP[1]) * ratio)
        b = int(BG_TOP[2] + (BG_BOTTOM[2] - BG_TOP[2]) * ratio)
        pygame.draw.line(screen, (r, g, b), (0, y), (WIDTH, y))


# ---------------- 平台 ----------------
class Platform:
    def __init__(self, x, y, floor_num):
        self.x = x
        self.y = y
        self.w = PLAT_W
        self.h = PLAT_H
        self.floor = floor_num

        # 类型
        r = random.random()
        if floor_num <= 2:
            self.kind = "normal"
        elif r < 0.15:
            self.kind = "spring"
        elif r < 0.30:
            self.kind = "moving"
        elif r < 0.42:
            self.kind = "break"
        else:
            self.kind = "normal"

        # 移动平台参数
        self.vx = random.choice([-1.8, 1.8]) if self.kind == "moving" else 0

        # 碎裂平台
        self.broken = False
        self.break_timer = 0

        self.alive = True

    @property
    def rect(self):
        return pygame.Rect(self.x, self.y, self.w, self.h)

    def update(self):
        if self.kind == "moving":
            self.x += self.vx
            if self.x < 0:
                self.x = 0
                self.vx = -self.vx
            elif self.x + self.w > WIDTH:
                self.x = WIDTH - self.w
                self.vx = -self.vx

        if self.broken:
            self.break_timer += 1
            if self.break_timer > 12:
                self.alive = False

    def draw(self):
        if self.broken and self.break_timer % 4 < 2:
            return

        color = {
            "normal": COLOR_NORMAL,
            "spring": COLOR_SPRING,
            "moving": COLOR_MOVING,
            "break":  COLOR_BREAK,
        }[self.kind]

        pygame.draw.rect(screen, color, (self.x, self.y, self.w, self.h))
        pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, self.w, self.h), 2)

        # 弹簧标记
        if self.kind == "spring":
            pygame.draw.rect(screen, (60, 140, 80), (self.x + self.w // 2 - 6, self.y - 8, 12, 8))

        # 碎裂标记
        if self.kind == "break":
            pygame.draw.line(screen, WHITE, (self.x + 8, self.y + 3), (self.x + self.w - 8, self.y + self.h - 3), 2)


# ---------------- 玩家 ----------------
class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.w = PLAYER_W
        self.h = PLAYER_H
        self.vx = 0
        self.vy = 0
        self.on_ground = False
        self.alive = True

    @property
    def rect(self):
        return pygame.Rect(self.x, self.y, self.w, self.h)

    def update(self, keys):
        self.vx = 0
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            self.vx = -MOVE_SPEED
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            self.vx = MOVE_SPEED

        self.vy += GRAVITY
        if self.vy > 18:
            self.vy = 18

        self.x += self.vx
        self.y += self.vy

        # 左右边界
        if self.x < 0:
            self.x = 0
        elif self.x + self.w > WIDTH:
            self.x = WIDTH - self.w

        self.on_ground = False

    def draw(self):
        pygame.draw.rect(screen, PLAYER_COLOR, (self.x, self.y, self.w, self.h))
        pygame.draw.rect(screen, PLAYER_OUTLINE, (self.x, self.y, self.w, self.h), 2)

        # 眼睛
        pygame.draw.rect(screen, WHITE, (self.x + 6, self.y + 8, 8, 8))
        pygame.draw.rect(screen, WHITE, (self.x + 18, self.y + 8, 8, 8))
        pygame.draw.rect(screen, BLACK, (self.x + 9, self.y + 11, 3, 3))
        pygame.draw.rect(screen, BLACK, (self.x + 21, self.y + 11, 3, 3))


# ---------------- 关卡生成 ----------------
def generate_platforms():
    platforms = []

    # 起始平台
    start = Platform(WIDTH // 2 - PLAT_W // 2, HEIGHT - 80, 1)
    start.kind = "normal"
    platforms.append(start)

    current_y = HEIGHT - 80
    current_floor = 1

    # 生成到目标层 + 一些余量
    while current_floor < TARGET_FLOOR + 5:
        gap = random.randint(PLAT_GAP_MIN, PLAT_GAP_MAX)
        current_y -= gap
        current_floor += 1

        x = random.randint(10, WIDTH - PLAT_W - 10)
        platforms.append(Platform(x, current_y, current_floor))

    return platforms


# ---------------- 主循环 ----------------
def main():
    platforms = generate_platforms()
    player = Player(WIDTH // 2 - PLAYER_W // 2, HEIGHT - 80 - PLAYER_H)

    camera_y = 0          # 摄像机偏移（世界坐标下向上为正）
    highest_y = player.y  # 玩家到达过的最高位置
    current_floor = 1
    game_over = False
    win = False

    running = True
    while running:
        clock.tick(FPS)

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

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    platforms = generate_platforms()
                    player = Player(WIDTH // 2 - PLAYER_W // 2, HEIGHT - 80 - PLAYER_H)
                    camera_y = 0
                    highest_y = player.y
                    current_floor = 1
                    game_over = False
                    win = False

        if not game_over:
            keys = pygame.key.get_pressed()
            player.update(keys)

            # 更新平台
            for p in platforms:
                p.update()

            # 碰撞检测：只在下落时着陆
            if player.vy >= 0:
                for plat in platforms:
                    if plat.broken or not plat.alive:
                        continue

                    pr = player.rect
                    plr = plat.rect

                    if (pr.bottom >= plr.top and
                        pr.bottom <= plr.top + player.vy + 4 and
                        pr.right > plr.left + 4 and
                        pr.left < plr.right - 4):

                        player.y = plat.y - player.h
                        player.vy = 0
                        player.on_ground = True

                        if plat.kind == "spring":
                            player.vy = SPRING_VY
                            player.on_ground = False
                        elif plat.kind == "break":
                            plat.broken = True
                        else:
                            # 普通 / 移动：普通跳跃
                            player.vy = JUMP_VY
                            player.on_ground = False

                        break

            # 更新最高点和楼层
            if player.y < highest_y:
                highest_y = player.y
                # 每上升一段距离算一层
                current_floor = max(1, int((HEIGHT - 80 - highest_y) // 80) + 1)

            # 摄像机跟随：让玩家大致在屏幕中上部
            target_camera = highest_y - HEIGHT // 3
            camera_y += (target_camera - camera_y) * 0.1

            # 掉出屏幕下方
            if player.y - camera_y > HEIGHT + 50:
                game_over = True

            # 胜利
            if current_floor >= TARGET_FLOOR:
                game_over = True
                win = True

        # ---------------- 绘制 ----------------
        draw_background()

        # 绘制平台
        for p in platforms:
            if not p.alive:
                continue
            draw_y = p.y - camera_y
            if draw_y < -50 or draw_y > HEIGHT + 50:
                continue

            color = {
                "normal": COLOR_NORMAL,
                "spring": COLOR_SPRING,
                "moving": COLOR_MOVING,
                "break":  COLOR_BREAK,
            }[p.kind]

            if p.broken and p.break_timer % 4 < 2:
                continue

            pygame.draw.rect(screen, color, (p.x, draw_y, p.w, p.h))
            pygame.draw.rect(screen, WHITE, (p.x, draw_y, p.w, p.h), 2)

            if p.kind == "spring":
                pygame.draw.rect(screen, (60, 140, 80), (p.x + p.w // 2 - 6, draw_y - 8, 12, 8))
            if p.kind == "break":
                pygame.draw.line(screen, WHITE, (p.x + 8, draw_y + 3), (p.x + p.w - 8, draw_y + p.h - 3), 2)

        # 绘制玩家
        if not game_over or win:
            py = player.y - camera_y
            pygame.draw.rect(screen, PLAYER_COLOR, (player.x, py, player.w, player.h))
            pygame.draw.rect(screen, PLAYER_OUTLINE, (player.x, py, player.w, player.h), 2)
            pygame.draw.rect(screen, WHITE, (player.x + 6, py + 8, 8, 8))
            pygame.draw.rect(screen, WHITE, (player.x + 18, py + 8, 8, 8))
            pygame.draw.rect(screen, BLACK, (player.x + 9, py + 11, 3, 3))
            pygame.draw.rect(screen, BLACK, (player.x + 21, py + 11, 3, 3))

        # HUD
        floor_text = font.render(f"楼层: {current_floor} / {TARGET_FLOOR}", True, WHITE)
        screen.blit(floor_text, (16, 16))

        hint = font.render("R 重新开始", True, WHITE)
        screen.blit(hint, (WIDTH - hint.get_width() - 16, 16))

        # 游戏结束 / 胜利
        if game_over:
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 150))
            screen.blit(overlay, (0, 0))

            if win:
                text = big_font.render("通关！", True, COLOR_SPRING)
            else:
                text = big_font.render("失败", True, COLOR_BREAK)

            screen.blit(text, (WIDTH // 2 - text.get_width() // 2, HEIGHT // 2 - 50))

            sub = font.render(f"到达楼层: {current_floor}", True, WHITE)
            screen.blit(sub, (WIDTH // 2 - sub.get_width() // 2, HEIGHT // 2 + 10))

            restart = font.render("按 R 重新开始", True, WHITE)
            screen.blit(restart, (WIDTH // 2 - restart.get_width() // 2, HEIGHT // 2 + 50))

        pygame.display.flip()

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()