feature updates
This commit is contained in:
233
scripts/game/abilities/TriggerMatcher.gd
Normal file
233
scripts/game/abilities/TriggerMatcher.gd
Normal file
@@ -0,0 +1,233 @@
|
||||
class_name TriggerMatcher
|
||||
extends RefCounted
|
||||
|
||||
## TriggerMatcher - Matches game events to ability triggers
|
||||
## Scans all cards on field for abilities that trigger from the given event
|
||||
|
||||
## Reference to ConditionChecker for evaluating trigger conditions
|
||||
var condition_checker: ConditionChecker = null
|
||||
|
||||
|
||||
## Find all abilities that should trigger for a given event
|
||||
func find_triggered_abilities(
|
||||
event_type: String,
|
||||
event_data: Dictionary,
|
||||
game_state,
|
||||
all_abilities: Dictionary
|
||||
) -> Array:
|
||||
var triggered = []
|
||||
|
||||
# Check abilities on all cards in play
|
||||
for player in game_state.players:
|
||||
# Check forwards
|
||||
for card in player.field_forwards.get_cards():
|
||||
var card_abilities = all_abilities.get(card.card_data.id, [])
|
||||
triggered.append_array(_check_card_abilities(card, card_abilities, event_type, event_data, game_state))
|
||||
|
||||
# Check backups
|
||||
for card in player.field_backups.get_cards():
|
||||
var card_abilities = all_abilities.get(card.card_data.id, [])
|
||||
triggered.append_array(_check_card_abilities(card, card_abilities, event_type, event_data, game_state))
|
||||
|
||||
return triggered
|
||||
|
||||
|
||||
## Check all abilities on a card for triggers
|
||||
func _check_card_abilities(
|
||||
card: CardInstance,
|
||||
abilities: Array,
|
||||
event_type: String,
|
||||
event_data: Dictionary,
|
||||
game_state
|
||||
) -> Array:
|
||||
var triggered = []
|
||||
|
||||
for ability in abilities:
|
||||
if _matches_trigger(ability, event_type, event_data, card, game_state):
|
||||
triggered.append({
|
||||
"source": card,
|
||||
"ability": ability,
|
||||
"event_data": event_data
|
||||
})
|
||||
|
||||
return triggered
|
||||
|
||||
|
||||
## Check if an ability's trigger matches the event
|
||||
func _matches_trigger(
|
||||
ability: Dictionary,
|
||||
event_type: String,
|
||||
event_data: Dictionary,
|
||||
source_card: CardInstance,
|
||||
game_state
|
||||
) -> bool:
|
||||
var parsed = ability.get("parsed", {})
|
||||
if parsed.is_empty():
|
||||
return false
|
||||
|
||||
# Only AUTO abilities have triggers
|
||||
if parsed.get("type") != "AUTO":
|
||||
return false
|
||||
|
||||
var trigger = parsed.get("trigger", {})
|
||||
if trigger.is_empty():
|
||||
return false
|
||||
|
||||
# Check event type matches
|
||||
var trigger_event = trigger.get("event", "")
|
||||
if not _event_matches(trigger_event, event_type):
|
||||
return false
|
||||
|
||||
# Check source filter
|
||||
var trigger_source = trigger.get("source", "ANY")
|
||||
if not _source_matches(trigger_source, event_data, source_card, game_state):
|
||||
return false
|
||||
|
||||
# Check additional trigger filters
|
||||
if trigger.has("source_filter"):
|
||||
var filter = trigger.source_filter
|
||||
var event_card = event_data.get("card")
|
||||
if event_card and not _matches_card_filter(event_card, filter):
|
||||
return false
|
||||
|
||||
# Check trigger condition (if present)
|
||||
var trigger_condition = trigger.get("condition", {})
|
||||
if not trigger_condition.is_empty() and condition_checker:
|
||||
var context = {
|
||||
"source_card": source_card,
|
||||
"target_card": event_data.get("card"),
|
||||
"game_state": game_state,
|
||||
"player_id": source_card.controller_index if source_card else 0,
|
||||
"event_data": event_data
|
||||
}
|
||||
if not condition_checker.evaluate(trigger_condition, context):
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Check if event type matches trigger event
|
||||
func _event_matches(trigger_event: String, actual_event: String) -> bool:
|
||||
# Direct match
|
||||
if trigger_event == actual_event:
|
||||
return true
|
||||
|
||||
# Handle variations
|
||||
match trigger_event:
|
||||
"ENTERS_FIELD":
|
||||
return actual_event in ["ENTERS_FIELD", "CARD_PLAYED"]
|
||||
"LEAVES_FIELD":
|
||||
return actual_event in ["LEAVES_FIELD", "FORWARD_BROKEN", "CARD_BROKEN"]
|
||||
"DEALS_DAMAGE":
|
||||
return actual_event in ["DEALS_DAMAGE", "DEALS_DAMAGE_TO_OPPONENT", "DEALS_DAMAGE_TO_FORWARD"]
|
||||
"DEALS_DAMAGE_TO_OPPONENT":
|
||||
return actual_event == "DEALS_DAMAGE_TO_OPPONENT"
|
||||
"DEALS_DAMAGE_TO_FORWARD":
|
||||
return actual_event == "DEALS_DAMAGE_TO_FORWARD"
|
||||
"BLOCKS_OR_IS_BLOCKED":
|
||||
return actual_event in ["BLOCKS", "IS_BLOCKED"]
|
||||
|
||||
return false
|
||||
|
||||
|
||||
## Check if source matches trigger requirements
|
||||
func _source_matches(
|
||||
trigger_source: String,
|
||||
event_data: Dictionary,
|
||||
source_card: CardInstance,
|
||||
game_state
|
||||
) -> bool:
|
||||
var event_card = event_data.get("card")
|
||||
|
||||
match trigger_source:
|
||||
"SELF":
|
||||
# Trigger source must be this card
|
||||
return event_card == source_card
|
||||
"CONTROLLER":
|
||||
# Trigger source must be controlled by same player
|
||||
if event_card:
|
||||
return event_card.controller_index == source_card.controller_index
|
||||
var event_player = event_data.get("player", -1)
|
||||
return event_player == source_card.controller_index
|
||||
"OPPONENT":
|
||||
# Trigger source must be controlled by opponent
|
||||
if event_card:
|
||||
return event_card.controller_index != source_card.controller_index
|
||||
var event_player = event_data.get("player", -1)
|
||||
return event_player != source_card.controller_index and event_player >= 0
|
||||
"ANY", _:
|
||||
# Any source triggers
|
||||
return true
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Check if a card matches a filter
|
||||
func _matches_card_filter(card: CardInstance, filter: Dictionary) -> bool:
|
||||
if filter.is_empty():
|
||||
return true
|
||||
|
||||
# Card type filter
|
||||
if filter.has("card_type"):
|
||||
var type_str = str(filter.card_type).to_upper()
|
||||
match type_str:
|
||||
"FORWARD":
|
||||
if not card.is_forward():
|
||||
return false
|
||||
"BACKUP":
|
||||
if not card.is_backup():
|
||||
return false
|
||||
"SUMMON":
|
||||
if not card.is_summon():
|
||||
return false
|
||||
|
||||
# Element filter
|
||||
if filter.has("element"):
|
||||
var element_str = str(filter.element).to_upper()
|
||||
var element = Enums.element_from_string(element_str)
|
||||
if element not in card.get_elements():
|
||||
return false
|
||||
|
||||
# Cost filters
|
||||
if filter.has("cost_min"):
|
||||
if card.card_data.cost < filter.cost_min:
|
||||
return false
|
||||
if filter.has("cost_max"):
|
||||
if card.card_data.cost > filter.cost_max:
|
||||
return false
|
||||
if filter.has("cost"):
|
||||
if card.card_data.cost != filter.cost:
|
||||
return false
|
||||
|
||||
# Power filters
|
||||
if filter.has("power_min"):
|
||||
if card.get_power() < filter.power_min:
|
||||
return false
|
||||
if filter.has("power_max"):
|
||||
if card.get_power() > filter.power_max:
|
||||
return false
|
||||
|
||||
# State filters
|
||||
if filter.has("is_dull"):
|
||||
if card.is_dull() != filter.is_dull:
|
||||
return false
|
||||
if filter.has("is_active"):
|
||||
if card.is_active() != filter.is_active:
|
||||
return false
|
||||
|
||||
# Name filter
|
||||
if filter.has("name"):
|
||||
if card.card_data.name != filter.name:
|
||||
return false
|
||||
|
||||
# Category filter
|
||||
if filter.has("category"):
|
||||
if card.card_data.category != filter.category:
|
||||
return false
|
||||
|
||||
# Job filter
|
||||
if filter.has("job"):
|
||||
if card.card_data.job != filter.job:
|
||||
return false
|
||||
|
||||
return true
|
||||
Reference in New Issue
Block a user