269 lines
9.1 KiB
Python
269 lines
9.1 KiB
Python
"""
|
|
战场系统实现
|
|
包含HQ、前线、支援线的战场布局和管理
|
|
"""
|
|
from typing import List, Optional, Dict, Tuple
|
|
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 = ""
|
|
|
|
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:
|
|
"""战线类(前线或支援线)"""
|
|
|
|
def __init__(self, line_type: LineType, max_positions: int = 5):
|
|
self.line_type = line_type
|
|
self.max_positions = max_positions
|
|
self.positions: List[Optional[Unit]] = [None] * max_positions
|
|
|
|
def deploy_unit(self, unit: Unit, position: int) -> bool:
|
|
"""在指定位置部署单位"""
|
|
if not self.is_position_valid(position):
|
|
return False
|
|
|
|
if self.positions[position] is not None:
|
|
return False # 位置被占用
|
|
|
|
self.positions[position] = unit
|
|
unit.position = (self.line_type, position)
|
|
return True
|
|
|
|
def remove_unit(self, position: int) -> Optional[Unit]:
|
|
"""移除指定位置的单位"""
|
|
if not self.is_position_valid(position):
|
|
return None
|
|
|
|
unit = self.positions[position]
|
|
if unit:
|
|
self.positions[position] = None
|
|
unit.position = None
|
|
return unit
|
|
|
|
def get_unit_at(self, position: int) -> Optional[Unit]:
|
|
"""获取指定位置的单位"""
|
|
if not self.is_position_valid(position):
|
|
return None
|
|
return self.positions[position]
|
|
|
|
def get_all_units(self) -> List[Unit]:
|
|
"""获取战线上所有单位"""
|
|
return [unit for unit in self.positions if unit is not None]
|
|
|
|
def find_unit_position(self, unit: Unit) -> Optional[int]:
|
|
"""查找单位在战线上的位置"""
|
|
try:
|
|
return self.positions.index(unit)
|
|
except ValueError:
|
|
return None
|
|
|
|
def is_position_valid(self, position: int) -> bool:
|
|
"""检查位置是否有效"""
|
|
return 0 <= position < self.max_positions
|
|
|
|
def is_position_empty(self, position: int) -> bool:
|
|
"""检查位置是否为空"""
|
|
return self.is_position_valid(position) and self.positions[position] is None
|
|
|
|
def get_adjacent_positions(self, position: int) -> List[int]:
|
|
"""获取相邻位置"""
|
|
if not self.is_position_valid(position):
|
|
return []
|
|
|
|
adjacent = []
|
|
if position > 0:
|
|
adjacent.append(position - 1)
|
|
if position < self.max_positions - 1:
|
|
adjacent.append(position + 1)
|
|
return adjacent
|
|
|
|
def get_adjacent_units(self, position: int) -> List[Unit]:
|
|
"""获取相邻单位"""
|
|
adjacent_positions = self.get_adjacent_positions(position)
|
|
return [self.positions[pos] for pos in adjacent_positions
|
|
if self.positions[pos] is not None]
|
|
|
|
def is_full(self) -> bool:
|
|
"""检查战线是否已满"""
|
|
return all(pos is not None for pos in self.positions)
|
|
|
|
def get_empty_positions(self) -> List[int]:
|
|
"""获取所有空位置"""
|
|
return [i for i, pos in enumerate(self.positions) if pos is None]
|
|
|
|
def __str__(self) -> str:
|
|
unit_strs = []
|
|
for i, unit in enumerate(self.positions):
|
|
if unit:
|
|
unit_strs.append(f"{i}:{unit.name}")
|
|
else:
|
|
unit_strs.append(f"{i}:空")
|
|
return f"{self.line_type} [{', '.join(unit_strs)}]"
|
|
|
|
|
|
class Battlefield:
|
|
"""战场类,管理整个战场状态"""
|
|
|
|
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)
|
|
|
|
# 战线
|
|
self.player1_support = BattleLine(LineType.SUPPORT)
|
|
self.player1_front = BattleLine(LineType.FRONT)
|
|
self.player2_support = BattleLine(LineType.SUPPORT)
|
|
self.player2_front = BattleLine(LineType.FRONT)
|
|
|
|
# 单位索引(快速查找)
|
|
self.unit_registry: Dict[UUID, Unit] = {}
|
|
|
|
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_line(self, player_id: str, line_type: LineType) -> Optional[BattleLine]:
|
|
"""获取玩家的战线"""
|
|
if player_id == self.player1_id:
|
|
return self.player1_support if line_type == LineType.SUPPORT else self.player1_front
|
|
elif player_id == self.player2_id:
|
|
return self.player2_support if line_type == LineType.SUPPORT else self.player2_front
|
|
return None
|
|
|
|
def get_enemy_line(self, player_id: str, line_type: LineType) -> Optional[BattleLine]:
|
|
"""获取敌方的战线"""
|
|
enemy_id = self.get_enemy_player_id(player_id)
|
|
return self.get_player_line(enemy_id, line_type) if enemy_id else None
|
|
|
|
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 deploy_unit(self, unit: Unit, player_id: str, line_type: LineType, position: int) -> bool:
|
|
"""部署单位到战场"""
|
|
battle_line = self.get_player_line(player_id, line_type)
|
|
if not battle_line:
|
|
return False
|
|
|
|
if battle_line.deploy_unit(unit, position):
|
|
unit.owner = player_id
|
|
self.unit_registry[unit.id] = unit
|
|
return True
|
|
return False
|
|
|
|
def remove_unit(self, unit: Unit) -> bool:
|
|
"""从战场移除单位"""
|
|
if unit.position is None:
|
|
return False
|
|
|
|
line_type, position = unit.position
|
|
battle_line = self.get_player_line(unit.owner, line_type)
|
|
if battle_line and battle_line.remove_unit(position):
|
|
if unit.id in self.unit_registry:
|
|
del self.unit_registry[unit.id]
|
|
return True
|
|
return False
|
|
|
|
def get_all_units(self, player_id: Optional[str] = None) -> List[Unit]:
|
|
"""获取所有单位,可按玩家筛选"""
|
|
all_units = []
|
|
|
|
lines = []
|
|
if player_id is None:
|
|
lines = [self.player1_support, self.player1_front,
|
|
self.player2_support, self.player2_front]
|
|
else:
|
|
support = self.get_player_line(player_id, LineType.SUPPORT)
|
|
front = self.get_player_line(player_id, LineType.FRONT)
|
|
if support and front:
|
|
lines = [support, front]
|
|
|
|
for line in lines:
|
|
all_units.extend(line.get_all_units())
|
|
|
|
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(self, attacker: Unit) -> List[Unit]:
|
|
"""获取单位可以攻击的所有目标"""
|
|
if not attacker.owner:
|
|
return []
|
|
|
|
enemy_id = self.get_enemy_player_id(attacker.owner)
|
|
if not enemy_id:
|
|
return []
|
|
|
|
enemy_units = self.get_all_units(enemy_id)
|
|
valid_targets = []
|
|
|
|
for target in enemy_units:
|
|
if (attacker.can_attack_target(target, self) and
|
|
target.can_be_attacked_by(attacker, self)):
|
|
valid_targets.append(target)
|
|
|
|
return valid_targets
|
|
|
|
def __str__(self) -> str:
|
|
return f"""
|
|
=== 战场状态 ===
|
|
玩家1 ({self.player1_id}):
|
|
HQ: {self.player1_hq}
|
|
{self.player1_support}
|
|
{self.player1_front}
|
|
|
|
玩家2 ({self.player2_id}):
|
|
HQ: {self.player2_hq}
|
|
{self.player2_support}
|
|
{self.player2_front}
|
|
==================
|
|
""" |