"""Player class: manages hand, support line, frontline, HP, provisions.""" from card_game.config import ( STARTING_CAPITAL_HP, MAX_PROVISIONS, MAX_HAND_SIZE, MAX_SUPPORT_SLOTS, MAX_FRONTLINE_SLOTS, DECK_SIZE, FATIGUE_START_DAMAGE, FACTIONS, DECK_PRESETS, FIRST_HAND_SIZE, SECOND_HAND_SIZE, ) from card_game.deck import Deck from card_game.card import Card class Player: def __init__(self, faction_id, is_ai=False): faction = FACTIONS[faction_id] self.faction_id = faction_id self.faction = faction self.is_ai = is_ai self.capital_hp = faction["capital_hp"] self.max_capital_hp = faction["capital_hp"] self.provisions = 0 self.max_provisions = 0 self.hand = [] self.support_line = [None] * MAX_SUPPORT_SLOTS self.frontline = [None] * MAX_FRONTLINE_SLOTS self.deck = Deck() self.fatigue_damage = 0 self.turn_number = 0 def build_deck(self): preset = DECK_PRESETS[self.faction_id] self.deck.build(preset["cards"]) def start_game(self, hand_size=None): self.build_deck() if hand_size is None: hand_size = FIRST_HAND_SIZE for _ in range(hand_size): self.draw_card() def start_turn(self, turn_number): self.turn_number = turn_number gained = min(turn_number, MAX_PROVISIONS) self.provisions = gained self.max_provisions = gained # Faction passive: Qi extra provision if self.faction_id == "qi": self.provisions += 1 self.draw_card() # Reset unit flags for unit in self.get_all_units(): unit.reset_turn_flags() if unit.zone == "frontline" and unit.turn_played < turn_number: unit.can_attack = True if unit.zone == "support" and unit.turn_played < turn_number: unit.can_attack = True # Chu healer if self.faction_id == "chu": self._apply_heal_ability() def draw_card(self): if len(self.hand) >= MAX_HAND_SIZE: return card = self.deck.draw() if card: card.zone = "hand" self.hand.append(card) else: self.fatigue_damage += 1 self.capital_hp -= self.fatigue_damage def can_play_card(self, card): if card.cost > self.provisions: return False if card.card_type == "unit": return any(s is None for s in self.support_line) return True def deploy_unit(self, card, slot=-1): if slot < 0: for i, s in enumerate(self.support_line): if s is None: slot = i break if slot < 0 or slot >= len(self.support_line): return None self.support_line[slot] = card card.zone = "support" card.slot = slot card.turn_played = self.turn_number self.provisions -= card.cost self.hand.remove(card) return slot def play_order(self, card): self.provisions -= card.cost self.hand.remove(card) def move_to_frontline(self, unit): op_cost = self._get_op_cost(unit) if self.provisions < op_cost: return -1 slot = -1 for i, s in enumerate(self.frontline): if s is None: slot = i break if slot < 0: return -1 self.support_line[unit.slot] = None self.frontline[slot] = unit unit.zone = "frontline" unit.slot = slot unit.has_moved = True self.provisions -= op_cost if unit.turn_played < self.turn_number: if unit.can_move_and_attack(): unit.can_attack = True return slot def move_to_frontline_free(self, unit): slot = -1 for i, s in enumerate(self.frontline): if s is None: slot = i break if slot < 0: return -1 self.support_line[unit.slot] = None self.frontline[slot] = unit unit.zone = "frontline" unit.slot = slot unit.has_moved = True if unit.turn_played < self.turn_number: unit.can_attack = True return slot def remove_unit(self, unit): if unit.zone == "support": if 0 <= unit.slot < len(self.support_line): self.support_line[unit.slot] = None elif unit.zone == "frontline": if 0 <= unit.slot < len(self.frontline): self.frontline[unit.slot] = None def get_all_units(self): units = [] for u in self.support_line: if u is not None: units.append(u) for u in self.frontline: if u is not None: units.append(u) return units def get_frontline_units(self): return [u for u in self.frontline if u is not None] def get_support_units(self): return [u for u in self.support_line if u is not None] def _get_op_cost(self, unit): cost = unit.op_cost if self.faction_id == "yan" and unit.unit_type == "cavalry": cost = max(0, cost - 1) return cost def _apply_heal_ability(self): healers = [u for u in self.get_all_units() if "heal_all:1" in u.abilities] if healers: for unit in self.get_all_units(): if unit.current_hp < unit.max_hp: unit.current_hp = min(unit.max_hp, unit.current_hp + 1) def get_attack_cost(self, unit): cost = unit.op_cost if self.faction_id == "yan" and unit.unit_type == "cavalry": cost = max(0, cost - 1) return cost def can_afford_attack(self, unit): return self.provisions >= self.get_attack_cost(unit) def cleanup_dead(self): for i in range(len(self.support_line)): u = self.support_line[i] if u is not None and not u.is_alive(): self.support_line[i] = None for i in range(len(self.frontline)): u = self.frontline[i] if u is not None and not u.is_alive(): self.frontline[i] = None