kards-env/kards_battle/effects/effects.py

394 lines
14 KiB
Python
Raw Normal View History

2025-09-05 17:05:43 +08:00
"""
效果系统
定义各种游戏效果的实现
"""
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, TYPE_CHECKING
from enum import Enum
if TYPE_CHECKING:
from ..units.unit import Unit
from ..battlefield.battlefield import Battlefield
from ..core.enums import UnitType
class EffectType(Enum):
"""效果类型枚举"""
DAMAGE = "damage" # 造成伤害
HEAL = "heal" # 治疗
BUFF_ATTACK = "buff_attack" # 增加攻击力
BUFF_DEFENSE = "buff_defense" # 增加防御力
DEBUFF_ATTACK = "debuff_attack" # 减少攻击力
DEBUFF_DEFENSE = "debuff_defense" # 减少防御力
ADD_KEYWORD = "add_keyword" # 添加关键词
REMOVE_KEYWORD = "remove_keyword" # 移除关键词
MOVE_UNIT = "move_unit" # 移动单位
DESTROY_UNIT = "destroy_unit" # 摧毁单位
SUMMON_UNIT = "summon_unit" # 召唤单位
DRAW_CARD = "draw_card" # 抽卡
GAIN_RESOURCE = "gain_resource" # 获得资源
class Effect(ABC):
"""效果基类"""
def __init__(self, name: str, effect_type: EffectType, description: str = ""):
self.name = name
self.effect_type = effect_type
self.description = description
@abstractmethod
def apply(self, source: 'Unit', target: Any, battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
"""应用效果"""
pass
def can_apply(self, source: 'Unit', target: Any, battlefield: 'Battlefield') -> bool:
"""检查是否可以应用效果"""
return True
def __str__(self) -> str:
return f"{self.name}: {self.description}"
class DamageEffect(Effect):
"""伤害效果"""
def __init__(self, damage: int, name: str = "DAMAGE"):
super().__init__(name, EffectType.DAMAGE, f"造成{damage}点伤害")
self.damage = damage
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
if not isinstance(target, type(source)): # 确保target是Unit类型
return {"success": False, "reason": "Invalid target type"}
# 应用重甲减伤等效果
final_damage = self.damage
# 检查重甲关键词
for keyword in target.keywords:
if keyword.startswith("HEAVY_ARMOR_"):
armor_value = int(keyword.split("_")[-1])
final_damage = max(0, final_damage - armor_value)
break
actual_damage = target.stats.take_damage(final_damage)
result = {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"damage_dealt": actual_damage,
"final_damage": final_damage,
"target_destroyed": not target.stats.is_alive()
}
# 如果目标被摧毁,从战场移除
if not target.stats.is_alive():
battlefield.remove_unit(target)
return result
class HealEffect(Effect):
"""治疗效果"""
def __init__(self, heal_amount: int, name: str = "HEAL"):
super().__init__(name, EffectType.HEAL, f"治疗{heal_amount}")
self.heal_amount = heal_amount
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
actual_heal = target.stats.heal(self.heal_amount)
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"heal_amount": actual_heal
}
class BuffAttackEffect(Effect):
"""攻击力增益效果"""
def __init__(self, attack_bonus: int, duration: int = -1, name: str = "BUFF_ATTACK"):
super().__init__(name, EffectType.BUFF_ATTACK, f"攻击力+{attack_bonus}")
self.attack_bonus = attack_bonus
self.duration = duration # -1表示永久
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
target.stats.attack += self.attack_bonus
# 如果有持续时间,添加到临时修正器
if self.duration > 0:
if "temporary_buffs" not in target.temporary_modifiers:
target.temporary_modifiers["temporary_buffs"] = []
target.temporary_modifiers["temporary_buffs"].append({
"type": "attack",
"value": self.attack_bonus,
"duration": self.duration
})
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"attack_bonus": self.attack_bonus,
"new_attack": target.stats.attack
}
class BuffDefenseEffect(Effect):
"""防御力增益效果"""
def __init__(self, defense_bonus: int, duration: int = -1, name: str = "BUFF_DEFENSE"):
super().__init__(name, EffectType.BUFF_DEFENSE, f"防御力+{defense_bonus}")
self.defense_bonus = defense_bonus
self.duration = duration
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
target.stats.defense += self.defense_bonus
target.stats.current_defense += self.defense_bonus
if self.duration > 0:
if "temporary_buffs" not in target.temporary_modifiers:
target.temporary_modifiers["temporary_buffs"] = []
target.temporary_modifiers["temporary_buffs"].append({
"type": "defense",
"value": self.defense_bonus,
"duration": self.duration
})
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"defense_bonus": self.defense_bonus,
"new_defense": target.stats.defense
}
class AddKeywordEffect(Effect):
"""添加关键词效果"""
def __init__(self, keyword: str, name: str = "ADD_KEYWORD"):
super().__init__(name, EffectType.ADD_KEYWORD, f"获得{keyword}")
self.keyword = keyword
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
target.add_keyword(self.keyword)
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"keyword_added": self.keyword
}
class RemoveKeywordEffect(Effect):
"""移除关键词效果"""
def __init__(self, keyword: str, name: str = "REMOVE_KEYWORD"):
super().__init__(name, EffectType.REMOVE_KEYWORD, f"失去{keyword}")
self.keyword = keyword
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
had_keyword = target.has_keyword(self.keyword)
target.remove_keyword(self.keyword)
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"keyword_removed": self.keyword,
"had_keyword": had_keyword
}
class DestroyUnitEffect(Effect):
"""摧毁单位效果"""
def __init__(self, name: str = "DESTROY_UNIT"):
super().__init__(name, EffectType.DESTROY_UNIT, "摧毁目标单位")
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
# 直接将单位防御力设为0
target.stats.current_defense = 0
battlefield.remove_unit(target)
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"unit_destroyed": True
}
class MoveUnitEffect(Effect):
"""移动单位效果"""
def __init__(self, from_line, to_line, name: str = "MOVE_UNIT"):
super().__init__(name, EffectType.MOVE_UNIT, f"{from_line}移动到{to_line}")
self.from_line = from_line
self.to_line = to_line
def apply(self, source: 'Unit', target: 'Unit', battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
if not target.position:
return {"success": False, "reason": "Target not on battlefield"}
current_line_type, current_pos = target.position
# 检查是否可以移动
if current_line_type != self.from_line:
return {"success": False, "reason": "Target not on source line"}
# 获取目标战线
target_line = battlefield.get_player_line(target.owner, self.to_line)
if not target_line:
return {"success": False, "reason": "Invalid target line"}
# 查找空位
empty_positions = target_line.get_empty_positions()
if not empty_positions:
return {"success": False, "reason": "Target line is full"}
# 从当前位置移除
current_line = battlefield.get_player_line(target.owner, current_line_type)
if current_line:
current_line.remove_unit(current_pos)
# 移动到新位置(选择第一个空位)
new_pos = empty_positions[0]
target_line.deploy_unit(target, new_pos)
return {
"success": True,
"effect_type": self.effect_type.value,
"target_id": target.id,
"from_position": (current_line_type, current_pos),
"to_position": (self.to_line, new_pos)
}
class CompositeEffect(Effect):
"""复合效果 - 可以包含多个子效果"""
def __init__(self, effects: List[Effect], name: str = "COMPOSITE_EFFECT"):
descriptions = [effect.description for effect in effects]
description = "; ".join(descriptions)
super().__init__(name, EffectType.DAMAGE, description) # 使用DAMAGE作为默认类型
self.effects = effects
def apply(self, source: 'Unit', target: Any, battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
results = []
for effect in self.effects:
if effect.can_apply(source, target, battlefield):
result = effect.apply(source, target, battlefield, context)
results.append(result)
# 如果目标已被摧毁,停止应用后续效果
if (isinstance(target, type(source)) and
hasattr(target, 'stats') and
not target.stats.is_alive()):
break
return {
"success": True,
"effect_type": "composite",
"sub_effects": results
}
class ConditionalEffect(Effect):
"""条件效果 - 只在满足条件时应用"""
def __init__(self, effect: Effect, condition: callable, name: str = "CONDITIONAL_EFFECT"):
super().__init__(name, effect.effect_type, f"条件: {effect.description}")
self.effect = effect
self.condition = condition
def can_apply(self, source: 'Unit', target: Any, battlefield: 'Battlefield') -> bool:
return self.condition(source, target, battlefield)
def apply(self, source: 'Unit', target: Any, battlefield: 'Battlefield',
context: Dict[str, Any] = None) -> Dict[str, Any]:
if not self.can_apply(source, target, battlefield):
return {
"success": False,
"reason": "Condition not met",
"effect_type": self.effect_type.value
}
return self.effect.apply(source, target, battlefield, context)
class EffectBuilder:
"""效果构建器 - 用于创建复杂效果"""
def __init__(self):
self.effects = []
def add_damage(self, damage: int) -> 'EffectBuilder':
"""添加伤害效果"""
self.effects.append(DamageEffect(damage))
return self
def add_heal(self, heal_amount: int) -> 'EffectBuilder':
"""添加治疗效果"""
self.effects.append(HealEffect(heal_amount))
return self
def add_buff_attack(self, bonus: int, duration: int = -1) -> 'EffectBuilder':
"""添加攻击力增益"""
self.effects.append(BuffAttackEffect(bonus, duration))
return self
def add_buff_defense(self, bonus: int, duration: int = -1) -> 'EffectBuilder':
"""添加防御力增益"""
self.effects.append(BuffDefenseEffect(bonus, duration))
return self
def add_keyword(self, keyword: str) -> 'EffectBuilder':
"""添加关键词"""
self.effects.append(AddKeywordEffect(keyword))
return self
def remove_keyword(self, keyword: str) -> 'EffectBuilder':
"""移除关键词"""
self.effects.append(RemoveKeywordEffect(keyword))
return self
def add_conditional(self, effect: Effect, condition: callable) -> 'EffectBuilder':
"""添加条件效果"""
self.effects.append(ConditionalEffect(effect, condition))
return self
def build_single(self) -> Optional[Effect]:
"""构建单个效果(如果只有一个)"""
if len(self.effects) == 1:
return self.effects[0]
elif len(self.effects) > 1:
return CompositeEffect(self.effects)
return None
def build_composite(self, name: str = "COMPOSITE_EFFECT") -> CompositeEffect:
"""构建复合效果"""
return CompositeEffect(self.effects, name)
def build_all(self) -> List[Effect]:
"""构建所有效果的列表"""
return self.effects.copy()