class_name Player extends RefCounted ## Player - Represents a player's game state var player_index: int = 0 var player_name: String = "Player" # Zones var deck: Zone var hand: Zone var field_forwards: Zone var field_backups: Zone var damage_zone: Zone var break_zone: Zone # Resources var cp_pool: CPPool # Game state var is_first_player: bool = false var has_mulliganed: bool = false # Constants const MAX_HAND_SIZE: int = 5 const MAX_BACKUPS: int = 5 const DAMAGE_TO_LOSE: int = 7 func _init(index: int, name: String = "") -> void: player_index = index player_name = name if name != "" else "Player %d" % (index + 1) # Initialize zones deck = Zone.new(Enums.ZoneType.DECK, index) hand = Zone.new(Enums.ZoneType.HAND, index) field_forwards = Zone.new(Enums.ZoneType.FIELD_FORWARDS, index) field_backups = Zone.new(Enums.ZoneType.FIELD_BACKUPS, index) damage_zone = Zone.new(Enums.ZoneType.DAMAGE, index) break_zone = Zone.new(Enums.ZoneType.BREAK, index) # Initialize CP pool cp_pool = CPPool.new() ## Setup the player's deck from a list of card IDs func setup_deck(card_ids: Array[String]) -> void: for card_id in card_ids: var card_data = CardDatabase.get_card(card_id) if card_data: var card = CardInstance.new(card_data, player_index) deck.add_card(card) # Shuffle the deck deck.shuffle() ## Draw cards from deck to hand func draw_cards(count: int) -> Array[CardInstance]: var drawn: Array[CardInstance] = [] for i in range(count): if deck.is_empty(): break # Can't draw from empty deck var card = deck.pop_top_card() if card: hand.add_card(card) drawn.append(card) return drawn ## Check if player can draw (deck not empty) func can_draw() -> bool: return not deck.is_empty() ## Get current damage count func get_damage_count() -> int: return damage_zone.get_count() ## Check if player has lost (7+ damage) func has_lost() -> bool: return get_damage_count() >= DAMAGE_TO_LOSE ## Take damage (move cards from deck to damage zone) func take_damage(amount: int) -> Array[CardInstance]: var damage_cards: Array[CardInstance] = [] for i in range(amount): if deck.is_empty(): break var card = deck.pop_top_card() if card: damage_zone.add_card(card) damage_cards.append(card) return damage_cards ## Discard a card from hand to generate CP func discard_for_cp(card: CardInstance) -> bool: if not hand.has_card(card): return false # Light/Dark cards cannot be discarded for CP if card.is_light_or_dark(): return false hand.remove_card(card) break_zone.add_card(card) # Generate 2 CP of the card's element var element = card.get_element() cp_pool.add_cp(element, 2) return true ## Dull a backup to generate CP func dull_backup_for_cp(card: CardInstance) -> bool: if not field_backups.has_card(card): return false if not card.is_backup(): return false if card.is_dull(): return false card.dull() # Generate 1 CP of the backup's element var element = card.get_element() cp_pool.add_cp(element, 1) return true ## Play a card from hand to field func play_card(card: CardInstance) -> bool: if not hand.has_card(card): return false # Check if we can afford it if not cp_pool.can_afford_card(card.card_data): return false # Check field restrictions if card.is_backup(): if field_backups.get_count() >= MAX_BACKUPS: return false # Check unique name restriction if not card.card_data.is_generic: if card.is_forward() and field_forwards.has_card_with_name(card.card_data.name): return false if card.is_backup() and field_backups.has_card_with_name(card.card_data.name): return false # Check Light/Dark restriction if card.is_light_or_dark(): if field_forwards.has_light_or_dark() or field_backups.has_light_or_dark(): return false # Pay the cost if not cp_pool.spend_for_card(card.card_data): return false # Move to field hand.remove_card(card) if card.is_forward(): field_forwards.add_card(card) card.state = Enums.CardState.ACTIVE elif card.is_backup(): field_backups.add_card(card) card.state = Enums.CardState.DULL # Backups enter dull card.entered_field() return true ## Break a card (move from field to break zone) func break_card(card: CardInstance) -> bool: var removed = false if field_forwards.has_card(card): field_forwards.remove_card(card) removed = true elif field_backups.has_card(card): field_backups.remove_card(card) removed = true if removed: break_zone.add_card(card) return true return false ## Activate all dull cards (Active Phase) func activate_all() -> void: for card in field_forwards.get_dull_cards(): card.activate() for card in field_backups.get_dull_cards(): card.activate() ## Discard down to hand size (End Phase) func discard_to_hand_limit() -> Array[CardInstance]: var discarded: Array[CardInstance] = [] while hand.get_count() > MAX_HAND_SIZE: # For now, just discard the last card # In actual game, player would choose var card = hand.pop_top_card() if card: break_zone.add_card(card) discarded.append(card) return discarded ## End of turn cleanup func end_turn_cleanup() -> void: # Clear CP pool cp_pool.clear() # Reset temporary effects on field cards for card in field_forwards.get_cards(): card.end_turn_cleanup() for card in field_backups.get_cards(): card.end_turn_cleanup() ## Start of turn setup func start_turn() -> void: # Increment turn counter for field cards for card in field_forwards.get_cards(): card.start_turn() for card in field_backups.get_cards(): card.start_turn() ## Get all cards on field func get_all_field_cards() -> Array[CardInstance]: var cards: Array[CardInstance] = [] cards.append_array(field_forwards.get_cards()) cards.append_array(field_backups.get_cards()) return cards ## Get forwards that can attack func get_attackable_forwards() -> Array[CardInstance]: var attackers: Array[CardInstance] = [] for card in field_forwards.get_cards(): if card.can_attack(): attackers.append(card) return attackers ## Get forwards that can block func get_blockable_forwards() -> Array[CardInstance]: var blockers: Array[CardInstance] = [] for card in field_forwards.get_cards(): if card.can_block(): blockers.append(card) return blockers func _to_string() -> String: return "[Player: %s, Hand: %d, Forwards: %d, Backups: %d, Damage: %d]" % [ player_name, hand.get_count(), field_forwards.get_count(), field_backups.get_count(), damage_zone.get_count() ]