import pygame, random, math, sys

pygame.init()

# ---------- 基础配置 ----------
W, H = 960, 600
CELL = 48
COLS, ROWS = W // CELL, H // CELL
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("豆腐公主")
clock = pygame.time.Clock()

# ---------- 中文字体 ----------
def find_cn_font():
    import os
    candidates = [
        r"C:\Windows\Fonts\msyhbd.ttc",
        r"C:\Windows\Fonts\msyh.ttc",
        r"C:\Windows\Fonts\simhei.ttf",
        r"C:\Windows\Fonts\Deng.ttf",
        "/System/Library/Fonts/PingFang.ttc",
        "/usr/share/fonts/truetype/noto/NotoSansCJK-Bold.ttc",
    ]
    for p in candidates:
        if os.path.exists(p):
            return p
    return None

FONT_PATH = find_cn_font()

def font(size, bold=False):
    if FONT_PATH:
        return pygame.font.Font(FONT_PATH, size)
    return pygame.font.SysFont(["microsoftyahei", "simhei", "arial"], size, bold)

def text(s, msg, size, color, pos, center=True):
    f = font(size)
    surf = f.render(msg, True, color)
    r = surf.get_rect(center=pos) if center else surf.get_rect(topleft=pos)
    s.blit(surf, r)

# ---------- 颜色 ----------
WHITE = (255, 255, 255)
PINK  = (255, 182, 193)
TOFU  = (245, 245, 230)
BROWN = (120, 80, 50)
GREEN = (170, 220, 150)
RED   = (220, 80, 80)
BLUE  = (120, 200, 255)

