From bd5e351223bc26e83baf00b596e01816d5f3e63a Mon Sep 17 00:00:00 2001 From: laxika Date: Sat, 10 Jan 2015 17:10:54 +0100 Subject: [PATCH 01/34] Added Urborg Uprising card --- .../mage/sets/apocalypse/UrborgUprising.java | 67 +++++++++++++++++++ .../sets/vintagemasters/UrborgUprising.java | 24 +++++++ 2 files changed, 91 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java create mode 100644 Mage.Sets/src/mage/sets/vintagemasters/UrborgUprising.java diff --git a/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java b/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java new file mode 100644 index 00000000000..a7facaa0360 --- /dev/null +++ b/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java @@ -0,0 +1,67 @@ +/* + * 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.apocalypse; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author Laxika + */ +public class UrborgUprising extends CardImpl { + + public UrborgUprising(UUID ownerId) { + super(ownerId, 53, "Urborg Uprising", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{4}{B}"); + this.expansionSetCode = "APC"; + + this.color.setBlack(true); + + // Return up to two target creature cards from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, new FilterCreatureCard("creature cards from your graveyard"))); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + public UrborgUprising(final UrborgUprising card) { + super(card); + } + + @Override + public UrborgUprising copy() { + return new UrborgUprising(this); + } +} diff --git a/Mage.Sets/src/mage/sets/vintagemasters/UrborgUprising.java b/Mage.Sets/src/mage/sets/vintagemasters/UrborgUprising.java new file mode 100644 index 00000000000..4d1baadc87e --- /dev/null +++ b/Mage.Sets/src/mage/sets/vintagemasters/UrborgUprising.java @@ -0,0 +1,24 @@ +package mage.sets.vintagemasters; + +import java.util.UUID; + +/** + * @author Laxika + */ +public class UrborgUprising extends mage.sets.apocalypse.UrborgUprising { + + public UrborgUprising(UUID ownerId) { + super(ownerId); + this.cardNumber = 144; + this.expansionSetCode = "VMA"; + } + + public UrborgUprising(final UrborgUprising card) { + super(card); + } + + @Override + public UrborgUprising copy() { + return new UrborgUprising(this); + } +} From fff4f97d3baea11d83c725cf4187f70cd02a8c97 Mon Sep 17 00:00:00 2001 From: laxika Date: Sat, 10 Jan 2015 21:34:49 +0100 Subject: [PATCH 02/34] added fishliver oil --- .../mage/sets/arabiannights/FishliverOil.java | 130 ++++++++++++++++++ .../mage/sets/ninthedition/FishliverOil.java | 51 +++++++ 2 files changed, 181 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java create mode 100644 Mage.Sets/src/mage/sets/ninthedition/FishliverOil.java diff --git a/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java b/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java new file mode 100644 index 00000000000..dc374e6e465 --- /dev/null +++ b/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java @@ -0,0 +1,130 @@ +/* + * 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.arabiannights; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.IslandwalkAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.AbilityAddingRemovingEffects_6; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * @author Laxika + */ +public class FishliverOil extends CardImpl { + + public FishliverOil(UUID ownerId) { + super(ownerId, 17, "Fishliver Oil", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "ARN"; + this.subtype.add("Aura"); + + this.color.setBlue(true); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has islandwalk. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FishliverOilEffect())); + } + + public FishliverOil(final FishliverOil card) { + super(card); + } + + @Override + public FishliverOil copy() { + return new FishliverOil(this); + } +} + +class FishliverOilEffect extends ContinuousEffectImpl { + + public FishliverOilEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Enchanted creature has islandwalk"; + } + + public FishliverOilEffect(final FishliverOilEffect effect) { + super(effect); + } + + @Override + public FishliverOilEffect copy() { + return new FishliverOilEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Permanent creature = game.getPermanent(enchantment.getAttachedTo()); + if (creature != null) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(new IslandwalkAbility(), game); + } + break; + } + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/ninthedition/FishliverOil.java b/Mage.Sets/src/mage/sets/ninthedition/FishliverOil.java new file mode 100644 index 00000000000..ebad40a8646 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/FishliverOil.java @@ -0,0 +1,51 @@ +/* + * 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.ninthedition; + +import java.util.UUID; + +/** + * @author Laxika + */ +public class FishliverOil extends mage.sets.arabiannights.FishliverOil { + + public FishliverOil(UUID ownerId) { + super(ownerId); + this.cardNumber = 77; + this.expansionSetCode = "9ED"; + } + + public FishliverOil(final FishliverOil card) { + super(card); + } + + @Override + public FishliverOil copy() { + return new FishliverOil(this); + } +} From 3c97a0c9cc0533e9512280b514d048de8194d475 Mon Sep 17 00:00:00 2001 From: someoneseth Date: Fri, 16 Jan 2015 09:57:22 -0500 Subject: [PATCH 03/34] Added Novijen, Heart of Progress. --- .../dissension/NovijenHeartOfProgress.java | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java diff --git a/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java new file mode 100644 index 00000000000..25a444a38f7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java @@ -0,0 +1,109 @@ +/* + * 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.dissension; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author someoneseth@gmail.com + */ +public class NovijenHeartOfProgress extends CardImpl { + + public NovijenHeartOfProgress(UUID ownerId) { + super(ownerId, 175, "Novijen, Heart of Progress", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "DIS"; + + // {tap}: Add {1} to your mana pool. + // {G}{U}, {tap}: Put a +1/+1 counter on each creature that entered the battlefield this turn. + this.addAbility(new EntersBattlefieldTappedAbility()); + this.addAbility(new ColorlessManaAbility()); + + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new NovijenHeartOfProgressEffect(), new ManaCostsImpl<>("{G}{U}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public NovijenHeartOfProgress(final NovijenHeartOfProgress card) { + super(card); + } + + @Override + public NovijenHeartOfProgress copy() { + return new NovijenHeartOfProgress(this); + } +} + +class NovijenHeartOfProgressEffect extends OneShotEffect { + + public NovijenHeartOfProgressEffect() { + super(Outcome.BoostCreature); + staticText = "Put a +1/+1 counter on each creature that came into play this turn."; + } + + public NovijenHeartOfProgressEffect(final NovijenHeartOfProgressEffect effect) { + super(effect); + } + + @Override + public NovijenHeartOfProgressEffect copy() { + return new NovijenHeartOfProgressEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterPermanent filter = new FilterPermanent(); + filter.add(new CardTypePredicate(CardType.CREATURE)); + for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + if (permanent.getTurnsOnBattlefield() == 0) { + permanent.addCounters(CounterType.P1P1.createInstance(), game); + } + } + return true; + } + +} \ No newline at end of file From 2113f6f0fc64149927cb1000ee91168ea6f2b8df Mon Sep 17 00:00:00 2001 From: someoneseth Date: Sun, 18 Jan 2015 00:51:10 -0500 Subject: [PATCH 04/34] Fixed Novijen, Heart of Progress. Used FilterCreaturePermanent directly. --- .../mage/sets/dissension/NovijenHeartOfProgress.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java index 25a444a38f7..70198612789 100644 --- a/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java +++ b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java @@ -44,6 +44,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -58,11 +59,10 @@ public class NovijenHeartOfProgress extends CardImpl { super(ownerId, 175, "Novijen, Heart of Progress", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "DIS"; - // {tap}: Add {1} to your mana pool. - // {G}{U}, {tap}: Put a +1/+1 counter on each creature that entered the battlefield this turn. - this.addAbility(new EntersBattlefieldTappedAbility()); + // {tap}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); + // {G}{U}, {tap}: Put a +1/+1 counter on each creature that entered the battlefield this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new NovijenHeartOfProgressEffect(), new ManaCostsImpl<>("{G}{U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -96,8 +96,8 @@ class NovijenHeartOfProgressEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - FilterPermanent filter = new FilterPermanent(); - filter.add(new CardTypePredicate(CardType.CREATURE)); + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { if (permanent.getTurnsOnBattlefield() == 0) { permanent.addCounters(CounterType.P1P1.createInstance(), game); @@ -105,5 +105,4 @@ class NovijenHeartOfProgressEffect extends OneShotEffect { } return true; } - } \ No newline at end of file From b12b044e36b89afb9b875fb4221608cbc8239175 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Jan 2015 14:40:05 +0100 Subject: [PATCH 05/34] * Added some basic logging for deck format validation --- Mage.Server/src/main/java/mage/server/TableController.java | 2 +- Mage/src/mage/cards/decks/Constructed.java | 6 +++++- Utils/gen-list-unimplemented-cards-for-set.pl | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 9690e0da2cf..9433c1d032a 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -283,7 +283,6 @@ public class TableController { } return false; } - Player player = createPlayer(name, seat.getPlayerType(), skill); if (player == null) { String message = new StringBuilder("Could not create player ").append(name).append(" of type ").append(seat.getPlayerType()).toString(); @@ -291,6 +290,7 @@ public class TableController { user.showUserMessage("Join Table",message); return false; } + logger.debug("DECK validated: " + table.getValidator().getName() + " " + player.getName() + " " + deck.getName()); if (!player.canJoinTable(table)) { user.showUserMessage("Join Table", new StringBuilder("A ").append(seat.getPlayerType()).append(" player can't join this table.").toString()); return false; diff --git a/Mage/src/mage/cards/decks/Constructed.java b/Mage/src/mage/cards/decks/Constructed.java index 4e1113d794f..8218afa0fc2 100644 --- a/Mage/src/mage/cards/decks/Constructed.java +++ b/Mage/src/mage/cards/decks/Constructed.java @@ -38,6 +38,7 @@ import mage.cards.Card; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.Rarity; +import org.apache.log4j.Logger; /** * @@ -45,6 +46,8 @@ import mage.constants.Rarity; */ public class Constructed extends DeckValidator { + private static final Logger logger = Logger.getLogger(DeckValidator.class); + protected List banned = new ArrayList<>(); protected List restricted = new ArrayList<>(); protected List setCodes = new ArrayList<>(); @@ -60,6 +63,7 @@ public class Constructed extends DeckValidator { @Override public boolean validate(Deck deck) { + logger.debug("DECK validate start: " + name + " deckname: " + deck.getName() ); boolean valid = true; //20091005 - 100.2a if (deck.getCards().size() < 60) { @@ -153,7 +157,7 @@ public class Constructed extends DeckValidator { } } } - + logger.debug("DECK validate end: " + name + " deckname: " + deck.getName() + " invalids:" + invalid.size()); return valid; } diff --git a/Utils/gen-list-unimplemented-cards-for-set.pl b/Utils/gen-list-unimplemented-cards-for-set.pl index 41e09fd7c0c..39255747d47 100644 --- a/Utils/gen-list-unimplemented-cards-for-set.pl +++ b/Utils/gen-list-unimplemented-cards-for-set.pl @@ -62,6 +62,7 @@ sub toCamelCase { $string; } +# TODO: check for basic lands with ending 1,2,3,4,5 ... my $toPrint = ''; foreach my $card (sort cardSort @setCards) { my $className = toCamelCase(@{$card}[0]); From 1340ebff49afd549c58f4fd8a85e0fd6e3fad684 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Jan 2015 22:48:32 +0100 Subject: [PATCH 06/34] * Untap restricting effects - Fixed that the selection of the permanent to untap was wrongly handled targeted. So something with protection from red could not be untapped while e.g. Smoke was into play. --- .../abilities/effects/RestrictionUntapNotMoreThanEffect.java | 2 +- Mage/src/mage/players/PlayerImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/effects/RestrictionUntapNotMoreThanEffect.java b/Mage/src/mage/abilities/effects/RestrictionUntapNotMoreThanEffect.java index 324998f2b60..9bda2189408 100644 --- a/Mage/src/mage/abilities/effects/RestrictionUntapNotMoreThanEffect.java +++ b/Mage/src/mage/abilities/effects/RestrictionUntapNotMoreThanEffect.java @@ -42,7 +42,7 @@ import mage.players.Player; */ public abstract class RestrictionUntapNotMoreThanEffect extends ContinuousEffectImpl { - private int number; + private final int number; private FilterControlledPermanent filter; public RestrictionUntapNotMoreThanEffect(Duration duration, int number, FilterControlledPermanent filter) { diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 6d5d6abb9c5..6663eecc517 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1374,7 +1374,7 @@ public abstract class PlayerImpl implements Player, Serializable { } sb.append(")"); filter.setMessage(sb.toString()); - Target target = new TargetPermanent(filter); + Target target = new TargetPermanent(1, 1, filter, true); if (!this.chooseTarget(Outcome.Untap, target, ability, game)) { // player canceled, go on with the next effect (if no other effect available, this effect will be active again) playerCanceledSelection = true; From c8eb9f00a92feef05778c142d8c64d94182d1a94 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Jan 2015 23:41:11 +0100 Subject: [PATCH 07/34] * Fixed that lose restricting effects could not be replaced (e.g. by Abysal Persecutor's ability) if the player has conceded or left the match. Fixed that "can't win" or "can't lose" messages where repeated send to the players if such an effect activly prevents a player from losing or winning. --- Mage.Client/serverlist.txt | 8 ++++---- .../mage/sets/innistrad/LaboratoryManiac.java | 7 ++++++- .../mage/sets/shardsofalara/LichsMirror.java | 7 ++++++- .../src/mage/sets/tenth/PlatinumAngel.java | 10 +++------- .../src/mage/sets/timespiral/AngelsGrace.java | 19 ++++++++++--------- .../sets/worldwake/AbyssalPersecutor.java | 2 +- Mage/src/mage/players/PlayerImpl.java | 17 ++++++++++++++--- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt index e48b45d95f3..5bda14f5241 100644 --- a/Mage.Client/serverlist.txt +++ b/Mage.Client/serverlist.txt @@ -1,5 +1,5 @@ -woogerworks :xmage.woogerworks.com:17171 -XMage.info 1 :176.31.186.181:17171 -XMage.info 2 :176.31.186.181:17000 -Seedds Server (inactive?) :115.29.203.80:17171 +woogerworks (North America):xmage.woogerworks.com:17171 +XMage.info 1 (Europe) :176.31.186.181:17171 +XMage.info 2 (Europe):176.31.186.181:17000 +Seedds Server (Asia) :115.29.203.80:17171 localhost -> connect to your local server (must be started):localhost:17171 diff --git a/Mage.Sets/src/mage/sets/innistrad/LaboratoryManiac.java b/Mage.Sets/src/mage/sets/innistrad/LaboratoryManiac.java index 829af586a79..2ff2661bd01 100644 --- a/Mage.Sets/src/mage/sets/innistrad/LaboratoryManiac.java +++ b/Mage.Sets/src/mage/sets/innistrad/LaboratoryManiac.java @@ -105,9 +105,14 @@ class LaboratoryManiacEffect extends ReplacementEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.LOSES; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.LOSES && event.getPlayerId().equals(source.getControllerId())) { + if (event.getPlayerId().equals(source.getControllerId())) { Player player = game.getPlayer(event.getPlayerId()); if (!player.hasLost() && ( (player.getLife() > 0 || !player.canLoseByZeroOrLessLife()) diff --git a/Mage.Sets/src/mage/sets/shardsofalara/LichsMirror.java b/Mage.Sets/src/mage/sets/shardsofalara/LichsMirror.java index cb21f978485..fd93901578b 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/LichsMirror.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/LichsMirror.java @@ -119,9 +119,14 @@ class LichsMirrorEffect extends ReplacementEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOSES; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.LOSES && event.getPlayerId().equals(source.getControllerId())) { + if (event.getPlayerId().equals(source.getControllerId())) { return true; } return false; diff --git a/Mage.Sets/src/mage/sets/tenth/PlatinumAngel.java b/Mage.Sets/src/mage/sets/tenth/PlatinumAngel.java index 698be267888..4802714da75 100644 --- a/Mage.Sets/src/mage/sets/tenth/PlatinumAngel.java +++ b/Mage.Sets/src/mage/sets/tenth/PlatinumAngel.java @@ -37,6 +37,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -70,10 +71,10 @@ public class PlatinumAngel extends CardImpl { return new PlatinumAngel(this); } - class PlatinumAngelEffect extends ReplacementEffectImpl { + class PlatinumAngelEffect extends ContinuousRuleModifiyingEffectImpl { public PlatinumAngelEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); + super(Duration.WhileOnBattlefield, Outcome.Benefit, false, false); staticText = "You can't lose the game and your opponents can't win the game"; } @@ -91,11 +92,6 @@ public class PlatinumAngel extends CardImpl { return true; } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - return true; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if ((event.getType() == EventType.WINS && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) || diff --git a/Mage.Sets/src/mage/sets/timespiral/AngelsGrace.java b/Mage.Sets/src/mage/sets/timespiral/AngelsGrace.java index 9bc2a66e2ef..cff3e098615 100644 --- a/Mage.Sets/src/mage/sets/timespiral/AngelsGrace.java +++ b/Mage.Sets/src/mage/sets/timespiral/AngelsGrace.java @@ -29,6 +29,7 @@ package mage.sets.timespiral; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.SplitSecondAbility; import mage.cards.CardImpl; @@ -71,10 +72,10 @@ public class AngelsGrace extends CardImpl { } } -class AngelsGraceEffect extends ReplacementEffectImpl { +class AngelsGraceEffect extends ContinuousRuleModifiyingEffectImpl { public AngelsGraceEffect() { - super(Duration.EndOfTurn, Outcome.Benefit); + super(Duration.EndOfTurn, Outcome.Benefit, false, false); staticText = "You can't lose the game this turn and your opponents can't win the game this turn"; } @@ -92,11 +93,6 @@ class AngelsGraceEffect extends ReplacementEffectImpl { return true; } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - return true; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if ((event.getType() == EventType.WINS && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) || @@ -124,10 +120,15 @@ class AngelsGraceReplacementEffect extends ReplacementEffectImpl { return new AngelsGraceReplacementEffect(this); } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType().equals(GameEvent.EventType.DAMAGE_CAUSES_LIFE_LOSS); + } + + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(GameEvent.EventType.DAMAGE_CAUSES_LIFE_LOSS) - && event.getPlayerId().equals(source.getControllerId())) { + if (event.getPlayerId().equals(source.getControllerId())) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && (controller.getLife() - event.getAmount()) < 1 ) { diff --git a/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java b/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java index 1986ee19cfd..90c1ed0f69e 100644 --- a/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java +++ b/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java @@ -79,7 +79,7 @@ public class AbyssalPersecutor extends CardImpl { class AbyssalPersecutorCannotWinEffect extends ContinuousRuleModifiyingEffectImpl { AbyssalPersecutorCannotWinEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); + super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false); staticText = "You can't win the game and your opponents can't lose the game"; } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 6663eecc517..3ee92c04d70 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1896,12 +1896,23 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canLose(Game game) { - return !game.replaceEvent(new GameEvent(GameEvent.EventType.LOSES, null, null, playerId)); + return hasLeft() // If a player concedes or has left the match he loses also if effect would say otherwise + || !game.replaceEvent(new GameEvent(GameEvent.EventType.LOSES, null, null, playerId)); } @Override - public void won(Game game) { - if (!game.replaceEvent(new GameEvent(GameEvent.EventType.WINS, null, null, playerId))) { + public void won(Game game) { + boolean opponentInGame = false; + for (UUID opponentId: game.getOpponents(playerId)) { + Player opponent = game.getPlayer(opponentId); + + if (opponent != null && opponent.isInGame()) { + opponentInGame = true; + break; + } + } + if (!opponentInGame || // if no more opponent is in game the wins event may no longer be replaced + !game.replaceEvent(new GameEvent(GameEvent.EventType.WINS, null, null, playerId))) { logger.debug("player won -> start: " + this.getName()); if (!this.loses) { //20130501 - 800.7, 801.16 From 63ccafacb1ec4de1bcffcdb70012c414804334f0 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 18 Jan 2015 23:50:39 -0500 Subject: [PATCH 08/34] Added implementation of Balduvian Rage --- .../src/mage/sets/coldsnap/BalduvianRage.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java diff --git a/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java b/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java new file mode 100644 index 00000000000..b4a414ed615 --- /dev/null +++ b/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java @@ -0,0 +1,73 @@ +/* + * 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.coldsnap; + +import java.util.UUID; + +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continious.BoostTargetEffect; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; + + +/** + * @author duncancmt + */ +public class BalduvianRage extends CardImpl { + + public BalduvianRage(UUID ownerId) { + super(ownerId, 76, "Balduvian Rage", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{X}{R}"); + this.expansionSetCode = "CSP"; + this.color.setRed(true); + + // Target attacking creature gets +X/+0 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card at the beginning of the next turn's upkeep. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)),false)); + } + + public BalduvianRage(final BalduvianRage card) { + super(card); + } + + @Override + public BalduvianRage copy() { + return new BalduvianRage(this); + } +} From efd820c2ddce9505cf4bfd36a0733e0416e7a6ff Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 19 Jan 2015 01:06:44 -0500 Subject: [PATCH 09/34] Added implementation of Rally the Righteous --- .../mage/sets/ravnika/RallyTheRighteous.java | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java diff --git a/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java new file mode 100644 index 00000000000..b0c148e0f2d --- /dev/null +++ b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java @@ -0,0 +1,143 @@ +/* + * 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.ravnika; + +import java.util.UUID; + +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Outcome; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.SubLayer; +import mage.game.permanent.Permanent; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.game.Game; + +/** + * @author duncancmt + */ + +public class RallyTheRighteous extends CardImpl { + + public RallyTheRighteous(UUID ownerId) { + super(ownerId, 222, "Rally the Righteous", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}{W}"); + this.expansionSetCode = "RAV"; + this.color.setRed(true); + this.color.setWhite(true); + + // Radiance — Untap target creature and each other creature that shares a color with it. Those creatures get +2/+0 until end of turn. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new RallyTheRighteousUntapEffect()); + this.getSpellAbility().addEffect(new RallyTheRighteousBoostEffect()); + } + + public RallyTheRighteous(final RallyTheRighteous card) { + super(card); + } + + @Override + public RallyTheRighteous copy() { + return new RallyTheRighteous(this); + } +} + + +class RallyTheRighteousUntapEffect extends OneShotEffect { + + public RallyTheRighteousUntapEffect() { + super(Outcome.Untap); + staticText = "Radiance — Untap target creature and each other creature that shares a color with it."; + } + + public RallyTheRighteousUntapEffect(final RallyTheRighteousUntapEffect effect) { + super(effect); + } + + @Override + public RallyTheRighteousUntapEffect copy() { + return new RallyTheRighteousUntapEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + if (target != null) { + ObjectColor color = target.getColor(); + target.untap(game); + for (Permanent p : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + if (p.getColor().shares(color) && !p.getId().equals(target.getId())) { + p.untap(game); + } + } + return true; + } + return false; + } +} + + +class RallyTheRighteousBoostEffect extends ContinuousEffectImpl { + + public RallyTheRighteousBoostEffect() { + super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); + staticText = "Radiance — Target creature and each other creature that shares a color with it get +2/+0 until end of turn."; + } + + public RallyTheRighteousBoostEffect(final RallyTheRighteousBoostEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + if (target != null) { + ObjectColor color = target.getColor(); + target.addPower(2); + for (Permanent p : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + if (p.getColor().shares(color) && !p.getId().equals(target.getId())) { + p.addPower(2); + } + } + return true; + } + return false; + } + + @Override + public RallyTheRighteousBoostEffect copy() { + return new RallyTheRighteousBoostEffect(this); + } +} From 56e2fff814e98792c281de7896d9f88dd76a72f6 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 19 Jan 2015 01:51:13 -0500 Subject: [PATCH 10/34] Added implementation of Mercy Killing --- .../mage/sets/shadowmoor/MercyKilling.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java new file mode 100644 index 00000000000..2c47938f03c --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java @@ -0,0 +1,100 @@ +/* + * 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.shadowmoor; + +import java.util.UUID; + +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.cards.CardImpl; +import mage.target.common.TargetCreaturePermanent; +import mage.game.permanent.token.ElfToken; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Zone; +import mage.game.Game; +import mage.abilities.Ability; +import mage.game.permanent.Permanent; +import mage.constants.Outcome; + + +/** + * @author duncancmt + */ +public class MercyKilling extends CardImpl { + + public MercyKilling(UUID ownerId) { + super(ownerId, 231, "Mercy Killing", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{G/W}"); + this.expansionSetCode = "SHM"; + this.color.setGreen(true); + this.color.setWhite(true); + + // Target creature's controller sacrifices it, then puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new SacrificeTargetEffect()); + this.getSpellAbility().addEffect(new MercyKillingTokenEffect()); + } + + public MercyKilling(final MercyKilling card) { + super(card); + } + + @Override + public MercyKilling copy() { + return new MercyKilling(this); + } +} + +class MercyKillingTokenEffect extends OneShotEffect { + + public MercyKillingTokenEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "Its controller puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power."; + } + + public MercyKillingTokenEffect(final MercyKillingTokenEffect effect) { + super(effect); + } + + @Override + public MercyKillingTokenEffect copy() { + return new MercyKillingTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); + if (permanent != null) { + int power = permanent.getPower().getValue(); + ElfToken token = new ElfToken(); + token.putOntoBattlefield(power, game, source.getSourceId(), permanent.getControllerId()); + } + return true; + } + +} From faea2c847e8f29d666f9696e1dd651330d4818b3 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 19 Jan 2015 16:32:16 -0500 Subject: [PATCH 11/34] Added implementation of Veilstone Amulet --- .../sets/futuresight/VeilstoneAmulet.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java diff --git a/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java new file mode 100644 index 00000000000..624b130fc48 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java @@ -0,0 +1,111 @@ +/* + * 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.futuresight; + +import java.util.UUID; + +import mage.cards.CardImpl; +import mage.constants.Rarity; +import mage.constants.CardType; + + +import mage.abilities.common.SpellCastControllerTriggeredAbility; + +import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.abilities.Ability; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.events.GameEvent.EventType; + +/** + * @author duncancmt + */ +public class VeilstoneAmulet extends CardImpl { + + public VeilstoneAmulet(UUID ownerId) { + super(ownerId, 166, "Veilstone Amulet", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "FUT"; + + // Whenever you cast a spell, creatures you control can't be the targets of spells or abilities your opponents control this turn. + this.addAbility(new SpellCastControllerTriggeredAbility(new VeilstoneAmuletEffect(), false)); + } + + public VeilstoneAmulet(final VeilstoneAmulet card) { + super(card); + } + + @Override + public VeilstoneAmulet copy() { + return new VeilstoneAmulet(this); + } +} + +// Veilstone Amulet's effect is strange. It effects all creatures you control, +// even if they entered the battlefield after the ability resolved. It modifies +// the rules of the game until end of turn. +class VeilstoneAmuletEffect extends ContinuousRuleModifiyingEffectImpl { + + public VeilstoneAmuletEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + } + + public VeilstoneAmuletEffect(final VeilstoneAmuletEffect effect) { + super(effect); + } + + @Override + public VeilstoneAmuletEffect copy() { + return new VeilstoneAmuletEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability ability, Game game) { + if (event.getType() == EventType.TARGET) { + Permanent permanent = game.getPermanent(event.getTargetId()); + UUID permanentController = permanent.getControllerId(); + UUID abilityController = ability.getControllerId(); + UUID sourceController = event.getPlayerId(); + + if (permanent != null && + permanent.getCardType().contains(CardType.CREATURE) && + permanentController.equals(abilityController) && + game.getPlayer(abilityController).hasOpponent(sourceController, game)) { + return true; + } + } + return false; + } +} From 1a95461e4281cfd5d26d7409c3a0271af8d52d7f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 19 Jan 2015 16:32:36 -0500 Subject: [PATCH 12/34] Added implementation of Ink-Treader Nephilim Implementation is slightly wrong because it does not allow the player to choose the order that copies go on the stack. --- .../sets/guildpact/InkTreaderNephilim.java | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java diff --git a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java new file mode 100644 index 00000000000..ac172d237a8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -0,0 +1,216 @@ +/* + * 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.guildpact; + +import java.util.UUID; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.MageInt; +import mage.cards.CardImpl; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.Target; +import mage.abilities.Modes; + + +/** + * @author duncancmt + */ +public class InkTreaderNephilim extends CardImpl { + + public InkTreaderNephilim(UUID ownerId) { + super(ownerId, 117, "Ink-Treader Nephilim", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{R}{G}{W}{U}"); + this.expansionSetCode = "GPT"; + this.subtype.add("Nephilim"); + this.color.setRed(true); + this.color.setGreen(true); + this.color.setWhite(true); + this.color.setBlue(true); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever a player casts an instant or sorcery spell, if that spell targets only Ink-Treader Nephilim, copy the spell for each other creature that spell could target. Each copy targets a different one of those creatures. + this.addAbility(new InkTreaderNephilimTriggeredAbility()); + } + + public InkTreaderNephilim(final InkTreaderNephilim card) { + super(card); + } + + @Override + public InkTreaderNephilim copy() { + return new InkTreaderNephilim(this); + } +} + +class InkTreaderNephilimTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterSpell filter = new FilterSpell(); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.INSTANT), + new CardTypePredicate(CardType.SORCERY))); + } + + InkTreaderNephilimTriggeredAbility() { + super(Zone.BATTLEFIELD, new InkTreaderNephilimEffect(), false); + } + + InkTreaderNephilimTriggeredAbility(final InkTreaderNephilimTriggeredAbility ability) { + super(ability); + } + + @Override + public InkTreaderNephilimTriggeredAbility copy() { + return new InkTreaderNephilimTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && + spell.getCardType().contains(CardType.INSTANT) || spell.getCardType().contains(CardType.SORCERY)){ + for (Effect effect : getEffects()) { + effect.setValue("TriggeringSpell", spell); + } + return true; + } + } + return false; + } + + @Override + public boolean checkInterveningIfClause(Game game) { + Spell spell = (Spell) getEffects().get(0).getValue("TriggeringSpell"); + if (spell != null) { + boolean allTargetsInkTreaderNephilim = true; + boolean atLeastOneTargetsInkTreaderNephilim = false; + for (SpellAbility sa: spell.getSpellAbilities()){ + Modes modes = sa.getModes(); + for (UUID mode : modes.getSelectedModes()) { + for (Target targetInstance : modes.get(mode).getTargets()) { + for (UUID target : targetInstance.getTargets()) { + allTargetsInkTreaderNephilim &= target.equals(sourceId); + atLeastOneTargetsInkTreaderNephilim |= target.equals(sourceId); + } + } + } + } + if (allTargetsInkTreaderNephilim && atLeastOneTargetsInkTreaderNephilim) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a player casts an instant or sorcery spell, if that spell targets only Ink-Treader Nephilim, copy the spell for each other creature that spell could target. Each copy targets a different one of those creatures."; + } +} + +class InkTreaderNephilimEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public InkTreaderNephilimEffect() { + super(Outcome.Copy); + } + + public InkTreaderNephilimEffect(final InkTreaderNephilimEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell) getValue("TriggeringSpell"); + if (spell != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + Spell copy = spell.copySpell(); + copy.setControllerId(source.getControllerId()); + copy.setCopiedSpell(true); + if (permanent.getId().equals(source.getSourceId())) { + continue; // copy only for other creatures + } + boolean legal = true; + for (SpellAbility sa : copy.getSpellAbilities()) { + Modes modes = sa.getModes(); + for (UUID mode : modes.getSelectedModes()) { + for (Target targetInstance : modes.get(mode).getTargets()) { + legal &= targetInstance.canTarget(permanent.getId(), sa, game); + } + } + } + if (legal) { + for (SpellAbility sa : copy.getSpellAbilities()) { + Modes modes = sa.getModes(); + for (UUID mode : modes.getSelectedModes()) { + for (Target targetInstance : modes.get(mode).getTargets()) { + int numTargets = targetInstance.getNumberOfTargets(); + targetInstance.clearChosen(); + while (numTargets > 0) { + targetInstance.add(permanent.getId(), game); + numTargets--; + } + } + } + } + game.getStack().push(copy); + } + } + return true; + } + return false; + } + + @Override + public InkTreaderNephilimEffect copy() { + return new InkTreaderNephilimEffect(this); + } + +} From 25ec2a95d008609b8c6af8c4cc79639d7c7706fe Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 19 Jan 2015 19:21:21 -0500 Subject: [PATCH 13/34] Added implementation of Breath of Fury --- .../src/mage/sets/ravnika/BreathOfFury.java | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java diff --git a/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java new file mode 100644 index 00000000000..5d493b9e822 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java @@ -0,0 +1,209 @@ +/* + * 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.ravnika; + +import java.util.UUID; + +import mage.cards.CardImpl; +import mage.constants.Rarity; +import mage.constants.CardType; + +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.abilities.Ability; +import mage.abilities.keyword.EnchantAbility; + +import mage.abilities.TriggeredAbilityImpl; +import mage.constants.Zone; +import mage.game.events.GameEvent; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.abilities.effects.OneShotEffect; +import mage.game.permanent.Permanent; +import mage.abilities.effects.Effect; +import mage.target.targetpointer.FixedTarget; +import mage.players.Player; +import mage.target.Target; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.turn.TurnMod; +import mage.constants.TurnPhase; +import mage.MageObject; +import mage.filter.predicate.Predicate; + +/** + * @author duncancmt + */ +public class BreathOfFury extends CardImpl { + public BreathOfFury(UUID ownerId) { + super(ownerId, 116, "Breath of Fury", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); + this.expansionSetCode = "RAV"; + this.subtype.add("Aura"); + + this.color.setRed(true); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When enchanted creature deals combat damage to a player, sacrifice it and attach Breath of Fury to a creature you control. If you do, untap all creatures you control and after this phase, there is an additional combat phase. + this.addAbility(new BreathOfFuryAbility()); + } + + public BreathOfFury(final BreathOfFury card) { + super(card); + } + + @Override + public BreathOfFury copy() { + return new BreathOfFury(this); + } +} + +class BreathOfFuryAbility extends TriggeredAbilityImpl { + + public BreathOfFuryAbility() { + super(Zone.BATTLEFIELD, new BreathOfFuryEffect()); + } + + public BreathOfFuryAbility(final BreathOfFuryAbility ability) { + super(ability); + } + + @Override + public BreathOfFuryAbility copy() { + return new BreathOfFuryAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event instanceof DamagedPlayerEvent) { + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; + Permanent p = game.getPermanent(event.getSourceId()); + if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(p.getId())); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When enchanted creature deals combat damage to a player, sacrifice it and attach Breath of Fury to a creature you control. If you do, untap all creatures you control and after this phase, there is an additional combat phase."; + } +} + +class BreathOfFuryEffect extends OneShotEffect { + + public BreathOfFuryEffect() { + super(Outcome.Benefit); + staticText = "Sacrifice enchanted creature and attach Breath of Fury to a creature you control. If you do, untap all creatures you control and after this phase, there is an additional combat phase."; + } + + public BreathOfFuryEffect(final BreathOfFuryEffect effect) { + super(effect); + } + + @Override + public BreathOfFuryEffect copy() { + return new BreathOfFuryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source){ + Permanent enchantedCreature = game.getPermanent(targetPointer.getFirst(game, source)); + Permanent enchantment = game.getPermanent(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + Target target = new TargetControlledCreaturePermanent(new FilterCanBeEnchantedControlledCreaturePermanent(enchantment)); + target.setNotTarget(true); + if (enchantedCreature != null && + enchantedCreature.sacrifice(source.getSourceId(), game) && + enchantment != null && + controller != null && + target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + controller.choose(outcome, target, source.getId(), game); + Permanent newCreature = game.getPermanent(target.getFirstTarget()); + if (newCreature != null && + newCreature.addAttachment(enchantment.getId(), game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterControlledCreaturePermanent(), + controller.getId(), game)) { + permanent.untap(game); + } + game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false)); + return true; + } + } + return false; + } +} + + + +class FilterCanBeEnchantedControlledCreaturePermanent extends FilterControlledCreaturePermanent { + + public FilterCanBeEnchantedControlledCreaturePermanent(final FilterCanBeEnchantedControlledCreaturePermanent filter) { + super(filter); + } + + public FilterCanBeEnchantedControlledCreaturePermanent(MageObject auraEnchantment) { + super("creature you control that could be enchanted by " + auraEnchantment.getName()); + this.add(new CanBeEnchantedPredicate(auraEnchantment)); + } + + @Override + public FilterCanBeEnchantedControlledCreaturePermanent copy() { + return new FilterCanBeEnchantedControlledCreaturePermanent(this); + } +} + + +class CanBeEnchantedPredicate implements Predicate { + + private final MageObject auraEnchantment; + + public CanBeEnchantedPredicate(MageObject auraEnchantment){ + this.auraEnchantment = auraEnchantment; + } + + @Override + public boolean apply(Permanent input, Game game) { + return !input.cantBeEnchantedBy(auraEnchantment, game); + } + + @Override + public String toString() { + return "CanBeEnchanted(" + auraEnchantment.toString() + ")"; + } +} From f08ec6f2aabe0b5b299f7a9119a19b3dd71317bd Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 21 Jan 2015 22:16:31 -0500 Subject: [PATCH 14/34] Fixed null pointer dereference in Veilstone Amulet --- .../sets/futuresight/VeilstoneAmulet.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java index 624b130fc48..5861cc4a01a 100644 --- a/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java +++ b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java @@ -35,7 +35,7 @@ import mage.constants.CardType; import mage.abilities.common.SpellCastControllerTriggeredAbility; - +import mage.filter.FilterSpell; import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; import mage.constants.Duration; import mage.constants.Outcome; @@ -55,7 +55,10 @@ public class VeilstoneAmulet extends CardImpl { this.expansionSetCode = "FUT"; // Whenever you cast a spell, creatures you control can't be the targets of spells or abilities your opponents control this turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new VeilstoneAmuletEffect(), false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new VeilstoneAmuletEffect(), + new FilterSpell(), + false, + "Whenever you cast a spell, creatures you control can't be the targets of spells or abilities your opponents control this turn.")); } public VeilstoneAmulet(final VeilstoneAmulet card) { @@ -95,15 +98,15 @@ class VeilstoneAmuletEffect extends ContinuousRuleModifiyingEffectImpl { public boolean applies(GameEvent event, Ability ability, Game game) { if (event.getType() == EventType.TARGET) { Permanent permanent = game.getPermanent(event.getTargetId()); - UUID permanentController = permanent.getControllerId(); - UUID abilityController = ability.getControllerId(); - UUID sourceController = event.getPlayerId(); - - if (permanent != null && - permanent.getCardType().contains(CardType.CREATURE) && - permanentController.equals(abilityController) && - game.getPlayer(abilityController).hasOpponent(sourceController, game)) { - return true; + if (permanent != null) { + UUID permanentController = permanent.getControllerId(); + UUID abilityController = ability.getControllerId(); + UUID sourceController = event.getPlayerId(); + if (permanent.getCardType().contains(CardType.CREATURE) && + permanentController.equals(abilityController) && + game.getPlayer(abilityController).hasOpponent(sourceController, game)) { + return true; + } } } return false; From 00e79f2fdd9c1bc0d0992dad523ddd23f7bb4e38 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 21 Jan 2015 22:18:07 -0500 Subject: [PATCH 15/34] Fixed the color of Mercy Killing's tokens. --- .../mage/sets/shadowmoor/MercyKilling.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java index 2c47938f03c..5d31d3636cf 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java @@ -34,14 +34,14 @@ import mage.constants.Rarity; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.cards.CardImpl; import mage.target.common.TargetCreaturePermanent; -import mage.game.permanent.token.ElfToken; import mage.abilities.effects.OneShotEffect; import mage.constants.Zone; import mage.game.Game; import mage.abilities.Ability; import mage.game.permanent.Permanent; import mage.constants.Outcome; - +import mage.game.permanent.token.Token; +import mage.MageInt; /** * @author duncancmt @@ -91,10 +91,24 @@ class MercyKillingTokenEffect extends OneShotEffect { Permanent permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); if (permanent != null) { int power = permanent.getPower().getValue(); - ElfToken token = new ElfToken(); + MercyKillingToken token = new MercyKillingToken(); token.putOntoBattlefield(power, game, source.getSourceId(), permanent.getControllerId()); } return true; } } + +class MercyKillingToken extends Token { + + public MercyKillingToken() { + super("Elf Warrior", "1/1 green and white Elf Warrior creature token"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + color.setWhite(true); + subtype.add("Elf"); + subtype.add("Warrior"); + power = new MageInt(1); + toughness = new MageInt(1); + } +} From e27a504348197443e988b2f8f87f01b82f7ec52a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 21 Jan 2015 22:24:17 -0500 Subject: [PATCH 16/34] Allow Ink-Treader Nephilim's ability's controller to choose the order in which copies go on the stack. --- .../sets/guildpact/InkTreaderNephilim.java | 72 ++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java index ac172d237a8..c632d7d58d9 100644 --- a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -27,6 +27,9 @@ */ package mage.sets.guildpact; +import java.util.Collection; +import java.util.HashMap; +import java.util.ArrayList; import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; @@ -48,8 +51,15 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; +import java.util.Map; +import java.util.Set; +import java.util.List; +import mage.MageObject; import mage.target.Target; import mage.abilities.Modes; +import mage.filter.predicate.ObjectPlayer; +import mage.filter.predicate.ObjectPlayerPredicate; +import mage.target.TargetPermanent; /** @@ -170,9 +180,11 @@ class InkTreaderNephilimEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Spell spell = (Spell) getValue("TriggeringSpell"); if (spell != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + Map targetable = new HashMap<>(); + UUID controller = source.getControllerId(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller, source.getSourceId(), game)) { Spell copy = spell.copySpell(); - copy.setControllerId(source.getControllerId()); + copy.setControllerId(controller); copy.setCopiedSpell(true); if (permanent.getId().equals(source.getSourceId())) { continue; // copy only for other creatures @@ -200,7 +212,32 @@ class InkTreaderNephilimEffect extends OneShotEffect { } } } - game.getStack().push(copy); + targetable.put(permanent.getId(), copy); + } + } + while (targetable.size() > 0) { + TargetPermanent target = new TargetPermanent(0, 1, + new FilterPermanentFromSet("creature that spell could target ("+Integer.toString(targetable.size())+" remaining)", + targetable.keySet()), + true); + if (target.possibleTargets(controller, game).size() > 1 + && target.canChoose(source.getSourceId(), controller, game)) { + game.getPlayer(controller).choose(Outcome.Neutral, target, source.getId(), game); + } + Collection chosen = target.getTargets(); + if (chosen.size() == 0) { + chosen = targetable.keySet(); + } + List toDelete = new ArrayList<>(); + for (UUID chosenId : chosen) { + Spell chosenCopy = targetable.get(chosenId); + if (chosenCopy != null) { + game.getStack().push(chosenCopy); + toDelete.add(chosenId); + } + } + for (UUID id : toDelete) { + targetable.remove(id); } } return true; @@ -214,3 +251,32 @@ class InkTreaderNephilimEffect extends OneShotEffect { } } + +class FromSetPredicate> implements ObjectPlayerPredicate { + protected Set set; + + public FromSetPredicate(Set set) { + this.set = set; + } + + public boolean apply(T input, Game game) { + return set.contains(input.getObject().getId()); + } +} + +class FilterPermanentFromSet extends FilterPermanent { + public FilterPermanentFromSet(Set set) { + super(); + this.extraPredicates.add(new FromSetPredicate(set)); + } + + public FilterPermanentFromSet(String name, Set set) { + super(name); + this.extraPredicates.add(new FromSetPredicate(set)); + } + + public FilterPermanentFromSet(String subtype, String name, Set set) { + super(subtype, name); + this.extraPredicates.add(new FromSetPredicate(set)); + } +} From d341e39e0525451b952d6d7164fb0ae6a8b77748 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 22 Jan 2015 01:17:13 -0500 Subject: [PATCH 17/34] Added mage.util.SpellTargetAddress a utility for addressing and iterating over the targets of a spell --- Mage/src/mage/util/SpellTargetAddress.java | 155 +++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 Mage/src/mage/util/SpellTargetAddress.java diff --git a/Mage/src/mage/util/SpellTargetAddress.java b/Mage/src/mage/util/SpellTargetAddress.java new file mode 100644 index 00000000000..9220afab775 --- /dev/null +++ b/Mage/src/mage/util/SpellTargetAddress.java @@ -0,0 +1,155 @@ +/* + * 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.util; + +import java.util.Iterator; +import java.util.UUID; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.SpellAbility; +import mage.game.stack.Spell; +import mage.target.Target; + + +/** + * @author duncancmt + */ +public class SpellTargetAddress { + protected int spellAbilityIndex; + protected UUID mode; + protected int targetIndex; + + public SpellTargetAddress(int spellAbilityIndex, UUID mode, int targetIndex) { + this.spellAbilityIndex = spellAbilityIndex; + this.mode = mode; + this.targetIndex = targetIndex; + } + + protected static class SpellTargetAddressIterable implements Iterable { + protected final Spell spell; + + public SpellTargetAddressIterable(Spell spell) { + this.spell = spell; + } + + public Iterator iterator() { + return new SpellTargetAddressIterator(spell); + } + } + + protected static class SpellTargetAddressIterator implements Iterator { + protected Iterator spellAbilityIterator; + protected Integer lastSpellAbilityIndex = null; + protected Iterator modeIterator = null; + protected Modes modes = null; + protected UUID lastMode = null; + protected Iterator targetIterator = null; + protected Integer lastTargetIndex = null; + + public SpellTargetAddressIterator(Spell spell) { + this.spellAbilityIterator = spell.getSpellAbilities().iterator(); + calcNext(); + } + + public boolean hasNext() { + return lastTargetIndex != null; + } + + public SpellTargetAddress next() { + SpellTargetAddress ret = new SpellTargetAddress(lastSpellAbilityIndex, + lastMode, + lastTargetIndex); + calcNext(); + return ret; + + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + protected void calcNext() { + if (targetIterator == null) { + if (modeIterator == null) { + if (spellAbilityIterator.hasNext()) { + if (lastSpellAbilityIndex == null) { + lastSpellAbilityIndex = 0; + } else { + lastSpellAbilityIndex++; + } + modes = spellAbilityIterator.next().getModes(); + modeIterator = modes.getSelectedModes().iterator(); + } else { + lastSpellAbilityIndex = null; + return; + } + } + + if (modeIterator != null && modeIterator.hasNext()) { + lastMode = modeIterator.next(); + targetIterator = modes.get(lastMode).getTargets().iterator(); + } else { + lastMode = null; + modes = null; + modeIterator = null; + calcNext(); + } + } + + if (targetIterator != null && targetIterator.hasNext()) { + if (lastTargetIndex == null) { + lastTargetIndex = 0; + } else { + lastTargetIndex++; + } + targetIterator.next(); + } else { + targetIterator = null; + lastTargetIndex = null; + calcNext(); + } + } + } + + + public static Iterable walk(Spell spell) { + return new SpellTargetAddressIterable(spell); + } + + public Target getTarget(Spell spell) { + return spell.getSpellAbilities().get(spellAbilityIndex).getModes().get(mode).getTargets().get(targetIndex); + } + + public Mode getMode(Spell spell) { + return spell.getSpellAbilities().get(spellAbilityIndex).getModes().get(mode); + } + + public SpellAbility getSpellAbility(Spell spell) { + return spell.getSpellAbilities().get(spellAbilityIndex); + } +} From 018a2a163e18fd44807fe2276c20daf9ce5cac5c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 22 Jan 2015 01:19:17 -0500 Subject: [PATCH 18/34] Use mage.util.SpellTargetAddress in Ink-Treader Nephilim. --- .../sets/guildpact/InkTreaderNephilim.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java index c632d7d58d9..7dfdd03cad6 100644 --- a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -60,7 +60,7 @@ import mage.abilities.Modes; import mage.filter.predicate.ObjectPlayer; import mage.filter.predicate.ObjectPlayerPredicate; import mage.target.TargetPermanent; - +import mage.util.SpellTargetAddress; /** * @author duncancmt @@ -190,26 +190,18 @@ class InkTreaderNephilimEffect extends OneShotEffect { continue; // copy only for other creatures } boolean legal = true; - for (SpellAbility sa : copy.getSpellAbilities()) { - Modes modes = sa.getModes(); - for (UUID mode : modes.getSelectedModes()) { - for (Target targetInstance : modes.get(mode).getTargets()) { - legal &= targetInstance.canTarget(permanent.getId(), sa, game); - } - } + for (SpellTargetAddress addr : SpellTargetAddress.walk(copy)) { + Target targetInstance = addr.getTarget(copy); + legal &= targetInstance.canTarget(permanent.getId(), addr.getSpellAbility(copy), game); } if (legal) { - for (SpellAbility sa : copy.getSpellAbilities()) { - Modes modes = sa.getModes(); - for (UUID mode : modes.getSelectedModes()) { - for (Target targetInstance : modes.get(mode).getTargets()) { - int numTargets = targetInstance.getNumberOfTargets(); - targetInstance.clearChosen(); - while (numTargets > 0) { - targetInstance.add(permanent.getId(), game); - numTargets--; - } - } + for (SpellTargetAddress addr : SpellTargetAddress.walk(copy)) { + Target targetInstance = addr.getTarget(copy); + int numTargets = targetInstance.getNumberOfTargets(); + targetInstance.clearChosen(); + while (numTargets > 0) { + targetInstance.add(permanent.getId(), game); + numTargets--; } } targetable.put(permanent.getId(), copy); From c4d1150e32cca54721dfd294474dff45579050d0 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 22 Jan 2015 01:19:47 -0500 Subject: [PATCH 19/34] Use mage.util.SpellTargetAddress in Precursor Golem --- .../sets/scarsofmirrodin/PrecursorGolem.java | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java index 55da525676f..65e614fb420 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java @@ -53,6 +53,7 @@ import mage.target.Target; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.util.SpellTargetAddress; /** * @author nantuko @@ -122,22 +123,20 @@ class PrecursorGolemCopyTriggeredAbility extends TriggeredAbilityImpl { if (spell != null && (spell.getCardType().contains(CardType.INSTANT) || spell.getCardType().contains(CardType.SORCERY))) { UUID targetGolem = null; - SpellAbility sa = spell.getSpellAbility(); - for (Effect effect : sa.getEffects()) { - for (UUID target : effect.getTargetPointer().getTargets(game, sa)) { + for (SpellTargetAddress addr : SpellTargetAddress.walk(spell)) { + Target targetInstance = addr.getTarget(spell); + for (UUID target : targetInstance.getTargets()) { Permanent permanent = game.getPermanent(target); - if (permanent != null) { - if (!permanent.hasSubtype("Golem")) { + if (permanent == null || !permanent.hasSubtype("Golem")) { + return false; + } + if (targetGolem == null) { + targetGolem = target; + } else { + // If a spell has multiple targets, but it's targeting the same Golem with all of them, Precursor Golem's last ability will trigger + if (!targetGolem.equals(target)) { return false; } - if (targetGolem == null) { - targetGolem = target; - } else { - // If a spell has multiple targets, but it's targeting the same Golem with all of them, Precursor Golem's last ability will trigger - if (!targetGolem.equals(target)) { - return false; - } - } } } } @@ -176,14 +175,14 @@ class PrecursorGolemCopySpellEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); if (spell != null) { - SpellAbility sa = spell.getSpellAbility(); UUID targetedGolem = (UUID) getValue("targetedGolem"); for (Permanent permanent : game.getBattlefield().getActivePermanents(filterGolem, source.getControllerId(), source.getSourceId(), game)) { if (permanent.getId().equals(targetedGolem)) { continue; // copy only for other golems } boolean legal = true; - for (Target target : sa.getTargets()) { + for (SpellTargetAddress addr : SpellTargetAddress.walk(spell)) { + Target target = addr.getTarget(spell); if (!target.canTarget(permanent.getId(), game)) { legal = false; break; @@ -193,10 +192,8 @@ class PrecursorGolemCopySpellEffect extends OneShotEffect { Spell copy = spell.copySpell(); copy.setControllerId(spell.getControllerId()); copy.setCopiedSpell(true); - for (Effect effect : copy.getSpellAbility().getEffects()) { - effect.setTargetPointer(new FixedTarget(permanent.getId())); - } - for (Target target : copy.getSpellAbility().getTargets()) { + for (SpellTargetAddress addr : SpellTargetAddress.walk(copy)) { + Target target = addr.getTarget(copy); target.clearChosen(); target.add(permanent.getId(), game); } From 0e10ea0c84f8bba9eaf5a44c1dda413fe20c36ca Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 22 Jan 2015 01:43:13 -0500 Subject: [PATCH 20/34] Moved FromSetPredicate to its own file, mage.filter.predicate.mageobject.FromSetPredicate --- .../sets/guildpact/InkTreaderNephilim.java | 41 ++------------- .../mageobject/FromSetPredicate.java | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+), 37 deletions(-) create mode 100644 Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java diff --git a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java index 7dfdd03cad6..6751f1ddc98 100644 --- a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -52,13 +52,10 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import java.util.Map; -import java.util.Set; import java.util.List; -import mage.MageObject; import mage.target.Target; import mage.abilities.Modes; -import mage.filter.predicate.ObjectPlayer; -import mage.filter.predicate.ObjectPlayerPredicate; +import mage.filter.predicate.mageobject.FromSetPredicate; import mage.target.TargetPermanent; import mage.util.SpellTargetAddress; @@ -208,10 +205,9 @@ class InkTreaderNephilimEffect extends OneShotEffect { } } while (targetable.size() > 0) { - TargetPermanent target = new TargetPermanent(0, 1, - new FilterPermanentFromSet("creature that spell could target ("+Integer.toString(targetable.size())+" remaining)", - targetable.keySet()), - true); + FilterPermanent filter = new FilterPermanent("creature that spell could target ("+Integer.toString(targetable.size())+" remaining)"); + filter.add(new FromSetPredicate(targetable.keySet())); + TargetPermanent target = new TargetPermanent(0, 1, filter, true); if (target.possibleTargets(controller, game).size() > 1 && target.canChoose(source.getSourceId(), controller, game)) { game.getPlayer(controller).choose(Outcome.Neutral, target, source.getId(), game); @@ -243,32 +239,3 @@ class InkTreaderNephilimEffect extends OneShotEffect { } } - -class FromSetPredicate> implements ObjectPlayerPredicate { - protected Set set; - - public FromSetPredicate(Set set) { - this.set = set; - } - - public boolean apply(T input, Game game) { - return set.contains(input.getObject().getId()); - } -} - -class FilterPermanentFromSet extends FilterPermanent { - public FilterPermanentFromSet(Set set) { - super(); - this.extraPredicates.add(new FromSetPredicate(set)); - } - - public FilterPermanentFromSet(String name, Set set) { - super(name); - this.extraPredicates.add(new FromSetPredicate(set)); - } - - public FilterPermanentFromSet(String subtype, String name, Set set) { - super(subtype, name); - this.extraPredicates.add(new FromSetPredicate(set)); - } -} diff --git a/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java b/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java new file mode 100644 index 00000000000..0c0822e3d20 --- /dev/null +++ b/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java @@ -0,0 +1,50 @@ +/* + * 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.filter.predicate.mageobject; + +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.filter.predicate.ObjectPlayer; +import mage.filter.predicate.ObjectPlayerPredicate; +import mage.game.Game; + +/** + * @author duncancmt + */ +public class FromSetPredicate> implements ObjectPlayerPredicate { + protected Set set; + + public FromSetPredicate(Set set) { + this.set = set; + } + + public boolean apply(T input, Game game) { + return set.contains(input.getObject().getId()); + } +} From 5ee31e6cc0f1c5843f1e5efd0001918d334e810f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 22 Jan 2015 01:50:45 -0500 Subject: [PATCH 21/34] Fixed a bug where Precursor Golem triggers wouldn't use last-known information and would instead be countered if the triggering spell left the stack. Added the ability for the player to control the order in which Precursor Golem copies go on the stack. --- .../sets/scarsofmirrodin/PrecursorGolem.java | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java index 65e614fb420..73e543efb2d 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java @@ -27,6 +27,11 @@ */ package mage.sets.scarsofmirrodin; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -53,6 +58,8 @@ import mage.target.Target; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.filter.predicate.mageobject.FromSetPredicate; +import mage.target.TargetPermanent; import mage.util.SpellTargetAddress; /** @@ -141,7 +148,7 @@ class PrecursorGolemCopyTriggeredAbility extends TriggeredAbilityImpl { } } if (targetGolem != null) { - getEffects().get(0).setTargetPointer(new FixedTarget(spell.getId())); + getEffects().get(0).setValue("triggeringSpell", spell); getEffects().get(0).setValue("targetedGolem", targetGolem); return true; } @@ -173,9 +180,10 @@ class PrecursorGolemCopySpellEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + Spell spell = (Spell) getValue("triggeringSpell"); if (spell != null) { UUID targetedGolem = (UUID) getValue("targetedGolem"); + Map targetable = new HashMap<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(filterGolem, source.getControllerId(), source.getSourceId(), game)) { if (permanent.getId().equals(targetedGolem)) { continue; // copy only for other golems @@ -190,14 +198,40 @@ class PrecursorGolemCopySpellEffect extends OneShotEffect { } if (legal) { Spell copy = spell.copySpell(); - copy.setControllerId(spell.getControllerId()); copy.setCopiedSpell(true); for (SpellTargetAddress addr : SpellTargetAddress.walk(copy)) { Target target = addr.getTarget(copy); target.clearChosen(); target.add(permanent.getId(), game); } - game.getStack().push(copy); + targetable.put(permanent.getId(), copy); + } + } + UUID spellController = spell.getControllerId(); + while (targetable.size() > 0) { + FilterPermanent filter = new FilterPermanent("Golem", + "Golem that spell could target ("+Integer.toString(targetable.size())+" remaining)"); + filter.add(new FromSetPredicate(targetable.keySet())); + TargetPermanent target = new TargetPermanent(0, 1, filter, true); + + if (target.possibleTargets(spellController, game).size() > 1 + && target.canChoose(spell.getSourceId(), spellController, game)) { + game.getPlayer(spellController).choose(Outcome.Neutral, target, source.getId(), game); + } + Collection chosen = target.getTargets(); + if (chosen.size() == 0) { + chosen = targetable.keySet(); + } + List toDelete = new ArrayList<>(); + for (UUID chosenId : chosen) { + Spell chosenCopy = targetable.get(chosenId); + if (chosenCopy != null) { + game.getStack().push(chosenCopy); + toDelete.add(chosenId); + } + } + for (UUID id : toDelete) { + targetable.remove(id); } } return true; From 81c2b3e4737a5a02c71e1aa348264a770a35a2ac Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 08:16:14 +0100 Subject: [PATCH 22/34] * Vaultbreaker - Fixed hat the discard was wrongly random. --- Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java b/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java index d0e3f58f163..4f6840806bc 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java +++ b/Mage.Sets/src/mage/sets/fatereforged/Vaultbreaker.java @@ -88,7 +88,7 @@ class VaultbreakerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Cards discardedCard = controller.discard(1, true, source, game); + Cards discardedCard = controller.discard(1, false, source, game); if (discardedCard != null) { controller.drawCards(1, game); return true; From 9956d91a4ef906a1bafe917bdd9b77c678b331d3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 13:05:44 +0100 Subject: [PATCH 23/34] Minor chnages to cards committed by Laxika. --- .../mage/sets/apocalypse/UrborgUprising.java | 2 - .../mage/sets/arabiannights/FishliverOil.java | 65 ++----------------- 2 files changed, 6 insertions(+), 61 deletions(-) diff --git a/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java b/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java index a7facaa0360..3568089da48 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java +++ b/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java @@ -46,8 +46,6 @@ public class UrborgUprising extends CardImpl { super(ownerId, 53, "Urborg Uprising", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{4}{B}"); this.expansionSetCode = "APC"; - this.color.setBlack(true); - // Return up to two target creature cards from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, new FilterCreatureCard("creature cards from your graveyard"))); diff --git a/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java b/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java index dc374e6e465..8ba0be128c6 100644 --- a/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java +++ b/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java @@ -30,21 +30,17 @@ package mage.sets.arabiannights; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continious.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.IslandwalkAbility; import mage.cards.CardImpl; +import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; -import static mage.constants.Layer.AbilityAddingRemovingEffects_6; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.SubLayer; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -58,18 +54,16 @@ public class FishliverOil extends CardImpl { this.expansionSetCode = "ARN"; this.subtype.add("Aura"); - this.color.setBlue(true); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - // Enchanted creature has islandwalk. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FishliverOilEffect())); + // Enchanted creature has islandwalk. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAttachedEffect(new IslandwalkAbility(), AttachmentType.AURA, Duration.WhileOnBattlefield))); } public FishliverOil(final FishliverOil card) { @@ -81,50 +75,3 @@ public class FishliverOil extends CardImpl { return new FishliverOil(this); } } - -class FishliverOilEffect extends ContinuousEffectImpl { - - public FishliverOilEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - staticText = "Enchanted creature has islandwalk"; - } - - public FishliverOilEffect(final FishliverOilEffect effect) { - super(effect); - } - - @Override - public FishliverOilEffect copy() { - return new FishliverOilEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (creature != null) { - switch (layer) { - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - creature.addAbility(new IslandwalkAbility(), game); - } - break; - } - return true; - } - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6; - } - -} \ No newline at end of file From f1c78784f7e518931540d6716aaa29cf118faed3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 13:13:43 +0100 Subject: [PATCH 24/34] Minor changes to card committed by someoneseth. --- .../dissension/NovijenHeartOfProgress.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java index 70198612789..cbc0dc7915f 100644 --- a/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java +++ b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java @@ -28,26 +28,23 @@ package mage.sets.dissension; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.ColorlessManaAbility; -import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; /** * @@ -59,10 +56,10 @@ public class NovijenHeartOfProgress extends CardImpl { super(ownerId, 175, "Novijen, Heart of Progress", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "DIS"; - // {tap}: Add {1} to your mana pool. + // {T}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); - // {G}{U}, {tap}: Put a +1/+1 counter on each creature that entered the battlefield this turn. + // {G}{U}, {T}: Put a +1/+1 counter on each creature that entered the battlefield this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new NovijenHeartOfProgressEffect(), new ManaCostsImpl<>("{G}{U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -82,7 +79,7 @@ class NovijenHeartOfProgressEffect extends OneShotEffect { public NovijenHeartOfProgressEffect() { super(Outcome.BoostCreature); - staticText = "Put a +1/+1 counter on each creature that came into play this turn."; + staticText = "put a +1/+1 counter on each creature that came into play this turn"; } public NovijenHeartOfProgressEffect(final NovijenHeartOfProgressEffect effect) { @@ -96,13 +93,17 @@ class NovijenHeartOfProgressEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (permanent.getTurnsOnBattlefield() == 0) { - permanent.addCounters(CounterType.P1P1.createInstance(), game); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + if (permanent.getTurnsOnBattlefield() == 0) { + permanent.addCounters(CounterType.P1P1.createInstance(), game); + game.informPlayers(sourceObject.getLogName()+ ": " + controller.getName() + " puts a +1/+1 counter on " + permanent.getLogName()); + } } + return true; } - return true; + return false; } } \ No newline at end of file From a160cb2e99dc878765d997ad3a7e77a67865202f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 22 Jan 2015 10:51:14 -0500 Subject: [PATCH 25/34] Fixed comments by LevelX2 on pull request #687 Removed superfluous calls to this.color.set* Added attacking filter to Balduvian Rage Fixed text and formatting on Rally the Righteous Use game.getPermanentOrLKIBattlefield in Mercy Killing Fixed text on Mercy Killing --- Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java | 4 ++-- .../src/mage/sets/guildpact/InkTreaderNephilim.java | 6 +----- Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java | 2 -- .../src/mage/sets/ravnika/RallyTheRighteous.java | 6 ++---- .../src/mage/sets/scarsofmirrodin/PrecursorGolem.java | 2 +- Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java | 11 ++++++----- 6 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java b/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java index b4a414ed615..efeeb667132 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java +++ b/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java @@ -42,6 +42,7 @@ import mage.target.common.TargetCreaturePermanent; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.filter.common.FilterAttackingCreature; /** @@ -52,11 +53,10 @@ public class BalduvianRage extends CardImpl { public BalduvianRage(UUID ownerId) { super(ownerId, 76, "Balduvian Rage", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{X}{R}"); this.expansionSetCode = "CSP"; - this.color.setRed(true); // Target attacking creature gets +X/+0 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterAttackingCreature())); // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)),false)); diff --git a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java index 6751f1ddc98..74b60c53590 100644 --- a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -68,10 +68,6 @@ public class InkTreaderNephilim extends CardImpl { super(ownerId, 117, "Ink-Treader Nephilim", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{R}{G}{W}{U}"); this.expansionSetCode = "GPT"; this.subtype.add("Nephilim"); - this.color.setRed(true); - this.color.setGreen(true); - this.color.setWhite(true); - this.color.setBlue(true); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -205,7 +201,7 @@ class InkTreaderNephilimEffect extends OneShotEffect { } } while (targetable.size() > 0) { - FilterPermanent filter = new FilterPermanent("creature that spell could target ("+Integer.toString(targetable.size())+" remaining)"); + FilterPermanent filter = new FilterPermanent("creature that spell could target ("+targetable.size()+" remaining)"); filter.add(new FromSetPredicate(targetable.keySet())); TargetPermanent target = new TargetPermanent(0, 1, filter, true); if (target.possibleTargets(controller, game).size() > 1 diff --git a/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java index 5d493b9e822..475b4ec40c8 100644 --- a/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java +++ b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java @@ -66,8 +66,6 @@ public class BreathOfFury extends CardImpl { this.expansionSetCode = "RAV"; this.subtype.add("Aura"); - this.color.setRed(true); - // Enchant creature you control TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); diff --git a/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java index b0c148e0f2d..d3a61293479 100644 --- a/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java +++ b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java @@ -55,8 +55,6 @@ public class RallyTheRighteous extends CardImpl { public RallyTheRighteous(UUID ownerId) { super(ownerId, 222, "Rally the Righteous", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}{W}"); this.expansionSetCode = "RAV"; - this.color.setRed(true); - this.color.setWhite(true); // Radiance — Untap target creature and each other creature that shares a color with it. Those creatures get +2/+0 until end of turn. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -79,7 +77,7 @@ class RallyTheRighteousUntapEffect extends OneShotEffect { public RallyTheRighteousUntapEffect() { super(Outcome.Untap); - staticText = "Radiance — Untap target creature and each other creature that shares a color with it."; + staticText = "Radiance — Untap target creature and each other creature that shares a color with it."; } public RallyTheRighteousUntapEffect(final RallyTheRighteousUntapEffect effect) { @@ -113,7 +111,7 @@ class RallyTheRighteousBoostEffect extends ContinuousEffectImpl { public RallyTheRighteousBoostEffect() { super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); - staticText = "Radiance — Target creature and each other creature that shares a color with it get +2/+0 until end of turn."; + staticText = " Those creatures get +2/+0 until end of turn."; } public RallyTheRighteousBoostEffect(final RallyTheRighteousBoostEffect effect) { diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java index 73e543efb2d..9d56275812e 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java @@ -210,7 +210,7 @@ class PrecursorGolemCopySpellEffect extends OneShotEffect { UUID spellController = spell.getControllerId(); while (targetable.size() > 0) { FilterPermanent filter = new FilterPermanent("Golem", - "Golem that spell could target ("+Integer.toString(targetable.size())+" remaining)"); + "Golem that spell could target ("+targetable.size()+" remaining)"); filter.add(new FromSetPredicate(targetable.keySet())); TargetPermanent target = new TargetPermanent(0, 1, filter, true); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java index 5d31d3636cf..f3cedb9033e 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java @@ -42,6 +42,7 @@ import mage.game.permanent.Permanent; import mage.constants.Outcome; import mage.game.permanent.token.Token; import mage.MageInt; +import mage.abilities.effects.Effect; /** * @author duncancmt @@ -51,12 +52,12 @@ public class MercyKilling extends CardImpl { public MercyKilling(UUID ownerId) { super(ownerId, 231, "Mercy Killing", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{G/W}"); this.expansionSetCode = "SHM"; - this.color.setGreen(true); - this.color.setWhite(true); // Target creature's controller sacrifices it, then puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new SacrificeTargetEffect()); + Effect sacEffect = new SacrificeTargetEffect(); + sacEffect.setText("Target creature's controller sacrifices it"); + this.getSpellAbility().addEffect(sacEffect); this.getSpellAbility().addEffect(new MercyKillingTokenEffect()); } @@ -74,7 +75,7 @@ class MercyKillingTokenEffect extends OneShotEffect { public MercyKillingTokenEffect() { super(Outcome.PutCreatureInPlay); - staticText = "Its controller puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power."; + staticText = ", then puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power."; } public MercyKillingTokenEffect(final MercyKillingTokenEffect effect) { @@ -88,7 +89,7 @@ class MercyKillingTokenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); + Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); if (permanent != null) { int power = permanent.getPower().getValue(); MercyKillingToken token = new MercyKillingToken(); From f77c93029964fc9fa5aaeed24c28893f9fcadae6 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 17:31:30 +0100 Subject: [PATCH 26/34] * Some changes to cards committed by duncant. --- .../sets/futuresight/VeilstoneAmulet.java | 16 +--- .../sets/guildpact/InkTreaderNephilim.java | 51 ++++++------ .../src/mage/sets/ravnika/BreathOfFury.java | 79 +++++++------------ .../mage/sets/ravnika/RallyTheRighteous.java | 39 +++++---- .../mage/sets/shadowmoor/MercyKilling.java | 16 ++-- .../mageobject/FromSetPredicate.java | 8 +- 6 files changed, 99 insertions(+), 110 deletions(-) diff --git a/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java index 5861cc4a01a..b406d81ff73 100644 --- a/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java +++ b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java @@ -28,12 +28,9 @@ package mage.sets.futuresight; import java.util.UUID; - import mage.cards.CardImpl; import mage.constants.Rarity; import mage.constants.CardType; - - import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.filter.FilterSpell; import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; @@ -55,10 +52,7 @@ public class VeilstoneAmulet extends CardImpl { this.expansionSetCode = "FUT"; // Whenever you cast a spell, creatures you control can't be the targets of spells or abilities your opponents control this turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new VeilstoneAmuletEffect(), - new FilterSpell(), - false, - "Whenever you cast a spell, creatures you control can't be the targets of spells or abilities your opponents control this turn.")); + this.addAbility(new SpellCastControllerTriggeredAbility(new VeilstoneAmuletEffect(), new FilterSpell("a spell"), false)); } public VeilstoneAmulet(final VeilstoneAmulet card) { @@ -78,6 +72,7 @@ class VeilstoneAmuletEffect extends ContinuousRuleModifiyingEffectImpl { public VeilstoneAmuletEffect() { super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "creatures you control can't be the targets of spells or abilities your opponents control this turn"; } public VeilstoneAmuletEffect(final VeilstoneAmuletEffect effect) { @@ -99,12 +94,9 @@ class VeilstoneAmuletEffect extends ContinuousRuleModifiyingEffectImpl { if (event.getType() == EventType.TARGET) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { - UUID permanentController = permanent.getControllerId(); - UUID abilityController = ability.getControllerId(); - UUID sourceController = event.getPlayerId(); if (permanent.getCardType().contains(CardType.CREATURE) && - permanentController.equals(abilityController) && - game.getPlayer(abilityController).hasOpponent(sourceController, game)) { + permanent.getControllerId().equals(ability.getControllerId()) && + game.getPlayer(ability.getControllerId()).hasOpponent(event.getPlayerId(), game)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java index 74b60c53590..b086a567d7f 100644 --- a/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -35,7 +35,6 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; import mage.cards.CardImpl; - import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; @@ -56,6 +55,7 @@ import java.util.List; import mage.target.Target; import mage.abilities.Modes; import mage.filter.predicate.mageobject.FromSetPredicate; +import mage.players.Player; import mage.target.TargetPermanent; import mage.util.SpellTargetAddress; @@ -68,6 +68,7 @@ public class InkTreaderNephilim extends CardImpl { super(ownerId, 117, "Ink-Treader Nephilim", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{R}{G}{W}{U}"); this.expansionSetCode = "GPT"; this.subtype.add("Nephilim"); + this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -113,7 +114,7 @@ class InkTreaderNephilimTriggeredAbility extends TriggeredAbilityImpl { if (event.getType() == GameEvent.EventType.SPELL_CAST) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && - spell.getCardType().contains(CardType.INSTANT) || spell.getCardType().contains(CardType.SORCERY)){ + (spell.getCardType().contains(CardType.INSTANT) || spell.getCardType().contains(CardType.SORCERY))){ for (Effect effect : getEffects()) { effect.setValue("TriggeringSpell", spell); } @@ -129,10 +130,10 @@ class InkTreaderNephilimTriggeredAbility extends TriggeredAbilityImpl { if (spell != null) { boolean allTargetsInkTreaderNephilim = true; boolean atLeastOneTargetsInkTreaderNephilim = false; - for (SpellAbility sa: spell.getSpellAbilities()){ - Modes modes = sa.getModes(); - for (UUID mode : modes.getSelectedModes()) { - for (Target targetInstance : modes.get(mode).getTargets()) { + for (SpellAbility spellAbility: spell.getSpellAbilities()){ + Modes modesSpell = spellAbility.getModes(); + for (UUID mode : modesSpell.getSelectedModes()) { + for (Target targetInstance : modesSpell.get(mode).getTargets()) { for (UUID target : targetInstance.getTargets()) { allTargetsInkTreaderNephilim &= target.equals(sourceId); atLeastOneTargetsInkTreaderNephilim |= target.equals(sourceId); @@ -149,7 +150,7 @@ class InkTreaderNephilimTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a player casts an instant or sorcery spell, if that spell targets only Ink-Treader Nephilim, copy the spell for each other creature that spell could target. Each copy targets a different one of those creatures."; + return "Whenever a player casts an instant or sorcery spell, if that spell targets only {this}, copy the spell for each other creature that spell could target. Each copy targets a different one of those creatures."; } } @@ -163,6 +164,7 @@ class InkTreaderNephilimEffect extends OneShotEffect { public InkTreaderNephilimEffect() { super(Outcome.Copy); + staticText = "copy the spell for each other creature that spell could target. Each copy targets a different one of those creatures"; } public InkTreaderNephilimEffect(final InkTreaderNephilimEffect effect) { @@ -171,13 +173,17 @@ class InkTreaderNephilimEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } Spell spell = (Spell) getValue("TriggeringSpell"); if (spell != null) { Map targetable = new HashMap<>(); - UUID controller = source.getControllerId(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller, source.getSourceId(), game)) { + // gather all creatures that can be targeted from the spell to copy + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { Spell copy = spell.copySpell(); - copy.setControllerId(controller); + copy.setControllerId(controller.getId()); copy.setCopiedSpell(true); if (permanent.getId().equals(source.getSourceId())) { continue; // copy only for other creatures @@ -200,28 +206,29 @@ class InkTreaderNephilimEffect extends OneShotEffect { targetable.put(permanent.getId(), copy); } } + // controller while (targetable.size() > 0) { - FilterPermanent filter = new FilterPermanent("creature that spell could target ("+targetable.size()+" remaining)"); - filter.add(new FromSetPredicate(targetable.keySet())); - TargetPermanent target = new TargetPermanent(0, 1, filter, true); - if (target.possibleTargets(controller, game).size() > 1 - && target.canChoose(source.getSourceId(), controller, game)) { - game.getPlayer(controller).choose(Outcome.Neutral, target, source.getId(), game); + FilterPermanent filterCreatures = new FilterPermanent("creature that spell could target ("+ targetable.size() + " remaining)"); + filterCreatures.add(new FromSetPredicate(targetable.keySet())); + TargetPermanent target = new TargetPermanent(0, 1, filterCreatures, true); + if (target.possibleTargets(controller.getId(), game).size() > 1 + && target.canChoose(source.getSourceId(), controller.getId(), game)) { + controller.choose(Outcome.Neutral, target, source.getId(), game); } - Collection chosen = target.getTargets(); - if (chosen.size() == 0) { - chosen = targetable.keySet(); + Collection choosenIds = target.getTargets(); + if (choosenIds.isEmpty()) { + choosenIds = targetable.keySet(); } List toDelete = new ArrayList<>(); - for (UUID chosenId : chosen) { + for (UUID chosenId : choosenIds) { Spell chosenCopy = targetable.get(chosenId); if (chosenCopy != null) { game.getStack().push(chosenCopy); toDelete.add(chosenId); } } - for (UUID id : toDelete) { - targetable.remove(id); + for (UUID idToDelte : toDelete) { + targetable.remove(idToDelte); } } return true; diff --git a/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java index 475b4ec40c8..341e361df3f 100644 --- a/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java +++ b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java @@ -28,18 +28,15 @@ package mage.sets.ravnika; import java.util.UUID; - import mage.cards.CardImpl; import mage.constants.Rarity; import mage.constants.CardType; - import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.abilities.effects.common.AttachEffect; import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.keyword.EnchantAbility; - import mage.abilities.TriggeredAbilityImpl; import mage.constants.Zone; import mage.game.events.GameEvent; @@ -47,8 +44,6 @@ import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.abilities.effects.OneShotEffect; import mage.game.permanent.Permanent; -import mage.abilities.effects.Effect; -import mage.target.targetpointer.FixedTarget; import mage.players.Player; import mage.target.Target; import mage.filter.common.FilterControlledCreaturePermanent; @@ -105,12 +100,11 @@ class BreathOfFuryAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event instanceof DamagedPlayerEvent) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; - Permanent p = game.getPermanent(event.getSourceId()); - if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) { - for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(p.getId())); - } + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; + Permanent enchantment = game.getPermanent(getSourceId()); + if (damageEvent.isCombatDamage() && + enchantment != null && + enchantment.getAttachedTo().equals(event.getSourceId())) { return true; } } @@ -119,7 +113,7 @@ class BreathOfFuryAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "When enchanted creature deals combat damage to a player, sacrifice it and attach Breath of Fury to a creature you control. If you do, untap all creatures you control and after this phase, there is an additional combat phase."; + return "When enchanted creature deals combat damage to a player, " + super.getRule(); } } @@ -127,7 +121,7 @@ class BreathOfFuryEffect extends OneShotEffect { public BreathOfFuryEffect() { super(Outcome.Benefit); - staticText = "Sacrifice enchanted creature and attach Breath of Fury to a creature you control. If you do, untap all creatures you control and after this phase, there is an additional combat phase."; + staticText = "sacrifice enchanted creature and attach {this} to a creature you control. If you do, untap all creatures you control and after this phase, there is an additional combat phase."; } public BreathOfFuryEffect(final BreathOfFuryEffect effect) { @@ -141,52 +135,39 @@ class BreathOfFuryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source){ - Permanent enchantedCreature = game.getPermanent(targetPointer.getFirst(game, source)); Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment == null) { + return false; + } + Permanent enchantedCreature = game.getPermanent(enchantment.getAttachedTo()); Player controller = game.getPlayer(source.getControllerId()); - Target target = new TargetControlledCreaturePermanent(new FilterCanBeEnchantedControlledCreaturePermanent(enchantment)); + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control that could be enchanted by " + enchantment.getName()); + filter.add(new CanBeEnchantedPredicate(enchantment)); + Target target = new TargetControlledCreaturePermanent(filter); target.setNotTarget(true); - if (enchantedCreature != null && - enchantedCreature.sacrifice(source.getSourceId(), game) && - enchantment != null && - controller != null && - target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - controller.choose(outcome, target, source.getId(), game); - Permanent newCreature = game.getPermanent(target.getFirstTarget()); - if (newCreature != null && - newCreature.addAttachment(enchantment.getId(), game)) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterControlledCreaturePermanent(), - controller.getId(), game)) { - permanent.untap(game); + if (enchantedCreature != null && controller != null) { + // sacrifice the enchanted creature (don't check return state because controller has sarificed independant if something replaced later); + // e.g. Commander replacement effect going to command zone + enchantedCreature.sacrifice(source.getSourceId(), game); + if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + controller.choose(outcome, target, source.getSourceId(), game); + Permanent newCreature = game.getPermanent(target.getFirstTarget()); + if (newCreature != null && + newCreature.addAttachment(enchantment.getId(), game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterControlledCreaturePermanent(), controller.getId(), game)) { + permanent.untap(game); + } + game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false)); + } - game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false)); - return true; + } + return true; } return false; } } - - -class FilterCanBeEnchantedControlledCreaturePermanent extends FilterControlledCreaturePermanent { - - public FilterCanBeEnchantedControlledCreaturePermanent(final FilterCanBeEnchantedControlledCreaturePermanent filter) { - super(filter); - } - - public FilterCanBeEnchantedControlledCreaturePermanent(MageObject auraEnchantment) { - super("creature you control that could be enchanted by " + auraEnchantment.getName()); - this.add(new CanBeEnchantedPredicate(auraEnchantment)); - } - - @Override - public FilterCanBeEnchantedControlledCreaturePermanent copy() { - return new FilterCanBeEnchantedControlledCreaturePermanent(this); - } -} - - class CanBeEnchantedPredicate implements Predicate { private final MageObject auraEnchantment; diff --git a/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java index d3a61293479..0773e7f478d 100644 --- a/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java +++ b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java @@ -29,7 +29,7 @@ package mage.sets.ravnika; import java.util.UUID; - +import mage.MageObjectReference; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Outcome; @@ -77,7 +77,7 @@ class RallyTheRighteousUntapEffect extends OneShotEffect { public RallyTheRighteousUntapEffect() { super(Outcome.Untap); - staticText = "Radiance — Untap target creature and each other creature that shares a color with it."; + staticText = "Radiance — Untap target creature and each other creature that shares a color with it"; } public RallyTheRighteousUntapEffect(final RallyTheRighteousUntapEffect effect) { @@ -91,13 +91,13 @@ class RallyTheRighteousUntapEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { ObjectColor color = target.getColor(); target.untap(game); - for (Permanent p : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { - if (p.getColor().shares(color) && !p.getId().equals(target.getId())) { - p.untap(game); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + if (permanent.getColor().shares(color) && !permanent.getId().equals(target.getId())) { + permanent.untap(game); } } return true; @@ -111,7 +111,7 @@ class RallyTheRighteousBoostEffect extends ContinuousEffectImpl { public RallyTheRighteousBoostEffect() { super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); - staticText = " Those creatures get +2/+0 until end of turn."; + staticText = "Those creatures get +2/+0 until end of turn"; } public RallyTheRighteousBoostEffect(final RallyTheRighteousBoostEffect effect) { @@ -119,19 +119,30 @@ class RallyTheRighteousBoostEffect extends ContinuousEffectImpl { } @Override - public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + public void init(Ability source, Game game) { + super.init(source, game); + Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { + affectedObjectList.add(new MageObjectReference(target)); ObjectColor color = target.getColor(); target.addPower(2); - for (Permanent p : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { - if (p.getColor().shares(color) && !p.getId().equals(target.getId())) { - p.addPower(2); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + if (!permanent.getId().equals(target.getId()) && permanent.getColor().shares(color)) { + affectedObjectList.add(new MageObjectReference(permanent)); } } - return true; + } + } + + @Override + public boolean apply(Game game, Ability source) { + for(MageObjectReference mageObjectReference :affectedObjectList) { + Permanent permanent = mageObjectReference.getPermanent(game); + if (permanent != null) { + permanent.addPower(2); + } } - return false; + return true; } @Override diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java index f3cedb9033e..572f93919f0 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.java @@ -42,7 +42,6 @@ import mage.game.permanent.Permanent; import mage.constants.Outcome; import mage.game.permanent.token.Token; import mage.MageInt; -import mage.abilities.effects.Effect; /** * @author duncancmt @@ -54,11 +53,9 @@ public class MercyKilling extends CardImpl { this.expansionSetCode = "SHM"; // Target creature's controller sacrifices it, then puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power. - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - Effect sacEffect = new SacrificeTargetEffect(); - sacEffect.setText("Target creature's controller sacrifices it"); - this.getSpellAbility().addEffect(sacEffect); + this.getSpellAbility().addEffect(new SacrificeTargetEffect("Target creature's controller sacrifices it")); this.getSpellAbility().addEffect(new MercyKillingTokenEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } public MercyKilling(final MercyKilling card) { @@ -75,7 +72,7 @@ class MercyKillingTokenEffect extends OneShotEffect { public MercyKillingTokenEffect() { super(Outcome.PutCreatureInPlay); - staticText = ", then puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power."; + staticText = ", then puts X 1/1 green and white Elf Warrior creature tokens onto the battlefield, where X is that creature's power"; } public MercyKillingTokenEffect(final MercyKillingTokenEffect effect) { @@ -89,13 +86,12 @@ class MercyKillingTokenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { int power = permanent.getPower().getValue(); - MercyKillingToken token = new MercyKillingToken(); - token.putOntoBattlefield(power, game, source.getSourceId(), permanent.getControllerId()); + return new MercyKillingToken().putOntoBattlefield(power, game, source.getSourceId(), permanent.getControllerId()); } - return true; + return false; } } diff --git a/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java b/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java index 0c0822e3d20..a106b232937 100644 --- a/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java +++ b/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java @@ -29,22 +29,24 @@ package mage.filter.predicate.mageobject; import java.util.Set; import java.util.UUID; -import mage.MageObject; import mage.filter.predicate.ObjectPlayer; import mage.filter.predicate.ObjectPlayerPredicate; +import mage.game.Controllable; import mage.game.Game; /** * @author duncancmt */ -public class FromSetPredicate> implements ObjectPlayerPredicate { +public class FromSetPredicate implements ObjectPlayerPredicate> { + protected Set set; public FromSetPredicate(Set set) { this.set = set; } - public boolean apply(T input, Game game) { + @Override + public boolean apply(ObjectPlayer input, Game game) { return set.contains(input.getObject().getId()); } } From 8ea8e77b885e4de09b7a0c152f8210505dcee6d6 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 21:29:38 +0100 Subject: [PATCH 27/34] Renamed CantCounter to CantBeCountered. --- .../sets/alarareborn/SpellbreakerBehemoth.java | 8 ++++---- .../betrayersofkamigawa/IsaoEnlightenedBushi.java | 4 ++-- .../src/mage/sets/commander/AkromaAngelOfFury.java | 4 ++-- .../src/mage/sets/conflux/VolcanicFallout.java | 4 ++-- Mage.Sets/src/mage/sets/darksteel/LastWord.java | 4 ++-- Mage.Sets/src/mage/sets/dragonsmaze/Skylasher.java | 4 ++-- Mage.Sets/src/mage/sets/guildpact/WreakHavoc.java | 4 ++-- .../src/mage/sets/invasion/BlurredMongoose.java | 4 ++-- Mage.Sets/src/mage/sets/invasion/Obliterate.java | 4 ++-- .../mage/sets/khansoftarkir/PearlLakeAncient.java | 4 ++-- .../mage/sets/khansoftarkir/SurrakDragonclaw.java | 8 ++++---- Mage.Sets/src/mage/sets/legions/RootSliver.java | 8 ++++---- .../src/mage/sets/magic2010/GreatSableStag.java | 4 ++-- Mage.Sets/src/mage/sets/magic2011/AutumnsVeil.java | 4 ++-- Mage.Sets/src/mage/sets/magic2011/Combust.java | 4 ++-- .../src/mage/sets/magic2011/GaeasRevenge.java | 4 ++-- .../src/mage/sets/magic2014/SavageSummoning.java | 4 ++-- .../sets/mirrodinbesieged/ThrunTheLastTroll.java | 4 ++-- .../src/mage/sets/returntoravnica/AbruptDecay.java | 4 ++-- .../src/mage/sets/returntoravnica/Counterflux.java | 4 ++-- .../mage/sets/returntoravnica/LoxodonSmiter.java | 4 ++-- .../mage/sets/returntoravnica/SlaughterGames.java | 4 ++-- .../sets/riseoftheeldrazi/EmrakulTheAeonsTorn.java | 4 ++-- .../src/mage/sets/shadowmoor/VexingShusher.java | 4 ++-- Mage.Sets/src/mage/sets/tempest/Scragnoth.java | 4 ++-- .../src/mage/sets/theros/MistcutterHydra.java | 4 ++-- Mage.Sets/src/mage/sets/zendikar/TerraStomper.java | 4 ++-- ...terAbility.java => CantBeCounteredAbility.java} | 14 +++++++------- ...t.java => CantBeCounteredControlledEffect.java} | 12 ++++++------ ...ffect.java => CantBeCounteredSourceEffect.java} | 10 +++++----- 30 files changed, 78 insertions(+), 78 deletions(-) rename Mage/src/mage/abilities/common/{CantCounterAbility.java => CantBeCounteredAbility.java} (83%) rename Mage/src/mage/abilities/effects/common/{CantCounterControlledEffect.java => CantBeCounteredControlledEffect.java} (88%) rename Mage/src/mage/abilities/effects/common/{CantCounterSourceEffect.java => CantBeCounteredSourceEffect.java} (91%) diff --git a/Mage.Sets/src/mage/sets/alarareborn/SpellbreakerBehemoth.java b/Mage.Sets/src/mage/sets/alarareborn/SpellbreakerBehemoth.java index c6773dfb3f9..62d61e2c437 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/SpellbreakerBehemoth.java +++ b/Mage.Sets/src/mage/sets/alarareborn/SpellbreakerBehemoth.java @@ -35,8 +35,8 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterControlledEffect; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.cards.CardImpl; import mage.filter.Filter; import mage.filter.FilterSpell; @@ -66,8 +66,8 @@ public class SpellbreakerBehemoth extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(5); - this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantCounterSourceEffect())); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantCounterControlledEffect(filter, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantBeCounteredSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeCounteredControlledEffect(filter, Duration.WhileOnBattlefield))); } public SpellbreakerBehemoth(final SpellbreakerBehemoth card) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/IsaoEnlightenedBushi.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/IsaoEnlightenedBushi.java index 149e08b5c36..bbc46096561 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/IsaoEnlightenedBushi.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/IsaoEnlightenedBushi.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.RegenerateTargetEffect; @@ -67,7 +67,7 @@ public class IsaoEnlightenedBushi extends CardImpl { this.toughness = new MageInt(1); // Isao, Enlightened Bushi can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); this.addAbility(new BushidoAbility(2)); // {2}: Regenerate target Samurai. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new GenericManaCost(2)); diff --git a/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java b/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java index 5fbae5933d5..4b30fce97b7 100644 --- a/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java +++ b/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java @@ -30,7 +30,7 @@ package mage.sets.commander; import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continious.BoostSourceEffect; @@ -70,7 +70,7 @@ public class AkromaAngelOfFury extends CardImpl { this.toughness = new MageInt(6); // Akroma, Angel of Fury can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Flying this.addAbility(FlyingAbility.getInstance()); // Trample diff --git a/Mage.Sets/src/mage/sets/conflux/VolcanicFallout.java b/Mage.Sets/src/mage/sets/conflux/VolcanicFallout.java index edc08d563d9..9b3dd2fb236 100644 --- a/Mage.Sets/src/mage/sets/conflux/VolcanicFallout.java +++ b/Mage.Sets/src/mage/sets/conflux/VolcanicFallout.java @@ -30,7 +30,7 @@ package mage.sets.conflux; import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.cards.CardImpl; @@ -47,7 +47,7 @@ public class VolcanicFallout extends CardImpl { this.color.setRed(true); // Volcanic Fallout can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Volcanic Fallout deals 2 damage to each creature and each player. this.getSpellAbility().addEffect(new DamageEverythingEffect(2)); } diff --git a/Mage.Sets/src/mage/sets/darksteel/LastWord.java b/Mage.Sets/src/mage/sets/darksteel/LastWord.java index d15e2d75595..57a10603b11 100644 --- a/Mage.Sets/src/mage/sets/darksteel/LastWord.java +++ b/Mage.Sets/src/mage/sets/darksteel/LastWord.java @@ -31,7 +31,7 @@ package mage.sets.darksteel; import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.target.TargetSpell; @@ -46,7 +46,7 @@ public class LastWord extends CardImpl { super(ownerId, 23, "Last Word", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); this.expansionSetCode = "DST"; this.color.setBlue(true); - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell()); } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/Skylasher.java b/Mage.Sets/src/mage/sets/dragonsmaze/Skylasher.java index a9a11beedfc..c3a772fd3c6 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/Skylasher.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/Skylasher.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.ReachAbility; @@ -65,7 +65,7 @@ public class Skylasher extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); // Skylasher can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Reach, protection from blue this.addAbility(ReachAbility.getInstance()); this.addAbility(new ProtectionAbility(filter)); diff --git a/Mage.Sets/src/mage/sets/guildpact/WreakHavoc.java b/Mage.Sets/src/mage/sets/guildpact/WreakHavoc.java index 718e56db204..8cb7dd07c21 100644 --- a/Mage.Sets/src/mage/sets/guildpact/WreakHavoc.java +++ b/Mage.Sets/src/mage/sets/guildpact/WreakHavoc.java @@ -30,7 +30,7 @@ package mage.sets.guildpact; import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.filter.FilterPermanent; @@ -57,7 +57,7 @@ public class WreakHavoc extends CardImpl { this.expansionSetCode = "GPT"; this.color.setRed(true); this.color.setGreen(true); - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); } diff --git a/Mage.Sets/src/mage/sets/invasion/BlurredMongoose.java b/Mage.Sets/src/mage/sets/invasion/BlurredMongoose.java index 025bc19db68..c36462eaa93 100644 --- a/Mage.Sets/src/mage/sets/invasion/BlurredMongoose.java +++ b/Mage.Sets/src/mage/sets/invasion/BlurredMongoose.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.keyword.ShroudAbility; import mage.cards.CardImpl; @@ -51,7 +51,7 @@ public class BlurredMongoose extends CardImpl { this.toughness = new MageInt(1); // Blurred Mongoose can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); this.addAbility(ShroudAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/invasion/Obliterate.java b/Mage.Sets/src/mage/sets/invasion/Obliterate.java index 3508b5475bb..86fe481c414 100644 --- a/Mage.Sets/src/mage/sets/invasion/Obliterate.java +++ b/Mage.Sets/src/mage/sets/invasion/Obliterate.java @@ -30,7 +30,7 @@ package mage.sets.invasion; import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.filter.FilterPermanent; @@ -59,7 +59,7 @@ public class Obliterate extends CardImpl { this.color.setRed(true); // Obliterate can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Destroy all artifacts, creatures, and lands. They can't be regenerated. this.getSpellAbility().addEffect(new DestroyAllEffect(filter)); } diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/PearlLakeAncient.java b/Mage.Sets/src/mage/sets/khansoftarkir/PearlLakeAncient.java index f0933c85688..bd0d7a667c1 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/PearlLakeAncient.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/PearlLakeAncient.java @@ -29,7 +29,7 @@ package mage.sets.khansoftarkir; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ReturnToHandTargetCost; import mage.abilities.effects.common.ReturnToHandSourceEffect; @@ -61,7 +61,7 @@ public class PearlLakeAncient extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Pearl Lake Ancient can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Prowess this.addAbility(new ProwessAbility()); diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SurrakDragonclaw.java b/Mage.Sets/src/mage/sets/khansoftarkir/SurrakDragonclaw.java index 3c73555ab8c..fcb77af897e 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SurrakDragonclaw.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SurrakDragonclaw.java @@ -29,9 +29,9 @@ package mage.sets.khansoftarkir; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterControlledEffect; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; import mage.abilities.effects.common.continious.GainAbilityControlledEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.TrampleAbility; @@ -74,10 +74,10 @@ public class SurrakDragonclaw extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Surrak Dragonclaw can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Creature spells you control can't be countered. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantCounterControlledEffect(filterTarget, null, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeCounteredControlledEffect(filterTarget, null, Duration.WhileOnBattlefield))); // Other creatures you control have trample. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, diff --git a/Mage.Sets/src/mage/sets/legions/RootSliver.java b/Mage.Sets/src/mage/sets/legions/RootSliver.java index 266b262a543..1291064b610 100644 --- a/Mage.Sets/src/mage/sets/legions/RootSliver.java +++ b/Mage.Sets/src/mage/sets/legions/RootSliver.java @@ -31,8 +31,8 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterControlledEffect; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -65,9 +65,9 @@ public class RootSliver extends CardImpl { this.toughness = new MageInt(2); // Root Sliver can't be countered. - this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantCounterSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantBeCounteredSourceEffect())); // Sliver spells can't be countered by spells or abilities. - this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantCounterControlledEffect(filter, new FilterStackObject(), Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantBeCounteredControlledEffect(filter, new FilterStackObject(), Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/sets/magic2010/GreatSableStag.java b/Mage.Sets/src/mage/sets/magic2010/GreatSableStag.java index 2cc418e5837..a7952ffcae3 100644 --- a/Mage.Sets/src/mage/sets/magic2010/GreatSableStag.java +++ b/Mage.Sets/src/mage/sets/magic2010/GreatSableStag.java @@ -35,7 +35,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.filter.FilterCard; @@ -64,7 +64,7 @@ public class GreatSableStag extends CardImpl { this.addAbility(new ProtectionAbility(filter1)); this.addAbility(new ProtectionAbility(filter2)); - this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantCounterSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantBeCounteredSourceEffect())); } public GreatSableStag(final GreatSableStag card) { diff --git a/Mage.Sets/src/mage/sets/magic2011/AutumnsVeil.java b/Mage.Sets/src/mage/sets/magic2011/AutumnsVeil.java index 7f61bcf9ec6..ce914b9f8c9 100644 --- a/Mage.Sets/src/mage/sets/magic2011/AutumnsVeil.java +++ b/Mage.Sets/src/mage/sets/magic2011/AutumnsVeil.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.ObjectColor; -import mage.abilities.effects.common.CantCounterControlledEffect; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; import mage.abilities.effects.common.CantBeTargetedAllEffect; import mage.cards.CardImpl; import mage.filter.FilterSpell; @@ -62,7 +62,7 @@ public class AutumnsVeil extends CardImpl { this.expansionSetCode = "M11"; this.color.setGreen(true); // Spells you control can't be countered by blue or black spells this turn - this.getSpellAbility().addEffect(new CantCounterControlledEffect(filterTarget1, filterSource, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new CantBeCounteredControlledEffect(filterTarget1, filterSource, Duration.EndOfTurn)); // and creatures you control can't be the targets of blue or black spells this turn. this.getSpellAbility().addEffect(new CantBeTargetedAllEffect(filterTarget2, filterSource, Duration.EndOfTurn)); } diff --git a/Mage.Sets/src/mage/sets/magic2011/Combust.java b/Mage.Sets/src/mage/sets/magic2011/Combust.java index 03313773584..434c4320d6f 100644 --- a/Mage.Sets/src/mage/sets/magic2011/Combust.java +++ b/Mage.Sets/src/mage/sets/magic2011/Combust.java @@ -34,7 +34,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.filter.common.FilterCreaturePermanent; @@ -62,7 +62,7 @@ public class Combust extends CardImpl { this.color.setRed(true); this.getSpellAbility().addEffect(new DamageTargetEffect(5, false)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantCounterSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantBeCounteredSourceEffect())); } public Combust(final Combust card) { diff --git a/Mage.Sets/src/mage/sets/magic2011/GaeasRevenge.java b/Mage.Sets/src/mage/sets/magic2011/GaeasRevenge.java index bbe3a25a379..73adc0a825e 100644 --- a/Mage.Sets/src/mage/sets/magic2011/GaeasRevenge.java +++ b/Mage.Sets/src/mage/sets/magic2011/GaeasRevenge.java @@ -36,7 +36,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.CantBeTargetedSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -64,7 +64,7 @@ public class GaeasRevenge extends CardImpl { this.power = new MageInt(8); this.toughness = new MageInt(5); - this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantCounterSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.STACK, new CantBeCounteredSourceEffect())); this.addAbility(HasteAbility.getInstance()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedSourceEffect(filter, Duration.WhileOnBattlefield))); diff --git a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java index cc050a6b8bb..b80573d13c1 100644 --- a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java +++ b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java @@ -35,7 +35,7 @@ import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; @@ -67,7 +67,7 @@ public class SavageSummoning extends CardImpl { this.color.setGreen(true); // Savage Summoning can't be countered. - Ability ability = new CantCounterAbility(); + Ability ability = new CantBeCounteredAbility(); ability.setRuleAtTheTop(true); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/ThrunTheLastTroll.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/ThrunTheLastTroll.java index c0899bf905c..fe92b131b4b 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/ThrunTheLastTroll.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/ThrunTheLastTroll.java @@ -36,7 +36,7 @@ import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; @@ -58,7 +58,7 @@ public class ThrunTheLastTroll extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(4); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantCounterSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantBeCounteredSourceEffect())); this.addAbility(HexproofAbility.getInstance()); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{1}{G}"))); } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/AbruptDecay.java b/Mage.Sets/src/mage/sets/returntoravnica/AbruptDecay.java index 018cd76e3f6..5fda69b4543 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/AbruptDecay.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/AbruptDecay.java @@ -35,7 +35,7 @@ import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.filter.Filter; @@ -62,7 +62,7 @@ public class AbruptDecay extends CardImpl { this.color.setBlack(true); // Abrupt Decay can't be countered by spells or abilities. - Effect effect = new CantCounterSourceEffect(); + Effect effect = new CantBeCounteredSourceEffect(); effect.setText("{this} can't be countered by spells or abilities"); Ability ability = new SimpleStaticAbility(Zone.STACK,effect); ability.setRuleAtTheTop(true); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/Counterflux.java b/Mage.Sets/src/mage/sets/returntoravnica/Counterflux.java index 7082d893f9a..a0e0597d6ab 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/Counterflux.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/Counterflux.java @@ -38,7 +38,7 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.keyword.OverloadAbility; import mage.cards.CardImpl; @@ -73,7 +73,7 @@ public class Counterflux extends CardImpl { this.color.setRed(true); // Counterflux can't be countered by spells or abilities. - Effect effect = new CantCounterSourceEffect(); + Effect effect = new CantBeCounteredSourceEffect(); effect.setText("{this} can't be countered by spells or abilities"); Ability ability = new SimpleStaticAbility(Zone.STACK,effect); ability.setRuleAtTheTop(true); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/LoxodonSmiter.java b/Mage.Sets/src/mage/sets/returntoravnica/LoxodonSmiter.java index 802dd72d4bd..87e3eb2d8d2 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/LoxodonSmiter.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/LoxodonSmiter.java @@ -30,7 +30,7 @@ package mage.sets.returntoravnica; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; @@ -64,7 +64,7 @@ public class LoxodonSmiter extends CardImpl { this.toughness = new MageInt(4); // Loxodon Smiter can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // If a spell or ability an opponent controls causes you to discard Loxodon Smiter, put it onto the battlefield instead of putting it into your graveyard. this.addAbility(new SimpleStaticAbility(Zone.HAND, new LoxodonSmiterEffect())); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SlaughterGames.java b/Mage.Sets/src/mage/sets/returntoravnica/SlaughterGames.java index ec7f2dd1190..66ef17155c5 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/SlaughterGames.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/SlaughterGames.java @@ -36,7 +36,7 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -62,7 +62,7 @@ public class SlaughterGames extends CardImpl { this.color.setRed(true); // Slaughter Games can't be countered by spells or abilities. - Effect effect = new CantCounterSourceEffect(); + Effect effect = new CantBeCounteredSourceEffect(); effect.setText("{this} can't be countered by spells or abilities"); Ability ability = new SimpleStaticAbility(Zone.STACK,effect); ability.setRuleAtTheTop(true); diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/EmrakulTheAeonsTorn.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/EmrakulTheAeonsTorn.java index c93267f37d8..d20b48458de 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/EmrakulTheAeonsTorn.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/EmrakulTheAeonsTorn.java @@ -36,7 +36,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.AnnihilatorAbility; @@ -73,7 +73,7 @@ public class EmrakulTheAeonsTorn extends CardImpl { this.toughness = new MageInt(15); // Emrakul, the Aeons Torn can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // When you cast Emrakul, take an extra turn after this one. this.addAbility(new EmrakulTheAeonsTornOnCastAbility()); // Flying, protection from colored spells, annihilator 6 diff --git a/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java b/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java index 4f8e5592adc..2f5066eafb6 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; @@ -64,7 +64,7 @@ public class VexingShusher extends CardImpl { this.toughness = new MageInt(2); // Vexing Shusher can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // {R/G}: Target spell can't be countered by spells or abilities. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VexingShusherCantCounterTargetEffect(), new ManaCostsImpl("{R/G}")); ability.addTarget(new TargetSpell()); diff --git a/Mage.Sets/src/mage/sets/tempest/Scragnoth.java b/Mage.Sets/src/mage/sets/tempest/Scragnoth.java index bfa7fa0bcde..b5cc2219c6c 100644 --- a/Mage.Sets/src/mage/sets/tempest/Scragnoth.java +++ b/Mage.Sets/src/mage/sets/tempest/Scragnoth.java @@ -30,7 +30,7 @@ package mage.sets.tempest; import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -59,7 +59,7 @@ public class Scragnoth extends CardImpl { this.toughness = new MageInt(4); // Scragnoth can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Protection from blue this.addAbility(new ProtectionAbility(filter)); } diff --git a/Mage.Sets/src/mage/sets/theros/MistcutterHydra.java b/Mage.Sets/src/mage/sets/theros/MistcutterHydra.java index b98c86cab14..8787d4435b6 100644 --- a/Mage.Sets/src/mage/sets/theros/MistcutterHydra.java +++ b/Mage.Sets/src/mage/sets/theros/MistcutterHydra.java @@ -32,7 +32,7 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.SpellAbility; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.HasteAbility; @@ -68,7 +68,7 @@ public class MistcutterHydra extends CardImpl { this.toughness = new MageInt(0); // Mistcutter Hydra can't be countered. - this.addAbility(new CantCounterAbility()); + this.addAbility(new CantBeCounteredAbility()); // Haste this.addAbility(HasteAbility.getInstance()); // protection from blue diff --git a/Mage.Sets/src/mage/sets/zendikar/TerraStomper.java b/Mage.Sets/src/mage/sets/zendikar/TerraStomper.java index 72b7e44b5bd..42f14da676b 100644 --- a/Mage.Sets/src/mage/sets/zendikar/TerraStomper.java +++ b/Mage.Sets/src/mage/sets/zendikar/TerraStomper.java @@ -33,7 +33,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -52,7 +52,7 @@ public class TerraStomper extends CardImpl { this.power = new MageInt(8); this.toughness = new MageInt(8); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantCounterSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantBeCounteredSourceEffect())); this.addAbility(TrampleAbility.getInstance()); } diff --git a/Mage/src/mage/abilities/common/CantCounterAbility.java b/Mage/src/mage/abilities/common/CantBeCounteredAbility.java similarity index 83% rename from Mage/src/mage/abilities/common/CantCounterAbility.java rename to Mage/src/mage/abilities/common/CantBeCounteredAbility.java index bf5bd6d152c..fac6b58e282 100644 --- a/Mage/src/mage/abilities/common/CantCounterAbility.java +++ b/Mage/src/mage/abilities/common/CantBeCounteredAbility.java @@ -29,20 +29,20 @@ package mage.abilities.common; import mage.abilities.StaticAbility; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.constants.Zone; /** * * @author BetaSteward_at_googlemail.com */ -public class CantCounterAbility extends StaticAbility { +public class CantBeCounteredAbility extends StaticAbility { - public CantCounterAbility() { - super(Zone.STACK, new CantCounterSourceEffect()); + public CantBeCounteredAbility() { + super(Zone.STACK, new CantBeCounteredSourceEffect()); } - public CantCounterAbility(CantCounterAbility ability) { + public CantBeCounteredAbility(CantBeCounteredAbility ability) { super(ability); } @@ -52,7 +52,7 @@ public class CantCounterAbility extends StaticAbility { } @Override - public CantCounterAbility copy() { - return new CantCounterAbility(this); + public CantBeCounteredAbility copy() { + return new CantBeCounteredAbility(this); } } diff --git a/Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java b/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java similarity index 88% rename from Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java rename to Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java index 93179db3392..d44f080bc6e 100644 --- a/Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java @@ -44,23 +44,23 @@ import mage.game.stack.Spell; * * @author BetaSteward_at_googlemail.com */ -public class CantCounterControlledEffect extends ContinuousRuleModifiyingEffectImpl { +public class CantBeCounteredControlledEffect extends ContinuousRuleModifiyingEffectImpl { private FilterSpell filterTarget; private FilterObject filterSource; - public CantCounterControlledEffect(FilterSpell filterTarget, FilterObject filterSource, Duration duration) { + public CantBeCounteredControlledEffect(FilterSpell filterTarget, FilterObject filterSource, Duration duration) { super(duration, Outcome.Benefit); this.filterTarget = filterTarget; this.filterSource = filterSource; setText(); } - public CantCounterControlledEffect(FilterSpell filterTarget, Duration duration) { + public CantBeCounteredControlledEffect(FilterSpell filterTarget, Duration duration) { this(filterTarget, null, duration); } - public CantCounterControlledEffect(final CantCounterControlledEffect effect) { + public CantBeCounteredControlledEffect(final CantBeCounteredControlledEffect effect) { super(effect); if (effect.filterTarget != null) { this.filterTarget = effect.filterTarget.copy(); @@ -71,8 +71,8 @@ public class CantCounterControlledEffect extends ContinuousRuleModifiyingEffectI } @Override - public CantCounterControlledEffect copy() { - return new CantCounterControlledEffect(this); + public CantBeCounteredControlledEffect copy() { + return new CantBeCounteredControlledEffect(this); } @Override diff --git a/Mage/src/mage/abilities/effects/common/CantCounterSourceEffect.java b/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java similarity index 91% rename from Mage/src/mage/abilities/effects/common/CantCounterSourceEffect.java rename to Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java index f845cc66123..c74c54775ec 100644 --- a/Mage/src/mage/abilities/effects/common/CantCounterSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java @@ -43,20 +43,20 @@ import mage.game.stack.StackObject; * * @author BetaSteward_at_googlemail.com */ -public class CantCounterSourceEffect extends ContinuousRuleModifiyingEffectImpl { +public class CantBeCounteredSourceEffect extends ContinuousRuleModifiyingEffectImpl { - public CantCounterSourceEffect() { + public CantBeCounteredSourceEffect() { super(Duration.WhileOnStack, Outcome.Benefit, false, true); staticText = "{this} can't be countered"; } - public CantCounterSourceEffect(final CantCounterSourceEffect effect) { + public CantBeCounteredSourceEffect(final CantBeCounteredSourceEffect effect) { super(effect); } @Override - public CantCounterSourceEffect copy() { - return new CantCounterSourceEffect(this); + public CantBeCounteredSourceEffect copy() { + return new CantBeCounteredSourceEffect(this); } @Override From dbffbad3cbbcc5a16d79401a2c82875b3ace6edf Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 22:41:03 +0100 Subject: [PATCH 28/34] Added early eventType check for ContinuousRuleModifying effects. --- .../mage/sets/alarareborn/MeddlingMage.java | 17 ++---- .../bornofthegods/SpiritOfTheLabyrinth.java | 13 +++-- .../sets/commander/AkromaAngelOfFury.java | 1 - .../mage/sets/commander2014/WakeTheDead.java | 7 ++- .../dragonsmaze/CouncilOfTheAbsolute.java | 26 ++++----- .../mage/sets/dragonsmaze/RenderSilent.java | 13 +++-- .../src/mage/sets/eventide/Moonhold.java | 18 ++++-- .../fatereforged/HewedStoneRetainers.java | 7 ++- .../sets/fatereforged/WardscaleDragon.java | 13 +++-- .../src/mage/sets/fatereforged/WildSlash.java | 12 ++-- .../mage/sets/magic2011/AngelicArbiter.java | 7 ++- .../mage/sets/magic2015/AggressiveMining.java | 7 ++- .../mage/sets/magic2015/HushwingGryff.java | 19 ++++--- .../src/mage/sets/odyssey/CeaseFire.java | 7 ++- .../sets/returntoravnica/SupremeVerdict.java | 6 +- .../src/mage/sets/scourge/XantidSwarm.java | 13 +++-- .../mage/sets/shadowmoor/VexingShusher.java | 7 ++- .../shardsofalara/EtherswornCanonist.java | 15 +++-- Mage.Sets/src/mage/sets/tenth/Incinerate.java | 13 +++-- .../src/mage/sets/theros/RageOfPurphoros.java | 6 -- .../mage/sets/theros/ShipbreakerKraken.java | 7 +++ .../mage/sets/theros/UnderworldCerberus.java | 19 ++++--- .../sets/worldwake/AbyssalPersecutor.java | 5 ++ ...ditionalContinuousRuleModifyingEffect.java | 10 ++++ .../abilities/effects/ContinuousEffects.java | 3 + .../ContinuousRuleModifiyingEffect.java | 9 +++ .../ContinuousRuleModifiyingEffectImpl.java | 5 ++ .../CantActivateAbilitiesAttachedEffect.java | 15 +++-- .../CantBeCounteredControlledEffect.java | 23 ++++---- .../common/CantBeCounteredSourceEffect.java | 16 ++++-- .../common/CantBeTargetedAllEffect.java | 23 ++++---- .../common/CantBeTargetedAttachedEffect.java | 17 +++--- .../common/CantBeTargetedSourceEffect.java | 7 ++- .../common/CantBeTargetedTargetEffect.java | 7 ++- ...nControllersNextUntapStepSourceEffect.java | 8 ++- ...nControllersNextUntapStepTargetEffect.java | 16 ++++-- ...tUntapInControllersUntapStepAllEffect.java | 8 ++- ...InControllersUntapStepEnchantedEffect.java | 6 +- ...tapInControllersUntapStepSourceEffect.java | 6 +- ...tapInControllersUntapStepTargetEffect.java | 8 ++- .../abilities/effects/common/EpicEffect.java | 10 +++- .../CantCastMoreThanOneSpellEffect.java | 57 ++++++++++--------- .../CantRegenerateTargetEffect.java | 14 +++-- .../abilities/keyword/SplitSecondAbility.java | 5 ++ 44 files changed, 343 insertions(+), 188 deletions(-) diff --git a/Mage.Sets/src/mage/sets/alarareborn/MeddlingMage.java b/Mage.Sets/src/mage/sets/alarareborn/MeddlingMage.java index b2a3a682f4c..c05a1cf39b9 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/MeddlingMage.java +++ b/Mage.Sets/src/mage/sets/alarareborn/MeddlingMage.java @@ -28,29 +28,22 @@ package mage.sets.alarareborn; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.NameACardEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * diff --git a/Mage.Sets/src/mage/sets/bornofthegods/SpiritOfTheLabyrinth.java b/Mage.Sets/src/mage/sets/bornofthegods/SpiritOfTheLabyrinth.java index 6614ba2dc99..8e76586676a 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/SpiritOfTheLabyrinth.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/SpiritOfTheLabyrinth.java @@ -137,13 +137,16 @@ class SpiritOfTheLabyrinthEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DRAW_CARD; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.DRAW_CARD) { - SpiritOfTheLabyrinthWatcher watcher = (SpiritOfTheLabyrinthWatcher) game.getState().getWatchers().get("DrewCard"); - if (watcher != null && watcher.hasPlayerDrewCardThisTurn(event.getPlayerId())) { - return true; - } + SpiritOfTheLabyrinthWatcher watcher = (SpiritOfTheLabyrinthWatcher) game.getState().getWatchers().get("DrewCard"); + if (watcher != null && watcher.hasPlayerDrewCardThisTurn(event.getPlayerId())) { + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java b/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java index 4b30fce97b7..d1df42ce6c8 100644 --- a/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java +++ b/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java @@ -65,7 +65,6 @@ public class AkromaAngelOfFury extends CardImpl { this.supertype.add("Legendary"); this.subtype.add("Angel"); - this.color.setRed(true); this.power = new MageInt(6); this.toughness = new MageInt(6); diff --git a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java index d588f1df4d7..5a22ffff0b5 100644 --- a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java +++ b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java @@ -106,9 +106,14 @@ class WakeTheDeadEffect extends ContinuousRuleModifiyingEffectImpl { super(effect); } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(GameEvent.EventType.CAST_SPELL) && event.getSourceId().equals(source.getSourceId())) { + if (event.getSourceId().equals(source.getSourceId())) { if (game.getPhase().getType().equals(TurnPhase.COMBAT)) { return !game.getOpponents(source.getControllerId()).contains(game.getActivePlayerId()); } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/CouncilOfTheAbsolute.java b/Mage.Sets/src/mage/sets/dragonsmaze/CouncilOfTheAbsolute.java index 4f480c3621e..861293bbeeb 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/CouncilOfTheAbsolute.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/CouncilOfTheAbsolute.java @@ -29,11 +29,6 @@ package mage.sets.dragonsmaze; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -41,21 +36,20 @@ import mage.abilities.SpellAbility; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.NameACardEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.util.CardUtil; /** @@ -83,7 +77,6 @@ public class CouncilOfTheAbsolute extends CardImpl { // Spells with the chosen name cost 2 less for you to cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CouncilOfTheAbsoluteCostReductionEffect())); - } public CouncilOfTheAbsolute (final CouncilOfTheAbsolute card) { @@ -127,9 +120,14 @@ class CouncilOfTheAbsoluteReplacementEffect extends ContinuousRuleModifiyingEffe return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.CAST_SPELL && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { MageObject object = game.getObject(event.getSourceId()); if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/RenderSilent.java b/Mage.Sets/src/mage/sets/dragonsmaze/RenderSilent.java index d78f7383bb6..74a0bacd07a 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/RenderSilent.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/RenderSilent.java @@ -146,13 +146,16 @@ class RenderSilentEffect extends ContinuousRuleModifiyingEffectImpl { return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL ) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null && player.getId().equals(event.getPlayerId())) { - return true; - } + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player != null && player.getId().equals(event.getPlayerId())) { + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/eventide/Moonhold.java b/Mage.Sets/src/mage/sets/eventide/Moonhold.java index f2fff80e214..4279bb178e8 100644 --- a/Mage.Sets/src/mage/sets/eventide/Moonhold.java +++ b/Mage.Sets/src/mage/sets/eventide/Moonhold.java @@ -110,15 +110,19 @@ class MoonholdEffect extends ContinuousRuleModifiyingEffectImpl { public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); if (mageObject != null) { - return "You can't play land cards this turn (" + mageObject.getLogName() + ")."; + return "you can't play land cards this turn (" + mageObject.getLogName() + ")."; } return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PLAY_LAND; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.PLAY_LAND - && event.getPlayerId().equals(source.getFirstTarget())) { + if (event.getPlayerId().equals(source.getFirstTarget())) { return true; } return false; @@ -154,10 +158,14 @@ class MoonholdEffect2 extends ContinuousRuleModifiyingEffectImpl { return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL - && event.getPlayerId().equals(source.getFirstTarget())) { + if (event.getPlayerId().equals(source.getFirstTarget())) { Card card = game.getCard(event.getSourceId()); if (card != null && card.getCardType().contains(CardType.CREATURE)) { return true; diff --git a/Mage.Sets/src/mage/sets/fatereforged/HewedStoneRetainers.java b/Mage.Sets/src/mage/sets/fatereforged/HewedStoneRetainers.java index 235cdd23502..e93d63247ad 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/HewedStoneRetainers.java +++ b/Mage.Sets/src/mage/sets/fatereforged/HewedStoneRetainers.java @@ -79,9 +79,14 @@ class HewedStoneRetainersEffect extends ContinuousRuleModifiyingEffectImpl { super(effect); } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL && event.getSourceId().equals(source.getSourceId())) { + if (event.getSourceId().equals(source.getSourceId())) { CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) == 0) { return true; diff --git a/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java b/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java index 51b44ea2d5a..2ef467bd773 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java @@ -96,13 +96,16 @@ class WardscaleDragonRuleEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL ) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null && sourcePermanent.isAttacking()) { - return event.getPlayerId() == game.getCombat().getDefendingPlayerId(sourcePermanent.getId(), game); - } + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null && sourcePermanent.isAttacking()) { + return event.getPlayerId() == game.getCombat().getDefendingPlayerId(sourcePermanent.getId(), game); } return false; } diff --git a/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java b/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java index f27ccc2cb55..475556f1bff 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java @@ -81,7 +81,7 @@ class DamageCantBePreventedEffect extends ContinuousRuleModifiyingEffectImpl { public DamageCantBePreventedEffect() { super(Duration.EndOfTurn, Outcome.Benefit, false, false); - staticText = "Damage can't be prevented this turn"; + staticText = "damage can't be prevented this turn"; } public DamageCantBePreventedEffect(final DamageCantBePreventedEffect effect) { @@ -98,11 +98,13 @@ class DamageCantBePreventedEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PREVENT_DAMAGE; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(GameEvent.EventType.PREVENT_DAMAGE)) { - return true; - } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/sets/magic2011/AngelicArbiter.java b/Mage.Sets/src/mage/sets/magic2011/AngelicArbiter.java index 96690bbdbb8..735e1ca7695 100644 --- a/Mage.Sets/src/mage/sets/magic2011/AngelicArbiter.java +++ b/Mage.Sets/src/mage/sets/magic2011/AngelicArbiter.java @@ -182,9 +182,14 @@ class AngelicArbiterEffect2 extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.CAST_SPELL && game.getActivePlayerId().equals(event.getPlayerId()) && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + if (game.getActivePlayerId().equals(event.getPlayerId()) && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { AngelicArbiterWatcher2 watcher = (AngelicArbiterWatcher2) game.getState().getWatchers().get("PlayerAttacked"); if (watcher != null && watcher.hasPlayerAttackedThisTurn(event.getPlayerId())) { return true; diff --git a/Mage.Sets/src/mage/sets/magic2015/AggressiveMining.java b/Mage.Sets/src/mage/sets/magic2015/AggressiveMining.java index 3c909a83785..71c982f9c21 100644 --- a/Mage.Sets/src/mage/sets/magic2015/AggressiveMining.java +++ b/Mage.Sets/src/mage/sets/magic2015/AggressiveMining.java @@ -97,9 +97,14 @@ class AggressiveMiningEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PLAY_LAND; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getType().equals(GameEvent.EventType.PLAY_LAND) && event.getPlayerId().equals(source.getControllerId()); + return event.getPlayerId().equals(source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java b/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java index 6ec1eb22479..d369e393d88 100644 --- a/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java +++ b/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java @@ -99,17 +99,20 @@ class HushwingGryffEffect extends ContinuousRuleModifiyingEffectImpl { } return null; } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { - Permanent permanent = ((EntersTheBattlefieldEvent)event).getTarget(); - if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { - // Because replacement events have to be executed - // call replaceEvent here without calling the triggering event after - game.getContinuousEffects().replaceEvent(event, game); - return true; - } + Permanent permanent = ((EntersTheBattlefieldEvent)event).getTarget(); + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { + // Because replacement events have to be executed + // call replaceEvent here without calling the triggering event after + game.getContinuousEffects().replaceEvent(event, game); + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java b/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java index e0ac8ec6d3b..544ef24b031 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java +++ b/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java @@ -110,9 +110,14 @@ class CeaseFireEffect extends ContinuousRuleModifiyingEffectImpl { return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL && event.getPlayerId().equals(source.getFirstTarget())) { + if (event.getPlayerId().equals(source.getFirstTarget())) { MageObject object = game.getObject(event.getSourceId()); if (filter.match((Spell) object, game)) { return true; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SupremeVerdict.java b/Mage.Sets/src/mage/sets/returntoravnica/SupremeVerdict.java index e21a64d9b9c..4e3d3dab2ad 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/SupremeVerdict.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/SupremeVerdict.java @@ -30,12 +30,12 @@ package mage.sets.returntoravnica; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.CantCounterAbility; +import mage.abilities.common.CantBeCounteredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.effects.common.CantCounterSourceEffect; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.constants.Zone; @@ -55,7 +55,7 @@ public class SupremeVerdict extends CardImpl { this.color.setBlue(true); // Supreme Verdict can't be countered. - Ability ability = new CantCounterAbility(); + Ability ability = new CantBeCounteredAbility(); ability.setRuleAtTheTop(true); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/scourge/XantidSwarm.java b/Mage.Sets/src/mage/sets/scourge/XantidSwarm.java index ef8da56be57..2939a3cc57e 100644 --- a/Mage.Sets/src/mage/sets/scourge/XantidSwarm.java +++ b/Mage.Sets/src/mage/sets/scourge/XantidSwarm.java @@ -129,13 +129,16 @@ class XantidSwarmReplacementEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL ) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null && player.getId().equals(event.getPlayerId())) { - return true; - } + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player != null && player.getId().equals(event.getPlayerId())) { + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java b/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java index 2f5066eafb6..604e9dc16ff 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java @@ -111,9 +111,14 @@ class VexingShusherCantCounterTargetEffect extends ContinuousRuleModifiyingEffec return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.COUNTER; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getType() == EventType.COUNTER && event.getTargetId().equals(targetPointer.getFirst(game, source)); + return event.getTargetId().equals(targetPointer.getFirst(game, source)); } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/EtherswornCanonist.java b/Mage.Sets/src/mage/sets/shardsofalara/EtherswornCanonist.java index 1bcb3c3e104..e3e773bbacd 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/EtherswornCanonist.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/EtherswornCanonist.java @@ -144,14 +144,17 @@ class EtherswornCanonistReplacementEffect extends ContinuousRuleModifiyingEffect return new EtherswornCanonistReplacementEffect(this); } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL) { - EtherswornCanonistWatcher watcher = (EtherswornCanonistWatcher)game.getState().getWatchers().get("EtherswornCanonistWatcher"); - Card card = game.getCard(event.getSourceId()); - if (card != null && !card.getCardType().contains(CardType.ARTIFACT) && watcher.castNonArtifactSpell(event.getPlayerId())) { - return true; - } + EtherswornCanonistWatcher watcher = (EtherswornCanonistWatcher)game.getState().getWatchers().get("EtherswornCanonistWatcher"); + Card card = game.getCard(event.getSourceId()); + if (card != null && !card.getCardType().contains(CardType.ARTIFACT) && watcher.castNonArtifactSpell(event.getPlayerId())) { + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/tenth/Incinerate.java b/Mage.Sets/src/mage/sets/tenth/Incinerate.java index 2a74ae3db27..ceef626402d 100644 --- a/Mage.Sets/src/mage/sets/tenth/Incinerate.java +++ b/Mage.Sets/src/mage/sets/tenth/Incinerate.java @@ -91,13 +91,16 @@ class IncinerateEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.REGENERATE; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.REGENERATE) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", source.getSourceId()); - if (watcher != null) { - return watcher.wasDamaged(event.getTargetId(), game); - } + DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", source.getSourceId()); + if (watcher != null) { + return watcher.wasDamaged(event.getTargetId(), game); } return false; } diff --git a/Mage.Sets/src/mage/sets/theros/RageOfPurphoros.java b/Mage.Sets/src/mage/sets/theros/RageOfPurphoros.java index 0b15bba1cc2..66afe5c6b4e 100644 --- a/Mage.Sets/src/mage/sets/theros/RageOfPurphoros.java +++ b/Mage.Sets/src/mage/sets/theros/RageOfPurphoros.java @@ -28,19 +28,13 @@ package mage.sets.theros; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousRuleModifiyingEffectImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.effects.common.ruleModifying.CantRegenerateTargetEffect; 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.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.DamagedByWatcher; diff --git a/Mage.Sets/src/mage/sets/theros/ShipbreakerKraken.java b/Mage.Sets/src/mage/sets/theros/ShipbreakerKraken.java index 39a92dc6397..a62a31ad8b0 100644 --- a/Mage.Sets/src/mage/sets/theros/ShipbreakerKraken.java +++ b/Mage.Sets/src/mage/sets/theros/ShipbreakerKraken.java @@ -105,6 +105,13 @@ class ShipbreakerKrakenReplacementEffect extends ContinuousRuleModifiyingEffectI return false; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_CONTROL || + event.getType() == GameEvent.EventType.ZONE_CHANGE || + event.getType() == GameEvent.EventType.UNTAP; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { // Source must be on the battlefield (it's neccessary to check here because if as response to the enter diff --git a/Mage.Sets/src/mage/sets/theros/UnderworldCerberus.java b/Mage.Sets/src/mage/sets/theros/UnderworldCerberus.java index fcf12ad5d38..bc4955e92b3 100644 --- a/Mage.Sets/src/mage/sets/theros/UnderworldCerberus.java +++ b/Mage.Sets/src/mage/sets/theros/UnderworldCerberus.java @@ -105,16 +105,19 @@ class UnderworldCerberusEffect extends ContinuousRuleModifiyingEffectImpl { return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TARGET; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.TARGET) { - Card targetCard = game.getCard(event.getTargetId()); - StackObject stackObject = (StackObject) game.getStack().getStackObject(event.getSourceId()); - if (targetCard != null && stackObject != null) { - Zone zone = game.getState().getZone(targetCard.getId()); - if (zone != null && (zone == Zone.GRAVEYARD)) { - return true; - } + Card targetCard = game.getCard(event.getTargetId()); + StackObject stackObject = (StackObject) game.getStack().getStackObject(event.getSourceId()); + if (targetCard != null && stackObject != null) { + Zone zone = game.getState().getZone(targetCard.getId()); + if (zone != null && (zone == Zone.GRAVEYARD)) { + return true; } } return false; diff --git a/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java b/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java index 90c1ed0f69e..b7716fb5110 100644 --- a/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java +++ b/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java @@ -87,6 +87,11 @@ class AbyssalPersecutorCannotWinEffect extends ContinuousRuleModifiyingEffectImp super(effect); } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.LOSES || event.getType() == EventType.WINS ; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { if ((event.getType() == EventType.LOSES && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) diff --git a/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java b/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java index 03f7f71cbdc..51e1a1ec804 100644 --- a/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java +++ b/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java @@ -99,6 +99,16 @@ public class ConditionalContinuousRuleModifyingEffect extends ContinuousRuleModi return false; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + if (effect.checksEventType(event, game)) { + return true; + } else if (otherwiseEffect != null) { + return otherwiseEffect.checksEventType(event, game); + } + return false; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (!initDone) { // if simpleStaticAbility, init won't be called diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index d769ef989a4..220b9570a1e 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -646,6 +646,9 @@ public class ContinuousEffects implements Serializable { */ public boolean preventedByRuleModification(GameEvent event, Ability targetAbility, Game game, boolean checkPlayableMode) { for (ContinuousRuleModifiyingEffect effect: continuousRuleModifyingEffects) { + if (!effect.checksEventType(event, game)) { + continue; + } for (Ability sourceAbility : continuousRuleModifyingEffects.getAbility(effect.getId())) { if (!(sourceAbility instanceof StaticAbility) || sourceAbility.isInUseableZone(game, null, false)) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { diff --git a/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffect.java b/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffect.java index 60e27543685..f6bc9981b64 100644 --- a/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffect.java +++ b/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffect.java @@ -38,6 +38,15 @@ import mage.game.events.GameEvent; */ public interface ContinuousRuleModifiyingEffect extends ContinuousEffect { + /** + * This check for the relevant events is called at first to prevent further actions if + * the current event is ignored from this effect + * @param event + * @param game + * @return + */ + boolean checksEventType(GameEvent event, Game game); + /** * * @param event the event to check if it may happen diff --git a/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffectImpl.java b/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffectImpl.java index 9d4f756babb..ee3fdadb0e3 100644 --- a/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffectImpl.java +++ b/Mage/src/mage/abilities/effects/ContinuousRuleModifiyingEffectImpl.java @@ -78,6 +78,11 @@ public abstract class ContinuousRuleModifiyingEffectImpl extends ContinuousEffec this.messageToGameLog = effect.messageToGameLog; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return true; + } + @Override public boolean apply(Game game, Ability source) { return true; diff --git a/Mage/src/mage/abilities/effects/common/CantActivateAbilitiesAttachedEffect.java b/Mage/src/mage/abilities/effects/common/CantActivateAbilitiesAttachedEffect.java index c3a3ad2041c..6870b413cf9 100644 --- a/Mage/src/mage/abilities/effects/common/CantActivateAbilitiesAttachedEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantActivateAbilitiesAttachedEffect.java @@ -61,14 +61,17 @@ public class CantActivateAbilitiesAttachedEffect extends ContinuousRuleModifiyin return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ACTIVATE_ABILITY; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { - if (event.getSourceId().equals(enchantment.getAttachedTo())) { - return true; - } + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + if (event.getSourceId().equals(enchantment.getAttachedTo())) { + return true; } } return false; diff --git a/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java b/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java index d44f080bc6e..45a6ea29b26 100644 --- a/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java @@ -80,19 +80,22 @@ public class CantBeCounteredControlledEffect extends ContinuousRuleModifiyingEff return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.COUNTER; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.COUNTER) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.getControllerId().equals(source.getControllerId()) - && filterTarget.match(spell, game)) { - if (filterSource == null) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.getControllerId().equals(source.getControllerId()) + && filterTarget.match(spell, game)) { + if (filterSource == null) { + return true; + } else { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject != null && filterSource.match(sourceObject, game)) { return true; - } else { - MageObject sourceObject = game.getObject(source.getSourceId()); - if (sourceObject != null && filterSource.match(sourceObject, game)) { - return true; - } } } } diff --git a/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java b/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java index c74c54775ec..56e13eb14ab 100644 --- a/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java @@ -74,14 +74,18 @@ public class CantBeCounteredSourceEffect extends ContinuousRuleModifiyingEffectI return staticText; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.COUNTER; + } + + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.COUNTER) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - if (spell.getSourceId().equals(source.getSourceId())) { - return true; - } + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null) { + if (spell.getSourceId().equals(source.getSourceId())) { + return true; } } return false; diff --git a/Mage/src/mage/abilities/effects/common/CantBeTargetedAllEffect.java b/Mage/src/mage/abilities/effects/common/CantBeTargetedAllEffect.java index d030c329dc9..8c8f68724e1 100644 --- a/Mage/src/mage/abilities/effects/common/CantBeTargetedAllEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeTargetedAllEffect.java @@ -81,20 +81,23 @@ public class CantBeTargetedAllEffect extends ContinuousRuleModifiyingEffectImpl return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGET; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.TARGET) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && filterTarget.match(permanent, source.getSourceId(), source.getControllerId(), game)) { - if (filterSource == null) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null && filterTarget.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (filterSource == null) { + return true; + } + else { + StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); + if (sourceObject != null && filterSource.match(sourceObject, sourceObject.getSourceId(), game)) { return true; } - else { - StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); - if (sourceObject != null && filterSource.match(sourceObject, sourceObject.getSourceId(), game)) { - return true; - } - } } } return false; diff --git a/Mage/src/mage/abilities/effects/common/CantBeTargetedAttachedEffect.java b/Mage/src/mage/abilities/effects/common/CantBeTargetedAttachedEffect.java index 0b1e9889409..5971c1ac3de 100644 --- a/Mage/src/mage/abilities/effects/common/CantBeTargetedAttachedEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeTargetedAttachedEffect.java @@ -72,15 +72,18 @@ public class CantBeTargetedAttachedEffect extends ContinuousRuleModifiyingEffect return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGET; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.TARGET) { - Permanent attachment = game.getPermanent(source.getSourceId()); - if (attachment != null && event.getTargetId().equals(attachment.getAttachedTo())) { - StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); - if (sourceObject != null && filterSource.match(sourceObject, source.getControllerId(), game)) { - return true; - } + Permanent attachment = game.getPermanent(source.getSourceId()); + if (attachment != null && event.getTargetId().equals(attachment.getAttachedTo())) { + StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); + if (sourceObject != null && filterSource.match(sourceObject, source.getControllerId(), game)) { + return true; } } return false; diff --git a/Mage/src/mage/abilities/effects/common/CantBeTargetedSourceEffect.java b/Mage/src/mage/abilities/effects/common/CantBeTargetedSourceEffect.java index e00e75831d9..f8165a0f4bc 100644 --- a/Mage/src/mage/abilities/effects/common/CantBeTargetedSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeTargetedSourceEffect.java @@ -66,10 +66,15 @@ public class CantBeTargetedSourceEffect extends ContinuousRuleModifiyingEffectIm public boolean apply(Game game, Ability source) { return true; } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGET; + } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.TARGET && event.getTargetId().equals(source.getSourceId())) { + if (event.getTargetId().equals(source.getSourceId())) { StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); if (sourceObject != null && filterSource.match(sourceObject, source.getControllerId(), game)) { return true; diff --git a/Mage/src/mage/abilities/effects/common/CantBeTargetedTargetEffect.java b/Mage/src/mage/abilities/effects/common/CantBeTargetedTargetEffect.java index a8c3c1bb1d3..f79af2655e7 100644 --- a/Mage/src/mage/abilities/effects/common/CantBeTargetedTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantBeTargetedTargetEffect.java @@ -67,9 +67,14 @@ public class CantBeTargetedTargetEffect extends ContinuousRuleModifiyingEffectIm return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGET; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.TARGET && getTargetPointer().getTargets(game, source).contains(event.getTargetId())) { + if (getTargetPointer().getTargets(game, source).contains(event.getTargetId())) { StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); if (sourceObject != null && filterSource.match(sourceObject, source.getControllerId(), game)) { return true; diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java index e9158b91f20..ebca00685af 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java @@ -42,7 +42,11 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR return null; } - + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP_STEP || event.getType() == GameEvent.EventType.UNTAP; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { // the check for turn number is needed if multiple effects are added to prevent untap in next untap step @@ -55,7 +59,7 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR return false; } // remember the turn of the untap step the effect has to be applied - if (GameEvent.EventType.UNTAP_STEP.equals(event.getType()) + if (GameEvent.EventType.UNTAP_STEP.equals(event.getType()) && game.getActivePlayerId().equals(source.getControllerId())) { if (validForTurnNum == game.getTurnNum()) { // the turn has a second untap step but the effect is already related to the first untap step discard(); diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java index 1702e81da43..356838b0a51 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java @@ -86,6 +86,11 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR } return null; } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.UNTAP_STEP || event.getType() == EventType.UNTAP; + } @Override public boolean applies(GameEvent event, Ability source, Game game) { @@ -99,7 +104,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR return false; } // remember the turn of the untap step the effect has to be applied - if (GameEvent.EventType.UNTAP_STEP.equals(event.getType())) { + if (GameEvent.EventType.UNTAP_STEP.equals(event.getType())) { UUID controllerId = null; for(UUID targetId : getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); @@ -109,17 +114,16 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR } if (controllerId == null) { // no more targets on the battlefield, effect can be discarded discard(); - return false; + return false; } - - if (game.getActivePlayerId().equals(controllerId)) { + + if (game.getActivePlayerId().equals(controllerId)) { if (validForTurnNum == game.getTurnNum()) { // the turn has a second untap step but the effect is already related to the first untap step discard(); - return false; + return false; } validForTurnNum = game.getTurnNum(); } - } if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == EventType.UNTAP) { diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java index 87561e97f3b..2b203c2222b 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java @@ -41,6 +41,7 @@ import static mage.constants.TargetController.YOU; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; @@ -76,10 +77,15 @@ public class DontUntapInControllersUntapStepAllEffect extends ContinuousRuleModi public boolean apply(Game game, Ability source) { return false; } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.UNTAP; + } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (GameEvent.EventType.UNTAP.equals(event.getType()) && PhaseStep.UNTAP.equals(game.getTurn().getStepType())) { + if (PhaseStep.UNTAP.equals(game.getTurn().getStepType())) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { switch(targetController) { diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java index 350f2601745..164ec3bced4 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java @@ -45,10 +45,14 @@ public class DontUntapInControllersUntapStepEnchantedEffect extends ContinuousRu return null; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP; + } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (GameEvent.EventType.UNTAP.equals(event.getType()) && PhaseStep.UNTAP.equals(game.getTurn().getStepType())) { + if (PhaseStep.UNTAP.equals(game.getTurn().getStepType())) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null && event.getTargetId().equals(enchantment.getAttachedTo())) { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java index f309574aa69..694098bf192 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java @@ -62,10 +62,14 @@ public class DontUntapInControllersUntapStepSourceEffect extends ContinuousRuleM return false; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.UNTAP; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getTurn().getStepType() == PhaseStep.UNTAP - && event.getType() == EventType.UNTAP && event.getTargetId().equals(source.getSourceId())) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null && permanent.getControllerId().equals(game.getActivePlayerId())) { diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepTargetEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepTargetEffect.java index 9bdcc13d543..327a85d02b1 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepTargetEffect.java @@ -38,7 +38,6 @@ import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; /** @@ -74,10 +73,15 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM } return null; } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP; + } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (GameEvent.EventType.UNTAP.equals(event.getType()) && PhaseStep.UNTAP.equals(game.getTurn().getStepType())) { + if (PhaseStep.UNTAP.equals(game.getTurn().getStepType())) { for (UUID targetId : targetPointer.getTargets(game, source)) { if (event.getTargetId().equals(targetId)) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage/src/mage/abilities/effects/common/EpicEffect.java b/Mage/src/mage/abilities/effects/common/EpicEffect.java index a161e9cc01f..325f3d3dedf 100644 --- a/Mage/src/mage/abilities/effects/common/EpicEffect.java +++ b/Mage/src/mage/abilities/effects/common/EpicEffect.java @@ -108,11 +108,15 @@ class EpicReplacementEffect extends ContinuousRuleModifiyingEffectImpl { } return null; } - + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL - && source.getControllerId() == event.getPlayerId()) { + if (source.getControllerId() == event.getPlayerId()) { MageObject object = game.getObject(event.getSourceId()); if (object != null) { return true; diff --git a/Mage/src/mage/abilities/effects/common/continious/CantCastMoreThanOneSpellEffect.java b/Mage/src/mage/abilities/effects/common/continious/CantCastMoreThanOneSpellEffect.java index 85c37b476dc..81d04070fc8 100644 --- a/Mage/src/mage/abilities/effects/common/continious/CantCastMoreThanOneSpellEffect.java +++ b/Mage/src/mage/abilities/effects/common/continious/CantCastMoreThanOneSpellEffect.java @@ -68,35 +68,38 @@ public class CantCastMoreThanOneSpellEffect extends ContinuousRuleModifiyingEffe return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL) { - switch (targetController) { - case YOU: - if (!event.getPlayerId().equals(source.getControllerId())) { - return false; - } - break; - case NOT_YOU: - if (event.getPlayerId().equals(source.getControllerId())) { - return false; - } - break; - case OPPONENT: - if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - return false; - } - break; - case CONTROLLER_ATTACHED_TO: - Permanent attachment = game.getPermanent(source.getSourceId()); - if (attachment == null || !attachment.getAttachedTo().equals(event.getPlayerId())) { - return false; - } - } - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); - if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId())> 0) { - return true; - } + switch (targetController) { + case YOU: + if (!event.getPlayerId().equals(source.getControllerId())) { + return false; + } + break; + case NOT_YOU: + if (event.getPlayerId().equals(source.getControllerId())) { + return false; + } + break; + case OPPONENT: + if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + return false; + } + break; + case CONTROLLER_ATTACHED_TO: + Permanent attachment = game.getPermanent(source.getSourceId()); + if (attachment == null || !attachment.getAttachedTo().equals(event.getPlayerId())) { + return false; + } + } + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); + if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId())> 0) { + return true; } return false; } diff --git a/Mage/src/mage/abilities/effects/common/ruleModifying/CantRegenerateTargetEffect.java b/Mage/src/mage/abilities/effects/common/ruleModifying/CantRegenerateTargetEffect.java index ba4f29177f8..ce6693c4a6c 100644 --- a/Mage/src/mage/abilities/effects/common/ruleModifying/CantRegenerateTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ruleModifying/CantRegenerateTargetEffect.java @@ -35,6 +35,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; /** * @@ -62,13 +63,16 @@ public class CantRegenerateTargetEffect extends ContinuousRuleModifiyingEffectIm return true; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.REGENERATE; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (GameEvent.EventType.REGENERATE.equals(event.getType())) { - UUID targetId = getTargetPointer().getFirst(game, source); - if (targetId != null) { - return targetId.equals(event.getTargetId()); - } + UUID targetId = getTargetPointer().getFirst(game, source); + if (targetId != null) { + return targetId.equals(event.getTargetId()); } return false; } diff --git a/Mage/src/mage/abilities/keyword/SplitSecondAbility.java b/Mage/src/mage/abilities/keyword/SplitSecondAbility.java index 8e583142db9..72bb0f8ac6e 100644 --- a/Mage/src/mage/abilities/keyword/SplitSecondAbility.java +++ b/Mage/src/mage/abilities/keyword/SplitSecondAbility.java @@ -55,6 +55,11 @@ class SplitSecondEffect extends ContinuousRuleModifiyingEffectImpl { return "You can't cast spells or activate abilities that aren't mana abilities (Split second)."; } + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL || event.getType() == GameEvent.EventType.ACTIVATE_ABILITY; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.CAST_SPELL) { From 89c8425d949fa0492ad2a476905af493ad22f257 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Jan 2015 23:43:25 +0100 Subject: [PATCH 29/34] * Fixed that replacement or rule modifying effects of cards played with morph were wrongly applied on the stack (e.g. can't be countered of Akroma, Angel of Fury). --- .../abilities/keywords/ManifestTest.java | 4 +-- .../cards/abilities/keywords/MorphTest.java | 29 +++++++++++++++ .../abilities/effects/ContinuousEffects.java | 36 +++++++++++-------- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java index 9055fc57637..f3f299705b8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java @@ -27,10 +27,8 @@ */ package org.mage.test.cards.abilities.keywords; -import mage.abilities.keyword.HexproofAbility; import mage.constants.PhaseStep; import mage.constants.Zone; -import mage.game.permanent.Permanent; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -70,5 +68,5 @@ public class ManifestTest extends CardTestPlayerBase { // not tapped assertTapped("face down creature", false); } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index f6cc00537ae..689ba24e9f7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -401,4 +401,33 @@ public class MorphTest extends CardTestPlayerBase { assertPermanentCount(playerA, "face down creature", 1); } + + /** + * I played a Akroma, Angel of Fury face down, and my opponent tried to counter it. + * The counter failed and Akroma face successfully play face down, when it should have + * been countered. (The card text on akroma should not prevent her from being countered). + */ + + @Test + public void testRuleModifyingEffectsFromManifestedCardWontBeAppliedAbilities() { + addCard(Zone.HAND, playerA, "Akroma, Angel of Fury", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + + addCard(Zone.HAND, playerB, "Counterspell", 1); + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akroma, Angel of Fury"); + setChoice(playerA, "Yes"); // cast it face down as 2/2 creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Counterspell", "Akroma, Angel of Fury"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerB, 20); + + assertGraveyardCount(playerB, "Counterspell", 1); + assertGraveyardCount(playerA, "Akroma, Angel of Fury", 1); + + } } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 220b9570a1e..2bbc85cf77b 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -67,6 +67,7 @@ import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; +import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInHand; import org.apache.log4j.Logger; @@ -416,6 +417,11 @@ public class ContinuousEffects implements Serializable { if (permanent.isFaceDown() && !ability.getWorksFaceDown()) { return false; } + } else if (object instanceof Spell) { + Spell spell = (Spell)object; + if (spell.isFaceDown() && !ability.getWorksFaceDown()) { + return false; + } } } return exists; @@ -651,24 +657,26 @@ public class ContinuousEffects implements Serializable { } for (Ability sourceAbility : continuousRuleModifyingEffects.getAbility(effect.getId())) { if (!(sourceAbility instanceof StaticAbility) || sourceAbility.isInUseableZone(game, null, false)) { - if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { - effect.setValue("targetAbility", targetAbility); - if (effect.applies(event, sourceAbility, game)) { - if (!checkPlayableMode) { - String message = effect.getInfoMessage(sourceAbility, event, game); - if (message != null && !message.isEmpty()) { - if (effect.sendMessageToUser()) { - Player player = game.getPlayer(event.getPlayerId()); - if (player != null) { - game.informPlayer(player, message); + if (checkAbilityStillExists(sourceAbility, effect, event, game)) { + if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { + effect.setValue("targetAbility", targetAbility); + if (effect.applies(event, sourceAbility, game)) { + if (!checkPlayableMode) { + String message = effect.getInfoMessage(sourceAbility, event, game); + if (message != null && !message.isEmpty()) { + if (effect.sendMessageToUser()) { + Player player = game.getPlayer(event.getPlayerId()); + if (player != null) { + game.informPlayer(player, message); + } + } + if (effect.sendMessageToGameLog()) { + game.informPlayers(message); } } - if (effect.sendMessageToGameLog()) { - game.informPlayers(message); - } } + return true; } - return true; } } } From ac0d923afdfab415171802c0983608e4d1502fb5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Jan 2015 00:05:37 +0100 Subject: [PATCH 30/34] Added one more test for manifest. --- .../abilities/keywords/ManifestTest.java | 33 ++++++++++++++++++- .../abilityword/ConstellationAbility.java | 1 - 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java index f3f299705b8..6b6b280f877 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java @@ -68,5 +68,36 @@ public class ManifestTest extends CardTestPlayerBase { // not tapped assertTapped("face down creature", false); } - + + /** + * If Doomwake Giant gets manifested, it's Constellation trigger may not trigger + */ + @Test + public void testETBTriggeredAbilities2() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // Manifest the top card of your library {1}{W} + addCard(Zone.HAND, playerA, "Soul Summons"); + + // Constellation - When Doomwake Giant or another enchantment enters the battlefield + // under your control, creatures your opponents control get -1/-1 until end of turn. + addCard(Zone.LIBRARY, playerA, "Doomwake Giant"); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Soul Summons"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + // no life gain + assertLife(playerA, 20); + assertLife(playerB, 20); + // a facedown creature is on the battlefield + assertPermanentCount(playerA, "face down creature", 1); + assertPowerToughness(playerA, "face down creature", 2, 2); + // PlayerB's Silvercoat Lion should not have get -1/-1/ + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); + } } diff --git a/Mage/src/mage/abilities/abilityword/ConstellationAbility.java b/Mage/src/mage/abilities/abilityword/ConstellationAbility.java index 7b3fc33149a..fd656686f4a 100644 --- a/Mage/src/mage/abilities/abilityword/ConstellationAbility.java +++ b/Mage/src/mage/abilities/abilityword/ConstellationAbility.java @@ -30,7 +30,6 @@ package mage.abilities.abilityword; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; -import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Zone; import mage.game.Game; From 105e12db10023ff555932c2b4618bfcf38b6f42f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Jan 2015 00:25:39 +0100 Subject: [PATCH 31/34] * Fixed AddManaOfAnyColorEffect to send TAPPED_FOR_MANA event correctly (fixed that City of Brass did not work with Heartbeat of Spring). --- Mage/src/mage/abilities/AbilityImpl.java | 2 +- .../mage/abilities/effects/common/AddManaOfAnyColorEffect.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 5a5543667b6..891e0d01edb 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -359,7 +359,7 @@ public abstract class AbilityImpl implements Ability { } else if (effect instanceof DynamicManaEffect) { mana = ((DynamicManaEffect)effect).getMana(game, this); } - if (mana != null) { // if mana == null the event has to be fires in the mana effect + if (mana != null) { // if mana == null the event has to be fired in the mana effect game.fireEvent(new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, sourceId, sourceId, controllerId, mana)); } break; diff --git a/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java b/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java index 55ff35d1703..5a080336e73 100644 --- a/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java +++ b/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java @@ -73,7 +73,7 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { if (controller.choose(outcome, choice, game)) { if (choice.getColor() == null) { - return false; // it happenes, don't know how + return false; // it happens, don't know how } Mana createdMana = null; if (choice.getColor().isBlack()) { @@ -89,6 +89,7 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { } if (createdMana != null) { controller.getManaPool().addMana(createdMana, game, source); + checkToFirePossibleEvents(createdMana, game, source); } return true; } From 24c757647efa65e7eac48f6f7cc6d2a142c96687 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Jan 2015 01:22:11 +0100 Subject: [PATCH 32/34] * Mystical Teachings - Fixed wrong tooltip text (fixes #686). --- Mage.Sets/src/mage/sets/timespiral/MysticalTeachings.java | 2 +- Mage/src/mage/game/permanent/PermanentImpl.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/timespiral/MysticalTeachings.java b/Mage.Sets/src/mage/sets/timespiral/MysticalTeachings.java index 86bbab0247d..0de1bbb8ca2 100644 --- a/Mage.Sets/src/mage/sets/timespiral/MysticalTeachings.java +++ b/Mage.Sets/src/mage/sets/timespiral/MysticalTeachings.java @@ -49,7 +49,7 @@ import mage.target.common.TargetCardInLibrary; public class MysticalTeachings extends CardImpl { - private static final FilterCard filter = new FilterCard("creature an opponent controls"); + private static final FilterCard filter = new FilterCard("an instant card or a card with flash"); static { filter.add(Predicates.or( diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 7b3692e29de..432fa0631ae 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -854,6 +855,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { //20091005 - 701.13 if (!game.replaceEvent(GameEvent.getEvent(EventType.SACRIFICE_PERMANENT, objectId, sourceId, controllerId))) { // Commander replacement effect or Rest in Peace (exile instead of graveyard) in play does not prevent successful sacrifice + // so the return value of the moveToZone is not taken into account here moveToZone(Zone.GRAVEYARD, sourceId, game, false); Player player = game.getPlayer(getControllerId()); if (player != null) { From d218279b042152f54a7703f7465877eadf93a7a9 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 22 Jan 2015 18:27:05 -0600 Subject: [PATCH 33/34] - Finally got the time to fix Manaforge Cinder. Better late than never. --- .../mage/sets/shadowmoor/ManaforgeCinder.java | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ManaforgeCinder.java b/Mage.Sets/src/mage/sets/shadowmoor/ManaforgeCinder.java index 52b766ce9b6..46d33e9ab6c 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ManaforgeCinder.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ManaforgeCinder.java @@ -27,16 +27,24 @@ */ package mage.sets.shadowmoor; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.Mana; +import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; /** * @@ -53,7 +61,7 @@ public class ManaforgeCinder extends CardImpl { this.toughness = new MageInt(1); // {1}: Add {B} or {R} to your mana pool. Activate this ability no more than three times each turn. - this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.BlackMana), new ManaCostsImpl("{1}"), 3)); + this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new ManaforgeCinderManaEffect(), new ManaCostsImpl("{1}"), 3)); } @@ -66,3 +74,55 @@ public class ManaforgeCinder extends CardImpl { return new ManaforgeCinder(this); } } + + + +class ManaforgeCinderManaEffect extends OneShotEffect { + + public ManaforgeCinderManaEffect() { + super(Outcome.PutManaInPool); + this.staticText = "Add {B} or {R} to your mana pool"; + } + + public ManaforgeCinderManaEffect(final ManaforgeCinderManaEffect effect) { + super(effect); + } + + @Override + public ManaforgeCinderManaEffect copy() { + return new ManaforgeCinderManaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Choice manaChoice = new ChoiceImpl(); + Set choices = new LinkedHashSet<>(); + choices.add("Black"); + choices.add("Red"); + manaChoice.setChoices(choices); + manaChoice.setMessage("Select black or red mana to add to your mana pool"); + Mana mana = new Mana(); + while (!controller.choose(Outcome.Benefit, manaChoice, game)) { + if (!controller.isInGame()) { + return false; + } + } + if (manaChoice.getChoice() == null) { + return false; + } + switch (manaChoice.getChoice()) { + case "Black": + mana.addBlack(); + break; + case "Red": + mana.addRed(); + break; + } + controller.getManaPool().addMana(mana, game, source); + return true; + } + return false; + } +} From ea5a7696831855e468129806ed6ed035fc1857ef Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Jan 2015 01:41:30 +0100 Subject: [PATCH 34/34] * Arcbond - Fixed that as damage source was wrongly set Arcbond instead of the targeted creature. --- Mage.Sets/src/mage/sets/fatereforged/Arcbond.java | 5 +++-- .../effects/common/DamageEverythingEffect.java | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fatereforged/Arcbond.java b/Mage.Sets/src/mage/sets/fatereforged/Arcbond.java index fd3badac385..b1b4daae98f 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/Arcbond.java +++ b/Mage.Sets/src/mage/sets/fatereforged/Arcbond.java @@ -30,6 +30,7 @@ package mage.sets.fatereforged; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -86,7 +87,7 @@ class ArcbondDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.DAMAGED_CREATURE && event.getTargetId().equals(this.getFirstTarget())) { for (Effect effect : this.getEffects()) { - effect.setValue("damage", event.getAmount()); + effect.setValue("damage", event.getAmount()); } return true; } @@ -126,7 +127,7 @@ class ArcbondEffect extends OneShotEffect { if (damage > 0) { FilterPermanent filter = new FilterCreaturePermanent("each other creature"); filter.add(Predicates.not(new PermanentIdPredicate(source.getTargets().getFirstTarget()))); - return new DamageEverythingEffect(damage, filter).apply(game, source); + return new DamageEverythingEffect(new StaticValue(damage), filter, source.getTargets().getFirstTarget()).apply(game, source); } return false; } diff --git a/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java b/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java index e45f227091e..cb5fab6149f 100644 --- a/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java +++ b/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java @@ -49,6 +49,7 @@ public class DamageEverythingEffect extends OneShotEffect { private DynamicValue amount; private FilterPermanent filter; + private UUID damageSource; public DamageEverythingEffect(int amount) { this(new StaticValue(amount), new FilterCreaturePermanent()); @@ -57,11 +58,15 @@ public class DamageEverythingEffect extends OneShotEffect { public DamageEverythingEffect(int amount, FilterPermanent filter) { this(new StaticValue(amount), filter); } - public DamageEverythingEffect(DynamicValue amount, FilterPermanent filter) { + this(amount, filter, null); + } + + public DamageEverythingEffect(DynamicValue amount, FilterPermanent filter, UUID damageSource) { super(Outcome.Damage); this.amount = amount; this.filter = filter; + this.damageSource = damageSource; staticText = "{source} deals " + amount.toString() + " damage to each " + filter.getMessage() + " and each player"; } @@ -69,6 +74,7 @@ public class DamageEverythingEffect extends OneShotEffect { super(effect); this.amount = effect.amount; this.filter = effect.filter; + this.damageSource = effect.damageSource; } @Override @@ -81,12 +87,12 @@ public class DamageEverythingEffect extends OneShotEffect { int damage = amount.calculate(game, source, this); List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game); for (Permanent permanent: permanents) { - permanent.damage(damage, source.getSourceId(), game, false, true); + permanent.damage(damage, damageSource == null ? source.getSourceId(): damageSource, game, false, true); } for (UUID playerId: game.getPlayer(source.getControllerId()).getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - player.damage(damage, source.getSourceId(), game, false, true); + player.damage(damage, damageSource == null ? source.getSourceId(): damageSource, game, false, true); } } return true;