175 lines
4.2 KiB
GDScript
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
|