kards-env/kards_battle/events/managers/smokescreen_manager.py

163 lines
5.7 KiB
Python
Raw Normal View History

2025-09-05 17:05:43 +08:00
"""
烟幕关键词管理器
实现所有烟幕相关的复杂规则逻辑
"""
from typing import List, Optional
from ..event_system import EventType, GameEvent, publish_event
from .base import ConditionalKeywordManager, ProtectiveKeywordManager
from ...core.enums import LineType
# 避免循环导入
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ...units.unit import Unit
class SmokescreenManager(ConditionalKeywordManager, ProtectiveKeywordManager):
"""
烟幕管理器
规则
1. 单位移动后失去烟幕
2. 单位攻击后失去烟幕
3. 单位在前线时失去烟幕
4. 单位获得GUARD关键词时失去烟幕
5. 单位离开己方支援线时失去烟幕
6. 烟幕单位不能被攻击
"""
def __init__(self, unit: 'Unit'):
super().__init__(unit, "SMOKESCREEN")
def get_subscribed_events(self) -> List[EventType]:
"""烟幕管理器关心的事件"""
return [
EventType.UNIT_MOVED, # 移动后失去烟幕
EventType.UNIT_ATTACKED, # 攻击后失去烟幕
EventType.UNIT_POSITION_CHANGED, # 位置改变检查
EventType.KEYWORD_ADDED, # 获得关键词时检查冲突
EventType.BEFORE_ATTACK_CHECK, # 保护免受攻击
]
def get_protection_priority(self) -> int:
"""烟幕的保护优先级"""
return 10 # 较高优先级,但不是最高
def check_conditions(self, event: GameEvent) -> bool:
"""
检查烟幕生效条件
烟幕失效条件
1. 单位具有GUARD关键词
2. 单位在前线
3. 单位不在己方支援线
"""
# 检查是否有GUARD关键词冲突
if self.unit.has_keyword("GUARD"):
return False
# 检查位置
if not self.unit.position:
return False
line_type, _ = self.unit.position
# 前线单位不能有烟幕
if line_type == LineType.FRONT:
return False
# 必须在支援线
if line_type not in [LineType.PLAYER1_SUPPORT, LineType.PLAYER2_SUPPORT]:
return False
return True
def handle_specific_event(self, event: GameEvent) -> None:
"""处理特定事件"""
if event.event_type == EventType.UNIT_MOVED:
self._handle_unit_moved(event)
elif event.event_type == EventType.UNIT_ATTACKED:
self._handle_unit_attacked(event)
elif event.event_type == EventType.KEYWORD_ADDED:
self._handle_keyword_added(event)
elif event.event_type == EventType.BEFORE_ATTACK_CHECK:
self.handle_attack_check(event)
def _handle_unit_moved(self, event: GameEvent) -> None:
"""处理单位移动事件"""
if event.source == self.unit and self.active:
self.logger.debug(f"Unit {self.unit.id} moved, removing smokescreen")
self.remove_keyword_from_unit("unit moved")
def _handle_unit_attacked(self, event: GameEvent) -> None:
"""处理单位攻击事件"""
if event.source == self.unit and self.active:
self.logger.debug(f"Unit {self.unit.id} attacked, removing smokescreen")
self.remove_keyword_from_unit("unit attacked")
def _handle_keyword_added(self, event: GameEvent) -> None:
"""处理关键词添加事件"""
if event.target == self.unit:
keyword = event.data.get('keyword')
if keyword == "GUARD" and self.active:
self.logger.debug(f"Unit {self.unit.id} gained GUARD, removing smokescreen")
self.remove_keyword_from_unit("gained GUARD keyword")
def should_protect_from_attack(self, attacker: 'Unit', event: GameEvent) -> bool:
"""判断是否保护单位免受攻击"""
# 烟幕提供完全保护,阻止所有攻击
return True
def _on_deactivate(self, reason: str):
"""烟幕停用时的额外处理"""
# 发布烟幕移除事件
publish_event(GameEvent(
event_type=EventType.KEYWORD_REMOVED,
source=self.unit,
data={
'keyword': self.keyword,
'reason': reason
}
))
@classmethod
def create_for_unit(cls, unit: 'Unit') -> Optional['SmokescreenManager']:
"""
为单位创建烟幕管理器
Args:
unit: 目标单位
Returns:
如果单位有SMOKESCREEN关键词返回管理器实例否则返回None
"""
if unit.has_keyword("SMOKESCREEN"):
manager = cls(unit)
# 立即检查条件,如果不满足则不激活
if not manager.check_conditions(GameEvent(EventType.UNIT_DEPLOYED, source=unit)):
unit.remove_keyword("SMOKESCREEN")
return None
return manager
return None
def __str__(self) -> str:
position_str = f" at {self.unit.position}" if self.unit.position else ""
return f"SmokescreenManager(unit={self.unit.id}{position_str}, active={self.active})"
def setup_smokescreen_for_unit(unit: 'Unit') -> Optional[SmokescreenManager]:
"""
便利函数为单位设置烟幕管理器并自动订阅事件
Args:
unit: 目标单位
Returns:
创建的管理器实例如果没有创建则返回None
"""
manager = SmokescreenManager.create_for_unit(unit)
if manager:
from ..event_system import subscribe_to_events
subscribe_to_events(manager)
manager.logger.debug(f"Set up smokescreen manager for unit {unit.id}")
return manager