kards-env/kards_battle/effects/target_selectors.py

260 lines
9.9 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 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)