游戏可以运行
This commit is contained in:
187
card_game/player.py
Normal file
187
card_game/player.py
Normal file
@@ -0,0 +1,187 @@
|
||||
"""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, STARTING_HAND_SIZE,
|
||||
FATIGUE_START_DAMAGE, FACTIONS, DECK_PRESETS,
|
||||
)
|
||||
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):
|
||||
self.build_deck()
|
||||
for _ in range(STARTING_HAND_SIZE):
|
||||
self.draw_card()
|
||||
|
||||
def start_turn(self, turn_number):
|
||||
self.turn_number = turn_number
|
||||
gained = min(turn_number + 1, 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.is_ranged() 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 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
|
||||
Reference in New Issue
Block a user