Files
FFCardGame/scripts/game/abilities/TargetSelector.gd
2026-02-02 16:28:53 -05:00

175 lines
4.2 KiB
GDScript

class_name TargetSelector
extends RefCounted
## TargetSelector - Validates and provides target options for effects
## Get all valid targets for an effect's target specification
func get_valid_targets(
target_spec: Dictionary,
source: CardInstance,
game_state
) -> Array:
if target_spec.is_empty():
return []
var candidates: Array = []
var zone = str(target_spec.get("zone", "FIELD")).to_upper()
var owner = str(target_spec.get("owner", "ANY")).to_upper()
var filter = target_spec.get("filter", {})
var target_type = str(target_spec.get("type", "CHOOSE")).to_upper()
# Handle SELF and ALL targets specially
if target_type == "SELF":
return [source]
elif target_type == "ALL":
return _get_all_matching(owner, zone, filter, source, game_state)
# Collect candidates from appropriate zones
match zone:
"FIELD":
candidates = _get_field_cards(owner, source, game_state)
"HAND":
candidates = _get_hand_cards(owner, source, game_state)
"BREAK_ZONE", "BREAK":
candidates = _get_break_zone_cards(owner, source, game_state)
"DECK":
candidates = _get_deck_cards(owner, source, game_state)
_:
# Default to field
candidates = _get_field_cards(owner, source, game_state)
# Apply filters using CardFilter utility
return CardFilter.get_matching(candidates, filter, source)
## Get all cards matching filter (for "ALL" target type)
func _get_all_matching(
owner: String,
zone: String,
filter: Dictionary,
source: CardInstance,
game_state
) -> Array:
var candidates = _get_field_cards(owner, source, game_state)
return CardFilter.get_matching(candidates, filter, source)
## Get cards from field
func _get_field_cards(
owner: String,
source: CardInstance,
game_state
) -> Array:
var cards: Array = []
match owner:
"CONTROLLER":
var player = game_state.get_player(source.controller_index)
if player:
cards.append_array(_get_player_field_cards(player))
"OPPONENT":
var opponent = game_state.get_player(1 - source.controller_index)
if opponent:
cards.append_array(_get_player_field_cards(opponent))
"ANY", _:
for player in game_state.players:
cards.append_array(_get_player_field_cards(player))
return cards
## Get all field cards for a player
func _get_player_field_cards(player) -> Array:
var cards: Array = []
cards.append_array(player.field_forwards.get_cards())
cards.append_array(player.field_backups.get_cards())
return cards
## Get cards from hand
func _get_hand_cards(
owner: String,
source: CardInstance,
game_state
) -> Array:
var cards: Array = []
var player_index = source.controller_index
if owner == "OPPONENT":
player_index = 1 - player_index
var player = game_state.get_player(player_index)
if player:
cards.append_array(player.hand.get_cards())
return cards
## Get cards from break zone
func _get_break_zone_cards(
owner: String,
source: CardInstance,
game_state
) -> Array:
var cards: Array = []
var player_index = source.controller_index
if owner == "OPPONENT":
player_index = 1 - player_index
var player = game_state.get_player(player_index)
if player:
cards.append_array(player.break_zone.get_cards())
return cards
## Get cards from deck
func _get_deck_cards(
owner: String,
source: CardInstance,
game_state
) -> Array:
# Usually not directly targetable, used for search effects
var cards: Array = []
var player_index = source.controller_index
if owner == "OPPONENT":
player_index = 1 - player_index
var player = game_state.get_player(player_index)
if player:
cards.append_array(player.deck.get_cards())
return cards
## Validate that a set of targets meets the target specification requirements
func validate_targets(
targets: Array,
target_spec: Dictionary,
source: CardInstance,
game_state
) -> bool:
var target_type = str(target_spec.get("type", "CHOOSE")).to_upper()
# Check count requirements
if target_spec.has("count"):
var required = int(target_spec.count)
if targets.size() != required:
return false
elif target_spec.has("count_up_to"):
var max_count = int(target_spec.count_up_to)
if targets.size() > max_count:
return false
# Validate each target is valid
var valid_targets = get_valid_targets(target_spec, source, game_state)
for target in targets:
if target not in valid_targets:
return false
return true