import pygame
import sys

# 初始化
pygame.init()
WIDTH, HEIGHT = 800, 500
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("马里奥小游戏")
clock = pygame.time.Clock()
FPS = 60

# 颜色定义
SKY = (100, 180, 255)
GROUND = (120, 70, 20)
BRICK = (200, 100, 40)
COIN = (255, 220, 0)
MARIO_RED = (255, 0, 0)
SKIN = (255, 200, 150)
LEG = (80, 40, 20)
TURTLE = (20, 180, 20)
PILLAR = (100, 100, 100)
PIPE_GREEN = (0, 160, 0)
FLOWER_RED = (255, 30, 30)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)

# 全局变量
scroll_x = 0
score = 0
hp = 3
ground_y = 420
game_over = False
MAX_SCROLL = 1500
current_level = 1  # 当前关卡
max_level = 3      # 总关卡数
level_complete = False  # 关卡完成标记

# ========== 马里奥类 ==========
class Mario:
    def __init__(self):
        self.x = 100
        self.y = 300
        self.w = 40
        self.h = 60
        self.vx = 0
        self.vy = 0
        self.speed = 5
        self.gravity = 0.7
        self.jump_pow = -17
        self.jumping = False
        self.invincible = 0

    def update(self, keys):
        if game_over:
            return
        if self.invincible > 0:
            self.invincible -= 1

        self.vx = 0
        if keys[pygame.K_LEFT]:
            self.vx = -self.speed
        if keys[pygame.K_RIGHT]:
            self.vx = self.speed

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

        # 地面碰撞
        if self.y + self.h >= ground_y:
            self.y = ground_y - self.h
            self.vy = 0
            self.jumping = False

        # 限制角色左边界
        if self.x < 0:
            self.x = 0

    def jump(self):
        if not self.jumping and not game_over:
            self.vy = self.jump_pow
            self.jumping = True

    def draw(self):
        # 受伤闪烁
        if self.invincible > 0 and self.invincible % 8 < 4:
            return
        pygame.draw.circle(screen, SKIN, (self.x+20, self.y+12), 12)
        pygame.draw.rect(screen, MARIO_RED, (self.x+2, self.y, 36, 10))
        pygame.draw.rect(screen, MARIO_RED, (self.x+5, self.y+20, 30, 25))
        pygame.draw.rect(screen, LEG, (self.x+8, self.y+45, 8, 15))
        pygame.draw.rect(screen, LEG, (self.x+24, self.y+45, 8, 15))

    def get_rect(self):
        return pygame.Rect(self.x, self.y, self.w, self.h)

# ========== 金币类 ==========
class Coin:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.r = 12
        self.get = False

    def draw(self):
        if not self.get:
            dx = self.x - scroll_x
            pygame.draw.circle(screen, COIN, (dx, self.y), self.r)

    def get_rect(self):
        dx = self.x - scroll_x
        return pygame.Rect(dx-12, self.y-12, 24, 24)

# ========== 障碍物方块类 ==========
class Block:
    def __init__(self, x, y, w, h, color):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.color = color

    def draw(self):
        dx = self.x - scroll_x
        pygame.draw.rect(screen, self.color, (dx, self.y, self.w, self.h))

    def get_rect(self):
        dx = self.x - scroll_x
        return pygame.Rect(dx, self.y, self.w, self.h)

# ========== 管道类 ==========
class Pipe:
    def __init__(self, x):
        self.x = x
        self.y = ground_y - 80
        self.w = 40
        self.h = 80

    def draw(self):
        dx = self.x - scroll_x
        # 管道主体
        pygame.draw.rect(screen, PIPE_GREEN, (dx, self.y, self.w, self.h))
        # 管道顶部边框
        pygame.draw.rect(screen, PIPE_GREEN, (dx-5, self.y, self.w+10, 15))

    def get_rect(self):
        dx = self.x - scroll_x
        return pygame.Rect(dx, self.y, self.w, self.h)

