# /// script
# requires-python = ">=3.11"
# dependencies = ["pygame"]
# ///
# -*- coding: utf-8 -*-
"""
硬核荒野求生 2D — 终极硬核生存游戏
2D俯视视角 | 肢体受伤 | 昼夜交替 | 天气系统 | 精神值 | 冻伤/中暑 | 食物腐烂 | 疾病感染
"""

import pygame
import random
import math
import sys
import os
from enum import Enum, IntEnum
from collections import defaultdict

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

# 尝试加载中文字体
FONT_PATH = None
FONT_CANDIDATES = [
    "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
    "/usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc",
    "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf",
    "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
    "/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
    "/System/Library/Fonts/PingFang.ttc",
    "C:/Windows/Fonts/msyh.ttc",
    "C:/Windows/Fonts/simhei.ttf",
]
for fp in FONT_CANDIDATES:
    if os.path.exists(fp):
        FONT_PATH = fp
        break

def get_font(size):
    if FONT_PATH:
        try:
            return pygame.font.Font(FONT_PATH, size)
        except:
            pass
    return pygame.font.SysFont("simhei", size)

# ─── 常量 ─────────────────────────────────────────
WINDOW_W, WINDOW_H = 1280, 720
TILE = 32
MAP_W, MAP_H = 80, 80
FPS = 60

# 时间：120帧(2秒)=1游戏分钟 → 1秒=0.5分钟 → 24小时=48分钟现实
FRAMES_PER_GAME_MIN = 120

# ─── 颜色 ─────────────────────────────────────────
C_WHITE = (255, 255, 255)
C_BLACK = (0, 0, 0)
C_GRAY = (128, 128, 128)
C_DARK = (40, 40, 40)
C_RED = (220, 50, 50)
C_GREEN = (50, 180, 50)
C_BLUE = (60, 120, 200)
C_YELLOW = (230, 200, 50)
C_ORANGE = (230, 150, 50)
C_BROWN = (139, 90, 43)
C_DARKGREEN = (30, 100, 30)
C_DARKBLUE = (30, 60, 120)
C_SKY = (135, 206, 235)
C_NIGHT = (15, 15, 40)

# 地形颜色
TILE_COLORS = {
    'grass': (90, 160, 70),
    'grass2': (80, 145, 60),
    'tree': (30, 90, 30),
    'tree_trunk': (100, 65, 30),
    'water': (50, 120, 200),
    'deep_water': (30, 80, 160),
    'rock': (140, 140, 140),
    'rock_dark': (110, 110, 110),
    'dirt': (160, 130, 90),
    'bush': (60, 130, 50),
    'tall_grass': (70, 140, 55),
    'sand': (210, 190, 140),
    'snow': (230, 235, 245),
    'campfire_off': (100, 70, 40),
    'campfire_on': (230, 140, 40),
    'shelter': (120, 85, 50),
    'wall': (90, 80, 70),
}

# ─── 枚举 ─────────────────────────────────────────
class Tile(IntEnum):
    GRASS = 0
    TREE = 1
    WATER = 2
    ROCK = 3
    DIRT = 4
    BUSH = 5
    TALL_GRASS = 6
    SAND = 7
    DEEP_WATER = 8
    CAMPFIRE_OFF = 10
    CAMPFIRE_ON = 11
    SHELTER = 12
    WALL = 13

class Season(Enum):
    SPRING = "春"
    SUMMER = "夏"
    AUTUMN = "秋"
    WINTER = "冬"

class Weather(Enum):
    CLEAR = "晴"
    CLOUDY = "云"
    RAIN = "雨"
    STORM = "暴雨"
    WIND = "风"
    BLIZZARD = "暴雪"

class BodyPart(Enum):
    HEAD = "头部"
    TORSO = "躯干"
    L_ARM = "左臂"
    R_ARM = "右臂"
    L_LEG = "左腿"
    R_LEG = "右腿"

class GameMode(Enum):
    WORLD = 0
    INVENTORY = 1
    CRAFT = 2
    COMBAT = 3
    BUILD = 4
    STATUS = 5
    PAUSE = 6
    GAMEOVER = 7
    HELP = 8
    EAT = 9
    HEAL = 10

# ─── 物品定义 ─────────────────────────────────────
ITEMS = {
    'wood': ('木材', (139, 90, 43), '资源'),
    'stone': ('石头', (140, 140, 140), '资源'),
    'fiber': ('纤维', (80, 160, 80), '资源'),
    'dirty_water': ('脏水', (120, 150, 100), '资源'),
    'clean_water': ('净水', (80, 180, 230), '资源'),
    'berries': ('浆果', (180, 40, 60), '食物'),
    'mushroom': ('蘑菇', (180, 140, 80), '食物'),
    'raw_meat': ('生肉', (200, 80, 80), '食物'),
    'cooked_meat': ('烤肉', (160, 100, 60), '食物'),
    'raw_fish': ('生鱼', (120, 160, 200), '食物'),
    'cooked_fish': ('烤鱼', (180, 150, 100), '食物'),
    'herb': ('草药', (60, 180, 80), '医疗'),
    'bandage': ('绷带', (230, 230, 220), '医疗'),
    'splint': ('夹板', (160, 130, 80), '医疗'),
    'antibiotic': ('抗生素', (80, 200, 120), '医疗'),
    'stone_axe': ('石斧', (130, 120, 100), '武器'),
    'stone_spear': ('石矛', (140, 130, 110), '武器'),
    'bone_knife': ('骨刃', (200, 190, 170), '武器'),
    'wooden_club': ('木棍', (150, 110, 60), '武器'),
    'torch': ('火把', (230, 160, 50), '工具'),
    'fur': ('兽皮', (170, 140, 100), '资源'),
    'bone': ('骨头', (220, 210, 190), '资源'),
    'leather_armor': ('皮甲', (140, 100, 60), '防具'),
    'stew': ('炖肉汤', (180, 120, 60), '食物'),
    'rope': ('绳索', (160, 140, 80), '资源'),
    'tea': ('草药茶', (120, 180, 100), '食物'),
    'trap': ('陷阱', (130, 110, 70), '工具'),
    'iron_armor': ('铁甲', (160, 165, 170), '防具'),
    'water_filter': ('净水器', (100, 160, 180), '工具'),
}

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

# ─── 配方 ─────────────────────────────────────────
RECIPES = [
    ('stone_axe', {'wood': 3, 'stone': 2, 'fiber': 2}, '武器', '攻击力+8 伐木效率x2'),
    ('stone_spear', {'wood': 4, 'stone': 3, 'fiber': 2}, '武器', '攻击力+12 狩猎利器'),
    ('bone_knife', {'bone': 3, 'fiber': 2}, '武器', '攻击力+18 锋利无比'),
    ('wooden_club', {'wood': 5}, '武器', '攻击力+5 简单粗暴'),
    ('bandage', {'fiber': 4}, '医疗', '止血 治疗流血'),
    ('splint', {'wood': 3, 'fiber': 2}, '医疗', '固定骨折'),
    ('antibiotic', {'herb': 5, 'clean_water': 1}, '医疗', '治疗感染和疾病'),
    ('torch', {'wood': 2, 'fiber': 1}, '工具', '夜间照明 驱赶野兽'),
    ('leather_armor', {'fur': 4, 'fiber': 3}, '防具', '防御+8 保暖'),
    ('iron_armor', {'stone': 8, 'fur': 2, 'fiber': 4}, '防具', '防御+18 重型护甲'),
    ('rope', {'fiber': 6}, '资源', '制作高级物品'),
    ('trap', {'wood': 4, 'rope': 2, 'fiber': 2}, '工具', '放置后自动捕获猎物'),
    ('stew', {'cooked_meat': 1, 'clean_water': 1, 'herb': 1}, '食物', '饱食+50 水分+20'),
    ('tea', {'herb': 3, 'clean_water': 1}, '食物', '恢复精神 治疗感冒'),
    ('water_filter', {'wood': 3, 'stone': 2, 'fiber': 3}, '工具', '脏水→净水'),
]

# ─── 野兽定义 ─────────────────────────────────────
BEAST_TYPES = {
    'rabbit': {'name': '野兔', 'hp': 30, 'atk': 5, 'def': 0, 'speed': 4, 'color': (180, 150, 120),
               'drop': [('raw_meat', 1), ('fur', 1)], 'xp': 10, 'aggro': False, 'night_mult': 1.0},
    'snake': {'name': '毒蛇', 'hp': 40, 'atk': 15, 'def': 2, 'speed': 3, 'color': (80, 140, 60),
              'drop': [('raw_meat', 1), ('herb', 1)], 'xp': 20, 'aggro': True, 'night_mult': 1.2},
    'wolf': {'name': '灰狼', 'hp': 100, 'atk': 22, 'def': 5, 'speed': 3, 'color': (120, 120, 130),
             'drop': [('raw_meat', 2), ('fur', 2), ('bone', 1)], 'xp': 40, 'aggro': True, 'night_mult': 1.4},
    'boar': {'name': '野猪', 'hp': 120, 'atk': 18, 'def': 8, 'speed': 2, 'color': (120, 80, 60),
             'drop': [('raw_meat', 3), ('fur', 2)], 'xp': 35, 'aggro': True, 'night_mult': 1.1},
    'bear': {'name': '棕熊', 'hp': 220, 'atk': 35, 'def': 12, 'speed': 2, 'color': (100, 70, 40),
             'drop': [('raw_meat', 4), ('fur', 3), ('bone', 2)], 'xp': 80, 'aggro': True, 'night_mult': 1.3},
    'leopard': {'name': '山豹', 'hp': 140, 'atk': 30, 'def': 6, 'speed': 5, 'color': (200, 170, 80),
                'drop': [('raw_meat', 2), ('fur', 3), ('bone', 1)], 'xp': 60, 'aggro': True, 'night_mult': 1.5},
}

# ─── 肢体数据 ─────────────────────────────────────
BODY_PART_DATA = {
    BodyPart.HEAD: {'max_hp': 80, 'pos': (0, -20), 'size': (16, 16)},
    BodyPart.TORSO: {'max_hp': 180, 'pos': (0, 0), 'size': (20, 24)},
    BodyPart.L_ARM: {'max_hp': 60, 'pos': (-16, -4), 'size': (10, 20)},
    BodyPart.R_ARM: {'max_hp': 60, 'pos': (16, -4), 'size': (10, 20)},
    BodyPart.L_LEG: {'max_hp': 60, 'pos': (-8, 20), 'size': (10, 22)},
    BodyPart.R_LEG: {'max_hp': 60, 'pos': (8, 20), 'size': (10, 22)},
}

# 攻击部位概率
HIT_WEIGHTS = {
    BodyPart.HEAD: 8,
    BodyPart.TORSO: 35,
    BodyPart.L_ARM: 14,
    BodyPart.R_ARM: 14,
    BodyPart.L_LEG: 15,
    BodyPart.R_LEG: 14,
}

