kards-env/kards_battle/effects/target_selectors.py

260 lines
9.9 KiB
Python
Raw Normal View History

2025-09-05 17:05:43 +08:00
"""
目标选择系统
用于选择能力和效果的作用目标
"""
from typing import List, Optional, TYPE_CHECKING
from abc import ABC, abstractmethod
if TYPE_CHECKING:
from ..units.unit import Unit
from ..battlefield.battlefield import Battlefield
from ..abilities.abilities import TargetType
from ..core.enums import LineType
class TargetSelector:
"""目标选择器"""
def get_targets_by_type(self, source: 'Unit', battlefield: 'Battlefield',
target_type: TargetType) -> List['Unit']:
"""根据目标类型获取有效目标列表"""
if target_type == TargetType.SELF:
return [source]
elif target_type == TargetType.NO_TARGET:
return []
elif target_type == TargetType.FRIENDLY_UNIT:
friendly_units = battlefield.get_all_units(source.owner)
return [unit for unit in friendly_units if unit.id != source.id]
elif target_type == TargetType.ENEMY_UNIT:
enemy_id = battlefield.get_enemy_player_id(source.owner)
return battlefield.get_all_units(enemy_id) if enemy_id else []
elif target_type == TargetType.ANY_UNIT:
all_units = battlefield.get_all_units()
return [unit for unit in all_units if unit.id != source.id]
elif target_type == TargetType.ALL_FRIENDLY:
return battlefield.get_all_units(source.owner)
elif target_type == TargetType.ALL_ENEMY:
enemy_id = battlefield.get_enemy_player_id(source.owner)
return battlefield.get_all_units(enemy_id) if enemy_id else []
elif target_type == TargetType.ADJACENT_FRIENDLY:
return self.get_adjacent_friendly_units(source, battlefield)
elif target_type == TargetType.FRIENDLY_HQ:
# HQ目标需要特殊处理这里返回空列表
return []
elif target_type == TargetType.ENEMY_HQ:
# HQ目标需要特殊处理这里返回空列表
return []
return []
def get_adjacent_friendly_units(self, source: 'Unit', battlefield: 'Battlefield') -> List['Unit']:
"""获取相邻的友方单位"""
if not source.position:
return []
line_type, position = source.position
battle_line = battlefield.get_player_line(source.owner, line_type)
if not battle_line:
return []
adjacent_units = battle_line.get_adjacent_units(position)
return [unit for unit in adjacent_units if unit.owner == source.owner]
def get_units_in_line(self, source: 'Unit', battlefield: 'Battlefield',
line_type: LineType, friendly: bool = True) -> List['Unit']:
"""获取指定战线上的单位"""
target_player = source.owner if friendly else battlefield.get_enemy_player_id(source.owner)
if not target_player:
return []
battle_line = battlefield.get_player_line(target_player, line_type)
return battle_line.get_all_units() if battle_line else []
def get_units_with_keyword(self, source: 'Unit', battlefield: 'Battlefield',
keyword: str, friendly: bool = True) -> List['Unit']:
"""获取具有指定关键词的单位"""
target_player = source.owner if friendly else battlefield.get_enemy_player_id(source.owner)
return battlefield.get_units_with_keyword(keyword, target_player)
def get_damaged_units(self, source: 'Unit', battlefield: 'Battlefield',
friendly: bool = True) -> List['Unit']:
"""获取受伤的单位"""
target_player = source.owner if friendly else battlefield.get_enemy_player_id(source.owner)
units = battlefield.get_all_units(target_player)
return [unit for unit in units if unit.stats.current_defense < unit.stats.defense]
def get_units_by_type(self, source: 'Unit', battlefield: 'Battlefield',
unit_type, friendly: bool = True) -> List['Unit']:
"""获取指定类型的单位"""
target_player = source.owner if friendly else battlefield.get_enemy_player_id(source.owner)
units = battlefield.get_all_units(target_player)
return [unit for unit in units if unit.unit_type == unit_type]
class TargetFilter:
"""目标过滤器"""
@staticmethod
def filter_by_attack_range(units: List['Unit'], min_attack: int = 0, max_attack: int = float('inf')) -> List['Unit']:
"""按攻击力范围过滤"""
return [unit for unit in units if min_attack <= unit.get_effective_attack() <= max_attack]
@staticmethod
def filter_by_defense_range(units: List['Unit'], min_defense: int = 0, max_defense: int = float('inf')) -> List['Unit']:
"""按防御力范围过滤"""
return [unit for unit in units if min_defense <= unit.stats.current_defense <= max_defense]
@staticmethod
def filter_by_keywords(units: List['Unit'], required_keywords: List[str] = None,
forbidden_keywords: List[str] = None) -> List['Unit']:
"""按关键词过滤"""
if required_keywords is None:
required_keywords = []
if forbidden_keywords is None:
forbidden_keywords = []
filtered = []
for unit in units:
# 检查必需关键词
if required_keywords and not all(unit.has_keyword(kw) for kw in required_keywords):
continue
# 检查禁止关键词
if forbidden_keywords and any(unit.has_keyword(kw) for kw in forbidden_keywords):
continue
filtered.append(unit)
return filtered
@staticmethod
def filter_by_position(units: List['Unit'], line_type: LineType = None,
positions: List[int] = None) -> List['Unit']:
"""按位置过滤"""
filtered = []
for unit in units:
if not unit.position:
continue
unit_line, unit_pos = unit.position
# 检查战线类型
if line_type is not None and unit_line != line_type:
continue
# 检查具体位置
if positions is not None and unit_pos not in positions:
continue
filtered.append(unit)
return filtered
@staticmethod
def get_random_target(units: List['Unit'], count: int = 1) -> List['Unit']:
"""随机选择目标"""
import random
if count >= len(units):
return units.copy()
return random.sample(units, count)
@staticmethod
def get_highest_attack_targets(units: List['Unit'], count: int = 1) -> List['Unit']:
"""选择攻击力最高的目标"""
if not units:
return []
sorted_units = sorted(units, key=lambda u: u.get_effective_attack(), reverse=True)
return sorted_units[:count]
@staticmethod
def get_lowest_defense_targets(units: List['Unit'], count: int = 1) -> List['Unit']:
"""选择防御力最低的目标"""
if not units:
return []
sorted_units = sorted(units, key=lambda u: u.stats.current_defense)
return sorted_units[:count]
class TargetingRule:
"""目标选择规则"""
def __init__(self, name: str):
self.name = name
def apply(self, source: 'Unit', potential_targets: List['Unit'],
battlefield: 'Battlefield') -> List['Unit']:
"""应用目标选择规则"""
return potential_targets
class SmartTargetingRule(TargetingRule):
"""智能目标选择规则"""
def __init__(self):
super().__init__("SMART_TARGETING")
def apply(self, source: 'Unit', potential_targets: List['Unit'],
battlefield: 'Battlefield') -> List['Unit']:
"""智能选择最优目标"""
if not potential_targets:
return []
# 优先级:能一击击杀 > 攻击力高 > 防御力低
killable_targets = [t for t in potential_targets
if t.stats.current_defense <= source.get_effective_attack()]
if killable_targets:
# 在可击杀的目标中选择攻击力最高的
return TargetFilter.get_highest_attack_targets(killable_targets, 1)
# 选择防御力最低的目标
return TargetFilter.get_lowest_defense_targets(potential_targets, 1)
class RandomTargetingRule(TargetingRule):
"""随机目标选择规则"""
def __init__(self):
super().__init__("RANDOM_TARGETING")
def apply(self, source: 'Unit', potential_targets: List['Unit'],
battlefield: 'Battlefield') -> List['Unit']:
"""随机选择目标"""
return TargetFilter.get_random_target(potential_targets, 1)
class PriorityTargetingRule(TargetingRule):
"""优先级目标选择规则"""
def __init__(self, priority_keywords: List[str] = None):
super().__init__("PRIORITY_TARGETING")
self.priority_keywords = priority_keywords or []
def apply(self, source: 'Unit', potential_targets: List['Unit'],
battlefield: 'Battlefield') -> List['Unit']:
"""按优先级选择目标"""
if not potential_targets:
return []
# 按优先级关键词排序
for keyword in self.priority_keywords:
priority_targets = [t for t in potential_targets if t.has_keyword(keyword)]
if priority_targets:
return TargetFilter.get_highest_attack_targets(priority_targets, 1)
# 如果没有优先级目标,选择攻击力最高的
return TargetFilter.get_highest_attack_targets(potential_targets, 1)