#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 本文件由 360问AI 生成
"""
终极硬核荒野求生 2D - PyGame版
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
操作: WASD移动 | Shift冲刺 | E互动 | Tab菜单 | 1-9快捷操作
      M地图 | I背包 | C制作 | B建造 | 鼠标点击UI按钮

核心系统: 2D俯视地图 | 昼夜交替 | 肢体受伤 | 体温 | 精神值 | 天气 | 四季
          食物腐烂 | 疾病感染 | 冻伤 | 战斗 | 野兽AI | 营火燃料 | 建筑
"""

import pygame
import random
import math
import time
import sys

# ─── 常量 ──────────────────────────────────────────────────
WIDTH, HEIGHT = 1200, 800
TILE_SIZE = 32
MAP_W, MAP_H = 80, 60
FPS = 60

# 时间流速: 120帧(2秒) = 1游戏分钟  →  24h = 48分钟现实
SECONDS_PER_GAME_MINUTE = 2.0
MINUTES_PER_HOUR = 60
HOURS_PER_DAY = 24
DAYS_PER_SEASON = 10

# ─── 颜色 ──────────────────────────────────────────────────
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)
DARK_GRAY = (50, 50, 50)
RED = (220, 50, 50)
DARK_RED = (140, 20, 20)
GREEN = (50, 180, 50)
DARK_GREEN = (30, 100, 30)
FOREST_GREEN = (20, 70, 20)
BLUE = (50, 100, 200)
LIGHT_BLUE = (135, 206, 235)
BROWN = (139, 90, 43)
DARK_BROWN = (90, 55, 25)
YELLOW = (230, 200, 50)
ORANGE = (230, 140, 50)
PURPLE = (160, 60, 200)
CYAN = (0, 200, 200)
SKIN = (230, 190, 150)

# 地形颜色
TILE_COLORS = {
    0: (100, 160, 70),   # 草地
    1: (80, 140, 55),    # 深草
    2: (30, 80, 30),     # 森林
    3: (50, 110, 190),   # 水
    4: (30, 70, 150),    # 深水
    5: (160, 160, 160),  # 岩石
    6: (180, 160, 100),  # 沙地
    7: (120, 90, 50),    # 泥地
    8: (60, 60, 60),     # 洞穴
    9: (220, 220, 235),  # 雪地
}

# 地形类型
T_GRASS = 0
T_TALL_GRASS = 1
T_FOREST = 2
T_WATER = 3
T_DEEP_WATER = 4
T_ROCK = 5
T_SAND = 6
T_DIRT = 7
T_CAVE = 8
T_SNOW = 9

TILE_WALKABLE = {
    T_GRASS: True, T_TALL_GRASS: True, T_FOREST: False,
    T_WATER: True, T_DEEP_WATER: False, T_ROCK: False,
    T_SAND: True, T_DIRT: True, T_CAVE: True, T_SNOW: True,
}

TILE_NAMES = {
    T_GRASS: "草地", T_TALL_GRASS: "深草丛", T_FOREST: "森林",
    T_WATER: "浅水", T_DEEP_WATER: "深水", T_ROCK: "岩石",
    T_SAND: "沙地", T_DIRT: "泥地", T_CAVE: "洞穴入口", T_SNOW: "雪地",
}

# 季节
SPRING, SUMMER, AUTUMN, WINTER = 0, 1, 2, 3
SEASON_NAMES = ["春", "夏", "秋", "冬"]

# 天气
W_CLEAR, W_CLOUDY, W_RAIN, W_STORM, W_WIND, W_BLIZZARD = range(6)
WEATHER_NAMES = ["晴天", "多云", "小雨", "暴风雨", "大风", "暴风雪"]

# 身体部位
BP_HEAD = "head"
BP_TORSO = "torso"
BP_L_ARM = "l_arm"
BP_R_ARM = "r_arm"
BP_L_LEG = "l_leg"
BP_R_LEG = "r_leg"
BODY_PARTS = [BP_HEAD, BP_TORSO, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG]
BP_NAMES = {
    BP_HEAD: "头部", BP_TORSO: "躯干", BP_L_ARM: "左臂",
    BP_R_ARM: "右臂", BP_L_LEG: "左腿", BP_R_LEG: "右腿"
}
BP_MAX_HP = {BP_HEAD: 100, BP_TORSO: 200, BP_L_ARM: 80, BP_R_ARM: 80, BP_L_LEG: 80, BP_R_LEG: 80}

# ─── 物品定义 ──────────────────────────────────────────────
ITEMS = {
    # 材料
    "wood": ("木材", BROWN, "material"),
    "stone": ("石头", GRAY, "material"),
    "fiber": ("纤维", (150, 180, 80), "material"),
    "bone": ("骨头", (230, 220, 200), "material"),
    "clay": ("黏土", (180, 120, 70), "material"),
    "herb": ("草药", (80, 200, 80), "material"),
    "fur": ("兽皮", (180, 140, 90), "material"),
    "iron_ore": ("铁矿", (120, 120, 140), "material"),
    "rope": ("绳索", (160, 140, 80), "material"),
    # 食物
    "berry": ("浆果", (200, 50, 80), "food"),
    "mushroom": ("蘑菇", (180, 140, 80), "food"),
    "raw_meat": ("生肉", (200, 80, 80), "food"),
    "cooked_meat": ("烤肉", (160, 100, 60), "food"),
    "raw_fish": ("生鱼", (100, 150, 200), "food"),
    "cooked_fish": ("烤鱼", (180, 150, 100), "food"),
    "stew": ("肉汤", (180, 120, 60), "food"),
    "tea": ("草药茶", (120, 180, 100), "food"),
    "dirty_water": ("脏水", (120, 140, 100), "food"),
    "clean_water": ("净水", (80, 180, 220), "food"),
    # 医疗
    "bandage": ("绷带", (240, 240, 230), "medical"),
    "splint": ("夹板", (180, 150, 100), "medical"),
    "poultice": ("药膏", (100, 180, 100), "medical"),
    "antibiotic": ("抗生素", (60, 200, 120), "medical"),
    # 武器
    "stone_axe": ("石斧", (160, 140, 100), "weapon"),
    "spear": ("长矛", (180, 160, 120), "weapon"),
    "bone_knife": ("骨刃", (220, 200, 170), "weapon"),
    "wood_club": ("木棍", (150, 110, 60), "weapon"),
    "bow": ("弓", (140, 100, 50), "weapon"),
    "arrow": ("箭", (160, 140, 100), "weapon"),
    # 工具
    "torch": ("火把", (255, 180, 50), "tool"),
    "trap": ("捕兽夹", (140, 120, 80), "tool"),
    "fishing_rod": ("鱼竿", (150, 120, 70), "tool"),
    "water_filter": ("净水器", (100, 180, 200), "tool"),
    # 装备
    "leather_armor": ("皮甲", (160, 120, 70), "armor"),
    "fur_coat": ("皮袄", (140, 110, 70), "armor"),
    "backpack": ("大背包", (130, 100, 60), "armor"),
}

# 食物属性: (饱食, 水分, HP恢复, 精神恢复, 能否生吃, 腐烂时间游戏小时)
FOOD_DATA = {
    "berry":       (12, 5, 0, 3, True, 60),
    "mushroom":    (8, 0, 0, 1, True, 48),
    "raw_meat":    (15, 0, -5, -2, True, 48),
    "cooked_meat": (40, 0, 15, 5, False, 120),
    "raw_fish":    (12, 5, -3, -1, True, 36),
    "cooked_fish": (35, 5, 10, 4, False, 96),
    "stew":        (55, 20, 25, 12, False, 72),
    "tea":         (0, 15, 5, 10, False, 48),
    "dirty_water": (0, 20, -8, -5, True, 9999),
    "clean_water": (0, 35, 2, 2, True, 9999),
}

# 武器属性: (伤害, 速度, 特殊)
WEAPON_DATA = {
    None: (5, 1.0, ""),
    "wood_club": (12, 0.8, ""),
    "stone_axe": (18, 0.7, "砍树效率x2"),
    "spear": (22, 0.9, "穿刺"),
    "bone_knife": (25, 1.2, "流血+"),
    "bow": (30, 0.6, "远程"),
}

ARMOR_DATA = {
    None: (0, 0),
    "leather_armor": (8, 0),
    "fur_coat": (5, 5),  # (防御, 保暖)
    "backpack": (0, 0),  # 增加背包容量
}

# 配方
RECIPES = [
    ("wood_club", {"wood": 3}, "简易武器 ATK+12"),
    ("stone_axe", {"wood": 2, "stone": 2, "fiber": 1}, "工具武器 ATK+18 伐木x2"),
    ("spear", {"wood": 3, "stone": 2, "fiber": 2}, "穿刺武器 ATK+22"),
    ("bone_knife", {"bone": 3, "fiber": 2}, "锋利武器 ATK+25 流血"),
    ("bow", {"wood": 4, "fiber": 4, "rope": 1}, "远程武器 ATK+30"),
    ("arrow", {"wood": 1, "stone": 1, "fiber": 1}, "箭矢x3 (需要弓)"),
    ("bandage", {"fiber": 3}, "止血 治疗流血"),
    ("splint", {"wood": 2, "fiber": 2}, "固定骨折"),
    ("poultice", {"herb": 3, "fiber": 1}, "治疗感染 恢复HP"),
    ("antibiotic", {"herb": 5, "clean_water": 1}, "根治感染+疾病"),
    ("torch", {"wood": 1, "fiber": 2}, "照明 驱兽 持续60分钟"),
    ("trap", {"wood": 3, "stone": 2, "fiber": 2}, "放置后自动捕猎"),
    ("fishing_rod", {"wood": 3, "fiber": 3}, "在水边钓鱼"),
    ("water_filter", {"wood": 2, "stone": 3, "fiber": 2}, "脏水→净水"),
    ("stew", {"cooked_meat": 1, "clean_water": 1, "herb": 1}, "饱食+55 水分+20 HP+25"),
    ("tea", {"herb": 2, "clean_water": 1}, "精神+10 治疗感冒"),
    ("rope", {"fiber": 5}, "合成材料"),
    ("leather_armor", {"fur": 4, "fiber": 3}, "防御+8"),
    ("fur_coat", {"fur": 6, "fiber": 4, "rope": 1}, "防御+5 保暖+5"),
    ("backpack", {"fur": 3, "fiber": 5, "rope": 2}, "背包容量+20"),
    ("campfire_kit", {"wood": 5, "stone": 3}, "可放置营火"),
]

# 野兽定义
BEASTS = {
    "rabbit": {
        "name": "野兔", "hp": 30, "atk": 5, "def": 0, "speed": 5,
        "color": (180, 150, 120), "drops": [("raw_meat", 1), ("fur", 1)],
        "xp": 10, "aggro": False, "size": 8,
    },
    "snake": {
        "name": "毒蛇", "hp": 40, "atk": 18, "def": 1, "speed": 3,
        "color": (80, 160, 50), "drops": [("raw_meat", 1)],
        "xp": 25, "aggro": True, "size": 10, "poison": True,
    },
    "wolf": {
        "name": "灰狼", "hp": 100, "atk": 25, "def": 5, "speed": 4,
        "color": (130, 130, 140), "drops": [("raw_meat", 2), ("fur", 2), ("bone", 1)],
        "xp": 40, "aggro": True, "size": 14,
    },
    "boar": {
        "name": "野猪", "hp": 130, "atk": 20, "def": 8, "speed": 3,
        "color": (130, 80, 50), "drops": [("raw_meat", 3), ("fur", 2)],
        "xp": 35, "aggro": True, "size": 16,
    },
    "bear": {
        "name": "棕熊", "hp": 250, "atk": 40, "def": 12, "speed": 2,
        "color": (100, 70, 40), "drops": [("raw_meat", 4), ("fur", 3), ("bone", 2)],
        "xp": 80, "aggro": True, "size": 22,
    },
    "leopard": {
        "name": "山豹", "hp": 150, "atk": 35, "def": 6, "speed": 5,
        "color": (210, 180, 80), "drops": [("raw_meat", 2), ("fur", 3), ("bone", 1)],
        "xp": 60, "aggro": True, "size": 16,
    },
}

# 建筑定义
BUILDINGS = {
    "campfire": ("营火", {"wood": 5, "stone": 3}, (255, 140, 30), 2),
    "shelter": ("庇护所", {"wood": 15, "fiber": 8, "stone": 5}, (140, 100, 60), 3),
    "wall": ("围墙", {"stone": 8, "wood": 2}, (120, 120, 120), 1),
    "drying_rack": ("晾肉架", {"wood": 6, "fiber": 4}, (160, 130, 80), 2),
    "storage": ("储物箱", {"wood": 8, "stone": 4}, (130, 90, 50), 2),
}


