""" 卡牌基类和各种卡牌类型定义 """ from typing import Optional, Set, List, Dict, Any from dataclasses import dataclass from uuid import uuid4, UUID from abc import ABC, abstractmethod from ..core.enums import Nation, Rarity, CardType, UnitType from ..units.unit import Unit @dataclass class CardStats: """卡牌基础属性""" cost: int # 使用花费 nation: Nation # 所属国家 rarity: Rarity # 稀有度 exile_nations: Optional[Set[Nation]] = None # 流亡国家(可选) def can_be_used_by_nation(self, nation: Nation) -> bool: """判断该卡是否可以被指定国家使用(考虑流亡效果)""" if self.nation == nation: return True if self.exile_nations and nation in self.exile_nations: return True return False class BaseCard(ABC): """所有卡牌的基类""" def __init__( self, name: str, card_type: CardType, cost: int, nation: Nation, rarity: Rarity, exile_nations: Optional[Set[Nation]] = None, description: str = "", parameters: Optional[List] = None ): self.id: UUID = uuid4() self.name = name self.card_type = card_type self.description = description self.stats = CardStats(cost, nation, rarity, exile_nations) self.parameters = parameters or [] # 参数定义列表 def __str__(self) -> str: exile_str = "" if self.stats.exile_nations: exile_nations = [str(n) for n in self.stats.exile_nations] exile_str = f" (流亡: {', '.join(exile_nations)})" return f"{self.name} [{self.card_type}] - {self.stats.cost}费 {self.stats.nation}{exile_str} {self.stats.rarity}" @abstractmethod def can_be_played(self, game_state: Any) -> bool: """检查该卡牌是否可以被打出""" pass @abstractmethod def play_effect(self, game_state: Any, target: Any = None, parameters: Optional[Dict[str, Any]] = None) -> bool: """执行卡牌效果,返回是否成功""" pass def has_parameters(self) -> bool: """检查卡牌是否有参数""" return len(self.parameters) > 0 def get_required_parameters(self) -> List: """获取必需参数列表""" from .card_params import ParameterDefinition return [p for p in self.parameters if isinstance(p, ParameterDefinition) and p.required] def validate_parameters(self, parameters: Dict[str, Any], game_state: Any = None) -> Dict[str, str]: """验证参数,返回错误信息字典""" from .card_params import CardParameterValidator return CardParameterValidator.validate_card_parameters(self.parameters, parameters, game_state) class UnitCard(BaseCard): """单位卡牌""" def __init__( self, name: str, cost: int, nation: Nation, rarity: Rarity, unit_definition_id: str, # 对应的单位定义ID exile_nations: Optional[Set[Nation]] = None, description: str = "", card_id: Optional[str] = None, # YAML文件中的卡牌ID parameters: Optional[List] = None # 参数定义列表 ): # 根据单位定义确定卡牌类型 card_type = self._determine_card_type_from_unit_id(unit_definition_id) super().__init__(name, card_type, cost, nation, rarity, exile_nations, description, parameters) self.unit_definition_id = unit_definition_id self.card_id = card_id # 存储YAML中的卡牌ID def _determine_card_type_from_unit_id(self, unit_id: str) -> CardType: """根据单位ID推断卡牌类型""" # 简单的ID到卡牌类型映射,后续可以优化 if "infantry" in unit_id.lower(): return CardType.UNIT_INFANTRY elif "tank" in unit_id.lower(): return CardType.UNIT_TANK elif "artillery" in unit_id.lower(): return CardType.UNIT_ARTILLERY elif "fighter" in unit_id.lower(): return CardType.UNIT_FIGHTER elif "bomber" in unit_id.lower(): return CardType.UNIT_BOMBER else: return CardType.UNIT_INFANTRY # 默认为步兵 def can_be_played(self, game_state: Any) -> bool: """检查单位卡是否可以被打出""" # 基础检查:玩家是否有足够的kredits current_player = game_state.get_current_player() if current_player.kredits < self.stats.cost: return False # 检查是否有空间部署单位 battlefield = game_state.get_battlefield() # 这里需要根据具体的部署规则来实现 return True def play_effect(self, game_state: Any, target: Any = None, parameters: Optional[Dict[str, Any]] = None) -> bool: """部署单位到战场""" try: from ..units.unit_loader import load_unit # 验证参数 if parameters is None: parameters = {} validation_errors = self.validate_parameters(parameters, game_state) if validation_errors: print(f"参数验证失败: {validation_errors}") return False # 加载单位 unit = load_unit(self.unit_definition_id) if not unit: return False # 部署到战场 battle_engine = game_state.get_battle_engine() current_player_id = game_state.get_current_player_id() # 检查参数中是否指定了位置 deploy_position = parameters.get('position') if deploy_position is not None: # 部署到指定槽位 result = battle_engine.deploy_unit_to_support(unit, current_player_id, deploy_position) elif target: # 兼容旧接口 line_type, position = target result = battle_engine.deploy_unit_to_line(unit, line_type, position, current_player_id) else: # 部署到支援线(默认) result = battle_engine.deploy_unit_to_support(unit, current_player_id) if hasattr(result, 'success') and result.success: # 扣除费用 current_player = game_state.get_current_player() current_player.kredits -= self.stats.cost return True elif isinstance(result, bool) and result: # 如果result直接是bool类型 current_player = game_state.get_current_player() current_player.kredits -= self.stats.cost return True return False except Exception as e: print(f"部署单位失败: {e}") return False class OrderCard(BaseCard): """指令卡牌""" def __init__( self, name: str, cost: int, nation: Nation, rarity: Rarity, effect_callback: callable, # 效果回调函数 exile_nations: Optional[Set[Nation]] = None, description: str = "", target_required: bool = False, parameters: Optional[List] = None ): super().__init__(name, CardType.ORDER, cost, nation, rarity, exile_nations, description, parameters) self.effect_callback = effect_callback self.target_required = target_required def can_be_played(self, game_state: Any) -> bool: """检查指令卡是否可以被打出""" current_player = game_state.get_current_player() if current_player.kredits < self.stats.cost: return False # 如果需要目标,检查是否有有效目标 if self.target_required: # 这里需要根据具体的指令效果来检查 pass return True def play_effect(self, game_state: Any, target: Any = None, parameters: Optional[Dict[str, Any]] = None) -> bool: """执行指令效果""" try: # 验证参数 if parameters is None: parameters = {} validation_errors = self.validate_parameters(parameters, game_state) if validation_errors: print(f"参数验证失败: {validation_errors}") return False # 执行效果回调,传入参数 success = self.effect_callback(game_state, target, parameters) if success: # 扣除费用 current_player = game_state.get_current_player() current_player.kredits -= self.stats.cost return True return False except Exception as e: print(f"指令卡效果执行失败: {e}") return False class CounterCard(BaseCard): """反制卡牌(陷阱卡)""" def __init__( self, name: str, cost: int, nation: Nation, rarity: Rarity, trigger_condition: str, # 触发条件描述 counter_effect: callable, # 反制效果回调 exile_nations: Optional[Set[Nation]] = None, description: str = "", parameters: Optional[List] = None ): super().__init__(name, CardType.COUNTER, cost, nation, rarity, exile_nations, description, parameters) self.trigger_condition = trigger_condition self.counter_effect = counter_effect self.is_set = False # 是否已经设置到场上 def can_be_played(self, game_state: Any) -> bool: """检查反制卡是否可以被打出(设置到场上)""" current_player = game_state.get_current_player() if current_player.kredits < self.stats.cost: return False # 检查是否已经设置了太多反制卡 # 这里可以根据游戏规则限制同时设置的反制卡数量 return True def play_effect(self, game_state: Any, target: Any = None, parameters: Optional[Dict[str, Any]] = None) -> bool: """设置反制卡到场上""" try: # 验证参数 if parameters is None: parameters = {} validation_errors = self.validate_parameters(parameters, game_state) if validation_errors: print(f"参数验证失败: {validation_errors}") return False # 将反制卡设置为激活状态 self.is_set = True # 存储设置时的参数,触发时可能需要用到 self.set_parameters = parameters # 扣除费用 current_player = game_state.get_current_player() current_player.kredits -= self.stats.cost # 将卡牌添加到玩家的已设置反制卡列表 if hasattr(current_player, 'set_counters'): current_player.set_counters.append(self) return True except Exception as e: print(f"设置反制卡失败: {e}") return False def can_trigger(self, game_state: Any, trigger_event: Any) -> bool: """检查是否可以触发反制效果""" if not self.is_set: return False # 这里需要根据trigger_condition和trigger_event来判断 # 暂时返回True,具体实现取决于事件系统 return True def trigger_effect(self, game_state: Any, trigger_event: Any) -> bool: """触发反制效果""" try: success = self.counter_effect(game_state, trigger_event) if success: # 反制卡使用后移除 self.is_set = False current_player = game_state.get_current_player() if self in current_player.set_counters: current_player.set_counters.remove(self) # 将反制卡移到弃牌堆 current_player.card_manager.discard_pile.append(self) return success except Exception as e: print(f"反制效果执行失败: {e}") return False