# ========== 食人花类 ==========
class Flower:
    def __init__(self, pipe_x):
        self.x = pipe_x + 8
        self.base_y = ground_y - 70
        self.y = self.base_y
        self.w = 24
        self.h = 30
        self.anim_timer = 0
        self.extend_speed = 2
        self.is_extend = False

    def update(self):
        if game_over:
            return
        self.anim_timer += 1
        # 伸缩动画
        if self.is_extend:
            self.y -= self.extend_speed
            if self.y <= self.base_y - 50:
                self.is_extend = False
        else:
            self.y += self.extend_speed
            if self.y >= self.base_y:
                self.is_extend = True

    def draw(self):
        dx = self.x - scroll_x
        # 花茎
        pygame.draw.rect(screen, PIPE_GREEN, (dx+8, self.y, 8, 30))
        # 花朵
        pygame.draw.circle(screen, FLOWER_RED, (dx+12, self.y), 12)

    def get_rect(self):
        dx = self.x - scroll_x
        return pygame.Rect(dx, self.y, self.w, self.h)

# ========== 乌龟敌人类 ==========
class Turtle:
    def __init__(self, x, speed=2):
        self.x = x
        self.y = ground_y - 35
        self.w = 30
        self.h = 35
        self.speed = speed
        self.dir = 1
        self.live = True

    def update(self):
        if not self.live or game_over:
            return
        self.x += self.speed * self.dir
        if self.x < 100 or self.x > 2200:
            self.dir *= -1

    def draw(self):
        if not self.live:
            return
        dx = self.x - scroll_x
        pygame.draw.ellipse(screen, TURTLE, (dx, self.y, self.w, self.h))

    def get_rect(self):
        dx = self.x - scroll_x
        return pygame.Rect(dx, self.y, self.w, self.h)

# 生成当前关卡场景
def create_level(level):
    blocks = []
    coins = []
    turtles = []
    pipes = []
    flowers = []

    # 根据关卡调整敌人数量、速度
    turtle_speed = 2 + level * 0.5
    enemy_num = 4 + level * 2

    # 基础平台与金币
    for i in range(1, 12):
        bx = 300 + i * 160
        blocks.append(Block(bx, 320, 50, 30, BRICK))
        blocks.append(Block(bx+80, ground_y-60, 25, 60, PILLAR))
        coins.append(Coin(bx+20, 280))
        coins.append(Coin(bx+100, 350))

    # 生成管道 + 食人花
    pipe_pos = [450, 750, 1100, 1400, 1700]
    for pos in pipe_pos[:3+level]:
        p = Pipe(pos)
        pipes.append(p)
        flowers.append(Flower(pos))

    # 生成乌龟敌人
    for i in range(enemy_num):
        tx = 400 + i * 220
        turtles.append(Turtle(tx, turtle_speed))

    return blocks, coins, turtles, pipes, flowers

# 重置游戏 / 切换关卡
def reset_game(next_level=False):
    global mario, blocks, coins, turtles, pipes, flowers
    global scroll_x, score, hp, game_over, current_level, level_complete

    if next_level:
        current_level += 1
        level_complete = False
        scroll_x = 0
    else:
        scroll_x = 0
        score = 0
        hp = 3
        current_level = 1
        game_over = False
        level_complete = False

    mario = Mario()
    blocks, coins, turtles, pipes, flowers = create_level(current_level)

# 初始化游戏
reset_game()

# 字体加载
try:
    font = pygame.font.SysFont("arial", 28)
    big_font = pygame.font.SysFont("arial", 50)
    tip_font = pygame.font.SysFont("arial", 36)
except:
    font = pygame.font.Font(None, 28)
    big_font = pygame.font.Font(None, 50)
    tip_font = pygame.font.Font(None, 36)

