""" KARDS单位战斗规则实现 完整实现各兵种的特殊攻击和防御规则 """ from typing import List, Union, Optional from ..units.unit import Unit from ..battlefield.battlefield import HQ, Battlefield from ..core.enums import UnitType, LineType class UnitCombatRules: """单位战斗规则管理器""" @staticmethod def can_attack_target(attacker: Unit, target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """检查攻击者是否能攻击目标""" if not attacker.owner or not attacker.position: return False # 不能攻击己方目标 if isinstance(target, Unit) and target.owner == attacker.owner: return False elif isinstance(target, HQ) and target.player_id == attacker.owner: return False # 根据攻击者类型应用规则 if attacker.unit_type == UnitType.INFANTRY: return UnitCombatRules._infantry_can_attack(attacker, target, battlefield) elif attacker.unit_type == UnitType.TANK: return UnitCombatRules._tank_can_attack(attacker, target, battlefield) elif attacker.unit_type == UnitType.ARTILLERY: return UnitCombatRules._artillery_can_attack(attacker, target, battlefield) elif attacker.unit_type == UnitType.FIGHTER: return UnitCombatRules._fighter_can_attack(attacker, target, battlefield) elif attacker.unit_type == UnitType.BOMBER: return UnitCombatRules._bomber_can_attack(attacker, target, battlefield) return False @staticmethod def _infantry_can_attack(attacker: Unit, target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """步兵攻击规则:只能攻击相邻阵线""" attacker_line, _ = attacker.position if isinstance(target, HQ): # 步兵只能从前线攻击敌方支援线的HQ enemy_support_line = battlefield.get_player_support_line( battlefield.get_enemy_player_id(attacker.owner) ) return (attacker_line == LineType.FRONT and enemy_support_line and target in enemy_support_line.get_all_objectives()) if not target.position: return False target_line, _ = target.position # 前线攻击敌方支援线,支援线攻击前线 if attacker_line == LineType.FRONT: # 前线单位可以攻击任一敌方支援线 return target_line in [LineType.PLAYER1_SUPPORT, LineType.PLAYER2_SUPPORT] else: # 支援线只能攻击前线 return target_line == LineType.FRONT @staticmethod def _tank_can_attack(attacker: Unit, target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """坦克攻击规则:与步兵相同的距离限制,但可以一回合内移动+攻击""" return UnitCombatRules._infantry_can_attack(attacker, target, battlefield) @staticmethod def _artillery_can_attack(attacker: Unit, target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """火炮攻击规则:无视攻击距离,无视守护,不受反击""" # 火炮可以攻击任意敌方目标 if isinstance(target, HQ): return target.player_id != attacker.owner else: return target.owner != attacker.owner @staticmethod def _fighter_can_attack(attacker: Unit, target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """战斗机攻击规则:无视攻击距离""" # 战斗机可以攻击任意敌方目标 if isinstance(target, HQ): return target.player_id != attacker.owner else: return target.owner != attacker.owner @staticmethod def _bomber_can_attack(attacker: Unit, target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """轰炸机攻击规则:无视攻击距离,无视守护,但有战斗机保护限制""" if isinstance(target, HQ): return target.player_id != attacker.owner if target.owner == attacker.owner: return False # 检查目标所在阵线是否有战斗机保护 if isinstance(target, Unit) and target.position: target_line_type, _ = target.position target_line = battlefield.get_line_by_type(target_line_type) if target_line: # 检查同阵线是否有战斗机 for obj in target_line.get_all_objectives(): if (isinstance(obj, Unit) and obj.unit_type == UnitType.FIGHTER and obj.owner == target.owner): # 如果目标不是战斗机,且同阵线有战斗机,则不能攻击 return target.unit_type == UnitType.FIGHTER return True @staticmethod def can_counter_attack(defender: Unit, attacker: Unit) -> bool: """检查防御者是否可以反击""" # 被压制的单位可以反击,只是不能主动攻击 # (PINNED不影响反击能力) # 轰炸机和火炮攻击不受反击 if attacker.unit_type in [UnitType.BOMBER, UnitType.ARTILLERY]: return False # 轰炸机被攻击时不会反击(除非攻击者是战斗机) if defender.unit_type == UnitType.BOMBER: return attacker.unit_type == UnitType.FIGHTER return True @staticmethod def is_protected_by_guard(target: Union[Unit, HQ], battlefield: Battlefield) -> bool: """检查目标是否被守护保护""" if isinstance(target, HQ): # HQ的守护检查 hq_player = target.player_id support_line = battlefield.get_player_support_line(hq_player) if not support_line: return False hq_index = None objectives = support_line.get_all_objectives() for i, obj in enumerate(objectives): if obj == target: hq_index = i break if hq_index is None: return False # 检查相邻位置是否有守护单位 adjacent_indices = support_line.get_adjacent_indices(hq_index) for idx in adjacent_indices: if idx < len(objectives): obj = objectives[idx] if isinstance(obj, Unit) and obj.has_keyword("GUARD"): return True return False elif isinstance(target, Unit) and target.position: target_line_type, target_index = target.position target_line = battlefield.get_line_by_type(target_line_type) if not target_line: return False # 检查相邻位置是否有守护单位 adjacent_objectives = target_line.get_adjacent_objectives(target_index) for obj in adjacent_objectives: if isinstance(obj, Unit) and obj.has_keyword("GUARD"): return True return False @staticmethod def can_ignore_guard(attacker: Unit) -> bool: """检查攻击者是否可以无视守护""" # 火炮和轰炸机可以无视守护 return attacker.unit_type in [UnitType.ARTILLERY, UnitType.BOMBER] @staticmethod def get_valid_targets(attacker: Unit, battlefield: Battlefield) -> List[Union[Unit, HQ]]: """获取攻击者的所有有效目标""" if not attacker.owner: return [] all_targets = [] enemy_id = battlefield.get_enemy_player_id(attacker.owner) if enemy_id: # 获取敌方所有目标 enemy_support = battlefield.get_player_support_line(enemy_id) if enemy_support: all_targets.extend(enemy_support.get_all_objectives()) # 前线敌方单位 front_units = battlefield.front_line.get_all_units() enemy_front_units = [u for u in front_units if u.owner == enemy_id] all_targets.extend(enemy_front_units) # 过滤出可攻击的目标 valid_targets = [] for target in all_targets: if UnitCombatRules.can_attack_target(attacker, target, battlefield): # 检查守护保护 if UnitCombatRules.is_protected_by_guard(target, battlefield): if UnitCombatRules.can_ignore_guard(attacker): valid_targets.append(target) # 被守护保护且攻击者不能无视守护 else: valid_targets.append(target) return valid_targets