manabrew_engine/spellability/spell_ability_predicates.rs
1//! Predicate functions for filtering spell abilities.
2//!
3//! Mirrors Java's `SpellAbilityPredicates.java` — provides closure-based
4//! predicates for filtering spell abilities by API type, sub-abilities, etc.
5
6use crate::ability::api_type::ApiType;
7use crate::spellability::SpellAbility;
8
9/// Returns a predicate that matches spell abilities with the given API type.
10/// Mirrors Java's `SpellAbilityPredicates.isApi(ApiType)`.
11pub fn is_api(api: ApiType) -> impl Fn(&SpellAbility) -> bool {
12 move |sa: &SpellAbility| sa.api == Some(api)
13}
14
15/// Returns a predicate that matches spell abilities whose sub-ability chain
16/// contains an ability with the given API type.
17/// Mirrors Java's `SpellAbilityPredicates.hasSubAbilityApi(ApiType)`.
18pub fn has_sub_ability_api(api: ApiType) -> impl Fn(&SpellAbility) -> bool {
19 move |sa: &SpellAbility| {
20 let mut current = sa.sub_ability.as_deref();
21 while let Some(sub) = current {
22 if sub.api == Some(api) {
23 return true;
24 }
25 current = sub.sub_ability.as_deref();
26 }
27 false
28 }
29}
30
31/// Returns a predicate that checks if a spell ability matches all given
32/// restriction strings. Each restriction is checked against the ability's params.
33/// Mirrors Java's `SpellAbilityPredicates.isValid(String[])`.
34pub fn is_valid<'a>(restrictions: &'a [&'a str]) -> impl Fn(&SpellAbility) -> bool + 'a {
35 move |sa: &SpellAbility| {
36 for &restriction in restrictions {
37 // Check if the restriction matches a param key set to "True"
38 if let Some(key) = restriction.strip_prefix('!') {
39 // Negated restriction: must NOT have the param
40 if sa.param_is_true(key) {
41 return false;
42 }
43 } else if restriction.contains('$') {
44 // Key-value restriction: "Key$ Value" — check param equals value
45 let parts: Vec<&str> = restriction.splitn(2, '$').collect();
46 if parts.len() == 2 {
47 let key = parts[0].trim();
48 let expected = parts[1].trim();
49 match sa.param_value(key) {
50 Some(val) if val.eq_ignore_ascii_case(expected) => {}
51 _ => return false,
52 }
53 }
54 } else {
55 // Simple flag restriction: param must be "True"
56 if !sa.param_is_true(restriction) {
57 return false;
58 }
59 }
60 }
61 true
62 }
63}