260 lines
9.9 KiB
Python
260 lines
9.9 KiB
Python
"""
|
||
目标选择系统
|
||
用于选择能力和效果的作用目标
|
||
"""
|
||
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) |