working updates
This commit is contained in:
@@ -14,9 +14,9 @@ func clear() -> void:
|
||||
for element in Enums.Element.values():
|
||||
_cp[element] = 0
|
||||
|
||||
## Add CP of a specific element
|
||||
## Add CP of a specific element (floor at 0 to prevent negative)
|
||||
func add_cp(element: Enums.Element, amount: int) -> void:
|
||||
_cp[element] = _cp.get(element, 0) + amount
|
||||
_cp[element] = max(0, _cp.get(element, 0) + amount)
|
||||
|
||||
## Get CP of a specific element
|
||||
func get_cp(element: Enums.Element) -> int:
|
||||
@@ -29,6 +29,14 @@ func get_total_cp() -> int:
|
||||
total += _cp[element]
|
||||
return total
|
||||
|
||||
## Get total CP of non-Light/Dark elements
|
||||
func get_non_light_dark_cp() -> int:
|
||||
var total = 0
|
||||
for element in _cp:
|
||||
if not Enums.is_light_or_dark(element):
|
||||
total += _cp[element]
|
||||
return total
|
||||
|
||||
## Check if we can afford a card cost
|
||||
func can_afford_card(card_data: CardDatabase.CardData) -> bool:
|
||||
if not card_data:
|
||||
@@ -37,14 +45,19 @@ func can_afford_card(card_data: CardDatabase.CardData) -> bool:
|
||||
var cost = card_data.cost
|
||||
var elements = card_data.elements
|
||||
|
||||
# For Light/Dark cards, just need total CP
|
||||
# Check if this is a Light/Dark card
|
||||
var is_light_dark = false
|
||||
for element in elements:
|
||||
if Enums.is_light_or_dark(element):
|
||||
is_light_dark = true
|
||||
break
|
||||
|
||||
# For Light/Dark cards: need at least 1 CP of any non-Light/Dark element
|
||||
# (Light/Dark cards can be paid with any combination of CP, but you need
|
||||
# at least 1 CP from a regular element - can't pay entirely with L/D CP)
|
||||
if is_light_dark:
|
||||
if get_non_light_dark_cp() < 1:
|
||||
return false
|
||||
return get_total_cp() >= cost
|
||||
|
||||
# For multi-element cards, need at least 1 CP of each element
|
||||
@@ -63,19 +76,39 @@ func can_afford_card(card_data: CardDatabase.CardData) -> bool:
|
||||
return get_total_cp() >= cost
|
||||
|
||||
## Spend CP to pay a card cost
|
||||
## Returns true if successful, false if cannot afford
|
||||
func spend_for_card(card_data: CardDatabase.CardData) -> bool:
|
||||
## Returns dictionary of CP spent by element, or empty dict if cannot afford
|
||||
func spend_for_card(card_data: CardDatabase.CardData) -> Dictionary:
|
||||
if not can_afford_card(card_data):
|
||||
return false
|
||||
return {}
|
||||
|
||||
var cost = card_data.cost
|
||||
var elements = card_data.elements
|
||||
var remaining = cost
|
||||
var spent_cp: Dictionary = {} # Track what we spent
|
||||
var max_iterations = cost + 10 # Safety limit to prevent infinite loops
|
||||
var iterations = 0
|
||||
|
||||
# Check if this is a Light/Dark card
|
||||
var is_light_dark = false
|
||||
for element in elements:
|
||||
if Enums.is_light_or_dark(element):
|
||||
is_light_dark = true
|
||||
break
|
||||
|
||||
# For Light/Dark cards: spend 1 non-Light/Dark CP first (required)
|
||||
if is_light_dark:
|
||||
for element in _cp:
|
||||
if not Enums.is_light_or_dark(element) and _cp[element] > 0:
|
||||
_cp[element] -= 1
|
||||
spent_cp[element] = spent_cp.get(element, 0) + 1
|
||||
remaining -= 1
|
||||
break
|
||||
|
||||
# For multi-element, spend 1 of each required element first
|
||||
if elements.size() > 1:
|
||||
elif elements.size() > 1:
|
||||
for element in elements:
|
||||
_cp[element] -= 1
|
||||
spent_cp[element] = spent_cp.get(element, 0) + 1
|
||||
remaining -= 1
|
||||
|
||||
# For single element (non-Light/Dark), spend at least 1 of that element
|
||||
@@ -83,22 +116,42 @@ func spend_for_card(card_data: CardDatabase.CardData) -> bool:
|
||||
var element = elements[0]
|
||||
if not Enums.is_light_or_dark(element):
|
||||
_cp[element] -= 1
|
||||
spent_cp[element] = spent_cp.get(element, 0) + 1
|
||||
remaining -= 1
|
||||
|
||||
# Spend remaining from any element
|
||||
while remaining > 0:
|
||||
var spent = false
|
||||
for element in _cp:
|
||||
if _cp[element] > 0:
|
||||
_cp[element] -= 1
|
||||
remaining -= 1
|
||||
spent = true
|
||||
break
|
||||
if not spent:
|
||||
push_error("Failed to spend remaining CP")
|
||||
return false
|
||||
# Spend remaining from any element (prefer non-Light/Dark first)
|
||||
while remaining > 0 and iterations < max_iterations:
|
||||
iterations += 1
|
||||
var did_spend = false
|
||||
|
||||
return true
|
||||
# First try non-Light/Dark elements
|
||||
for element in _cp:
|
||||
if not Enums.is_light_or_dark(element) and _cp[element] > 0:
|
||||
_cp[element] -= 1
|
||||
spent_cp[element] = spent_cp.get(element, 0) + 1
|
||||
remaining -= 1
|
||||
did_spend = true
|
||||
break
|
||||
|
||||
# Then try Light/Dark elements if needed
|
||||
if not did_spend:
|
||||
for element in _cp:
|
||||
if _cp[element] > 0:
|
||||
_cp[element] -= 1
|
||||
spent_cp[element] = spent_cp.get(element, 0) + 1
|
||||
remaining -= 1
|
||||
did_spend = true
|
||||
break
|
||||
|
||||
if not did_spend:
|
||||
push_error("Failed to spend remaining CP")
|
||||
return {}
|
||||
|
||||
if remaining > 0:
|
||||
push_error("CP spending exceeded maximum iterations")
|
||||
return {}
|
||||
|
||||
return spent_cp
|
||||
|
||||
## Check if we can afford an ability cost
|
||||
func can_afford_ability(cost: CardDatabase.CostData) -> bool:
|
||||
@@ -131,30 +184,30 @@ func spend_for_ability(cost: CardDatabase.CostData) -> bool:
|
||||
if not can_afford_ability(cost):
|
||||
return false
|
||||
|
||||
# Spend element-specific CP
|
||||
# Spend element-specific CP (use add_cp with negative to ensure floor at 0)
|
||||
if cost.fire > 0:
|
||||
_cp[Enums.Element.FIRE] -= cost.fire
|
||||
add_cp(Enums.Element.FIRE, -cost.fire)
|
||||
if cost.ice > 0:
|
||||
_cp[Enums.Element.ICE] -= cost.ice
|
||||
add_cp(Enums.Element.ICE, -cost.ice)
|
||||
if cost.wind > 0:
|
||||
_cp[Enums.Element.WIND] -= cost.wind
|
||||
add_cp(Enums.Element.WIND, -cost.wind)
|
||||
if cost.lightning > 0:
|
||||
_cp[Enums.Element.LIGHTNING] -= cost.lightning
|
||||
add_cp(Enums.Element.LIGHTNING, -cost.lightning)
|
||||
if cost.water > 0:
|
||||
_cp[Enums.Element.WATER] -= cost.water
|
||||
add_cp(Enums.Element.WATER, -cost.water)
|
||||
if cost.earth > 0:
|
||||
_cp[Enums.Element.EARTH] -= cost.earth
|
||||
add_cp(Enums.Element.EARTH, -cost.earth)
|
||||
if cost.light > 0:
|
||||
_cp[Enums.Element.LIGHT] -= cost.light
|
||||
add_cp(Enums.Element.LIGHT, -cost.light)
|
||||
if cost.dark > 0:
|
||||
_cp[Enums.Element.DARK] -= cost.dark
|
||||
add_cp(Enums.Element.DARK, -cost.dark)
|
||||
|
||||
# Spend generic from any element
|
||||
var generic_remaining = cost.generic
|
||||
while generic_remaining > 0:
|
||||
for element in _cp:
|
||||
if _cp[element] > 0:
|
||||
_cp[element] -= 1
|
||||
add_cp(element, -1)
|
||||
generic_remaining -= 1
|
||||
break
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ extends RefCounted
|
||||
signal game_started
|
||||
signal game_ended(winner_index: int)
|
||||
signal card_played(card: CardInstance, player_index: int)
|
||||
signal summon_cast(card: CardInstance, player_index: int)
|
||||
signal card_moved(card: CardInstance, from_zone: Enums.ZoneType, to_zone: Enums.ZoneType)
|
||||
signal damage_dealt(player_index: int, amount: int, cards: Array[CardInstance])
|
||||
signal forward_broken(card: CardInstance)
|
||||
@@ -106,7 +107,31 @@ func end_main_phase() -> void:
|
||||
turn_manager.advance_phase()
|
||||
|
||||
## Play a card from hand
|
||||
func play_card(player_index: int, card: CardInstance) -> bool:
|
||||
## Returns dictionary of CP spent, or empty dict on failure
|
||||
func play_card(player_index: int, card: CardInstance) -> Dictionary:
|
||||
if not game_active:
|
||||
return {}
|
||||
|
||||
if player_index != turn_manager.current_player_index:
|
||||
return {}
|
||||
|
||||
if not turn_manager.is_main_phase():
|
||||
return {}
|
||||
|
||||
var player = players[player_index]
|
||||
|
||||
# Validate and play (returns CP spent dict)
|
||||
var cp_spent = player.play_card(card)
|
||||
if not cp_spent.is_empty():
|
||||
card_played.emit(card, player_index)
|
||||
card_moved.emit(card, Enums.ZoneType.HAND,
|
||||
Enums.ZoneType.FIELD_FORWARDS if card.is_forward() else Enums.ZoneType.FIELD_BACKUPS)
|
||||
return cp_spent
|
||||
|
||||
return {}
|
||||
|
||||
## Cast a summon from hand
|
||||
func cast_summon(player_index: int, card: CardInstance) -> bool:
|
||||
if not game_active:
|
||||
return false
|
||||
|
||||
@@ -118,11 +143,15 @@ func play_card(player_index: int, card: CardInstance) -> bool:
|
||||
|
||||
var player = players[player_index]
|
||||
|
||||
# Validate and play
|
||||
if player.play_card(card):
|
||||
card_played.emit(card, player_index)
|
||||
card_moved.emit(card, Enums.ZoneType.HAND,
|
||||
Enums.ZoneType.FIELD_FORWARDS if card.is_forward() else Enums.ZoneType.FIELD_BACKUPS)
|
||||
# Cast the summon (pays cost, removes from hand)
|
||||
var cast_card = player.cast_summon(card)
|
||||
if cast_card:
|
||||
# Emit signal for effect resolution (TODO: implement effect system)
|
||||
summon_cast.emit(cast_card, player_index)
|
||||
|
||||
# Move to break zone after casting
|
||||
player.break_zone.add_card(cast_card)
|
||||
card_moved.emit(cast_card, Enums.ZoneType.HAND, Enums.ZoneType.BREAK)
|
||||
return true
|
||||
|
||||
return false
|
||||
@@ -168,6 +197,10 @@ func declare_attack(attacker: CardInstance) -> bool:
|
||||
if not turn_manager.is_attack_phase():
|
||||
return false
|
||||
|
||||
# Must be in DECLARATION step to declare attack
|
||||
if turn_manager.attack_step != Enums.AttackStep.DECLARATION:
|
||||
return false
|
||||
|
||||
var player = get_current_player()
|
||||
|
||||
if not player.field_forwards.has_card(attacker):
|
||||
@@ -181,7 +214,14 @@ func declare_attack(attacker: CardInstance) -> bool:
|
||||
attacker.dull()
|
||||
|
||||
attacker.attacked_this_turn = true
|
||||
turn_manager.set_attacker(attacker)
|
||||
|
||||
# Update attack step (now returns bool for validation)
|
||||
if not turn_manager.set_attacker(attacker):
|
||||
# Rollback dull if state transition failed
|
||||
if not attacker.has_brave():
|
||||
attacker.activate()
|
||||
attacker.attacked_this_turn = false
|
||||
return false
|
||||
|
||||
attack_declared.emit(attacker)
|
||||
return true
|
||||
@@ -203,7 +243,10 @@ func declare_block(blocker: CardInstance) -> bool:
|
||||
if not blocker.can_block():
|
||||
return false
|
||||
|
||||
turn_manager.set_blocker(blocker)
|
||||
# Update attack step (now returns bool for validation)
|
||||
if not turn_manager.set_blocker(blocker):
|
||||
return false
|
||||
|
||||
if blocker:
|
||||
block_declared.emit(blocker)
|
||||
|
||||
@@ -220,25 +263,37 @@ func resolve_combat() -> void:
|
||||
|
||||
var attacker = turn_manager.current_attacker
|
||||
var blocker = turn_manager.current_blocker
|
||||
var player = get_current_player()
|
||||
|
||||
# Validate attacker is still on field (could have been broken by ability)
|
||||
if not attacker or not player.field_forwards.has_card(attacker):
|
||||
turn_manager.complete_attack()
|
||||
return
|
||||
|
||||
if blocker == null:
|
||||
# Unblocked - deal 1 damage to opponent
|
||||
_deal_damage_to_player(1 - turn_manager.current_player_index, 1)
|
||||
else:
|
||||
# Blocked - exchange damage
|
||||
var attacker_power = attacker.get_power()
|
||||
var blocker_power = blocker.get_power()
|
||||
# Validate blocker is still on field
|
||||
var opponent = get_opponent()
|
||||
if not opponent.field_forwards.has_card(blocker):
|
||||
# Blocker was removed - attack goes through as unblocked
|
||||
_deal_damage_to_player(1 - turn_manager.current_player_index, 1)
|
||||
else:
|
||||
# Blocked - exchange damage
|
||||
var attacker_power = attacker.get_power()
|
||||
var blocker_power = blocker.get_power()
|
||||
|
||||
# Apply damage
|
||||
var attacker_broken = attacker.apply_damage(blocker_power)
|
||||
var blocker_broken = blocker.apply_damage(attacker_power)
|
||||
# Apply damage
|
||||
var attacker_broken = attacker.apply_damage(blocker_power)
|
||||
var blocker_broken = blocker.apply_damage(attacker_power)
|
||||
|
||||
# Break destroyed forwards
|
||||
if attacker_broken:
|
||||
_break_forward(attacker, turn_manager.current_player_index)
|
||||
# Break destroyed forwards
|
||||
if attacker_broken:
|
||||
_break_forward(attacker, turn_manager.current_player_index)
|
||||
|
||||
if blocker_broken:
|
||||
_break_forward(blocker, 1 - turn_manager.current_player_index)
|
||||
if blocker_broken:
|
||||
_break_forward(blocker, 1 - turn_manager.current_player_index)
|
||||
|
||||
combat_resolved.emit(attacker, blocker)
|
||||
turn_manager.complete_attack()
|
||||
|
||||
@@ -130,34 +130,36 @@ func dull_backup_for_cp(card: CardInstance) -> bool:
|
||||
return true
|
||||
|
||||
## Play a card from hand to field
|
||||
func play_card(card: CardInstance) -> bool:
|
||||
## Returns dictionary of CP spent, or empty dict on failure
|
||||
func play_card(card: CardInstance) -> Dictionary:
|
||||
if not hand.has_card(card):
|
||||
return false
|
||||
return {}
|
||||
|
||||
# Check if we can afford it
|
||||
if not cp_pool.can_afford_card(card.card_data):
|
||||
return false
|
||||
return {}
|
||||
|
||||
# Check field restrictions
|
||||
if card.is_backup():
|
||||
if field_backups.get_count() >= MAX_BACKUPS:
|
||||
return false
|
||||
return {}
|
||||
|
||||
# Check unique name restriction
|
||||
# Check unique name restriction (non-generic cards can't share names across entire field)
|
||||
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
|
||||
if field_forwards.has_card_with_name(card.card_data.name):
|
||||
return {}
|
||||
if field_backups.has_card_with_name(card.card_data.name):
|
||||
return {}
|
||||
|
||||
# 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
|
||||
return {}
|
||||
|
||||
# Pay the cost
|
||||
if not cp_pool.spend_for_card(card.card_data):
|
||||
return false
|
||||
# Pay the cost (returns dict of spent CP, empty if failed)
|
||||
var spent = cp_pool.spend_for_card(card.card_data)
|
||||
if spent.is_empty():
|
||||
return {}
|
||||
|
||||
# Move to field
|
||||
hand.remove_card(card)
|
||||
@@ -171,7 +173,29 @@ func play_card(card: CardInstance) -> bool:
|
||||
|
||||
card.entered_field()
|
||||
|
||||
return true
|
||||
return spent
|
||||
|
||||
## Cast a summon from hand (pays cost, removes from hand, returns card for effect resolution)
|
||||
func cast_summon(card: CardInstance) -> CardInstance:
|
||||
if not hand.has_card(card):
|
||||
return null
|
||||
|
||||
if not card.is_summon():
|
||||
return null
|
||||
|
||||
# Check if we can afford it
|
||||
if not cp_pool.can_afford_card(card.card_data):
|
||||
return null
|
||||
|
||||
# Pay the cost (returns dict of spent CP, empty if failed)
|
||||
var spent = cp_pool.spend_for_card(card.card_data)
|
||||
if spent.is_empty():
|
||||
return null
|
||||
|
||||
# Remove from hand - card will be moved to break zone after effect resolves
|
||||
hand.remove_card(card)
|
||||
|
||||
return card
|
||||
|
||||
## Break a card (move from field to break zone)
|
||||
func break_card(card: CardInstance) -> bool:
|
||||
|
||||
@@ -96,36 +96,53 @@ func is_attack_phase() -> bool:
|
||||
|
||||
## Get cards drawn this turn (2 normally, 1 on first turn for first player)
|
||||
func get_draw_count() -> int:
|
||||
if is_first_turn and current_player_index == 0:
|
||||
if is_first_turn:
|
||||
return 1
|
||||
return 2
|
||||
|
||||
## Attack phase state management
|
||||
|
||||
## Start attack declaration
|
||||
func start_attack_declaration() -> void:
|
||||
## Start attack declaration (only valid from PREPARATION)
|
||||
func start_attack_declaration() -> bool:
|
||||
if attack_step != Enums.AttackStep.PREPARATION:
|
||||
return false
|
||||
attack_step = Enums.AttackStep.DECLARATION
|
||||
return true
|
||||
|
||||
## Set the attacking forward
|
||||
func set_attacker(attacker: CardInstance) -> void:
|
||||
## Set the attacking forward (only valid from DECLARATION)
|
||||
func set_attacker(attacker: CardInstance) -> bool:
|
||||
if attack_step != Enums.AttackStep.DECLARATION:
|
||||
return false
|
||||
if attacker == null:
|
||||
return false
|
||||
current_attacker = attacker
|
||||
attack_step = Enums.AttackStep.BLOCK_DECLARATION
|
||||
return true
|
||||
|
||||
## Set the blocking forward (or null for no block)
|
||||
func set_blocker(blocker: CardInstance) -> void:
|
||||
current_blocker = blocker
|
||||
## Set the blocking forward (or null for no block) - only valid from BLOCK_DECLARATION
|
||||
func set_blocker(blocker: CardInstance) -> bool:
|
||||
if attack_step != Enums.AttackStep.BLOCK_DECLARATION:
|
||||
return false
|
||||
current_blocker = blocker # null is valid (no block)
|
||||
attack_step = Enums.AttackStep.DAMAGE_RESOLUTION
|
||||
return true
|
||||
|
||||
## Complete the current attack
|
||||
func complete_attack() -> void:
|
||||
## Complete the current attack (only valid from DAMAGE_RESOLUTION)
|
||||
func complete_attack() -> bool:
|
||||
if attack_step != Enums.AttackStep.DAMAGE_RESOLUTION:
|
||||
return false
|
||||
current_attacker = null
|
||||
current_blocker = null
|
||||
attack_step = Enums.AttackStep.DECLARATION
|
||||
return true
|
||||
|
||||
## End the attack phase (no more attacks)
|
||||
func end_attack_phase() -> void:
|
||||
## End the attack phase (no more attacks) - only valid from DECLARATION
|
||||
func end_attack_phase() -> bool:
|
||||
if attack_step != Enums.AttackStep.DECLARATION and attack_step != Enums.AttackStep.PREPARATION:
|
||||
return false
|
||||
_reset_attack_state()
|
||||
advance_phase()
|
||||
return true
|
||||
|
||||
## Get current phase as string
|
||||
func get_phase_string() -> String:
|
||||
|
||||
@@ -23,6 +23,7 @@ class UndoAction:
|
||||
# Additional data depending on action type
|
||||
var cp_element: Enums.Element = Enums.Element.FIRE
|
||||
var cp_amount: int = 0
|
||||
var cp_spent: Dictionary = {} # Tracks CP spent by element for proper refund
|
||||
var previous_card_state: Enums.CardState = Enums.CardState.ACTIVE
|
||||
var from_zone: Enums.ZoneType = Enums.ZoneType.HAND
|
||||
var to_zone: Enums.ZoneType = Enums.ZoneType.FIELD_FORWARDS
|
||||
@@ -69,13 +70,14 @@ func record_dull_backup_for_cp(player_index: int, card: CardInstance, element: E
|
||||
undo_available_changed.emit(true)
|
||||
|
||||
## Record playing a card
|
||||
func record_play_card(player_index: int, card: CardInstance, to_zone: Enums.ZoneType, _cp_spent: Dictionary) -> void:
|
||||
func record_play_card(player_index: int, card: CardInstance, to_zone: Enums.ZoneType, cp_spent: Dictionary) -> void:
|
||||
var action = UndoAction.new()
|
||||
action.type = ActionType.PLAY_CARD
|
||||
action.player_index = player_index
|
||||
action.card = card
|
||||
action.from_zone = Enums.ZoneType.HAND
|
||||
action.to_zone = to_zone
|
||||
action.cp_spent = cp_spent # Store actual CP spent for proper refund
|
||||
action.description = "Play " + card.get_display_name()
|
||||
|
||||
last_action = action
|
||||
@@ -177,12 +179,16 @@ func _undo_play_card(action: UndoAction) -> bool:
|
||||
card.state = Enums.CardState.ACTIVE
|
||||
card.turns_on_field = 0
|
||||
|
||||
# Refund the CP (we don't track exact CP spent, so this is simplified)
|
||||
# In a full implementation, we'd track what CP was spent
|
||||
# For now, we'll add back CP equal to the card cost
|
||||
var cost = card.card_data.cost
|
||||
var element = card.get_element()
|
||||
player.cp_pool.add_cp(element, cost)
|
||||
# Refund the actual CP spent (by element)
|
||||
if action.cp_spent.is_empty():
|
||||
# Fallback: refund card cost as primary element (legacy behavior)
|
||||
var cost = card.card_data.cost
|
||||
var element = card.get_element()
|
||||
player.cp_pool.add_cp(element, cost)
|
||||
else:
|
||||
# Refund each element's CP properly
|
||||
for element in action.cp_spent:
|
||||
player.cp_pool.add_cp(element, action.cp_spent[element])
|
||||
|
||||
return true
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@ func _init(type: Enums.ZoneType, owner: int = -1) -> void:
|
||||
owner_index = owner
|
||||
|
||||
## Add a card to this zone
|
||||
func add_card(card: CardInstance, at_top: bool = true) -> void:
|
||||
## Returns true if successful, false if card was already in zone
|
||||
func add_card(card: CardInstance, at_top: bool = true) -> bool:
|
||||
if card in _cards:
|
||||
push_warning("Card already in zone: " + str(card))
|
||||
return
|
||||
return false
|
||||
|
||||
card.zone_type = zone_type
|
||||
|
||||
@@ -30,6 +31,7 @@ func add_card(card: CardInstance, at_top: bool = true) -> void:
|
||||
_cards.insert(0, card)
|
||||
|
||||
on_card_added.call(card)
|
||||
return true
|
||||
|
||||
## Remove a card from this zone
|
||||
func remove_card(card: CardInstance) -> bool:
|
||||
@@ -142,12 +144,12 @@ func find_cards_by_element(element: Enums.Element) -> Array[CardInstance]:
|
||||
found.append(card)
|
||||
return found
|
||||
|
||||
## Check if zone has a card with specific name (non-generic check)
|
||||
## Check if zone has a card with specific name
|
||||
## Note: The non-generic check should be on the card being played, not the field card
|
||||
func has_card_with_name(card_name: String) -> bool:
|
||||
for card in _cards:
|
||||
if card.card_data and card.card_data.name == card_name:
|
||||
if not card.card_data.is_generic:
|
||||
return true
|
||||
return true
|
||||
return false
|
||||
|
||||
## Check if zone has any Light or Dark card
|
||||
|
||||
Reference in New Issue
Block a user