基于Python的RPG游戏开发全解析

本文将深入分析一个完整的Python角色扮演游戏(RPG)代码实现,涵盖游戏架构、核心系统设计以及关键编程技巧。这个RPG游戏包含了角色创建、战斗系统、任务系统、物品管理、地图探索等完整功能。

游戏架构概述

该RPG游戏采用模块化设计,主要包含以下几个核心系统:

  1. 角色系统:玩家角色创建、属性管理和成长
  2. 物品系统:装备、消耗品和任务物品管理
  3. 战斗系统:回合制战斗机制
  4. 任务系统:任务接取、进度追踪和奖励发放
  5. 地图系统:网格化地图探索和随机事件
  6. 存档系统:游戏进度保存和加载

核心类设计

1. 枚举类型定义

游戏使用Python的Enum类定义了多种枚举类型,确保类型安全:

class ItemType(Enum):
    WEAPON = "武器"
    ARMOR = "护甲"
    CONSUMABLE = "消耗品"
    MATERIAL = "材料"
    QUEST = "任务物品"
    SPECIAL = "特殊物品"

class Rarity(Enum):
    COMMON = "普通"
    UNCOMMON = "稀有"
    RARE = "精良"
    EPIC = "史诗"
    LEGENDARY = "传说"
    
    @property
    def color(self) -> str:
        colors = {
            "普通": "\033[0m",    # 白色
            "稀有": "\033[92m",   # 绿色
            "精良": "\033[94m",   # 蓝色
            "史诗": "\033[95m",   # 紫色
            "传说": "\033[93m"    # 金色
        }
        return colors[self.value]

class QuestStatus(Enum):
    NOT_STARTED = "未开始"
    IN_PROGRESS = "进行中"
    COMPLETED = "已完成"
    FAILED = "已失败"

class EquipmentSlot(Enum):
    WEAPON = "武器"
    ARMOR = "护甲"
    ACCESSORY = "饰品"

class PlayerRace(Enum):
    HUMAN = "人类"
    ELF = "精灵"
    DWARF = "矮人"
    ORC = "兽人"
    HALFLING = "半身人"

class PlayerClass(Enum):
    WARRIOR = "战士"
    MAGE = "法师"
    ROGUE = "盗贼"
    CLERIC = "牧师"
    RANGER = "游侠"

class StatusEffect(Enum):
    POISONED = "中毒"
    BURNING = "燃烧"
    FROZEN = "冻结"
    STUNNED = "眩晕"
    DEFENSE_UP = "防御+10"
    SPEED_UP = "速度+10"
    DAMAGE_UP = "伤害+10"
    
    def __init__(self, *args):
        super().__init__(*args)
        self.reset_duration()
    
    def reset_duration(self) -> None:
        self.duration = 3
    
    def should_remove(self) -> bool:
        self.duration -= 1
        return self.duration <= 0
    
    def clear(self, target: Any) -> None:
        if self in target.status_effects:
            target.status_effects.remove(self)
            self.reset_duration()
            print(f"{target.name}的{self.value}效果解除了!")

class TerrainType(Enum):
    PLAIN = "平原"
    FOREST = "森林"
    MOUNTAIN = "山地"
    STARTING_POINT = "起始点"
    DRAGON_LAIR = "巨龙巢穴"
    VILLAGE = "村庄"
    RUINS = "古老遗迹"
    
class PlayerGender(Enum):
    MALE = "男"
    FEMALE = "女"

2. 物品系统

物品系统通过继承实现不同类型物品:

class Item:
    COLOR_MAP = {  # 类常量
        Rarity.COMMON: Fore.WHITE,
        Rarity.UNCOMMON: Fore.GREEN,
        Rarity.RARE: Fore.BLUE,
        Rarity.EPIC: Fore.MAGENTA,
        Rarity.LEGENDARY: Fore.YELLOW
    }
    def __init__(self, name: str, item_type: ItemType, description: str = "", 
                 rarity: Rarity = Rarity.COMMON, value: int = 0):
        self.name = name
        self.type = item_type
        self.description = description
        self.rarity = rarity
        self.value = value
        self.id = str(uuid.uuid4())
    
    def __str__(self) -> str:
        return f"{self.rarity.color}{self.name}\033[0m - {self.description}"
    
    def colored_name(self) -> str:
        """返回带有颜色格式的物品名称(使用 colorama 确保跨平台兼容)"""
        return f"{self.COLOR_MAP.get(self.rarity, Fore.WHITE)}{self.name}{Style.RESET_ALL}"

class Equipment(Item):
    def __init__(self, name: str, item_type: ItemType, slot: EquipmentSlot, 
                 stats: Dict[str, Any], description: str = "", rarity: Rarity = Rarity.COMMON, 
                 value: int = 0, requirements: Optional[Dict[str, int]] = None):
        super().__init__(name, item_type, description, rarity, value)
        self.slot = slot
        self.stats = stats
        self.requirements = requirements or {}
    
    def can_equip(self, player: 'Player') -> bool:
        for attr, value in self.requirements.items():
            if getattr(player, attr, 0) < value:
                return False
        return True

class Consumable(Item):
    def __init__(self, name: str, effects: Dict[str, Any], description: str = "", 
                 rarity: Rarity = Rarity.COMMON, value: int = 0, quantity: int = 1):
        super().__init__(name, ItemType.CONSUMABLE, description, rarity, value)
        self.effects = effects
        self.quantity = quantity
    
    def use(self, player: 'Player') -> bool:
        if self.quantity <= 0:
            print("物品数量不足!")
            return False
            
        success = True
        for effect, value in self.effects.items():
            if effect == "heal":
                player.hp = min(player.hp + value, player.max_hp)
                print(f"恢复了{value}点生命值!")
            elif effect == "restore_mp":
                player.magic = min(player.magic + value, player.max_magic)
                print(f"恢复了{value}点魔法值!")
            elif effect == "status":
                if isinstance(value, str):
                    player.add_status_effect(value)
                    print(f"获得了{value}效果!")
                else:
                    print("无效的状态效果!")
                    success = False
            else:
                print(f"未知效果: {effect}")
                success = False
        
        return success

3. 角色系统

玩家角色类整合了属性、装备和技能:

class Player:
    def __init__(self):
        self.name = input('请输入角色名: ')
        self.gender = self.select_gender()
        self.race = self.select_race()
        self.class_type = self.select_class()
        self.set_initial_stats()
        self.inventory: Dict[str, Union[Item, Equipment, Consumable]] = {}
        self.equipment = {slot: None for slot in EquipmentSlot}
        self.quest_log: List[Quest] = []
        self.status_effects: List[StatusEffect] = []
        self.title = "冒险者"
        self.gold = 50
        self.add_class_starting_items()
    
    def clear_status_effects(self) -> None:
        for effect in self.status_effects[:]:
            effect.clear(self)
    
    def select_gender(self) -> Dict[str, str]:
        print("\n选择性别:")
        for i, gender in enumerate(PlayerGender, 1):
            print(f"{i}. {gender.value}")
        choice = input(">> ")
        try:
            return {'name': list(PlayerGender)[int(choice)-1].value}
        except (ValueError, IndexError):
            print("无效选择,默认为男性")
            return {'name': PlayerGender.MALE.value}
        
    def select_race(self) -> Dict[str, Any]:
        print("\n选择种族:")
        for i, race in enumerate(PlayerRace, 1):
            print(f"{i}. {race.value}")
        
        bonuses = {
            PlayerRace.HUMAN: {'hp': 10, 'attack': 2, 'defense': 2, 'magic': 5},
            PlayerRace.ELF: {'hp': 5, 'attack': 1, 'defense': 1, 'magic': 15},
            PlayerRace.DWARF: {'hp': 15, 'attack': 1, 'defense': 5, 'magic': 0},
            PlayerRace.ORC: {'hp': 10, 'attack': 5, 'defense': 0, 'magic': -5},
            PlayerRace.HALFLING: {'hp': 8, 'attack': 0, 'defense': 3, 'magic': 5}
        }
        
        choice = input(">> ")
        try:
            selected = list(PlayerRace)[int(choice)-1]
            return {'name': selected.value, 'bonus': bonuses[selected]}
        except (ValueError, IndexError):
            print("无效选择,默认为人类")
            return {'name': PlayerRace.HUMAN.value, 'bonus': bonuses[PlayerRace.HUMAN]}
    
    def select_class(self) -> Dict[str, Any]:
        print("\n选择职业:")
        for i, cls in enumerate(PlayerClass, 1):
            print(f"{i}. {cls.value}")
        
        bonuses = {
            PlayerClass.WARRIOR: {'hp': 20, 'attack': 5, 'defense': 3, 'magic': 0},
            PlayerClass.MAGE: {'hp': 10, 'attack': 1, 'defense': 1, 'magic': 30},
            PlayerClass.ROGUE: {'hp': 15, 'attack': 8, 'defense': 2, 'magic': 5},
            PlayerClass.CLERIC: {'hp': 15, 'attack': 3, 'defense': 2, 'magic': 20},
            PlayerClass.RANGER: {'hp': 18, 'attack': 6, 'defense': 3, 'magic': 10}
        }
        
        skills = {
            PlayerClass.WARRIOR: ['猛击', '防御姿态'],
            PlayerClass.MAGE: ['火球术', '冰霜新星'],
            PlayerClass.ROGUE: ['背刺', '闪避'],
            PlayerClass.CLERIC: ['治疗术', '神圣打击'],
            PlayerClass.RANGER: ['精准射击', '陷阱设置']
        }
        
        choice = input(">> ")
        try:
            selected = list(PlayerClass)[int(choice)-1]
            return {'name': selected.value, 'bonus': bonuses[selected], 'skills': skills[selected]}
        except (ValueError, IndexError):
            print("无效选择,默认为战士")
            return {'name': PlayerClass.WARRIOR.value, 'bonus': bonuses[PlayerClass.WARRIOR], 'skills': skills[PlayerClass.WARRIOR]}
    
    def set_initial_stats(self) -> None:
        self.max_hp = 80 + self.race['bonus'].get('hp', 0) + self.class_type['bonus'].get('hp', 0)
        self.hp = self.max_hp
        self.attack = 10 + self.race['bonus'].get('attack', 0) + self.class_type['bonus'].get('attack', 0)
        self.defense = 8 + self.race['bonus'].get('defense', 0) + self.class_type['bonus'].get('defense', 0)
        self.max_magic = 30 + self.race['bonus'].get('magic', 0) + self.class_type['bonus'].get('magic', 0)
        self.magic = self.max_magic
        self.skills = self.class_type['skills']
        self.level = 1
        self.exp = 0
        self.exp_to_next = 100
    
    def add_class_starting_items(self) -> None:
        starting_items = {
            PlayerClass.WARRIOR: {'长剑': Equipment("长剑", ItemType.WEAPON, EquipmentSlot.WEAPON, 
                                                  {"attack": 15}, "基础长剑", Rarity.COMMON, 50),
                                '钢盾': Equipment("钢盾", ItemType.ARMOR, EquipmentSlot.ARMOR,
                                                 {"defense": 10}, "钢制盾牌", Rarity.COMMON, 40)},
            PlayerClass.MAGE: {'法杖': Equipment("法杖", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                              {"attack": 8, "magic": 5}, "魔法法杖", Rarity.UNCOMMON, 60),
                             '火焰卷轴': Consumable("火焰卷轴", {"damage": 40}, "造成40点火焰伤害", Rarity.UNCOMMON, 30)},
            PlayerClass.ROGUE: {'匕首': Equipment("匕首", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                               {"attack": 12, "critical": 0.1}, "锋利的匕首", Rarity.COMMON, 45),
                              '皮甲': Equipment("皮甲", ItemType.ARMOR, EquipmentSlot.ARMOR,
                                              {"defense": 8}, "轻便皮甲", Rarity.COMMON, 30)},
            PlayerClass.CLERIC: {'治疗法杖': Equipment("治疗法杖", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                                   {"attack": 8, "heal": 20}, "神圣治疗法杖", Rarity.UNCOMMON, 70),
                               '圣徽': Item("圣徽", ItemType.SPECIAL, "神圣徽章", Rarity.RARE, 50)},
            PlayerClass.RANGER: {'短弓': Equipment("短弓", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                                {"attack": 10, "range": 3}, "狩猎短弓", Rarity.COMMON, 55),
                               '皮甲': Equipment("皮甲", ItemType.ARMOR, EquipmentSlot.ARMOR,
                                              {"defense": 8}, "轻便皮甲", Rarity.COMMON, 30)}
        }
        
        for cls in PlayerClass:
            if self.class_type['name'] == cls.value:
                for item_name, item in starting_items[cls].items():
                    self.add_item(item)
                break
    
    def add_item(self, item: Union[Item, Equipment, Consumable]) -> None:
        """统一添加物品逻辑"""
        if isinstance(item, Consumable):
            existing = next((i for i in self.inventory.values() 
                           if isinstance(i, Consumable) and i.name == item.name), None)
            if existing:
                existing.quantity += item.quantity
            else:
                self.inventory[item.id] = item
        else:
            self.inventory[item.id] = item
    
    def find_item_by_name(self, name: str) -> Optional[Union[Item, Equipment, Consumable]]:
        """通过名称查找物品"""
        return next((item for item in self.inventory.values() if item.name == name), None)
    
    def equip_item(self, item_name: str) -> bool:
        item = self.find_item_by_name(item_name)
        if not item:
            print(f"错误:物品'{item_name}'不在背包中!")
            return False
        
        if not isinstance(item, Equipment):
            print(f"错误:'{item_name}'不是可装备的物品!")
            return False
        
        if not item.can_equip(self):
            print(f"错误:不满足装备'{item_name}'的要求!")
            return False
        
        if self.equipment[item.slot]:
            self.unequip_item(item.slot)
        
        self.equipment[item.slot] = item
        # 从背包移除装备的物品
        del self.inventory[item.id]
        print(f"装备了{item.name}!")
        return True
    
    def unequip_item(self, slot: EquipmentSlot) -> bool:
        if not self.equipment[slot]:
            print(f"你没有装备{slot.value}!")
            return False
        
        item = self.equipment[slot]
        self.add_item(item)
        self.equipment[slot] = None
        print(f"卸下了{item.name}!")
        return True
    
    def use_item(self, item_name: str) -> bool:
        # 先尝试通过名称查找
        item = next((i for i in self.inventory.values() if i.name == item_name), None)
        
        if not item:
            print("你没有这个物品!")
            return False
        
        if not isinstance(item, Consumable):
            print("这个物品不能使用!")
            return False

        if item.use(self):
            item.quantity -= 1
            if item.quantity <= 0:
                # 从背包中移除
                keys_to_remove = [k for k, v in self.inventory.items() if v.name == item_name]
                for key in keys_to_remove:
                    del self.inventory[key]
            return True
        return False
    
    def add_quest(self, quest: Quest) -> None:
        if quest.name not in [q.name for q in self.quest_log]:
            quest.status = QuestStatus.IN_PROGRESS
            self.quest_log.append(quest)
            print(f"接受了新任务: {quest.name}")
    
    def update_quest(self, objective: str, amount: int = 1) -> None:
        for quest in self.quest_log:
            if quest.status == QuestStatus.IN_PROGRESS and objective in quest.objectives:
                quest.update_progress(objective, amount)
    
    def get_attack(self) -> int:
        weapon = self.equipment[EquipmentSlot.WEAPON]
        base = self.attack
        if weapon and isinstance(weapon, Equipment):
            return base + weapon.stats.get('attack', 0)
        return base
    
    def get_defense(self) -> int:
        armor = self.equipment[EquipmentSlot.ARMOR]
        base = self.defense
        if armor and isinstance(armor, Equipment):
            return base + armor.stats.get('defense', 0)
        return base
    
    def add_status_effect(self, effect: str) -> None:
        if effect not in [se.value for se in self.status_effects]:
            self.status_effects.append(StatusEffect(effect))
            print(f"你受到了{effect}效果!")
    
    def clear_status_effects(self) -> None:
        if self.status_effects:
            print("清除了所有状态效果!")
        self.status_effects = []
    
    def gain_exp(self, amount: int) -> None:
        self.exp += amount
        print(f"获得 {amount} 经验值!")
        if self.exp >= self.exp_to_next:
            self.level_up()
    
    def level_up(self) -> None:
        self.level += 1
        self.exp -= self.exp_to_next
        self.exp_to_next = int(self.exp_to_next * 1.5)
        self.max_hp += 10 + self.race['bonus'].get('hp', 0) // 2
        self.hp = self.max_hp
        self.attack += 2 + self.race['bonus'].get('attack', 0) // 2
        self.defense += 1 + self.race['bonus'].get('defense', 0) // 2
        self.max_magic += 5 + self.race['bonus'].get('magic', 0) // 2
        self.magic = self.max_magic
        print(f"""
        === 升级到 Lv{self.level}! ===
        最大HP: {self.max_hp}
        攻击力: {self.attack}
        防御力: {self.defense}
        魔法值: {self.max_magic}
        """)

