kards-env/kards_battle/core/unit_combat_rules.py

212 lines
8.8 KiB
Python
Raw Permalink Normal View History

2025-09-05 17:05:43 +08:00
"""
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