# ─── 地图生成 ─────────────────────────────────────
def generate_map():
    """生成80x80的游戏地图"""
    tile_map = [[Tile.GRASS for _ in range(MAP_W)] for _ in range(MAP_H)]

    # 生成河流
    for _ in range(2):
        rx, ry = random.randint(5, MAP_W-5), 0
        for y in range(MAP_H):
            for dx in range(-1, 2):
                nx = rx + dx
                if 0 <= nx < MAP_W:
                    tile_map[y][nx] = Tile.WATER
            # 深水区域
            tile_map[y][rx] = Tile.DEEP_WATER
            rx += random.choice([-1, 0, 0, 1])
            rx = max(2, min(MAP_W - 3, rx))

    # 湖泊
    for _ in range(3):
        cx, cy = random.randint(10, MAP_W-10), random.randint(10, MAP_H-10)
        r = random.randint(3, 6)
        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 dx*dx + dy*dy <= (r-1)*(r-1):
                            tile_map[ny][nx] = Tile.DEEP_WATER
                        else:
                            tile_map[ny][nx] = Tile.WATER

    # 沙地围绕水域
    for y in range(MAP_H):
        for x in range(MAP_W):
            if tile_map[y][x] in (Tile.WATER, Tile.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 tile_map[ny][nx] == Tile.GRASS and random.random() < 0.5:
                                tile_map[ny][nx] = Tile.SAND

    # 森林区域
    for _ in range(12):
        cx, cy = random.randint(5, MAP_W-5), random.randint(5, MAP_H-5)
        r = random.randint(4, 9)
        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 tile_map[ny][nx] == Tile.GRASS:
                            if random.random() < 0.6:
                                tile_map[ny][nx] = Tile.TREE
                            elif random.random() < 0.3:
                                tile_map[ny][nx] = Tile.BUSH

    # 岩石区域
    for _ in range(8):
        cx, cy = random.randint(5, MAP_W-5), random.randint(5, MAP_H-5)
        r = random.randint(2, 5)
        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 tile_map[ny][nx] == Tile.GRASS and random.random() < 0.5:
                            tile_map[ny][nx] = Tile.ROCK

    # 散布的树和灌木
    for y in range(MAP_H):
        for x in range(MAP_W):
            if tile_map[y][x] == Tile.GRASS:
                r = random.random()
                if r < 0.04:
                    tile_map[y][x] = Tile.TREE
                elif r < 0.07:
                    tile_map[y][x] = Tile.BUSH
                elif r < 0.12:
                    tile_map[y][x] = Tile.TALL_GRASS
                elif r < 0.14:
                    tile_map[y][x] = Tile.ROCK

    # 小路
    for _ in range(4):
        px, py = random.randint(0, MAP_W-1), random.randint(0, MAP_H-1)
        for _ in range(60):
            if 0 <= px < MAP_W and 0 <= py < MAP_H:
                if tile_map[py][px] in (Tile.GRASS, Tile.TALL_GRASS):
                    tile_map[py][px] = Tile.DIRT
            px += random.choice([-1, 0, 0, 1])
            py += random.choice([-1, 0, 0, 1])
            px = max(0, min(MAP_W-1, px))
            py = max(0, min(MAP_H-1, py))

    # 确保中心附近有空地（玩家出生点）
    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:
                tile_map[ny][nx] = Tile.GRASS

    # 探索迷雾
    explored = [[False]*MAP_W for _ in range(MAP_H)]

    return tile_map, explored

# ─── 玩家类 ─────────────────────────────────────
class Player:
    def __init__(self):
        self.x = MAP_W // 2
        self.y = MAP_H // 2
        self.px = self.x * TILE + TILE // 2  # 像素坐标
        self.py = self.y * TILE + TILE // 2

        # 生存属性
        self.hp = 100
        self.max_hp = 100
        self.hunger = 100  # 饱食度
        self.thirst = 100  # 水分
        self.stamina = 100  # 体力
        self.mental = 100   # 精神值
        self.body_temp = 36.5  # 体温
        self.energy = 100   # 精力

        # 肢体
        self.body_parts = {}
        for part, data in BODY_PART_DATA.items():
            self.body_parts[part] = {
                'hp': data['max_hp'],
                'max_hp': data['max_hp'],
                'bleeding': False,
                'fractured': False,
                'infected': False,
                'frostbite': False,
                'crippled': False,
            }

        # 状态效果
        self.poisoned = 0      # 中毒剩余时间(游戏分钟)
        self.sick = 0          # 生病剩余时间
        self.disease_name = ""

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

        # 背包
        self.inventory = defaultdict(int)
        self.inventory['wood'] = 2  # 初始少量资源
        self.inventory['fiber'] = 3

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

        # 移动速度
        self.base_speed = 2.5
        self.move_cooldown = 0

        # 统计数据
        self.days_survived = 0
        self.beasts_killed = 0
        self.total_damage_dealt = 0
        self.steps_walked = 0

    def get_speed(self):
        speed = self.base_speed
        # 腿部受伤减速
        for leg in [BodyPart.L_LEG, BodyPart.R_LEG]:
            bp = self.body_parts[leg]
            if bp['crippled']:
                speed *= 0.3
            elif bp['fractured']:
                speed *= 0.5
            if bp['frostbite']:
                speed *= 0.7
        # 体力不足减速
        if self.stamina < 20:
            speed *= 0.5
        elif self.stamina < 50:
            speed *= 0.7
        # 负重减速
        total_weight = sum(v for v in self.inventory.values())
        if total_weight > 50:
            speed *= 0.7
        return max(0.5, speed)

    def get_attack(self):
        base = 5 + self.level * 2
        if self.weapon:
            wpn_atk = {'wooden_club': 5, 'stone_axe': 8, 'stone_spear': 12, 'bone_knife': 18}
            base += wpn_atk.get(self.weapon, 0)
        # 手臂受伤减攻
        for arm in [BodyPart.L_ARM, BodyPart.R_ARM]:
            bp = self.body_parts[arm]
            if bp['crippled']:
                base *= 0.5
            elif bp['fractured']:
                base *= 0.6
        # 头部受伤
        if self.body_parts[BodyPart.HEAD]['crippled']:
            base *= 0.5
        return max(1, int(base))

    def get_defense(self):
        base = 2
        if self.armor:
            arm_def = {'leather_armor': 8, 'iron_armor': 18}
            base += arm_def.get(self.armor, 0)
        return base

    def get_total_hp(self):
        """总生命值 = 躯干HP + 其他部位HP加权"""
        total = 0
        for part, data in self.body_parts.items():
            if not data['crippled']:
                total += data['hp']
        return total

    def take_damage(self, amount, part=None):
        """受到伤害"""
        if part is None:
            # 随机选择部位
            weights = list(HIT_WEIGHTS.values())
            parts = list(HIT_WEIGHTS.keys())
            part = random.choices(parts, weights=weights, k=1)[0]

        bp = self.body_parts[part]
        if bp['crippled']:
            # 残废部位转移伤害到躯干
            part = BodyPart.TORSO
            bp = self.body_parts[part]

        actual = max(1, amount - self.get_defense() // 2)
        bp['hp'] -= actual

        # 概率流血(30%)
        if random.random() < 0.30 and not bp['bleeding']:
            bp['bleeding'] = True

        # 概率骨折(15%，重伤时更高)
        fracture_chance = 0.15 if actual < 20 else 0.30
        if random.random() < fracture_chance and not bp['fractured']:
            bp['fractured'] = True

        # 检查残废
        if bp['hp'] <= 0:
            bp['hp'] = 0
            bp['crippled'] = True
            bp['bleeding'] = True
            if part == BodyPart.TORSO:
                return True  # 死亡

        return False

    def heal_part(self, part, amount):
        bp = self.body_parts[part]
        if bp['crippled']:
            return
        bp['hp'] = min(bp['max_hp'], bp['hp'] + amount)

    def is_alive(self):
        return self.body_parts[BodyPart.TORSO]['hp'] > 0

    def add_xp(self, amount):
        self.xp += amount
        while self.xp >= self.xp_next:
            self.xp -= self.xp_next
            self.level += 1
            self.xp_next = int(self.xp_next * 1.5)
            self.max_hp += 10
            self.body_parts[BodyPart.TORSO]['max_hp'] += 15
            # 升级恢复
            for bp in self.body_parts.values():
                if not bp['crippled']:
                    bp['hp'] = min(bp['max_hp'], bp['hp'] + 20)
            return True
        return False

    def has_items(self, requirements):
        for item, count in requirements.items():
            if self.inventory.get(item, 0) < count:
                return False
        return True

    def consume_items(self, requirements):
        for item, count in requirements.items():
            self.inventory[item] -= count
            if self.inventory[item] <= 0:
                del self.inventory[item]

# ─── 野兽实体 ─────────────────────────────────────
class Beast:
    def __init__(self, btype, x, y):
        self.btype = btype
        self.data = BEAST_TYPES[btype]
        self.x = x
        self.y = y
        self.px = x * TILE + TILE // 2
        self.py = y * TILE + TILE // 2
        self.hp = self.data['hp']
        self.max_hp = self.data['hp']
        self.atk = self.data['atk']
        self.speed = self.data['speed']
        self.move_timer = 0
        self.aggro_range = 6 if self.data['aggro'] else 0
        self.flee_hp_ratio = 0.2
        self.direction = random.choice([(0,1),(0,-1),(1,0),(-1,0)])
        self.alive = True
        self.attack_cooldown = 0

    def update(self, player, tile_map, game_hour, is_night):
        if not self.alive:
            return

        self.move_timer += 1
        self.attack_cooldown = max(0, self.attack_cooldown - 1)

        # 夜间强化
        night_mult = self.data['night_mult'] if is_night else 1.0

        dist = math.sqrt((self.px - player.px)**2 + (self.py - player.py)**2)

        # AI行为
        if self.hp / self.max_hp < self.flee_hp_ratio:
            # 逃跑
            self._flee(player)
        elif self.data['aggro'] and dist < self.aggro_range * TILE * night_mult:
            # 追击
            self._chase(player)
        else:
            # 巡逻
            if self.move_timer % (60 // max(1, self.speed)) == 0:
                self._wander(tile_map)

        # 攻击判定
        if dist < TILE * 1.2 and self.attack_cooldown <= 0:
            self.attack_cooldown = 90  # 1.5秒攻击间隔
            return True  # 发起攻击
        return False

    def _chase(self, player):
        dx = player.px - self.px
        dy = player.py - self.py
        dist = max(1, math.sqrt(dx*dx + dy*dy))
        speed = self.speed * 0.8
        self.px += dx / dist * speed
        self.py += dy / dist * speed
        self._clamp_pos()

    def _flee(self, player):
        dx = self.px - player.px
        dy = self.py - player.py
        dist = max(1, math.sqrt(dx*dx + dy*dy))
        speed = self.speed * 1.2
        self.px += dx / dist * speed
        self.py += dy / dist * speed
        self._clamp_pos()

    def _wander(self, tile_map):
        if random.random() < 0.3:
            self.direction = random.choice([(0,1),(0,-1),(1,0),(-1,0)])
        nx = self.px + self.direction[0] * self.speed * 2
        ny = self.py + self.direction[1] * self.speed * 2
        tx = int(nx // TILE)
        ty = int(ny // TILE)
        if 0 <= tx < MAP_W and 0 <= ty < MAP_H:
            t = tile_map[ty][tx]
            if t not in (Tile.WATER, Tile.DEEP_WATER, Tile.TREE, Tile.ROCK, Tile.WALL):
                self.px = nx
                self.py = ny
        self._clamp_pos()

    def _clamp_pos(self):
        self.px = max(TILE, min((MAP_W-1)*TILE, self.px))
        self.py = max(TILE, min((MAP_H-1)*TILE, self.py))
        self.x = int(self.px // TILE)
        self.y = int(self.py // TILE)

# ─── 陷阱实体 ─────────────────────────────────────
class Trap:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.active = True
        self.cooldown = 0
        self.caught = None  # 捕获的物品

    def update(self, beasts, game_minute):
        if not self.active:
            self.cooldown -= 1
            if self.cooldown <= 0:
                self.active = True
            return

        for beast in beasts:
            if beast.alive and abs(beast.x - self.x) <= 1 and abs(beast.y - self.y) <= 1:
                if beast.btype in ('rabbit', 'snake'):
                    beast.alive = False
                    self.active = False
                    self.cooldown = 600  # 10游戏小时后重置
                    self.caught = beast.data['drop'][0][0] if beast.data['drop'] else 'raw_meat'
                    return True
        return False

# ─── 天气粒子 ─────────────────────────────────────
class WeatherParticle:
    def __init__(self, ptype):
        self.ptype = ptype
        self.reset()

    def reset(self):
        self.x = random.uniform(0, WINDOW_W)
        self.y = random.uniform(-20, 0)
        self.speed = random.uniform(4, 8)
        self.size = random.uniform(1, 3)
        self.wind_x = random.uniform(-1, 1)
        self.alpha = random.randint(100, 255)

    def update(self):
        if self.ptype == 'rain':
            self.y += self.speed * 2
            self.x += self.wind_x + 1
        elif self.ptype == 'snow':
            self.y += self.speed * 0.5
            self.x += math.sin(self.y * 0.02) * 0.5 + self.wind_x
        elif self.ptype == 'wind':
            self.x += self.speed * 3
            self.y += self.wind_x * 0.5
        if self.y > WINDOW_H or self.x > WINDOW_W + 20 or self.x < -20:
            self.reset()

# ─── 主游戏类 ─────────────────────────────────────
class Game:
    def __init__(self):
        self.screen = pygame.display.set_mode((WINDOW_W, WINDOW_H))
        pygame.display.set_caption("硬核荒野求生 2D — 终极版")
        self.clock = pygame.time.Clock()

        # 字体
        self.font_sm = get_font(14)
        self.font_md = get_font(18)
        self.font_lg = get_font(24)
        self.font_xl = get_font(36)
        self.font_title = get_font(48)

        # 游戏状态
        self.running = True
        self.mode = GameMode.WORLD
        self.frame = 0

        # 时间系统
        self.game_minute = 360  # 从早上6点开始 (6*60)
        self.game_day = 1
        self.season = Season.SPRING
        self.total_minutes = 0

        # 天气
        self.weather = Weather.CLEAR
        self.weather_timer = 0
        self.weather_particles = []

        # 地图
        self.tile_map, self.explored = generate_map()

        # 玩家
        self.player = Player()

        # 野兽
        self.beasts = []
        self.beast_spawn_timer = 0
        self._spawn_initial_beasts()

        # 陷阱
        self.traps = []

        # 消息日志
        self.messages = []
        self.message_timer = 0

        # 相机
        self.cam_x = 0
        self.cam_y = 0

        # 战斗状态
        self.combat_beast = None
        self.combat_log = []
        self.combat_player_turn = True
        self.combat_anim_timer = 0

        # UI选择
        self.craft_scroll = 0
        self.inv_scroll = 0
        self.eat_scroll = 0
        self.heal_scroll = 0
        self.build_selected = 0

        # 食物腐烂追踪
        self.food_timers = {}  # {item_name: game_hour_obtained}

        # 提示
        self.interact_hint = ""
        self.interact_target = None

        # 初始天气粒子
        self._update_weather_particles()

        self._log("你醒来发现自己身处荒野之中...", C_YELLOW)
        self._log("WASD移动 | E互动 | I背包 | C制作 | B建造 | H治疗 | M状态 | F1帮助", C_WHITE)

    def _log(self, msg, color=C_WHITE):
        self.messages.append((msg, color, self.frame))
        if len(self.messages) > 50:
            self.messages.pop(0)

    def _spawn_initial_beasts(self):
        for _ in range(20):
            self._spawn_beast()

    def _spawn_beast(self):
        for _ in range(50):
            x = random.randint(2, MAP_W - 3)
            y = random.randint(2, MAP_H - 3)
            if self.tile_map[y][x] in (Tile.GRASS, Tile.TALL_GRASS, Tile.DIRT):
                dist = math.sqrt((x - self.player.x)**2 + (y - self.player.y)**2)
                if dist > 10:
                    weights = {'rabbit': 30, 'snake': 20, 'wolf': 20, 'boar': 15, 'bear': 8, 'leopard': 7}
                    btype = random.choices(list(weights.keys()), weights=list(weights.values()), k=1)[0]
                    self.beasts.append(Beast(btype, x, y))
                    return

    def _update_weather_particles(self):
        self.weather_particles = []
        if self.weather in (Weather.RAIN, Weather.STORM):
            count = 80 if self.weather == Weather.RAIN else 150
            for _ in range(count):
                self.weather_particles.append(WeatherParticle('rain'))
        elif self.weather == Weather.BLIZZARD:
            for _ in range(100):
                self.weather_particles.append(WeatherParticle('snow'))
        elif self.weather == Weather.WIND:
            for _ in range(40):
                self.weather_particles.append(WeatherParticle('wind'))

    # ─── 时间系统 ───────────────────────────────
    def update_time(self):
        self.frame += 1
        if self.frame % FRAMES_PER_GAME_MIN == 0:
            self.game_minute += 1
            self.total_minutes += 1

            if self.game_minute >= 1440:  # 24小时
                self.game_minute = 0
                self.game_day += 1
                self.player.days_survived = self.game_day - 1
                self._log(f"═══ 第{self.game_day}天 ═══", C_YELLOW)
                # 换季
                if self.game_day % 10 == 1:
                    seasons = list(Season)
                    idx = (seasons.index(self.season) + 1) % 4
                    self.season = seasons[idx]
                    self._log(f"季节变更: {self.season.value}季", C_ORANGE)

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

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

            # 陷阱检查(每30分钟)
            if self.game_minute % 30 == 0:
                self._update_traps()

    def _change_weather(self):
        season_weights = {
            Season.SPRING: {Weather.CLEAR: 30, Weather.CLOUDY: 25, Weather.RAIN: 25, Weather.STORM: 10, Weather.WIND: 10},
            Season.SUMMER: {Weather.CLEAR: 40, Weather.CLOUDY: 20, Weather.RAIN: 15, Weather.STORM: 15, Weather.WIND: 10},
            Season.AUTUMN: {Weather.CLEAR: 20, Weather.CLOUDY: 25, Weather.RAIN: 20, Weather.STORM: 10, Weather.WIND: 25},
            Season.WINTER: {Weather.CLEAR: 15, Weather.CLOUDY: 20, Weather.WIND: 20, Weather.BLIZZARD: 30, Weather.RAIN: 15},
        }
        w = season_weights[self.season]
        self.weather = random.choices(list(w.keys()), weights=list(w.values()), k=1)[0]
        self.weather_timer = random.randint(120, 360)  # 2-6游戏小时
        self._update_weather_particles()
        self._log(f"天气: {self.weather.value}", C_SKY if self.weather == Weather.CLEAR else C_GRAY)

    @property
    def game_hour(self):
        return self.game_minute / 60.0

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

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

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

    def get_sky_tint(self):
        """返回天空颜色覆盖层"""
        h = self.game_hour
        if 8 <= h <= 17:
            return None  # 白天无覆盖
        elif 21 <= h or h <= 4:
            return (*C_NIGHT, 160)  # 深夜
        elif self.is_dawn:
            t = (h - 5) / 2  # 0→1
            alpha = int(160 * (1 - t))
            return (40, 30, 60, alpha)
        elif self.is_dusk:
            t = (h - 18) / 2
            alpha = int(160 * t)
            return (30, 20, 50, alpha)
        return None

    # ─── 生存更新 ───────────────────────────────
    def update_survival(self):
        if self.frame % FRAMES_PER_GAME_MIN != 0:
            return

        p = self.player
        minute = self.game_minute

        # 每小时(每60分钟)衰减
        hourly = (minute % 60 == 0)
        # 每10分钟
        ten_min = (minute % 10 == 0)
        # 每分钟
        every_min = True

        # 饱食度衰减
        if hourly:
            p.hunger = max(0, p.hunger - 3)

        # 水分衰减(更快)
        if ten_min:
            decay = 2
            if self.weather in (Weather.STORM, Weather.BLIZZARD, Weather.WIND):
                decay += 1
            if self.season == Season.SUMMER:
                decay += 1
            p.thirst = max(0, p.thirst - decay)

        # 体力恢复/消耗
        if hourly:
            if self.mode == GameMode.WORLD:
                p.stamina = min(100, p.stamina + 2)

        # 精神值
        if hourly:
            if self.is_night:
                has_fire = self._near_campfire()
                has_shelter = self._on_tile(Tile.SHELTER)
                if has_fire and has_shelter:
                    p.mental = min(100, p.mental + 3)
                elif has_fire:
                    p.mental = min(100, p.mental + 1)
                else:
                    p.mental = max(0, p.mental - 5)
            else:
                p.mental = min(100, p.mental + 1)

        # 体温调节
        if ten_min:
            target = 36.5
            if self.season == Season.WINTER:
                target -= 3
            if self.season == Season.SUMMER:
                target += 1
            if self.weather == Weather.BLIZZARD:
                target -= 5
            if self.weather in (Weather.RAIN, Weather.STORM):
                target -= 2
            if self._on_tile(Tile.SHELTER):
                target += 2
            if self._near_campfire():
                target += 3
            if p.armor == 'leather_armor':
                target += 1
            elif p.armor == 'iron_armor':
                target += 0.5

            diff = target - p.body_temp
            p.body_temp += diff * 0.1
            p.body_temp = max(30, min(42, p.body_temp))

        # 体温伤害
        if hourly:
            if p.body_temp < 34:
                # 冻伤
                dmg = int((34 - p.body_temp) * 3)
                for part in [BodyPart.L_ARM, BodyPart.R_ARM, BodyPart.L_LEG, BodyPart.R_LEG]:
                    if random.random() < 0.3:
                        p.body_parts[part]['frostbite'] = True
                        p.body_parts[part]['hp'] = max(0, p.body_parts[part]['hp'] - dmg)
                self._log(f"寒冷! 体温{p.body_temp:.1f}°C 冻伤风险!", (100, 180, 255))
            elif p.body_temp > 39:
                # 中暑
                dmg = int((p.body_temp - 39) * 4)
                p.take_damage(dmg, BodyPart.TORSO)
                p.thirst = max(0, p.thirst - 5)
                self._log(f"中暑! 体温{p.body_temp:.1f}°C!", C_RED)

        # 流血伤害
        if ten_min:
            for part_name, bp in p.body_parts.items():
                if bp['bleeding']:
                    bp['hp'] = max(0, bp['hp'] - 3)
                    if bp['hp'] <= 0:
                        bp['crippled'] = True
                        self._log(f"{part_name.value}残废!", C_RED)
                    # 感染概率
                    if random.random() < 0.05 and not bp['infected']:
                        bp['infected'] = True
                        self._log(f"{part_name.value}伤口感染!", (180, 50, 50))
                if bp['infected']:
                    bp['hp'] = max(0, bp['hp'] - 2)
                    if bp['hp'] <= 0:
                        bp['crippled'] = True

        # 中毒
        if p.poisoned > 0:
            p.poisoned -= 1
            if ten_min:
                p.take_damage(3, BodyPart.TORSO)
                p.hunger = max(0, p.hunger - 2)
            if p.poisoned <= 0:
                self._log("毒素已消散", C_GREEN)

        # 疾病
        if p.sick > 0:
            p.sick -= 1
            if hourly:
                p.take_damage(2, random.choice(list(BodyPart)))
                p.mental = max(0, p.mental - 2)
            if p.sick <= 0:
                self._log("疾病已痊愈", C_GREEN)
                p.disease_name = ""

        # 饥饿/脱水伤害
        if hourly:
            if p.hunger <= 0:
                p.take_damage(5, BodyPart.TORSO)
                self._log("饥饿正在侵蚀你的身体!", C_RED)
            if p.thirst <= 0:
                p.take_damage(8, BodyPart.TORSO)
                self._log("严重脱水! 你需要水!", C_RED)

        # 精神崩溃
        if p.mental <= 0:
            p.take_damage(3, BodyPart.HEAD)
            if hourly:
                self._log("精神崩溃... 你感到绝望", (150, 80, 180))

        # 庇护所休息回血
        if self._on_tile(Tile.SHELTER) and hourly:
            for bp in p.body_parts.values():
                if not bp['crippled']:
                    bp['hp'] = min(bp['max_hp'], bp['hp'] + 3)
            p.stamina = min(100, p.stamina + 5)

    # ─── 食物腐烂 ───────────────────────────────
    def _check_food_rot(self):
        current_hour = self.game_day * 24 + self.game_hour
        to_remove = []
        for item, obtain_hour in list(self.food_timers.items()):
            if item in FOOD_DATA:
                rot_hours = FOOD_DATA[item][5]
                if current_hour - obtain_hour > rot_hours:
                    if self.player.inventory.get(item, 0) > 0:
                        self.player.inventory[item] -= 1
                        if self.player.inventory[item] <= 0:
                            del self.player.inventory[item]
                        to_remove.append(item)
                        self._log(f"{ITEMS[item][0]}腐烂了!", (150, 100, 50))
        for item in to_remove:
            if item in self.food_timers:
                del self.food_timers[item]

    def _add_food_item(self, item, count=1):
        current_hour = self.game_day * 24 + self.game_hour
        self.player.inventory[item] = self.player.inventory.get(item, 0) + count
        if item in FOOD_DATA:
            self.food_timers[item] = current_hour

    # ─── 陷阱更新 ───────────────────────────────
    def _update_traps(self):
        for trap in self.traps:
            caught = trap.update(self.beasts, self.game_minute)
            if caught:
                self._add_food_item(trap.caught)
                self._log(f"陷阱捕获了 {ITEMS[trap.caught][0]}!", C_GREEN)

    # ─── 辅助方法 ───────────────────────────────
    def _near_campfire(self):
        px, py = self.player.x, self.player.y
        for dy in range(-2, 3):
            for dx in range(-2, 3):
                nx, ny = px+dx, py+dy
                if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                    if self.tile_map[ny][nx] == Tile.CAMPFIRE_ON:
                        return True
        return False

    def _on_tile(self, tile_type):
        px, py = self.player.x, self.player.y
        if 0 <= px < MAP_W and 0 <= py < MAP_H:
            return self.tile_map[py][px] == tile_type
        return False

    def _get_tile_at(self, x, y):
        if 0 <= x < MAP_W and 0 <= y < MAP_H:
            return self.tile_map[y][x]
        return Tile.GRASS

    def _get_nearby_interactable(self):
        """获取附近可互动的物体"""
        px, py = self.player.x, self.player.y
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx == 0 and dy == 0:
                    continue
                nx, ny = px+dx, py+dy
                if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                    t = self.tile_map[ny][nx]
                    if t in (Tile.TREE, Tile.ROCK, Tile.BUSH, Tile.WATER, 
                             Tile.CAMPFIRE_OFF, Tile.CAMPFIRE_ON, Tile.TALL_GRASS):
                        return (nx, ny, t)
        # 检查当前脚下
        t = self._get_tile_at(px, py)
        if t in (Tile.WATER, Tile.DIRT):
            return (px, py, t)
        return None

    def _update_explored(self):
        px, py = self.player.x, self.player.y
        radius = 7 if not self.is_night else 4
        for dy in range(-radius, radius+1):
            for dx in range(-radius, radius+1):
                if dx*dx + dy*dy <= radius*radius:
                    nx, ny = px+dx, py+dy
                    if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                        self.explored[ny][nx] = True

    # ─── 相机 ───────────────────────────────────
    def update_camera(self):
        target_cx = self.player.px - WINDOW_W // 2
        target_cy = self.player.py - (WINDOW_H - 80) // 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 - WINDOW_W, self.cam_x))
        self.cam_y = max(0, min(MAP_H * TILE - (WINDOW_H - 80), self.cam_y))

    # ─── 移动 ───────────────────────────────────
    def update_movement(self):
        keys = pygame.key.get_pressed()
        speed = self.player.get_speed()

        if self.player.move_cooldown > 0:
            self.player.move_cooldown -= 1
            return

        dx, dy = 0, 0
        if keys[pygame.K_w] or keys[pygame.K_UP]:
            dy = -speed
        if keys[pygame.K_s] or keys[pygame.K_DOWN]:
            dy = speed
        if keys[pygame.K_a] or keys[pygame.K_LEFT]:
            dx = -speed
        if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
            dx = speed

        if dx != 0 or dy != 0:
            # 对角线归一化
            if dx != 0 and dy != 0:
                dx *= 0.707
                dy *= 0.707

            new_px = self.player.px + dx
            new_py = self.player.py + dy

            # 碰撞检测
            tx = int(new_px // TILE)
            ty = int(new_py // TILE)

            if 0 <= tx < MAP_W and 0 <= ty < MAP_H:
                t = self.tile_map[ty][tx]
                blocked = t in (Tile.TREE, Tile.ROCK, Tile.WATER, Tile.DEEP_WATER, Tile.WALL)

                if not blocked:
                    self.player.px = new_px
                    self.player.py = new_py

                    # 深水检测
                    if t == Tile.DEEP_WATER:
                        self.player.thirst = min(100, self.player.thirst + 1)

                    # 体力消耗
                    if self.frame % 120 == 0:
                        self.player.stamina = max(0, self.player.stamina - 0.5)

                    old_x, old_y = self.player.x, self.player.y
                    self.player.x = tx
                    self.player.y = ty

                    if old_x != tx or old_y != ty:
                        self.player.steps_walked += 1
                        self._update_explored()

    # ─── 互动 ───────────────────────────────────
    def interact(self):
        target = self._get_nearby_interactable()
        if not target:
            # 检查是否有可拾取的
            self._check_pickup()
            return

        tx, ty, tile = target

        if tile == Tile.TREE:
            # 砍树
            if self.player.stamina < 10:
                self._log("体力不足!", C_RED)
                return
            self.player.stamina -= 10
            amount = 2
            if self.player.weapon == 'stone_axe':
                amount = 4
            self.player.inventory['wood'] = self.player.inventory.get('wood', 0) + amount
            if random.random() < 0.3:
                self.player.inventory['fiber'] = self.player.inventory.get('fiber', 0) + 1
            self.tile_map[ty][tx] = Tile.GRASS
            self._log(f"获得 木材x{amount}", C_GREEN)

        elif tile == Tile.ROCK:
            if self.player.stamina < 8:
                self._log("体力不足!", C_RED)
                return
            self.player.stamina -= 8
            amount = 2
            if self.player.weapon == 'stone_axe':
                amount = 3
            self.player.inventory['stone'] = self.player.inventory.get('stone', 0) + amount
            self.tile_map[ty][tx] = Tile.DIRT
            self._log(f"获得 石头x{amount}", C_GREEN)

        elif tile == Tile.BUSH:
            if random.random() < 0.5:
                self._add_food_item('berries', random.randint(1, 3))
                self._log("获得 浆果", C_GREEN)
            elif random.random() < 0.3:
                self._add_food_item('herb', 1)
                self._log("获得 草药", C_GREEN)
            else:
                self._add_food_item('mushroom', 1)
                self._log("获得 蘑菇", C_GREEN)
            self.tile_map[ty][tx] = Tile.GRASS
            self.player.stamina = max(0, self.player.stamina - 3)

        elif tile == Tile.WATER:
            self.player.inventory['dirty_water'] = self.player.inventory.get('dirty_water', 0) + 1
            self._log("获得 脏水 (需要煮沸!)", C_ORANGE)

        elif tile == Tile.TALL_GRASS:
            self.player.inventory['fiber'] = self.player.inventory.get('fiber', 0) + random.randint(1, 2)
            self._log("获得 纤维", C_GREEN)
            self.tile_map[ty][tx] = Tile.GRASS

        elif tile == Tile.CAMPFIRE_OFF:
            # 点燃营火
            if self.player.inventory.get('wood', 0) >= 1:
                self.player.inventory['wood'] -= 1
                if self.player.inventory['wood'] <= 0:
                    del self.player.inventory['wood']
                self.tile_map[ty][tx] = Tile.CAMPFIRE_ON
                self._log("营火已点燃!", C_ORANGE)
            else:
                self._log("需要木材来点燃", C_RED)

        elif tile == Tile.CAMPFIRE_ON:
            # 使用营火: 净水/煮食
            if self.player.inventory.get('dirty_water', 0) > 0:
                self.player.inventory['dirty_water'] -= 1
                if self.player.inventory['dirty_water'] <= 0:
                    del self.player.inventory['dirty_water']
                self._add_food_item('clean_water')
                self._log("脏水已煮沸 → 净水!", C_GREEN)
            elif self.player.inventory.get('raw_meat', 0) > 0:
                self.player.inventory['raw_meat'] -= 1
                if self.player.inventory['raw_meat'] <= 0:
                    del self.player.inventory['raw_meat']
                self._add_food_item('cooked_meat')
                self._log("生肉已烤熟!", C_GREEN)
            elif self.player.inventory.get('raw_fish', 0) > 0:
                self.player.inventory['raw_fish'] -= 1
                if self.player.inventory['raw_fish'] <= 0:
                    del self.player.inventory['raw_fish']
                self._add_food_item('cooked_fish')
                self._log("生鱼已烤熟!", C_GREEN)
            else:
                self._log("没有可烹饪的物品", C_GRAY)

    def _check_pickup(self):
        self._log("附近没有可互动的物体", C_GRAY)

    # ─── 战斗 ───────────────────────────────────
    def start_combat(self, beast):
        self.mode = GameMode.COMBAT
        self.combat_beast = beast
        self.combat_log = [f"遭遇了 {beast.data['name']}!"]
        self.combat_player_turn = True
        if self.is_night:
            self.combat_log.append("夜间野兽更加凶猛!")

    def combat_attack(self):
        if not self.combat_player_turn or not self.combat_beast:
            return
        b = self.combat_beast
        p = self.player

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

        dmg = max(1, atk - b.data['def'] // 2)
        b.hp -= dmg
        p.total_damage_dealt += dmg

        msg = f"你攻击了{b.data['name']}，造成{dmg}点伤害"
        if crit:
            msg += " (暴击!)"
        self.combat_log.append(msg)

        if b.hp <= 0:
            # 击杀
            b.alive = False
            p.beasts_killed += 1
            p.add_xp(b.data['xp'])
            self.combat_log.append(f"击杀了{b.data['name']}! +{b.data['xp']}XP")
            # 掉落
            for item, count in b.data['drop']:
                self._add_food_item(item, count)
                self.combat_log.append(f"获得 {ITEMS[item][0]}x{count}")
            self.mode = GameMode.WORLD
            self._log(f"击杀了{b.data['name']}!", C_GREEN)
            return

        # 野兽反击
        self._beast_attack_in_combat()

    def _beast_attack_in_combat(self):
        b = self.combat_beast
        p = self.player

        night_mult = 1.3 if self.is_night else 1.0
        atk = int(b.atk * night_mult)

        dead = p.take_damage(atk)

        # 找到受伤部位
        weights = list(HIT_WEIGHTS.values())
        parts = list(HIT_WEIGHTS.keys())
        hit_part = random.choices(parts, weights=weights, k=1)[0]
        bp = p.body_parts[hit_part]
        actual_dmg = max(1, atk - p.get_defense() // 2)

        self.combat_log.append(f"{b.data['name']}攻击了你的{hit_part.value}，造成{actual_dmg}点伤害")

        if bp['bleeding']:
            self.combat_log.append(f"{hit_part.value}在流血!")
        if bp['fractured']:
            self.combat_log.append(f"{hit_part.value}骨折了!")

        # 蛇咬中毒
        if b.btype == 'snake' and random.random() < 0.3:
            p.poisoned = 300  # 5游戏小时
            self.combat_log.append("你中毒了!")

        if dead or not p.is_alive():
            self.combat_log.append("你倒下了...")
            self.mode = GameMode.GAMEOVER
            return

    def combat_flee(self):
        b = self.combat_beast
        p = self.player

        # 逃跑概率受腿部影响
        flee_chance = 40
        for leg in [BodyPart.L_LEG, BodyPart.R_LEG]:
            if p.body_parts[leg]['crippled']:
                flee_chance -= 20
            elif p.body_parts[leg]['fractured']:
                flee_chance -= 10

        if self.is_night:
            flee_chance -= 15

        if random.randint(1, 100) <= flee_chance:
            self.combat_log.append("你成功逃脱了!")
            self.mode = GameMode.WORLD
            self._log("成功逃离了战斗", C_YELLOW)
        else:
            self.combat_log.append("逃跑失败!")
            self._beast_attack_in_combat()

    def combat_heal(self):
        p = self.player
        if p.inventory.get('bandage', 0) > 0:
            # 止血最严重的部位
            worst = None
            worst_hp = 999
            for part, bp in p.body_parts.items():
                if bp['bleeding'] and bp['hp'] < worst_hp:
                    worst = part
                    worst_hp = bp['hp']
            if worst:
                p.body_parts[worst]['bleeding'] = False
                p.heal_part(worst, 15)
                p.inventory['bandage'] -= 1
                if p.inventory['bandage'] <= 0:
                    del p.inventory['bandage']
                self.combat_log.append(f"使用绷带治疗了{worst.value}")
            else:
                self.combat_log.append("没有流血的伤口")
        elif p.inventory.get('herb', 0) > 0:
            # 草药回血
            for part in p.body_parts:
                p.heal_part(part, 5)
            p.inventory['herb'] -= 1
            if p.inventory['herb'] <= 0:
                del p.inventory['herb']
            self.combat_log.append("使用草药恢复了少量HP")
        else:
            self.combat_log.append("没有可用的医疗物品")

    # ─── 制作 ───────────────────────────────────
    def craft_item(self, idx):
        if idx < 0 or idx >= len(RECIPES):
            return
        item_id, req, cat, desc = RECIPES[idx]

        if not self.player.has_items(req):
            self._log("材料不足!", C_RED)
            return

        self.player.consume_items(req)

        if cat == '武器':
            self.player.weapon = item_id
            self._log(f"制作并装备了 {ITEMS[item_id][0]}", C_GREEN)
        elif cat == '防具':
            self.player.armor = item_id
            self._log(f"制作并穿上了 {ITEMS[item_id][0]}", C_GREEN)
        elif cat == '工具' and item_id == 'water_filter':
            # 净水器：转换所有脏水
            dirty = self.player.inventory.get('dirty_water', 0)
            if dirty > 0:
                self.player.inventory['dirty_water'] = 0
                del self.player.inventory['dirty_water']
                self._add_food_item('clean_water', dirty)
                self._log(f"净水器过滤了{dirty}份脏水", C_GREEN)
            else:
                self.player.inventory[item_id] = self.player.inventory.get(item_id, 0) + 1
                self._log(f"制作了 {ITEMS[item_id][0]}", C_GREEN)
        else:
            self.player.inventory[item_id] = self.player.inventory.get(item_id, 0) + 1
            self._log(f"制作了 {ITEMS[item_id][0]}", C_GREEN)

    # ─── 建造 ───────────────────────────────────
    BUILD_OPTIONS = [
        ('campfire', '营火', {'wood': 5, 'stone': 3}, '提供温暖、烹饪、照明'),
        ('shelter', '庇护所', {'wood': 15, 'fiber': 8, 'stone': 5}, '遮风挡雨、恢复体力'),
        ('wall', '石墙', {'stone': 8, 'wood': 2}, '阻挡野兽'),
        ('trap_place', '放置陷阱', {'trap': 1}, '自动捕获小型猎物'),
    ]

    def build_item(self, idx):
        if idx < 0 or idx >= len(self.BUILD_OPTIONS):
            return
        bid, name, req, desc = self.BUILD_OPTIONS[idx]

        if not self.player.has_items(req):
            self._log("材料不足!", C_RED)
            return

        px, py = self.player.x, self.player.y
        # 找附近的空地
        placed = False
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                nx, ny = px+dx, py+dy
                if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
                    if self.tile_map[ny][nx] == Tile.GRASS or self.tile_map[ny][nx] == Tile.DIRT:
                        if bid == 'campfire':
                            self.tile_map[ny][nx] = Tile.CAMPFIRE_OFF
                            placed = True
                        elif bid == 'shelter':
                            self.tile_map[ny][nx] = Tile.SHELTER
                            placed = True
                        elif bid == 'wall':
                            self.tile_map[ny][nx] = Tile.WALL
                            placed = True
                        elif bid == 'trap_place':
                            self.traps.append(Trap(nx, ny))
                            placed = True
                        if placed:
                            break
            if placed:
                break

        if placed:
            self.player.consume_items(req)
            self._log(f"建造了 {name}!", C_GREEN)
        else:
            self._log("附近没有可建造的空地", C_RED)

    # ─── 进食 ───────────────────────────────────
    def eat_item(self, item_id):
        if item_id not in FOOD_DATA:
            return
        if self.player.inventory.get(item_id, 0) <= 0:
            return

        fd = FOOD_DATA[item_id]
        hunger, thirst, hp, mental, _, _ = fd

        self.player.hunger = min(100, self.player.hunger + hunger)
        self.player.thirst = min(100, self.player.thirst + thirst)
        if hp > 0:
            for part in self.player.body_parts:
                self.player.heal_part(part, hp // 6 + 1)
        elif hp < 0:
            self.player.take_damage(abs(hp), BodyPart.TORSO)
        self.player.mental = min(100, self.player.mental + mental)

        self.player.inventory[item_id] -= 1
        if self.player.inventory[item_id] <= 0:
            del self.player.inventory[item_id]

        self._log(f"食用了 {ITEMS[item_id][0]}  饱食+{hunger} 水分+{thirst}", C_GREEN)

        # 脏水风险
        if item_id == 'dirty_water':
            if random.random() < 0.30:
                self.player.poisoned = 180
                self.player.sick = 600
                self.player.disease_name = "水中毒"
                self._log("脏水让你生病了!", C_RED)

        # 生食风险
        if item_id in ('raw_meat', 'raw_fish') and random.random() < 0.15:
            self.player.sick = 480
            self.player.disease_name = "食物中毒"
            self._log("生食让你生病了!", C_RED)

    # ─── 治疗 ───────────────────────────────────
    def heal_action(self, idx):
        """治疗选项"""
        p = self.player
        heal_options = self._get_heal_options()
        if idx < 0 or idx >= len(heal_options):
            return

        action, part, item = heal_options[idx]

        if action == 'bandage':
            p.inventory['bandage'] -= 1
            if p.inventory['bandage'] <= 0:
                del p.inventory['bandage']
            p.body_parts[part]['bleeding'] = False
            p.heal_part(part, 20)
            self._log(f"绷带止住了{part.value}的出血", C_GREEN)

        elif action == 'splint':
            p.inventory['splint'] -= 1
            if p.inventory['splint'] <= 0:
                del p.inventory['splint']
            p.body_parts[part]['fractured'] = False
            p.heal_part(part, 10)
            self._log(f"夹板固定了{part.value}的骨折", C_GREEN)

        elif action == 'antibiotic':
            p.inventory['antibiotic'] -= 1
            if p.inventory['antibiotic'] <= 0:
                del p.inventory['antibiotic']
            for bp in p.body_parts.values():
                bp['infected'] = False
            p.sick = 0
            p.disease_name = ""
            self._log("抗生素治疗了感染和疾病", C_GREEN)

        elif action == 'herb':
            p.inventory['herb'] -= 1
            if p.inventory['herb'] <= 0:
                del p.inventory['herb']
            for bp_name in p.body_parts:
                p.heal_part(bp_name, 8)
            self._log("草药恢复了少量生命值", C_GREEN)

    def _get_heal_options(self):
        opts = []
        p = self.player
        # 止血
        for part, bp in p.body_parts.items():
            if bp['bleeding'] and p.inventory.get('bandage', 0) > 0:
                opts.append(('bandage', part, 'bandage'))
        # 固定骨折
        for part, bp in p.body_parts.items():
            if bp['fractured'] and p.inventory.get('splint', 0) > 0:
                opts.append(('splint', part, 'splint'))
        # 抗生素
        if p.inventory.get('antibiotic', 0) > 0:
            has_infection = any(bp['infected'] for bp in p.body_parts.values())
            if has_infection or p.sick > 0:
                opts.append(('antibiotic', None, 'antibiotic'))
        # 草药回血
        if p.inventory.get('herb', 0) > 0:
            opts.append(('herb', None, 'herb'))
        return opts

    # ─── 主更新 ─────────────────────────────────
    def update(self):
        if self.mode == GameMode.GAMEOVER:
            return
        if self.mode == GameMode.PAUSE:
            return
        if self.mode == GameMode.WORLD:
            self.update_time()
            self.update_movement()
            self.update_survival()
            self.update_camera()
            self._update_beasts()
            self._check_interact_hint()

            # 死亡检查
            if not self.player.is_alive():
                self.mode = GameMode.GAMEOVER

    def _update_beasts(self):
        # 生成新野兽
        self.beast_spawn_timer += 1
        if self.beast_spawn_timer > 300 and len([b for b in self.beasts if b.alive]) < 15:
            self._spawn_beast()
            self.beast_spawn_timer = 0

        for beast in self.beasts:
            if not beast.alive:
                continue
            attacked = beast.update(self.player, self.tile_map, self.game_hour, self.is_night)
            if attacked:
                self.start_combat(beast)
                return

        # 清理死亡野兽
        self.beasts = [b for b in self.beasts if b.alive or random.random() < 0.99]

    def _check_interact_hint(self):
        target = self._get_nearby_interactable()
        if target:
            tx, ty, tile = target
            hints = {
                Tile.TREE: "[E] 砍树",
                Tile.ROCK: "[E] 采矿",
                Tile.BUSH: "[E] 采集",
                Tile.WATER: "[E] 取水",
                Tile.CAMPFIRE_OFF: "[E] 点燃",
                Tile.CAMPFIRE_ON: "[E] 烹饪",
                Tile.TALL_GRASS: "[E] 采集纤维",
            }
            self.interact_hint = hints.get(tile, "")
            self.interact_target = target
        else:
            self.interact_hint = ""
            self.interact_target = None

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

        if self.mode == GameMode.WORLD:
            self._render_world()
            self._render_hud()
            self._render_messages()
        elif self.mode == GameMode.COMBAT:
            self._render_combat()
        elif self.mode == GameMode.INVENTORY:
            self._render_world()
            self._render_hud()
            self._render_inventory()
        elif self.mode == GameMode.CRAFT:
            self._render_world()
            self._render_hud()
            self._render_craft()
        elif self.mode == GameMode.BUILD:
            self._render_world()
            self._render_hud()
            self._render_build()
        elif self.mode == GameMode.STATUS:
            self._render_status()
        elif self.mode == GameMode.EAT:
            self._render_world()
            self._render_hud()
            self._render_eat()
        elif self.mode == GameMode.HEAL:
            self._render_world()
            self._render_hud()
            self._render_heal()
        elif self.mode == GameMode.GAMEOVER:
            self._render_gameover()
        elif self.mode == GameMode.HELP:
            self._render_help()

        # 夜间覆盖
        tint = self.get_sky_tint()
        if tint and self.mode in (GameMode.WORLD, GameMode.INVENTORY, GameMode.CRAFT, 
                                   GameMode.BUILD, GameMode.EAT, GameMode.HEAL):
            tint_surf = pygame.Surface((WINDOW_W, WINDOW_H), pygame.SRCALPHA)
            tint_surf.fill(tint)
            # 营火/火把周围减暗效果减弱
            if self._near_campfire() or self.player.inventory.get('torch', 0) > 0:
                # 中心区域透明
                cx, cy = WINDOW_W // 2, (WINDOW_H - 80) // 2
                light_surf = pygame.Surface((WINDOW_W, WINDOW_H), pygame.SRCALPHA)
                pygame.draw.circle(light_surf, (0, 0, 0, 180), (cx, cy), 180)
                tint_surf.blit(light_surf, (0, 0), special_flags=pygame.BLEND_RGBA_SUB)
            self.screen.blit(tint_surf, (0, 0))

        # 幻觉效果
        if self.player.mental < 15:
            if self.frame % 30 < 5:
                purple = pygame.Surface((WINDOW_W, WINDOW_H), pygame.SRCALPHA)
                purple.fill((100, 0, 150, 40))
                self.screen.blit(purple, (0, 0))

        # 天气粒子
        if self.mode in (GameMode.WORLD, GameMode.INVENTORY, GameMode.CRAFT, 
                         GameMode.BUILD, GameMode.EAT, GameMode.HEAL):
            self._render_weather()

        pygame.display.flip()

    def _render_world(self):
        """渲染2D地图"""
        # 计算可见范围
        start_tx = max(0, int(self.cam_x // TILE) - 1)
        start_ty = max(0, int(self.cam_y // TILE) - 1)
        end_tx = min(MAP_W, start_tx + WINDOW_W // TILE + 3)
        end_ty = min(MAP_H, start_ty + (WINDOW_H - 80) // TILE + 3)

        for ty in range(start_ty, end_ty):
            for tx in range(start_tx, end_tx):
                if not self.explored[ty][tx]:
                    # 未探索区域
                    sx = tx * TILE - int(self.cam_x)
                    sy = ty * TILE - int(self.cam_y)
                    pygame.draw.rect(self.screen, (20, 20, 25), (sx, sy, TILE, TILE))
                    continue

                tile = self.tile_map[ty][tx]
                sx = tx * TILE - int(self.cam_x)
                sy = ty * TILE - int(self.cam_y)

                # 地形变化
                variation = ((tx * 7 + ty * 13) % 5) * 3

                if tile == Tile.GRASS:
                    c = (90 + variation, 160 + variation, 70)
                    pygame.draw.rect(self.screen, c, (sx, sy, TILE, TILE))
                elif tile == Tile.TREE:
                    # 树干
                    pygame.draw.rect(self.screen, TILE_COLORS['grass'], (sx, sy, TILE, TILE))
                    pygame.draw.rect(self.screen, TILE_COLORS['tree_trunk'], (sx+12, sy+16, 8, 16))
                    # 树冠
                    color = TILE_COLORS['tree']
                    if self.season == Season.AUTUMN:
                        color = (180, 120, 40)
                    elif self.season == Season.WINTER:
                        color = (100, 120, 100)
                    pygame.draw.circle(self.screen, color, (sx+16, sy+10), 12)
                elif tile == Tile.WATER:
                    wave = int(math.sin(self.frame * 0.03 + tx + ty) * 10)
                    c = (50 + wave, 120 + wave, 200)
                    pygame.draw.rect(self.screen, c, (sx, sy, TILE, TILE))
                elif tile == Tile.DEEP_WATER:
                    wave = int(math.sin(self.frame * 0.02 + tx + ty) * 8)
                    c = (30 + wave, 80 + wave, 160)
                    pygame.draw.rect(self.screen, c, (sx, sy, TILE, TILE))
                elif tile == Tile.ROCK:
                    pygame.draw.rect(self.screen, TILE_COLORS['grass'], (sx, sy, TILE, TILE))
                    pygame.draw.polygon(self.screen, TILE_COLORS['rock'], 
                                       [(sx+4, sy+28), (sx+16, sy+4), (sx+28, sy+28)])
                    pygame.draw.polygon(self.screen, TILE_COLORS['rock_dark'], 
                                       [(sx+10, sy+28), (sx+20, sy+10), (sx+28, sy+28)])
                elif tile == Tile.DIRT:
                    c = (160 + variation, 130 + variation, 90)
                    pygame.draw.rect(self.screen, c, (sx, sy, TILE, TILE))
                elif tile == Tile.BUSH:
                    pygame.draw.rect(self.screen, TILE_COLORS['grass'], (sx, sy, TILE, TILE))
                    pygame.draw.circle(self.screen, TILE_COLORS['bush'], (sx+16, sy+18), 10)
                    # 小浆果
                    for dx, dy in [(8,14),(22,16),(14,22),(20,10)]:
                        pygame.draw.circle(self.screen, (180, 40, 60), (sx+dx, sy+dy), 2)
                elif tile == Tile.TALL_GRASS:
                    c = (70 + variation, 140 + variation, 55)
                    pygame.draw.rect(self.screen, c, (sx, sy, TILE, TILE))
                    # 草叶
                    for i in range(4):
                        gx = sx + 4 + i * 8
                        pygame.draw.line(self.screen, (50, 130, 40), (gx, sy+28), (gx+2, sy+8), 2)
                elif tile == Tile.SAND:
                    c = (210 + variation, 190 + variation, 140)
                    pygame.draw.rect(self.screen, c, (sx, sy, TILE, TILE))
                elif tile == Tile.CAMPFIRE_OFF:
                    pygame.draw.rect(self.screen, TILE_COLORS['grass'], (sx, sy, TILE, TILE))
                    pygame.draw.circle(self.screen, (80, 60, 40), (sx+16, sy+18), 8)
                    pygame.draw.circle(self.screen, (100, 70, 40), (sx+16, sy+16), 5)
                elif tile == Tile.CAMPFIRE_ON:
                    pygame.draw.rect(self.screen, TILE_COLORS['grass'], (sx, sy, TILE, TILE))
                    # 火焰动画
                    flicker = math.sin(self.frame * 0.15) * 3
                    pygame.draw.circle(self.screen, (80, 50, 30), (sx+16, sy+20), 8)
                    pygame.draw.circle(self.screen, (230, 140, 40), (sx+16, sy+16 + int(flicker)), 7)
                    pygame.draw.circle(self.screen, (255, 200, 60), (sx+16, sy+14 + int(flicker)), 4)
                    # 光照
                    light = pygame.Surface((TILE*3, TILE*3), pygame.SRCALPHA)
                    pygame.draw.circle(light, (255, 180, 60, 30), (TILE*3//2, TILE*3//2), TILE*3//2)
                    self.screen.blit(light, (sx - TILE, sy - TILE), special_flags=pygame.BLEND_RGBA_ADD)
                elif tile == Tile.SHELTER:
                    pygame.draw.rect(self.screen, TILE_COLORS['grass'], (sx, sy, TILE, TILE))
                    # 小屋
                    pygame.draw.rect(self.screen, (100, 70, 40), (sx+2, sy+8, 28, 22))
                    pygame.draw.polygon(self.screen, (140, 90, 50), 
                                       [(sx, sy+10), (sx+16, sy), (sx+32, sy+10)])
                    pygame.draw.rect(self.screen, (80, 60, 35), (sx+12, sy+18, 8, 12))
                elif tile == Tile.WALL:
                    pygame.draw.rect(self.screen, (110, 100, 90), (sx, sy, TILE, TILE))
                    pygame.draw.rect(self.screen, (90, 80, 70), (sx+1, sy+1, TILE-2, TILE-2), 2)
                    pygame.draw.line(self.screen, (70, 60, 50), (sx, sy+16), (sx+TILE, sy+16), 1)

        # 渲染陷阱
        for trap in self.traps:
            sx = trap.x * TILE - int(self.cam_x)
            sy = trap.y * TILE - int(self.cam_y)
            if 0 <= sx < WINDOW_W and 0 <= sy < WINDOW_H - 80:
                if trap.active:
                    pygame.draw.rect(self.screen, (130, 110, 70), (sx+8, sy+8, 16, 16), 2)
                    pygame.draw.line(self.screen, (130, 110, 70), (sx+8, sy+8), (sx+24, sy+24), 1)
                    pygame.draw.line(self.screen, (130, 110, 70), (sx+24, sy+8), (sx+8, sy+24), 1)

        # 渲染野兽
        for beast in self.beasts:
            if not beast.alive:
                continue
            bsx = int(beast.px - int(self.cam_x))
            bsy = int(beast.py - int(self.cam_y))
            if -TILE < bsx < WINDOW_W + TILE and -TILE < bsy < WINDOW_H - 80 + TILE:
                btx, bty = int(beast.px // TILE), int(beast.py // TILE)
                if 0 <= btx < MAP_W and 0 <= bty < MAP_H and self.explored[bty][btx]:
                    color = beast.data['color']
                    size = 10 if beast.btype in ('rabbit', 'snake') else 14
                    pygame.draw.circle(self.screen, color, (bsx, bsy), size)
                    # 眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255), (bsx-3, bsy-3), 2)
                    pygame.draw.circle(self.screen, (255, 255, 255), (bsx+3, bsy-3), 2)
                    pygame.draw.circle(self.screen, C_BLACK, (bsx-3, bsy-3), 1)
                    pygame.draw.circle(self.screen, C_BLACK, (bsx+3, bsy-3), 1)
                    # 血条
                    if beast.hp < beast.max_hp:
                        bar_w = 24
                        hp_ratio = beast.hp / beast.max_hp
                        pygame.draw.rect(self.screen, (60, 0, 0), (bsx - bar_w//2, bsy - size - 6, bar_w, 3))
                        pygame.draw.rect(self.screen, C_RED, (bsx - bar_w//2, bsy - size - 6, int(bar_w * hp_ratio), 3))
                    # 名字
                    name_surf = self.font_sm.render(beast.data['name'], True, C_WHITE)
                    self.screen.blit(name_surf, (bsx - name_surf.get_width()//2, bsy - size - 18))

        # 渲染玩家
        psx = int(self.player.px - int(self.cam_x))
        psy = int(self.player.py - int(self.cam_y))
        # 玩家身体
        pygame.draw.circle(self.screen, (220, 190, 150), (psx, psy - 8), 8)  # 头
        pygame.draw.rect(self.screen, (60, 100, 180), (psx - 6, psy, 12, 14))  # 身体
        pygame.draw.rect(self.screen, (80, 60, 40), (psx - 5, psy + 14, 4, 10))  # 左腿
        pygame.draw.rect(self.screen, (80, 60, 40), (psx + 1, psy + 14, 4, 10))  # 右腿

        # 装备显示
        if self.player.weapon:
            pygame.draw.line(self.screen, (180, 160, 120), (psx + 8, psy + 2), (psx + 18, psy - 6), 2)
        if self.player.armor:
            armor_color = (140, 100, 60) if self.player.armor == 'leather_armor' else (160, 165, 170)
            pygame.draw.rect(self.screen, armor_color, (psx - 7, psy + 1, 14, 12), 1)

        # 互动提示
        if self.interact_hint:
            hint_surf = self.font_md.render(self.interact_hint, True, C_YELLOW)
            hx = psx - hint_surf.get_width() // 2
            hy = psy - 40
            bg = pygame.Surface((hint_surf.get_width() + 8, hint_surf.get_height() + 4), pygame.SRCALPHA)
            bg.fill((0, 0, 0, 150))
            self.screen.blit(bg, (hx - 4, hy - 2))
            self.screen.blit(hint_surf, (hx, hy))

    def _render_weather(self):
        for p in self.weather_particles:
            p.update()
            if p.ptype == 'rain':
                pygame.draw.line(self.screen, (150, 180, 255, 180), 
                               (int(p.x), int(p.y)), (int(p.x + p.wind_x * 2), int(p.y + 8)), 1)
            elif p.ptype == 'snow':
                pygame.draw.circle(self.screen, (240, 245, 255), (int(p.x), int(p.y)), int(p.size))
            elif p.ptype == 'wind':
                pygame.draw.line(self.screen, (200, 200, 200, 100),
                               (int(p.x), int(p.y)), (int(p.x + 12), int(p.y)), 1)

    def _render_hud(self):
        """底部HUD"""
        hud_y = WINDOW_H - 78
        pygame.draw.rect(self.screen, (20, 20, 25), (0, hud_y, WINDOW_W, 78))
        pygame.draw.line(self.screen, (60, 60, 70), (0, hud_y), (WINDOW_W, hud_y), 2)

        p = self.player
        y = hud_y + 4

        # 第一行：状态条
        bars = [
            ("HP", p.body_parts[BodyPart.TORSO]['hp'], p.body_parts[BodyPart.TORSO]['max_hp'], C_RED),
            ("饱食", p.hunger, 100, C_ORANGE),
            ("水分", p.thirst, 100, C_BLUE),
            ("体力", p.stamina, 100, C_YELLOW),
            ("精神", p.mental, 100, (160, 80, 200)),
        ]

        bx = 8
        for label, val, max_val, color in bars:
            # 标签
            lbl = self.font_sm.render(f"{label}", True, C_WHITE)
            self.screen.blit(lbl, (bx, y))
            # 条
            bar_x = bx + 30
            bar_w = 80
            pygame.draw.rect(self.screen, (40, 40, 40), (bar_x, y + 2, bar_w, 10))
            fill = int(bar_w * max(0, val) / max(1, max_val))
            pygame.draw.rect(self.screen, color, (bar_x, y + 2, fill, 10))
            # 数值
            val_surf = self.font_sm.render(f"{int(val)}", True, C_WHITE)
            self.screen.blit(val_surf, (bar_x + bar_w + 4, y))
            bx += 130

        # 体温
        temp_color = C_WHITE
        if p.body_temp < 35:
            temp_color = (100, 180, 255)
        elif p.body_temp > 38:
            temp_color = (255, 100, 80)
        temp_surf = self.font_sm.render(f"体温:{p.body_temp:.1f}°C", True, temp_color)
        self.screen.blit(temp_surf, (bx + 10, y))

        # 第二行：时间和信息
        y += 18
        hour = int(self.game_hour)
        minute = self.game_minute % 60
        time_str = f"第{self.game_day}天 {hour:02d}:{minute:02d}"
        time_surf = self.font_sm.render(time_str, True, C_WHITE)
        self.screen.blit(time_surf, (8, y))

        # 季节
        season_color = {Season.SPRING: (100, 200, 100), Season.SUMMER: (255, 200, 50), 
                        Season.AUTUMN: (230, 150, 50), Season.WINTER: (150, 200, 255)}
        season_surf = self.font_sm.render(f"{self.season.value}季", True, season_color[self.season])
        self.screen.blit(season_surf, (110, y))

        # 天气
        weather_surf = self.font_sm.render(f"天气:{self.weather.value}", True, (180, 200, 220))
        self.screen.blit(weather_surf, (170, y))

        # 等级
        lv_surf = self.font_sm.render(f"Lv.{p.level} XP:{p.xp}/{p.xp_next}", True, C_YELLOW)
        self.screen.blit(lv_surf, (270, y))

        # 装备
        wpn = ITEMS[p.weapon][0] if p.weapon else "空手"
        arm = ITEMS[p.armor][0] if p.armor else "无"
        equip_surf = self.font_sm.render(f"武器:{wpn} 防具:{arm}", True, (180, 180, 180))
        self.screen.blit(equip_surf, (420, y))

        # 状态效果
        effects = []
        if p.poisoned > 0: effects.append("☠毒")
        if p.sick > 0: effects.append("🤒病")
        for part, bp in p.body_parts.items():
            if bp['bleeding']: effects.append(f"🩸{part.value}")
            if bp['fractured']: effects.append(f"🦴{part.value}")
            if bp['infected']: effects.append(f"🦠{part.value}")
            if bp['frostbite']: effects.append(f"🥶{part.value}")
            if bp['crippled']: effects.append(f"💀{part.value}")
        if effects:
            eff_str = " ".join(effects[:6])
            eff_surf = self.font_sm.render(eff_str, True, C_RED)
            self.screen.blit(eff_surf, (8, y + 16))

        # 操作提示
        help_text = "1-背包 2-制作 3-建造 4-进食 5-治疗 6-状态 7-帮助 ESC-暂停"
        help_surf = self.font_sm.render(help_text, True, (120, 120, 130))
        self.screen.blit(help_surf, (WINDOW_W - help_surf.get_width() - 10, y + 16))

        # 右上角：人体模型
        self._render_body_model(WINDOW_W - 100, 10)

    def _render_body_model(self, bx, by):
        """渲染人体模型"""
        # 背景
        bg = pygame.Surface((90, 100), pygame.SRCALPHA)
        bg.fill((0, 0, 0, 120))
        self.screen.blit(bg, (bx, by))

        cx = bx + 45
        cy = by + 35

        for part, data in BODY_PART_DATA.items():
            bp = self.player.body_parts[part]
            ratio = bp['hp'] / bp['max_hp'] if bp['max_hp'] > 0 else 0

            if bp['crippled']:
                color = (60, 60, 60)
            elif bp['infected']:
                color = (150, 80, 50)
            elif bp['bleeding']:
                color = (200, 50, 50)
            elif bp['fractured']:
                color = (200, 150, 50)
            elif bp['frostbite']:
                color = (100, 150, 220)
            elif ratio > 0.7:
                color = (80, 180, 80)
            elif ratio > 0.4:
                color = (200, 180, 50)
            else:
                color = (200, 80, 50)

            px, py = data['pos']
            w, h = data['size']
            pygame.draw.rect(self.screen, color, (cx + px - w//2, cy + py - h//2, w, h))
            pygame.draw.rect(self.screen, (200, 200, 200), (cx + px - w//2, cy + py - h//2, w, h), 1)

    def _render_messages(self):
        """渲染消息日志"""
        visible_msgs = [m for m in self.messages if self.frame - m[2] < 360]
        y = WINDOW_H - 78 - len(visible_msgs) * 16 - 4
        for msg, color, _ in visible_msgs[-5:]:
            surf = self.font_sm.render(msg, True, color)
            # 背景
            bg = pygame.Surface((surf.get_width() + 8, 16), pygame.SRCALPHA)
            bg.fill((0, 0, 0, 120))
            self.screen.blit(bg, (4, y))
            self.screen.blit(surf, (8, y))
            y += 16

    def _render_combat(self):
        """渲染战斗界面"""
        self.screen.fill((30, 20, 20))

        b = self.combat_beast
        if not b:
            return

        # 标题
        title = self.font_xl.render(f"⚔ 战斗: {b.data['name']}", True, C_RED)
        self.screen.blit(title, (WINDOW_W // 2 - title.get_width() // 2, 20))

        # 野兽信息
        beast_hp_bar_w = 300
        bx = WINDOW_W // 2 - beast_hp_bar_w // 2
        by = 80
        hp_ratio = b.hp / b.max_hp
        pygame.draw.rect(self.screen, (40, 0, 0), (bx, by, beast_hp_bar_w, 20))
        pygame.draw.rect(self.screen, C_RED, (bx, by, int(beast_hp_bar_w * hp_ratio), 20))
        hp_text = self.font_md.render(f"HP: {b.hp}/{b.max_hp}  ATK:{b.atk}", True, C_WHITE)
        self.screen.blit(hp_text, (bx, by + 24))

        # 野兽图像
        beast_color = b.data['color']
        beast_size = 40 if b.btype in ('bear', 'leopard') else 30
        pygame.draw.circle(self.screen, beast_color, (WINDOW_W // 2, 160), beast_size)
        pygame.draw.circle(self.screen, (255, 255, 255), (WINDOW_W // 2 - 10, 150), 6)
        pygame.draw.circle(self.screen, (255, 255, 255), (WINDOW_W // 2 + 10, 150), 6)
        pygame.draw.circle(self.screen, C_BLACK, (WINDOW_W // 2 - 10, 150), 3)
        pygame.draw.circle(self.screen, C_BLACK, (WINDOW_W // 2 + 10, 150), 3)

        # 玩家肢体状态
        px_start = 50
        py_start = 220
        body_title = self.font_md.render("你的身体状态:", True, C_WHITE)
        self.screen.blit(body_title, (px_start, py_start))

        y = py_start + 24
        for part, data in BODY_PART_DATA.items():
            bp = self.player.body_parts[part]
            ratio = bp['hp'] / bp['max_hp']

            status_parts = []
            if bp['crippled']: status_parts.append("残废")
            if bp['bleeding']: status_parts.append("流血")
            if bp['fractured']: status_parts.append("骨折")
            if bp['infected']: status_parts.append("感染")
            if bp['frostbite']: status_parts.append("冻伤")

            color = C_GREEN if ratio > 0.6 else (C_YELLOW if ratio > 0.3 else C_RED)
            if bp['crippled']: color = (80, 80, 80)

            text = f"{part.value}: {bp['hp']}/{bp['max_hp']}"
            if status_parts:
                text += f"  [{'/'.join(status_parts)}]"

            surf = self.font_sm.render(text, True, color)
            self.screen.blit(surf, (px_start + 20, y))
            y += 18

        # 战斗日志
        log_y = 420
        log_title = self.font_md.render("战斗日志:", True, C_YELLOW)
        self.screen.blit(log_title, (50, log_y))
        for i, msg in enumerate(self.combat_log[-8:]):
            surf = self.font_sm.render(msg, True, C_WHITE)
            self.screen.blit(surf, (70, log_y + 22 + i * 18))

        # 操作按钮
        btn_y = WINDOW_H - 60
        btns = [("[A] 攻击", (200, 60, 60)), ("[H] 用药", (60, 180, 60)), ("[F] 逃跑", (60, 60, 200))]
        for i, (text, color) in enumerate(btns):
            bx = WINDOW_W // 2 - 200 + i * 160
            pygame.draw.rect(self.screen, color, (bx, btn_y, 130, 36))
            pygame.draw.rect(self.screen, C_WHITE, (bx, btn_y, 130, 36), 2)
            surf = self.font_md.render(text, True, C_WHITE)
            self.screen.blit(surf, (bx + 15, btn_y + 8))

        # 玩家信息
        p_info = self.font_md.render(f"ATK:{self.player.get_attack()} DEF:{self.player.get_defense()} Lv.{self.player.level}", True, C_YELLOW)
        self.screen.blit(p_info, (WINDOW_W - 250, btn_y + 8))

    def _render_inventory(self):
        """渲染背包"""
        panel_x, panel_y = 100, 40
        panel_w, panel_h = WINDOW_W - 200, WINDOW_H - 160

        # 面板背景
        bg = pygame.Surface((panel_w, panel_h), pygame.SRCALPHA)
        bg.fill((20, 20, 30, 230))
        self.screen.blit(bg, (panel_x, panel_y))
        pygame.draw.rect(self.screen, (100, 100, 120), (panel_x, panel_y, panel_w, panel_h), 2)

        title = self.font_lg.render("📦 背包", True, C_WHITE)
        self.screen.blit(title, (panel_x + 20, panel_y + 10))

        items = list(self.player.inventory.items())
        y = panel_y + 50

        if not items:
            empty = self.font_md.render("背包空空如也...", True, C_GRAY)
            self.screen.blit(empty, (panel_x + 40, y))
            return

        # 分类显示
        categories = {'资源': [], '食物': [], '医疗': [], '武器': [], '防具': [], '工具': []}
        for item_id, count in items:
            if item_id in ITEMS:
                cat = ITEMS[item_id][2]
                if cat in categories:
                    categories[cat].append((item_id, count))

        for cat, cat_items in categories.items():
            if not cat_items:
                continue
            cat_surf = self.font_md.render(f"── {cat} ──", True, C_YELLOW)
            self.screen.blit(cat_surf, (panel_x + 20, y))
            y += 24

            for item_id, count in cat_items:
                name, color, _ = ITEMS[item_id]
                icon = pygame.Surface((12, 12))
                icon.fill(color)
                self.screen.blit(icon, (panel_x + 40, y + 2))

                status = ""
                if item_id in FOOD_DATA and item_id in self.food_timers:
                    current_hour = self.game_day * 24 + self.game_hour
                    rot_hours = FOOD_DATA[item_id][5]
                    remaining = rot_hours - (current_hour - self.food_timers[item_id])
                    if remaining < 24:
                        status = f" ⚠ {int(remaining)}h后腐烂"

                text = f"{name} x{count}{status}"
                surf = self.font_sm.render(text, True, C_WHITE)
                self.screen.blit(surf, (panel_x + 60, y))
                y += 18

            y += 8

        # 关闭提示
        close = self.font_sm.render("[ESC] 关闭背包", True, C_GRAY)
        self.screen.blit(close, (panel_x + panel_w - 150, panel_y + panel_h - 30))

    def _render_craft(self):
        """渲染制作界面"""
        panel_x, panel_y = 80, 30
        panel_w, panel_h = WINDOW_W - 160, WINDOW_H - 140

        bg = pygame.Surface((panel_w, panel_h), pygame.SRCALPHA)
        bg.fill((20, 25, 35, 230))
        self.screen.blit(bg, (panel_x, panel_y))
        pygame.draw.rect(self.screen, (80, 100, 140), (panel_x, panel_y, panel_w, panel_h), 2)

        title = self.font_lg.render("🔨 制作台", True, C_WHITE)
        self.screen.blit(title, (panel_x + 20, panel_y + 10))

        y = panel_y + 50
        visible = RECIPES[self.craft_scroll:self.craft_scroll + 12]

        for i, (item_id, req, cat, desc) in enumerate(visible):
            idx = self.craft_scroll + i
            can_craft = self.player.has_items(req)

            # 背景条
            bar_color = (40, 50, 60) if can_craft else (30, 30, 35)
            pygame.draw.rect(self.screen, bar_color, (panel_x + 10, y, panel_w - 20, 36))

            name, color, _ = ITEMS[item_id]

            # 名称
            name_color = C_WHITE if can_craft else C_GRAY
            name_surf = self.font_md.render(f"{idx+1}. {name} [{cat}]", True, name_color)
            self.screen.blit(name_surf, (panel_x + 20, y + 2))

            # 材料
            mat_parts = []
            for mat, cnt in req.items():
                have = self.player.inventory.get(mat, 0)
                mat_name = ITEMS[mat][0]
                mat_color = C_GREEN if have >= cnt else C_RED
                mat_parts.append(f"{mat_name}:{have}/{cnt}")
            mat_str = "  ".join(mat_parts)
            mat_surf = self.font_sm.render(mat_str, True, C_WHITE if can_craft else C_GRAY)
            self.screen.blit(mat_surf, (panel_x + 20, y + 20))

            # 描述
            desc_surf = self.font_sm.render(desc, True, (150, 150, 160))
            self.screen.blit(desc_surf, (panel_x + panel_w - desc_surf.get_width() - 20, y + 10))

            y += 40

        # 翻页提示
        if len(RECIPES) > 12:
            page_info = self.font_sm.render(f"[↑↓] 翻页  ({self.craft_scroll+1}-{min(self.craft_scroll+12, len(RECIPES))}/{len(RECIPES)})", True, C_GRAY)
            self.screen.blit(page_info, (panel_x + panel_w - 200, panel_y + panel_h - 30))

        close = self.font_sm.render("[ESC] 关闭  [数字键] 制作", True, C_GRAY)
        self.screen.blit(close, (panel_x + 20, panel_y + panel_h - 30))

    def _render_build(self):
        """渲染建造界面"""
        panel_x, panel_y = 150, 100
        panel_w, panel_h = WINDOW_W - 300, WINDOW_H - 250

        bg = pygame.Surface((panel_w, panel_h), pygame.SRCALPHA)
        bg.fill((25, 30, 25, 230))
        self.screen.blit(bg, (panel_x, panel_y))
        pygame.draw.rect(self.screen, (80, 120, 80), (panel_x, panel_y, panel_w, panel_h), 2)

        title = self.font_lg.render("🏗 建造", True, C_WHITE)
        self.screen.blit(title, (panel_x + 20, panel_y + 10))

        y = panel_y + 50
        for i, (bid, name, req, desc) in enumerate(self.BUILD_OPTIONS):
            can_build = self.player.has_items(req)

            bar_color = (40, 50, 40) if can_build else (30, 30, 30)
            pygame.draw.rect(self.screen, bar_color, (panel_x + 10, y, panel_w - 20, 40))

            name_color = C_WHITE if can_build else C_GRAY
            name_surf = self.font_md.render(f"{i+1}. {name}", True, name_color)
            self.screen.blit(name_surf, (panel_x + 20, y + 4))

            mat_parts = []
            for mat, cnt in req.items():
                have = self.player.inventory.get(mat, 0)
                mat_name = ITEMS[mat][0]
                mat_color = "✓" if have >= cnt else "✗"
                mat_parts.append(f"{mat_name}:{have}/{cnt}{mat_color}")
            mat_str = "  ".join(mat_parts)
            mat_surf = self.font_sm.render(mat_str, True, C_WHITE if can_build else C_GRAY)
            self.screen.blit(mat_surf, (panel_x + 20, y + 22))

            desc_surf = self.font_sm.render(desc, True, (140, 160, 140))
            self.screen.blit(desc_surf, (panel_x + panel_w - desc_surf.get_width() - 20, y + 12))

            y += 48

        close = self.font_sm.render("[ESC] 关闭  [数字键] 建造", True, C_GRAY)
        self.screen.blit(close, (panel_x + 20, panel_y + panel_h - 30))

    def _render_eat(self):
        """渲染进食界面"""
        panel_x, panel_y = 150, 80
        panel_w, panel_h = WINDOW_W - 300, WINDOW_H - 200

        bg = pygame.Surface((panel_w, panel_h), pygame.SRCALPHA)
        bg.fill((30, 25, 20, 230))
        self.screen.blit(bg, (panel_x, panel_y))
        pygame.draw.rect(self.screen, (120, 90, 60), (panel_x, panel_y, panel_w, panel_h), 2)

        title = self.font_lg.render("🍖 进食", True, C_WHITE)
        self.screen.blit(title, (panel_x + 20, panel_y + 10))

        y = panel_y + 50
        idx = 0
        for item_id, count in self.player.inventory.items():
            if item_id not in FOOD_DATA:
                continue
            fd = FOOD_DATA[item_id]
            name, color, _ = ITEMS[item_id]

            bar_color = (40, 35, 30)
            pygame.draw.rect(self.screen, bar_color, (panel_x + 10, y, panel_w - 20, 32))

            text = f"{idx+1}. {name} x{count}  (饱食+{fd[0]} 水分+{fd[1]} HP{'+' if fd[2]>=0 else ''}{fd[2]})"
            surf = self.font_sm.render(text, True, C_WHITE)
            self.screen.blit(surf, (panel_x + 20, y + 8))

            y += 36
            idx += 1

        if idx == 0:
            empty = self.font_md.render("没有可食用的物品", True, C_GRAY)
            self.screen.blit(empty, (panel_x + 40, y))

        close = self.font_sm.render("[ESC] 关闭  [数字键] 食用", True, C_GRAY)
        self.screen.blit(close, (panel_x + 20, panel_y + panel_h - 30))

    def _render_heal(self):
        """渲染治疗界面"""
        panel_x, panel_y = 120, 60
        panel_w, panel_h = WINDOW_W - 240, WINDOW_H - 170

        bg = pygame.Surface((panel_w, panel_h), pygame.SRCALPHA)
        bg.fill((25, 20, 30, 230))
        self.screen.blit(bg, (panel_x, panel_y))
        pygame.draw.rect(self.screen, (100, 60, 60), (panel_x, panel_y, panel_w, panel_h), 2)

        title = self.font_lg.render("💊 治疗", True, C_WHITE)
        self.screen.blit(title, (panel_x + 20, panel_y + 10))

        # 身体状态总览
        y = panel_y + 45
        for part, data in BODY_PART_DATA.items():
            bp = self.player.body_parts[part]
            ratio = bp['hp'] / bp['max_hp']

            effects = []
            if bp['crippled']: effects.append("💀残废")
            if bp['bleeding']: effects.append("🩸流血")
            if bp['fractured']: effects.append("🦴骨折")
            if bp['infected']: effects.append("🦠感染")
            if bp['frostbite']: effects.append("🥶冻伤")

            color = C_GREEN if ratio > 0.6 else (C_YELLOW if ratio > 0.3 else C_RED)
            if bp['crippled']: color = (80, 80, 80)

            eff_str = " " + " ".join(effects) if effects else ""
            text = f"{part.value}: {bp['hp']}/{bp['max_hp']}{eff_str}"
            surf = self.font_sm.render(text, True, color)
            self.screen.blit(surf, (panel_x + 20, y))
            y += 18

        y += 10
        heal_title = self.font_md.render("可用治疗:", True, C_YELLOW)
        self.screen.blit(heal_title, (panel_x + 20, y))
        y += 24

        heal_opts = self._get_heal_options()
        if not heal_opts:
            no_heal = self.font_sm.render("没有可用的治疗手段", True, C_GRAY)
            self.screen.blit(no_heal, (panel_x + 40, y))

        for i, (action, part, item) in enumerate(heal_opts):
            if action == 'bandage':
                text = f"{i+1}. 绷带 → 止住{part.value}的出血"
            elif action == 'splint':
                text = f"{i+1}. 夹板 → 固定{part.value}的骨折"
            elif action == 'antibiotic':
                text = f"{i+1}. 抗生素 → 治疗感染和疾病"
            elif action == 'herb':
                text = f"{i+1}. 草药 → 恢复少量HP"
            else:
                text = f"{i+1}. 治疗"
            surf = self.font_sm.render(text, True, C_WHITE)
            self.screen.blit(surf, (panel_x + 40, y))
            y += 20

        close = self.font_sm.render("[ESC] 关闭  [数字键] 治疗", True, C_GRAY)
        self.screen.blit(close, (panel_x + 20, panel_y + panel_h - 30))

    def _render_status(self):
        """渲染详细状态"""
        self.screen.fill((20, 20, 30))

        p = self.player
        title = self.font_xl.render("📊 详细状态", True, C_WHITE)
        self.screen.blit(title, (WINDOW_W // 2 - title.get_width() // 2, 20))

        # 左列：基础属性
        x1, y = 60, 80
        attrs = [
            ("等级", f"Lv.{p.level}  XP:{p.xp}/{p.xp_next}"),
            ("攻击力", str(p.get_attack())),
            ("防御力", str(p.get_defense())),
            ("武器", ITEMS[p.weapon][0] if p.weapon else "空手"),
            ("防具", ITEMS[p.armor][0] if p.armor else "无"),
            ("", ""),
            ("饱食度", f"{int(p.hunger)}/100"),
            ("水分", f"{int(p.thirst)}/100"),
            ("体力", f"{int(p.stamina)}/100"),
            ("精神值", f"{int(p.mental)}/100"),
            ("体温", f"{p.body_temp:.1f}°C"),
            ("", ""),
            ("存活天数", f"第{self.game_day}天"),
            ("击杀野兽", str(p.beasts_killed)),
            ("总伤害", str(p.total_damage_dealt)),
            ("步数", str(p.steps_walked)),
        ]

        for label, val in attrs:
            if label == "":
                y += 10
                continue
            lbl = self.font_md.render(f"{label}:", True, C_GRAY)
            val_s = self.font_md.render(val, True, C_WHITE)
            self.screen.blit(lbl, (x1, y))
            self.screen.blit(val_s, (x1 + 120, y))
            y += 24

        # 右列：肢体状态
        x2 = WINDOW_W // 2 + 40
        y = 80
        limb_title = self.font_lg.render("肢体状态", True, C_WHITE)
        self.screen.blit(limb_title, (x2, y))
        y += 36

        for part, data in BODY_PART_DATA.items():
            bp = p.body_parts[part]
            ratio = bp['hp'] / bp['max_hp']

            # 名称
            name_surf = self.font_md.render(part.value, True, C_WHITE)
            self.screen.blit(name_surf, (x2, y))

            # 血条
            bar_x = x2 + 60
            bar_w = 150
            pygame.draw.rect(self.screen, (40, 40, 40), (bar_x, y + 4, bar_w, 14))
            fill_color = C_GREEN if ratio > 0.6 else (C_YELLOW if ratio > 0.3 else C_RED)
            if bp['crippled']: fill_color = (60, 60, 60)
            fill = int(bar_w * ratio)
            pygame.draw.rect(self.screen, fill_color, (bar_x, y + 4, fill, 14))

            hp_text = self.font_sm.render(f"{bp['hp']}/{bp['max_hp']}", True, C_WHITE)
            self.screen.blit(hp_text, (bar_x + bar_w + 8, y + 4))

            # 状态效果
            effects = []
            if bp['crippled']: effects.append("💀残废")
            if bp['bleeding']: effects.append("🩸流血")
            if bp['fractured']: effects.append("🦴骨折")
            if bp['infected']: effects.append("🦠感染")
            if bp['frostbite']: effects.append("🥶冻伤")
            if effects:
                eff_surf = self.font_sm.render(" ".join(effects), True, C_RED)
                self.screen.blit(eff_surf, (x2 + 20, y + 20))
                y += 12

            y += 28

        # 状态效果
        y += 10
        if p.poisoned > 0:
            s = self.font_md.render(f"☠ 中毒: {p.poisoned}分钟", True, (150, 255, 50))
            self.screen.blit(s, (x2, y))
            y += 24
        if p.sick > 0:
            s = self.font_md.render(f"🤒 {p.disease_name}: {p.sick}分钟", True, (255, 150, 50))
            self.screen.blit(s, (x2, y))
            y += 24

        close = self.font_sm.render("[ESC] 关闭", True, C_GRAY)
        self.screen.blit(close, (WINDOW_W // 2 - 40, WINDOW_H - 40))

    def _render_gameover(self):
        """游戏结束画面"""
        self.screen.fill((15, 10, 10))

        p = self.player

        # 标题
        go_title = self.font_title.render("你 死 了", True, C_RED)
        self.screen.blit(go_title, (WINDOW_W // 2 - go_title.get_width() // 2, 60))

        # 死因
        cause = "未知原因"
        if p.body_parts[BodyPart.TORSO]['hp'] <= 0:
            cause = "躯干致命伤"
        if p.hunger <= 0 and p.thirst <= 0:
            cause = "饥饿与脱水"
        elif p.hunger <= 0:
            cause = "饥饿"
        elif p.thirst <= 0:
            cause = "脱水"
        if p.mental <= 0:
            cause = "精神崩溃"
        if p.body_temp < 32:
            cause = "冻死"

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

        # 统计
        stats = [
            f"存活天数: {p.days_survived}",
            f"等级: Lv.{p.level}",
            f"击杀野兽: {p.beasts_killed}",
            f"总伤害: {p.total_damage_dealt}",
            f"行走步数: {p.steps_walked}",
        ]

        score = p.days_survived * 100 + p.beasts_killed * 50 + p.level * 30 + p.steps_walked
        grade = 'F' if score < 200 else 'D' if score < 500 else 'C' if score < 1000 else 'B' if score < 2000 else 'A' if score < 4000 else 'S'

        y = 200
        for s in stats:
            surf = self.font_md.render(s, True, C_WHITE)
            self.screen.blit(surf, (WINDOW_W // 2 - surf.get_width() // 2, y))
            y += 30

        y += 20
        score_surf = self.font_xl.render(f"总评分: {score}  [{grade}]", True, C_YELLOW)
        self.screen.blit(score_surf, (WINDOW_W // 2 - score_surf.get_width() // 2, y))

        restart = self.font_md.render("[R] 重新开始  [Q] 退出", True, C_GRAY)
        self.screen.blit(restart, (WINDOW_W // 2 - restart.get_width() // 2, WINDOW_H - 60))

    def _render_help(self):
        """帮助界面"""
        self.screen.fill((15, 20, 30))

        title = self.font_xl.render("📖 操作指南", True, C_WHITE)
        self.screen.blit(title, (WINDOW_W // 2 - title.get_width() // 2, 20))

        x1, y = 80, 80
        sections = [
            ("移动", [
                "W/A/S/D 或 方向键 - 移动角色",
                "E - 与附近物体互动(砍树/采矿/采集/取水/烹饪)",
            ]),
            ("菜单", [
                "1 / I - 打开背包",
                "2 / C - 打开制作台",
                "3 / B - 打开建造菜单",
                "4 / F - 进食",
                "5 / H - 治疗",
                "6 / M - 查看详细状态",
                "7 / F1 - 帮助",
                "ESC - 暂停/关闭菜单",
            ]),
            ("战斗", [
                "靠近野兽会自动进入战斗",
                "A - 攻击  H - 用药  F - 逃跑",
                "夜间野兽更强，逃跑更难",
            ]),
            ("生存", [
                "饱食度/水分会持续下降，归零会持续掉血",
                "肢体受伤会流血/骨折/感染，需要及时治疗",
                "躯干HP归零 = 死亡",
                "夜间没有营火会快速降低精神值",
                "冬季暴雪会导致冻伤，夏季高温会中暑",
                "脏水/生肉可能导致中毒和疾病",
                "食物会腐烂，尽快食用或烤熟保存",
            ]),
        ]

        for section, lines in sections:
            s_title = self.font_md.render(f"【{section}】", True, C_YELLOW)
            self.screen.blit(s_title, (x1, y))
            y += 26
            for line in lines:
                l_surf = self.font_sm.render(f"  {line}", True, C_WHITE)
                self.screen.blit(l_surf, (x1, y))
                y += 20
            y += 12

        close = self.font_sm.render("[ESC] 关闭", True, C_GRAY)
        self.screen.blit(close, (WINDOW_W // 2 - 40, WINDOW_H - 40))

    # ─── 事件处理 ───────────────────────────────
    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.mode == GameMode.GAMEOVER:
                    if event.key == pygame.K_r:
                        self.__init__()
                    elif event.key == pygame.K_q:
                        self.running = False
                    continue

                if self.mode == GameMode.COMBAT:
                    if event.key == pygame.K_a:
                        self.combat_attack()
                    elif event.key == pygame.K_h:
                        self.combat_heal()
                    elif event.key == pygame.K_f:
                        self.combat_flee()
                    continue

                if self.mode == GameMode.WORLD:
                    if event.key == pygame.K_e:
                        self.interact()
                    elif event.key in (pygame.K_1, pygame.K_i):
                        self.mode = GameMode.INVENTORY
                    elif event.key in (pygame.K_2, pygame.K_c):
                        self.mode = GameMode.CRAFT
                        self.craft_scroll = 0
                    elif event.key in (pygame.K_3, pygame.K_b):
                        self.mode = GameMode.BUILD
                    elif event.key in (pygame.K_4, pygame.K_f):
                        self.mode = GameMode.EAT
                    elif event.key in (pygame.K_5, pygame.K_h):
                        self.mode = GameMode.HEAL
                    elif event.key in (pygame.K_6, pygame.K_m):
                        self.mode = GameMode.STATUS
                    elif event.key in (pygame.K_7, pygame.K_F1):
                        self.mode = GameMode.HELP
                    elif event.key == pygame.K_ESCAPE:
                        self.mode = GameMode.PAUSE
                    continue

                # 菜单中的操作
                if event.key == pygame.K_ESCAPE:
                    self.mode = GameMode.WORLD
                    continue

                if self.mode == GameMode.CRAFT:
                    if event.key == pygame.K_UP:
                        self.craft_scroll = max(0, self.craft_scroll - 1)
                    elif event.key == pygame.K_DOWN:
                        self.craft_scroll = min(max(0, len(RECIPES) - 12), self.craft_scroll + 1)
                    elif pygame.K_1 <= event.key <= pygame.K_9:
                        idx = self.craft_scroll + (event.key - pygame.K_1)
                        self.craft_item(idx)
                    elif event.key == pygame.K_0:
                        idx = self.craft_scroll + 9
                        self.craft_item(idx)
                    continue

                if self.mode == GameMode.BUILD:
                    if pygame.K_1 <= event.key <= pygame.K_4:
                        self.build_item(event.key - pygame.K_1)
                    continue

                if self.mode == GameMode.EAT:
                    if pygame.K_1 <= event.key <= pygame.K_9:
                        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])
                    continue

                if self.mode == GameMode.HEAL:
                    if pygame.K_1 <= event.key <= pygame.K_9:
                        idx = event.key - pygame.K_1
                        self.heal_action(idx)
                    continue

                if self.mode == GameMode.PAUSE:
                    if event.key == pygame.K_ESCAPE:
                        self.mode = GameMode.WORLD
                    elif event.key == pygame.K_q:
                        self.running = False

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

        pygame.quit()
        sys.exit()


# ─── 启动 ─────────────────────────────────────────
if __name__ == '__main__':
    game = Game()
    game.run()
