212 lines
8.8 KiB
Python
212 lines
8.8 KiB
Python
|
|
"""
|
|||
|
|
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
|