""" 重新设计的战场系统 符合KARDS真实的3条战线布局:玩家1支援线 - 共用前线 - 玩家2支援线 """ from typing import List, Optional, Dict, Tuple, Union from dataclasses import dataclass from uuid import UUID from ..core.enums import LineType from ..units.unit import Unit @dataclass class HQ: """总部类 - 作为支援线上的特殊目标""" defense: int = 20 current_defense: int = 20 player_id: str = "" position_index: int = 2 # HQ默认在支援线中间位置 def take_damage(self, damage: int) -> int: """总部受到伤害""" actual_damage = min(damage, self.current_defense) self.current_defense -= actual_damage return actual_damage def is_destroyed(self) -> bool: """判断总部是否被摧毁""" return self.current_defense <= 0 def __str__(self) -> str: return f"HQ ({self.current_defense}/{self.defense})" class BattleLine: """战线类 - 支持单位和HQ的紧凑排列""" def __init__(self, line_type: LineType, max_objectives: int = 5, hq: Optional[HQ] = None): self.line_type = line_type self.max_objectives = max_objectives self.objectives: List[Optional[Union[Unit, HQ]]] = [] # 紧凑排列的目标 # 如果有HQ,放在中间位置 if hq: self.objectives.append(hq) hq.position_index = 0 def add_unit(self, unit: Unit) -> bool: """添加单位到战线(自动紧凑排列)""" if len(self.objectives) >= self.max_objectives: return False # 战线已满 self.objectives.append(unit) unit.position = (self.line_type, len(self.objectives) - 1) # 检查烟幕条件 unit.check_smokescreen_conditions() return True def get_hq(self) -> Optional[HQ]: """获取战线上的HQ""" for obj in self.objectives: if isinstance(obj, HQ): return obj return None def get_units(self) -> List[Unit]: """获取战线上的所有单位(不包括HQ)""" units = [] for obj in self.objectives: if isinstance(obj, Unit): units.append(obj) return units def remove_unit(self, unit: Unit) -> bool: """移除单位并重新排列""" try: index = self.objectives.index(unit) self.objectives.pop(index) unit.position = None # 重新分配位置索引 self._reindex_objectives() return True except ValueError: return False def _reindex_objectives(self) -> None: """重新分配所有目标的位置索引""" for i, obj in enumerate(self.objectives): if isinstance(obj, Unit): obj.position = (self.line_type, i) # 重新索引后检查烟幕条件 obj.check_smokescreen_conditions() elif isinstance(obj, HQ): obj.position_index = i def get_unit_at_index(self, index: int) -> Optional[Union[Unit, HQ]]: """获取指定索引位置的目标""" if 0 <= index < len(self.objectives): return self.objectives[index] return None def get_all_units(self) -> List[Unit]: """获取战线上所有单位(不包括HQ)""" return [obj for obj in self.objectives if isinstance(obj, Unit)] def get_all_objectives(self) -> List[Union[Unit, HQ]]: """获取战线上所有目标(包括单位和HQ)""" return self.objectives.copy() def find_unit_index(self, unit: Unit) -> Optional[int]: """查找单位的索引位置""" try: return self.objectives.index(unit) except ValueError: return None def get_adjacent_indices(self, index: int) -> List[int]: """获取相邻位置的索引""" adjacent = [] if index > 0: adjacent.append(index - 1) if index < len(self.objectives) - 1: adjacent.append(index + 1) return adjacent def get_adjacent_objectives(self, index: int) -> List[Union[Unit, HQ]]: """获取相邻的目标""" adjacent_indices = self.get_adjacent_indices(index) return [self.objectives[i] for i in adjacent_indices] def is_full(self) -> bool: """检查战线是否已满""" return len(self.objectives) >= self.max_objectives def is_empty(self) -> bool: """检查战线是否为空""" return len(self.objectives) == 0 def get_objective_count(self) -> int: """获取目标数量""" return len(self.objectives) def __str__(self) -> str: if not self.objectives: return f"{self.line_type}: [空]" obj_strs = [] for i, obj in enumerate(self.objectives): if isinstance(obj, Unit): obj_strs.append(f"{i}:{obj.name}") elif isinstance(obj, HQ): obj_strs.append(f"{i}:HQ") else: obj_strs.append(f"{i}:未知") return f"{self.line_type}: [{', '.join(obj_strs)}]" class Battlefield: """重新设计的战场类 - 3条战线布局""" def __init__(self, player1_id: str, player2_id: str): # 玩家信息 self.player1_id = player1_id self.player2_id = player2_id # 创建HQ self.player1_hq = HQ(player_id=player1_id) self.player2_hq = HQ(player_id=player2_id) # 创建3条战线 self.player1_support = BattleLine(LineType.PLAYER1_SUPPORT, hq=self.player1_hq) self.front_line = BattleLine(LineType.FRONT) # 共用前线,无HQ self.player2_support = BattleLine(LineType.PLAYER2_SUPPORT, hq=self.player2_hq) # 单位快速查找索引 self.unit_registry: Dict[UUID, Unit] = {} # 前线控制权(None表示无人控制) self.front_line_controller: Optional[str] = None def get_player_hq(self, player_id: str) -> Optional[HQ]: """获取玩家的HQ""" if player_id == self.player1_id: return self.player1_hq elif player_id == self.player2_id: return self.player2_hq return None def get_player_support_line(self, player_id: str) -> Optional[BattleLine]: """获取玩家的支援线""" if player_id == self.player1_id: return self.player1_support elif player_id == self.player2_id: return self.player2_support return None def get_line_by_type(self, line_type: LineType) -> Optional[BattleLine]: """根据类型获取战线""" if line_type == LineType.PLAYER1_SUPPORT: return self.player1_support elif line_type == LineType.FRONT: return self.front_line elif line_type == LineType.PLAYER2_SUPPORT: return self.player2_support return None def deploy_unit_to_support(self, unit: Unit, player_id: str) -> bool: """部署单位到玩家支援线""" support_line = self.get_player_support_line(player_id) if not support_line: return False if support_line.add_unit(unit): unit.owner = player_id self.unit_registry[unit.id] = unit return True return False def deploy_unit_to_front(self, unit: Unit, player_id: str) -> bool: """部署单位到前线""" if self.front_line.add_unit(unit): unit.owner = player_id self.unit_registry[unit.id] = unit # 更新前线控制权 self._update_front_line_control() return True return False def _update_front_line_control(self) -> None: """更新前线控制权""" units = self.front_line.get_all_units() if not units: self.front_line_controller = None return # 检查前线上的单位是否都属于同一玩家 owners = set(unit.owner for unit in units) if len(owners) == 1: self.front_line_controller = list(owners)[0] else: self.front_line_controller = None # 混合控制或争夺中 def remove_unit(self, unit: Unit) -> bool: """从战场移除单位""" if not unit.position: return False line_type, _ = unit.position battle_line = self.get_line_by_type(line_type) if battle_line and battle_line.remove_unit(unit): if unit.id in self.unit_registry: del self.unit_registry[unit.id] # 如果是前线单位,更新控制权 if line_type == LineType.FRONT: self._update_front_line_control() return True return False def get_all_units(self, player_id: Optional[str] = None) -> List[Unit]: """获取所有单位,可按玩家筛选""" all_units = [] # 收集所有战线的单位 for line in [self.player1_support, self.front_line, self.player2_support]: all_units.extend(line.get_all_units()) # 按玩家筛选 if player_id: all_units = [unit for unit in all_units if unit.owner == player_id] return all_units def find_unit(self, unit_id: UUID) -> Optional[Unit]: """通过ID查找单位""" return self.unit_registry.get(unit_id) def get_units_with_keyword(self, keyword: str, player_id: Optional[str] = None) -> List[Unit]: """获取具有特定关键词的所有单位""" units = self.get_all_units(player_id) return [unit for unit in units if unit.has_keyword(keyword)] def is_game_over(self) -> Tuple[bool, Optional[str]]: """检查游戏是否结束,返回(是否结束, 胜利者ID)""" if self.player1_hq.is_destroyed(): return True, self.player2_id elif self.player2_hq.is_destroyed(): return True, self.player1_id return False, None def get_valid_attack_targets_for_unit(self, attacker: Unit) -> List[Union[Unit, HQ]]: """获取单位可以攻击的所有目标""" if not attacker.owner or not attacker.position: return [] valid_targets = [] attacker_line, attacker_index = attacker.position # 根据单位类型和位置确定攻击规则 if attacker.unit_type.name == "ARTILLERY": # 火炮可以攻击任意敌方目标 valid_targets = self._get_all_enemy_objectives(attacker.owner) elif attacker.unit_type.name in ["FIGHTER", "BOMBER"]: # 飞机可以攻击任意敌方目标 valid_targets = self._get_all_enemy_objectives(attacker.owner) else: # 常规单位攻击规则 if attacker_line == LineType.FRONT: # 前线单位可以攻击敌方支援线 enemy_id = self.get_enemy_player_id(attacker.owner) enemy_support = self.get_player_support_line(enemy_id) if enemy_support: valid_targets = enemy_support.get_all_objectives() else: # 支援线单位只能攻击前线单位 front_units = self.front_line.get_all_units() enemy_units = [u for u in front_units if u.owner != attacker.owner] valid_targets = enemy_units # 应用守护等规则过滤目标 return self._filter_protected_targets(valid_targets, attacker) def _get_all_enemy_objectives(self, player_id: str) -> List[Union[Unit, HQ]]: """获取所有敌方目标(单位+HQ)""" enemy_id = self.get_enemy_player_id(player_id) if not enemy_id: return [] targets = [] # 敌方支援线目标 enemy_support = self.get_player_support_line(enemy_id) if enemy_support: targets.extend(enemy_support.get_all_objectives()) # 前线敌方单位 front_units = self.front_line.get_all_units() enemy_front_units = [u for u in front_units if u.owner == enemy_id] targets.extend(enemy_front_units) return targets def _filter_protected_targets(self, targets: List[Union[Unit, HQ]], attacker: Unit) -> List[Union[Unit, HQ]]: """过滤受保护的目标""" valid_targets = [] for target in targets: can_attack = True if isinstance(target, Unit): # 检查烟幕保护 if target.has_keyword("SMOKESCREEN"): can_attack = False # 检查守护保护 if self._is_target_guarded(target) and attacker.unit_type.name not in ["BOMBER", "ARTILLERY"]: can_attack = False if can_attack: valid_targets.append(target) return valid_targets def _is_target_guarded(self, target: Union[Unit, HQ]) -> bool: """检查目标是否被守护""" if not isinstance(target, Unit) or not target.position: return False line_type, target_index = target.position battle_line = self.get_line_by_type(line_type) if not battle_line: return False # 检查相邻位置是否有守护单位 adjacent_objectives = battle_line.get_adjacent_objectives(target_index) for obj in adjacent_objectives: if isinstance(obj, Unit) and obj.has_keyword("GUARD"): return True return False def get_enemy_player_id(self, player_id: str) -> Optional[str]: """获取敌方玩家ID""" if player_id == self.player1_id: return self.player2_id elif player_id == self.player2_id: return self.player1_id return None def __str__(self) -> str: front_control = f" (控制: {self.front_line_controller})" if self.front_line_controller else " (无人控制)" return f""" === 战场状态 === {self.player1_support} {self.front_line}{front_control} {self.player2_support} ================== """