kards-env/kards_battle/cards/card.py

339 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
卡牌基类和各种卡牌类型定义
"""
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