游戏核心机制

1. 战斗系统

回合制战斗实现:

def battle(player: Player, enemy: Enemy) -> bool:
    print(f"\n遭遇 {enemy.name}!")
    
    while player.hp > 0 and enemy.hp > 0:
        print(f"\n{player.name}: HP {player.hp}/{player.max_hp} | {enemy.name}: HP {enemy.hp}/{enemy.max_hp}")
        print("选择行动: [1]攻击 [2]使用物品 [3]使用技能 [4]逃跑(50%成功率)")
        
        choice = input(">> ")
  
        if choice == '1':  # 攻击
            damage = calculate_damage(player, enemy, player.get_attack())
            enemy.hp -= damage
            print(f"你对{enemy.name}造成{damage}点伤害!")
        elif choice == '2':  # 物品
            if not use_item_menu(player):
                continue
        elif choice == '3':  # 技能
            if not use_skill_menu(player, enemy):
                continue
        elif choice == '4':  # 逃跑
            if random.random() < 0.5:
                print("成功逃脱!")
                player.clear_status_effects()
                return False  # 逃跑成功
            else:
                print("逃跑失败!")
                # 逃跑失败后直接进入敌人回合
                if player.hp <=0:
                    print("\n游戏结束...")
                    return False
        
        # 检查敌人是否被击败
        if enemy.hp <= 0:
            print(f"\n你击败了{enemy.name}!")
            player.gain_exp(enemy.exp_value)
            return True
            
        # 敌人回合
        if not enemy.use_skill(player):
            damage = enemy.attack - random.randint(0, player.get_defense())
            damage = max(damage, 1)
            player.hp -= damage
            print(f"{enemy.name}对你造成{damage}点伤害!")
        
        # 检查状态效果
        if check_status_effects(player, enemy):
            continue
        
        # 检查玩家是否被击败
        if player.hp <= 0:
            break
    
    if player.hp > 0:
        if enemy.hp <= 0:
            print(f"\n你击败了{enemy.name}!")
            player.gain_exp(enemy.exp_value)
            # 处理战利品...
        return True
    else:
        print("\n游戏结束...")
        return False

2. 任务系统

任务进度追踪和奖励发放:

class Quest:
    def __init__(self, name: str, description: str, objectives: Dict[str, int], 
                 rewards: Dict[str, Any], status: QuestStatus = QuestStatus.NOT_STARTED):
        self.name = name
        self.description = description
        self.objectives = objectives  # {objective: target, ...}
        self.rewards = rewards  # {exp: int, items: [], gold: int, etc.}
        self.status = status
        self.progress = {obj: 0 for obj in objectives.keys()}
    
    def update_progress(self, objective: str, amount: int = 1) -> None:
        if self.status != QuestStatus.IN_PROGRESS:
            return
        
        if objective in self.progress:
            self.progress[objective] += amount
            print(f"任务更新: {objective} ({self.progress[objective]}/{self.objectives[objective]})")
            
            if all(self.progress[obj] >= target for obj, target in self.objectives.items()):
                self.complete()
    
    def complete(self) -> Dict[str, Any]:
        self.status = QuestStatus.COMPLETED
        print(f"\n=== 任务完成: {self.name} ===")
        print("获得奖励:")
        if 'exp' in self.rewards:
            print(f"- 经验值: {self.rewards['exp']}")
        if 'gold' in self.rewards:
            print(f"- 金币: {self.rewards['gold']}")
        if 'items' in self.rewards:
            print(f"- 物品: {', '.join(self.rewards['items'])}")
        if 'title' in self.rewards:
            print(f"- 称号: {self.rewards['title']}")
        return self.rewards
    
    def fail(self) -> None:
        self.status = QuestStatus.FAILED
        print(f"任务失败: {self.name}")

3. 地图探索

网格化地图实现:

