diff --git a/crates/engine/src/parser/oracle_nom/condition.rs b/crates/engine/src/parser/oracle_nom/condition.rs index 72f1a1d872..1265fc71a9 100644 --- a/crates/engine/src/parser/oracle_nom/condition.rs +++ b/crates/engine/src/parser/oracle_nom/condition.rs @@ -3879,7 +3879,8 @@ fn parse_control_count_ge_distinct_quality(input: &str) -> OracleResult<'_, Stat )) } -/// CR 201.2 + CR 109.3: Parse "you control N or more [type] with the same name" +/// CR 201.2 + CR 109.3: Parse "you control N or more [type] with the same name +/// as one another" /// → `QuantityComparison(ObjectCountBySharedQuality[Name, Max] >= N)`. /// /// The same-quality mirror of `parse_control_count_ge_distinct_quality`. Both read @@ -3907,7 +3908,10 @@ fn parse_control_count_ge_shared_quality(input: &str) -> OracleResult<'_, Static let trimmed = remainder.trim_start(); let (after_suffix, quality) = preceded( tag("with the same "), - alt((value(SharedQuality::Name, tag("name")),)), + terminated( + alt((value(SharedQuality::Name, tag("name")),)), + opt(tag(" as one another")), + ), ) .parse(trimmed)?; let filter = inject_controller_you(filter); diff --git a/crates/engine/src/parser/oracle_tests.rs b/crates/engine/src/parser/oracle_tests.rs index b8dba929b3..7c6c1a3154 100644 --- a/crates/engine/src/parser/oracle_tests.rs +++ b/crates/engine/src/parser/oracle_tests.rs @@ -6882,6 +6882,51 @@ fn thassas_oracle_win_condition_gated_by_devotion_vs_library() { ); } +#[test] +fn mechanized_production_win_requires_eight_artifacts_sharing_a_name() { + let r = parse( + "Enchant artifact you control\nAt the beginning of your upkeep, create a token that's a copy of enchanted artifact. Then if you control eight or more artifacts with the same name as one another, you win the game.", + "Mechanized Production", + &[], + &["Enchantment"], + &["Aura"], + ); + let trigger = r + .triggers + .first() + .expect("Mechanized Production must parse its upkeep trigger"); + let copy = trigger + .execute + .as_deref() + .expect("the upkeep trigger must create the token copy"); + let win = copy + .sub_ability + .as_deref() + .expect("the conditional win must follow the token copy"); + assert!(matches!(*win.effect, Effect::WinTheGame { .. })); + assert_eq!( + win.condition, + Some(AbilityCondition::QuantityCheck { + lhs: QuantityExpr::Ref { + qty: QuantityRef::ObjectCountBySharedQuality { + filter: TargetFilter::Typed( + TypedFilter::new(TypeFilter::Artifact) + .controller(ControllerRef::You) + .properties(vec![FilterProp::InZone { + zone: Zone::Battlefield, + }]) + ), + quality: SharedQuality::Name, + aggregate: AggregateFunction::Max, + }, + }, + comparator: Comparator::GE, + rhs: QuantityExpr::Fixed { value: 8 }, + }), + "the win must be gated by one shared artifact name, not the total artifact count" + ); +} + #[test] fn incubate_parses_as_effect() { let r = parse(