# 主循环
while True:
    screen.fill(SKY)
    keys = pygame.key.get_pressed()

    # 事件监听
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if e.type == pygame.KEYDOWN:
            if e.key == pygame.K_SPACE:
                mario.jump()
            if game_over and e.key == pygame.K_r:
                reset_game()
            # 关卡通关后按空格进入下一关
            if level_complete and e.key == pygame.K_SPACE:
                if current_level < max_level:
                    reset_game(next_level=True)
                else:
                    game_over = True

    if not game_over and not level_complete:
        # 场景滚动
        if mario.vx > 0 and mario.x > 250 and scroll_x < MAX_SCROLL:
            scroll_x += mario.vx
        if mario.vx < 0 and scroll_x > 0:
            scroll_x += mario.vx

        mario.update(keys)
        for t in turtles:
            t.update()
        for f in flowers:
            f.update()

    # 绘制地面
    pygame.draw.rect(screen, GROUND, (-scroll_x, ground_y, 2800, 80))

    mario_rect = mario.get_rect()

    # 1. 砖块障碍物 + 碰撞
    for b in blocks:
        b.draw()
        block_rect = b.get_rect()
        if mario_rect.colliderect(block_rect):
            if mario.vx > 0:
                mario.x = block_rect.left - mario.w
            elif mario.vx < 0:
                mario.x = block_rect.right

    # 2. 管道 + 碰撞阻挡
    for p in pipes:
        p.draw()
        pipe_rect = p.get_rect()
        if mario_rect.colliderect(pipe_rect):
            if mario.vx > 0:
                mario.x = pipe_rect.left - mario.w
            elif mario.vx < 0:
                mario.x = pipe_rect.right

    # 3. 金币收集
    for c in coins:
        c.draw()
        if not c.get and mario_rect.colliderect(c.get_rect()):
            c.get = True
            score += 10

    # 4. 乌龟敌人逻辑
    for t in turtles:
        t.draw()
        if not t.live:
            continue
        t_rect = t.get_rect()
        if mario_rect.colliderect(t_rect):
            # 踩踏击杀
            if mario.vy > 0 and mario.y + mario.h < t.y + 15:
                t.live = False
                mario.vy = -8
                score += 50
            # 受伤扣血
            elif mario.invincible <= 0:
                hp -= 1
                mario.invincible = 80
                if hp <= 0:
                    game_over = True

    # 5. 食人花碰撞扣血
    for f in flowers:
        f.draw()
        flower_rect = f.get_rect()
        if mario_rect.colliderect(flower_rect) and mario.invincible <= 0:
            hp -= 1
            mario.invincible = 80
            if hp <= 0:
                game_over = True

    # 检测关卡通关（走到地图最右侧）
    if scroll_x >= MAX_SCROLL - 200 and not level_complete and not game_over:
        level_complete = True

    # 绘制马里奥
    mario.draw()

    # 绘制UI：分数、血量、关卡
    s_text = font.render(f"Score: {score}", True, WHITE)
    h_text = font.render(f"HP: {hp}", True, RED)
    l_text = font.render(f"Level: {current_level}/{max_level}", True, WHITE)
    screen.blit(s_text, (10, 10))
    screen.blit(h_text, (10, 40))
    screen.blit(l_text, (620, 10))

    # 关卡通关界面
    if level_complete and not game_over:
        cover = pygame.Surface((WIDTH, HEIGHT))
        cover.set_alpha(140)
        cover.fill(BLACK)
        screen.blit(cover, (0, 0))
        if current_level < max_level:
            clear_text = tip_font.render(f"Level {current_level} Clear!", True, WHITE)
            next_text = font.render("Press SPACE to Next Level", True, WHITE)
        else:
            clear_text = tip_font.render("ALL LEVELS CLEAR!", True, (0, 255, 0))
            next_text = font.render("Game Complete!", True, WHITE)
        screen.blit(clear_text, (WIDTH//2 - clear_text.get_width()//2, 200))
        screen.blit(next_text, (WIDTH//2 - next_text.get_width()//2, 280))

    # 游戏结束界面
    if game_over:
        cover = pygame.Surface((WIDTH, HEIGHT))
        cover.set_alpha(160)
        cover.fill(BLACK)
        screen.blit(cover, (0, 0))

        over = big_font.render("GAME OVER", True, RED)
        tip = font.render("Press R to Restart", True, WHITE)
        final = font.render(f"Final Score: {score}", True, WHITE)

        screen.blit(over, (WIDTH//2 - over.get_width()//2, 180))
        screen.blit(final, (WIDTH//2 - final.get_width()//2, 260))
        screen.blit(tip, (WIDTH//2 - tip.get_width()//2, 320))

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