# ─── 身体部位类 ────────────────────────────────────────────
class BodyPart:
    def __init__(self, name, max_hp):
        self.name = name
        self.max_hp = max_hp
        self.hp = max_hp
        self.bleeding = False
        self.bleed_timer = 0.0
        self.fractured = False
        self.infected = False
        self.frostbite = False
        self.crippled = False

    @property
    def ratio(self):
        return max(0, self.hp / self.max_hp) if self.max_hp > 0 else 0

    @property
    def alive(self):
        return self.hp > 0

    def take_damage(self, dmg):
        if self.crippled:
            return
        actual = max(1, int(dmg))
        self.hp = max(0, self.hp - actual)
        if self.hp <= 0:
            self.crippled = True
            self.bleeding = True
        elif random.random() < 0.2:
            self.bleeding = True
        return actual

    def heal(self, amount):
        if self.crippled:
            return 0
        old = self.hp
        self.hp = min(self.max_hp, self.hp + int(amount))
        return self.hp - old

    def get_status(self):
        parts = []
        if self.crippled:
            parts.append("💀残废")
        if self.bleeding:
            parts.append("🩸流血")
        if self.fractured:
            parts.append("🦴骨折")
        if self.infected:
            parts.append("🦠感染")
        if self.frostbite:
            parts.append("🥶冻伤")
        return " ".join(parts) if parts else "正常"

    def get_color(self):
        if self.crippled:
            return (60, 60, 60)
        if self.infected:
            return (160, 50, 50)
        if self.bleeding:
            return (200, 50, 50)
        if self.fractured:
            return (220, 180, 50)
        if self.frostbite:
            return (100, 180, 255)
        r = self.ratio
        if r > 0.7:
            return (50, 200, 50)
        elif r > 0.4:
            return (220, 200, 50)
        elif r > 0.1:
            return (220, 120, 50)
        else:
            return (200, 50, 50)


# ─── 玩家类 ────────────────────────────────────────────────
class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.direction = 0  # 0下 1左 2右 3上

        # 生存属性
        self.hunger = 100.0
        self.thirst = 100.0
        self.stamina = 100.0
        self.mental = 100.0
        self.body_temp = 36.5
        self.energy = 100.0

        # 身体部位
        self.body = {}
        for bp in BODY_PARTS:
            self.body[bp] = BodyPart(bp, BP_MAX_HP[bp])

        # 状态效果
        self.poisoned = 0.0     # 中毒剩余时间(游戏分钟)
        self.sick = 0.0         # 生病剩余时间
        self.disease_name = ""
        self.cold = False       # 感冒
        self.wet = 0.0          # 潮湿程度

        # 装备
        self.weapon = None
        self.armor = None

        # 背包
        self.inventory = {}
        self.max_inventory = 30
        self.inventory["wood"] = 2
        self.inventory["fiber"] = 3

        # 食物腐烂追踪 {item_name: [(count, expire_game_hour), ...]}
        self.food_timers = {}

        # 等级
        self.level = 1
        self.xp = 0
        self.xp_next = 50

        # 移动
        self.move_speed = 3.0  # 格/秒
        self.sprint_mult = 1.8
        self.is_sprinting = False
        self.move_cooldown = 0

        # 统计
        self.days_survived = 0
        self.beasts_killed = 0
        self.steps_walked = 0

    @property
    def is_alive(self):
        return self.body[BP_TORSO].hp > 0

    @property
    def total_hp(self):
        return sum(bp.hp for bp in self.body.values())

    @property
    def total_max_hp(self):
        return sum(bp.max_hp for bp in self.body.values())

    def get_attack(self):
        base = 5 + self.level * 2
        if self.weapon and self.weapon in WEAPON_DATA:
            base += WEAPON_DATA[self.weapon][0]
        # 手臂影响
        if self.body[BP_L_ARM].crippled:
            base *= 0.5
        if self.body[BP_R_ARM].crippled:
            base *= 0.5
        if self.body[BP_L_ARM].fractured:
            base *= 0.7
        if self.body[BP_R_ARM].fractured:
            base *= 0.7
        return max(1, int(base))

    def get_defense(self):
        base = 0
        if self.armor and self.armor in ARMOR_DATA:
            base += ARMOR_DATA[self.armor][0]
        base += self.level
        return base

    def get_warmth(self):
        warmth = 0
        if self.armor and self.armor in ARMOR_DATA:
            warmth += ARMOR_DATA[self.armor][1]
        return warmth

    def get_speed(self):
        speed = self.move_speed
        if self.body[BP_L_LEG].crippled:
            speed *= 0.3
        if self.body[BP_R_LEG].crippled:
            speed *= 0.3
        if self.body[BP_L_LEG].fractured:
            speed *= 0.5
        if self.body[BP_R_LEG].fractured:
            speed *= 0.5
        if self.stamina < 20:
            speed *= 0.5
        if self.energy < 10:
            speed *= 0.6
        return speed

    def get_backpack_size(self):
        base = self.max_inventory
        if self.armor == "backpack":
            base += 20
        return base

    def add_item(self, item, count=1):
        current = sum(self.inventory.values())
        if current + count > self.get_backpack_size():
            return False
        self.inventory[item] = self.inventory.get(item, 0) + count
        return True

    def remove_item(self, item, count=1):
        if item in self.inventory:
            self.inventory[item] -= count
            if self.inventory[item] <= 0:
                del self.inventory[item]
            return True
        return False

    def has_item(self, item, count=1):
        return self.inventory.get(item, 0) >= count

    def has_items(self, recipe):
        for item, count in recipe.items():
            if not self.has_item(item, count):
                return False
        return True

    def remove_items(self, recipe):
        for item, count in recipe.items():
            self.remove_item(item, count)

    def add_xp(self, amount):
        self.xp += amount
        leveled = False
        while self.xp >= self.xp_next:
            self.xp -= self.xp_next
            self.level += 1
            self.xp_next = int(self.xp_next * 1.6)
            leveled = True
        return leveled

    def add_food_timered(self, item, count, game_hour):
        """添加有保质期的食物"""
        if item not in self.food_timers:
            self.food_timers[item] = []
        if item in FOOD_DATA:
            rot_time = FOOD_DATA[item][5]
        else:
            rot_time = 9999
        self.food_timers[item].append((count, game_hour + rot_time))

    def get_food_count(self, item):
        """获取未过期的食物数量"""
        if item not in self.food_timers:
            return self.inventory.get(item, 0)
        total = 0
        for cnt, exp in self.food_timers[item]:
            total += cnt
        return total


# ─── 野兽类 ────────────────────────────────────────────────
class Beast:
    def __init__(self, btype, x, y, night_buff=False):
        data = BEASTS[btype]
        self.type = btype
        self.name = data["name"]
        self.x = x
        self.y = y
        self.max_hp = data["hp"]
        self.hp = self.max_hp
        self.atk = data["atk"]
        self.defense = data["def"]
        self.speed = data["speed"]
        self.color = data["color"]
        self.drops = data["drops"]
        self.xp = data["xp"]
        self.aggro = data["aggro"]
        self.size = data["size"]
        self.poison = data.get("poison", False)

        # AI状态
        self.state = "idle"  # idle, chase, flee, patrol
        self.target_x = x
        self.target_y = y
        self.move_timer = 0
        self.aggro_range = 6
        self.flee_range = 10
        self.alive = True

        if night_buff:
            self.atk = int(self.atk * 1.3)
            self.max_hp = int(self.max_hp * 1.2)
            self.hp = self.max_hp

    def take_damage(self, dmg):
        actual = max(1, dmg - self.defense)
        self.hp = max(0, self.hp - actual)
        if self.hp <= 0:
            self.alive = False
        return actual


# ─── 建筑类 ────────────────────────────────────────────────
class Building:
    def __init__(self, btype, x, y):
        self.type = btype
        self.x = x
        self.y = y
        self.data = BUILDINGS[btype]
        self.fuel = 0  # 营火燃料(游戏分钟)
        self.active = True
        self.contents = {}  # 储物箱内容

    @property
    def name(self):
        return self.data[0]

    @property
    def color(self):
        return self.data[2]

    @property
    def radius(self):
        return self.data[3]


# ─── 陷阱类 ────────────────────────────────────────────────
class Trap:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.caught = None
        self.check_timer = 0


# ─── 地图生成 ──────────────────────────────────────────────
def generate_map():
    """生成80x60的地形地图"""
    tiles = [[T_GRASS for _ in range(MAP_W)] for _ in range(MAP_H)]

    # 生成河流
    for _ in range(3):
        x = random.randint(10, MAP_W - 10)
        for y in range(MAP_H):
            for dx in range(-1, 2):
                nx = x + dx
                if 0 <= nx < MAP_W:
                    tiles[y][nx] = T_WATER
            if random.random() < 0.1:
                tiles[y][x] = T_DEEP_WATER
            x += random.choice([-1, 0, 0, 1])
            x = max(1, min(MAP_W - 2, x))

    # 生成森林区块
    for _ in range(15):
        cx = random.randint(5, MAP_W - 5)
        cy = random.randint(5, MAP_H - 5)
        r = random.randint(3, 7)
        for dy in range(-r, r + 1):
            for dx in range(-r, r + 1):
                if dx * dx + dy * dy <= r * r:
                    nx, ny = cx + dx, cy + dy
                    if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                        if tiles[ny][nx] in (T_GRASS, T_TALL_GRASS):
                            tiles[ny][nx] = T_FOREST

    # 散布资源
    for y in range(MAP_H):
        for x in range(MAP_W):
            if tiles[y][x] == T_GRASS:
                r = random.random()
                if r < 0.15:
                    tiles[y][x] = T_TALL_GRASS
                elif r < 0.18:
                    tiles[y][x] = T_ROCK

    # 水边沙地
    for y in range(MAP_H):
        for x in range(MAP_W):
            if tiles[y][x] in (T_WATER, T_DEEP_WATER):
                for dy in range(-1, 2):
                    for dx in range(-1, 2):
                        nx, ny = x + dx, y + dy
                        if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                            if tiles[ny][nx] == T_GRASS and random.random() < 0.5:
                                tiles[ny][nx] = T_SAND

    # 洞穴
    for _ in range(4):
        cx = random.randint(5, MAP_W - 5)
        cy = random.randint(5, MAP_H - 5)
        tiles[cy][cx] = T_CAVE

    # 确保出生点可走
    cx, cy = MAP_W // 2, MAP_H // 2
    for dy in range(-3, 4):
        for dx in range(-3, 4):
            nx, ny = cx + dx, cy + dy
            if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                tiles[ny][nx] = T_GRASS

    return tiles


# ─── 粒子系统 ──────────────────────────────────────────────
class Particle:
    def __init__(self, x, y, vx, vy, life, color, size=2):
        self.x = x
        self.y = y
        self.vx = vx
        self.vy = vy
        self.life = life
        self.max_life = life
        self.color = color
        self.size = size

    def update(self, dt):
        self.x += self.vx * dt
        self.y += self.vy * dt
        self.life -= dt
        return self.life > 0

    @property
    def alpha(self):
        return max(0, min(255, int(255 * self.life / self.max_life)))


# ─── 消息系统 ──────────────────────────────────────────────
class Message:
    def __init__(self, text, color=WHITE, duration=5.0):
        self.text = text
        self.color = color
        self.duration = duration
        self.timer = 0.0


