Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions crates/engine/src/parser/oracle_effect/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31224,6 +31224,23 @@ fn public_attack_prohibition_parser_preserves_legacy_anaphora_and_connector() {
}
));
assert!(connector.duration.is_none());

let planeswalker_only = parse_effect_chain(
"that player can't attack planeswalkers you control during their next turn.",
AbilityKind::Spell,
);
assert!(matches!(
planeswalker_only.effect.as_ref(),
Effect::AddRestriction {
restriction: GameRestriction::ProhibitActivity {
activity: ProhibitedActivity::Attack {
defended: crate::types::triggers::AttackTargetFilter::Planeswalker,
protected_player: None,
},
..
},
}
));
}

#[test]
Expand All @@ -31233,6 +31250,10 @@ fn scoped_cant_attack_prohibition_supports_both_verbs_and_all_defended_scopes()
for verb in ["can't", "cannot"] {
for (scope, expected_defended) in [
("you", AttackTargetFilter::Player),
(
"planeswalkers you control",
AttackTargetFilter::Planeswalker,
),
(
"you or planeswalkers you control",
AttackTargetFilter::PlayerOrPlaneswalker,
Expand Down
16 changes: 16 additions & 0 deletions crates/engine/src/parser/oracle_ir/snapshot_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2487,6 +2487,22 @@ fn liliana_the_repentant() {
insta::assert_json_snapshot!("liliana_the_repentant_lowered", &lowered);
}

/// CR 508.1b-c + CR 508.1h + CR 602.2: Onakke's two printed lines exercise both the
/// planeswalker-only combat-tax static and its graveyard activation. Snapshot
/// both document IR and lowering so neither line can silently degrade while
/// the other stays supported.
#[test]
fn onakke_oathkeeper() {
let (ir, lowered) = parse_two_layer(
"Creatures can't attack planeswalkers you control unless their controller pays {1} for each creature they control that's attacking a planeswalker you control.\n{4}{W}{W}, Exile this card from your graveyard: Return target planeswalker card from your graveyard to the battlefield.",
"Onakke Oathkeeper",
&["Creature"],
&["Ogre", "Spirit"],
);
insta::assert_json_snapshot!("onakke_oathkeeper_ir", &ir);
insta::assert_json_snapshot!("onakke_oathkeeper_lowered", &lowered);
}

/// CR 702.142a Boast: pins the order of the two IMPLICIT restrictions.
///
/// No Boast card in the pool states its activation instruction outside reminder
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
---
source: crates/engine/src/parser/oracle_ir/snapshot_tests.rs
expression: "&ir"
---
{
"items": [
{
"id": 0,
"source": {
"id": {
"item": 0,
"ordinal": 0
},
"span": {
"first_line": 0,
"last_line": 0,
"start_byte": 0,
"end_byte": 157,
"precision": "Exact",
"ordinal_within_span": 0
},
"fragment": "Creatures can't attack planeswalkers you control unless their controller pays {1} for each creature they control that's attacking a planeswalker you control."
},
"node": {
"Static": {
"definition": {
"mode": "CantAttack",
"affected": {
"type": "Typed",
"type_filters": [
"Creature"
],
"controller": "Opponent",
"properties": []
},
"modifications": [],
"condition": {
"type": "UnlessPay",
"cost": {
"type": "Cost",
"shards": [],
"generic": 1
},
"scaling": {
"type": "PerAffectedCreature"
},
"defended": "Planeswalker"
},
"affected_zone": null,
"effect_zone": null,
"active_zones": [],
"characteristic_defining": false,
"description": "Creatures can't attack planeswalkers you control unless their controller pays {1} for each creature they control that's attacking a planeswalker you control."
},
"source_text": "Creatures can't attack planeswalkers you control unless their controller pays {1} for each creature they control that's attacking a planeswalker you control.",
"body_ir": null
}
}
},
{
"id": 1,
"source": {
"id": {
"item": 1,
"ordinal": 0
},
"span": {
"first_line": 1,
"last_line": 1,
"start_byte": 158,
"end_byte": 277,
"precision": "Exact",
"ordinal_within_span": 0
},
"fragment": "{4}{W}{W}, Exile this card from your graveyard: Return target planeswalker card from your graveyard to the battlefield."
},
"node": {
"Spell": {
"source_text": "Return target planeswalker card from your graveyard to the battlefield",
"body": {
"clauses": [
{
"id": 0,
"source": {
"id": {
"item": 0,
"ordinal": 1
},
"span": {
"first_line": 0,
"last_line": 0,
"start_byte": 0,
"end_byte": 70,
"precision": "ChainRelative",
"ordinal_within_span": 0
},
"fragment": "Return target planeswalker card from your graveyard to the battlefield"
},
"disposition": {
"Emit": {
"followup": null,
"intrinsic": null
}
},
"parsed": {
"effect": {
"type": "ChangeZone",
"origin": "Graveyard",
"destination": "Battlefield",
"target": {
"type": "Typed",
"type_filters": [
"Planeswalker"
],
"controller": "You",
"properties": [
{
"type": "InZone",
"zone": "Graveyard"
}
]
},
"owner_library": false,
"enter_transformed": false,
"enter_tapped": false,
"enters_attacking": false
},
"duration": null,
"sub_ability": null,
"distribute": null,
"multi_target": null,
"condition": null,
"optional": false,
"unless_pay": null
},
"boundary": null,
"condition": null,
"is_optional": false,
"opponent_may_scope": null,
"repeat_for": null,
"player_scope": null,
"starting_with": null,
"delayed_condition": null,
"prefix_delayed_condition": null,
"multi_target": null,
"where_x_expression": null,
"unless_pay": null
}
],
"kind": "Activated",
"continuation_kind": null,
"player_scope_rewrite": "Apply",
"chain_rounding": null,
"actor": null,
"in_trigger": false,
"repeat_until": null
},
"shell": {
"sub_link": null,
"cost": {
"type": "Composite",
"costs": [
{
"type": "Mana",
"cost": {
"type": "Cost",
"shards": [
"White",
"White"
],
"generic": 4
}
},
{
"type": "Exile",
"count": 1,
"zone": "Graveyard",
"filter": {
"type": "SelfRef"
}
}
]
},
"activation_zone": "Graveyard",
"description": "{4}{W}{W}, Exile this card from your graveyard: Return target planeswalker card from your graveyard to the battlefield.",
"stages": [
"NormalizeActivatedManaInstead",
"ExtractCostReduction",
"ExtractManaSpendTrigger"
]
},
"die_results": [],
"root_transforms": []
}
}
}
],
"source_text": "Creatures can't attack planeswalkers you control unless their controller pays {1} for each creature they control that's attacking a planeswalker you control.\n{4}{W}{W}, Exile this card from your graveyard: Return target planeswalker card from your graveyard to the battlefield.",
"card_name": "Onakke Oathkeeper"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
source: crates/engine/src/parser/oracle_ir/snapshot_tests.rs
expression: "&lowered"
---
{
"abilities": [
{
"kind": "Activated",
"effect": {
"type": "ChangeZone",
"origin": "Graveyard",
"destination": "Battlefield",
"target": {
"type": "Typed",
"type_filters": [
"Planeswalker"
],
"controller": "You",
"properties": [
{
"type": "InZone",
"zone": "Graveyard"
}
]
},
"owner_library": false,
"enter_transformed": false,
"enter_tapped": false,
"enters_attacking": false
},
"cost": {
"type": "Composite",
"costs": [
{
"type": "Mana",
"cost": {
"type": "Cost",
"shards": [
"White",
"White"
],
"generic": 4
}
},
{
"type": "Exile",
"count": 1,
"zone": "Graveyard",
"filter": {
"type": "SelfRef"
}
}
]
},
"sub_ability": null,
"duration": null,
"description": "{4}{W}{W}, Exile this card from your graveyard: Return target planeswalker card from your graveyard to the battlefield.",
"target_prompt": null,
"activation_zone": "Graveyard",
"condition": null,
"optional_targeting": false,
"optional": false,
"forward_result": false
}
],
"triggers": [],
"statics": [
{
"mode": "CantAttack",
"affected": {
"type": "Typed",
"type_filters": [
"Creature"
],
"controller": "Opponent",
"properties": []
},
"modifications": [],
"condition": {
"type": "UnlessPay",
"cost": {
"type": "Cost",
"shards": [],
"generic": 1
},
"scaling": {
"type": "PerAffectedCreature"
},
"defended": "Planeswalker"
},
"affected_zone": null,
"effect_zone": null,
"active_zones": [],
"characteristic_defining": false,
"description": "Creatures can't attack planeswalkers you control unless their controller pays {1} for each creature they control that's attacking a planeswalker you control."
}
],
"replacements": [],
"extractedKeywords": []
}
Loading
Loading