From bd6fa770aac1e9da47ff2840bf1d4c515e31646d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Aug 2015 03:31:44 +0200 Subject: [PATCH] * Fixed a lot of cards where order of card discarding/hand,graveyard,permanents into library shuffling and card draw order was not correctly implemented. This could cause bugs for draw replacement effects (e.g. Notion Thief). --- .../sets/avacynrestored/ReforgeTheSoul.java | 10 +- .../betrayersofkamigawa/SwayOfTheStars.java | 43 ++++---- .../sets/commander2013/IncendiaryCommand.java | 22 +++-- .../src/mage/sets/fatereforged/DarkDeal.java | 13 ++- .../mage/sets/limitedalpha/Timetwister.java | 28 ++---- .../src/mage/sets/magic2011/TimeReversal.java | 41 ++++---- .../mage/sets/magicorigins/DaysUndoing.java | 28 ++---- .../sets/magicorigins/TheGreatAurora.java | 2 +- .../sets/ninthedition/TeferisPuzzleBox.java | 40 ++------ .../sets/planechase2012/WhirlpoolWarrior.java | 38 ++++--- .../sets/scarsofmirrodin/MoltenPsyche.java | 77 +++++++++------ .../src/mage/sets/urzassaga/TimeSpiral.java | 28 +++--- .../src/mage/sets/urzassaga/Windfall.java | 12 +-- .../src/mage/sets/zendikar/ChandraAblaze.java | 23 +---- .../cards/replacement/DrawEffectsTest.java | 28 ++++++ .../common/SetPlayerLifeAllEffect.java | 99 +++++++++++++++++++ Mage/src/mage/actions/MageDrawAction.java | 12 +-- 17 files changed, 329 insertions(+), 215 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/SetPlayerLifeAllEffect.java diff --git a/Mage.Sets/src/mage/sets/avacynrestored/ReforgeTheSoul.java b/Mage.Sets/src/mage/sets/avacynrestored/ReforgeTheSoul.java index 7047040a5fc..d59ec802eb4 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/ReforgeTheSoul.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/ReforgeTheSoul.java @@ -30,7 +30,10 @@ package mage.sets.avacynrestored; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.discard.DiscardHandAllEffect; import mage.abilities.keyword.MiracleAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -50,9 +53,11 @@ public class ReforgeTheSoul extends CardImpl { super(ownerId, 151, "Reforge the Soul", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); this.expansionSetCode = "AVR"; - // Each player discards his or her hand, then draws seven cards. - this.getSpellAbility().addEffect(new ReforgeTheSoulEffect()); + this.getSpellAbility().addEffect(new DiscardHandAllEffect()); + Effect effect = new DrawCardAllEffect(7); + effect.setText(", then draws seven cards"); + this.getSpellAbility().addEffect(effect); // Miracle {1}{R} this.addAbility(new MiracleAbility(this, new ManaCostsImpl("{1}{R}"))); @@ -94,7 +99,6 @@ class ReforgeTheSoulEffect extends OneShotEffect { for (Card card : player.getHand().getCards(game)) { player.discard(card, source, game); } - player.drawCards(7, game); } } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SwayOfTheStars.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SwayOfTheStars.java index 5641bb5968e..4764132a428 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SwayOfTheStars.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SwayOfTheStars.java @@ -28,14 +28,18 @@ package mage.sets.betrayersofkamigawa; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.SetPlayerLifeAllEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; +import mage.filter.FilterPermanent; +import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -50,9 +54,12 @@ public class SwayOfTheStars extends CardImpl { super(ownerId, 54, "Sway of the Stars", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{8}{U}{U}"); this.expansionSetCode = "BOK"; - // Each player shuffles his or her hand, graveyard, and permanents he or she owns into his or her library, then draws seven cards. Each player's life total becomes 7. this.getSpellAbility().addEffect(new SwayOfTheStarsEffect()); + Effect effect = new DrawCardAllEffect(7); + effect.setText(", then draws seven cards"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new SetPlayerLifeAllEffect(7)); } @@ -66,7 +73,6 @@ public class SwayOfTheStars extends CardImpl { } } - class SwayOfTheStarsEffect extends OneShotEffect { public SwayOfTheStarsEffect() { @@ -80,24 +86,19 @@ class SwayOfTheStarsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); - for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - - for (UUID playerId: sourcePlayer.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getHand().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card: player.getGraveyard().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + player.moveCards(player.getGraveyard(), Zone.GRAVEYARD, Zone.LIBRARY, source, game); + FilterPermanent filter = new FilterPermanent(); + filter.add(new OwnerIdPredicate(playerId)); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { + permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } player.shuffleLibrary(game); - player.drawCards(7, game); - player.setLife(7, game); } } return true; @@ -108,4 +109,4 @@ class SwayOfTheStarsEffect extends OneShotEffect { return new SwayOfTheStarsEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/commander2013/IncendiaryCommand.java b/Mage.Sets/src/mage/sets/commander2013/IncendiaryCommand.java index 133206403f4..15d7bd457fe 100644 --- a/Mage.Sets/src/mage/sets/commander2013/IncendiaryCommand.java +++ b/Mage.Sets/src/mage/sets/commander2013/IncendiaryCommand.java @@ -27,6 +27,8 @@ */ package mage.sets.commander2013; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; @@ -54,8 +56,7 @@ public class IncendiaryCommand extends CardImpl { super(ownerId, 113, "Incendiary Command", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); this.expansionSetCode = "C13"; - - // Choose two - + // Choose two - this.getSpellAbility().getModes().setMinModes(2); this.getSpellAbility().getModes().setMaxModes(2); // Incendiary Command deals 4 damage to target player; @@ -107,16 +108,23 @@ class IncendiaryCommandDrawEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId : controller.getInRange()) { + Map cardsToDraw = new HashMap<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - int cards = player.getHand().size(); - if (cards > 0) { - player.discard(cards, source, game); - player.drawCards(cards, game); + int cardsInHand = player.getHand().size(); + player.discard(cardsInHand, false, source, game); + if (cardsInHand > 0) { + cardsToDraw.put(playerId, cardsInHand); } } } + for (UUID playerId : cardsToDraw.keySet()) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(cardsToDraw.get(playerId), game); + } + } return true; } return false; diff --git a/Mage.Sets/src/mage/sets/fatereforged/DarkDeal.java b/Mage.Sets/src/mage/sets/fatereforged/DarkDeal.java index ae2ee332e95..d9530570948 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/DarkDeal.java +++ b/Mage.Sets/src/mage/sets/fatereforged/DarkDeal.java @@ -27,6 +27,8 @@ */ package mage.sets.fatereforged; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -81,16 +83,23 @@ class DarkDealEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId : controller.getInRange()) { + Map cardsToDraw = new LinkedHashMap<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { int cardsInHand = player.getHand().size(); player.discard(cardsInHand, false, source, game); if (cardsInHand > 1) { - player.drawCards(cardsInHand - 1, game); + cardsToDraw.put(playerId, cardsInHand - 1); } } } + for (UUID playerId : cardsToDraw.keySet()) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(cardsToDraw.get(playerId), game); + } + } return true; } return false; diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Timetwister.java b/Mage.Sets/src/mage/sets/limitedalpha/Timetwister.java index c35a2e31b6a..b515aba3a58 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/Timetwister.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/Timetwister.java @@ -29,8 +29,9 @@ package mage.sets.limitedalpha; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.DrawCardAllEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -49,9 +50,11 @@ public class Timetwister extends CardImpl { super(ownerId, 85, "Timetwister", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{U}"); this.expansionSetCode = "LEA"; - // Each player shuffles his or her hand and graveyard into his or her library, then draws seven cards. this.getSpellAbility().addEffect(new TimetwisterEffect()); + Effect effect = new DrawCardAllEffect(7); + effect.setText(", then draws seven cards"); + this.getSpellAbility().addEffect(effect); } @@ -69,7 +72,7 @@ class TimetwisterEffect extends OneShotEffect { public TimetwisterEffect() { super(Outcome.Neutral); - staticText = "Each player shuffles his or her hand and graveyard into his or her library, then draws seven cards"; + staticText = "Each player shuffles his or her hand and graveyard into his or her library"; } public TimetwisterEffect(final TimetwisterEffect effect) { @@ -78,27 +81,14 @@ class TimetwisterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId: sourcePlayer.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getHand().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card: player.getGraveyard().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + player.moveCards(player.getGraveyard(), Zone.GRAVEYARD, Zone.LIBRARY, source, game); player.shuffleLibrary(game); - } } - game.getState().handleSimultaneousEvent(game); // needed here so state based triggered effects - for (UUID playerId: sourcePlayer.getInRange()) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.drawCards(7, game); - } - } return true; } diff --git a/Mage.Sets/src/mage/sets/magic2011/TimeReversal.java b/Mage.Sets/src/mage/sets/magic2011/TimeReversal.java index 6762ceeef9a..adf004f62a1 100644 --- a/Mage.Sets/src/mage/sets/magic2011/TimeReversal.java +++ b/Mage.Sets/src/mage/sets/magic2011/TimeReversal.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,23 +20,23 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2011; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileSpellEffect; -import mage.cards.Card; -import mage.cards.CardImpl; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -51,7 +51,11 @@ public class TimeReversal extends CardImpl { super(ownerId, 75, "Time Reversal", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); this.expansionSetCode = "M11"; + // Each player shuffles his or her hand and graveyard into his or her library, then draws seven cards this.getSpellAbility().addEffect(new TimeReversalEffect()); + Effect effect = new DrawCardAllEffect(7); + effect.setText(", then draws seven cards"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); } @@ -78,18 +82,13 @@ class TimeReversalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId: sourcePlayer.getInRange()) { + Player controller = game.getPlayer(source.getControllerId()); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getHand().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card: player.getGraveyard().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + player.moveCards(player.getGraveyard(), Zone.GRAVEYARD, Zone.LIBRARY, source, game); player.shuffleLibrary(game); - player.drawCards(7, game); } } return true; @@ -100,4 +99,4 @@ class TimeReversalEffect extends OneShotEffect { return new TimeReversalEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magicorigins/DaysUndoing.java b/Mage.Sets/src/mage/sets/magicorigins/DaysUndoing.java index a77cbe2b199..9e68ba3fd71 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/DaysUndoing.java +++ b/Mage.Sets/src/mage/sets/magicorigins/DaysUndoing.java @@ -31,9 +31,10 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.EndTurnEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -54,6 +55,9 @@ public class DaysUndoing extends CardImpl { // Each player shuffles his or her hand and graveyard into his or her library, then draws seven cards. If it's your turn, end the turn. this.getSpellAbility().addEffect(new DaysUndoingEffect()); + Effect effect = new DrawCardAllEffect(7); + effect.setText(", then draws seven cards"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new EndTurnEffect(), MyTurnCondition.getInstance(), "If it's your turn, end the turn")); } @@ -71,7 +75,7 @@ class DaysUndoingEffect extends OneShotEffect { public DaysUndoingEffect() { super(Outcome.Neutral); - staticText = "Each player shuffles his or her hand and graveyard into his or her library, then draws seven cards"; + staticText = "Each player shuffles his or her hand and graveyard into his or her library"; } public DaysUndoingEffect(final DaysUndoingEffect effect) { @@ -80,28 +84,16 @@ class DaysUndoingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId : sourcePlayer.getInRange()) { + Player controller = game.getPlayer(source.getControllerId()); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card : player.getHand().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card : player.getGraveyard().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - game.informPlayers(player.getLogName() + " puts his or her hand and graveyard into his or her library"); + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + player.moveCards(player.getGraveyard(), Zone.GRAVEYARD, Zone.LIBRARY, source, game); player.shuffleLibrary(game); } } - game.getState().handleSimultaneousEvent(game); // needed here so state based triggered effects - for (UUID playerId : sourcePlayer.getInRange()) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.drawCards(7, game); - } - } return true; } diff --git a/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java b/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java index dd5b0b2a6ca..93e61a08d9e 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java +++ b/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java @@ -94,7 +94,7 @@ class TheGreatAuroraEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Map> permanentsOwned = new HashMap<>(); - Collection permanents = game.getBattlefield().getAllPermanents(); + Collection permanents = game.getBattlefield().getActivePermanents(source.getControllerId(), game); for (Permanent permanent : permanents) { List list = permanentsOwned.get(permanent.getOwnerId()); if (list == null) { diff --git a/Mage.Sets/src/mage/sets/ninthedition/TeferisPuzzleBox.java b/Mage.Sets/src/mage/sets/ninthedition/TeferisPuzzleBox.java index 636a1fe1ad8..a62fe24a922 100644 --- a/Mage.Sets/src/mage/sets/ninthedition/TeferisPuzzleBox.java +++ b/Mage.Sets/src/mage/sets/ninthedition/TeferisPuzzleBox.java @@ -27,25 +27,22 @@ */ package mage.sets.ninthedition; -import mage.constants.*; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.filter.FilterCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; - -import java.util.UUID; /** * * @author noxx - + * */ public class TeferisPuzzleBox extends CardImpl { @@ -87,30 +84,7 @@ class TeferisPuzzleBoxEffect extends OneShotEffect { Player player = game.getPlayer(targetPointer.getFirst(game, source)); if (player != null) { int count = player.getHand().size(); - - // puts the cards in his or her hand on the bottom of his or her library in any order - Cards cards = new CardsImpl(); - for (Card card : player.getHand().getCards(game)) { - cards.add(card.getId()); - } - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - player.getHand().clear(); - - // draws that many cards + player.putCardsOnBottomOfLibrary(player.getHand(), game, source, true); player.drawCards(count, game); } return true; diff --git a/Mage.Sets/src/mage/sets/planechase2012/WhirlpoolWarrior.java b/Mage.Sets/src/mage/sets/planechase2012/WhirlpoolWarrior.java index 475a7fd9634..059d5a709c2 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/WhirlpoolWarrior.java +++ b/Mage.Sets/src/mage/sets/planechase2012/WhirlpoolWarrior.java @@ -27,11 +27,9 @@ */ package mage.sets.planechase2012; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -41,7 +39,10 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -99,16 +100,23 @@ class WhirlpoolWarriorTriggeredEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int cardsHand = controller.getHand().size(); - if (cardsHand > 0){ - for (Card card: controller.getHand().getCards(game)) { - if (card != null) { - controller.removeFromHand(card, game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + Map cardsToDraw = new LinkedHashMap<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int cardsInHand = player.getHand().size(); + if (cardsInHand > 0) { + cardsToDraw.put(playerId, cardsInHand); } + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + player.shuffleLibrary(game); + } + } + for (UUID playerId : cardsToDraw.keySet()) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(cardsToDraw.get(playerId), game); } - controller.shuffleLibrary(game); - controller.drawCards(cardsHand, game); } return true; } @@ -141,8 +149,8 @@ class WhirlpoolWarriorActivatedEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { int cardsHand = player.getHand().size(); - if (cardsHand > 0){ - for (Card card: player.getHand().getCards(game)) { + if (cardsHand > 0) { + for (Card card : player.getHand().getCards(game)) { if (card != null) { player.removeFromHand(card, game); card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/MoltenPsyche.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/MoltenPsyche.java index 9b944c42689..42122cfa4cc 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/MoltenPsyche.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/MoltenPsyche.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -28,18 +28,18 @@ package mage.sets.scarsofmirrodin; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.condition.common.MetalcraftCondition; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.WatcherScope; -import mage.abilities.Ability; -import mage.abilities.condition.common.MetalcraftCondition; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -56,7 +56,6 @@ public class MoltenPsyche extends CardImpl { super(ownerId, 98, "Molten Psyche", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{1}{R}{R}"); this.expansionSetCode = "SOM"; - // Each player shuffles the cards from his or her hand into his or her library, then draws that many cards. // Metalcraft - If you control three or more artifacts, Molten Psyche deals damage to each opponent equal to the number of cards that player has drawn this turn. this.getSpellAbility().addEffect(new MoltenPsycheEffect()); @@ -78,8 +77,8 @@ class MoltenPsycheEffect extends OneShotEffect { public MoltenPsycheEffect() { super(Outcome.Neutral); - staticText = "Each player shuffles the cards from his or her hand into his or her library, then draws that many cards.\n" + - "Metalcraft - If you control three or more artifacts, {this} deals damage to each opponent equal to the number of cards that player has drawn this turn."; + staticText = "Each player shuffles the cards from his or her hand into his or her library, then draws that many cards.\n" + + "Metalcraft - If you control three or more artifacts, {this} deals damage to each opponent equal to the number of cards that player has drawn this turn."; } public MoltenPsycheEffect(final MoltenPsycheEffect effect) { @@ -88,27 +87,43 @@ class MoltenPsycheEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId: sourcePlayer.getInRange()) { - Player player = game.getPlayer(playerId); - if (player != null) { - int count = player.getHand().size(); - for (Card card: player.getHand().getCards(game)) { - if (card != null) { - player.removeFromHand(card, game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Map cardsToDraw = new LinkedHashMap<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int cardsInHand = player.getHand().size(); + if (cardsInHand > 0) { + cardsToDraw.put(playerId, cardsInHand); } - } - game.informPlayers(player.getLogName() + " shuffles the cards from his or her hand into his or her library"); - player.shuffleLibrary(game); - player.drawCards(count, game); - if (MetalcraftCondition.getInstance().apply(game, source) && !playerId.equals(source.getControllerId())) { - MoltenPsycheWatcher watcher = (MoltenPsycheWatcher) game.getState().getWatchers().get("CardsDrawn"); - player.damage(watcher.getDraws(playerId), source.getSourceId(), game, false, true); + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + player.shuffleLibrary(game); } } + for (UUID playerId : cardsToDraw.keySet()) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(cardsToDraw.get(playerId), game); + if (MetalcraftCondition.getInstance().apply(game, source) && !playerId.equals(source.getControllerId())) { + MoltenPsycheWatcher watcher = (MoltenPsycheWatcher) game.getState().getWatchers().get("CardsDrawn"); + player.damage(watcher.getDraws(playerId), source.getSourceId(), game, false, true); + } + } + } + if (MetalcraftCondition.getInstance().apply(game, source)) { + MoltenPsycheWatcher watcher = (MoltenPsycheWatcher) game.getState().getWatchers().get("CardsDrawn"); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.damage(watcher.getDraws(playerId), source.getSourceId(), game, false, true); + } + } + } + return true; } - return true; + + return false; } @Override @@ -128,7 +143,7 @@ class MoltenPsycheWatcher extends Watcher { public MoltenPsycheWatcher(final MoltenPsycheWatcher watcher) { super(watcher); - for (Entry entry: watcher.draws.entrySet()) { + for (Entry entry : watcher.draws.entrySet()) { draws.put(entry.getKey(), entry.getValue()); } } diff --git a/Mage.Sets/src/mage/sets/urzassaga/TimeSpiral.java b/Mage.Sets/src/mage/sets/urzassaga/TimeSpiral.java index 1b19a828190..fff482faff9 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/TimeSpiral.java +++ b/Mage.Sets/src/mage/sets/urzassaga/TimeSpiral.java @@ -28,15 +28,17 @@ package mage.sets.urzassaga; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.effects.common.UntapLandsEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -51,12 +53,15 @@ public class TimeSpiral extends CardImpl { super(ownerId, 103, "Time Spiral", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); this.expansionSetCode = "USG"; - // Exile Time Spiral. Each player shuffles his or her graveyard and hand into his or her library, then draws seven cards. You untap up to six lands. this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); this.getSpellAbility().addEffect(new TimeSpiralEffect()); + Effect effect = new DrawCardAllEffect(7); + effect.setText(", then draws seven cards"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new UntapLandsEffect(6)); } + public TimeSpiral(final TimeSpiral card) { super(card); } @@ -71,7 +76,7 @@ class TimeSpiralEffect extends OneShotEffect { public TimeSpiralEffect() { super(Outcome.Neutral); - staticText = "Each player shuffles his or her hand and graveyard into his or her library, then draws seven cards"; + staticText = "Each player shuffles his or her hand and graveyard into his or her library"; } public TimeSpiralEffect(final TimeSpiralEffect effect) { @@ -81,17 +86,16 @@ class TimeSpiralEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId: sourcePlayer.getInRange()) { + for (UUID playerId : sourcePlayer.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getHand().getCards(game)) { + for (Card card : player.getHand().getCards(game)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card: player.getGraveyard().getCards(game)) { + } + for (Card card : player.getGraveyard().getCards(game)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + } player.shuffleLibrary(game); - player.drawCards(7, game); } } return true; @@ -102,4 +106,4 @@ class TimeSpiralEffect extends OneShotEffect { return new TimeSpiralEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Windfall.java b/Mage.Sets/src/mage/sets/urzassaga/Windfall.java index 4b398342cfd..c6f2b14192f 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Windfall.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Windfall.java @@ -48,7 +48,6 @@ public class Windfall extends CardImpl { super(ownerId, 111, "Windfall", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{U}"); this.expansionSetCode = "USG"; - // Each player discards his or her hand, then draws cards equal to the greatest number of cards a player discarded this way. this.getSpellAbility().addEffect(new WindfallEffect()); } @@ -64,6 +63,7 @@ public class Windfall extends CardImpl { } class WindfallEffect extends OneShotEffect { + WindfallEffect() { super(Outcome.Discard); staticText = "Each player discards his or her hand, then draws cards equal to the greatest number of cards a player discarded this way."; @@ -76,11 +76,11 @@ class WindfallEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int maxDiscarded = 0; - Player sourcePlayer = game.getPlayer(source.getControllerId()); - if (sourcePlayer == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - for (UUID playerId : sourcePlayer.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { int discarded = 0; @@ -94,7 +94,7 @@ class WindfallEffect extends OneShotEffect { } } } - for (UUID playerId : sourcePlayer.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { player.drawCards(maxDiscarded, game); @@ -107,4 +107,4 @@ class WindfallEffect extends OneShotEffect { public WindfallEffect copy() { return new WindfallEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java b/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java index 9ccf7a83cff..a64697b5814 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java +++ b/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java @@ -33,6 +33,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -65,7 +66,6 @@ public class ChandraAblaze extends CardImpl { this.expansionSetCode = "ZEN"; this.subtype.add("Chandra"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); // +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to target creature or player. @@ -75,7 +75,9 @@ public class ChandraAblaze extends CardImpl { this.addAbility(ability); // -2: Each player discards his or her hand, then draws three cards. ability = new LoyaltyAbility(new DiscardHandAllEffect(), -2); - ability.addEffect(new ChandraAblazeEffect4()); + Effect effect = new DrawCardAllEffect(3); + effect.setText(", then draws three cards"); + ability.addEffect(effect); this.addAbility(ability); // -7: Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs. ability = new LoyaltyAbility(new ChandraAblazeEffect5(), -7); @@ -162,23 +164,6 @@ class ChandraAblazeEffect2 extends OneShotEffect { } } -class ChandraAblazeEffect4 extends DrawCardAllEffect { - - public ChandraAblazeEffect4() { - super(3); - this.staticText = "Then draws three cards"; - } - - public ChandraAblazeEffect4(final ChandraAblazeEffect4 effect) { - super(effect); - } - - @Override - public ChandraAblazeEffect4 copy() { - return new ChandraAblazeEffect4(this); - } -} - class ChandraAblazeEffect5 extends OneShotEffect { public ChandraAblazeEffect5() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java index e5141680ace..05811424a5d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java @@ -82,4 +82,32 @@ public class DrawEffectsTest extends CardTestPlayerBase { assertHandCount(playerB, 1); } + /** + * Notion thief and Reforge the Soul - opponent got 0 cards - ok but I got + * only 7 cards (should be 14) + */ + @Test + public void testNotionThief2() { + addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 3); + skipInitShuffling(); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // Flash + // If an opponent would draw a card except the first one he or she draws in each of his or her draw steps, instead that player skips that draw and you draw a card. + addCard(Zone.BATTLEFIELD, playerA, "Notion Thief", 1); + // Each player discards his or her hand, then draws seven cards. + // Miracle {1}{R} + addCard(Zone.HAND, playerA, "Reforge the Soul", 1); + + addCard(Zone.HAND, playerB, "Mountain", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reforge the Soul"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Reforge the Soul", 1); + assertGraveyardCount(playerB, "Mountain", 1); + assertHandCount(playerA, 14); + assertHandCount(playerB, 0); + } } diff --git a/Mage/src/mage/abilities/effects/common/SetPlayerLifeAllEffect.java b/Mage/src/mage/abilities/effects/common/SetPlayerLifeAllEffect.java new file mode 100644 index 00000000000..5f54db01260 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/SetPlayerLifeAllEffect.java @@ -0,0 +1,99 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.TargetController; +import static mage.constants.TargetController.ANY; +import static mage.constants.TargetController.OPPONENT; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class SetPlayerLifeAllEffect extends OneShotEffect { + + private TargetController targetController; + protected DynamicValue amount; + + public SetPlayerLifeAllEffect(int amount) { + this(amount, TargetController.ANY); + } + + public SetPlayerLifeAllEffect(DynamicValue amount) { + this(amount, TargetController.ANY); + } + + public SetPlayerLifeAllEffect(int amount, TargetController targetController) { + this(new StaticValue(amount), targetController); + } + + public SetPlayerLifeAllEffect(DynamicValue amount, TargetController targetController) { + super(Outcome.DrawCard); + this.amount = amount; + this.targetController = targetController; + staticText = setText(); + } + + public SetPlayerLifeAllEffect(final SetPlayerLifeAllEffect effect) { + super(effect); + this.amount = effect.amount; + this.targetController = effect.targetController; + } + + @Override + public SetPlayerLifeAllEffect copy() { + return new SetPlayerLifeAllEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player sourcePlayer = game.getPlayer(source.getControllerId()); + switch (targetController) { + case ANY: + for (UUID playerId : sourcePlayer.getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.setLife(amount.calculate(game, source, this), game); + } + } + break; + case OPPONENT: + for (UUID playerId : game.getOpponents(sourcePlayer.getId())) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.setLife(amount.calculate(game, source, this), game); + } + } + break; + } + return true; + } + + private String setText() { + StringBuilder sb = new StringBuilder("Each "); + switch (targetController) { + case ANY: + sb.append("player"); + break; + case OPPONENT: + sb.append("opponent"); + break; + default: + throw new UnsupportedOperationException("Not supported value for targetController"); + } + sb.append(" 's life total becomes "); + sb.append(amount.toString()); + return sb.toString(); + } +} diff --git a/Mage/src/mage/actions/MageDrawAction.java b/Mage/src/mage/actions/MageDrawAction.java index 60cd6dcbd8b..db2e2f3620c 100644 --- a/Mage/src/mage/actions/MageDrawAction.java +++ b/Mage/src/mage/actions/MageDrawAction.java @@ -1,7 +1,8 @@ package mage.actions; import java.util.ArrayList; - +import java.util.List; +import java.util.UUID; import mage.actions.impl.MageAction; import mage.actions.score.ArtificialScoringSystem; import mage.cards.Card; @@ -9,9 +10,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; - -import java.util.List; -import java.util.UUID; import mage.util.CardUtil; /** @@ -39,7 +37,7 @@ public class MageDrawAction extends MageAction { * Draw and set action score. * * @param game Game context. - * @return + * @return */ @Override public int doAction(Game game) { @@ -70,8 +68,8 @@ public class MageDrawAction extends MageAction { } /** - * Draw a card if possible (there is no replacement effect that prevent us from drawing). - * Fire event about card drawn. + * Draw a card if possible (there is no replacement effect that prevent us + * from drawing). Fire event about card drawn. * * @param game * @return