From d145885d2d20ca8a617b0a65f5723073e76a8d9f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 18 Oct 2015 10:21:12 +0200 Subject: [PATCH] * Sylvan Library - Fixed that a player that controlled a Sylvan Library from another player was not forced to play life for cards he kept from Sylvan Library's triggered ability (fixes #1307). --- .../mage/sets/fifthedition/SylvanLibrary.java | 37 ++++++----- .../ExileAndReturnUnderYourControl.java | 62 ++++++++++++++++--- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index afa1cd28900..d20b20c4158 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -27,7 +27,9 @@ */ package mage.sets.fifthedition; -import java.util.HashSet; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import java.util.UUID; import mage.MageObject; @@ -64,7 +66,8 @@ public class SylvanLibrary extends CardImpl { this.expansionSetCode = "5ED"; // At the beginning of your draw step, you may draw two additional cards. If you do, choose two cards in your hand drawn this turn. For each of those cards, pay 4 life or put the card on top of your library. - this.addAbility(new BeginningOfDrawTriggeredAbility(new SylvanLibraryEffect(), TargetController.YOU, true), new CardsDrawnThisTurnWatcher()); + this.addAbility(new BeginningOfDrawTriggeredAbility(new SylvanLibraryEffect(), TargetController.YOU, true), + new CardsDrawnThisTurnWatcher()); } @@ -99,11 +102,11 @@ class SylvanLibraryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.drawCards(2, game); - CardsDrawnThisTurnWatcher watcher = (CardsDrawnThisTurnWatcher) game.getState().getWatchers().get("CardsDrawnThisTurnWatcher", source.getControllerId()); + CardsDrawnThisTurnWatcher watcher = (CardsDrawnThisTurnWatcher) game.getState().getWatchers().get("CardsDrawnThisTurnWatcher"); if (watcher != null) { Cards cards = new CardsImpl(); for (UUID cardId : controller.getHand()) { - if (watcher.getCardsDrawnThisTurn().contains(cardId)) { + if (watcher.getCardsDrawnThisTurn(controller.getId()).contains(cardId)) { Card card = game.getCard(cardId); if (card != null) { cards.add(card); @@ -161,26 +164,31 @@ class SylvanLibraryEffect extends OneShotEffect { class CardsDrawnThisTurnWatcher extends Watcher { - private final Set cardsDrawnThisTurn = new HashSet(); + private final Map> cardsDrawnThisTurn = new HashMap<>(); public CardsDrawnThisTurnWatcher() { - super("CardsDrawnThisTurnWatcher", WatcherScope.PLAYER); + super("CardsDrawnThisTurnWatcher", WatcherScope.GAME); } public CardsDrawnThisTurnWatcher(final CardsDrawnThisTurnWatcher watcher) { super(watcher); - this.cardsDrawnThisTurn.addAll(watcher.cardsDrawnThisTurn); + this.cardsDrawnThisTurn.putAll(watcher.cardsDrawnThisTurn); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DREW_CARD && event.getPlayerId().equals(this.getControllerId())) { - cardsDrawnThisTurn.add(event.getTargetId()); + if (event.getType() == GameEvent.EventType.DREW_CARD) { + if (!cardsDrawnThisTurn.containsKey(event.getPlayerId())) { + Set cardsDrawn = new LinkedHashSet<>(); + cardsDrawnThisTurn.put(event.getPlayerId(), cardsDrawn); + } + Set cardsDrawn = cardsDrawnThisTurn.get(event.getPlayerId()); + cardsDrawn.add(event.getTargetId()); } } - public Set getCardsDrawnThisTurn() { - return cardsDrawnThisTurn; + public Set getCardsDrawnThisTurn(UUID playerId) { + return cardsDrawnThisTurn.get(playerId); } @Override @@ -195,7 +203,6 @@ class CardsDrawnThisTurnWatcher extends Watcher { } } - class CardIdPredicate implements Predicate { private final Cards cardsId; @@ -206,10 +213,8 @@ class CardIdPredicate implements Predicate { @Override public boolean apply(MageObject input, Game game) { - for(UUID uuid : cardsId) - { - if(uuid.equals(input.getId())) - { + for (UUID uuid : cardsId) { + if (uuid.equals(input.getId())) { return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java index 5f1c950fb75..13f434621e6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java @@ -7,11 +7,12 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Tests the effect: - * - Exile target creature you control, then return that card to the battlefield under your control + * Tests the effect: - Exile target creature you control, then return that card + * to the battlefield under your control * - * This effect grants you permanent control over the returned creature. - * So you mail steal opponent's creature with "Act of Treason" and then use this effect for permanent control effect. + * This effect grants you permanent control over the returned creature. So you + * mail steal opponent's creature with "Act of Treason" and then use this effect + * for permanent control effect. * * @author noxx */ @@ -67,7 +68,7 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { Assert.assertTrue("player A should play with top card revealed", playerA.isTopCardRevealed()); Assert.assertFalse("player B should play NOT with top card revealed", playerB.isTopCardRevealed()); } - + @Test public void testVillainousWealthExilesBoost() { // Villainous Wealth {X}{B}{G}{U} @@ -76,14 +77,14 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { // their mana costs. addCard(Zone.HAND, playerA, "Villainous Wealth"); addCard(Zone.HAND, playerA, "Master of Pearls"); - + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 4); // Secret Plans {G}{U} // Face-down creatures you control get +0/+1. - // Whenever a permanent you control is turned face up, draw a card. + // Whenever a permanent you control is turned face up, draw a card. addCard(Zone.LIBRARY, playerB, "Secret Plans"); skipInitShuffling(); // to keep this card on top of library @@ -101,9 +102,50 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { assertExileCount(playerB, 2); assertExileCount("Secret Plans", 0); assertPermanentCount(playerA, "Secret Plans", 1); - + assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 3); - } + assertPowerToughness(playerA, "", 2, 3); + } + + /** + * My opponent cast Villainous Wealth and took control of my Sylvan Library. + * On his next turn, when Sylvan Library's trigger resolved, he kept the two + * extra cards without paying life. + */ + @Test + public void testVillainousWealthExilesSylvanLibrary() { + // Villainous Wealth {X}{B}{G}{U} + // Target opponent exiles the top X cards of his or her library. You may cast any number + // of nonland cards with converted mana cost X or less from among them without paying + // their mana costs. + addCard(Zone.HAND, playerA, "Villainous Wealth"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // At the beginning of your draw step, you may draw two additional cards. + // If you do, choose two cards in your hand drawn this turn. + // For each of those cards, pay 4 life or put the card on top of your library. + addCard(Zone.LIBRARY, playerB, "Sylvan Library"); + skipInitShuffling(); // to keep this card on top of library + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Villainous Wealth", playerB); + setChoice(playerA, "X=3"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sylvan Library"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Villainous Wealth", 1); + assertExileCount(playerB, 2); + assertExileCount("Sylvan Library", 0); + assertPermanentCount(playerA, "Sylvan Library", 1); + + assertHandCount(playerB, 1); + assertHandCount(playerA, 3); + assertLife(playerA, 12); + assertLife(playerB, 20); + + } }