# ---------- 路径 ----------
PATH = [(0, 3), (6, 3), (6, 7), (13, 7), (13, 2), (18, 2)]
def path_points():
    pts = []
    for i in range(len(PATH) - 1):
        x1, y1 = PATH[i]
        x2, y2 = PATH[i + 1]
        steps = max(abs(x2 - x1), abs(y2 - y1))
        for s in range(steps):
            t = s / steps
            px = (x1 + (x2 - x1) * t) * CELL + CELL // 2
            py = (y1 + (y2 - y1) * t) * CELL + CELL // 2
            pts.append((px, py))
    pts.append((PATH[-1][0] * CELL + CELL // 2, PATH[-1][1] * CELL + CELL // 2))
    return pts

PATH_PTS = path_points()
PATH_SET = set(PATH)

# ---------- 炮台定义 ----------
TOWERS = {
    1: {"name": "嫩豆腐", "cost": 60, "dmg": 8,  "range": 110, "cd": 35, "color": TOFU},
    2: {"name": "炸豆腐", "cost": 120,"dmg": 22, "range": 90,  "cd": 70, "color": BROWN},
    3: {"name": "豆浆冰", "cost": 90, "dmg": 5,  "range": 130, "cd": 25, "color": BLUE, "slow": 0.5},
}

# ---------- 妖怪定义 ----------
MOBS = {
    "rat":   {"hp": 30,  "speed": 1.1, "money": 8,  "color": (160, 120, 90)},
    "latiao":{"hp": 55,  "speed": 1.6, "money": 12, "color": (200, 60, 60)},
    "stinky":{"hp": 120, "speed": 0.8, "money": 20, "color": (90, 90, 60)},
    "king":  {"hp": 600, "speed": 0.7, "money": 100,"color": (180, 80, 200)},
}

# ---------- 实体 ----------
class Mob:
    def __init__(self, kind):
        self.kind = kind
        d = MOBS[kind]
        self.hp = d["hp"]
        self.maxhp = d["hp"]
        self.speed = d["speed"]
        self.money = d["money"]
        self.color = d["color"]
        self.i = 0
        self.x, self.y = PATH_PTS[0]
        self.slow = 0

    def update(self):
        if self.slow > 0:
            self.slow -= 1
            sp = self.speed * 0.5
        else:
            sp = self.speed
        self.i += sp
        idx = int(self.i)
        if idx >= len(PATH_PTS) - 1:
            return "reach"
        self.x, self.y = PATH_PTS[idx]
        return "ok"

    def draw(self, s):
        pygame.draw.circle(s, self.color, (int(self.x), int(self.y)), 14)
        pygame.draw.rect(s, RED, (int(self.x)-16, int(self.y)-24, 32, 4))
        pygame.draw.rect(s, GREEN, (int(self.x)-16, int(self.y)-24, int(32*self.hp/self.maxhp), 4))

class Tower:
    def __init__(self, cx, cy, tid):
        self.cx, self.cy = cx, cy
        self.tid = tid
        self.cd = 0
        d = TOWERS[tid]
        self.dmg = d["dmg"]
        self.range = d["range"]
        self.interval = d["cd"]
        self.color = d["color"]
        self.slow = d.get("slow", 0)

    def update(self, mobs):
        if self.cd > 0:
            self.cd -= 1
            return None
        for m in mobs:
            if math.hypot(m.x - self.cx, m.y - self.cy) <= self.range:
                self.cd = self.interval
                if self.slow:
                    m.slow = 120
                return (m, self.dmg)
        return None

    def draw(self, s):
        pygame.draw.rect(s, self.color, (self.cx-18, self.cy-18, 36, 36), border_radius=8)
        pygame.draw.circle(s, WHITE, (self.cx, self.cy), 6)

# ---------- 游戏状态 ----------
class Game:
    def __init__(self):
        self.mobs = []
        self.towers = []
        self.money = 200
        self.life = 10
        self.wave = 0
        self.sel = 1
        self.state = "menu"
        self.spawn = []
        self.timer = 0

    def start_wave(self):
        self.wave += 1
        base = ["rat"] * 5
        if self.wave > 2: base += ["latiao"] * 3
        if self.wave > 4: base += ["stinky"] * 2
        if self.wave % 5 == 0: base += ["king"]
        self.spawn = base
        self.timer = 0

    def update(self):
        if self.state != "play":
            return
        self.timer += 1
        if self.spawn and self.timer % 40 == 0:
            self.mobs.append(Mob(self.spawn.pop(0)))

        for t in self.towers:
            r = t.update(self.mobs)
            if r:
                m, dmg = r
                m.hp -= dmg
                if m.hp <= 0 and m in self.mobs:
                    self.mobs.remove(m)
                    self.money += m.money

        for m in self.mobs[:]:
            if m.update() == "reach":
                self.mobs.remove(m)
                self.life -= 1
                if self.life <= 0:
                    self.state = "lose"

        if not self.spawn and not self.mobs and self.state == "play":
            if self.wave >= 10:
                self.state = "win"
            else:
                self.state = "shop"

# ---------- 绘制 ----------
def draw_map(s):
    s.fill(GREEN)
    for x in range(COLS):
        for y in range(ROWS):
            if (x, y) in PATH_SET:
                pygame.draw.rect(s, (210, 180, 140), (x*CELL, y*CELL, CELL, CELL))
    # 公主小屋
    pygame.draw.rect(s, PINK, (W-90, 40, 70, 70), border_radius=10)
    text(s, "豆腐公主", 18, BROWN, (W-55, 75))

def draw_ui(s, g):
    text(s, f"豆币 {g.money}", 22, WHITE, (20, 20), False)
    text(s, f"公主血 {g.life}", 22, RED, (20, 50), False)
    text(s, f"第 {g.wave} 波", 22, WHITE, (20, 80), False)
    for k in (1, 2, 3):
        d = TOWERS[k]
        col = (255, 255, 0) if g.sel == k else WHITE
        text(s, f"{k}.{d['name']} {d['cost']}", 20, col, (20, 520 + k*30), False)

def draw(s, g):
    draw_map(s)
    for t in g.towers: t.draw(s)
    for m in g.mobs: m.draw(s)
    draw_ui(s, g)

    if g.state == "menu":
        s.fill((0, 0, 0, 180))
        text(s, "豆 腐 公 主", 64, PINK, (W//2, 220))
        text(s, "空格开始 · 1/2/3 建塔", 24, WHITE, (W//2, 320))

    elif g.state == "shop":
        text(s, "本波结束！空格开始下一波", 28, WHITE, (W//2, 300))

    elif g.state == "win":
        text(s, "公主平安，豆腐永存 🎉", 40, PINK, (W//2, 280))

    elif g.state == "lose":
        text(s, "公主被馋哭了呢…", 40, RED, (W//2, 280))
        text(s, "按 R 重来", 24, WHITE, (W//2, 340))

# ---------- 主循环 ----------
def main():
    g = Game()
    while True:
        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:
                    if g.state in ("menu", "shop"):
                        g.state = "play"
                        g.start_wave()
                    elif g.state in ("win", "lose"):
                        pass
                if e.key in (pygame.K_1, pygame.K_2, pygame.K_3):
                    g.sel = e.key - pygame.K_0
                if e.key == pygame.K_r and g.state == "lose":
                    g = Game()
                if e.key == pygame.K_p:
                    g.state = "menu" if g.state == "play" else "play"

            if e.type == pygame.MOUSEBUTTONDOWN and g.state == "play":
                mx, my = e.pos
                cx, cy = (mx // CELL) * CELL + CELL//2, (my // CELL) * CELL + CELL//2
                gx, gy = mx // CELL, my // CELL
                if (gx, gy) in PATH_SET: continue
                if any(t.cx == cx and t.cy == cy for t in g.towers): continue
                d = TOWERS[g.sel]
                if g.money >= d["cost"]:
                    g.money -= d["cost"]
                    g.towers.append(Tower(cx, cy, g.sel))

        g.update()
        draw(screen, g)
        pygame.display.flip()
        clock.tick(60)

if __name__ == "__main__":
    main()