166 lines
3.7 KiB
GDScript
166 lines
3.7 KiB
GDScript
class_name Deck
|
|
extends RefCounted
|
|
|
|
## Deck - Data model for a player's deck
|
|
|
|
signal deck_changed
|
|
|
|
const MIN_CARDS: int = 50
|
|
const MAX_CARDS: int = 50
|
|
const MAX_COPIES: int = 3
|
|
|
|
var name: String = "New Deck"
|
|
var cards: Dictionary = {} # card_id -> count
|
|
|
|
|
|
## Add a card to the deck
|
|
## Returns empty string on success, error message on failure
|
|
func add_card(card_id: String) -> String:
|
|
var current_count = cards.get(card_id, 0)
|
|
if current_count >= MAX_COPIES:
|
|
return "Maximum %d copies allowed" % MAX_COPIES
|
|
|
|
var total = get_total_cards()
|
|
if total >= MAX_CARDS:
|
|
return "Deck is full (%d cards)" % MAX_CARDS
|
|
|
|
cards[card_id] = current_count + 1
|
|
deck_changed.emit()
|
|
return ""
|
|
|
|
|
|
## Remove a card from the deck
|
|
## Returns true if successful
|
|
func remove_card(card_id: String) -> bool:
|
|
if not cards.has(card_id):
|
|
return false
|
|
|
|
cards[card_id] -= 1
|
|
if cards[card_id] <= 0:
|
|
cards.erase(card_id)
|
|
|
|
deck_changed.emit()
|
|
return true
|
|
|
|
|
|
## Set card count directly
|
|
func set_card_count(card_id: String, count: int) -> void:
|
|
if count <= 0:
|
|
cards.erase(card_id)
|
|
else:
|
|
cards[card_id] = mini(count, MAX_COPIES)
|
|
deck_changed.emit()
|
|
|
|
|
|
## Get total number of cards in deck
|
|
func get_total_cards() -> int:
|
|
var total = 0
|
|
for count in cards.values():
|
|
total += count
|
|
return total
|
|
|
|
|
|
## Get count for a specific card
|
|
func get_card_count(card_id: String) -> int:
|
|
return cards.get(card_id, 0)
|
|
|
|
|
|
## Get all unique card IDs in deck
|
|
func get_card_ids() -> Array[String]:
|
|
var ids: Array[String] = []
|
|
for card_id in cards.keys():
|
|
ids.append(card_id)
|
|
return ids
|
|
|
|
|
|
## Validate the deck
|
|
## Returns array of error messages (empty if valid)
|
|
func validate() -> Array[String]:
|
|
var errors: Array[String] = []
|
|
var total = get_total_cards()
|
|
|
|
if total < MIN_CARDS:
|
|
errors.append("Deck needs %d more cards" % (MIN_CARDS - total))
|
|
elif total > MAX_CARDS:
|
|
errors.append("Deck has %d too many cards" % (total - MAX_CARDS))
|
|
|
|
for card_id in cards:
|
|
if cards[card_id] > MAX_COPIES:
|
|
var card_data = CardDatabase.get_card(card_id)
|
|
var card_name = card_data.name if card_data else card_id
|
|
errors.append("%s has too many copies (%d)" % [card_name, cards[card_id]])
|
|
|
|
return errors
|
|
|
|
|
|
## Check if deck is valid
|
|
func is_valid() -> bool:
|
|
return validate().size() == 0
|
|
|
|
|
|
## Convert deck to array of card IDs (for gameplay)
|
|
func to_card_array() -> Array[String]:
|
|
var result: Array[String] = []
|
|
for card_id in cards:
|
|
for i in range(cards[card_id]):
|
|
result.append(card_id)
|
|
return result
|
|
|
|
|
|
## Clear the deck
|
|
func clear() -> void:
|
|
cards.clear()
|
|
deck_changed.emit()
|
|
|
|
|
|
## Get deck statistics
|
|
func get_stats() -> Dictionary:
|
|
var stats = {
|
|
"total": get_total_cards(),
|
|
"unique": cards.size(),
|
|
"elements": {},
|
|
"types": {},
|
|
"cost_curve": {}
|
|
}
|
|
|
|
for card_id in cards:
|
|
var count = cards[card_id]
|
|
var card_data = CardDatabase.get_card(card_id)
|
|
if not card_data:
|
|
continue
|
|
|
|
# Element breakdown
|
|
for element in card_data.elements:
|
|
var elem_name = Enums.element_to_string(element)
|
|
stats.elements[elem_name] = stats.elements.get(elem_name, 0) + count
|
|
|
|
# Type breakdown
|
|
var type_name = Enums.card_type_to_string(card_data.type)
|
|
stats.types[type_name] = stats.types.get(type_name, 0) + count
|
|
|
|
# Cost curve
|
|
var cost_key = str(card_data.cost)
|
|
stats.cost_curve[cost_key] = stats.cost_curve.get(cost_key, 0) + count
|
|
|
|
return stats
|
|
|
|
|
|
## Serialize deck to dictionary (for saving)
|
|
func to_dict() -> Dictionary:
|
|
return {
|
|
"name": name,
|
|
"cards": cards.duplicate(),
|
|
"version": "1.0"
|
|
}
|
|
|
|
|
|
## Load deck from dictionary
|
|
func from_dict(data: Dictionary) -> void:
|
|
name = data.get("name", "Unnamed Deck")
|
|
cards = data.get("cards", {}).duplicate()
|
|
deck_changed.emit()
|
|
|
|
|
|
func _to_string() -> String:
|
|
return "[Deck: %s (%d cards)]" % [name, get_total_cards()]
|