339 lines
12 KiB
Python
339 lines
12 KiB
Python
"""
|
||
卡牌基类和各种卡牌类型定义
|
||
"""
|
||
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 |