# ─── 主游戏类 ──────────────────────────────────────────────
class Game:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
        pygame.display.set_caption("硬核荒野求生 2D - 终极版")
        self.clock = pygame.time.Clock()
        self.font_sm = pygame.font.SysFont("simhei", 14)
        self.font_md = pygame.font.SysFont("simhei", 18)
        self.font_lg = pygame.font.SysFont("simhei", 24)
        self.font_xl = pygame.font.SysFont("simhei", 32)
        self.font_title = pygame.font.SysFont("simhei", 48)

        self.running = True
        self.dt = 0

        # 地图
        self.tile_map = generate_map()
        self.explored = [[False] * MAP_W for _ in range(MAP_H)]

        # 出生点
        self.player = Player(MAP_W // 2, MAP_H // 2)
        self._reveal_area(self.player.x, self.player.y, 5)

        # 相机
        self.cam_x = self.player.x * TILE_SIZE - WIDTH // 2
        self.cam_y = self.player.y * TILE_SIZE - HEIGHT // 2

        # 时间
        self.game_minute = 6 * 60  # 从早上6点开始
        self.game_day = 1
        self.season = SPRING
        self.real_time_accum = 0.0

        # 天气
        self.weather = W_CLEAR
        self.weather_timer = 300  # 游戏分钟后换天气
        self.weather_particles = []

        # 实体
        self.beasts = []
        self.buildings = []
        self.traps = []
        self.particles = []
        self.messages = []

        # 生成初始野兽
        for _ in range(15):
            self._spawn_beast()

        # UI状态
        self.ui_mode = "game"  # game, inventory, craft, build, status, help, combat, dead
        self.ui_scroll = 0
        self.ui_selection = 0
        self.ui_tab = 0
        self.ui_interact_hint = ""
        self.combat_enemy = None
        self.combat_log = []
        self.combat_player_turn = True

        # 提示
        self.tutorial_shown = False
        self.add_message("你醒来发现自己身处荒野之中...", YELLOW)
        self.add_message("WASD移动 | E互动 | Tab菜单 | M地图", WHITE)
        self.add_message("活下去，尽可能久地生存！", GREEN)

    def add_message(self, text, color=WHITE):
        self.messages.append(Message(text, color))
        if len(self.messages) > 20:
            self.messages.pop(0)

    def _reveal_area(self, cx, cy, radius):
        for dy in range(-radius, radius + 1):
            for dx in range(-radius, radius + 1):
                nx, ny = cx + dx, cy + dy
                if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                    if dx * dx + dy * dy <= radius * radius:
                        self.explored[ny][nx] = True

    def _spawn_beast(self):
        for _ in range(50):
            x = random.randint(2, MAP_W - 3)
            y = random.randint(2, MAP_H - 3)
            dist = abs(x - self.player.x) + abs(y - self.player.y)
            if dist > 10:
                tile = self.tile_map[y][x]
                if tile in (T_GRASS, T_TALL_GRASS, T_FOREST, T_DIRT):
                    # 根据地形选择野兽
                    if tile == T_FOREST:
                        weights = [30, 15, 20, 15, 10, 10]
                    else:
                        weights = [40, 10, 20, 20, 5, 5]
                    types = list(BEASTS.keys())
                    btype = random.choices(types, weights=weights, k=1)[0]
                    night = self.is_night
                    self.beasts.append(Beast(btype, x, y, night))
                    return

    def _get_game_hour(self):
        return (self.game_minute % (HOURS_PER_DAY * MINUTES_PER_HOUR)) / MINUTES_PER_HOUR

    def _get_time_string(self):
        total_min = self.game_minute % (HOURS_PER_DAY * MINUTES_PER_HOUR)
        hour = total_min // MINUTES_PER_HOUR
        minute = total_min % MINUTES_PER_HOUR
        return f"{hour:02d}:{minute:02d}"

    @property
    def is_night(self):
        h = self._get_game_hour()
        return h < 6 or h > 20

    @property
    def is_dusk(self):
        h = self._get_game_hour()
        return 18 <= h <= 20

    @property
    def is_dawn(self):
        h = self._get_game_hour()
        return 5 <= h <= 7

    def get_daylight(self):
        """返回0.0~1.0的光照强度"""
        h = self._get_game_hour()
        if 7 <= h <= 17:
            return 1.0
        elif 21 <= h or h <= 4:
            return 0.08
        elif self.is_dawn:
            return 0.08 + (h - 5) / 2 * 0.92
        elif self.is_dusk:
            return 1.0 - (h - 18) / 2 * 0.92
        return 0.5

    def get_sky_color(self):
        h = self._get_game_hour()
        if 7 <= h <= 17:
            return (135, 206, 235)
        elif 21 <= h or h <= 4:
            return (10, 10, 35)
        elif self.is_dawn:
            t = (h - 5) / 2
            return (int(10 + t * 125), int(10 + t * 196), int(35 + t * 200))
        elif self.is_dusk:
            t = (h - 18) / 2
            return (int(200 - t * 190), int(120 - t * 110), int(80 - t * 45))
        return (80, 80, 120)

    def get_ambient_temp(self):
        """环境温度"""
        base = 20
        if self.season == SPRING:
            base = 18
        elif self.season == SUMMER:
            base = 30
        elif self.season == AUTUMN:
            base = 12
        elif self.season == WINTER:
            base = -5

        h = self._get_game_hour()
        if 6 <= h <= 14:
            base += 5
        elif h >= 22 or h <= 4:
            base -= 8

        if self.weather == W_RAIN:
            base -= 3
        elif self.weather == W_STORM:
            base -= 6
        elif self.weather == W_BLIZZARD:
            base -= 15
        elif self.weather == W_WIND:
            base -= 4

        return base

    # ─── 更新循环 ──────────────────────────────
    def update(self, dt):
        self.dt = dt

        if self.ui_mode == "dead":
            return

        # 时间推进
        self.real_time_accum += dt
        while self.real_time_accum >= SECONDS_PER_GAME_MINUTE:
            self.real_time_accum -= SECONDS_PER_GAME_MINUTE
            self._advance_game_minute()

        # 玩家移动
        if self.ui_mode == "game":
            self._update_player_movement(dt)

        # 野兽AI
        self._update_beasts(dt)

        # 粒子更新
        self.particles = [p for p in self.particles if p.update(dt)]

        # 消息更新
        for msg in self.messages:
            msg.timer += dt
        self.messages = [m for m in self.messages if m.timer < m.duration]

        # 天气粒子
        self._update_weather_particles(dt)

        # 相机跟随
        target_cx = self.player.x * TILE_SIZE - WIDTH // 2
        target_cy = self.player.y * TILE_SIZE - HEIGHT // 2
        self.cam_x += (target_cx - self.cam_x) * 0.1
        self.cam_y += (target_cy - self.cam_y) * 0.1
        self.cam_x = max(0, min(MAP_W * TILE_SIZE - WIDTH, self.cam_x))
        self.cam_y = max(0, min(MAP_H * TILE_SIZE - HEIGHT, self.cam_y))

        # 死亡检测
        if not self.player.is_alive:
            self.ui_mode = "dead"
            self.add_message("你死了...", RED)

    def _advance_game_minute(self):
        """每游戏分钟调用一次"""
        self.game_minute += 1

        # 检查日期
        total_hours = self.game_minute / MINUTES_PER_HOUR
        new_day = int(total_hours // HOURS_PER_DAY) + 1
        if new_day > self.game_day:
            self.game_day = new_day
            self.player.days_survived = self.game_day - 1
            self.add_message(f"══ 第 {self.game_day} 天 ══", YELLOW)

        # 季节
        new_season = ((self.game_day - 1) // DAYS_PER_SEASON) % 4
        if new_season != self.season:
            self.season = new_season
            self.add_message(f"季节变更: {SEASON_NAMES[self.season]}季", CYAN)

        # 每小时(60分钟)的生存消耗
        if self.game_minute % 60 == 0:
            self._hourly_survival()

        # 每10分钟检查
        if self.game_minute % 10 == 0:
            self._ten_min_update()

        # 食物腐烂检查 (每小时)
        if self.game_minute % 60 == 0:
            self._check_food_rot()

        # 营火燃料消耗
        for b in self.buildings:
            if b.type == "campfire" and b.fuel > 0:
                b.fuel -= 1
                if b.fuel <= 0:
                    b.active = False
                    self.add_message("营火熄灭了！", ORANGE)

        # 天气变化
        self.weather_timer -= 1
        if self.weather_timer <= 0:
            self._change_weather()

        # 陷阱检查
        for trap in self.traps:
            trap.check_timer += 1
            if trap.check_timer >= 120 and trap.caught is None:  # 每2小时检查
                trap.check_timer = 0
                if random.random() < 0.3:
                    trap.caught = random.choice(["raw_meat", "raw_meat", "fur", "bone"])
                    self.add_message(f"陷阱捕获了 {ITEMS[trap.caught][0]}！", GREEN)

        # 野兽重生
        if len(self.beasts) < 12 and random.random() < 0.1:
            self._spawn_beast()

    def _hourly_survival(self):
        p = self.player

        # 饱食度下降
        hunger_drain = 3.0
        if p.is_sprinting:
            hunger_drain += 2.0
        if self.season == WINTER:
            hunger_drain += 1.0
        p.hunger = max(0, p.hunger - hunger_drain)

        # 水分下降(比饱食更快)
        thirst_drain = 4.0
        if self.season == SUMMER:
            thirst_drain += 2.0
        if p.is_sprinting:
            thirst_drain += 2.0
        p.thirst = max(0, p.thirst - thirst_drain)

        # 体力恢复
        if not p.is_sprinting:
            stamina_regen = 5.0
            if self._near_building("shelter"):
                stamina_regen += 10.0
            if self._near_building("campfire") and self._building_active("campfire"):
                stamina_regen += 5.0
            p.stamina = min(100, p.stamina + stamina_regen)

        # 精力
        energy_drain = 2.0
        if self.is_night and not self._near_building("shelter"):
            energy_drain += 3.0
        if self._near_building("shelter"):
            p.energy = min(100, p.energy + 8.0)
        else:
            p.energy = max(0, p.energy - energy_drain)

        # 精神值
        mental_change = 0
        if self.is_night:
            if self._near_building("campfire") and self._building_active("campfire"):
                mental_change += 2
            else:
                mental_change -= 5
        if self._near_building("shelter"):
            mental_change += 1
        if p.hunger < 20:
            mental_change -= 2
        if p.thirst < 20:
            mental_change -= 3
        if self.weather in (W_STORM, W_BLIZZARD):
            mental_change -= 2
        # 流血影响
        bleeding_count = sum(1 for bp in p.body.values() if bp.bleeding)
        mental_change -= bleeding_count * 2
        p.mental = max(0, min(100, p.mental + mental_change))

        # 体温调节
        ambient = self.get_ambient_temp()
        warmth = p.get_warmth()
        if self._near_building("campfire") and self._building_active("campfire"):
            warmth += 10
        if self._near_building("shelter"):
            warmth += 5

        target_temp = 36.5
        temp_diff = ambient + warmth - target_temp
        if temp_diff < -10:
            p.body_temp = max(30.0, p.body_temp - 0.3)
        elif temp_diff < -5:
            p.body_temp = max(30.0, p.body_temp - 0.15)
        elif temp_diff > 15:
            p.body_temp = min(42.0, p.body_temp + 0.2)
        elif temp_diff > 5:
            p.body_temp = min(42.0, p.body_temp + 0.05)
        else:
            # 趋向正常
            if p.body_temp < 36.5:
                p.body_temp = min(36.5, p.body_temp + 0.1)
            elif p.body_temp > 36.5:
                p.body_temp = max(36.5, p.body_temp - 0.1)

        # 低温伤害
        if p.body_temp < 35.0:
            dmg = int((35.0 - p.body_temp) * 3)
            # 四肢优先冻伤
            for bp_name in [BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG]:
                bp = p.body[bp_name]
                if not bp.frostbite and p.body_temp < 34.0 and random.random() < 0.15:
                    bp.frostbite = True
                    self.add_message(f"{BP_NAMES[bp_name]}冻伤了！", CYAN)
                if bp.frostbite:
                    bp.take_damage(dmg * 0.5)
            if p.body_temp < 33.0:
                p.body[BP_TORSO].take_damage(dmg)
                self.add_message("体温过低！你会死的！", RED)

        # 高温伤害
        if p.body_temp > 39.0:
            dmg = int((p.body_temp - 39.0) * 4)
            p.body[BP_TORSO].take_damage(dmg)
            p.thirst = max(0, p.thirst - 5)
            if p.body_temp > 40.0:
                self.add_message("中暑了！快找阴凉！", RED)

        # 流血伤害
        for bp in p.body.values():
            if bp.bleeding:
                bp.bleed_timer += 1
                bp.take_damage(2)
                # 感染风险
                if bp.bleed_timer > 10 and not bp.infected and random.random() < 0.08:
                    bp.infected = True
                    self.add_message(f"{BP_NAMES[bp.name]}伤口感染了！", RED)

        # 骨折恶化
        for bp in p.body.values():
            if bp.fractured and random.random() < 0.02:
                bp.take_damage(3)

        # 感染恶化
        for bp in p.body.values():
            if bp.infected:
                bp.take_damage(2)
                if random.random() < 0.01:
                    # 感染扩散到邻近部位(简化)
                    pass

        # 冻伤恶化
        for bp in p.body.values():
            if bp.frostbite:
                bp.take_damage(1)

        # 中毒
        if p.poisoned > 0:
            p.poisoned -= 1
            p.body[BP_TORSO].take_damage(3)
            p.hunger = max(0, p.hunger - 2)
            if p.poisoned <= 0:
                self.add_message("毒素已代谢完毕", GREEN)

        # 疾病
        if p.sick > 0:
            p.sick -= 1
            p.stamina = max(0, p.stamina - 5)
            p.mental = max(0, p.mental - 2)
            if p.sick <= 0:
                self.add_message("疾病已痊愈", GREEN)
                p.disease_name = ""

        # 饥饿伤害
        if p.hunger <= 0:
            p.body[BP_TORSO].take_damage(5)
            p.mental = max(0, p.mental - 3)

        # 脱水伤害(更致命)
        if p.thirst <= 0:
            p.body[BP_TORSO].take_damage(8)
            p.mental = max(0, p.mental - 5)

        # 精神崩溃
        if p.mental <= 0:
            p.body[BP_HEAD].take_damage(5)
            self.add_message("精神崩溃了...", PURPLE)

        # 庇护所回血
        if self._near_building("shelter"):
            for bp in p.body.values():
                bp.heal(1)

        # 食物腐烂
        self._check_food_rot()

    def _ten_min_update(self):
        """每10游戏分钟"""
        p = self.player
        # 潮湿干燥
        if p.wet > 0:
            if self.weather not in (W_RAIN, W_STORM):
                p.wet = max(0, p.wet - 5)

    def _check_food_rot(self):
        """检查食物腐烂"""
        current_hour = self.game_minute / MINUTES_PER_HOUR
        p = self.player
        for item in list(p.food_timers.keys()):
            new_list = []
            for cnt, exp in p.food_timers[item]:
                if current_hour >= exp:
                    # 腐烂了
                    p.remove_item(item, cnt)
                    self.add_message(f"{ITEMS[item][0]} x{cnt} 腐烂了！", ORANGE)
                else:
                    new_list.append((cnt, exp))
            if new_list:
                p.food_timers[item] = new_list
            else:
                del p.food_timers[item]

    def _change_weather(self):
        season_weights = {
            SPRING: [(W_CLEAR, 30), (W_CLOUDY, 25), (W_RAIN, 25), (W_STORM, 10), (W_WIND, 10)],
            SUMMER: [(W_CLEAR, 40), (W_CLOUDY, 20), (W_RAIN, 15), (W_STORM, 15), (W_WIND, 10)],
            AUTUMN: [(W_CLEAR, 20), (W_CLOUDY, 25), (W_RAIN, 25), (W_STORM, 10), (W_WIND, 20)],
            WINTER: [(W_CLEAR, 15), (W_CLOUDY, 20), (W_WIND, 20), (W_BLIZZARD, 30), (W_RAIN, 15)],
        }
        choices = season_weights[self.season]
        types = [c[0] for c in choices]
        weights = [c[1] for c in choices]
        self.weather = random.choices(types, weights=weights, k=1)[0]
        self.weather_timer = random.randint(120, 360)
        self.add_message(f"天气: {WEATHER_NAMES[self.weather]}", LIGHT_BLUE)

    def _near_building(self, btype):
        for b in self.buildings:
            if b.type == btype:
                dx = abs(b.x - self.player.x)
                dy = abs(b.y - self.player.y)
                if dx <= b.radius and dy <= b.radius:
                    return True
        return False

    def _building_active(self, btype):
        for b in self.buildings:
            if b.type == btype and b.active:
                dx = abs(b.x - self.player.x)
                dy = abs(b.y - self.player.y)
                if dx <= b.radius and dy <= b.radius:
                    return True
        return False

    def _get_building_at(self, x, y):
        for b in self.buildings:
            if b.x == x and b.y == y:
                return b
        return None

    # ─── 玩家移动 ──────────────────────────────
    def _update_player_movement(self, dt):
        keys = pygame.key.get_pressed()
        p = self.player

        if p.move_cooldown > 0:
            p.move_cooldown -= dt
            return

        dx, dy = 0, 0
        if keys[pygame.K_w] or keys[pygame.K_UP]:
            dy = -1
            p.direction = 3
        if keys[pygame.K_s] or keys[pygame.K_DOWN]:
            dy = 1
            p.direction = 0
        if keys[pygame.K_a] or keys[pygame.K_LEFT]:
            dx = -1
            p.direction = 1
        if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
            dx = 1
            p.direction = 2

        if dx == 0 and dy == 0:
            p.is_sprinting = False
            return

        # 冲刺
        p.is_sprinting = keys[pygame.K_LSHIFT] and p.stamina > 0
        speed = p.get_speed()
        if p.is_sprinting:
            speed *= p.sprint_mult
            p.stamina = max(0, p.stamina - dt * 15)
            p.hunger = max(0, p.hunger - dt * 2)

        # 计算移动(格子制，带平滑)
        move_interval = 1.0 / speed
        if p.move_cooldown <= 0:
            nx = p.x + dx
            ny = p.y + dy

            if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                tile = self.tile_map[ny][nx]
                if TILE_WALKABLE.get(tile, False):
                    # 检查建筑阻挡
                    blocked = False
                    for b in self.buildings:
                        if b.x == nx and b.y == ny and b.type == "wall":
                            blocked = True
                    if not blocked:
                        p.x = nx
                        p.y = ny
                        p.steps_walked += 1
                        p.move_cooldown = move_interval
                        self._reveal_area(nx, ny, 4 if not self.is_night else 2)

                        # 进入水中
                        if tile == T_WATER:
                            p.wet = min(100, p.wet + 20)
                            p.body_temp = max(34, p.body_temp - 0.5)

    # ─── 野兽AI ────────────────────────────────
    def _update_beasts(self, dt):
        p = self.player
        for beast in self.beasts:
            if not beast.alive:
                continue

            beast.move_timer += dt
            if beast.move_timer < 1.0 / beast.speed:
                continue
            beast.move_timer = 0

            dist = abs(beast.x - p.x) + abs(beast.y - p.y)

            if beast.aggro and dist <= beast.aggro_range:
                beast.state = "chase"
            elif beast.state == "chase" and dist > beast.flee_range:
                beast.state = "idle"

            if beast.state == "chase":
                # 向玩家移动
                dx = 0 if beast.x == p.x else (1 if p.x > beast.x else -1)
                dy = 0 if beast.y == p.y else (1 if p.y > beast.y else -1)
                # 优先较大差距方向
                if abs(p.x - beast.x) > abs(p.y - beast.y):
                    dy = 0
                else:
                    dx = 0
                nx = beast.x + dx
                ny = beast.y + dy
                if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                    tile = self.tile_map[ny][nx]
                    if TILE_WALKABLE.get(tile, False):
                        beast.x = nx
                        beast.y = ny

                # 攻击检测
                if abs(beast.x - p.x) + abs(beast.y - p.y) <= 1:
                    self._start_combat(beast)

            elif beast.state == "idle":
                # 随机巡逻
                if random.random() < 0.3:
                    dx = random.choice([-1, 0, 1])
                    dy = random.choice([-1, 0, 1])
                    nx = beast.x + dx
                    ny = beast.y + dy
                    if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                        tile = self.tile_map[ny][nx]
                        if TILE_WALKABLE.get(tile, False):
                            beast.x = nx
                            beast.y = ny

        # 清除死亡且已处理的野兽
        self.beasts = [b for b in self.beasts if b.alive]

    # ─── 战斗系统 ──────────────────────────────
    def _start_combat(self, beast):
        self.ui_mode = "combat"
        self.combat_enemy = beast
        self.combat_log = [f"遭遇了 {beast.name}！"]
        if self.is_night:
            self.combat_log.append("夜间野兽更加凶猛！")
        self.combat_player_turn = True

    def _combat_player_attack(self):
        if not self.combat_player_turn or not self.combat_enemy:
            return
        p = self.player
        e = self.combat_enemy

        atk = p.get_attack()
        # 暴击
        crit = random.random() < 0.12
        if crit:
            atk = int(atk * 1.8)

        dmg = e.take_damage(atk)
        msg = f"你攻击{e.name}，造成 {dmg} 伤害"
        if crit:
            msg += " (暴击！)"
        self.combat_log.append(msg)

        if not e.alive:
            self._combat_victory()
            return

        self.combat_player_turn = False
        # 野兽反击
        self._combat_beast_attack()

    def _combat_beast_attack(self):
        p = self.player
        e = self.combat_enemy

        # 随机攻击部位
        weights = [10, 35, 15, 15, 13, 12]
        target = random.choices(BODY_PARTS, weights=weights, k=1)[0]
        bp = p.body[target]

        atk = e.atk
        if self.is_night:
            atk = int(atk * 1.3)

        defense = p.get_defense()
        dmg = max(1, atk - defense)
        bp.take_damage(dmg)

        msg = f"{e.name}攻击你的{BP_NAMES[target]}，造成 {dmg} 伤害"
        self.combat_log.append(msg)

        # 特殊效果
        if e.poison and random.random() < 0.3:
            p.poisoned = 180  # 3小时
            self.combat_log.append("你中毒了！")

        if dmg > 20 and random.random() < 0.25:
            bp.bleeding = True
            self.combat_log.append(f"{BP_NAMES[target]}开始流血！")

        if dmg > 30 and random.random() < 0.15:
            bp.fractured = True
            self.combat_log.append(f"{BP_NAMES[target]}骨折了！")

        if not p.is_alive:
            self.combat_log.append("你倒下了...")
            self.ui_mode = "dead"
            return

        self.combat_player_turn = True

    def _combat_flee(self):
        p = self.player
        # 逃跑概率受腿部状态影响
        flee_chance = 50
        if p.body[BP_L_LEG].crippled:
            flee_chance -= 25
        if p.body[BP_R_LEG].crippled:
            flee_chance -= 25
        if p.body[BP_L_LEG].fractured:
            flee_chance -= 15
        if p.body[BP_R_LEG].fractured:
            flee_chance -= 15
        if self.is_night:
            flee_chance -= 20

        if random.random() * 100 < flee_chance:
            self.combat_log.append("你成功逃脱了！")
            self.ui_mode = "game"
            # 推开玩家
            dx = 1 if self.combat_enemy.x > p.x else -1
            dy = 1 if self.combat_enemy.y > p.y else -1
            p.x = max(0, min(MAP_W - 1, p.x - dx * 3))
            p.y = max(0, min(MAP_H - 1, p.y - dy * 3))
        else:
            self.combat_log.append("逃跑失败！")
            self._combat_beast_attack()

    def _combat_victory(self):
        e = self.combat_enemy
        p = self.player
        p.beasts_killed += 1
        leveled = p.add_xp(e.xp)

        self.combat_log.append(f"击杀了 {e.name}！获得 {e.xp} 经验")
        if leveled:
            self.combat_log.append(f"升级！等级 {p.level}")

        # 掉落
        for item, count in e.drops:
            if random.random() < 0.7:
                actual = random.randint(1, count)
                if p.add_item(item, actual):
                    if item in FOOD_DATA:
                        p.add_food_timered(item, actual, self.game_minute / MINUTES_PER_HOUR)
                    self.combat_log.append(f"获得 {ITEMS[item][0]} x{actual}")
                else:
                    self.combat_log.append(f"背包已满，无法拾取 {ITEMS[item][0]}")

        self.ui_mode = "game"
        self.combat_enemy = None

    # ─── 天气粒子 ──────────────────────────────
    def _update_weather_particles(self, dt):
        # 生成新粒子
        if self.weather == W_RAIN:
            for _ in range(3):
                x = random.randint(0, WIDTH)
                self.weather_particles.append(
                    Particle(x, -10, -1, 400, 2.0, (150, 180, 220), 1))
        elif self.weather == W_STORM:
            for _ in range(6):
                x = random.randint(0, WIDTH)
                self.weather_particles.append(
                    Particle(x, -10, -3, 600, 1.5, (100, 130, 180), 2))
        elif self.weather == W_BLIZZARD:
            for _ in range(2):
                x = random.randint(0, WIDTH)
                self.weather_particles.append(
                    Particle(x, -10, random.uniform(-2, 2), random.uniform(50, 100),
                             4.0, (230, 235, 245), random.randint(2, 4)))
        elif self.weather == W_WIND:
            if random.random() < 0.3:
                y = random.randint(0, HEIGHT)
                self.weather_particles.append(
                    Particle(-10, y, 200, random.uniform(-20, 20), 3.0, (180, 180, 180, 100), 1))

        self.weather_particles = [p for p in self.weather_particles if p.update(dt)]
        if len(self.weather_particles) > 500:
            self.weather_particles = self.weather_particles[-500:]

    # ─── 互动 ──────────────────────────────────
    def _try_interact(self):
        p = self.player
        px, py = p.x, p.y

        # 检查当前格和周围格
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                nx, ny = px + dx, py + dy
                if not (0 <= nx < MAP_W and 0 <= ny < MAP_H):
                    continue

                tile = self.tile_map[ny][nx]
                building = self._get_building_at(nx, ny)

                # 营火互动
                if building and building.type == "campfire":
                    if building.fuel > 0:
                        # 添加燃料
                        if p.has_item("wood"):
                            p.remove_item("wood", 1)
                            building.fuel += 30
                            self.add_message("添加了木材作为燃料", ORANGE)
                            return
                        else:
                            self.add_message("没有木材添加燃料", GRAY)
                            return
                    else:
                        # 重新点燃
                        if p.has_item("wood", 2):
                            p.remove_item("wood", 2)
                            building.fuel = 60
                            building.active = True
                            self.add_message("营火重新点燃了！", ORANGE)
                            return
                        else:
                            self.add_message("需要2木材来重新点燃", GRAY)
                            return

                # 庇护所休息
                if building and building.type == "shelter":
                    self.add_message("在庇护所中休息...体力和精神恢复中", GREEN)
                    p.stamina = min(100, p.stamina + 20)
                    p.energy = min(100, p.energy + 15)
                    p.mental = min(100, p.mental + 5)
                    # 推进时间4小时
                    for _ in range(240):
                        self._advance_game_minute()
                    return

                # 储物箱
                if building and building.type == "storage":
                    self.ui_mode = "inventory"
                    self.ui_tab = 1  # 储物箱标签
                    return

                # 陷阱收取
                for trap in self.traps:
                    if trap.x == nx and trap.y == ny and trap.caught:
                        item = trap.caught
                        if p.add_item(item, 1):
                            if item in FOOD_DATA:
                                p.add_food_timered(item, 1, self.game_minute / MINUTES_PER_HOUR)
                            self.add_message(f"收取了 {ITEMS[item][0]}", GREEN)
                            trap.caught = None
                        else:
                            self.add_message("背包已满", RED)
                        return

                # 地形互动
                if dx == 0 and dy == 0:
                    if tile == T_WATER:
                        if p.has_item("water_filter"):
                            if p.add_item("clean_water", 1):
                                p.add_food_timered("clean_water", 1, self.game_minute / MINUTES_PER_HOUR)
                                self.add_message("使用净水器获得了净水", BLUE)
                            else:
                                self.add_message("背包已满", RED)
                        else:
                            if p.add_item("dirty_water", 1):
                                p.add_food_timered("dirty_water", 1, self.game_minute / MINUTES_PER_HOUR)
                                self.add_message("获得了脏水（需要净水器或煮沸）", ORANGE)
                            else:
                                self.add_message("背包已满", RED)
                        return

                    if tile == T_CAVE:
                        self.add_message("进入洞穴避寒...", CYAN)
                        p.body_temp = min(36.5, p.body_temp + 1.0)
                        p.stamina = min(100, p.stamina + 10)
                        for _ in range(120):
                            self._advance_game_minute()
                        return

        # 采集 (面向方向)
        dirs = [(0, 1), (-1, 0), (1, 0), (0, -1)]
        fdx, fdy = dirs[p.direction]
        fx, fy = px + fdx, py + fdy
        if 0 <= fx < MAP_W and 0 <= fy < MAP_H:
            ftile = self.tile_map[fy][fx]

            if ftile == T_FOREST:
                # 砍树
                wood_amt = 3 if p.weapon == "stone_axe" else 2
                if p.add_item("wood", wood_amt):
                    self.add_message(f"获得了木材 x{wood_amt}", GREEN)
                    p.stamina = max(0, p.stamina - 8)
                    # 概率获得纤维
                    if random.random() < 0.3:
                        p.add_item("fiber", 1)
                    # 概率获得草药
                    if random.random() < 0.15:
                        p.add_item("herb", 1)
                    # 砍掉一些树变草地
                    if random.random() < 0.2:
                        self.tile_map[fy][fx] = T_GRASS
                else:
                    self.add_message("背包已满", RED)
                return

            if ftile == T_ROCK:
                stone_amt = 2
                if p.add_item("stone", stone_amt):
                    self.add_message(f"获得了石头 x{stone_amt}", GREEN)
                    p.stamina = max(0, p.stamina - 10)
                    if random.random() < 0.15:
                        p.add_item("iron_ore", 1)
                        self.add_message("发现了铁矿！", YELLOW)
                    if random.random() < 0.1:
                        p.add_item("clay", 1)
                else:
                    self.add_message("背包已满", RED)
                return

            if ftile == T_TALL_GRASS:
                if p.add_item("fiber", 2):
                    self.add_message("获得了纤维 x2", GREEN)
                    p.stamina = max(0, p.stamina - 3)
                    if random.random() < 0.2:
                        p.add_item("herb", 1)
                        self.add_message("发现了草药！", GREEN)
                    if random.random() < 0.15:
                        item = random.choice(["berry", "mushroom"])
                        p.add_item(item, 1)
                        p.add_food_timered(item, 1, self.game_minute / MINUTES_PER_HOUR)
                        self.add_message(f"发现了 {ITEMS[item][0]}！", GREEN)
                else:
                    self.add_message("背包已满", RED)
                return

        self.add_message("这里没有可以互动的东西", GRAY)

    # ─── 进食 ──────────────────────────────────
    def _eat_item(self, item):
        if item not in FOOD_DATA:
            return
        p = self.player
        if not p.has_item(item):
            self.add_message(f"没有 {ITEMS[item][0]}", RED)
            return

        data = FOOD_DATA[item]
        hunger, thirst, hp, mental, can_raw, rot = data

        p.hunger = min(100, p.hunger + hunger)
        p.thirst = min(100, p.thirst + thirst)
        p.mental = min(100, max(0, p.mental + mental))

        # HP恢复分配到各部位
        if hp > 0:
            for bp in p.body.values():
                if not bp.crippled:
                    bp.heal(max(1, hp // len(BODY_PARTS)))
        elif hp < 0:
            p.body[BP_TORSO].take_damage(abs(hp))

        p.remove_item(item, 1)

        # 脏水风险
        if item == "dirty_water":
            if random.random() < 0.3:
                p.sick = 360
                p.disease_name = "腹泻"
                self.add_message("脏水让你生病了！", RED)

        # 生肉风险
        if item in ("raw_meat", "raw_fish", "mushroom"):
            if random.random() < 0.1:
                p.poisoned = 120
                self.add_message("食物中毒了！", RED)

        self.add_message(f"食用了 {ITEMS[item][0]}", GREEN)

    # ─── 制作 ──────────────────────────────────
    def _craft_item(self, idx):
        if idx < 0 or idx >= len(RECIPES):
            return
        p = self.player
        item_name, recipe, desc = RECIPES[idx]

        if not p.has_items(recipe):
            self.add_message("材料不足！", RED)
            return

        p.remove_items(recipe)

        # 特殊处理
        if item_name == "arrow":
            p.add_item("arrow", 3)
        elif item_name == "campfire_kit":
            # 放置营火
            b = Building("campfire", p.x, p.y)
            b.fuel = 60
            self.buildings.append(b)
            self.add_message("放置了营火！", ORANGE)
            return
        else:
            p.add_item(item_name, 1)

        self.add_message(f"制作了 {ITEMS[item_name][0]}", GREEN)

        # 自动装备
        if item_name in WEAPON_DATA:
            p.weapon = item_name
            self.add_message(f"装备了 {ITEMS[item_name][0]}", CYAN)
        if item_name in ARMOR_DATA:
            p.armor = item_name
            self.add_message(f"穿上了 {ITEMS[item_name][0]}", CYAN)

    # ─── 建造 ──────────────────────────────────
    def _build_item(self, idx):
        btypes = list(BUILDINGS.keys())
        if idx < 0 or idx >= len(btypes):
            return
        p = self.player
        btype = btypes[idx]
        bname, recipe, color, radius = BUILDINGS[btype]

        if not p.has_items(recipe):
            self.add_message("材料不足！", RED)
            return

        # 检查位置是否已有建筑
        if self._get_building_at(p.x, p.y):
            self.add_message("这里已经有建筑了", RED)
            return

        tile = self.tile_map[p.y][p.x]
        if not TILE_WALKABLE.get(tile, False) and btype != "campfire":
            self.add_message("无法在此建造", RED)
            return

        p.remove_items(recipe)
        b = Building(btype, p.x, p.y)
        if btype == "campfire":
            b.fuel = 120
        self.buildings.append(b)
        self.add_message(f"建造了 {bname}！", GREEN)

    # ─── 治疗 ──────────────────────────────────
    def _heal_body_part(self, bp_name, item):
        p = self.player
        bp = p.body[bp_name]

        if item == "bandage" and bp.bleeding:
            if p.has_item("bandage"):
                p.remove_item("bandage")
                bp.bleeding = False
                bp.bleed_timer = 0
                bp.heal(10)
                self.add_message(f"{BP_NAMES[bp_name]} 止血了", GREEN)
        elif item == "splint" and bp.fractured:
            if p.has_item("splint"):
                p.remove_item("splint")
                bp.fractured = False
                bp.heal(15)
                self.add_message(f"{BP_NAMES[bp_name]} 骨折固定了", GREEN)
        elif item == "poultice" and bp.infected:
            if p.has_item("poultice"):
                p.remove_item("poultice")
                bp.infected = False
                bp.heal(20)
                self.add_message(f"{BP_NAMES[bp_name]} 感染治愈了", GREEN)
        elif item == "antibiotic":
            if p.has_item("antibiotic"):
                p.remove_item("antibiotic")
                for b in p.body.values():
                    b.infected = False
                    b.heal(10)
                p.sick = 0
                p.disease_name = ""
                self.add_message("使用了抗生素，全面抗感染", GREEN)

    # ─── 渲染 ──────────────────────────────────
    def render(self):
        self.screen.fill(BLACK)

        if self.ui_mode == "dead":
            self._render_death()
            return

        if self.ui_mode == "combat":
            self._render_combat()
            return

        # 世界渲染
        self._render_world()
        self._render_hud()
        self._render_messages()

        # UI覆盖层
        if self.ui_mode == "inventory":
            self._render_inventory()
        elif self.ui_mode == "craft":
            self._render_craft()
        elif self.ui_mode == "build":
            self._render_build()
        elif self.ui_mode == "status":
            self._render_status()
        elif self.ui_mode == "help":
            self._render_help()
        elif self.ui_mode == "map":
            self._render_minimap()

    def _render_world(self):
        """渲染2D世界"""
        p = self.player
        daylight = self.get_daylight()

        # 计算可见范围
        start_x = max(0, int(self.cam_x / TILE_SIZE) - 1)
        start_y = max(0, int(self.cam_y / TILE_SIZE) - 1)
        end_x = min(MAP_W, start_x + WIDTH // TILE_SIZE + 3)
        end_y = min(MAP_H, start_y + HEIGHT // TILE_SIZE + 3)

        for ty in range(start_y, end_y):
            for tx in range(start_x, end_x):
                sx = int(tx * TILE_SIZE - self.cam_x)
                sy = int(ty * TILE_SIZE - self.cam_y)

                if not self.explored[ty][tx]:
                    pygame.draw.rect(self.screen, (20, 20, 30), (sx, sy, TILE_SIZE, TILE_SIZE))
                    continue

                tile = self.tile_map[ty][tx]
                base_color = TILE_COLORS.get(tile, (100, 100, 100))

                # 加入随机变化
                variation = ((tx * 7 + ty * 13) % 20) - 10
                color = tuple(max(0, min(255, c + variation)) for c in base_color)

                pygame.draw.rect(self.screen, color, (sx, sy, TILE_SIZE, TILE_SIZE))

                # 地形装饰
                if tile == T_FOREST:
                    # 树干
                    pygame.draw.rect(self.screen, BROWN, (sx + 12, sy + 16, 8, 16))
                    # 树冠
                    leaf_color = DARK_GREEN
                    if self.season == AUTUMN:
                        leaf_color = (180, 120, 40)
                    elif self.season == WINTER:
                        leaf_color = (100, 110, 100)
                    pygame.draw.circle(self.screen, leaf_color, (sx + 16, sy + 10), 12)
                elif tile == T_TALL_GRASS:
                    # 草叶
                    for i in range(3):
                        gx = sx + 6 + i * 10
                        pygame.draw.line(self.screen, (60, 140, 40), (gx, sy + 28), (gx + 2, sy + 8), 2)
                elif tile == T_ROCK:
                    pygame.draw.polygon(self.screen, (140, 140, 145),
                                        [(sx + 5, sy + 28), (sx + 16, sy + 4), (sx + 27, sy + 28)])
                elif tile == T_CAVE:
                    pygame.draw.circle(self.screen, (30, 30, 40), (sx + 16, sy + 16), 12)
                    pygame.draw.circle(self.screen, (15, 15, 20), (sx + 16, sy + 16), 8)
                elif tile == T_WATER:
                    # 水波纹
                    wave = int(math.sin(time.time() * 2 + tx * 0.5 + ty * 0.3) * 3)
                    pygame.draw.line(self.screen, (80, 140, 220),
                                     (sx + 4, sy + 16 + wave), (sx + 28, sy + 16 + wave), 1)

                # 季节覆盖(雪)
                if self.season == WINTER and tile in (T_GRASS, T_TALL_GRASS, T_SAND):
                    snow_alpha = 100
                    snow_surf = pygame.Surface((TILE_SIZE, TILE_SIZE), pygame.SRCALPHA)
                    snow_surf.fill((230, 235, 245, snow_alpha))
                    self.screen.blit(snow_surf, (sx, sy))

        # 渲染建筑
        for b in self.buildings:
            sx = int(b.x * TILE_SIZE - self.cam_x)
            sy = int(b.y * TILE_SIZE - self.cam_y)
            if -TILE_SIZE < sx < WIDTH and -TILE_SIZE < sy < HEIGHT:
                if b.type == "campfire":
                    # 营火
                    pygame.draw.circle(self.screen, DARK_BROWN, (sx + 16, sy + 20), 8)
                    if b.fuel > 0 and b.active:
                        # 火焰动画
                        flicker = math.sin(time.time() * 8) * 2
                        pygame.draw.circle(self.screen, (255, 140, 30),
                                           (sx + 16, sy + 14 + int(flicker)), 6)
                        pygame.draw.circle(self.screen, (255, 220, 80),
                                           (sx + 16, sy + 12 + int(flicker)), 3)
                        # 火光
                        glow = pygame.Surface((TILE_SIZE * 4, TILE_SIZE * 4), pygame.SRCALPHA)
                        pygame.draw.circle(glow, (255, 180, 60, 20),
                                           (TILE_SIZE * 2, TILE_SIZE * 2), TILE_SIZE * 2)
                        self.screen.blit(glow, (sx - TILE_SIZE * 2 + 16, sy - TILE_SIZE * 2 + 16),
                                         special_flags=pygame.BLEND_RGBA_ADD)
                elif b.type == "shelter":
                    # 庇护所 - 小木屋
                    pygame.draw.rect(self.screen, BROWN, (sx + 2, sy + 8, 28, 22))
                    pygame.draw.polygon(self.screen, DARK_BROWN,
                                        [(sx, sy + 10), (sx + 16, sy), (sx + 32, sy + 10)])
                    pygame.draw.rect(self.screen, DARK_BROWN, (sx + 12, sy + 18, 8, 12))
                elif b.type == "wall":
                    pygame.draw.rect(self.screen, (120, 120, 120), (sx + 2, sy + 2, 28, 28))
                    pygame.draw.rect(self.screen, (100, 100, 100), (sx + 4, sy + 4, 24, 24), 2)
                elif b.type == "drying_rack":
                    pygame.draw.line(self.screen, BROWN, (sx + 4, sy + 8), (sx + 4, sy + 28), 3)
                    pygame.draw.line(self.screen, BROWN, (sx + 28, sy + 8), (sx + 28, sy + 28), 3)
                    pygame.draw.line(self.screen, BROWN, (sx + 4, sy + 12), (sx + 28, sy + 12), 2)
                elif b.type == "storage":
                    pygame.draw.rect(self.screen, (130, 90, 50), (sx + 4, sy + 10, 24, 18))
                    pygame.draw.rect(self.screen, (100, 70, 40), (sx + 4, sy + 10, 24, 4))

        # 渲染陷阱
        for trap in self.traps:
            sx = int(trap.x * TILE_SIZE - self.cam_x)
            sy = int(trap.y * TILE_SIZE - self.cam_y)
            if -TILE_SIZE < sx < WIDTH and -TILE_SIZE < sy < HEIGHT:
                color = GREEN if trap.caught else (160, 140, 100)
                pygame.draw.rect(self.screen, color, (sx + 8, sy + 8, 16, 16), 2)
                if trap.caught:
                    pygame.draw.circle(self.screen, YELLOW, (sx + 16, sy + 16), 4)

        # 渲染野兽
        for beast in self.beasts:
            if not beast.alive:
                continue
            sx = int(beast.x * TILE_SIZE - self.cam_x)
            sy = int(beast.y * TILE_SIZE - self.cam_y)
            if -TILE_SIZE < sx < WIDTH and -TILE_SIZE < sy < HEIGHT:
                # 检查是否在已探索区域
                if 0 <= beast.x < MAP_W and 0 <= beast.y < MAP_H:
                    if self.explored[beast.y][beast.x]:
                        # 身体
                        pygame.draw.circle(self.screen, beast.color,
                                           (sx + 16, sy + 16), beast.size)
                        # 眼睛
                        pygame.draw.circle(self.screen, RED if beast.aggro else WHITE,
                                           (sx + 12, sy + 12), 2)
                        pygame.draw.circle(self.screen, RED if beast.aggro else WHITE,
                                           (sx + 20, sy + 12), 2)
                        # 血条
                        if beast.hp < beast.max_hp:
                            bar_w = 24
                            hp_ratio = beast.hp / beast.max_hp
                            pygame.draw.rect(self.screen, DARK_RED,
                                             (sx + 4, sy - 4, bar_w, 3))
                            pygame.draw.rect(self.screen, GREEN,
                                             (sx + 4, sy - 4, int(bar_w * hp_ratio), 3))
                        # 名字
                        name_surf = self.font_sm.render(beast.name, True, WHITE)
                        self.screen.blit(name_surf, (sx + 16 - name_surf.get_width() // 2, sy - 12))

        # 渲染玩家
        psx = int(p.x * TILE_SIZE - self.cam_x)
        psy = int(p.y * TILE_SIZE - self.cam_y)

        # 身体
        body_color = SKIN
        if p.armor:
            body_color = ARMOR_DATA.get(p.armor, (SKIN, 0))[0] if isinstance(
                ARMOR_DATA.get(p.armor, (SKIN, 0))[0], tuple) else SKIN

        # 头
        pygame.draw.circle(self.screen, SKIN, (psx + 16, psy + 8), 7)
        # 身体
        armor_color = (140, 100, 60) if p.armor == "leather_armor" else \
                      (120, 100, 70) if p.armor == "fur_coat" else (80, 120, 180)
        pygame.draw.rect(self.screen, armor_color, (psx + 10, psy + 14, 12, 12))
        # 腿
        pygame.draw.rect(self.screen, DARK_BROWN, (psx + 10, psy + 26, 5, 6))
        pygame.draw.rect(self.screen, DARK_BROWN, (psx + 17, psy + 26, 5, 6))

        # 武器
        if p.weapon:
            wcolor = WEAPON_DATA.get(p.weapon, (GRAY,))[0] if p.weapon else GRAY
            if p.direction == 0:
                pygame.draw.line(self.screen, wcolor, (psx + 24, psy + 16), (psx + 28, psy + 26), 2)
            elif p.direction == 1:
                pygame.draw.line(self.screen, wcolor, (psx + 8, psy + 16), (psx + 2, psy + 12), 2)
            elif p.direction == 2:
                pygame.draw.line(self.screen, wcolor, (psx + 24, psy + 16), (psx + 30, psy + 12), 2)
            else:
                pygame.draw.line(self.screen, wcolor, (psx + 16, psy + 6), (psx + 16, psy + 0), 2)

        # 手持火把的光
        if p.has_item("torch"):
            glow = pygame.Surface((TILE_SIZE * 6, TILE_SIZE * 6), pygame.SRCALPHA)
            pygame.draw.circle(glow, (255, 200, 80, 15),
                               (TILE_SIZE * 3, TILE_SIZE * 3), TILE_SIZE * 3)
            self.screen.blit(glow, (psx - TILE_SIZE * 3 + 16, psy - TILE_SIZE * 3 + 16),
                             special_flags=pygame.BLEND_RGBA_ADD)

        # 互动提示
        self._render_interact_hint(psx, psy)

        # 昼夜覆盖
        if daylight < 1.0:
            darkness = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            alpha = int((1.0 - daylight) * 200)
            darkness.fill((10, 10, 40, alpha))
            self.screen.blit(darkness, (0, 0))

            # 营火/火把照亮区域
            if self._near_building("campfire") and self._building_active("campfire"):
                light = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
                pygame.draw.circle(light, (0, 0, 0, min(120, alpha)),
                                   (psx + 16, psy + 16), 120)
                self.screen.blit(light, (0, 0), special_flags=pygame.BLEND_RGBA_SUB)
            if p.has_item("torch"):
                light = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
                pygame.draw.circle(light, (0, 0, 0, min(100, alpha)),
                                   (psx + 16, psy + 16), 100)
                self.screen.blit(light, (0, 0), special_flags=pygame.BLEND_RGBA_SUB)

        # 天气粒子渲染
        for part in self.weather_particles:
            sx = int(part.x)
            sy = int(part.y)
            alpha = part.alpha
            color = part.color
            if len(color) == 4:
                surf = pygame.Surface((part.size * 2, 1), pygame.SRCALPHA)
                surf.fill((*color[:3], alpha))
                self.screen.blit(surf, (sx, sy))
            else:
                pygame.draw.circle(self.screen, color, (sx, sy), part.size)
                if self.weather in (W_RAIN, W_STORM):
                    pygame.draw.line(self.screen, color, (sx, sy), (sx - 2, sy + 6), 1)

        # 幻觉效果
        if p.mental < 20:
            intensity = (20 - p.mental) / 20
            if random.random() < intensity * 0.3:
                overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
                overlay.fill((100, 0, 150, int(30 * intensity)))
                self.screen.blit(overlay, (0, 0))

    def _render_interact_hint(self, psx, psy):
        """渲染互动提示"""
        p = self.player
        hints = []

        # 检查周围
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                nx, ny = p.x + dx, p.y + dy
                if not (0 <= nx < MAP_W and 0 <= ny < MAP_H):
                    continue
                tile = self.tile_map[ny][nx]
                building = self._get_building_at(nx, ny)

                if building:
                    hints.append(f"[E] {building.name}")
                elif tile == T_WATER and dx == 0 and dy == 0:
                    hints.append("[E] 取水")
                elif tile == T_CAVE and dx == 0 and dy == 0:
                    hints.append("[E] 进洞休息")

        # 检查面向方向
        dirs = [(0, 1), (-1, 0), (1, 0), (0, -1)]
        fdx, fdy = dirs[p.direction]
        fx, fy = p.x + fdx, p.y + fdy
        if 0 <= fx < MAP_W and 0 <= fy < MAP_H:
            ftile = self.tile_map[fy][fx]
            if ftile == T_FOREST:
                hints.append("[E] 砍树")
            elif ftile == T_ROCK:
                hints.append("[E] 采矿")
            elif ftile == T_TALL_GRASS:
                hints.append("[E] 采集")

        if hints:
            hint_text = " | ".join(hints[:3])
            hint_surff = self.font_md.render(hint_text, True, YELLOW)
            hx = psx + 16 - hint_surff.get_width() // 2
            hy = psy - 20
            # 背景
            bg = pygame.Surface((hint_surff.get_width() + 10, hint_surff.get_height() + 6), pygame.SRCALPHA)
            bg.fill((0, 0, 0, 150))
            self.screen.blit(bg, (hx - 5, hy - 3))
            self.screen.blit(hint_surff, (hx, hy))

    def _render_hud(self):
        """渲染底部HUD"""
        p = self.player
        hud_y = HEIGHT - 90
        pygame.draw.rect(self.screen, (20, 20, 30, 220), (0, hud_y, WIDTH, 90))
        pygame.draw.line(self.screen, (60, 60, 80), (0, hud_y), (WIDTH, hud_y), 2)

        # 状态条
        bars = [
            ("❤", p.body[BP_TORSO].hp, p.body[BP_TORSO].max_hp, RED),
            ("🍖", p.hunger, 100, ORANGE),
            ("💧", p.thirst, 100, BLUE),
            ("⚡", p.stamina, 100, YELLOW),
            ("🧠", p.mental, 100, PURPLE),
        ]

        bar_x = 10
        for icon, val, max_val, color in bars:
            # 图标
            icon_surf = self.font_md.render(icon, True, WHITE)
            self.screen.blit(icon_surf, (bar_x, hud_y + 5))
            # 条
            bx = bar_x + 25
            bw = 80
            pygame.draw.rect(self.screen, DARK_GRAY, (bx, hud_y + 8, bw, 14))
            fill = int(bw * max(0, val) / max(1, max_val))
            pygame.draw.rect(self.screen, color, (bx, hud_y + 8, fill, 14))
            # 数值
            val_surf = self.font_sm.render(f"{int(val)}/{int(max_val)}", True, WHITE)
            self.screen.blit(val_surf, (bx + 2, hud_y + 9))
            bar_x += 120

        # 体温
        temp_color = WHITE
        if p.body_temp < 35:
            temp_color = CYAN
        elif p.body_temp > 38.5:
            temp_color = RED
        temp_surf = self.font_md.render(f"🌡 {p.body_temp:.1f}°C", True, temp_color)
        self.screen.blit(temp_surf, (bar_x + 10, hud_y + 5))

        # 第二行 - 时间和信息
        time_str = f"第{self.game_day}天 {self._get_time_string()}"
        time_surf = self.font_md.render(time_str, True, WHITE)
        self.screen.blit(time_surf, (10, hud_y + 30))

        season_str = f"{SEASON_NAMES[self.season]}季"
        season_colors = [GREEN, YELLOW, ORANGE, CYAN]
        season_surf = self.font_md.render(season_str, True, season_colors[self.season])
        self.screen.blit(season_surf, (160, hud_y + 30))

        weather_surf = self.font_md.render(WEATHER_NAMES[self.weather], True, LIGHT_BLUE)
        self.screen.blit(weather_surf, (230, hud_y + 30))

        # 装备
        weapon_name = ITEMS[p.weapon][0] if p.weapon else "拳头"
        armor_name = ITEMS[p.armor][0] if p.armor else "无"
        equip_surf = self.font_md.render(f"⚔{weapon_name} 🛡{armor_name}", True, WHITE)
        self.screen.blit(equip_surf, (380, hud_y + 30))

        # 等级
        lv_surf = self.font_md.render(f"Lv.{p.level} ({p.xp}/{p.xp_next})", True, YELLOW)
        self.screen.blit(lv_surf, (600, hud_y + 30))

        # 环境信息
        env_temp = self.get_ambient_temp()
        env_surf = self.font_md.render(f"环境:{env_temp}°C", True,
                                        CYAN if env_temp < 10 else ORANGE if env_temp > 30 else WHITE)
        self.screen.blit(env_surf, (780, hud_y + 30))

        # 状态效果
        effects = []
        if p.poisoned > 0:
            effects.append("☠毒")
        if p.sick > 0:
            effects.append("🤒病")
        if p.cold:
            effects.append("🤧感冒")
        if p.wet > 30:
            effects.append("💦湿")
        for bp_name in BODY_PARTS:
            bp = p.body[bp_name]
            if bp.bleeding:
                effects.append(f"🩸{BP_NAMES[bp_name][:1]}")
            if bp.fractured:
                effects.append(f"🦴{BP_NAMES[bp_name][:1]}")
            if bp.infected:
                effects.append(f"🦠{BP_NAMES[bp_name][:1]}")
            if bp.frostbite:
                effects.append(f"🥶{BP_NAMES[bp_name][:1]}")
            if bp.crippled:
                effects.append(f"💀{BP_NAMES[bp_name][:1]}")

        if effects:
            eff_surf = self.font_md.render(" ".join(effects[:10]), True, RED)
            self.screen.blit(eff_surf, (10, hud_y + 55))

        # 操作提示
        controls = "Tab:菜单 M:地图 I:背包 C:制作 B:建造"
        ctrl_surf = self.font_sm.render(controls, True, GRAY)
        self.screen.blit(ctrl_surf, (WIDTH - ctrl_surf.get_width() - 10, hud_y + 60))

        # 右上角人体模型
        self._render_body_model(WIDTH - 120, 10)

    def _render_body_model(self, bx, by):
        """渲染人体模型"""
        p = self.player
        bg = pygame.Surface((110, 130), pygame.SRCALPHA)
        bg.fill((0, 0, 0, 150))
        self.screen.blit(bg, (bx, by))

        # 头
        head = p.body[BP_HEAD]
        pygame.draw.circle(self.screen, head.get_color(), (bx + 55, by + 20), 12)
        pygame.draw.circle(self.screen, WHITE, (bx + 55, by + 20), 12, 1)

        # 躯干
        torso = p.body[BP_TORSO]
        pygame.draw.rect(self.screen, torso.get_color(), (bx + 40, by + 35, 30, 35))
        pygame.draw.rect(self.screen, WHITE, (bx + 40, by + 35, 30, 35), 1)

        # 左臂
        larm = p.body[BP_L_ARM]
        pygame.draw.rect(self.screen, larm.get_color(), (bx + 22, by + 38, 14, 28))
        pygame.draw.rect(self.screen, WHITE, (bx + 22, by + 38, 14, 28), 1)

        # 右臂
        rarm = p.body[BP_R_ARM]
        pygame.draw.rect(self.screen, rarm.get_color(), (bx + 74, by + 38, 14, 28))
        pygame.draw.rect(self.screen, WHITE, (bx + 74, by + 38, 14, 28), 1)

        # 左腿
        lleg = p.body[BP_L_LEG]
        pygame.draw.rect(self.screen, lleg.get_color(), (bx + 38, by + 74, 14, 30))
        pygame.draw.rect(self.screen, WHITE, (bx + 38, by + 74, 14, 30), 1)

        # 右腿
        rleg = p.body[BP_R_LEG]
        pygame.draw.rect(self.screen, rleg.get_color(), (bx + 58, by + 74, 14, 30))
        pygame.draw.rect(self.screen, WHITE, (bx + 58, by + 74, 14, 30), 1)

        # HP数值
        parts_pos = [
            (BP_HEAD, bx + 55, by + 110),
            (BP_TORSO, bx + 55, by + 118),
        ]
        total_hp = p.total_hp
        total_max = p.total_max_hp
        hp_text = self.font_sm.render(f"总HP: {total_hp}/{total_max}", True, WHITE)
        self.screen.blit(hp_text, (bx + 5, by + 112))

    def _render_messages(self):
        """渲染消息"""
        y = HEIGHT - 100
        for msg in reversed(self.messages[-5:]):
            alpha = max(0, min(255, int(255 * (1 - msg.timer / msg.duration))))
            surf = self.font_md.render(msg.text, True, msg.color)
            bg = pygame.Surface((surf.get_width() + 10, surf.get_height() + 4), pygame.SRCALPHA)
            bg.fill((0, 0, 0, min(150, alpha)))
            self.screen.blit(bg, (4, y - surf.get_height()))
            surf.set_alpha(alpha)
            self.screen.blit(surf, (8, y - surf.get_height() + 2))
            y -= surf.get_height() + 4

    def _render_combat(self):
        """渲染战斗界面"""
        # 背景
        self.screen.fill((30, 15, 15))

        p = self.player
        e = self.combat_enemy
        if not e:
            return

        # 标题
        title = self.font_xl.render(f"⚔ 战斗: {e.name}", True, RED)
        self.screen.blit(title, (WIDTH // 2 - title.get_width() // 2, 20))

        # 敌人信息
        enemy_surf = self.font_lg.render(f"{e.name}  HP: {e.hp}/{e.max_hp}  ATK:{e.atk} DEF:{e.defense}",
                                         True, ORANGE)
        self.screen.blit(enemy_surf, (WIDTH // 2 - enemy_surf.get_width() // 2, 70))

        # 敌人血条
        bar_w = 300
        bar_x = WIDTH // 2 - bar_w // 2
        pygame.draw.rect(self.screen, DARK_RED, (bar_x, 100, bar_w, 20))
        pygame.draw.rect(self.screen, RED, (bar_x, 100, int(bar_w * e.hp / e.max_hp), 20))

        # 敌人图像
        pygame.draw.circle(self.screen, e.color, (WIDTH // 2, 180), e.size * 3)

        # 战斗日志
        log_y = 260
        for i, msg in enumerate(self.combat_log[-8:]):
            color = WHITE
            if "暴击" in msg or "击杀" in msg:
                color = YELLOW
            elif "流血" in msg or "骨折" in msg:
                color = RED
            elif "中毒" in msg:
                color = PURPLE
            surf = self.font_md.render(msg, True, color)
            self.screen.blit(surf, (50, log_y + i * 25))

        # 玩家状态
        status_y = 500
        self.screen.blit(self.font_md.render(f"你的状态:", True, WHITE), (50, status_y))
        for i, bp_name in enumerate(BODY_PARTS):
            bp = p.body[bp_name]
            color = bp.get_color()
            text = f"{BP_NAMES[bp_name]}: {bp.hp}/{bp.max_hp} {bp.get_status()}"
            surf = self.font_sm.render(text, True, color)
            self.screen.blit(surf, (70, status_y + 25 + i * 18))

        # 操作按钮
        if self.combat_player_turn:
            btn_y = 660
            btns = [("[A] 攻击", RED), ("[F] 逃跑", BLUE), ("[H] 使用草药", GREEN)]
            for i, (text, color) in enumerate(btns):
                bx = WIDTH // 3 * i + 50
                btn_rect = pygame.Rect(bx, btn_y, 200, 40)
                pygame.draw.rect(self.screen, color, btn_rect, 2)
                surf = self.font_md.render(text, True, color)
                self.screen.blit(surf, (bx + 20, btn_y + 8))

        # 玩家战斗信息
        atk_surf = self.font_md.render(f"ATK:{p.get_attack()} DEF:{p.get_defense()}", True, YELLOW)
        self.screen.blit(atk_surf, (WIDTH - 200, 670))

    def _render_inventory(self):
        """渲染背包界面"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 180))
        self.screen.blit(overlay, (0, 0))

        panel_w, panel_h = 700, 550
        px = (WIDTH - panel_w) // 2
        py = (HEIGHT - panel_h) // 2

        pygame.draw.rect(self.screen, (30, 30, 40), (px, py, panel_w, panel_h))
        pygame.draw.rect(self.screen, (80, 80, 100), (px, py, panel_w, panel_h), 2)

        title = self.font_lg.render("📦 背包", True, WHITE)
        self.screen.blit(title, (px + 20, py + 10))

        p = self.player
        current = sum(p.inventory.values())
        cap_surf = self.font_md.render(f"{current}/{p.get_backpack_size()}", True, GRAY)
        self.screen.blit(cap_surf, (px + panel_w - 80, py + 15))

        # 物品列表
        y = py + 50
        items = sorted(p.inventory.items())
        for i, (item, count) in enumerate(items):
            if y > py + panel_h - 40:
                break
            name, color, cat = ITEMS.get(item, (item, WHITE, ""))

            # 高亮选中
            if i == self.ui_selection:
                pygame.draw.rect(self.screen, (60, 60, 80), (px + 10, y - 2, panel_w - 20, 24))

            # 颜色块
            pygame.draw.rect(self.screen, color, (px + 20, y + 2, 16, 16))

            # 名称
            text = f"{name} x{count}"
            # 食物腐烂提示
            if item in p.food_timers:
                timers = p.food_timers[item]
                if timers:
                    nearest_exp = min(t[1] for t in timers)
                    current_hour = self.game_minute / MINUTES_PER_HOUR
                    remaining = nearest_exp - current_hour
                    if remaining < 24:
                        text += f" ⚠{remaining:.0f}h"

            surf = self.font_md.render(text, True, WHITE)
            self.screen.blit(surf, (px + 45, y))

            # 类别
            cat_surf = self.font_sm.render(f"[{cat}]", True, GRAY)
            self.screen.blit(cat_surf, (px + panel_w - 100, y + 4))

            y += 26

        # 底部提示
        hint = self.font_sm.render("[F]食用 [E]装备 [ESC]关闭 [↑↓]选择", True, GRAY)
        self.screen.blit(hint, (px + 20, py + panel_h - 30))

    def _render_craft(self):
        """渲染制作界面"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 180))
        self.screen.blit(overlay, (0, 0))

        panel_w, panel_h = 800, 580
        px = (WIDTH - panel_w) // 2
        py = (HEIGHT - panel_h) // 2

        pygame.draw.rect(self.screen, (25, 30, 40), (px, py, panel_w, panel_h))
        pygame.draw.rect(self.screen, (70, 90, 120), (px, py, panel_w, panel_h), 2)

        title = self.font_lg.render("🔨 制作", True, WHITE)
        self.screen.blit(title, (px + 20, py + 10))

        p = self.player
        y = py + 50
        visible_start = max(0, self.ui_selection - 12)
        visible_end = min(len(RECIPES), visible_start + 16)

        for i in range(visible_start, visible_end):
            item_name, recipe, desc = RECIPES[i]
            if y > py + panel_h - 40:
                break

            can_craft = p.has_items(recipe)

            if i == self.ui_selection:
                pygame.draw.rect(self.screen, (50, 60, 80), (px + 10, y - 2, panel_w - 20, 30))

            # 名称
            name = ITEMS.get(item_name, (item_name, WHITE, ""))[0]
            name_color = WHITE if can_craft else GRAY
            surf = self.font_md.render(f"{i + 1}. {name}", True, name_color)
            self.screen.blit(surf, (px + 20, y))

            # 材料
            mat_parts = []
            for mat, cnt in recipe.items():
                have = p.inventory.get(mat, 0)
                mat_name = ITEMS.get(mat, (mat,))[0]
                mat_color = GREEN if have >= cnt else RED
                mat_parts.append(f"{mat_name}:{have}/{cnt}")
            mat_text = "  ".join(mat_parts)
            mat_surf = self.font_sm.render(mat_text, True, name_color)
            self.screen.blit(mat_surf, (px + 20, y + 18))

            # 描述
            desc_surf = self.font_sm.render(desc, True, GRAY)
            self.screen.blit(desc_surf, (px + panel_w - desc_surf.get_width() - 20, y + 5))

            y += 34

        hint = self.font_sm.render("[Enter]制作 [↑↓]选择 [ESC]关闭", True, GRAY)
        self.screen.blit(hint, (px + 20, py + panel_h - 30))

    def _render_build(self):
        """渲染建造界面"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 180))
        self.screen.blit(overlay, (0, 0))

        panel_w, panel_h = 600, 400
        px = (WIDTH - panel_w) // 2
        py = (HEIGHT - panel_h) // 2

        pygame.draw.rect(self.screen, (30, 25, 25), (px, py, panel_w, panel_h))
        pygame.draw.rect(self.screen, (100, 80, 60), (px, py, panel_w, panel_h), 2)

        title = self.font_lg.render("🏗 建造", True, WHITE)
        self.screen.blit(title, (px + 20, py + 10))

        p = self.player
        y = py + 50
        btypes = list(BUILDINGS.keys())
        for i, btype in enumerate(btypes):
            bname, recipe, color, radius = BUILDINGS[btype]
            can_build = p.has_items(recipe)

            if i == self.ui_selection:
                pygame.draw.rect(self.screen, (60, 50, 40), (px + 10, y - 2, panel_w - 20, 36))

            name_color = WHITE if can_build else GRAY
            surf = self.font_md.render(f"{i + 1}. {bname}", True, name_color)
            self.screen.blit(surf, (px + 20, y))

            # 材料
            mat_parts = []
            for mat, cnt in recipe.items():
                have = p.inventory.get(mat, 0)
                mat_name = ITEMS.get(mat, (mat,))[0]
                mat_color = GREEN if have >= cnt else RED
                mat_parts.append(f"{mat_name}:{have}/{cnt}")
            mat_surf = self.font_sm.render("  ".join(mat_parts), True, name_color)
            self.screen.blit(mat_surf, (px + 20, y + 20))

            y += 45

        hint = self.font_sm.render("[Enter]建造 [↑↓]选择 [ESC]关闭", True, GRAY)
        self.screen.blit(hint, (px + 20, py + panel_h - 30))

    def _render_status(self):
        """渲染详细状态"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 200))
        self.screen.blit(overlay, (0, 0))

        p = self.player
        panel_w, panel_h = 800, 600
        px = (WIDTH - panel_w) // 2
        py = (HEIGHT - panel_h) // 2

        pygame.draw.rect(self.screen, (20, 20, 30), (px, py, panel_w, panel_h))
        pygame.draw.rect(self.screen, (60, 60, 80), (px, py, panel_w, panel_h), 2)

        title = self.font_xl.render("📊 状态", True, WHITE)
        self.screen.blit(title, (px + 20, py + 10))

        # 左列 - 生存属性
        y = py + 60
        attrs = [
            ("饱食度", f"{p.hunger:.0f}/100", ORANGE),
            ("水分", f"{p.thirst:.0f}/100", BLUE),
            ("体力", f"{p.stamina:.0f}/100", YELLOW),
            ("精神值", f"{p.mental:.0f}/100", PURPLE),
            ("体温", f"{p.body_temp:.1f}°C", CYAN if p.body_temp < 35 else RED if p.body_temp > 38.5 else WHITE),
            ("精力", f"{p.energy:.0f}/100", GREEN),
        ]
        for name, val, color in attrs:
            surf = self.font_md.render(f"{name}: {val}", True, color)
            self.screen.blit(surf, (px + 30, y))
            y += 28

        # 右列 - 肢体状态
        y = py + 60
        self.screen.blit(self.font_lg.render("肢体状态", True, WHITE), (px + 400, y))
        y += 35
        for bp_name in BODY_PARTS:
            bp = p.body[bp_name]
            name = BP_NAMES[bp_name]
            color = bp.get_color()

            # 名称
            surf = self.font_md.render(f"{name}", True, color)
            self.screen.blit(surf, (px + 400, y))

            # 血条
            bar_x = px + 470
            bar_w = 120
            pygame.draw.rect(self.screen, DARK_GRAY, (bar_x, y + 4, bar_w, 14))
            fill = int(bar_w * bp.ratio)
            pygame.draw.rect(self.screen, color, (bar_x, y + 4, fill, 14))
            hp_surf = self.font_sm.render(f"{bp.hp}/{bp.max_hp}", True, WHITE)
            self.screen.blit(hp_surf, (bar_x + bar_w + 5, y + 4))

            # 状态
            status = bp.get_status()
            if status != "正常":
                st_surf = self.font_sm.render(status, True, RED)
                self.screen.blit(st_surf, (px + 650, y + 4))

            y += 26

        # 装备和统计
        y = py + 340
        self.screen.blit(self.font_md.render(f"武器: {ITEMS[p.weapon][0] if p.weapon else '拳头'}", True, WHITE), (px + 30, y))
        y += 25
        self.screen.blit(self.font_md.render(f"护甲: {ITEMS[p.armor][0] if p.armor else '无'}", True, WHITE), (px + 30, y))
        y += 25
        self.screen.blit(self.font_md.render(f"等级: {p.level}  经验: {p.xp}/{p.xp_next}", True, YELLOW), (px + 30, y))
        y += 25
        self.screen.blit(self.font_md.render(f"攻击力: {p.get_attack()}  防御力: {p.get_defense()}", True, WHITE), (px + 30, y))
        y += 25
        self.screen.blit(self.font_md.render(f"存活: {p.days_survived}天  击杀: {p.beasts_killed}", True, WHITE), (px + 30, y))

        # 状态效果
        y = py + 480
        effects = []
        if p.poisoned > 0:
            effects.append(f"中毒({p.poisoned:.0f}分钟)")
        if p.sick > 0:
            effects.append(f"{p.disease_name}({p.sick:.0f}分钟)")
        if p.cold:
            effects.append("感冒")
        if effects:
            self.screen.blit(self.font_md.render(f"状态: {' | '.join(effects)}", True, RED), (px + 30, y))

        hint = self.font_sm.render("[ESC]关闭", True, GRAY)
        self.screen.blit(hint, (px + panel_w - 80, py + panel_h - 30))

    def _render_help(self):
        """渲染帮助"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 200))
        self.screen.blit(overlay, (0, 0))

        panel_w, panel_h = 700, 550
        px = (WIDTH - panel_w) // 2
        py = (HEIGHT - panel_h) // 2

        pygame.draw.rect(self.screen, (20, 20, 35), (px, py, panel_w, panel_h))
        pygame.draw.rect(self.screen, (60, 60, 100), (px, py, panel_w, panel_h), 2)

        title = self.font_xl.render("📖 操作指南", True, WHITE)
        self.screen.blit(title, (px + 20, py + 10))

        lines = [
            ("移动", "WASD / 方向键"),
            ("冲刺", "Shift + 移动 (消耗体力)"),
            ("互动", "E - 砍树/采矿/采集/取水/使用建筑"),
            ("菜单", "Tab - 打开主菜单"),
            ("地图", "M - 查看地图"),
            ("背包", "I - 查看/使用物品"),
            ("制作", "C - 打开制作菜单"),
            ("建造", "B - 打开建造菜单"),
            ("状态", "H - 查看详细状态"),
            ("", ""),
            ("战斗", "A-攻击 F-逃跑 H-使用草药"),
            ("", ""),
            ("生存提示", ""),
            ("", "• 躯干HP归零 = 死亡"),
            ("", "• 流血不止会感染，感染会致死"),
            ("", "• 夜间没有营火会快速降低精神值"),
            ("", "• 冬季暴风雪会导致冻伤"),
            ("", "• 脏水需要净水器或煮沸后饮用"),
            ("", "• 生肉有概率食物中毒"),
            ("", "• 食物会腐烂，注意保质期"),
        ]

        y = py + 60
        for label, desc in lines:
            if label:
                label_surf = self.font_md.render(f"{label}:", True, YELLOW)
                self.screen.blit(label_surf, (px + 30, y))
                desc_surf = self.font_md.render(desc, True, WHITE)
                self.screen.blit(desc_surf, (px + 160, y))
            y += 22

        hint = self.font_sm.render("[ESC]关闭", True, GRAY)
        self.screen.blit(hint, (px + panel_w - 80, py + panel_h - 30))

    def _render_minimap(self):
        """渲染小地图"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 200))
        self.screen.blit(overlay, (0, 0))

        mm_w = MAP_W * 4
        mm_h = MAP_H * 4
        px = (WIDTH - mm_w) // 2
        py = (HEIGHT - mm_h) // 2

        pygame.draw.rect(self.screen, (10, 10, 20), (px - 2, py - 2, mm_w + 4, mm_h + 4))

        for ty in range(MAP_H):
            for tx in range(MAP_W):
                if not self.explored[ty][tx]:
                    pygame.draw.rect(self.screen, (20, 20, 30),
                                     (px + tx * 4, py + ty * 4, 4, 4))
                    continue
                tile = self.tile_map[ty][tx]
                color = TILE_COLORS.get(tile, (100, 100, 100))
                # 缩小颜色
                color = tuple(c // 2 for c in color)
                pygame.draw.rect(self.screen, color, (px + tx * 4, py + ty * 4, 4, 4))

        # 建筑标记
        for b in self.buildings:
            pygame.draw.rect(self.screen, b.color,
                             (px + b.x * 4, py + b.y * 4, 4, 4))

        # 野兽标记
        for beast in self.beasts:
            if beast.alive and self.explored[beast.y][beast.x]:
                pygame.draw.rect(self.screen, RED,
                                 (px + beast.x * 4, py + beast.y * 4, 4, 4))

        # 玩家
        pygame.draw.rect(self.screen, WHITE,
                         (px + self.player.x * 4 - 1, py + self.player.y * 4 - 1, 6, 6))

        hint = self.font_sm.render("[ESC/M]关闭", True, GRAY)
        self.screen.blit(hint, (px, py + mm_h + 10))

    def _render_death(self):
        """渲染死亡画面"""
        self.screen.fill((10, 5, 5))

        p = self.player
        # 标题
        title = self.font_title.render("你 死 了", True, RED)
        self.screen.blit(title, (WIDTH // 2 - title.get_width() // 2, 80))

        # 死因
        cause = "未知原因"
        if p.body[BP_TORSO].hp <= 0:
            cause = "躯干重伤"
        elif p.body[BP_HEAD].hp <= 0:
            cause = "头部重伤"
        elif p.hunger <= 0 and p.thirst <= 0:
            cause = "饥饿与脱水"
        elif p.hunger <= 0:
            cause = "饥饿"
        elif p.thirst <= 0:
            cause = "脱水"
        elif p.body_temp < 32:
            cause = "体温过低"
        elif p.body_temp > 41:
            cause = "中暑"
        elif p.mental <= 0:
            cause = "精神崩溃"
        elif p.poisoned > 0:
            cause = "中毒"

        cause_surf = self.font_lg.render(f"死因: {cause}", True, ORANGE)
        self.screen.blit(cause_surf, (WIDTH // 2 - cause_surf.get_width() // 2, 160))

        # 统计
        stats = [
            f"存活天数: {p.days_survived}",
            f"等级: {p.level}",
            f"击杀野兽: {p.beasts_killed}",
            f"行走步数: {p.steps_walked}",
        ]
        y = 230
        for s in stats:
            surf = self.font_lg.render(s, True, WHITE)
            self.screen.blit(surf, (WIDTH // 2 - surf.get_width() // 2, y))
            y += 40

        # 评分
        score = p.days_survived * 100 + p.beasts_killed * 50 + p.level * 30 + p.steps_walked // 10
        grade = "F" if score < 200 else "D" if score < 500 else "C" if score < 1000 else "B" if score < 2000 else "A" if score < 5000 else "S"
        score_surf = self.font_xl.render(f"评分: {score}  [{grade}]", True, YELLOW)
        self.screen.blit(score_surf, (WIDTH // 2 - score_surf.get_width() // 2, 430))

        restart = self.font_lg.render("按 R 重新开始  |  按 Q 退出", True, GRAY)
        self.screen.blit(restart, (WIDTH // 2 - restart.get_width() // 2, 520))

    # ─── 事件处理 ──────────────────────────────
    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
                return

            if event.type == pygame.KEYDOWN:
                if self.ui_mode == "dead":
                    if event.key == pygame.K_r:
                        self.__init__()
                    elif event.key == pygame.K_q:
                        self.running = False
                    return

                if self.ui_mode == "combat":
                    if event.key == pygame.K_a:
                        self._combat_player_attack()
                    elif event.key == pygame.K_f:
                        self._combat_flee()
                    elif event.key == pygame.K_h:
                        if self.player.has_item("herb"):
                            self.player.remove_item("herb")
                            for bp in self.player.body.values():
                                bp.heal(8)
                            self.combat_log.append("使用了草药，恢复了一些HP")
                        elif self.player.has_item("bandage"):
                            self.player.remove_item("bandage")
                            for bp in self.player.body.values():
                                if bp.bleeding:
                                    bp.bleeding = False
                                    bp.heal(10)
                            self.combat_log.append("使用了绷带止血")
                        else:
                            self.combat_log.append("没有可用的医疗物品")
                    return

                if self.ui_mode == "game":
                    if event.key == pygame.K_e:
                        self._try_interact()
                    elif event.key == pygame.K_TAB:
                        self.ui_mode = "inventory"
                        self.ui_selection = 0
                    elif event.key == pygame.K_m:
                        self.ui_mode = "map"
                    elif event.key == pygame.K_i:
                        self.ui_mode = "inventory"
                        self.ui_selection = 0
                    elif event.key == pygame.K_c:
                        self.ui_mode = "craft"
                        self.ui_selection = 0
                    elif event.key == pygame.K_b:
                        self.ui_mode = "build"
                        self.ui_selection = 0
                    elif event.key == pygame.K_h:
                        self.ui_mode = "status"
                    elif event.key == pygame.K_F1:
                        self.ui_mode = "help"
                    # 快捷进食
                    elif event.key in (pygame.K_1, pygame.K_2, pygame.K_3, pygame.K_4, pygame.K_5):
                        food_items = [k for k in self.player.inventory if k in FOOD_DATA]
                        idx = event.key - pygame.K_1
                        if idx < len(food_items):
                            self._eat_item(food_items[idx])
                    return

                # 菜单内操作
                if event.key == pygame.K_ESCAPE:
                    self.ui_mode = "game"
                    return

                if event.key == pygame.K_UP:
                    self.ui_selection = max(0, self.ui_selection - 1)
                elif event.key == pygame.K_DOWN:
                    if self.ui_mode == "inventory":
                        self.ui_selection = min(len(self.player.inventory) - 1, self.ui_selection + 1)
                    elif self.ui_mode == "craft":
                        self.ui_selection = min(len(RECIPES) - 1, self.ui_selection + 1)
                    elif self.ui_mode == "build":
                        self.ui_selection = min(len(BUILDINGS) - 1, self.ui_selection + 1)

                if event.key == pygame.K_RETURN:
                    if self.ui_mode == "craft":
                        self._craft_item(self.ui_selection)
                    elif self.ui_mode == "build":
                        self._build_item(self.ui_selection)

                # 背包内操作
                if self.ui_mode == "inventory":
                    items = sorted(self.player.inventory.items())
                    if self.ui_selection < len(items):
                        item_name = items[self.ui_selection][0]
                        if event.key == pygame.K_f:
                            if item_name in FOOD_DATA:
                                self._eat_item(item_name)
                        elif event.key == pygame.K_e:
                            if item_name in WEAPON_DATA:
                                self.player.weapon = item_name
                                self.add_message(f"装备了 {ITEMS[item_name][0]}", CYAN)
                            elif item_name in ARMOR_DATA:
                                self.player.armor = item_name
                                self.add_message(f"穿上了 {ITEMS[item_name][0]}", CYAN)
                            elif item_name == "bandage":
                                for bp_name in BODY_PARTS:
                                    if self.player.body[bp_name].bleeding:
                                        self._heal_body_part(bp_name, "bandage")
                                        break
                            elif item_name == "splint":
                                for bp_name in BODY_PARTS:
                                    if self.player.body[bp_name].fractured:
                                        self._heal_body_part(bp_name, "splint")
                                        break
                            elif item_name == "poultice":
                                for bp_name in BODY_PARTS:
                                    if self.player.body[bp_name].infected:
                                        self._heal_body_part(bp_name, "poultice")
                                        break
                            elif item_name == "antibiotic":
                                self._heal_body_part(BP_TORSO, "antibiotic")
                            elif item_name == "trap":
                                self.traps.append(Trap(self.player.x, self.player.y))
                                self.player.remove_item("trap")
                                self.add_message("放置了陷阱", GREEN)

                # 制作数字键
                if self.ui_mode == "craft":
                    if pygame.K_1 <= event.key <= pygame.K_9:
                        idx = event.key - pygame.K_1
                        if idx < len(RECIPES):
                            self._craft_item(idx)
                            self.ui_selection = idx

    # ─── 主循环 ────────────────────────────────
    def run(self):
        while self.running:
            self.handle_events()
            self.update(self.clock.get_time() / 1000.0)
            self.render()
            self.clock.tick(FPS)

        pygame.quit()
        sys.exit()


if __name__ == "__main__":
    game = Game()
    game.run()
