394 lines
14 KiB
Python
394 lines
14 KiB
Python
|
|
"""
|
||
|
|
效果系统
|
||
|
|
定义各种游戏效果的实现
|
||
|
|
"""
|
||
|
|
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()
|