From 12d584ebd131efc604a98301cb83f4aa5cbbc02d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 15 Sep 2015 17:38:12 +0200 Subject: [PATCH] [BFZ] Added Conduit of Ruin, Exert Influence and March from the Tomb. --- .../sets/battleforzendikar/ConduitOfRuin.java | 164 ++++++++++++++++++ .../battleforzendikar/ExertInfluence.java | 102 +++++++++++ .../battleforzendikar/MarchFromTheTomb.java | 154 ++++++++++++++++ .../sets/newphyrexia/BrutalizerExarch.java | 57 ++---- .../SpellsCostReductionControllerEffect.java | 23 ++- .../SearchLibraryPutOnLibraryEffect.java | 43 ++--- Mage/src/mage/players/PlayerImpl.java | 2 +- .../common/TargetCardInYourGraveyard.java | 15 +- 8 files changed, 462 insertions(+), 98 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/battleforzendikar/ConduitOfRuin.java create mode 100644 Mage.Sets/src/mage/sets/battleforzendikar/ExertInfluence.java create mode 100644 Mage.Sets/src/mage/sets/battleforzendikar/MarchFromTheTomb.java diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/ConduitOfRuin.java b/Mage.Sets/src/mage/sets/battleforzendikar/ConduitOfRuin.java new file mode 100644 index 0000000000..772c7872c7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/battleforzendikar/ConduitOfRuin.java @@ -0,0 +1,164 @@ +/* + * 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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * 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.battleforzendikar; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectPlayer; +import mage.filter.predicate.ObjectPlayerPredicate; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.common.TargetCardInLibrary; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public class ConduitOfRuin extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("a colorless creature card with converted mana cost 7 or greater"); + private static final FilterCreatureCard filterCost = new FilterCreatureCard("The first creature spell"); + + static { + filter.add(new ColorlessPredicate()); + filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.GreaterThan, 6)); + filterCost.add(new FirstCastCreatureSpellPredicate()); + } + + public ConduitOfRuin(UUID ownerId) { + super(ownerId, 4, "Conduit of Ruin", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}"); + this.expansionSetCode = "BFZ"; + this.subtype.add("Eldrazi"); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // When you cast Conduit of Ruin, you may search your library for a colorless creature card with converted mana cost 7 or greater, then shuffle your library and put that card on top of it. + TargetCardInLibrary target = new TargetCardInLibrary(filter); + this.addAbility(new CastSourceTriggeredAbility(new SearchLibraryPutOnLibraryEffect(target, true, true), true)); + + // The first creature spell you cast each turn costs {2} less to cast. + Effect effect = new SpellsCostReductionControllerEffect(filterCost, 2); + effect.setText("The first creature spell you cast each turn costs {2} less to cast"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), new ConduitOfRuinWatcher()); + } + + public ConduitOfRuin(final ConduitOfRuin card) { + super(card); + } + + @Override + public ConduitOfRuin copy() { + return new ConduitOfRuin(this); + } +} + +class ConduitOfRuinWatcher extends Watcher { + + Map playerCreatureSpells; + int spellCount = 0; + + public ConduitOfRuinWatcher() { + super("FirstCreatureSpellCastThisTurn", WatcherScope.GAME); + playerCreatureSpells = new HashMap<>(); + } + + public ConduitOfRuinWatcher(final ConduitOfRuinWatcher watcher) { + super(watcher); + this.playerCreatureSpells = new HashMap<>(); + playerCreatureSpells.putAll(watcher.playerCreatureSpells); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + Spell spell = (Spell) game.getObject(event.getTargetId()); + if (spell != null && spell.getCardType().contains(CardType.CREATURE)) { + if (playerCreatureSpells.containsKey(event.getPlayerId())) { + playerCreatureSpells.put(event.getPlayerId(), playerCreatureSpells.get(event.getPlayerId()) + 1); + } else { + playerCreatureSpells.put(event.getPlayerId(), 1); + } + } + } + } + + public int creatureSpellsCastThisTurn(UUID playerId) { + if (playerCreatureSpells.containsKey(playerId)) { + return playerCreatureSpells.get(playerId); + } + return 0; + } + + @Override + public ConduitOfRuinWatcher copy() { + return new ConduitOfRuinWatcher(this); + } + + @Override + public void reset() { + super.reset(); + playerCreatureSpells.clear(); + } +} + +class FirstCastCreatureSpellPredicate implements ObjectPlayerPredicate> { + + @Override + public boolean apply(ObjectPlayer input, Game game) { + if (input.getObject() instanceof Spell + && ((Spell) input.getObject()).getCardType().contains(CardType.CREATURE)) { + ConduitOfRuinWatcher watcher = (ConduitOfRuinWatcher) game.getState().getWatchers().get("FirstCreatureSpellCastThisTurn"); + return watcher != null && watcher.creatureSpellsCastThisTurn(input.getPlayerId()) == 0; + } + return false; + } + + @Override + public String toString() { + return "The first creature spell you cast each turn"; + } +} diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/ExertInfluence.java b/Mage.Sets/src/mage/sets/battleforzendikar/ExertInfluence.java new file mode 100644 index 0000000000..e408f80f98 --- /dev/null +++ b/Mage.Sets/src/mage/sets/battleforzendikar/ExertInfluence.java @@ -0,0 +1,102 @@ +/* + * 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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * 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.battleforzendikar; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class ExertInfluence extends CardImpl { + + public ExertInfluence(UUID ownerId) { + super(ownerId, 77, "Exert Influence", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{U}"); + this.expansionSetCode = "BFZ"; + + // Converge-Gain control of target creature if its power is less than or equal to the number of colors spent to cast Exert Influence. + getSpellAbility().addEffect(new ExertInfluenceEffect()); + getSpellAbility().addTarget(new TargetCreaturePermanent()); + + } + + public ExertInfluence(final ExertInfluence card) { + super(card); + } + + @Override + public ExertInfluence copy() { + return new ExertInfluence(this); + } +} + +class ExertInfluenceEffect extends OneShotEffect { + + public ExertInfluenceEffect() { + super(Outcome.GainControl); + this.staticText = "Converge-Gain control of target creature if its power is less than or equal to the number of colors spent to cast {this}"; + } + + public ExertInfluenceEffect(final ExertInfluenceEffect effect) { + super(effect); + } + + @Override + public ExertInfluenceEffect copy() { + return new ExertInfluenceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject sourceObject = game.getObject(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller != null && sourceObject != null) { + int colors = new ColorsOfManaSpentToCastCount().calculate(game, source, this); + if (targetCreature.getPower().getValue() <= colors) { + game.addEffect(new GainControlTargetEffect(Duration.Custom, true), source); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/MarchFromTheTomb.java b/Mage.Sets/src/mage/sets/battleforzendikar/MarchFromTheTomb.java new file mode 100644 index 0000000000..2f4ba01399 --- /dev/null +++ b/Mage.Sets/src/mage/sets/battleforzendikar/MarchFromTheTomb.java @@ -0,0 +1,154 @@ +/* + * 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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * 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.battleforzendikar; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author LevelX2 + */ +public class MarchFromTheTomb extends CardImpl { + + public MarchFromTheTomb(UUID ownerId) { + super(ownerId, 214, "March from the Tomb", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{W}{B}"); + this.expansionSetCode = "BFZ"; + + // Return any number of target Ally creature cards with total converted mana cost of 8 or less from your graveyard to the battlefield. + Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); + effect.setText("Return any number of target Ally creature cards with total converted mana cost of 8 or less from your graveyard to the battlefield"); + this.getSpellAbility().addEffect(effect); + FilterCard filter = new FilterCreatureCard(); + filter.add(new SubtypePredicate("Ally")); + this.getSpellAbility().addTarget(new MarchFromTheTombTarget(0, Integer.MAX_VALUE, filter)); + } + + public MarchFromTheTomb(final MarchFromTheTomb card) { + super(card); + } + + @Override + public MarchFromTheTomb copy() { + return new MarchFromTheTomb(this); + } +} + +class MarchFromTheTombTarget extends TargetCardInYourGraveyard { + + public MarchFromTheTombTarget(int minNumTargets, int maxNumTargets, FilterCard filter) { + super(minNumTargets, maxNumTargets, filter); + } + + public MarchFromTheTombTarget(MarchFromTheTombTarget target) { + super(target); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Cards cards, Game game) { + int cmcLeft = 8; + for (UUID targetId : this.getTargets()) { + Card card = game.getCard(targetId); + if (card != null) { + cmcLeft -= card.getManaCost().convertedManaCost(); + } + } + Set possibleTargets = super.possibleTargets(sourceControllerId, cards, game); + Set leftPossibleTargets = new HashSet<>(); + for (UUID targetId : possibleTargets) { + Card card = game.getCard(targetId); + if (card != null && card.getManaCost().convertedManaCost() <= cmcLeft) { + leftPossibleTargets.add(targetId); + } + } + setTargetName("any number of target Ally creature cards with total converted mana cost of 8 or less (" + cmcLeft + " left) from your graveyard"); + return leftPossibleTargets; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + int cmcLeft = 8; + for (UUID targetId : this.getTargets()) { + Card card = game.getCard(targetId); + if (card != null) { + cmcLeft -= card.getManaCost().convertedManaCost(); + } + } + Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + Set leftPossibleTargets = new HashSet<>(); + for (UUID targetId : possibleTargets) { + Card card = game.getCard(targetId); + if (card != null && card.getManaCost().convertedManaCost() <= cmcLeft) { + leftPossibleTargets.add(targetId); + } + } + setTargetName("any number of target Ally creature cards with total converted mana cost of 8 or less (" + cmcLeft + " left) from your graveyard"); + return leftPossibleTargets; + } + + @Override + public boolean canTarget(UUID objectId, Ability source, Game game) { + return this.canTarget(source.getControllerId(), objectId, source, game); + } + + @Override + public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { + if (super.canTarget(playerId, objectId, source, game)) { + int cmcLeft = 8; + for (UUID targetId : this.getTargets()) { + Card card = game.getCard(targetId); + if (card != null) { + cmcLeft -= card.getManaCost().convertedManaCost(); + } + } + Card card = game.getCard(objectId); + return card != null && card.getManaCost().convertedManaCost() <= cmcLeft; + } + return false; + } + + @Override + public MarchFromTheTombTarget copy() { + return new MarchFromTheTombTarget(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/newphyrexia/BrutalizerExarch.java b/Mage.Sets/src/mage/sets/newphyrexia/BrutalizerExarch.java index 9c516b48f1..76a5f179f4 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/BrutalizerExarch.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/BrutalizerExarch.java @@ -28,19 +28,17 @@ package mage.sets.newphyrexia; 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.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; @@ -71,7 +69,11 @@ public class BrutalizerExarch extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - Ability ability = new EntersBattlefieldTriggeredAbility(new BrutalizerExarchEffect1()); + // When Brutalizer Exarch enters the battlefield, choose one + // - Search your library for a creature card, reveal it, then shuffle your library and put that card on top of it; + TargetCardInLibrary target = new TargetCardInLibrary(new FilterCreatureCard("a creature card")); + Ability ability = new EntersBattlefieldTriggeredAbility(new SearchLibraryPutOnLibraryEffect(target, true, true), false); + // or put target noncreature permanent on the bottom of its owner's library. Mode mode = new Mode(); mode.getEffects().add(new BrutalizerExarchEffect2()); mode.getTargets().add(new TargetPermanent(filter)); @@ -89,45 +91,6 @@ public class BrutalizerExarch extends CardImpl { } } -class BrutalizerExarchEffect1 extends OneShotEffect { - - public BrutalizerExarchEffect1() { - super(Outcome.Benefit); - this.staticText = "Search your library for a creature card, reveal it, then shuffle your library and put that card on top of it"; - } - - public BrutalizerExarchEffect1(final BrutalizerExarchEffect1 effect) { - super(effect); - } - - @Override - public BrutalizerExarchEffect1 copy() { - return new BrutalizerExarchEffect1(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - TargetCardInLibrary target = new TargetCardInLibrary(new FilterCreatureCard("creature card in your library")); - if (player.searchLibrary(target, game)) { - Card card = player.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Brutalizer Exarch", cards, game); - } - player.shuffleLibrary(game); - if (card != null) - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - return true; - } - player.shuffleLibrary(game); - } - return false; - } -} - class BrutalizerExarchEffect2 extends OneShotEffect { public BrutalizerExarchEffect2() { diff --git a/Mage/src/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java b/Mage/src/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java index d8149f33cb..b91b76a182 100644 --- a/Mage/src/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java @@ -56,17 +56,16 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI private final boolean upTo; private ManaCosts manaCostsToReduce = null; - public SpellsCostReductionControllerEffect(FilterCard filter, ManaCosts manaCostsToReduce) { super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); this.filter = filter; this.amount = 0; this.manaCostsToReduce = manaCostsToReduce; this.upTo = false; - + StringBuilder sb = new StringBuilder(); sb.append(filter.getMessage()).append(" you cast cost "); - for (String manaSymbol :manaCostsToReduce.getSymbols()) { + for (String manaSymbol : manaCostsToReduce.getSymbols()) { sb.append(manaSymbol); } sb.append(" less to cast. This effect reduces only the amount of colored mana you pay."); @@ -81,8 +80,8 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); this.filter = filter; this.amount = amount; - this.upTo = upTo; - this.staticText = filter.getMessage() + " you cast cost " + (upTo ?"up to " :"") + "{" +amount + "} less to cast"; + this.upTo = upTo; + this.staticText = filter.getMessage() + " you cast cost " + (upTo ? "up to " : "") + "{" + amount + "} less to cast"; } protected SpellsCostReductionControllerEffect(final SpellsCostReductionControllerEffect effect) { @@ -95,28 +94,28 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - if (manaCostsToReduce != null){ + if (manaCostsToReduce != null) { CardUtil.adjustCost((SpellAbility) abilityToModify, manaCostsToReduce, false); } else { if (upTo) { Mana mana = abilityToModify.getManaCostsToPay().getMana(); int reduceMax = mana.getColorless(); - if (reduceMax > 2){ + if (reduceMax > 2) { reduceMax = 2; } if (reduceMax > 0) { Player controller = game.getPlayer(abilityToModify.getControllerId()); - if (controller == null){ + if (controller == null) { return false; } ChoiceImpl choice = new ChoiceImpl(true); Set set = new LinkedHashSet<>(); - for(int i = 0; i <= reduceMax; i++){ + for (int i = 0; i <= reduceMax; i++) { set.add(String.valueOf(i)); } choice.setChoices(set); choice.setMessage("Reduce cost of " + filter); - if(controller.choose(Outcome.Benefit, choice, game)){ + if (controller.choose(Outcome.Benefit, choice, game)) { int reduce = Integer.parseInt(choice.getChoice()); CardUtil.reduceCost(abilityToModify, reduce); } @@ -134,11 +133,11 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI if (abilityToModify.getControllerId().equals(source.getControllerId())) { Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); if (spell != null) { - return this.filter.match(spell, game); + return this.filter.match(spell, source.getSourceId(), source.getControllerId(), game); } else { // used at least for flashback ability because Flashback ability doesn't use stack or for getPlayables where spell is not cast yet Card sourceCard = game.getCard(abilityToModify.getSourceId()); - return sourceCard != null && this.filter.match(sourceCard, game); + return sourceCard != null && this.filter.match(sourceCard, source.getSourceId(), source.getControllerId(), game); } } } diff --git a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java index 65e05e6584..124b173a5a 100644 --- a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java +++ b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.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,25 +20,19 @@ * 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.abilities.effects.common.search; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObject; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; -import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; @@ -48,7 +42,7 @@ import mage.target.common.TargetCardInLibrary; * @author BetaSteward_at_googlemail.com */ public class SearchLibraryPutOnLibraryEffect extends SearchEffect { - + private boolean reveal; private boolean forceShuffle; @@ -56,7 +50,7 @@ public class SearchLibraryPutOnLibraryEffect extends SearchEffect { this(target, false, true); setText(); } - + public SearchLibraryPutOnLibraryEffect(TargetCardInLibrary target, boolean reveal, boolean forceShuffle) { super(target, Outcome.DrawCard); this.reveal = reveal; @@ -83,27 +77,14 @@ public class SearchLibraryPutOnLibraryEffect extends SearchEffect { return false; } if (controller.searchLibrary(target, game)) { - List cards = new ArrayList<>(); - for (UUID cardId: target.getTargets()) { - Card card = controller.getLibrary().remove(cardId, game); - if (card != null) { - cards.add(card); - } - } - Cards foundCards = new CardsImpl(); - foundCards.addAll(target.getTargets()); - if (reveal) { + Cards foundCards = new CardsImpl(target.getTargets()); + if (reveal && !foundCards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), foundCards, game); } if (forceShuffle) { controller.shuffleLibrary(game); } - if (cards.size() > 0 && !game.isSimulation()) { - game.informPlayers(controller.getLogName() + " moves " + cards.size() + " card" + (cards.size() == 1 ? " ":"s ") + "on top of his or her library"); - } - for (Card card: cards) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + controller.putCardsOnTopOfLibrary(foundCards, game, source, reveal); return true; } // shuffle @@ -115,7 +96,7 @@ public class SearchLibraryPutOnLibraryEffect extends SearchEffect { private void setText() { StringBuilder sb = new StringBuilder(); - sb.append("Search your library for a ").append(target.getTargetName()); + sb.append("search your library for a ").append(target.getTargetName()); if (reveal) { sb.append(" and reveal that card. Shuffle"); } else { diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 00d83fc7cf..d5bf156025 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -877,7 +877,7 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean putCardsOnTopOfLibrary(Cards cardsToLibrary, Game game, Ability source, boolean anyOrder) { Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException cards.addAll(cardsToLibrary); - if (cards.size() != 0) { + if (!cards.isEmpty()) { UUID sourceId = (source == null ? null : source.getSourceId()); if (!anyOrder) { for (UUID cardId : cards) { diff --git a/Mage/src/mage/target/common/TargetCardInYourGraveyard.java b/Mage/src/mage/target/common/TargetCardInYourGraveyard.java index a6e2645136..eba50fb268 100644 --- a/Mage/src/mage/target/common/TargetCardInYourGraveyard.java +++ b/Mage/src/mage/target/common/TargetCardInYourGraveyard.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,12 +20,11 @@ * 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.target.common; import java.util.HashSet; @@ -106,13 +105,14 @@ public class TargetCardInYourGraveyard extends TargetCard { public Set possibleTargets(UUID sourceControllerId, Cards cards, Game game) { Set possibleTargets = new HashSet<>(); Player player = game.getPlayer(sourceControllerId); - for (Card card: cards.getCards(filter, game)) { + for (Card card : cards.getCards(filter, game)) { if (player.getGraveyard().getCards(game).contains(card)) { possibleTargets.add(card.getId()); } } return possibleTargets; } + /** * Checks if there are enough {@link Card} that can be selected. * @@ -127,6 +127,7 @@ public class TargetCardInYourGraveyard extends TargetCard { } return false; } + @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { Player player = game.getPlayer(sourceControllerId);