Now let me also read the Complete cards section to understand the count and where to add the newly fixed cards.
Now I have all the context. Let me make all the doc updates. I'll update fdn-remediation.md, then ecl-remediation.md, tdm-remediation.md, and ROADMAP.md.
Now update the Phase 2 roadmap section and the overview counts.
Now I have all the context I need. Let me also check the DealDamageOpponents implementation in game.rs to match the pattern.
Now update the ECL and TDM remediation docs.
Need to read those files first.
Good, I have all the context. Let me also check the DealDamageOpponents implementation in game.rs for reference.
Now update the ROADMAP.md.
Now let me run the full test suite one more time to confirm everything is clean.
>cargo test --lib 2>&1 | tail -20All 244 tests pass. Here's a summary of everything done:
New Effect::LoseLifeOpponents { amount } variant added to:
mtg-engine/src/abilities.rs — enum variant + lose_life_opponents() constructormtg-engine/src/game.rs — match arm in execute_effects() (iterates opponents, subtracts life)This is semantically distinct from DealDamageOpponents — when damage prevention is added later, only damage effects will be affected, not life loss.
FDN (5 cards):
Custom → lose_life_opponents(1)Custom → lose_life_opponents(1)Custom → lose_life_opponents(2) + gain_life(2)Custom("You lose 1 life.") → lose_life(1)Custom → lose_life_opponents(1) + gain_life(1)ECL (2 cards):
TDM (1 card):
Custom → lose_life_opponents(2) (already had gain_life(2))docs/fdn-remediation.md — Added LoseLifeOpponents to effects table, marked 5 cards fixed, updated Phase 2 roadmapdocs/ecl-remediation.md — Updated Champion of the Weird and Boggart Mischief entriesdocs/tdm-remediation.md — Marked Skirmish Rhino as fixedROADMAP.md — Added LoseLifeOpponents to recently-implemented list, marked card-level fixes as doneDid we add tests for our new effect? If not let's do that.
Good catch — we didn't. Let me check where the existing effect tests live.
Good, I see the pattern. Tests use Game::new_two_player with AlwaysPassPlayer and call execute_effects directly. Let me add a test for LoseLifeOpponents right after gain_life_effect.
>cargo test --lib -p mtg-engine lose_life_opponents 2>&1Test passes. Now 158 engine tests (was 157) and 245 total.
How can we best do this work in a loop? Find a chunk of cards that share a common piece of missing implementation, implement the missing effect (if any) and implement the cards. Add tests for new effects, and update the documents. We should repeat this process over and over until we are done, using documents to maintain state instead of our context window.
The user wants to create a repeatable process for fixing cards in batches. Let me think about what they're asking:
They want this to be sustainable across context windows, using the docs as state. Let me think about the best approach.
The key insight is that we need a "work queue" document that tracks what's been done and what's next, organized by shared missing implementation. Let me look at what's currently in the remediation docs to understand the landscape of fixable card groups.
Now I'm reviewing the existing card groups to see what's already been addressed and what patterns emerge. I can see LoseLifeOpponents is done, there are several cards that just need simple effect swaps since the implementations already exist, and there are larger groups organized by the type of missing effect they need.
I'm thinking about how to structure this work systematically—organizing cards by their shared missing pieces, estimating the effort for each group, and tracking dependencies so we can tackle things in the right order. I should create a work queue document that groups everything clearly and gives us a concrete path forward.
Good question. The key is a work queue document that drives the loop — organized by shared missing implementation, not by card. Each iteration, you (or I) read the queue, pick the next batch, do the work, update docs, and move on. The context window never needs to hold the full history.
Let me scan the current state to build that queue.
Excellent! Now let me create the final comprehensive report:
## COMPREHENSIVE CUSTOM EFFECT ANALYSIS & CATEGORIZATION
### EXECUTIVE SUMMARY
**Total Custom Usages: ~825 across 4 sets**
- FDN: 320 (largest set)
- TDM: 120
- TLA: 197
- ECL: 188
**Breakdown:**
- **~301 placeholders** (Static/ETB/Activated/Spell stubs) - LOW VALUE, can ignore
- **~524 real game effects** - Grouped into 22 categories for prioritized implementation
---
## HIGH-ROI GROUPS (Best bang-for-buck)
### **GROUP 1: PLACEHOLDER STUBS** (301 total - IGNORE THESE)
- "Static effect." (108)
- "ETB effect." (94)
- "Activated effect." (73)
- "Spell effect." (26)
- "Attack trigger." (22)
- Other minor stubs (Spell cast trigger, Dies effect, etc.)
**Engine work needed:** NONE - These disappear as cards get real implementations. They safely resolve to `Custom("{text}")` which returns `Ok(())`.
---
### **GROUP 2: COMBAT & EVASION** (14 cards across 3 sets)
**Description:** Creatures with special combat rules (unblockable, can't block, etc.)
**Examples from code:**
- Line 2019 FDN: `"Can't be blocked by Humans."`
- FDN also has: `"Can't be blocked."`, `"Can't be blocked this turn."` (multiple)
- TDM: `"This creature can't be blocked this turn."`
- ECL: `"Can't be blocked by more than one creature."`, `"Daunt — can't be blocked by power 2 or less."`
**Engine work needed:**
```
StaticEffect::CantBlock (permanent, all blockers)
StaticEffect::CantBlockEot (until end of turn)
StaticEffect::UnblockableByType("Humans") (specific types)
StaticEffect::CantBeBlockedByMoreThanN(1)
```
**Impact:** 8-10 FDN/TDM/ECL cards fixed immediately
---
### **GROUP 3: WARD & COST REDUCTION** (13+ unique patterns)
**Description:** Protective costs and spell cost reduction mechanics
**Examples from code:**
- Line 347 TDM: `StaticEffect::Custom("Ward {2}".into())` (5 occurrences in TDM alone)
- Line 2019 TDM: Same Ward pattern repeats
- FDN has 4 distinct "This spell costs {N} less to cast if..." patterns
- ECL: `Evoke {R/W}{R/W}`, `Evoke {U/B}{U/B}`, `Evoke {W/B}{W/B}`
**Engine work needed:**
```
StaticEffect::Ward { cost: ManaCost } or Effect::Ward { cost }
SpellCostReduction with condition support
Evoke variants as cost reduction mechanics
```
**Impact:** 6+ TDM/ECL cards fixed immediately (Ward alone)
---
### **GROUP 4: DISTRIBUTED COUNTERS** (6+ cards, TDM focus)
**Description:** Put +1/+1 counters distributed among multiple creatures
**Examples from code:**
- TDM: `"Distribute three +1/+1 counters among one, two, or three target creatures you control."`
- TDM: `"Distribute two +1/+1 counters among one or two target creatures you control."`
**Engine work needed:**
```
Effect::DistributeCounters {
count: i32,
filter: String,
max_targets: Option<i32>
}
```
**Impact:** 6+ TDM cards
---
### **GROUP 5: MORBID & THRESHOLD CONDITIONALS** (7 cards, FDN only)
**Description:** Conditional effects based on game state (creatures died, graveyard size, etc.)
**Examples from code:**
- Line 5605 FDN: `"Morbid -- At the beginning of your end step, if a creature died this turn put a +1/+1 counter on this creature."`
- Line 6692 FDN: `"Morbid -- At the beginning of your end step, if a creature died this turn, put two +1/+1 counters on target creature you control."`
- Line 7125 FDN: `"Morbid -- At the beginning of each end step, if a creature died this turn, untap this creature."`
- Also Threshold effects: `"Threshold -- This creature can't be blocked as long as there are seven or more cards in your graveyard."`
**Engine work needed:**
```
Proper event system for Morbid (creature died this turn)
StaticEffect::ConditionalPT { condition, power, toughness }
Threshold checking mechanism
```
**Impact:** 7 FDN cards isolated to one set
---
### **GROUP 6: SAGA/ENCHANTMENT PROGRESSION** (6 cards)
**Description:** Saga mechanics with multi-step lore counter progression
**Examples from code:**
- TDM (4x): `"(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)"`
- TLA (2x): Similar saga patterns
**Engine work needed:**
- Lore counter tracking
- Episode 1/2/3 effect triggers at each threshold
- Sacrifice after 3 counters
**Impact:** 6 cards (4 TDM, 2 TLA)
---
### **GROUP 7: LOYALTY/PLANESWALKER EFFECTS** (8-10 cards)
**Description:** Planeswalker abilities with +1/0/−X loyalty costs
**Examples from code:**
- FDN: `"+1: Create a token that's a copy of target creature you control, except it has haste..."`
- FDN: `"+1: Look at the top four cards of your library..."`
- FDN: `"+1: Put a +1/+1 counter on up to one target creature."`
**Engine work needed:**
- Planeswalker loyalty tracking
- Loyalty ability cost system
**Impact:** 8-10 cards across FDN/other sets
---
### **GROUP 8: CREATE TOKENS** (20+ cards, all 4 sets)
**Description:** Token creation with various properties (generic, dynamic count, modified properties)
**Examples from code:**
- FDN: `"Create four 1/1 white Dog creature tokens."`, `"Create two 1/1 blue Faerie creature tokens with flying."`
- FDN: `"Create a token that's a copy of target creature you control, except it has haste and 'At the beginning of the end step, sacrifice this token.'"`
- TDM line 436: `"Create X 1/1 white Soldier creature tokens, where X is the number of creature cards in your graveyard."`
- TDM line 2170: `"Create X 1/1 white Spirit creature tokens with flying, where X is the number of creatures destroyed this way."`
- ECL: Kithkin token variations, token copy variants
**Engine work needed:**
```
Enhance CreateToken to support:
- Token copies with haste + sacrifice at EOT
- Tapped/attacking tokens (TDM patterns)
- Dynamic count (X = graveyard size, X = creatures destroyed, etc.)
- Flying variants for specific token types
```
**Impact:** 15+ cards across all 4 sets
---
### **GROUP 9: DRAW + CONDITIONAL/OPTIONAL EFFECTS** (15+ cards)
**Description:** Card draw linked to conditions, optional discard/draw combos
**Examples from code:**
- TDM: `"Draw a card if you control a creature with a counter on it. If you don't, put a +1/+1 counter on this creature."`
- TDM: `"Discard two cards unless you discard a creature card."`
- TDM: `"Discard up to two cards, then draw that many cards."`
- TDM: `"You may discard a card. If you do, draw a card."`
**Engine work needed:**
```
Effect::OptionalDiscard { count: i32 }
Conditional draw/discard chains
```
**Impact:** 15+ cards (FDN/TDM/ECL)
---
### **GROUP 10: CREATURE TYPE SELECTION** (8+ cards)
**Description:** Choose a creature type and apply type-based effects
**Examples from code:**
- FDN: `"Choose a creature type. This creature becomes that type."`
- ECL: `"Choose a creature type on ETB."`, `"Choose a creature type. Return all creature cards of the chosen type from your graveyard to the battlefield."`
- FDN: `"Chosen type creatures get +1/+1 per fellowship counter."`
**Engine work needed:**
- Type selection mechanism
- Type-based boosting/filtering
**Impact:** 8+ cards (FDN/ECL)
---
### **GROUP 11: LAND SEARCH & TUTORS** (12+ cards)
**Description:** Search library for lands or cards with specific conditions
**Examples from code:**
- FDN: `"Sacrifice a land, search for 2 basic lands tapped."`, `"Search your library for up to two basic lands and/or Gates..."`
**Engine work needed:**
- Enhanced `SearchLibrary` with multi-type support
- Sacrifice-as-cost mechanics
**Impact:** 12+ cards (mostly FDN)
---
### **GROUP 12: TRIGGERED ON-ATTACK** (8+ unique patterns)
**Description:** Various triggers when creatures attack
**Examples from code:**
- FDN: `"Whenever Drakuseth, Maw of Flames attacks, it deals 4 damage to any target and 3 damage to each of up to two other targets."`
- FDN: `"Whenever this creature attacks, you may sacrifice another creature. If you do, draw a card and this creature can't be blocked this turn."`
**Engine work needed:**
- Better attack trigger delegation
- Dynamic multi-target handling
**Impact:** 8+ cards (FDN dominant)
---
### **GROUP 13: MODAL/CHOICE EFFECTS** (15+ cards)
**Description:** Spells with "Choose one:" or "Choose two:" options
**Examples from code:**
- Line 2495 FDN: `"Choose one: Deal 3 damage to target creature, or destroy target artifact."`
- Line 2507 FDN: `"Choose one: 4 damage to target player/planeswalker; or permanents you control gain indestructible until EOT; or target creature gains double strike until EOT."`
- TDM: `"Choose one: Creatures target opponent controls get -1/-1 until end of turn; or return up to two creature cards from your graveyard to your hand."`
- ECL: `"Choose two: copy target Kithkin you control; target player creates 1/1 Kithkin token; ..."`
**Engine work needed:**
- Proper modal effect system with player choice resolution
- Support for X or Y or Z patterns
- Multi-mode (Choose two) support
**Impact:** 15+ cards across all sets (FDN dominant)
---
## MEDIUM-VALUE GROUPS
### **GROUP 14: BLIGHT MECHANIC** (5 cards, ECL focus)
`"As an additional cost to cast this spell, blight 1 or pay {3}."`, `"Blight 1, create a Treasure token."`, etc.
---
### **GROUP 15: COLOR-DEPENDENT EFFECTS** (8+ cards, ECL)
`"Deals X damage where X = colors among your permanents."`, `"Draw X cards where X = colors among your permanents."`, etc.
---
### **GROUP 16-21:** Additional medium-priority groups
Flicker/Bounce, Destruction variants, Graveyard recursion, Life gain/loss variants, Extra combat phases, Copy & casting effects
---
## RECOMMENDED IMPLEMENTATION ROADMAP
### **QUICK WINS (5-10 min each):**
1. **Combat/Evasion** - Add `StaticEffect::CantBlock`, `CantBlockEot` (fixes ~8-10 cards)
2. **Ward** - Convert to proper effect (fixes ~6 cards immediately in TDM/ECL)
3. **Enhanced CreateToken** - Support copies, haste+sac, dynamic count (fixes ~15+ cards)
### **MEDIUM-EFFORT (20-30 min each):**
4. **Distributed Counters** (6+ cards)
5. **Morbid/Threshold conditionals** (7 FDN cards)
6. **Modal/Choice effects** (15+ cards across all sets)
### **LONGER-TERM:**
7. Saga mechanics (6 cards)
8. Set-specific: Blight, Endure, Evoke, Harmonize, etc.
---
## FILE DISTRIBUTION SUMMARY
| Group | FDN | TDM | TLA | ECL | Total |
|-------|-----|-----|-----|-----|-------|
| Combat/Evasion | 9 | 2 | - | 1 | 14 |
| Ward & Cost Reduction | 4 | 6 | - | 3+ | 13+ |
| Create Tokens | 4 | 6 | 2 | 8+ | 20+ |
| Morbid/Threshold | 7 | - | - | - | 7 |
| Modal/Choice | 8+ | 4+ | - | 2+ | 15+ |
| Draw/Conditional | 3 | 8+ | 2 | 2+ | 15+ |
| Saga | - | 4 | 2 | - | 6 |
All exact file locations are in `/mnt/dest-btrfs/home/jc/src/mage/mtg-rl/mtg-cards/src/sets/{fdn,tla,tdm,ecl}.rs`
agentId: a8903eb (for resuming to continue this agent's work if needed)
<usage>total_tokens: 52082
tool_uses: 12
duration_ms: 212009</usage>The user wants me to design a repeatable process for fixing cards in batches. The exploration agent gave me a good overview of the groups. Now I need to:
Let me also do my own quick verification of the "easy swap" cases - cards where a typed effect already exists but the card still uses Custom. Those are the quickest wins and should be the first batches.
Let me grep for specific easy-swap patterns to get accurate counts before building the queue.
Good data from the scan. Before building the work queue, let me verify the easy-swap cases precisely — cards where a typed effect already exists but the card still uses Custom.
>grep -n 'Effect::Custom(' mtg-cards/src/sets/*.rs | grep -viE '(effect\.|static effect\.|activated effect\.|spell effect\.|attack trigger\.|etb effect\.|dies effect\.|spell cast trigger\.|combat damage trigger\.|triggered effect\.)' | grep -iE '(destroy all|each opponent discard|enters tapped|can.t block this turn|target creature can.t block|loses? \d+ life|gains? \d+ life|deal.? \d+ damage|draw.? (a |one |\d+ )card|scry|mill|create.*token|search.*library|return.*graveyard.*hand|exile target|counter target|tap target|untap target|sacrifice a|discard a card)' | head -60>grep -n 'StaticEffect::Custom(' mtg-cards/src/sets/*.rs | grep -viE '(static effect\.)' | head -40Now let me also count the easy-swap candidates precisely.
># Count exact easy-swap patterns
echo "=== Enters tapped ==="
grep -n 'StaticEffect::Custom("Enters tapped' mtg-cards/src/sets/*.rs
echo ""
echo "=== Destroy all creatures ==="
grep -n 'Effect::Custom("Destroy all creatures' mtg-cards/src/sets/*.rs
echo ""
echo "=== Each opponent discards a card ==="
grep -n 'Effect::Custom("Each opponent discards a card' mtg-cards/src/sets/*.rs
echo ""
echo "=== Target creature can't block this turn ==="
grep -n "Effect::Custom(\"Target creature can.t block this turn" mtg-cards/src/sets/*.rs
echo ""
echo "=== draw a card (simple ETB/trigger) ==="
grep -n 'Effect::Custom("When this creature enters, draw a card' mtg-cards/src/sets/*.rs
echo ""
echo "=== draw a card, then discard ==="
grep -n 'Effect::Custom(".*draw a card, then discard a card' mtg-cards/src/sets/*.rs
echo ""
echo "=== Ward {2} ==="
grep -n 'StaticEffect::Custom("Ward' mtg-cards/src/sets/*.rs
echo ""
echo "=== Self -1/-1 counter ==="
grep -n 'Effect::Custom("Put.*-1/-1 counter.*on.*\(this\|Sourbread\|Heirloom\|Sting\|Blighted\|Dream\)' mtg-cards/src/sets/*.rsNow I have a clear picture. Let me create the work queue document.
>ls /mnt/dest-btrfs/home/jc/src/mage/mtg-rl/docs/Now let me update the memory file so future sessions know about this process.
Here's the approach:
Created docs/work-queue.md — a batch-oriented work queue that drives each session. The process for every batch:
docs/work-queue.md → find next unchecked batchgame.rs), if neededcargo check && cargo test --libwork-queue.md| # | Batch | Engine work? | Cards |
|---|---|---|---|
| 1 | LoseLifeOpponents | New variant | 8 DONE |
| 2 | Easy swaps (DestroyAll, EntersTapped, CantBlock, self-counters, loot) | None | ~12 |
| 3 | OpponentDiscards | New variant | 3+ |
| 4 | Simple token creation (stubs with full text) | None | 6+ |
| 5 | Ward keyword | New StaticEffect | 6 |
| 6 | Enters-tapped-unless | New StaticEffect | 2 |
| 7 | Mass keyword grant EOT | New Effect | 5+ |
| 8 | Fight/Bite | New Effect | ~10 |
| 9 | Modal spells | New framework | 15+ |
| 10+ | Equipment, Planeswalkers, Token copy, X-cost, etc. | Major systems | many |
The key insight: docs are the state, not the context window. Any session can pick up where the last left off by reading work-queue.md. Want me to start on Batch 2 now?
What instructions would I give you to run the loop?
The user wants a prompt/instruction they can paste into a new Claude Code session to kick off the loop. Let me think about what that would look like.
The key requirements:
Let me draft something concise but complete.
Something like this:
Read docs/work-queue.md and do the next unchecked batch. For each batch:
1. Read the engine files (mtg-engine/src/abilities.rs, mtg-engine/src/game.rs) to understand current Effect/StaticEffect variants2. If engine work is needed: add the variant, constructor, and match arm3. Add a test for any new engine effect (follow the pattern in game.rs mod tests)4. Fix all cards listed in the batch (grep to find exact lines, fix across all 4 set files)5. cargo check -p mtg-cards && cargo test --lib6. Update docs: mark cards in docs/{fdn,tla,tdm,ecl}-remediation.md, update ROADMAP.md7. Check off the batch in docs/work-queue.md with today's date
Then do the next batch. Repeat until context is getting long, then stop and make sure work-queue.md is current.That's the core. A few things to consider:
What makes this work well:
work-queue.md has all the specifics (line numbers, exact substitutions, notes about gotchas)What could go wrong:
AddCounters works on self without a target. That needs investigation before fixing. The instructions should handle uncertainty gracefully.Optional additions:
If a batch has a NOTE about uncertainty, investigate first and update the queue with findings before committing the fix.If you discover new cards that fit an existing batch while working, add them.If a batch turns out to be wrong or more complex than described, update the queue and move on to the next one.Want me to put this into a file (like a CLAUDE.md section or a script) so it's always available, or is copy-paste sufficient?
Let's create a file called docs/work-queue-instructions.md. If you think the optional additions are valuable, add those as well.
Implement the following plan:
The FDN remediation doc identifies "Partial" cards using Effect::Custom(...) for abilities that should use typed variants. Four of these cards say "each opponent loses N life" — the Java implementation uses LoseLifeOpponentsEffect (life loss), which is mechanically distinct from damage in MTG rules. Our engine has DealDamageOpponents but no life-loss-to-opponents variant. We'll add LoseLifeOpponents to match the Java model, then fix 5 cards.
Effect::LoseLifeOpponents variantmtg-engine/src/abilities.rs
Effect enum in the // -- Life -- section (~line 77):
/// Each opponent loses life.LoseLifeOpponents { amount: u32 },pub fn lose_life_opponents(amount: u32) -> Self { Effect::LoseLifeOpponents { amount }}mtg-engine/src/game.rs — Add match arm in execute_effects() (after LoseLife arm, ~line 1015):
Effect::LoseLifeOpponents { amount } => { let opponents: Vec<PlayerId> = self.state.turn_order.iter() .filter(|&&id| id != controller) .copied() .collect(); for opp in opponents { if let Some(player) = self.state.players.get_mut(&opp) { player.life -= *amount as i32; } }}(Same implementation as DealDamageOpponents for now, but semantically correct — when damage prevention is added later, only DealDamageOpponents will be affected.)
All in mtg-cards/src/sets/fdn.rs — single-line replacements:
| Card | Current | Fix |
|---|---|---|
| Marauding Blight-Priest (~line 836) | Effect::Custom("Each opponent loses 1 life.".into()) | Effect::lose_life_opponents(1) |
| Pulse Tracker (~line 850) | Effect::Custom("Each opponent loses 1 life.".into()) | Effect::lose_life_opponents(1) |
| Vampire Spawn (~line 967) | Effect::Custom("Each opponent loses 2 life, you gain 2 life.".into()) | Effect::lose_life_opponents(2), Effect::gain_life(2) |
| Vampire Neonate (~line 1702) | Effect::Custom("Each opponent loses 1 life, you gain 1 life.".into()) | Effect::lose_life_opponents(1), Effect::gain_life(1) |
| Phyrexian Arena (~line 1410) | Effect::Custom("You lose 1 life.".into()) | Effect::lose_life(1) |
cargo check -p mtg-engine — new variant compilescargo check -p mtg-cards — card changes compilecargo test --lib — all tests passIf you need specific details from before exiting plan mode (like exact code snippets, error messages, or content you generated), read the full transcript at: /mnt/dest-btrfs/home/jc/.claude/projects/-mnt-dest-btrfs-home-jc-src-mage/a83bffdc-973c-4730-8a88-2ef219ba63de.jsonl
If this plan can be broken down into multiple independent tasks, consider using the TeamCreate tool to create a team and parallelize the work.
Done. The file is at docs/work-queue-instructions.md — you can just paste its contents into a fresh session to kick off the loop. The queue state lives in docs/work-queue.md so sessions pick up where the last one left off.
Now I have all the exact lines. Let me make all the changes.
Now add the match arm in game.rs and fix all 5 cards in fdn.rs.
I'll implement this plan step by step. Let me start by reading the relevant files.
Need to read game.rs first. Let me do that and retry all the edits.
All edits done. Now let's verify compilation and run tests.
>cd /mnt/dest-btrfs/home/jc/src/mage/mtg-rl && cargo check -p mtg-engine 2>&1>cargo check -p mtg-cards 2>&1>cargo test --lib 2>&1All 244 tests pass (52 + 18 + 157 + 17). Here's a summary of the changes:
mtg-engine/src/abilities.rs:
LoseLifeOpponents { amount: u32 } variant to the Effect enumlose_life_opponents(amount) constructor methodmtg-engine/src/game.rs:
LoseLifeOpponents in execute_effects() — iterates opponents and subtracts lifemtg-cards/src/sets/fdn.rs — Fixed 5 cards:
Custom(...) → lose_life_opponents(1)Custom(...) → lose_life_opponents(1)Custom(...) → lose_life_opponents(2), gain_life(2)Custom("You lose 1 life.") → lose_life(1)Custom(...) → lose_life_opponents(1), gain_life(1)Let's update the @docs/fdn-remediation.md doc and @ROADMAP.md to reflect that we did this. Let's also fix other cards that are now possible because we added this effect.
Let me first check what other cards across all sets use similar "each opponent loses" Custom effects that can now be fixed with LoseLifeOpponents.
Good. I can see 3 clean matches across ECL and TDM that can be fixed the same way. Let me read the surrounding context for each.
Now let me fix these 3 additional cards and also read the remediation docs so I can update them.
Now let me verify everything still compiles.
>cargo check -p mtg-cards 2>&1Good. Now let me check the remediation docs for ECL and TDM to understand what needs updating there too.
Now let me read the specific sections of the docs that need updating. Let me also check the FDN remediation doc for the entries about the 5 cards we fixed, and read the current "Effects that ACTUALLY WORK" table line count so I can add LoseLifeOpponents.
Now let me read the Partial Cards sections for the cards we fixed (Marauding Blight-Priest, Pulse Tracker, Vampire Spawn, Phyrexian Arena, Vampire Neonate) and the Phase 2 roadmap section.
Read docs/work-queue.md and do the next unchecked batch. For each batch:
1. Read the engine files (mtg-engine/src/abilities.rs, mtg-engine/src/game.rs) to understand current Effect/StaticEffect variants2. If engine work is needed: add the variant, constructor, and match arm3. Add a test for any new engine effect (follow the pattern in game.rs mod tests)4. Fix all cards listed in the batch (grep to find exact lines, fix across all 4 set files)5. cargo check -p mtg-cards && cargo test --lib6. Update docs: mark cards in docs/{fdn,tla,tdm,ecl}-remediation.md, update ROADMAP.md7. Check off the batch in docs/work-queue.md with today's date
Then do the next batch. Repeat until context is getting long, then stop and make sure work-queue.md is current./// Each opponent loses life.LoseLifeOpponents { amount: u32 },pub fn lose_life_opponents(amount: u32) -> Self { Effect::LoseLifeOpponents { amount }}Effect::LoseLifeOpponents { amount } => { let opponents: Vec<PlayerId> = self.state.turn_order.iter() .filter(|&&id| id != controller) .copied() .collect(); for opp in opponents { if let Some(player) = self.state.players.get_mut(&opp) { player.life -= *amount as i32; } }}