class GameMap:
    def __init__(self, size: int = 5):
        self.size = size
        self.grid = [[random.choice(list(TerrainType)).value for _ in range(size)] for _ in range(size)]
        self.grid[0][0] = TerrainType.STARTING_POINT.value
        self.grid[size-1][size-1] = TerrainType.DRAGON_LAIR.value
        self.grid[size//2][size//2] = TerrainType.VILLAGE.value
        self.grid[size//3][size//3] = TerrainType.RUINS.value
        self.player_x = 0
        self.player_y = 0
        self.revealed = [[False for _ in range(size)] for _ in range(size)]
        self.revealed[0][0] = True
        self.dungeon_level = 0
        self.dungeon_entrance = (0, 0)
    
    def display(self) -> None:
        terrain_symbols = {
            '平原': '·', '森林': '♣', '山地': '▲', 
            '起始点': 'S', '巨龙巢穴': 'D', 
            '村庄': 'V', '古老遗迹': 'R'
        }
    
        print("  " + " ".join(str(i) for i in range(self.size)))  # 列坐标
        for y in range(self.size):
            print(y, end=" ")  # 行坐标
            for x in range(self.size):
                if x == self.player_x and y == self.player_y:
                    print("P", end=" ")
                elif self.revealed[y][x]:  # 修正坐标顺序
                    terrain = self.grid[y][x]
                    print(terrain_symbols.get(terrain, '?'), end=" ")
                else:
                    print("?", end=" ")
            print()
    
    def enter_dungeon(self, player: 'Player') -> bool:
        if self.dungeon_level == 0:
            self.dungeon_level = 1
            self.dungeon_entrance = (player.player_x, player.player_y)
            return True
        return False
    
    def descend_dungeon(self, player: 'Player') -> bool:
        if self.dungeon_level < 3:  # 假设地牢有3层
            self.dungeon_level += 1
            return True
        print("已经到达地牢最底层!")
        return False

数据持久化

游戏存档系统实现:

def save_game(player: Player, game_map: GameMap) -> None:
    def convert_for_serialization(obj: Any) -> Any:
        """转换对象为可JSON序列化的格式"""
        if isinstance(obj, (ItemType, Rarity, EquipmentSlot, QuestStatus, StatusEffect, TerrainType)):
            return obj.value
        if isinstance(obj, Enum):
            return obj.name
        if isinstance(obj, (dict, list, tuple, set)):
            return {k: convert_for_serialization(v) for k, v in obj.items()} if isinstance(obj, dict) else [convert_for_serialization(x) for x in obj]
        if hasattr(obj, '__dict__'):
            return convert_for_serialization(obj.__dict__)
        return obj

    data = {
        'version': CURRENT_VERSION,
        'player': {
            'name': player.name,
            'gender': convert_for_serialization(player.gender),
            'race': convert_for_serialization(player.race),
            'class_type': convert_for_serialization(player.class_type),
            'hp': player.hp,
            'max_hp': player.max_hp,
            'attack': player.attack,
            'defense': player.defense,
            'magic': player.magic,
            'max_magic': player.max_magic,
            'level': player.level,
            'exp': player.exp,
            'exp_to_next': player.exp_to_next,
            'gold': player.gold,
            'title': player.title,
            'status_effects': convert_for_serialization(player.status_effects),
            'skills': player.skills,
            'inventory': {item.id: convert_for_serialization(item.__dict__) 
                         for item in player.inventory.values()},
            'equipment': {slot.value: item.id if item else None 
                         for slot, item in player.equipment.items()},
            'quest_log': [convert_for_serialization(quest.__dict__) 
                         for quest in player.quest_log]
        },
        'map': {
            'grid': game_map.grid,
            'player_x': game_map.player_x, 
            'player_y': game_map.player_y,
            'revealed': game_map.revealed,
            'size': game_map.size,
            'dungeon_level': game_map.dungeon_level,
            'dungeon_entrance': game_map.dungeon_entrance
        }
    }
    save_path = get_save_path()
    
    try:
        # 检查目录是否可写
        if not os.access(save_path.parent, os.W_OK):
            raise PermissionError(f"没有写入权限: {save_path.parent}")
        
        # 保存文件
        with open(save_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        
        print(f"游戏已成功保存到: {save_path}")
        
    except PermissionError:
        print("无法保存游戏:没有写入权限。请检查游戏目录是否可写。")
    except Exception as e:
        print(f"保存游戏时发生意外错误: {str(e)}")
        print("系统已自动创建备份并尝试恢复。")

def load_game() -> Tuple[Optional[Player], Optional[GameMap]]:
    save_path = get_save_path()
    
    try:
        if not save_path.exists():
            raise FileNotFoundError(f"存档文件不存在: {save_path}")
        
        with open(save_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            
        if not validate_save_data(data):
            raise ValueError("存档数据验证失败")
        
        # 版本验证
        save_version = data.get('version', 1.0)
        handle_version_differences(save_version)
        
        # 迁移旧版本存档数据
        data = migrate_save_data(data)
        
        # 创建游戏地图
        game_map = GameMap(data['map']['size'])
        game_map.grid = data['map']['grid']
        game_map.player_x = data['map']['player_x']
        game_map.player_y = data['map']['player_y']
        game_map.revealed = data['map']['revealed']
        game_map.dungeon_level = data['map']['dungeon_level']
        game_map.dungeon_entrance = tuple(data['map']['dungeon_entrance'])
        
        # 创建玩家角色
        player = Player()
        player_data = data['player']
        
        # 设置玩家属性
        player.name = player_data['name']
        player.gender = {'name': player_data['gender']['name']}
        player.race = {
            'name': player_data['race']['name'],
            'bonus': player_data['race']['bonus']
        }
        player.class_type = {
            'name': player_data['class_type']['name'],
            'bonus': player_data['class_type']['bonus'],
            'skills': player_data['class_type']['skills']
        }
        player.hp = player_data['hp']
        player.max_hp = player_data['max_hp']
        player.attack = player_data['attack']
        player.defense = player_data['defense']
        player.magic = player_data['magic']
        player.max_magic = player_data['max_magic']
        player.level = player_data['level']
        player.exp = player_data['exp']
        player.exp_to_next = player_data['exp_to_next']
        player.gold = player_data['gold']
        player.title = player_data['title']
        player.skills = player_data['skills']
        
        # 恢复状态效果
        player.status_effects = [
            StatusEffect(effect) for effect in player_data['status_effects']
        ]
        
        # 恢复物品栏
        player.inventory = {}
        for item_id, item_data in player_data['inventory'].items():
            item_type = safe_enum_convert(item_data['type'], ItemType)
            rarity = safe_enum_convert(item_data['rarity'], Rarity)
            
            if item_type == ItemType.WEAPON or item_type == ItemType.ARMOR:
                slot = safe_enum_convert(item_data['slot'], EquipmentSlot)
                item = Equipment(
                    item_data['name'], item_type, slot,
                    item_data['stats'], item_data['description'],
                    rarity, item_data['value'], item_data.get('requirements')
                )
            elif item_type == ItemType.CONSUMABLE:
                item = Consumable(
                    item_data['name'], item_data['effects'],
                    item_data['description'], rarity,
                    item_data['value'], item_data['quantity']
                )
            else:
                item = Item(
                    item_data['name'], item_type,
                    item_data['description'], rarity,
                    item_data['value']
                )
            
            item.id = item_id
            player.inventory[item_id] = item
        
        # 恢复装备
        player.equipment = {slot: None for slot in EquipmentSlot}
        for slot_name, item_id in player_data['equipment'].items():
            if item_id:
                slot = safe_enum_convert(slot_name, EquipmentSlot)
                player.equipment[slot] = player.inventory[item_id]
        
        # 恢复任务日志
        player.quest_log = []
        for quest_data in player_data['quest_log']:
            quest = Quest(
                quest_data['name'],
                quest_data['description'],
                quest_data['objectives'],
                quest_data['rewards'],
                safe_enum_convert(quest_data['status'], QuestStatus)
            )
            quest.progress = quest_data['progress']
            player.quest_log.append(quest)
        
        return player, game_map
        
    except Exception as e:
        print(f"加载失败: {str(e)}")
        backup_and_reset_save(save_path)  # 确保传递了save_path
        return None, None

游戏主循环

def main() -> None:
    try:
        print(Fore.YELLOW + "="*50)
        print("  欢迎来到RPG冒险世界".center(40))
        print("="*50 + Style.RESET_ALL)
        
        player = None
        game_map = None
        
        # 主菜单循环
        while True:
            choice = main_menu()
            
            if choice == '1':  # 新游戏
                player = create_new_player()
                game_map = GameMap()
                run_game_loop(player, game_map, npcs, quests)
                break
                
            elif choice == '2':  # 继续游戏
                player, game_map = load_game()
                if player:
                    run_game_loop(player, game_map, npcs, quests)
                    break
                    
            elif choice == '3':  # 游戏帮助
                show_game_help()
                
            elif choice == '4':  # 更新日志
                UpdateLog.show_version_history()
                input("\n按回车键返回主菜单...")
                
            elif choice == '5':  # 退出
                if input("确定要退出游戏吗?(y/n): ").lower() == 'y':
                    print("感谢游玩,再见!")
                    exit()

        # 主游戏循环
        if player and game_map:
            run_game_loop(player, game_map, npcs, quests)
    
    except KeyboardInterrupt:
        print("\n游戏被用户中断")
    except Exception as e:
        print(f"\n游戏发生错误: {str(e)}")
    finally:
        # 仅在程序未被exit终止时执行
        if 'sys' not in globals() or sys.exc_info()[0] != SystemExit:
            input("按任意键退出...")


if __name__ == '__main__':
    main()

完整游戏代码

以下是完整的Python RPG游戏代码,包含所有讨论的系统和功能:

import random
import json
import os
from enum import Enum
import uuid
import datetime
import shutil
from typing import Dict, List, Optional, Tuple, Any, Union, Callable
from colorama import init, Fore, Style
from pathlib import Path
import sys

# 初始化colorama(模块级别)
init(autoreset=True)

# ========== 常量定义 ==========
CURRENT_VERSION = 1.5
MAX_INVENTORY_SIZE = 100

# ========== 更新日志系统 ==========
class UpdateLog:
    """游戏更新日志系统"""
    VERSION_HISTORY = {
        1.0: [
            "游戏初始版本发布",
            "基础战斗系统",
            "任务系统框架"
        ],
        1.1: [
            "新增玩家称号系统",
            "添加装备品质颜色显示",
            "优化存档格式"
        ],
        1.2: [
            "修复任务进度追踪bug",
            "改进NPC对话系统",
            "添加状态效果持续时间"
        ],
        1.5: [
            "添加多层地牢系统",
            "增强异常处理机制",
            "新增更新日志功能"
        ]
    }

    @classmethod
    def show_version_history(cls, version: float = None) -> None:
        """显示更新日志"""
        print(f"\n{'='*40}")
        print(f"{'游戏更新日志'.center(36)}")
        print('='*40)
        
        if version:
            if version in cls.VERSION_HISTORY:
                print(f"\n版本 {Fore.YELLOW}v{version}{Style.RESET_ALL} 更新内容:")
                for item in cls.VERSION_HISTORY[version]:
                    print(f" {Fore.GREEN}▶{Style.RESET_ALL} {item}")
            else:
                print(f"未找到版本 v{version} 的记录")
        else:
            for ver, items in sorted(cls.VERSION_HISTORY.items(), reverse=True):
                print(f"\n版本 {Fore.YELLOW}v{ver}{Style.RESET_ALL}:")
                for item in items:
                    print(f" {Fore.GREEN}▶{Style.RESET_ALL} {item}")
        
        print(f"\n当前版本: {Fore.CYAN}v{CURRENT_VERSION}{Style.RESET_ALL}")
        print('='*40)

    @classmethod
    def check_for_updates(cls) -> bool:
        """检查更新(模拟实现)"""
        try:
            # 模拟网络请求
            mock_latest_version = 1.5
            mock_update_info = {
                'version': mock_latest_version,
                'changes': [
                    "新增竞技场系统",
                    "优化战斗平衡性"
                ],
                'critical': False
            }

            if CURRENT_VERSION < mock_latest_version:
                print(f"\n{Fore.YELLOW}发现新版本 v{mock_latest_version}!{Style.RESET_ALL}更新内容:")
                for change in mock_update_info['changes']:
                    print(f" {Fore.GREEN}▶{Style.RESET_ALL} {change}")
                
                if mock_update_info['critical']:
                    print(Fore.RED + "\n这是重要安全更新,请尽快升级!" + Style.RESET_ALL)
                return True
            
            print(f"\n{Fore.GREEN}当前已是最新版本{Style.RESET_ALL}")
            return False
                
        except Exception as e:
            print(f"\n{Fore.RED}版本检查失败: {e}{Style.RESET_ALL}")
            return False

# ========== 枚举定义 ==========
class ItemType(Enum):
    WEAPON = "武器"
    ARMOR = "护甲"
    CONSUMABLE = "消耗品"
    MATERIAL = "材料"
    QUEST = "任务物品"
    SPECIAL = "特殊物品"

class Rarity(Enum):
    COMMON = "普通"
    UNCOMMON = "稀有"
    RARE = "精良"
    EPIC = "史诗"
    LEGENDARY = "传说"
    
    @property
    def color(self) -> str:
        colors = {
            "普通": "\033[0m",    # 白色
            "稀有": "\033[92m",   # 绿色
            "精良": "\033[94m",   # 蓝色
            "史诗": "\033[95m",   # 紫色
            "传说": "\033[93m"    # 金色
        }
        return colors[self.value]

class QuestStatus(Enum):
    NOT_STARTED = "未开始"
    IN_PROGRESS = "进行中"
    COMPLETED = "已完成"
    FAILED = "已失败"

class EquipmentSlot(Enum):
    WEAPON = "武器"
    ARMOR = "护甲"
    ACCESSORY = "饰品"

class PlayerRace(Enum):
    HUMAN = "人类"
    ELF = "精灵"
    DWARF = "矮人"
    ORC = "兽人"
    HALFLING = "半身人"

class PlayerClass(Enum):
    WARRIOR = "战士"
    MAGE = "法师"
    ROGUE = "盗贼"
    CLERIC = "牧师"
    RANGER = "游侠"

class StatusEffect(Enum):
    POISONED = "中毒"
    BURNING = "燃烧"
    FROZEN = "冻结"
    STUNNED = "眩晕"
    DEFENSE_UP = "防御+10"
    SPEED_UP = "速度+10"
    DAMAGE_UP = "伤害+10"
    
    def __init__(self, *args):
        super().__init__(*args)
        self.reset_duration()
    
    def reset_duration(self) -> None:
        self.duration = 3
    
    def should_remove(self) -> bool:
        self.duration -= 1
        return self.duration <= 0
    
    def clear(self, target: Any) -> None:
        if self in target.status_effects:
            target.status_effects.remove(self)
            self.reset_duration()
            print(f"{target.name}的{self.value}效果解除了!")

class TerrainType(Enum):
    PLAIN = "平原"
    FOREST = "森林"
    MOUNTAIN = "山地"
    STARTING_POINT = "起始点"
    DRAGON_LAIR = "巨龙巢穴"
    VILLAGE = "村庄"
    RUINS = "古老遗迹"
    
class PlayerGender(Enum):
    MALE = "男"
    FEMALE = "女"

# ========== 工具函数 ==========
def safe_enum_convert(value: Any, enum_class: Enum, default: Optional[Enum] = None) -> Enum:
    if isinstance(value, enum_class):
        return value
    try:
        if isinstance(value, str):
            for member in enum_class:
                if member.value.lower() == value.lower().strip():  # 添加strip()处理空格
                    return member
            raise ValueError(f"No matching enum found for {value}")
        return enum_class(value)
    except (ValueError, AttributeError):
        return default if default is not None else list(enum_class.__members__.values())[0]

# ========== 游戏核心类 ==========
class Item:
    COLOR_MAP = {  # 类常量
        Rarity.COMMON: Fore.WHITE,
        Rarity.UNCOMMON: Fore.GREEN,
        Rarity.RARE: Fore.BLUE,
        Rarity.EPIC: Fore.MAGENTA,
        Rarity.LEGENDARY: Fore.YELLOW
    }
    def __init__(self, name: str, item_type: ItemType, description: str = "", 
                 rarity: Rarity = Rarity.COMMON, value: int = 0):
        self.name = name
        self.type = item_type
        self.description = description
        self.rarity = rarity
        self.value = value
        self.id = str(uuid.uuid4())
    
    def __str__(self) -> str:
        return f"{self.rarity.color}{self.name}\033[0m - {self.description}"
    
    def colored_name(self) -> str:
        """返回带有颜色格式的物品名称(使用 colorama 确保跨平台兼容)"""
        return f"{self.COLOR_MAP.get(self.rarity, Fore.WHITE)}{self.name}{Style.RESET_ALL}"

class Equipment(Item):
    def __init__(self, name: str, item_type: ItemType, slot: EquipmentSlot, 
                 stats: Dict[str, Any], description: str = "", rarity: Rarity = Rarity.COMMON, 
                 value: int = 0, requirements: Optional[Dict[str, int]] = None):
        super().__init__(name, item_type, description, rarity, value)
        self.slot = slot
        self.stats = stats
        self.requirements = requirements or {}
    
    def can_equip(self, player: 'Player') -> bool:
        for attr, value in self.requirements.items():
            if getattr(player, attr, 0) < value:
                return False
        return True

class Consumable(Item):
    def __init__(self, name: str, effects: Dict[str, Any], description: str = "", 
                 rarity: Rarity = Rarity.COMMON, value: int = 0, quantity: int = 1):
        super().__init__(name, ItemType.CONSUMABLE, description, rarity, value)
        self.effects = effects
        self.quantity = quantity
    
    def use(self, player: 'Player') -> bool:
        if self.quantity <= 0:
            print("物品数量不足!")
            return False
            
        success = True
        for effect, value in self.effects.items():
            if effect == "heal":
                player.hp = min(player.hp + value, player.max_hp)
                print(f"恢复了{value}点生命值!")
            elif effect == "restore_mp":
                player.magic = min(player.magic + value, player.max_magic)
                print(f"恢复了{value}点魔法值!")
            elif effect == "status":
                if isinstance(value, str):
                    player.add_status_effect(value)
                    print(f"获得了{value}效果!")
                else:
                    print("无效的状态效果!")
                    success = False
            else:
                print(f"未知效果: {effect}")
                success = False
        
        return success

class Quest:
    def __init__(self, name: str, description: str, objectives: Dict[str, int], 
                 rewards: Dict[str, Any], status: QuestStatus = QuestStatus.NOT_STARTED):
        self.name = name
        self.description = description
        self.objectives = objectives  # {objective: target, ...}
        self.rewards = rewards  # {exp: int, items: [], gold: int, etc.}
        self.status = status
        self.progress = {obj: 0 for obj in objectives.keys()}
    
    def update_progress(self, objective: str, amount: int = 1) -> None:
        if self.status != QuestStatus.IN_PROGRESS:
            return
        
        if objective in self.progress:
            self.progress[objective] += amount
            print(f"任务更新: {objective} ({self.progress[objective]}/{self.objectives[objective]})")
            
            if all(self.progress[obj] >= target for obj, target in self.objectives.items()):
                self.complete()
    
    def complete(self) -> Dict[str, Any]:
        self.status = QuestStatus.COMPLETED
        print(f"\n=== 任务完成: {self.name} ===")
        print("获得奖励:")
        if 'exp' in self.rewards:
            print(f"- 经验值: {self.rewards['exp']}")
        if 'gold' in self.rewards:
            print(f"- 金币: {self.rewards['gold']}")
        if 'items' in self.rewards:
            print(f"- 物品: {', '.join(self.rewards['items'])}")
        if 'title' in self.rewards:
            print(f"- 称号: {self.rewards['title']}")
        return self.rewards
    
    def fail(self) -> None:
        self.status = QuestStatus.FAILED
        print(f"任务失败: {self.name}")

class Enemy:
    def __init__(
        self,
        name: str,
        hp: int,
        attack: int,
        defense: int = 0,
        skills: Optional[List[Dict[str, Any]]] = None,
        exp_value: Optional[int] = None,
        loot: Optional[Dict[str, Union[int, Item]]] = None
    ):
        self.name = name
        self.max_hp = hp
        self.hp = hp
        self.attack = attack
        self.defense = defense
        self.skills = skills if skills is not None else []
        self.exp_value = exp_value if exp_value is not None else hp // 2
        self.loot = loot if loot is not None else self.generate_loot()
        self.status_effects: List[StatusEffect] = []
    
    def generate_loot(self) -> Dict[str, Union[int, Item]]:
        loot_table = {
            'common': [('药草', 0.6), ('金币', 0.5), ('魔法水晶', 0.3)],
            'uncommon': [('高级治疗药水', 0.4), ('魔法卷轴', 0.3)],
            'rare': [('稀有装备', 0.1)]
        }
        
        loot = {}
        for rarity, items in loot_table.items():
            for item_name, chance in items:
                if random.random() < chance:
                    if item_name == '金币':
                        amount = random.randint(5, 20)
                        loot[item_name] = loot.get(item_name, 0) + amount
                    else:
                        loot[item_name] = loot.get(item_name, 0) + 1
        return loot
    
    def use_skill(self, player: 'Player') -> bool:
        for skill in self.skills:
            if random.random() < skill.get('chance', 0.3):
                print(f"{self.name}使用了{skill['name']}!")
                if 'damage' in skill:
                    damage = skill['damage'] - random.randint(0, player.get_defense()//2)
                    player.hp -= max(damage, 1)
                    print(f"对你造成{max(damage, 1)}点伤害!")
                if 'heal' in skill:
                    heal = skill['heal']
                    self.hp = min(self.hp + heal, self.max_hp)
                    print(f"{self.name}恢复了{heal}点HP!")
                if 'effect' in skill:
                    player.add_status_effect(skill['effect'])
                return True
        return False
    
    def add_status_effect(self, effect: str) -> None:
        if effect not in [se.value for se in self.status_effects]:
            self.status_effects.append(StatusEffect(effect))
            print(f"{self.name}受到了{effect}效果!")
    
    def clear_status_effects(self) -> None:
        if self.status_effects:
            print(f"{self.name}清除了所有状态效果!")
        self.status_effects = []

class GameMap:
    def __init__(self, size: int = 5):
        self.size = size
        self.grid = [[random.choice(list(TerrainType)).value for _ in range(size)] for _ in range(size)]
        self.grid[0][0] = TerrainType.STARTING_POINT.value
        self.grid[size-1][size-1] = TerrainType.DRAGON_LAIR.value
        self.grid[size//2][size//2] = TerrainType.VILLAGE.value
        self.grid[size//3][size//3] = TerrainType.RUINS.value
        self.player_x = 0
        self.player_y = 0
        self.revealed = [[False for _ in range(size)] for _ in range(size)]
        self.revealed[0][0] = True
        self.dungeon_level = 0
        self.dungeon_entrance = (0, 0)
    
    def display(self) -> None:
        terrain_symbols = {
            '平原': '·', '森林': '♣', '山地': '▲', 
            '起始点': 'S', '巨龙巢穴': 'D', 
            '村庄': 'V', '古老遗迹': 'R'
        }
    
        print("  " + " ".join(str(i) for i in range(self.size)))  # 列坐标
        for y in range(self.size):
            print(y, end=" ")  # 行坐标
            for x in range(self.size):
                if x == self.player_x and y == self.player_y:
                    print("P", end=" ")
                elif self.revealed[y][x]:  # 修正坐标顺序
                    terrain = self.grid[y][x]
                    print(terrain_symbols.get(terrain, '?'), end=" ")
                else:
                    print("?", end=" ")
            print()
    
    def enter_dungeon(self, player: 'Player') -> bool:
        if self.dungeon_level == 0:
            self.dungeon_level = 1
            self.dungeon_entrance = (player.player_x, player.player_y)
            return True
        return False
    
    def descend_dungeon(self, player: 'Player') -> bool:
        if self.dungeon_level < 3:  # 假设地牢有3层
            self.dungeon_level += 1
            return True
        print("已经到达地牢最底层!")
        return False

class NPC:
    def __init__(self, name: str, role: str, dialogue_tree: Dict[str, Any]):
        self.name = name
        self.role = role
        self.dialogue_tree = dialogue_tree
        self.current_node = 'start'
    
    def replace_text_variables(self, text: str, player: 'Player', quests: Dict[str, Quest]) -> str:
        """替换对话文本中的变量"""
        replacements = {
            '{player_gold}': str(player.gold),
            '{player_attack}': str(player.get_attack()),
            '{player_name}': player.name,
            '{player_title}': player.title
        }
        
        for var, val in replacements.items():
            text = text.replace(var, val)
        
        if '{quest_name}' in text:
            quest_name = self.dialogue_tree[self.current_node].get('quest')
            if quest_name:
                text = text.replace('{quest_name}', quest_name)
        
        return text
    
    def talk(self, player: 'Player', quests: Dict[str, Quest]) -> None:
        while True:
            try:
                node = self.dialogue_tree.get(self.current_node, {})
                if not node:
                    print("对话节点不存在!")
                    break
                    
                text = self.replace_text_variables(node['text'], player, quests)
                print(f"\n{self.name}({self.role}): {text}")
                
                if 'options' not in node:
                    break
                    
                # 显示对话选项
                for i, option in enumerate(node['options'], 1):
                    print(f"{i}. {option['text']}")
                print("0. 结束对话")
                
                # 处理玩家选择
                try:
                    choice = input("选择回应(0-{}): ".format(len(node['options'])))
                    if choice == '0':
                        self.current_node = 'start'  # 重置对话到开始节点
                        break
                        
                    choice_idx = int(choice) - 1
                    if choice_idx < 0 or choice_idx >= len(node['options']):
                        print("无效选择,请重新输入")
                        continue
                        
                    selected = node['options'][choice_idx]
                    self.current_node = selected['next']
                    
                    if 'effect' in selected:
                        self.handle_effect(selected['effect'], player, quests)
                        
                except (ValueError, IndexError):
                    print("请输入有效的选项数字")
                    continue
                    
            except Exception as e:
                print(f"对话系统错误: {e}")
                break
    
    def handle_effect(self, effect: str, player: 'Player', quests: Dict[str, Quest]) -> None:
        if effect == 'buy_item':
            current_node = self.dialogue_tree[self.current_node]
            item = current_node.get('item')
            price = current_node.get('price')
        
            if not item or price is None:
                print("交易信息错误!")
                return
                
            if player.gold >= price:
                player.gold -= price
                player.add_item(item)
                print(f"购买了 {item.name}!")
            else:
                print(f"金币不足!需要 {price} 金币,你只有 {player.gold} 金币")
        
        elif effect == 'accept_goblin_quest':
            player.add_quest(quests["新手试炼"])
        elif effect == 'accept_dragon_quest':
            player.add_quest(quests["击败巨龙"])
        elif effect == 'complete_quest':
            quest_name = self.dialogue_tree[self.current_node].get('quest')
            if quest_name in [q.name for q in player.quest_log]:
                quest = next(q for q in player.quest_log if q.name == quest_name)
                rewards = quest.complete()
                self.give_rewards(player, rewards)
        elif effect == 'sell_item':
            item_name = self.dialogue_tree[self.current_node]['item']
            price = self.dialogue_tree[self.current_node]['price']
            if item_name in player.inventory:
                player.gold += price
                if isinstance(player.inventory[item_name], Consumable) and player.inventory[item_name].quantity > 1:
                    player.inventory[item_name].quantity -= 1
                else:
                    del player.inventory[item_name]
                print(f"出售了 {item_name}!")
            else:
                print(f"你没有 {item_name}!")
        elif effect == 'equip_item':
            item_name = self.dialogue_tree[self.current_node]['item_name']
            player.equip_item(item_name)
        elif effect == 'craft_dragon_armor':
            required = {'龙鳞': 3, 'gold': 100}
            if all(
                (item == 'gold' and player.gold >= qty) or 
                (item in player.inventory and 
                 isinstance(player.inventory[item], Consumable) and 
                 player.inventory[item].quantity >= qty)
                for item, qty in required.items()
            ):
                player.inventory['龙鳞'].quantity -= 3
                player.gold -= 100
                player.add_item(items["龙鳞铠甲"])
                print("成功打造了龙鳞铠甲!")
            else:
                print("材料不足!需要:3龙鳞+100金")
        elif effect == 'craft_fire_sword':
            required = {'火焰之心': 1, 'gold': 150}
            if all(
                (item == 'gold' and player.gold >= qty) or 
                (item in player.inventory and 
                 isinstance(player.inventory[item], Consumable) and 
                 player.inventory[item].quantity >= qty)
                for item, qty in required.items()
            ):
                player.inventory['火焰之心'].quantity -= 1
                player.gold -= 150
                player.add_item(items["火焰之剑"])
                print("成功打造了火焰之剑!")
            else:
                print("需要:1火焰之心+150金")
        elif effect == 'add_fireheart_quest':
            if "寻找火焰之心" not in [q.name for q in player.quest_log]:
                player.add_quest(quests["寻找火焰之心"])
                print("接受了任务:寻找火焰之心")
    
    def give_rewards(self, player: 'Player', rewards: Dict[str, Any]) -> None:
        if 'exp' in rewards:
            player.gain_exp(rewards['exp'])
        if 'gold' in rewards:
            player.gold += rewards['gold']
            print(f"获得 {rewards['gold']} 金币!")
        if 'items' in rewards:
            for item_name in rewards['items']:
                if item_name in items:
                    player.add_item(items[item_name])
                    print(f"获得 {item_name}!")
        if 'title' in rewards:
            player.title = rewards['title']
            print(f"获得新称号: {rewards['title']}!")

class Player:
    def __init__(self):
        self.name = input('请输入角色名: ')
        self.gender = self.select_gender()
        self.race = self.select_race()
        self.class_type = self.select_class()
        self.set_initial_stats()
        self.inventory: Dict[str, Union[Item, Equipment, Consumable]] = {}
        self.equipment = {slot: None for slot in EquipmentSlot}
        self.quest_log: List[Quest] = []
        self.status_effects: List[StatusEffect] = []
        self.title = "冒险者"
        self.gold = 50
        self.add_class_starting_items()
    
    def clear_status_effects(self) -> None:
        for effect in self.status_effects[:]:
            effect.clear(self)
    
    def select_gender(self) -> Dict[str, str]:
        print("\n选择性别:")
        for i, gender in enumerate(PlayerGender, 1):
            print(f"{i}. {gender.value}")
        choice = input(">> ")
        try:
            return {'name': list(PlayerGender)[int(choice)-1].value}
        except (ValueError, IndexError):
            print("无效选择,默认为男性")
            return {'name': PlayerGender.MALE.value}
        
    def select_race(self) -> Dict[str, Any]:
        print("\n选择种族:")
        for i, race in enumerate(PlayerRace, 1):
            print(f"{i}. {race.value}")
        
        bonuses = {
            PlayerRace.HUMAN: {'hp': 10, 'attack': 2, 'defense': 2, 'magic': 5},
            PlayerRace.ELF: {'hp': 5, 'attack': 1, 'defense': 1, 'magic': 15},
            PlayerRace.DWARF: {'hp': 15, 'attack': 1, 'defense': 5, 'magic': 0},
            PlayerRace.ORC: {'hp': 10, 'attack': 5, 'defense': 0, 'magic': -5},
            PlayerRace.HALFLING: {'hp': 8, 'attack': 0, 'defense': 3, 'magic': 5}
        }
        
        choice = input(">> ")
        try:
            selected = list(PlayerRace)[int(choice)-1]
            return {'name': selected.value, 'bonus': bonuses[selected]}
        except (ValueError, IndexError):
            print("无效选择,默认为人类")
            return {'name': PlayerRace.HUMAN.value, 'bonus': bonuses[PlayerRace.HUMAN]}
    
    def select_class(self) -> Dict[str, Any]:
        print("\n选择职业:")
        for i, cls in enumerate(PlayerClass, 1):
            print(f"{i}. {cls.value}")
        
        bonuses = {
            PlayerClass.WARRIOR: {'hp': 20, 'attack': 5, 'defense': 3, 'magic': 0},
            PlayerClass.MAGE: {'hp': 10, 'attack': 1, 'defense': 1, 'magic': 30},
            PlayerClass.ROGUE: {'hp': 15, 'attack': 8, 'defense': 2, 'magic': 5},
            PlayerClass.CLERIC: {'hp': 15, 'attack': 3, 'defense': 2, 'magic': 20},
            PlayerClass.RANGER: {'hp': 18, 'attack': 6, 'defense': 3, 'magic': 10}
        }
        
        skills = {
            PlayerClass.WARRIOR: ['猛击', '防御姿态'],
            PlayerClass.MAGE: ['火球术', '冰霜新星'],
            PlayerClass.ROGUE: ['背刺', '闪避'],
            PlayerClass.CLERIC: ['治疗术', '神圣打击'],
            PlayerClass.RANGER: ['精准射击', '陷阱设置']
        }
        
        choice = input(">> ")
        try:
            selected = list(PlayerClass)[int(choice)-1]
            return {'name': selected.value, 'bonus': bonuses[selected], 'skills': skills[selected]}
        except (ValueError, IndexError):
            print("无效选择,默认为战士")
            return {'name': PlayerClass.WARRIOR.value, 'bonus': bonuses[PlayerClass.WARRIOR], 'skills': skills[PlayerClass.WARRIOR]}
    
    def set_initial_stats(self) -> None:
        self.max_hp = 80 + self.race['bonus'].get('hp', 0) + self.class_type['bonus'].get('hp', 0)
        self.hp = self.max_hp
        self.attack = 10 + self.race['bonus'].get('attack', 0) + self.class_type['bonus'].get('attack', 0)
        self.defense = 8 + self.race['bonus'].get('defense', 0) + self.class_type['bonus'].get('defense', 0)
        self.max_magic = 30 + self.race['bonus'].get('magic', 0) + self.class_type['bonus'].get('magic', 0)
        self.magic = self.max_magic
        self.skills = self.class_type['skills']
        self.level = 1
        self.exp = 0
        self.exp_to_next = 100
    
    def add_class_starting_items(self) -> None:
        starting_items = {
            PlayerClass.WARRIOR: {'长剑': Equipment("长剑", ItemType.WEAPON, EquipmentSlot.WEAPON, 
                                                  {"attack": 15}, "基础长剑", Rarity.COMMON, 50),
                                '钢盾': Equipment("钢盾", ItemType.ARMOR, EquipmentSlot.ARMOR,
                                                 {"defense": 10}, "钢制盾牌", Rarity.COMMON, 40)},
            PlayerClass.MAGE: {'法杖': Equipment("法杖", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                              {"attack": 8, "magic": 5}, "魔法法杖", Rarity.UNCOMMON, 60),
                             '火焰卷轴': Consumable("火焰卷轴", {"damage": 40}, "造成40点火焰伤害", Rarity.UNCOMMON, 30)},
            PlayerClass.ROGUE: {'匕首': Equipment("匕首", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                               {"attack": 12, "critical": 0.1}, "锋利的匕首", Rarity.COMMON, 45),
                              '皮甲': Equipment("皮甲", ItemType.ARMOR, EquipmentSlot.ARMOR,
                                              {"defense": 8}, "轻便皮甲", Rarity.COMMON, 30)},
            PlayerClass.CLERIC: {'治疗法杖': Equipment("治疗法杖", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                                   {"attack": 8, "heal": 20}, "神圣治疗法杖", Rarity.UNCOMMON, 70),
                               '圣徽': Item("圣徽", ItemType.SPECIAL, "神圣徽章", Rarity.RARE, 50)},
            PlayerClass.RANGER: {'短弓': Equipment("短弓", ItemType.WEAPON, EquipmentSlot.WEAPON,
                                                {"attack": 10, "range": 3}, "狩猎短弓", Rarity.COMMON, 55),
                               '皮甲': Equipment("皮甲", ItemType.ARMOR, EquipmentSlot.ARMOR,
                                              {"defense": 8}, "轻便皮甲", Rarity.COMMON, 30)}
        }
        
        for cls in PlayerClass:
            if self.class_type['name'] == cls.value:
                for item_name, item in starting_items[cls].items():
                    self.add_item(item)
                break
    
    def add_item(self, item: Union[Item, Equipment, Consumable]) -> None:
        """统一添加物品逻辑"""
        if isinstance(item, Consumable):
            existing = next((i for i in self.inventory.values() 
                           if isinstance(i, Consumable) and i.name == item.name), None)
            if existing:
                existing.quantity += item.quantity
            else:
                self.inventory[item.id] = item
        else:
            self.inventory[item.id] = item
    
    def find_item_by_name(self, name: str) -> Optional[Union[Item, Equipment, Consumable]]:
        """通过名称查找物品"""
        return next((item for item in self.inventory.values() if item.name == name), None)
    
    def equip_item(self, item_name: str) -> bool:
        item = self.find_item_by_name(item_name)
        if not item:
            print(f"错误:物品'{item_name}'不在背包中!")
            return False
        
        if not isinstance(item, Equipment):
            print(f"错误:'{item_name}'不是可装备的物品!")
            return False
        
        if not item.can_equip(self):
            print(f"错误:不满足装备'{item_name}'的要求!")
            return False
        
        if self.equipment[item.slot]:
            self.unequip_item(item.slot)
        
        self.equipment[item.slot] = item
        # 从背包移除装备的物品
        del self.inventory[item.id]
        print(f"装备了{item.name}!")
        return True
    
    def unequip_item(self, slot: EquipmentSlot) -> bool:
        if not self.equipment[slot]:
            print(f"你没有装备{slot.value}!")
            return False
        
        item = self.equipment[slot]
        self.add_item(item)
        self.equipment[slot] = None
        print(f"卸下了{item.name}!")
        return True
    
    def use_item(self, item_name: str) -> bool:
        # 先尝试通过名称查找
        item = next((i for i in self.inventory.values() if i.name == item_name), None)
        
        if not item:
            print("你没有这个物品!")
            return False
        
        if not isinstance(item, Consumable):
            print("这个物品不能使用!")
            return False

        if item.use(self):
            item.quantity -= 1
            if item.quantity <= 0:
                # 从背包中移除
                keys_to_remove = [k for k, v in self.inventory.items() if v.name == item_name]
                for key in keys_to_remove:
                    del self.inventory[key]
            return True
        return False
    
    def add_quest(self, quest: Quest) -> None:
        if quest.name not in [q.name for q in self.quest_log]:
            quest.status = QuestStatus.IN_PROGRESS
            self.quest_log.append(quest)
            print(f"接受了新任务: {quest.name}")
    
    def update_quest(self, objective: str, amount: int = 1) -> None:
        for quest in self.quest_log:
            if quest.status == QuestStatus.IN_PROGRESS and objective in quest.objectives:
                quest.update_progress(objective, amount)
    
    def get_attack(self) -> int:
        weapon = self.equipment[EquipmentSlot.WEAPON]
        base = self.attack
        if weapon and isinstance(weapon, Equipment):
            return base + weapon.stats.get('attack', 0)
        return base
    
    def get_defense(self) -> int:
        armor = self.equipment[EquipmentSlot.ARMOR]
        base = self.defense
        if armor and isinstance(armor, Equipment):
            return base + armor.stats.get('defense', 0)
        return base
    
    def add_status_effect(self, effect: str) -> None:
        if effect not in [se.value for se in self.status_effects]:
            self.status_effects.append(StatusEffect(effect))
            print(f"你受到了{effect}效果!")
    
    def clear_status_effects(self) -> None:
        if self.status_effects:
            print("清除了所有状态效果!")
        self.status_effects = []
    
    def gain_exp(self, amount: int) -> None:
        self.exp += amount
        print(f"获得 {amount} 经验值!")
        if self.exp >= self.exp_to_next:
            self.level_up()
    
    def level_up(self) -> None:
        self.level += 1
        self.exp -= self.exp_to_next
        self.exp_to_next = int(self.exp_to_next * 1.5)
        self.max_hp += 10 + self.race['bonus'].get('hp', 0) // 2
        self.hp = self.max_hp
        self.attack += 2 + self.race['bonus'].get('attack', 0) // 2
        self.defense += 1 + self.race['bonus'].get('defense', 0) // 2
        self.max_magic += 5 + self.race['bonus'].get('magic', 0) // 2
        self.magic = self.max_magic
        print(f"""
        === 升级到 Lv{self.level}! ===
        最大HP: {self.max_hp}
        攻击力: {self.attack}
        防御力: {self.defense}
        魔法值: {self.max_magic}
        """)

class Skill:
    """技能类"""
    def __init__(self, name: str, cost: int, effect: Callable):
        self.name = name
        self.cost = cost
        self.effect = effect
    
    def execute(self, player: 'Player', enemy: 'Enemy') -> Tuple[str, bool]:
        """执行技能效果"""
        if player.magic < self.cost:
            return "魔法值不足!", False
        
        player.magic -= self.cost
        return self.effect(player, enemy)

def create_skills() -> Dict[str, Skill]:
    """创建技能库"""
    return {
        '猛击': Skill('猛击', 10, lambda p, e: (
            f"造成{int(p.get_attack() * 1.5)}点伤害!", 
            e.hp - int(p.get_attack() * 1.5)
        )),
        '火球术': Skill('火球术', 15, lambda p, e: (
            "造成25点火焰伤害并附加燃烧效果!", 
            (e.hp - 25, StatusEffect.BURNING)
        )),
        # 其他技能...
    }


# ========== 游戏数据 ==========
def load_game_items() -> Dict[str, Union[Item, Equipment, Consumable]]:
    items_dict = {}
    global items
    items = items_dict

    items_dict.update(
        {
        "药草": Consumable("药草", {"heal": 30}, "恢复30点生命值", Rarity.COMMON, 10),
        "高级治疗药水": Consumable("高级治疗药水", {"heal": 60}, "恢复60点生命值", Rarity.UNCOMMON, 30),
        "魔法水晶": Item("魔法水晶", ItemType.MATERIAL, "蕴含魔力的水晶", Rarity.UNCOMMON, 50),
        "钢铁长剑": Equipment("钢铁长剑", ItemType.WEAPON, EquipmentSlot.WEAPON, 
                            {"attack": 20}, "坚固的钢铁长剑", Rarity.UNCOMMON, 100),
        "秘银铠甲": Equipment("秘银铠甲", ItemType.ARMOR, EquipmentSlot.ARMOR, 
                            {"defense": 15, "max_hp": 20}, "轻便但坚固的铠甲", Rarity.RARE, 150),
        "圣剑": Equipment("圣剑", ItemType.WEAPON, EquipmentSlot.WEAPON,
                        {"attack": 35, "magic": 10}, "传说中的圣剑", Rarity.LEGENDARY, 500,
                        {"level": 5}),
        "龙鳞铠甲": Equipment("龙鳞铠甲", ItemType.ARMOR, EquipmentSlot.ARMOR,
                           {"defense": 25, "fire_resist": 0.5}, "龙鳞制成的铠甲", Rarity.EPIC, 400),
        "铁质护甲": Equipment("铁质护甲", ItemType.ARMOR, EquipmentSlot.ARMOR,
                           {"defense": 12}, "基础铁质护甲", Rarity.COMMON, 80),
        "火焰之心": Item("火焰之心", ItemType.MATERIAL, "炽热的魔法核心", Rarity.EPIC, 300),
        "精铁矿": Item("精铁矿", ItemType.MATERIAL, "高品质的铁矿石", Rarity.UNCOMMON, 80),
        "龙鳞": Item("龙鳞", ItemType.MATERIAL, "坚硬的龙类鳞片", Rarity.RARE, 200),
        "神圣金属": Item("神圣金属", ItemType.MATERIAL, "散发神圣光芒的金属", Rarity.EPIC, 400),
        "火焰之剑": Equipment("火焰之剑", ItemType.WEAPON, EquipmentSlot.WEAPON,
                           {"attack": 30, "fire_damage": 10}, "蕴含火焰之力的剑", Rarity.EPIC, 350)
    }
    )

    """加载游戏物品数据"""
    return items_dict

def load_quests() -> Dict[str, Quest]:
    """加载游戏任务数据"""
    return {
        "新手试炼": Quest(
            "新手试炼",
            "消灭3只哥布林,证明你的实力",
            {"击败哥布林": 3},
            {"exp": 100, "gold": 50, "items": ["铁质护甲"]}
        ),
        "寻找圣剑": Quest(
            "寻找圣剑",
            "在古老遗迹中找到传说中的圣剑",
            {"探索遗迹": 1, "找到圣剑": 1},
            {"exp": 200, "gold": 200, "items": ["圣剑"]}
        ),
        "击败巨龙": Quest(
            "击败巨龙",
            "击败盘踞在北方巢穴中的巨龙",
            {"击败巨龙": 1},
            {"exp": 500, "gold": 500, "items": ["龙鳞铠甲"], "title": "屠龙勇士"}
        ),
        "地牢探险": Quest(
            "地牢探险",
            "探索地牢的最底层",
            {"进入地牢": 1, "到达底层": 1},
            {"exp": 300, "gold": 300, "title": "地牢征服者"}
        ),
         "寻找火焰之心": Quest(
            "寻找火焰之心",
            "为铁匠寻找传说中的锻造材料火焰之心",
            {"获得火焰之心": 1},
            {"exp": 200, "gold": 300, "items": ["火焰之剑"]}
        )
    }

def load_enemies() -> List[Enemy]:
    """加载敌人数据"""
    return [
        Enemy('哥布林', 50, 12, 5, [
            {'name': '偷袭', 'damage': 15, 'chance': 0.2},
            {'name': '毒刃', 'damage': 10, 'effect': StatusEffect.POISONED.value, 'chance': 0.2}
        ], 30, {'药草': 1, '金币': random.randint(5, 15)}),
        Enemy('火焰法师', 70, 20, 8, [
            {'name': '火球术', 'damage': 30, 'effect': StatusEffect.BURNING.value, 'chance': 0.3},
            {'name': '烈焰护盾', 'effect': '防御+10', 'chance': 0.2}
        ], 50, {'魔法水晶': 1, '金币': random.randint(10, 20)}),
        Enemy('巨龙', 200, 40, 25, [
            {'name': '龙息', 'damage': 60, 'effect': StatusEffect.BURNING.value, 'chance': 0.5},
            {'name': '防御强化', 'effect': StatusEffect.DEFENSE_UP.value, 'power': 10, 'chance': 0.2},
            {'name': '恐惧咆哮', 'effect': '攻击下降', 'chance': 0.3},
            {'name': '巨龙威压', 'effect': StatusEffect.STUNNED.value, 'chance': 0.2}
        ], 300, {'金币': 500, '龙鳞': 3, '龙之心': 1}),
        Enemy('火焰元素', 120, 25, 15, [
            {'name': '烈焰冲击', 'damage': 35, 'effect': StatusEffect.BURNING.value, 'chance': 0.4},
            {'name': '熔岩护甲', 'defense': 10, 'chance': 0.3}
        ], 80, {'火焰之心': 1, '魔法水晶': 2})
    ]
def create_village_elder() -> NPC:
    """创建村长NPC"""
    dialogue_tree = {
        'start': {
            'text': "欢迎来到我们的村庄,{player_name}。需要什么帮助吗?",
            'options': [
                {'text': "有什么任务可以接吗?", 'next': 'quests'},
                {'text': "关于这个地区有什么信息?", 'next': 'info'},
                {'text': "再见", 'next': 'end'}
            ]
        },
        'quests': {
            'text': "我们正被哥布林困扰,你能帮忙消灭一些吗?",
            'options': [
                {'text': "我愿意帮忙", 'next': 'accept_goblin', 'effect': 'accept_goblin_quest'},
                {'text': "现在没空", 'next': 'start'}
            ]
        },
        # ...其他对话节点...
    }
    return NPC("村长", "村庄长老", dialogue_tree)

def create_blacksmith() -> NPC:
    """创建铁匠NPC"""
    dialogue_tree = {
        'start': {
            'text': "叮当!我是铁匠{player_name},需要打造装备吗?",
            'options': [
                {'text': "我想购买装备", 'next': 'buy'},
                {'text': "我想出售材料", 'next': 'sell'},
                {'text': "再见", 'next': 'end'}
            ]
        },
        # ...其他对话节点...
    }
    return NPC("铁匠", "装备商人", dialogue_tree)

# ========== 游戏功能函数 ==========
def calculate_damage(attacker: Any, defender: Any, base_damage: int) -> int:
    """统一的伤害计算逻辑"""
    defense_reduction = random.randint(0, defender.get_defense() // 2)
    return max(base_damage - defense_reduction, 1)

def battle(player: Player, enemy: Enemy) -> bool:
    print(f"\n遭遇 {enemy.name}!")
    
    while player.hp > 0 and enemy.hp > 0:
        print(f"\n{player.name}: HP {player.hp}/{player.max_hp} | {enemy.name}: HP {enemy.hp}/{enemy.max_hp}")
        print("选择行动: [1]攻击 [2]使用物品 [3]使用技能 [4]逃跑(50%成功率)")
        
        choice = input(">> ")
  
        if choice == '1':  # 攻击
            damage = calculate_damage(player, enemy, player.get_attack())
            enemy.hp -= damage
            print(f"你对{enemy.name}造成{damage}点伤害!")
        elif choice == '2':  # 物品
            if not use_item_menu(player):
                continue
        elif choice == '3':  # 技能
            if not use_skill_menu(player, enemy):
                continue
        elif choice == '4':  # 逃跑
            if random.random() < 0.5:
                print("成功逃脱!")
                player.clear_status_effects()
                return False  # 逃跑成功
            else:
                print("逃跑失败!")
                # 逃跑失败后直接进入敌人回合
                if player.hp <=0:
                    print("\n游戏结束...")
                    return False
        
        # 检查敌人是否被击败
        if enemy.hp <= 0:
            print(f"\n你击败了{enemy.name}!")
            player.gain_exp(enemy.exp_value)
            return True
            
        # 敌人回合
        if not enemy.use_skill(player):
            damage = enemy.attack - random.randint(0, player.get_defense())
            damage = max(damage, 1)
            player.hp -= damage
            print(f"{enemy.name}对你造成{damage}点伤害!")
        
        # 检查状态效果
        if check_status_effects(player, enemy):
            continue
        
        # 检查玩家是否被击败
        if player.hp <= 0:
            break
    
    if player.hp > 0:
        if enemy.hp <= 0:
            print(f"\n你击败了{enemy.name}!")
            player.gain_exp(enemy.exp_value)
            # 处理战利品...
        return True
    else:
        print("\n游戏结束...")
        return False

def check_status_effects(player: Player, enemy: Enemy) -> bool:
    # 处理玩家状态效果
    for effect in player.status_effects[:]:
        print(f"{player.name}的{effect.value}效果剩余{effect.duration}回合")
        if effect.should_remove():
            player.status_effects.remove(effect)
            print(f"{effect.value}效果已解除!")
        if effect == StatusEffect.POISONED:
            damage = 5
            player.hp -= damage
            print(f"你因中毒受到{damage}点伤害!")
        elif effect == StatusEffect.BURNING:
            damage = 8
            player.hp -= damage
            print(f"你因燃烧受到{damage}点伤害!")
        elif effect == StatusEffect.FROZEN:
            if random.random() < 0.5:
                print("你被冻结了,无法行动!")
                return True
        elif effect == StatusEffect.STUNNED:
            print("你被眩晕了,无法行动!")
            return True
    
    # 处理敌人状态效果
    for effect in enemy.status_effects[:]:
        if effect == StatusEffect.POISONED:
            damage = 5
            enemy.hp -= damage
            print(f"{enemy.name}因中毒受到{damage}点伤害!")
        elif effect == StatusEffect.BURNING:
            damage = 8
            enemy.hp -= damage
            print(f"{enemy.name}因燃烧受到{damage}点伤害!")
        elif effect == StatusEffect.FROZEN:
            if random.random() < 0.5:
                print(f"{enemy.name}被冻结了,无法行动!")
                return True
        elif effect == StatusEffect.STUNNED:
            print(f"{enemy.name}被眩晕了,无法行动!")
            return True
    
    return False

def use_item_menu(player: Player) -> bool:
    consumables = {name: item for name, item in player.inventory.items() if isinstance(item, Consumable)}
    
    if not consumables:
        print("没有可用的消耗品!")
        return False
    
    print("\n可用物品(0取消):")
    for i, (name, item) in enumerate(consumables.items(), 1):
        print(f"{i}. {name} x{item.quantity} - {item.description}")
    
    choice = input("选择物品: ")
    if choice == '0':
        return False
    
    try:
        item_name = list(consumables.keys())[int(choice)-1]
        return player.use_item(item_name)
    except (ValueError, IndexError):
        print("无效选择!")
        return False

def use_skill_menu(player: Player, enemy: Enemy) -> bool:
    if not player.skills:
        print("没有可用技能!")
        return False
    
    # 定义技能效果
    skills_info = {
        '猛击': {'cost': 10, 'effect': lambda p, e: p.get_attack() * 1.5},
        '火球术': {'cost': 15, 'effect': lambda p, e: 25},
        '冰霜新星': {'cost': 12, 'effect': lambda p, e: (20, StatusEffect.FROZEN)},
        '治疗术': {'cost': 18, 'effect': lambda p, e: (p.max_hp * 0.3, None)},
        '背刺': {'cost': 15, 'effect': lambda p, e: p.get_attack() * 2 if random.random() < 0.7 else p.get_attack()},
        '防御姿态': {'cost': 10, 'effect': lambda p, e: (0, StatusEffect.DEFENSE_UP)}
    }
    
    print("\n可用技能:")
    for i, skill in enumerate(player.skills, 1):
        info = skills_info.get(skill, {'cost': 10})
        print(f"{i}. {skill} (消耗{info['cost']}MP)")
    
    choice = input("选择技能(输入编号,0取消): ")
    if choice == '0':
        return False
    
    try:
        skill = player.skills[int(choice)-1]
        info = skills_info.get(skill, {'cost': 10})
        cost = info['cost']
        
        if player.magic < cost:
            print("魔法值不足!")
            return False
            
        player.magic -= cost
        result = info['effect'](player, enemy)
        
        if isinstance(result, tuple):  # 有额外效果
            damage, effect = result
            if damage > 0:
                damage = int(max(damage - random.randint(0, enemy.defense//2), 1))
                enemy.hp -= damage
                print(f"使用{skill}造成{damage}点伤害!")
            if effect:
                enemy.add_status_effect(effect.value)
        else:
            damage = int(max(result - random.randint(0, enemy.defense//2), 1))
            enemy.hp -= damage
            print(f"使用{skill}造成{damage}点伤害!")
        return True
    except (ValueError, IndexError):
        print("无效选择!")
        return False

def explore_ruins(player: Player) -> bool:
    print("\n你进入了一座古老遗迹,四周墙壁上刻满了神秘的符文...")
    print("1. 调查中央祭坛")
    print("2. 检查左侧石碑")
    print("3. 搜索宝物")
    print("4. 离开遗迹")
    
    choice = input("选择行动: ")
    
    if choice == '1':
        # 检查是否已经完成"寻找圣剑"任务
        quest_completed = any(q.name == "寻找圣剑" and q.status == QuestStatus.COMPLETED 
                            for q in player.quest_log)
        
        # 检查背包是否已有圣剑
        has_sword = any(item.name == "圣剑" for item in player.inventory.values()) or \
                   (player.equipment[EquipmentSlot.WEAPON] and 
                    player.equipment[EquipmentSlot.WEAPON].name == "圣剑")
        
        if not quest_completed and not has_sword:
            print("\n祭坛上插着一把闪耀的剑,剑身上刻着'圣剑'二字")
            player.add_item(items["圣剑"])
            player.update_quest("找到圣剑")
        elif has_sword:
            print("\n祭坛上有一个空槽,形状与你拥有的圣剑吻合")
        else:
            print("\n祭坛空空如也,只有风吹过的声音")
    
    elif choice == '2':
        print("\n石碑上记载着古老的文字:")
        print("'当巨龙苏醒之时,唯有圣剑可将其击败'")
        if not any(q.name == "击败巨龙" for q in player.quest_log):
            player.add_quest(quests["击败巨龙"])
    
    elif choice == '3':
        loot_chance = random.random()
        if loot_chance < 0.3:
            loot = random.choice(['魔法水晶', '古老卷轴', '遗迹钥匙'])
            player.add_item(items.get(loot, Item(loot, ItemType.MATERIAL)))
            print(f"\n在遗迹角落找到了{loot}!")
        elif loot_chance < 0.6:
            print("\n找到了一个宝箱!")
            gold = random.randint(10, 50)
            player.gold += gold
            print(f"获得{gold}金币!")
        else:
            print("\n什么都没找到...")
            
            # 30%几率遇到敌人
            if random.random() < 0.3:
                enemy = random.choice(enemies[:2])  # 只遇到较弱敌人
                print(f"\n惊动了守护遗迹的{enemy.name}!")
                battle(player, enemy)
    
    elif choice == '4':
        print("\n你离开了古老遗迹")
        return False
    
    return True

def visit_village(player: Player, npcs: Dict[str, NPC], quests: Dict[str, Quest]) -> None:
    print("\n你来到了一个宁静的村庄")
    print(f"村民们看到你的称号[{player.title}],纷纷投来敬佩目光")
    
    while True:
        print("\n1. 与村长交谈")
        print("2. 访问铁匠铺")
        print("3. 在旅馆休息")
        print("4. 离开村庄")
        
        choice = input("选择行动: ")
        
        if choice == '1':
            npcs['村长'].talk(player, quests)
        elif choice == '2':
            npcs['铁匠'].talk(player, quests)
        elif choice == '3':
            cost = 20
            print(f"\n旅馆老板: 住一晚只要{cost}金币,要休息吗?")
            if input("(Y/N) ").upper() == 'Y':
                if player.gold >= cost:
                    player.gold -= cost
                    player.hp = player.max_hp
                    player.magic = player.max_magic
                    player.clear_status_effects()
                    print("好好休息了一晚,状态完全恢复了!")
                else:
                    print("金币不足!")
        elif choice == '4':
            print("\n你离开了村庄")
            break

def explore_map(player: Player, game_map: GameMap, npcs: Dict[str, NPC], quests: Dict[str, Quest]) -> bool:
    while True:
        game_map.display()
        print(f"当前位置: ({game_map.player_x}, {game_map.player_y})")
        
        move = input(">> ").upper()
        
        if move == 'Q':
            break
        elif move == 'I':
            manage_inventory(player)
            continue
        elif move == 'M':
            game_map.display()
            continue
        elif move == 'S':
            save_game(player, game_map)
            continue
        elif move == 'H':
            show_help()
            continue
            
        dx, dy = 0, 0
        if move == 'W' and game_map.player_y > 0:
            dy = -1
        elif move == 'S' and game_map.player_y < game_map.size-1:
            dy = 1
        elif move == 'A' and game_map.player_x > 0:
            dx = -1
        elif move == 'D' and game_map.player_x < game_map.size-1:
            dx = 1
            
        if dx != 0 or dy != 0:
            game_map.player_x += dx
            game_map.player_y += dy
            game_map.revealed[game_map.player_y][game_map.player_x] = True  # 修正坐标顺序
            
        current_loc = game_map.grid[game_map.player_y][game_map.player_x]  # 修正坐标顺序
        print(f"\n进入{current_loc}...")
            
        # 特殊地点事件
        if current_loc == '巨龙巢穴':
            dragon = next(e for e in enemies if e.name=='巨龙')
            if battle(player, dragon):  # 与巨龙战斗
                print("\n=== 恭喜你击败了最终BOSS巨龙! ===")
                print(f"你以[{player.title}]的称号载入史册!")
                print("现在返回村庄领取你的奖励吧!")
                return True
            else:
                continue
        elif current_loc == '村庄':
            visit_village(player, npcs, quests)
        elif current_loc == '古老遗迹':
            while explore_ruins(player):
                pass
        elif current_loc == '地牢入口':
            if game_map.enter_dungeon(player):
                explore_dungeon(player, game_map)
            
        # 随机事件
        if random.random() < 0.3 and current_loc not in ['村庄', '古老遗迹']:
            trigger_random_event(player, game_map)
    
    return False

def explore_dungeon(player: Player, game_map: GameMap) -> None:
    while game_map.dungeon_level > 0:
        print(f"\n地牢第{game_map.dungeon_level}层")
        print("1. 探索当前层")
        print("2. 前往下一层")
        print("3. 返回地面")
        
        choice = input("选择行动: ")
        
        if choice == '1':
            # 地牢探索逻辑
            if random.random() < 0.6:
                enemy = random.choice(enemies[:3])
                print(f"\n遭遇了{enemy.name}!")
                if not battle(player, enemy):
                    return
            else:
                loot_chance = random.random()
                if loot_chance < 0.4:
                    loot = random.choice(['药草', '金币', '魔法水晶'])
                    if loot == '金币':
                        amount = random.randint(10, 30)
                        player.gold += amount
                        print(f"找到了{amount}金币!")
                    else:
                        player.add_item(items[loot])
                        print(f"找到了{loot}!")
                elif loot_chance < 0.7:
                    print("什么都没找到...")
                else:
                    print("发现了一个安全的角落,可以休息")
                    player.hp = min(player.hp + 20, player.max_hp)
                    print("恢复了20点生命值")
        
        elif choice == '2':
            if game_map.dungeon_level == 2:  # 地牢最底层
                print("\n你到达了地牢最底层!")
                print("这里盘踞着一只强大的火焰元素!")
                if battle(player, enemies[3]):  # 与火焰元素战斗
                    player.update_quest("到达底层")
                    print("\n你获得了火焰之心!")
                    player.add_item(items["火焰之心"])
            elif not game_map.descend_dungeon(player):
                break
        elif choice == '3':
            print("\n你返回了地面")
            game_map.dungeon_level = 0
            break

def trigger_random_event(player: Player, game_map: GameMap) -> None:
    events = [
        ('找到宝箱!', lambda: player.add_item(Consumable("药草", {"heal": 30}, quantity=2))),
        ('遇到旅行商人...', lambda: trade_with_merchant(player)),
        ('发现一个神秘的祭坛', lambda: restore_health(player)),
        ('什么都没发生', lambda: None),
        ('遭遇敌人!', lambda: battle(player, random.choice(enemies[:3])))
    ]
    
    event = random.choice(events)
    print(f"\n{event[0]}")
    event[1]()

def trade_with_merchant(player: Player) -> None:
    items_for_sale = {
        '药草': 10,
        '高级治疗药水': 30,
        '魔法水晶': 50
    }
    
    print("\n旅行商人: 想买点什么吗?")
    print(f"你拥有的金币: {player.gold}")
    for item, price in items_for_sale.items():
        print(f"- {item}: {price}金币")
    
    choice = input("输入要购买的物品名称(或回车离开): ")
    if choice and choice in items_for_sale:
        price = items_for_sale[choice]
        if player.gold >= price:
            player.gold -= price
            player.add_item(items[choice])
            print(f"购买了{choice}!")
        else:
            print("金币不足!")
    else:
        print("再见!")

def restore_health(player: Player) -> None:
    print("祭坛的光芒治愈了你的伤口!")
    player.hp = player.max_hp
    player.magic = player.max_magic
    player.clear_status_effects()

def show_status(player: Player) -> None:
    print(f"""
    === 角色状态 ===
    名称: {player.name} ({player.race['name']} {player.class_type['name']})
    称号: {player.title}
    等级: {player.level}
    经验: {player.exp}/{player.exp_to_next}
    HP: {player.hp}/{player.max_hp}
    魔法: {player.magic}/{player.max_magic}
    攻击: {player.get_attack()} (基础:{player.attack})
    防御: {player.get_defense()} (基础:{player.defense})
    金币: {player.gold}
    状态: {', '.join(se.value for se in player.status_effects) if player.status_effects else '无'}
    装备:
      武器: {player.equipment[EquipmentSlot.WEAPON].name if player.equipment[EquipmentSlot.WEAPON] else '无'}
      护甲: {player.equipment[EquipmentSlot.ARMOR].name if player.equipment[EquipmentSlot.ARMOR] else '无'}
      饰品: {player.equipment[EquipmentSlot.ACCESSORY].name if player.equipment[EquipmentSlot.ACCESSORY] else '无'}
    """)

def manage_inventory(player: Player) -> None:
    while True:
        print("\n=== 物品管理 ===")
        print("1. 查看物品")
        print("2. 使用物品")
        print("3. 装备物品")
        print("4. 卸下装备")
        print("5. 返回")
        
        choice = input("选择操作: ")
        
        if choice == '1':
            show_inventory(player)
        elif choice == '2':
            use_item_menu(player)
        elif choice == '3':
            item_name = input("输入要装备的物品名: ")
            player.equip_item(item_name)
        elif choice == '4':
            slot = input("输入要卸下的装备部位(武器/护甲/饰品): ")
            try:
                slot_enum = EquipmentSlot(slot)
                player.unequip_item(slot_enum)
            except ValueError:
                print("无效的装备部位!")
        elif choice == '5':
            break

def show_inventory_page(items: List[Item], page: int, page_size: int = 10):
    start = (page-1)*page_size
    end = start + page_size
    for i, item in enumerate(items[start:end], start+1):
        # 显示物品信息...
        pass

def show_inventory(player: Player) -> None:
    if not player.inventory:
        print("背包是空的!")
        return
    
    print("\n=== 背包 ===")
    print("物品:")
    for item in player.inventory.values():
        if isinstance(item, Consumable):
            print(f"  {item.name} x{item.quantity} - {item.description}")
        else:
            print(f"  {item.name} - {item.description}")
    
    print("\n装备:")
    for slot, item in player.equipment.items():
        print(f"  {slot.value}: {item.name if item else '无'}")

def show_quest_log(player: Player) -> None:
    if not player.quest_log:
        print("你当前没有任务")
        return
    
    print("\n=== 任务日志 ===")
    for quest in player.quest_log:
        print(f"{quest.name} ({quest.status.value})")
        print(f"  {quest.description}")
        for obj, target in quest.objectives.items():
            progress = quest.progress[obj]
            print(f"  - {obj}: {progress}/{target}")
        print()


def get_save_path() -> Path:
    """获取存档文件路径(与脚本同目录)"""
    script_dir = Path(__file__).parent.absolute()
    return script_dir / "rpg_save.json"


def save_game(player: Player, game_map: GameMap) -> None:
    def convert_for_serialization(obj: Any) -> Any:
        """转换对象为可JSON序列化的格式"""
        if isinstance(obj, (ItemType, Rarity, EquipmentSlot, QuestStatus, StatusEffect, TerrainType)):
            return obj.value
        if isinstance(obj, Enum):
            return obj.name
        if isinstance(obj, (dict, list, tuple, set)):
            return {k: convert_for_serialization(v) for k, v in obj.items()} if isinstance(obj, dict) else [convert_for_serialization(x) for x in obj]
        if hasattr(obj, '__dict__'):
            return convert_for_serialization(obj.__dict__)
        return obj

    data = {
        'version': CURRENT_VERSION,
        'player': {
            'name': player.name,
            'gender': convert_for_serialization(player.gender),
            'race': convert_for_serialization(player.race),
            'class_type': convert_for_serialization(player.class_type),
            'hp': player.hp,
            'max_hp': player.max_hp,
            'attack': player.attack,
            'defense': player.defense,
            'magic': player.magic,
            'max_magic': player.max_magic,
            'level': player.level,
            'exp': player.exp,
            'exp_to_next': player.exp_to_next,
            'gold': player.gold,
            'title': player.title,
            'status_effects': convert_for_serialization(player.status_effects),
            'skills': player.skills,
            'inventory': {item.id: convert_for_serialization(item.__dict__) 
                         for item in player.inventory.values()},
            'equipment': {slot.value: item.id if item else None 
                         for slot, item in player.equipment.items()},
            'quest_log': [convert_for_serialization(quest.__dict__) 
                         for quest in player.quest_log]
        },
        'map': {
            'grid': game_map.grid,
            'player_x': game_map.player_x, 
            'player_y': game_map.player_y,
            'revealed': game_map.revealed,
            'size': game_map.size,
            'dungeon_level': game_map.dungeon_level,
            'dungeon_entrance': game_map.dungeon_entrance
        }
    }
    save_path = get_save_path()
    
    try:
        # 检查目录是否可写
        if not os.access(save_path.parent, os.W_OK):
            raise PermissionError(f"没有写入权限: {save_path.parent}")
        
        # 保存文件
        with open(save_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        
        print(f"游戏已成功保存到: {save_path}")
        
    except PermissionError:
        print("无法保存游戏:没有写入权限。请检查游戏目录是否可写。")
    except Exception as e:
        print(f"保存游戏时发生意外错误: {str(e)}")
        print("系统已自动创建备份并尝试恢复。")

def backup_and_reset_save(save_path: Path = None) -> None:
    """备份并重置损坏的存档"""
    try:
        if save_path is None:
            save_path = get_save_path()
        
        if save_path.exists():
            # 创建备份
            timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_path = save_path.parent / f"rpg_save_backup_{timestamp}.json"
            shutil.copy(str(save_path), str(backup_path))
            print(f"已创建损坏存档的备份: {backup_path}")
            
            # 删除损坏的存档
            save_path.unlink()
            print(f"已移除损坏的存档文件: {save_path}")
    except Exception as e:
        print(f"备份存档失败: {str(e)}")

def validate_save_data(data: dict) -> bool:
    """验证存档数据完整性"""
    required_fields = ['player', 'map', 'version']
    if not all(field in data for field in required_fields):
        return False
        
    player_fields = ['name', 'hp', 'max_hp', 'attack', 'defense']
    return all(field in data['player'] for field in player_fields)


def load_game() -> Tuple[Optional[Player], Optional[GameMap]]:
    save_path = get_save_path()
    
    try:
        if not save_path.exists():
            raise FileNotFoundError(f"存档文件不存在: {save_path}")
        
        with open(save_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            
        if not validate_save_data(data):
            raise ValueError("存档数据验证失败")
        
        # 版本验证
        save_version = data.get('version', 1.0)
        handle_version_differences(save_version)
        
        # 迁移旧版本存档数据
        data = migrate_save_data(data)
        
        # 创建游戏地图
        game_map = GameMap(data['map']['size'])
        game_map.grid = data['map']['grid']
        game_map.player_x = data['map']['player_x']
        game_map.player_y = data['map']['player_y']
        game_map.revealed = data['map']['revealed']
        game_map.dungeon_level = data['map']['dungeon_level']
        game_map.dungeon_entrance = tuple(data['map']['dungeon_entrance'])
        
        # 创建玩家角色
        player = Player()
        player_data = data['player']
        
        # 设置玩家属性
        player.name = player_data['name']
        player.gender = {'name': player_data['gender']['name']}
        player.race = {
            'name': player_data['race']['name'],
            'bonus': player_data['race']['bonus']
        }
        player.class_type = {
            'name': player_data['class_type']['name'],
            'bonus': player_data['class_type']['bonus'],
            'skills': player_data['class_type']['skills']
        }
        player.hp = player_data['hp']
        player.max_hp = player_data['max_hp']
        player.attack = player_data['attack']
        player.defense = player_data['defense']
        player.magic = player_data['magic']
        player.max_magic = player_data['max_magic']
        player.level = player_data['level']
        player.exp = player_data['exp']
        player.exp_to_next = player_data['exp_to_next']
        player.gold = player_data['gold']
        player.title = player_data['title']
        player.skills = player_data['skills']
        
        # 恢复状态效果
        player.status_effects = [
            StatusEffect(effect) for effect in player_data['status_effects']
        ]
        
        # 恢复物品栏
        player.inventory = {}
        for item_id, item_data in player_data['inventory'].items():
            item_type = safe_enum_convert(item_data['type'], ItemType)
            rarity = safe_enum_convert(item_data['rarity'], Rarity)
            
            if item_type == ItemType.WEAPON or item_type == ItemType.ARMOR:
                slot = safe_enum_convert(item_data['slot'], EquipmentSlot)
                item = Equipment(
                    item_data['name'], item_type, slot,
                    item_data['stats'], item_data['description'],
                    rarity, item_data['value'], item_data.get('requirements')
                )
            elif item_type == ItemType.CONSUMABLE:
                item = Consumable(
                    item_data['name'], item_data['effects'],
                    item_data['description'], rarity,
                    item_data['value'], item_data['quantity']
                )
            else:
                item = Item(
                    item_data['name'], item_type,
                    item_data['description'], rarity,
                    item_data['value']
                )
            
            item.id = item_id
            player.inventory[item_id] = item
        
        # 恢复装备
        player.equipment = {slot: None for slot in EquipmentSlot}
        for slot_name, item_id in player_data['equipment'].items():
            if item_id:
                slot = safe_enum_convert(slot_name, EquipmentSlot)
                player.equipment[slot] = player.inventory[item_id]
        
        # 恢复任务日志
        player.quest_log = []
        for quest_data in player_data['quest_log']:
            quest = Quest(
                quest_data['name'],
                quest_data['description'],
                quest_data['objectives'],
                quest_data['rewards'],
                safe_enum_convert(quest_data['status'], QuestStatus)
            )
            quest.progress = quest_data['progress']
            player.quest_log.append(quest)
        
        return player, game_map
        
    except Exception as e:
        print(f"加载失败: {str(e)}")
        backup_and_reset_save(save_path)  # 确保传递了save_path
        return None, None

def handle_version_differences(save_version: float) -> None:
    """处理版本差异"""
    if save_version > CURRENT_VERSION:
        print(Fore.RED + f"\n警告:存档来自较新版本(v{save_version})")
        print("可能导致兼容性问题" + Style.RESET_ALL)
        if input("仍要尝试加载吗?(y/n): ").lower() != 'y':
            raise ValueError("用户取消加载高版本存档")
    
    elif save_version < CURRENT_VERSION:
        print(f"\n存档版本: v{save_version} → 当前版本: v{CURRENT_VERSION}")
        show_relevant_changes(save_version)
        
        if input("是否继续加载?(y/n): ").lower() != 'y':
            raise ValueError("用户取消加载旧版本存档")

def show_relevant_changes(old_version: float) -> None:
    """显示版本间重要变更"""
    print("\n主要变更内容:")
    for ver, changes in sorted(UpdateLog.VERSION_HISTORY.items()):
        if old_version < ver <= CURRENT_VERSION:
            print(f"\n版本 v{ver}:")
            for change in changes[:3]:  # 只显示前3条重要变更
                print(f" - {change}")
    
    print(Fore.YELLOW + "\n注意:旧存档可能需要数据迁移" + Style.RESET_ALL)

def migrate_save_data(data: dict) -> dict:
    """增强版存档数据迁移"""
    version = data.get('version', 1.0)
    
    # 确保基本结构存在
    data.setdefault('player', {}).setdefault('skills', [])
    data['player'].setdefault('status_effects', [])
    
    # 版本1.0 → 1.1 迁移
    if version < 1.1:
        data['player'].setdefault('title', '冒险者')
        data['player'].setdefault('status_effects', [])
        data['version'] = 1.1
    
    # 版本1.1 → 1.2 迁移
    if version < 1.2:
        for quest in data['player'].get('quest_log', []):
            quest.setdefault('progress', {obj: 0 for obj in quest.get('objectives', {})})
        data['version'] = 1.2
    
    # 版本1.2 → 1.5 迁移
    if version < 1.5:
        data['map'].setdefault('dungeon_level', 0)
        data['map'].setdefault('dungeon_entrance', [0, 0])
        
        # 确保物品有ID
        inventory = data['player'].get('inventory', {})
        for item_id, item_data in inventory.items():
            item_data.setdefault('id', item_id)
        
        data['version'] = CURRENT_VERSION
    
    # 验证迁移后的数据
    required_player_fields = ['name', 'hp', 'max_hp', 'attack', 'defense']
    for field in required_player_fields:
        if field not in data['player']:
            raise ValueError(f"迁移后缺少必要字段: player.{field}")
    
    return data

def get_valid_input(prompt: str, valid_choices: List[str]) -> str:
    while True:
        choice = input(prompt).strip().upper()
        if choice in valid_choices:
            return choice
        print(f"无效输入,请选择: {', '.join(valid_choices)}")


def show_help() -> None:
    print(Fore.CYAN + "="*50)
    print("  RPG游戏帮助手册".center(40))
    print("="*50 + Style.RESET_ALL)
    
    help_sections = [
        ("基本控制", [
            "移动: W(上), A(左), S(下), D(右)",
            "菜单: I(物品), M(地图), Q(退出当前场景)",
            "系统: S(保存), H(帮助), ESC(返回/退出)"
        ]),
        ("角色系统", [
            "5个种族: 人类、精灵、矮人、兽人、半身人",
            "5个职业: 战士、法师、盗贼、牧师、游侠",
            "升级提升属性,装备增强能力"
        ]),
        ("战斗系统", [
            "[1]攻击 - 基础武器攻击",
            "[2]物品 - 使用背包中的消耗品",
            "[3]技能 - 职业专属技能(消耗MP)",
            "[4]逃跑 - 50%几率脱离战斗"
        ]),
        ("任务系统", [
            "主线任务: 击败巨龙",
            "支线任务: 新手试炼、寻找圣剑等",
            "完成任务获得经验、金币和特殊奖励"
        ]),
        ("物品系统", [
            "装备: 武器、护甲、饰品",
            "消耗品: 药水、卷轴等",
            "材料: 用于打造高级装备",
            "背包容量: 100个物品栏位"
        ]),
        ("实用技巧", [
            "1. 定期保存游戏进度",
            "2. 不同地形会遇到不同敌人",
            "3. 完成任务可获得稀有装备",
            "4. 收集材料可打造高级装备",
            "5. 状态异常时回村庄休息可清除"
        ])
    ]
    
    for section, items in help_sections:
        print(Fore.YELLOW + f"\n◆ {section}:" + Style.RESET_ALL)
        for item in items:
            print(f"  {Fore.GREEN}•{Style.RESET_ALL} {item}")
    
    print(Fore.CYAN + "\n" + "="*50)
    input("按回车键返回主菜单..." + Style.RESET_ALL)

def main_menu() -> str:
    """显示主菜单并获取用户选择"""
    while True:
        print(Fore.YELLOW + "="*50)
        print("  RPG冒险游戏".center(40))
        print("="*50 + Style.RESET_ALL)
        print("1. 开始新游戏")
        print("2. 继续游戏")
        print("3. 游戏帮助")
        print("4. 更新日志")
        print("5. 退出游戏")
        print(Fore.YELLOW + "="*50 + Style.RESET_ALL)
        
        choice = input("请输入选项(1-5): ").strip()
        if choice in ('1', '2', '3', '4', '5'):
            return choice
        print(Fore.RED + "无效输入,请重新选择!" + Style.RESET_ALL)


def create_new_player() -> Player:
    """创建新玩家角色"""
    return Player()

def show_game_help() -> None:
    """显示游戏帮助"""
    show_help()
    input("\n按回车键返回主菜单...")

def confirm_exit() -> None:
    """确认退出游戏"""
    if input("确定要退出游戏吗?(y/n): ").lower() == 'y':
        print("感谢游玩,再见!")
        sys.exit(0)



def check_for_updates() -> None:
    """处理更新检查的用户界面"""
    print("\n=== 检查更新 ===")
    if UpdateLog.check_for_updates():
        input("\n按回车键返回主菜单...")
    else:
        input("\n按回车键返回主菜单...")


def run_game_loop(player: Player, game_map: GameMap, npcs: Dict[str, NPC], quests: Dict[str, Quest]) -> None:
    """运行游戏主循环"""
    print(f"\n欢迎来到RPG世界,{player.name}!")
    print(f"你是一名{player.race['name']} {player.class_type['name']},开始你的冒险吧!")
    
    while True:
        print("\n1. 探索地图")
        print("2. 查看状态")
        print("3. 管理物品")
        print("4. 查看任务")
        print("5. 保存游戏")
        print("6. 返回主菜单")
        
        choice = input("选择操作: ")
        
        if choice == '1':
            if explore_map(player, game_map, npcs, quests):
                break  # 游戏胜利
        elif choice == '2':
            show_status(player)
        elif choice == '3':
            manage_inventory(player)
        elif choice == '4':
            show_quest_log(player)
        elif choice == '5':
            save_game(player, game_map)
        elif choice == '6':
            if input("确定要返回主菜单吗?未保存的进度将丢失(y/n): ").lower() == 'y':
                break


items: Dict[str, Union[Item, Equipment, Consumable]] = None
def initialize_game() -> None:
    """初始化游戏资源"""
    global items, quests, npcs, enemies
    items = load_game_items()
    quests = load_quests()
    enemies = load_enemies()
    npcs = {
        '村长': create_village_elder(),
        '铁匠': create_blacksmith()
    }
    
    return items, quests, npcs, enemies

def show_update_log() -> None:
    """显示更新日志界面"""
    print("\n=== 更新日志 ===")
    UpdateLog.show_version_history()
    input("\n按回车键返回主菜单...")

# 全局游戏数据
items, quests, npcs, enemies = initialize_game()

def main() -> None:
    try:
        print(Fore.YELLOW + "="*50)
        print("  欢迎来到RPG冒险世界".center(40))
        print("="*50 + Style.RESET_ALL)
        
        player = None
        game_map = None
        
        # 主菜单循环
        while True:
            choice = main_menu()
            
            if choice == '1':  # 新游戏
                player = create_new_player()
                game_map = GameMap()
                run_game_loop(player, game_map, npcs, quests)
                break
                
            elif choice == '2':  # 继续游戏
                player, game_map = load_game()
                if player:
                    run_game_loop(player, game_map, npcs, quests)
                    break
                    
            elif choice == '3':  # 游戏帮助
                show_game_help()
                
            elif choice == '4':  # 更新日志
                UpdateLog.show_version_history()
                input("\n按回车键返回主菜单...")
                
            elif choice == '5':  # 退出
                if input("确定要退出游戏吗?(y/n): ").lower() == 'y':
                    print("感谢游玩,再见!")
                    exit()

        # 主游戏循环
        if player and game_map:
            run_game_loop(player, game_map, npcs, quests)
    
    except KeyboardInterrupt:
        print("\n游戏被用户中断")
    except Exception as e:
        print(f"\n游戏发生错误: {str(e)}")
    finally:
        # 仅在程序未被exit终止时执行
        if 'sys' not in globals() or sys.exc_info()[0] != SystemExit:
            input("按任意键退出...")

if __name__ == '__main__':
    main()

总结

这个Python RPG游戏实现了以下核心功能:

  1. 完整的角色系统:包含种族、职业、属性和成长
  2. 丰富的物品系统:装备、消耗品和材料分类管理
  3. 策略性战斗:回合制战斗与技能系统
  4. 任务驱动:多任务线并行推进
  5. 探索元素:随机地图生成与地点事件
  6. 数据持久化:完善的存档/读档功能

通过这个项目,我们可以学习到:

这个代码基础可以进一步扩展,比如添加图形界面、更多游戏内容或网络多人功能。