feat(parser): max-attackers-each-combat static (Judoon Enforcers + class)#3709
feat(parser): max-attackers-each-combat static (Judoon Enforcers + class)#3709ntindle wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements defender-scoped attacker caps (such as "no more than one creature can attack you each combat") by updating StaticMode::MaxAttackersEachCombat to support an optional defender scope and introducing validation logic to enforce these limits per defending player. The feedback recommends expanding the unit tests to explicitly verify that defender-scoped caps do not restrict attacks against other, unprotected players in multiplayer scenarios.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // Two attackers against player 1: illegal. | ||
| assert!(validate_per_defender_attacker_caps( | ||
| &state, | ||
| &[ | ||
| (a, AttackTarget::Player(PlayerId(1))), | ||
| (b, AttackTarget::Player(PlayerId(1))), | ||
| ], | ||
| ) | ||
| .is_err()); |
There was a problem hiding this comment.
[MEDIUM] Expand test coverage to verify defender-scoped restriction in multiplayer scenarios.
Why it matters: The test currently only verifies that attacking the protected player (Player 1) is restricted, but it does not assert that attacking other players (e.g., Player 2) remains unrestricted by the defender-scoped cap. Adding this assertion ensures that the cap is correctly scoped to the defender and does not act as a global cap in multiplayer games.
Suggested fix: Add an assertion verifying that attacking an unprotected player is legal.
| // Two attackers against player 1: illegal. | |
| assert!(validate_per_defender_attacker_caps( | |
| &state, | |
| &[ | |
| (a, AttackTarget::Player(PlayerId(1))), | |
| (b, AttackTarget::Player(PlayerId(1))), | |
| ], | |
| ) | |
| .is_err()); | |
| // Two attackers against player 1: illegal. | |
| assert!(validate_per_defender_attacker_caps( | |
| &state, | |
| &[ | |
| (a, AttackTarget::Player(PlayerId(1))), | |
| (b, AttackTarget::Player(PlayerId(1))), | |
| ], | |
| ) | |
| .is_err()); | |
| // Two attackers against player 2 (unprotected): legal. | |
| assert!(validate_per_defender_attacker_caps( | |
| &state, | |
| &[ | |
| (a, AttackTarget::Player(PlayerId(2))), | |
| (b, AttackTarget::Player(PlayerId(2))), | |
| ], | |
| ) | |
| .is_ok()); |
matthewevans
left a comment
There was a problem hiding this comment.
VERDICT: request-changes
[HIGH] Defender-scoped caps treat attacks on planeswalkers/battles as attacks "you". Evidence: crates/engine/src/game/combat.rs:551 counts every attack whose defending_player_for_target equals the static controller, and crates/engine/src/game/combat.rs:567 maps planeswalker targets to their controller and battle targets to their protector. The parser only creates this scoped mode for the plain text can attack you each combat, while the existing attack-scope machinery treats plain AttackTargetFilter::Player as direct-player only and reserves PlayerOrPlaneswalker for explicit you or planeswalkers you control text (crates/engine/src/game/restrictions.rs:1837, crates/engine/src/parser/oracle_static/shared.rs:2993).
Why this matters: Judoon Enforcers/Crawlspace-style text would reject legal declarations such as two creatures attacking a planeswalker controlled by the protected player, or a battle they protect, even though those creatures are not attacking that player. Please count against a direct-player defended scope here (or reuse the existing target-scope matcher) and add regression coverage for planeswalker/battle targets plus the multiplayer non-protected-player case Gemini noted.
Facts/confidence: confirmed from this diff and the existing parser/runtime attack-target scope code; high confidence. The evidence that would contradict this is a CR/card-text rule saying plain "attack you" includes planeswalkers or battles, but CR 508.1b/508.5 and the current engine model distinguish those attack targets.
Summary
Implements the "no more than N creatures can attack [you] each combat" static as
MaxAttackersEachCombat { max, defender }— a general class-level primitive (defender=Controller for "attack you", defender=null for the global form).Cards supported
Judoon Enforcers,Crawlspace Astral Arena,Caverns of Despair Dueling Grounds,Silent Arbiter
From the WHO Suspend/time cluster (Judoon Enforcers had this clause alongside Trample + Suspend 6, both preserved); the primitive generalizes to several non-WHO cards.
Verification
cargo fmtclean -cargo clippy -p engine --all-targets -D warningsclean -cargo test -p engineall pass - oracle-gen AST confirmed for all affected cards.CR refs verified against docs/MagicCompRules.txt.
🤖 Generated with Claude Code