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.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.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/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/apocalypse/UrborgUprising.java b/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java new file mode 100644 index 00000000000..3568089da48 --- /dev/null +++ b/Mage.Sets/src/mage/sets/apocalypse/UrborgUprising.java @@ -0,0 +1,65 @@ +/* + * 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"; + + // 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/arabiannights/FishliverOil.java b/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java new file mode 100644 index 00000000000..8ba0be128c6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/arabiannights/FishliverOil.java @@ -0,0 +1,77 @@ +/* + * 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.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.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +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"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + 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 GainAbilityAttachedEffect(new IslandwalkAbility(), AttachmentType.AURA, Duration.WhileOnBattlefield))); + } + + public FishliverOil(final FishliverOil card) { + super(card); + } + + @Override + public FishliverOil copy() { + return new FishliverOil(this); + } +} 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/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/coldsnap/BalduvianRage.java b/Mage.Sets/src/mage/sets/coldsnap/BalduvianRage.java new file mode 100644 index 00000000000..efeeb667132 --- /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; +import mage.filter.common.FilterAttackingCreature; + + +/** + * @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"; + + // 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(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)); + } + + public BalduvianRage(final BalduvianRage card) { + super(card); + } + + @Override + public BalduvianRage copy() { + return new BalduvianRage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java b/Mage.Sets/src/mage/sets/commander/AkromaAngelOfFury.java index 5fbae5933d5..d1df42ce6c8 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; @@ -65,12 +65,11 @@ 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); // 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/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/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/dissension/NovijenHeartOfProgress.java b/Mage.Sets/src/mage/sets/dissension/NovijenHeartOfProgress.java new file mode 100644 index 00000000000..cbc0dc7915f --- /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.MageObject; +import mage.abilities.Ability; +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.ColorlessManaAbility; +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.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @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"; + + // {T}: Add {1} to your mana pool. + this.addAbility(new ColorlessManaAbility()); + + // {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); + } + + 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) { + 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 false; + } +} \ No newline at end of file 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/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/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/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.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/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; 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/futuresight/VeilstoneAmulet.java b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java new file mode 100644 index 00000000000..b406d81ff73 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/VeilstoneAmulet.java @@ -0,0 +1,106 @@ +/* + * 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.filter.FilterSpell; +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(), new FilterSpell("a spell"), 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); + staticText = "creatures you control can't be the targets of spells or abilities your opponents control this turn"; + } + + 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()); + if (permanent != null) { + if (permanent.getCardType().contains(CardType.CREATURE) && + permanent.getControllerId().equals(ability.getControllerId()) && + game.getPlayer(ability.getControllerId()).hasOpponent(event.getPlayerId(), game)) { + return true; + } + } + } + return false; + } +} 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..b086a567d7f --- /dev/null +++ b/Mage.Sets/src/mage/sets/guildpact/InkTreaderNephilim.java @@ -0,0 +1,244 @@ +/* + * 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.Collection; +import java.util.HashMap; +import java.util.ArrayList; +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 java.util.Map; +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; + +/** + * @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.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 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); + } + } + } + } + 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 {this}, 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); + 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) { + super(effect); + } + + @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<>(); + // 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.getId()); + copy.setCopiedSpell(true); + if (permanent.getId().equals(source.getSourceId())) { + continue; // copy only for other creatures + } + boolean legal = true; + for (SpellTargetAddress addr : SpellTargetAddress.walk(copy)) { + Target targetInstance = addr.getTarget(copy); + legal &= targetInstance.canTarget(permanent.getId(), addr.getSpellAbility(copy), game); + } + if (legal) { + 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); + } + } + // controller + while (targetable.size() > 0) { + 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 choosenIds = target.getTargets(); + if (choosenIds.isEmpty()) { + choosenIds = targetable.keySet(); + } + List toDelete = new ArrayList<>(); + for (UUID chosenId : choosenIds) { + Spell chosenCopy = targetable.get(chosenId); + if (chosenCopy != null) { + game.getStack().push(chosenCopy); + toDelete.add(chosenId); + } + } + for (UUID idToDelte : toDelete) { + targetable.remove(idToDelte); + } + } + return true; + } + return false; + } + + @Override + public InkTreaderNephilimEffect copy() { + return new InkTreaderNephilimEffect(this); + } + +} 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/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/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/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/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/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/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/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); + } +} 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/ravnika/BreathOfFury.java b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java new file mode 100644 index 00000000000..341e361df3f --- /dev/null +++ b/Mage.Sets/src/mage/sets/ravnika/BreathOfFury.java @@ -0,0 +1,188 @@ +/* + * 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.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"); + + // 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 enchantment = game.getPermanent(getSourceId()); + if (damageEvent.isCombatDamage() && + enchantment != null && + enchantment.getAttachedTo().equals(event.getSourceId())) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When enchanted creature deals combat damage to a player, " + super.getRule(); + } +} + +class BreathOfFuryEffect extends OneShotEffect { + + public BreathOfFuryEffect() { + super(Outcome.Benefit); + 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) { + super(effect); + } + + @Override + public BreathOfFuryEffect copy() { + return new BreathOfFuryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source){ + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment == null) { + return false; + } + Permanent enchantedCreature = game.getPermanent(enchantment.getAttachedTo()); + Player controller = game.getPlayer(source.getControllerId()); + 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 && 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)); + + } + + } + return true; + } + return false; + } +} + +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() + ")"; + } +} 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..0773e7f478d --- /dev/null +++ b/Mage.Sets/src/mage/sets/ravnika/RallyTheRighteous.java @@ -0,0 +1,152 @@ +/* + * 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.MageObjectReference; +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"; + + // 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(getTargetPointer().getFirst(game, source)); + if (target != null) { + ObjectColor color = target.getColor(); + target.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; + } + return false; + } +} + + +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"; + } + + public RallyTheRighteousBoostEffect(final RallyTheRighteousBoostEffect effect) { + super(effect); + } + + @Override + 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 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)); + } + } + } + } + + @Override + public boolean apply(Game game, Ability source) { + for(MageObjectReference mageObjectReference :affectedObjectList) { + Permanent permanent = mageObjectReference.getPermanent(game); + if (permanent != null) { + permanent.addPower(2); + } + } + return true; + } + + @Override + public RallyTheRighteousBoostEffect copy() { + return new RallyTheRighteousBoostEffect(this); + } +} 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/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/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/scarsofmirrodin/PrecursorGolem.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PrecursorGolem.java index 55da525676f..9d56275812e 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,9 @@ 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; /** * @author nantuko @@ -122,27 +130,25 @@ 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; - } - } } } } 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; } @@ -174,16 +180,17 @@ 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) { - SpellAbility sa = spell.getSpellAbility(); 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 } 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; @@ -191,16 +198,40 @@ class PrecursorGolemCopySpellEffect extends OneShotEffect { } if (legal) { 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); } - 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 ("+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; 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/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; + } +} 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..572f93919f0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowmoor/MercyKilling.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.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.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 + */ +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"; + + // 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().addEffect(new SacrificeTargetEffect("Target creature's controller sacrifices it")); + this.getSpellAbility().addEffect(new MercyKillingTokenEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + 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 = ", 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) { + super(effect); + } + + @Override + public MercyKillingTokenEffect copy() { + return new MercyKillingTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + int power = permanent.getPower().getValue(); + return new MercyKillingToken().putOntoBattlefield(power, game, source.getSourceId(), permanent.getControllerId()); + } + return false; + } + +} + +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); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java b/Mage.Sets/src/mage/sets/shadowmoor/VexingShusher.java index 4f8e5592adc..604e9dc16ff 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()); @@ -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/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/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/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/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/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/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/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/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.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); + } +} diff --git a/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java b/Mage.Sets/src/mage/sets/worldwake/AbyssalPersecutor.java index 1986ee19cfd..b7716fb5110 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"; } @@ -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.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.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..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 @@ -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; @@ -71,4 +69,35 @@ public class ManifestTest extends CardTestPlayerBase { 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.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/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/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; 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/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..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; @@ -646,26 +652,31 @@ 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()) { - 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; } } } 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/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/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; } 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/CantCounterControlledEffect.java b/Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java similarity index 74% rename from Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java rename to Mage/src/mage/abilities/effects/common/CantBeCounteredControlledEffect.java index 93179db3392..45a6ea29b26 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 @@ -80,19 +80,22 @@ public class CantCounterControlledEffect extends ContinuousRuleModifiyingEffectI 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/CantCounterSourceEffect.java b/Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java similarity index 81% rename from Mage/src/mage/abilities/effects/common/CantCounterSourceEffect.java rename to Mage/src/mage/abilities/effects/common/CantBeCounteredSourceEffect.java index f845cc66123..56e13eb14ab 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 @@ -74,14 +74,18 @@ public class CantCounterSourceEffect extends ContinuousRuleModifiyingEffectImpl 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/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; 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) { 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/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java b/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java new file mode 100644 index 00000000000..a106b232937 --- /dev/null +++ b/Mage/src/mage/filter/predicate/mageobject/FromSetPredicate.java @@ -0,0 +1,52 @@ +/* + * 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.filter.predicate.ObjectPlayer; +import mage.filter.predicate.ObjectPlayerPredicate; +import mage.game.Controllable; +import mage.game.Game; + +/** + * @author duncancmt + */ +public class FromSetPredicate implements ObjectPlayerPredicate> { + + protected Set set; + + public FromSetPredicate(Set set) { + this.set = set; + } + + @Override + public boolean apply(ObjectPlayer input, Game game) { + return set.contains(input.getObject().getId()); + } +} 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) { diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 6d5d6abb9c5..3ee92c04d70 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; @@ -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 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); + } +} 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]);