From b397e2849c8215127a2ee78399a408a64239697d Mon Sep 17 00:00:00 2001 From: spjspj Date: Sun, 15 Jan 2017 23:33:20 +1100 Subject: [PATCH 01/13] Add missing field to userData --- Mage.Common/src/mage/view/UserView.java | 8 +++++++- Mage.Server/src/main/java/mage/server/MageServerImpl.java | 5 +++-- Mage.Server/src/main/java/mage/server/User.java | 7 +++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Mage.Common/src/mage/view/UserView.java b/Mage.Common/src/mage/view/UserView.java index e1118d32a0c..d8d5e6a1de0 100644 --- a/Mage.Common/src/mage/view/UserView.java +++ b/Mage.Common/src/mage/view/UserView.java @@ -45,8 +45,9 @@ public class UserView implements Serializable { private final String userState; private final Date muteChatUntil; private final String clientVersion; + private final String email; - public UserView(String userName, String host, String sessionId, Date timeConnected, String gameInfo, String userState, Date muteChatUntil, String clientVersion) { + public UserView(String userName, String host, String sessionId, Date timeConnected, String gameInfo, String userState, Date muteChatUntil, String clientVersion, String email) { this.userName = userName; this.host = host; this.sessionId = sessionId; @@ -55,6 +56,7 @@ public class UserView implements Serializable { this.userState = userState; this.muteChatUntil = muteChatUntil; this.clientVersion = clientVersion; + this.email = email; } public String getUserName() { @@ -88,5 +90,9 @@ public class UserView implements Serializable { public Date getTimeConnected() { return timeConnected; } + + public String getEmail() { + return email; + } } diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 827c85a7af6..70b94c0b4be 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -157,7 +157,7 @@ public class MageServerImpl implements MageServer { } return true; } - + @Override public boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException { if (!ConfigSettings.getInstance().isAuthenticationActivated()) { @@ -966,7 +966,8 @@ public class MageServerImpl implements MageServer { user.getGameInfo(), user.getUserState().toString(), user.getChatLockedUntil(), - user.getClientVersion() + user.getClientVersion(), + user.getEmail() )); } return users; diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 23469e48c07..cc0cdd5795b 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -783,6 +783,13 @@ public class User { } return number; } + + public String getEmail() { + if (authorizedUser != null) { + return authorizedUser.email; + } + return ""; + } private void updateAuthorizedUser() { if (authorizedUser != null) { From dd810f26788b8f856f02f1e7dbfd6e4916ef5e23 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 15:14:09 +0100 Subject: [PATCH 02/13] * Revolutionary Rebuff - FIxed tooltip text. --- Mage.Sets/src/mage/cards/r/RevolutionaryRebuff.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/r/RevolutionaryRebuff.java b/Mage.Sets/src/mage/cards/r/RevolutionaryRebuff.java index d2f6b0fd840..8fc0d6f6cfa 100644 --- a/Mage.Sets/src/mage/cards/r/RevolutionaryRebuff.java +++ b/Mage.Sets/src/mage/cards/r/RevolutionaryRebuff.java @@ -45,10 +45,10 @@ import mage.target.TargetSpell; public class RevolutionaryRebuff extends CardImpl { public RevolutionaryRebuff(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Counter target nonartifact spell unless its controller pays 2. - FilterSpell filter = new FilterSpell(); + FilterSpell filter = new FilterSpell("nonartifact spell"); filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); this.getSpellAbility().addTarget(new TargetSpell(filter)); this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); From 75cbfdf3b9a41cdc8a8d2f9226b37de8be87915b Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 15:22:33 +0100 Subject: [PATCH 03/13] * Some changes to EnterTheBattlefield events, some other fixes (fixes #2765). --- .../src/mage/cards/a/AdaptiveAutomaton.java | 9 +- Mage.Sets/src/mage/cards/m/MetallicMimic.java | 295 ++++++++---------- .../src/mage/cards/s/SphereOfTheSuns.java | 13 +- .../src/mage/cards/v/VanishIntoMemory.java | 67 ++-- .../cards/abilities/keywords/MeldTest.java | 6 +- .../cards/continuous/MetallicMiminTest.java | 128 ++++++++ .../base/impl/CardTestPlayerAPIImpl.java | 4 +- .../common/AsEntersBattlefieldAbility.java | 11 +- .../condition/common/MeldCondition.java | 9 +- .../effects/EntersBattlefieldEffect.java | 22 +- .../abilities/effects/common/MeldEffect.java | 9 +- .../EnterAttributeAddChosenSubtypeEffect.java | 73 +++++ .../mage/abilities/keyword/BestowAbility.java | 110 +++---- Mage/src/main/java/mage/cards/MeldCard.java | 5 +- .../java/mage/constants/EnterEventType.java | 12 + Mage/src/main/java/mage/game/GameImpl.java | 26 +- .../src/main/java/mage/game/ZonesHandler.java | 12 +- .../events/EntersTheBattlefieldEvent.java | 27 +- .../main/java/mage/game/events/GameEvent.java | 5 +- .../java/mage/game/permanent/Permanent.java | 2 + .../mage/game/permanent/PermanentCard.java | 7 + .../mage/game/permanent/PermanentImpl.java | 9 +- .../mage/game/permanent/PermanentToken.java | 6 + Mage/src/main/java/mage/game/stack/Spell.java | 14 +- 24 files changed, 562 insertions(+), 319 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/continuous/MetallicMiminTest.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java create mode 100644 Mage/src/main/java/mage/constants/EnterEventType.java diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java index b71eec19106..2cd05794a68 100644 --- a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java @@ -35,10 +35,12 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect; +import mage.abilities.effects.common.enterAttribute.EnterAttributeAddChosenSubtypeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.EnterEventType; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; @@ -61,15 +63,18 @@ public class AdaptiveAutomaton extends CardImpl { } public AdaptiveAutomaton(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add("Construct"); this.power = new MageInt(2); this.toughness = new MageInt(2); // As Adaptive Automaton enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); // Adaptive Automaton is the chosen type in addition to its other types. + AsEntersBattlefieldAbility ability = new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature), null, EnterEventType.SELF); + ability.addEffect(new EnterAttributeAddChosenSubtypeEffect()); + this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AdaptiveAutomatonAddSubtypeEffect())); // Other creatures you control of the chosen type get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllOfChosenSubtypeEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); diff --git a/Mage.Sets/src/mage/cards/m/MetallicMimic.java b/Mage.Sets/src/mage/cards/m/MetallicMimic.java index 7dad26c499f..b837e2e3b46 100644 --- a/Mage.Sets/src/mage/cards/m/MetallicMimic.java +++ b/Mage.Sets/src/mage/cards/m/MetallicMimic.java @@ -1,160 +1,135 @@ -/* - * 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.cards.m; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.ChooseCreatureTypeEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.events.EntersTheBattlefieldEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; - -/** - * - * @author Styxo - */ -public class MetallicMimic extends CardImpl { - - public MetallicMimic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); - - this.subtype.add("Shapeshifter"); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - - // As Metallic Mimic enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); - - // Metallic Mimic is the chosen type in addition to its other types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MetallicMimicEffect())); - - // Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MetallicMimicReplacementEffect())); - - } - - public MetallicMimic(final MetallicMimic card) { - super(card); - } - - @Override - public MetallicMimic copy() { - return new MetallicMimic(this); - } - - class MetallicMimicEffect extends ContinuousEffectImpl { - - public MetallicMimicEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); - staticText = "{this} is the chosen type in addition to its other types"; - } - - public MetallicMimicEffect(final MetallicMimicEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - String subtype = (String) game.getState().getValue(permanent.getId() + "_type"); - if (subtype != null && !permanent.getSubtype(game).contains(subtype)) { - permanent.getSubtype(game).add(subtype); - } - } - return true; - } - - @Override - public MetallicMimicEffect copy() { - return new MetallicMimicEffect(this); - } - } -} - -class MetallicMimicReplacementEffect extends ReplacementEffectImpl { - - MetallicMimicReplacementEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - staticText = "Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it"; - } - - MetallicMimicReplacementEffect(MetallicMimicReplacementEffect effect) { - super(effect); - } - - @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) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - Permanent enteringCreature = ((EntersTheBattlefieldEvent) event).getTarget(); - return enteringCreature != null && sourcePermanent != null - && enteringCreature.getControllerId().equals(source.getControllerId()) - && enteringCreature.getCardType().contains(CardType.CREATURE) - && enteringCreature.getSubtype(game).contains(game.getState().getValue(sourcePermanent.getId() + "_type")) - && !event.getTargetId().equals(source.getSourceId()); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); - if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); - } - return false; - } - - @Override - public MetallicMimicReplacementEffect copy() { - return new MetallicMimicReplacementEffect(this); - } -} +/* + * 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.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.enterAttribute.EnterAttributeAddChosenSubtypeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.EnterEventType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author Styxo + */ +public class MetallicMimic extends CardImpl { + + public MetallicMimic(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add("Shapeshifter"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // As Metallic Mimic enters the battlefield, choose a creature type. + AsEntersBattlefieldAbility ability = new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature), null, EnterEventType.SELF); + // Metallic Mimic is the chosen type in addition to its other types. + ability.addEffect(new EnterAttributeAddChosenSubtypeEffect()); + this.addAbility(ability); + + // Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MetallicMimicReplacementEffect())); + + } + + public MetallicMimic(final MetallicMimic card) { + super(card); + } + + @Override + public MetallicMimic copy() { + return new MetallicMimic(this); + } + +} + +class MetallicMimicReplacementEffect extends ReplacementEffectImpl { + + MetallicMimicReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it"; + setCharacterDefining(true); + } + + MetallicMimicReplacementEffect(MetallicMimicReplacementEffect effect) { + super(effect); + } + + @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) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent enteringCreature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (enteringCreature != null && sourcePermanent != null + && enteringCreature.getControllerId().equals(source.getControllerId()) + && enteringCreature.getCardType().contains(CardType.CREATURE) + && !event.getTargetId().equals(source.getSourceId())) { + String subtype = (String) game.getState().getValue(sourcePermanent.getId() + "_type"); + return subtype != null && enteringCreature.getSubtype(game).contains(subtype); + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game); + } + return false; + } + + @Override + public MetallicMimicReplacementEffect copy() { + return new MetallicMimicReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SphereOfTheSuns.java b/Mage.Sets/src/mage/cards/s/SphereOfTheSuns.java index a45157cfd63..f98a1421b10 100644 --- a/Mage.Sets/src/mage/cards/s/SphereOfTheSuns.java +++ b/Mage.Sets/src/mage/cards/s/SphereOfTheSuns.java @@ -27,7 +27,7 @@ */ package mage.cards.s; -import mage.constants.CardType; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; @@ -36,24 +36,23 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; import mage.counters.CounterType; -import java.util.UUID; - /** * * @author North, Loki, noxx */ public class SphereOfTheSuns extends CardImpl { - private static final String ruleText = "Sphere of the Suns enters the battlefield tapped and with three charge counters on it."; - + private static final String ruleText = "{this} enters the battlefield tapped and with three charge counters on it."; + public SphereOfTheSuns(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Sphere of the Suns enters the battlefield tapped and with three charge counters on it. Ability ability = new EntersBattlefieldTappedAbility(ruleText); - ((EntersBattlefieldEffect)ability.getEffects().get(0)).addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(3))); + ((EntersBattlefieldEffect) ability.getEffects().get(0)).addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(3))); this.addAbility(ability); RemoveCountersSourceCost removeCounterCost = new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()); diff --git a/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java b/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java index 67542662129..7a15df5e003 100644 --- a/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java +++ b/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java @@ -27,16 +27,21 @@ */ package mage.cards.v; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -49,6 +54,7 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTargets; /** * @@ -57,7 +63,7 @@ import mage.target.common.TargetCreaturePermanent; public class VanishIntoMemory extends CardImpl { public VanishIntoMemory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{U}"); // Exile target creature. You draw cards equal to that creature's power. // At the beginning of your next upkeep, return that card to the battlefield under its owner's control. If you do, discard cards equal to that creature's toughness. @@ -79,7 +85,7 @@ class VanishIntoMemoryEffect extends OneShotEffect { public VanishIntoMemoryEffect() { super(Outcome.Detriment); - staticText = "Exile target creature. You draw cards equal to that creature's power. At the beginning of your next upkeep, return that card to the battlefield under its owner's control. If you do, discard cards equal to that creature's toughness."; + staticText = "Exile target creature. You draw cards equal to that creature's power. At the beginning of your next upkeep, return that card to the battlefield under its owner's control. If you do, discard cards equal to that creature's toughness"; } public VanishIntoMemoryEffect(final VanishIntoMemoryEffect effect) { @@ -89,20 +95,18 @@ class VanishIntoMemoryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); - Player you = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (permanent != null && sourceObject != null) { - if (permanent.moveToExile(source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game)) { - you.drawCards(permanent.getPower().getValue(), game); + if (controller != null && permanent != null && sourceObject != null) { + if (controller.moveCardsToExile(permanent, source, game, true, source.getSourceId(), sourceObject.getIdName())) { + controller.drawCards(permanent.getPower().getValue(), game); ExileZone exile = game.getExile().getExileZone(source.getSourceId()); // only if permanent is in exile (tokens would be stop to exist) if (exile != null && !exile.isEmpty()) { - Card card = game.getCard(permanent.getId()); - if (card != null) { - //create delayed triggered ability - game.addDelayedTriggeredAbility(new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility( - new VanishIntoMemoryReturnFromExileEffect(new MageObjectReference(card, game))), source); - } + //create delayed triggered ability + Effect effect = new VanishIntoMemoryReturnFromExileEffect(); + effect.setTargetPointer(new FixedTargets(exile, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(effect), source); } return true; } @@ -118,17 +122,13 @@ class VanishIntoMemoryEffect extends OneShotEffect { class VanishIntoMemoryReturnFromExileEffect extends OneShotEffect { - MageObjectReference objectToReturn; - - public VanishIntoMemoryReturnFromExileEffect(MageObjectReference objectToReturn) { + public VanishIntoMemoryReturnFromExileEffect() { super(Outcome.PutCardInPlay); - this.objectToReturn = objectToReturn; staticText = "return that card to the battlefield under its owner's control"; } public VanishIntoMemoryReturnFromExileEffect(final VanishIntoMemoryReturnFromExileEffect effect) { super(effect); - this.objectToReturn = effect.objectToReturn; } @Override @@ -138,31 +138,30 @@ class VanishIntoMemoryReturnFromExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(objectToReturn.getSourceId()); - if (card != null && objectToReturn.refersTo(card, game)) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - game.addEffect(new VanishIntoMemoryEntersBattlefieldEffect(objectToReturn), source); - owner.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); - } + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cardsToBattlefield = new HashSet<>(); + cardsToBattlefield.addAll(cards.getCards(game)); + ContinuousEffect effect = new VanishIntoMemoryEntersBattlefieldEffect(); + effect.setTargetPointer(new FixedTargets(cards, game)); + game.addEffect(effect, source); + controller.moveCards(cardsToBattlefield, Zone.BATTLEFIELD, source, game, false, false, true, null); } + return true; } } class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl { - MageObjectReference objectToReturn; - - public VanishIntoMemoryEntersBattlefieldEffect(MageObjectReference objectToReturn) { - super(Duration.Custom, Outcome.BoostCreature); - this.objectToReturn = objectToReturn; + public VanishIntoMemoryEntersBattlefieldEffect() { + super(Duration.EndOfTurn, Outcome.Discard); staticText = "discard cards equal to that creature's toughness."; } public VanishIntoMemoryEntersBattlefieldEffect(VanishIntoMemoryEntersBattlefieldEffect effect) { super(effect); - this.objectToReturn = effect.objectToReturn; } @Override @@ -172,10 +171,7 @@ class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { - return event.getTargetId().equals(objectToReturn.getSourceId()); - } - return false; + return getTargetPointer().getTargets(game, source).contains(event.getTargetId()); } @Override @@ -186,7 +182,6 @@ class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl { if (you != null) { you.discard(permanent.getToughness().getValue(), false, source, game); } - discard(); // use only once } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MeldTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MeldTest.java index 8a1c5be48a2..234b489a2e0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MeldTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MeldTest.java @@ -127,11 +127,11 @@ public class MeldTest extends CardTestPlayerBase { // When you cast Bruna, the Fading Light, you may return target Angel or Human creature card from your graveyard to the battlefield. // Flying, Vigilance // (Melds with Gisela, the Broken Blade.) - addCard(Zone.HAND, playerA, "Bruna, the Fading Light"); // {5}{W}{W} + addCard(Zone.HAND, playerA, "Bruna, the Fading Light"); // Creature {5}{W}{W} 5/7 // Flying, First strike, Lifelink // At the beginning of your end step, if you both own and control Gisela, the Broken Blade and a // creature named Bruna, the Fading Light, exile them, then meld them into Brisela, Voice of Nightmares. - addCard(Zone.HAND, playerA, "Gisela, the Broken Blade"); // {2}{W}{W} + addCard(Zone.HAND, playerA, "Gisela, the Broken Blade"); // Creature {2}{W}{W} 4/3 // Brisela, Voice of Nightmares 9/10 // Flying, First strike, Vigilance, Lifelink // Your opponents can't cast spells with converted mana cost 3 or less. @@ -160,7 +160,7 @@ public class MeldTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Vanish into Memory", 1); assertPermanentCount(playerB, "Silvercoat Lion", 2); - assertHandCount(playerB, 0); + assertHandCount(playerB, 1); // discard 10 upkeep turn 6 ==> 0 + draw 1 at draw phase turn 6 } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MetallicMiminTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MetallicMiminTest.java new file mode 100644 index 00000000000..67c74b94e06 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MetallicMiminTest.java @@ -0,0 +1,128 @@ +/* + * 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 org.mage.test.cards.continuous; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class MetallicMiminTest extends CardTestPlayerBase { + + /** + * Additionally, if you play a Mimic naming, for example, "Dwarf", then if + * you play a second Mimic also naming "Dwarf", the second Mimic won't enter + * with a counter. Going by 616.2 in the Comp Rules, the second one should + * be getting a counter as long as you name the same type as the first one. + * + * 611.3c Continuous effects that modify characteristics of permanents do so + * simultaneously with the permanent entering the battlefield. They don’t + * wait until the permanent is on the battlefield and then change it. + * Because such effects apply as the permanent enters the battlefield, they + * are applied before determining whether the permanent will cause an + * ability to trigger when it enters the battlefield. # + * + * Example: A permanent with the static ability “All white creatures get + * +1/+1” is on the battlefield. A creature spell that would normally create + * a 1/1 white creature instead creates a 2/2 white creature. The creature + * doesn’t enter the battlefield as 1/1 and then change to 2/2. + * + */ + @Test + public void testMetallicMimic() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + // As Metallic Mimic enters the battlefield, choose a creature type. + // Metallic Mimic is the chosen type in addition to its other types. + // Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. + addCard(Zone.HAND, playerA, "Metallic Mimic", 2); // Creature {2} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Metallic Mimic"); + setChoice(playerA, "Dwarf"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Metallic Mimic"); + setChoice(playerA, "Dwarf"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Metallic Mimic", 2); + assertPowerToughness(playerA, "Metallic Mimic", 2, 1); + assertPowerToughness(playerA, "Metallic Mimic", 3, 2); + } + + @Test + public void testMetallicMimicBramblewoodParagon() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + + // As Metallic Mimic enters the battlefield, choose a creature type. + // Metallic Mimic is the chosen type in addition to its other types. + // Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. + addCard(Zone.HAND, playerA, "Metallic Mimic", 2); // Creature {2} + + // Each other Warrior creature you control enters the battlefield with an additional +1/+1 counter on it. + // Each creature you control with a +1/+1 counter on it has trample. + addCard(Zone.BATTLEFIELD, playerA, "Bramblewood Paragon", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Metallic Mimic"); + setChoice(playerA, "Warrior"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Metallic Mimic", 1); + assertPowerToughness(playerA, "Metallic Mimic", 3, 2); + } + + @Test + public void testMetallicLasts() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + + // As Metallic Mimic enters the battlefield, choose a creature type. + // Metallic Mimic is the chosen type in addition to its other types. + // Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. + addCard(Zone.HAND, playerA, "Metallic Mimic", 2); // Creature {2} + + // Flash (You may cast this spell any time you could cast an instant.) + // Each creature you control that's a Wolf or a Werewolf gets +1/+1 and has trample. + addCard(Zone.BATTLEFIELD, playerA, "Howlpack Resurgence", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Metallic Mimic"); + setChoice(playerA, "Wolf"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Metallic Mimic", 1); + assertPowerToughness(playerA, "Metallic Mimic", 3, 2); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 088da881677..c2b6e993c4e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -285,7 +285,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement if (card == null) { throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName); } - PermanentCard p = new PermanentCard(card, player.getId(), currentGame); + PermanentCard p = new PermanentCard(card.copy(), player.getId(), currentGame); p.setTapped(tapped); getBattlefieldCards(player).add(p); } @@ -466,7 +466,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement + ", cardName=" + cardName, count > 0); if (scope.equals(Filter.ComparisonScope.Any)) { - Assert.assertTrue("There is no such creature under player's control with specified power&toughness, player=" + player.getName() + Assert.assertTrue("There is no such creature under player's control with specified p/t of " + power + "/" + toughness + ", player=" + player.getName() + ", cardName=" + cardName + " (found similar: " + found + ", one of them: power=" + foundPower + " toughness=" + foundToughness + ")", fit > 0); } } diff --git a/Mage/src/main/java/mage/abilities/common/AsEntersBattlefieldAbility.java b/Mage/src/main/java/mage/abilities/common/AsEntersBattlefieldAbility.java index 7747a126d06..ca55f4a7260 100644 --- a/Mage/src/main/java/mage/abilities/common/AsEntersBattlefieldAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AsEntersBattlefieldAbility.java @@ -30,6 +30,7 @@ package mage.abilities.common; import mage.abilities.StaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.EntersBattlefieldEffect; +import mage.constants.EnterEventType; import mage.constants.Zone; /** @@ -39,14 +40,18 @@ import mage.constants.Zone; public class AsEntersBattlefieldAbility extends StaticAbility { public AsEntersBattlefieldAbility(Effect effect) { - super(Zone.ALL, new EntersBattlefieldEffect(effect)); + this(effect, null, EnterEventType.OTHER); } public AsEntersBattlefieldAbility(Effect effect, String text) { - super(Zone.ALL, new EntersBattlefieldEffect(effect, text)); + this(effect, text, EnterEventType.OTHER); } - public AsEntersBattlefieldAbility(AsEntersBattlefieldAbility ability) { + public AsEntersBattlefieldAbility(Effect effect, String text, EnterEventType enterEventType) { + super(Zone.ALL, new EntersBattlefieldEffect(effect, null, text, true, false, enterEventType)); + } + + public AsEntersBattlefieldAbility(final AsEntersBattlefieldAbility ability) { super(ability); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java index 1480a16c8a9..a757e16c27b 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -39,7 +40,6 @@ import mage.game.permanent.Permanent; * * @author emerald000 */ - public class MeldCondition implements Condition { private final String meldWithName; @@ -57,11 +57,8 @@ public class MeldCondition implements Condition { && sourcePermanent.getOwnerId().equals(source.getControllerId())) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(new NamePredicate(this.meldWithName)); - for (Permanent meldWithPermanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - if (meldWithPermanent.getOwnerId().equals(source.getControllerId())) { - return true; - } - } + filter.add(new OwnerIdPredicate(source.getControllerId())); + return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; } } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java index 549863083a8..37589a698c7 100644 --- a/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.condition.Condition; import mage.constants.Duration; +import mage.constants.EnterEventType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -50,6 +51,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { protected String text; protected Condition condition; protected boolean optional; + protected EnterEventType enterEventType; public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; @@ -66,19 +68,25 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { } public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text, boolean selfScope, boolean optional) { + this(baseEffect, condition, text, selfScope, optional, EnterEventType.OTHER); + } + + public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text, boolean selfScope, boolean optional, EnterEventType enterEventType) { super(Duration.WhileOnBattlefield, baseEffect.getOutcome(), selfScope); this.baseEffects.add(baseEffect); + this.enterEventType = enterEventType; this.text = text; this.condition = condition; this.optional = optional; } - public EntersBattlefieldEffect(EntersBattlefieldEffect effect) { + public EntersBattlefieldEffect(final EntersBattlefieldEffect effect) { super(effect); this.baseEffects = effect.baseEffects.copy(); this.text = effect.text; this.condition = effect.condition; this.optional = effect.optional; + this.enterEventType = effect.enterEventType; } public void addEffect(Effect effect) { @@ -87,7 +95,17 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return EventType.ENTERS_THE_BATTLEFIELD.equals(event.getType()); + switch (enterEventType) { + case OTHER: + return EventType.ENTERS_THE_BATTLEFIELD.equals(event.getType()); + case SELF: + return EventType.ENTERS_THE_BATTLEFIELD_SELF.equals(event.getType()); + case CONTROL: + return EventType.ENTERS_THE_BATTLEFIELD_CONTROL.equals(event.getType()); + case COPY: + return EventType.ENTERS_THE_BATTLEFIELD_COPY.equals(event.getType()); + } + return false; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java index 8a09e379994..127957787f5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common; +import java.util.HashSet; import java.util.Set; import java.util.UUID; import mage.abilities.Ability; @@ -93,8 +94,10 @@ public class MeldEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(sourceId); Permanent meldWithPermanent = game.getPermanent(meldWithId); if (sourcePermanent != null && meldWithPermanent != null) { - sourcePermanent.moveToExile(null, "", sourceId, game); - meldWithPermanent.moveToExile(null, "", sourceId, game); + Set toExile = new HashSet<>(); + toExile.add(sourcePermanent); + toExile.add(meldWithPermanent); + controller.moveCards(toExile, Zone.EXILED, source, game); // Create the meld card and move it to the battlefield. Card sourceCard = game.getExile().getCard(sourceId, game); Card meldWithCard = game.getExile().getCard(meldWithId, game); @@ -106,7 +109,7 @@ public class MeldEffect extends OneShotEffect { game.addMeldCard(meldCard.getId(), meldCard); game.getState().addCard(meldCard); meldCard.setZone(Zone.EXILED, game); - meldCard.moveToZone(Zone.BATTLEFIELD, sourceId, game, false); + controller.moveCards(meldCard, Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java new file mode 100644 index 00000000000..b5db7190aee --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.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.abilities.effects.common.enterAttribute; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect { + + public EnterAttributeAddChosenSubtypeEffect() { + super(Outcome.Benefit); + this.staticText = "{this} is the chosen type in addition to its other types"; + } + + public EnterAttributeAddChosenSubtypeEffect(final EnterAttributeAddChosenSubtypeEffect effect) { + super(effect); + } + + @Override + public EnterAttributeAddChosenSubtypeEffect copy() { + return new EnterAttributeAddChosenSubtypeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + String subtype = (String) game.getState().getValue(source.getSourceId() + "_type"); + if (permanent != null && subtype != null) { + MageObject mageObject = permanent.getBasicMageObject(game); + if (!mageObject.getSubtype(null).contains(subtype)) { + mageObject.getSubtype(null).add(subtype); + } + if (!permanent.getSubtype(null).contains(subtype)) { + permanent.getSubtype(null).add(subtype); + } + return true; + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/BestowAbility.java b/Mage/src/main/java/mage/abilities/keyword/BestowAbility.java index fffff63fb24..ab0dbd2c065 100644 --- a/Mage/src/main/java/mage/abilities/keyword/BestowAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/BestowAbility.java @@ -27,25 +27,23 @@ */ package mage.abilities.keyword; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.SourceEffect; import mage.cards.Card; -import mage.cards.repository.CardRepository; import mage.constants.CardType; -import mage.constants.DependencyType; import mage.constants.Duration; -import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SpellAbilityType; -import mage.constants.SubLayer; import mage.constants.TimingRule; 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.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -123,7 +121,7 @@ public class BestowAbility extends SpellAbility { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.addTarget(auraTarget); this.addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BestowTypeChangingEffect()); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BestowEntersBattlefieldEffect()); ability.setRuleVisible(false); addSubAbility(ability); } @@ -147,64 +145,60 @@ public class BestowAbility extends SpellAbility { return "Bestow " + getManaCostsToPay().getText() + " (If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature.)"; } - class BestowTypeChangingEffect extends ContinuousEffectImpl implements SourceEffect { - - private boolean wasAttached; - - public BestowTypeChangingEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - wasAttached = false; - dependencyTypes.add(DependencyType.AuraAddingRemoving); - } - - public BestowTypeChangingEffect(final BestowTypeChangingEffect effect) { - super(effect); - this.wasAttached = effect.wasAttached; - } - - @Override - public BestowTypeChangingEffect copy() { - return new BestowTypeChangingEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - switch (layer) { - case TypeChangingEffects_4: - if (sublayer == SubLayer.NA) { - if (permanent.getAttachedTo() == null) { - if (wasAttached && permanent.getSubtype(game).contains("Aura")) { - permanent.getSubtype(game).remove("Aura"); - wasAttached = false; - } - } else { - permanent.getCardType().remove(CardType.CREATURE); - permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes()); - if (!permanent.getSubtype(game).contains("Aura")) { - permanent.getSubtype(game).add("Aura"); - } - wasAttached = true; - } - } - break; + static public void becomeCreature(Permanent permanent, Game game) { + if (permanent != null) { + MageObject basicObject = permanent.getBasicMageObject(game); + if (basicObject != null) { + basicObject.getSubtype(null).remove("Aura"); + if (!basicObject.getCardType().contains(CardType.CREATURE)) { + basicObject.getCardType().add(CardType.CREATURE); } - return true; } - return false; - } + permanent.getSubtype(null).remove("Aura"); + if (!permanent.getCardType().contains(CardType.CREATURE)) { + permanent.getCardType().add(CardType.CREATURE); + } - @Override - public boolean apply(Game game, Ability source) { - return false; } + } +} - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.TypeChangingEffects_4; +class BestowEntersBattlefieldEffect extends ReplacementEffectImpl { + + public BestowEntersBattlefieldEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + } + + public BestowEntersBattlefieldEffect(final BestowEntersBattlefieldEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return EventType.ENTERS_THE_BATTLEFIELD_SELF.equals(event.getType()); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(source.getSourceId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent bestowPermanent = game.getPermanentEntering(source.getSourceId()); + if (bestowPermanent != null) { + if (bestowPermanent.getSubtype(game).contains("Aura")) { + MageObject basicObject = bestowPermanent.getBasicMageObject(game); + basicObject.getSubtype(null).add("Aura"); + basicObject.getCardType().remove(CardType.CREATURE); + } } + return false; + } + @Override + public BestowEntersBattlefieldEffect copy() { + return new BestowEntersBattlefieldEffect(this); } } diff --git a/Mage/src/main/java/mage/cards/MeldCard.java b/Mage/src/main/java/mage/cards/MeldCard.java index bbf2faef5d9..736dd293f2f 100644 --- a/Mage/src/main/java/mage/cards/MeldCard.java +++ b/Mage/src/main/java/mage/cards/MeldCard.java @@ -55,13 +55,13 @@ public abstract class MeldCard extends CardImpl { halves = new CardsImpl(); } - public MeldCard(MeldCard card) { + public MeldCard(final MeldCard card) { super(card); this.topHalfCard = card.topHalfCard; this.bottomHalfCard = card.bottomHalfCard; this.topLastZoneChangeCounter = card.topLastZoneChangeCounter; this.bottomLastZoneChangeCounter = card.bottomLastZoneChangeCounter; - this.halves = new CardsImpl(halves); + this.halves = new CardsImpl(card.halves); this.isMelded = card.isMelded; } @@ -211,4 +211,5 @@ public abstract class MeldCard extends CardImpl { public Cards getHalves() { return halves; } + } diff --git a/Mage/src/main/java/mage/constants/EnterEventType.java b/Mage/src/main/java/mage/constants/EnterEventType.java new file mode 100644 index 00000000000..09a5b75a92a --- /dev/null +++ b/Mage/src/main/java/mage/constants/EnterEventType.java @@ -0,0 +1,12 @@ +package mage.constants; + +/** + * + * @author LevelX2 + */ +public enum EnterEventType { + SELF, + CONTROL, + COPY, + OTHER +} diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index a17832e0ee6..68133f69edf 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -57,6 +57,7 @@ import mage.abilities.effects.ContinuousEffects; import mage.abilities.effects.Effect; import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.common.CopyEffect; +import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.MorphAbility; import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.DelayedTriggeredManaAbility; @@ -1787,7 +1788,7 @@ public abstract class GameImpl implements Game, Serializable { } } else { SpellAbility spellAbility = perm.getSpellAbility(); - if (perm.getSpellAbility().getTargets().isEmpty()) { + if (spellAbility.getTargets().isEmpty()) { for (Ability ability : perm.getAbilities(this)) { if ((ability instanceof SpellAbility) && SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType()) @@ -1810,6 +1811,7 @@ public abstract class GameImpl implements Game, Serializable { if (card != null && card.getCardType().contains(CardType.CREATURE)) { UUID wasAttachedTo = perm.getAttachedTo(); perm.attachTo(null, this); + BestowAbility.becomeCreature(perm, this); fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; @@ -2675,17 +2677,17 @@ public abstract class GameImpl implements Game, Serializable { card.setZone(Zone.GRAVEYARD, this); player.getGraveyard().add(card); } - for (PermanentCard card : battlefield) { - card.setZone(Zone.BATTLEFIELD, this); - card.setOwnerId(ownerId); - PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this); - getPermanentsEntering().put(permanent.getId(), permanent); - permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false); - getBattlefield().addPermanent(permanent); - getPermanentsEntering().remove(permanent.getId()); - permanent.removeSummoningSickness(); - if (card.isTapped()) { - permanent.setTapped(true); + for (PermanentCard permanentCard : battlefield) { + permanentCard.setZone(Zone.BATTLEFIELD, this); + permanentCard.setOwnerId(ownerId); + PermanentCard newPermanent = new PermanentCard(permanentCard.getCard(), ownerId, this); + getPermanentsEntering().put(newPermanent.getId(), newPermanent); + newPermanent.entersBattlefield(newPermanent.getId(), this, Zone.OUTSIDE, false); + getBattlefield().addPermanent(newPermanent); + getPermanentsEntering().remove(newPermanent.getId()); + newPermanent.removeSummoningSickness(); + if (permanentCard.isTapped()) { + newPermanent.setTapped(true); } } applyEffects(); diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index 427095c91bf..fc733a970b8 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -204,8 +204,7 @@ public class ZonesHandler { // If we can't find the card we can't remove it. return false; } - // If needed take attributes from the spell (e.g. color of spell was changed) - card = takeAttributesFromSpell(card, event, game); + boolean success = false; if (info.faceDown) { card.setFaceDown(true, game); @@ -213,6 +212,8 @@ public class ZonesHandler { if (!game.replaceEvent(event)) { Zone fromZone = event.getFromZone(); if (event.getToZone() == Zone.BATTLEFIELD) { + // If needed take attributes from the spell (e.g. color of spell was changed) + card = takeAttributesFromSpell(card, event, game); // controlling player can be replaced so use event player now Permanent permanent; if (card instanceof MeldCard) { @@ -232,7 +233,6 @@ public class ZonesHandler { if (info.faceDown) { card.setFaceDown(false, game); } - // make sure the controller of all continuous effects of this card are switched to the current controller game.setScopeRelevant(true); game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId()); @@ -282,16 +282,12 @@ public class ZonesHandler { } private static Card takeAttributesFromSpell(Card card, ZoneChangeEvent event, Game game) { + card = card.copy(); if (Zone.STACK.equals(event.getFromZone())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && !spell.isFaceDown(game)) { - boolean doCopy = false; if (!card.getColor(game).equals(spell.getColor(game))) { - doCopy = true; - } - if (doCopy) { // the card that is referenced to in the permanent is copied and the spell attributes are set to this copied card - card = card.copy(); card.getColor(game).setColor(spell.getColor(game)); } } diff --git a/Mage/src/main/java/mage/game/events/EntersTheBattlefieldEvent.java b/Mage/src/main/java/mage/game/events/EntersTheBattlefieldEvent.java index c4948e4b6e0..ab63ce854d9 100644 --- a/Mage/src/main/java/mage/game/events/EntersTheBattlefieldEvent.java +++ b/Mage/src/main/java/mage/game/events/EntersTheBattlefieldEvent.java @@ -24,12 +24,12 @@ * 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.game.events; -import java.util.ArrayList; import java.util.UUID; +import mage.constants.EnterEventType; +import static mage.constants.EnterEventType.SELF; import mage.constants.Zone; import mage.game.permanent.Permanent; @@ -43,17 +43,24 @@ public class EntersTheBattlefieldEvent extends GameEvent { private Permanent target; public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone) { - super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId); - this.fromZone = fromZone; - this.target = target; + this(target, sourceId, playerId, fromZone, EnterEventType.OTHER); } - public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, ArrayList appliedEffects) { + public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, EnterEventType enterType) { super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId); - this.fromZone = fromZone; - if (appliedEffects != null) { - this.appliedEffects = appliedEffects; + switch (enterType) { + case SELF: + type = EventType.ENTERS_THE_BATTLEFIELD_SELF; + break; + case CONTROL: + type = EventType.ENTERS_THE_BATTLEFIELD_CONTROL; + break; + case COPY: + type = EventType.ENTERS_THE_BATTLEFIELD_COPY; + break; } + this.fromZone = fromZone; + this.target = target; } public Zone getFromZone() { diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index a38958c2ea2..a554d276558 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -229,7 +229,10 @@ public class GameEvent implements Serializable { PAID_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP, //permanent events - ENTERS_THE_BATTLEFIELD, + ENTERS_THE_BATTLEFIELD_SELF, // 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b. + ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b + ENTERS_THE_BATTLEFIELD_COPY, // 616.1c + ENTERS_THE_BATTLEFIELD, // 616.1d TAP, TAPPED, TAPPED_FOR_MANA, UNTAP, UNTAPPED, FLIP, FLIPPED, diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 37f2a7efa2e..f4071c12148 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -149,6 +149,8 @@ public interface Permanent extends Card, Controllable { void reset(Game game); + MageObject getBasicMageObject(Game game); + boolean destroy(UUID sourceId, Game game, boolean noRegen); boolean sacrifice(UUID sourceId, Game game); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 9ff7eb7578a..c3ff27de593 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -28,6 +28,7 @@ package mage.game.permanent; import java.util.UUID; +import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; @@ -44,6 +45,7 @@ import mage.game.events.ZoneChangeEvent; public class PermanentCard extends PermanentImpl { protected int maxLevelCounters; + // A copy of the origin card that was cast (this is not the original card, so it's possible to chnage some attribute to this blueprint to change attributes to the permanent if it enters the battlefield with e.g. a subtype) protected Card card; // the number this permanent instance had protected int zoneChangeCounter; @@ -141,6 +143,11 @@ public class PermanentCard extends PermanentImpl { this.flipCardName = card.getFlipCardName(); } + @Override + public MageObject getBasicMageObject(Game game) { + return card; + } + public Card getCard() { return card; } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 23f00de9823..b8a21942091 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -59,6 +59,7 @@ import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; import mage.constants.CardType; import mage.constants.EffectType; +import mage.constants.EnterEventType; import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.Counter; @@ -872,12 +873,18 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { // remove some attributes here, because first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger MorphAbility.setPermanentToFaceDownCreature(this); } - EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone); + + EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone, EnterEventType.SELF); + if (game.replaceEvent(event)) { + return false; + } + event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone); if (!game.replaceEvent(event)) { if (fireEvent) { game.addSimultaneousEvent(event); return true; } + } return false; } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index fe51ad6c62b..c190345d9a1 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -28,6 +28,7 @@ package mage.game.permanent; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.game.Game; @@ -92,6 +93,11 @@ public class PermanentToken extends PermanentImpl { this.tokenDescriptor = token.getTokenDescriptor(); } + @Override + public MageObject getBasicMageObject(Game game) { + return token; + } + public Token getToken() { return token; } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index eedb53d704b..57a0fb74f9c 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -257,8 +257,8 @@ public class Spell extends StackObjImpl implements Card { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null && permanent instanceof PermanentCard) { permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set - ((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE); - ((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura"); + card.getCardType().add(CardType.CREATURE); + card.getSubtype(game).remove("Aura"); } } return ability.resolve(game); @@ -271,7 +271,15 @@ public class Spell extends StackObjImpl implements Card { // Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature if (this.getSpellAbility() instanceof BestowAbility) { updateOptionalCosts(0); - return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); + if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) { + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null && permanent instanceof PermanentCard) { + ((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE); + ((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura"); + return true; + } + } + return false; } else { //20091005 - 608.2b if (!game.isSimulation()) { From 97e1ebc569df0c5fc368d38bbe54349cf13cfaaf Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 15:28:49 +0100 Subject: [PATCH 04/13] * Aegis Automation - Fixed tooltip text. --- Mage.Sets/src/mage/cards/a/AegisAutomaton.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/a/AegisAutomaton.java b/Mage.Sets/src/mage/cards/a/AegisAutomaton.java index 46104e1bdd1..2f5422b4524 100644 --- a/Mage.Sets/src/mage/cards/a/AegisAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/AegisAutomaton.java @@ -47,7 +47,7 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public class AegisAutomaton extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { filter.add(new AnotherPredicate()); From 2974771cb5df0ea5623f8bd67832a5b1833d3829 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 15:41:41 +0100 Subject: [PATCH 05/13] * Lazav, Dimir Mastermind - Fixed a problem that was caused when the owner of the copied card left the game. --- .../mage/cards/l/LazavDimirMastermind.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java b/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java index 9cb8e216ae5..e3b356c8170 100644 --- a/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java +++ b/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java @@ -28,7 +28,6 @@ package mage.cards.l; import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; @@ -56,7 +55,7 @@ import mage.target.targetpointer.FixedTarget; public class LazavDimirMastermind extends CardImpl { public LazavDimirMastermind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{U}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}{B}{B}"); this.supertype.add("Legendary"); this.subtype.add("Shapeshifter"); @@ -85,7 +84,6 @@ public class LazavDimirMastermind extends CardImpl { class LazavDimirEffect extends ContinuousEffectImpl { - protected UUID IdOfCopiedCard; protected Card cardToCopy; public LazavDimirEffect() { @@ -96,7 +94,6 @@ class LazavDimirEffect extends ContinuousEffectImpl { public LazavDimirEffect(final LazavDimirEffect effect) { super(effect); this.cardToCopy = effect.cardToCopy; - this.IdOfCopiedCard = effect.IdOfCopiedCard; } @Override @@ -105,17 +102,23 @@ class LazavDimirEffect extends ContinuousEffectImpl { } @Override - public boolean apply(Game game, Ability source) { - Card card = game.getCard(((FixedTarget)getTargetPointer()).getTarget()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (card == null || permanent == null) { - discard(); - return false; - } - if (IdOfCopiedCard == null || !IdOfCopiedCard.equals(card.getId())) { - IdOfCopiedCard = card.getId(); + public void init(Ability source, Game game) { + super.init(source, game); + Card card = game.getCard(((FixedTarget) getTargetPointer()).getTarget()); + if (card != null) { cardToCopy = card.copy(); cardToCopy.assignNewId(); + } else { + discard(); + } + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + discard(); + return true; } permanent.getPower().setValue(cardToCopy.getPower().getValue()); permanent.getToughness().setValue(cardToCopy.getToughness().getValue()); From b7c0c1e8b4dc9b79e0bfde2a9024b080242012f3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 16:04:45 +0100 Subject: [PATCH 06/13] * Mindbreak Trap - Fixed a problem with exiling copied (e.g. by Storm)spells. --- .../effects/common/ExileTargetEffect.java | 4 ++-- Mage/src/main/java/mage/players/PlayerImpl.java | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java index cc0eb23cf5d..9862689e266 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java @@ -137,8 +137,8 @@ public class ExileTargetEffect extends OneShotEffect { } } else { StackObject stackObject = game.getStack().getStackObject(targetId); - if (stackObject instanceof Spell && ((Spell) stackObject).getCard() != null) { - toExile.add(((Spell) stackObject).getCard()); + if (stackObject instanceof Spell) { + toExile.add((Spell) stackObject); } } } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index f28a652e54f..70308b01bbe 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -27,6 +27,10 @@ */ package mage.players; +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; import mage.Mana; @@ -87,11 +91,6 @@ import mage.util.GameLog; import mage.util.RandomUtil; import org.apache.log4j.Logger; -import java.io.Serializable; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Map.Entry; - public abstract class PlayerImpl implements Player, Serializable { private static final Logger logger = Logger.getLogger(PlayerImpl.class); @@ -2423,7 +2422,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param ability - * @param available if null, it won't be checked if enough mana is available + * @param available if null, it won't be checked if enough mana is available * @param sourceObject * @param game * @return @@ -3229,7 +3228,7 @@ public abstract class PlayerImpl implements Player, Serializable { // identify cards from one owner Cards cards = new CardsImpl(); UUID ownerId = null; - for (Iterator it = allCards.iterator(); it.hasNext(); ) { + for (Iterator it = allCards.iterator(); it.hasNext();) { Card card = it.next(); if (cards.isEmpty()) { ownerId = card.getOwnerId(); @@ -3353,7 +3352,7 @@ public abstract class PlayerImpl implements Player, Serializable { card = basicCard; } } - game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() : "a card face down") + " " + game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + " " + (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " : "") + "to the exile zone"); } result = true; From c6c88ee1973575a93da77264b28ca1b796b4b18d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 16:21:06 +0100 Subject: [PATCH 07/13] * Chnaged some handling of transformable cards. --- Mage.Common/src/mage/view/CardView.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 01253de8bf7..3d03b865f21 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -244,7 +244,7 @@ public class CardView extends SimpleCardView { Zone cardZone = game.getState().getZone(card.getId()); if (card.isFaceDown(game)) { showFaceUp = false; - if (Zone.BATTLEFIELD!=cardZone) { + if (Zone.BATTLEFIELD != cardZone) { if (showFaceDownCard) { showFaceUp = true; } @@ -379,8 +379,9 @@ public class CardView extends SimpleCardView { this.isToken = false; } - if (card.getSecondCardFace() != null) { - this.secondCardFace = new CardView(card.getSecondCardFace()); + Card secondSideCard = card.getSecondCardFace(); + if (secondSideCard != null) { + this.secondCardFace = new CardView(secondSideCard); this.alternateName = secondCardFace.getName(); this.originalName = card.getName(); } @@ -458,7 +459,7 @@ public class CardView extends SimpleCardView { this.rarity = Rarity.NA; this.rules = new ArrayList<>(); this.rules.add(stackAbility.getRule()); - if (stackAbility.getZone()==Zone.COMMAND) { + if (stackAbility.getZone() == Zone.COMMAND) { this.expansionSetCode = stackAbility.getExpansionSetCode(); } } From bf5f3d861c7bae3b1ff6bca8fac3a2f621d1fd68 Mon Sep 17 00:00:00 2001 From: vereena42 Date: Sun, 15 Jan 2017 16:30:28 +0100 Subject: [PATCH 08/13] Fixing gen-card.pl --- Utils/gen-card.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils/gen-card.pl b/Utils/gen-card.pl index 44bf93cadaa..31a30365dc2 100755 --- a/Utils/gen-card.pl +++ b/Utils/gen-card.pl @@ -108,7 +108,7 @@ if (!exists $cards{$cardName}) { } # Check if card is already implemented -my $fileName = "../Mage.Sets/src/mage/cards/".substr($cardName, 0, 1)."/".toCamelCase($cardName).".java"; +my $fileName = "../Mage.Sets/src/mage/cards/".lc(substr($cardName, 0, 1))."/".toCamelCase($cardName).".java"; if(-e $fileName) { die "$cardName is already implemented.\n"; } From 7f7e89c2574286e6c68c5f4b9641dd68b86026ca Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 16:45:48 +0100 Subject: [PATCH 09/13] Fixed handling of some Revolt triggered abilities from AEN to intervening if clause. --- Mage.Sets/src/mage/cards/a/AirdropAeronauts.java | 11 ++++++++--- .../src/mage/cards/c/CountlessGearsRenegade.java | 15 ++++++++------- Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java | 12 +++++++----- Mage.Sets/src/mage/cards/h/HiddenHerbalists.java | 12 ++++++------ Mage.Sets/src/mage/cards/r/RenegadeRallier.java | 11 +++++++---- Mage.Sets/src/mage/cards/s/SilkweaverElite.java | 16 +++++++++------- 6 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java b/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java index b2806a5ab4a..8a87624a65e 100644 --- a/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java +++ b/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java @@ -32,11 +32,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.watchers.common.RevoltWatcher; @@ -58,8 +59,12 @@ public class AirdropAeronauts extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Revolt — When Airdrop Aeronauts enters the battlefield, if a permanent you controlled left the battlefield this turn, you gain 5 life. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new GainLifeEffect(5), RevoltCondition.getInstance()), false, "Revolt — "); + Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new GainLifeEffect(5), false), RevoltCondition.getInstance(), + "Revolt — When {this} enters the battlefield, if a permanent you controlled left" + + " the battlefield this turn, you gain 5 life." + ); + ability.setAbilityWord(AbilityWord.REVOLT); this.addAbility(ability, new RevoltWatcher()); } diff --git a/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java b/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java index afa170bb53d..7c11d16303f 100644 --- a/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java +++ b/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java @@ -25,23 +25,22 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.c; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.game.permanent.token.ServoToken; import mage.watchers.common.RevoltWatcher; -import java.util.UUID; - /** * @author JRHerlehy */ @@ -57,9 +56,11 @@ public class CountlessGearsRenegade extends CardImpl { // Revolt — When Countless Gears Renegade enters the battlefield, if a permanent you controlled // left the battlefield this turn, create a 1/1 colorless Servo artifact creature token. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new CreateTokenEffect(new ServoToken(), 1), RevoltCondition.getInstance()), - false, "Revolt — "); + Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new ServoToken(), 1), false), RevoltCondition.getInstance(), + "Revolt — When {this} enters the battlefield, if a permanent you controlled left" + + " the battlefield this turn, create a 1/1 colorless Servo artifact creature token."); + ability.setAbilityWord(AbilityWord.REVOLT); ability.addWatcher(new RevoltWatcher()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java b/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java index 9bfaaa6996c..bf07e3ace78 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java @@ -32,10 +32,11 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; @@ -63,11 +64,12 @@ public class DeadeyeHarpooner extends CardImpl { this.toughness = new MageInt(2); // Revolt — When Deadeye Harpooner enters the battlefield, if a permanent you controlled left the battlefield this turn, destroy target tapped creature an opponent controls. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new DestroyTargetEffect(), RevoltCondition.getInstance()), - false, - "Revolt — " + Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new DestroyTargetEffect(), false), RevoltCondition.getInstance(), + "Revolt — When {this} enters the battlefield, if a permanent you controlled left" + + " the battlefield this turn, destroy target tapped creature an opponent controls." ); + ability.setAbilityWord(AbilityWord.REVOLT); ability.addTarget(new TargetOpponentsCreaturePermanent(filter)); ability.addWatcher(new RevoltWatcher()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HiddenHerbalists.java b/Mage.Sets/src/mage/cards/h/HiddenHerbalists.java index 616480f3545..b3aadebfaef 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenHerbalists.java +++ b/Mage.Sets/src/mage/cards/h/HiddenHerbalists.java @@ -32,7 +32,7 @@ import mage.MageInt; import mage.Mana; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.BasicManaEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -53,12 +53,12 @@ public class HiddenHerbalists extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // Revolt &mdash When Hidden Herbalists enters the battlefield, if a permanent you controlled left the battlefield this turn add {G}{G} to your mana pool; + // Revolt &mdash When Hidden Herbalists enters the battlefield, if a permanent you controlled left the battlefield this turn, add {G}{G} to your mana pool; this.addAbility( - new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new BasicManaEffect(Mana.GreenMana(2)), RevoltCondition.getInstance()), - false, - "Revolt — "), + new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new BasicManaEffect(Mana.GreenMana(2)), false), RevoltCondition.getInstance(), + "Revolt — When {this} enters the battlefield, if a permanent you controlled left" + + " the battlefield this turn, add {G}{G} to your mana pool."), new RevoltWatcher() ); } diff --git a/Mage.Sets/src/mage/cards/r/RenegadeRallier.java b/Mage.Sets/src/mage/cards/r/RenegadeRallier.java index 6d72e819084..d36dda229aa 100644 --- a/Mage.Sets/src/mage/cards/r/RenegadeRallier.java +++ b/Mage.Sets/src/mage/cards/r/RenegadeRallier.java @@ -32,10 +32,11 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.filter.Filter; import mage.filter.common.FilterPermanentCard; @@ -65,9 +66,11 @@ public class RenegadeRallier extends CardImpl { // Revolt — When Renegade Rallier enters the battlefield, if a permanent you controlled left the battlefield this turn, // return target permanent card with converted mana cost 2 or less from your graveyard to your battlefield. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new ReturnFromGraveyardToBattlefieldTargetEffect(), RevoltCondition.getInstance()), - false, "Revolt — "); + Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), false), RevoltCondition.getInstance(), + "Revolt — When {this} enters the battlefield, if a permanent you controlled left" + + " the battlefield this turn, return target permanent card with converted mana cost 2 or less from your graveyard to your battlefield."); + ability.setAbilityWord(AbilityWord.REVOLT); ability.addTarget(new TargetCardInYourGraveyard(filter)); ability.addWatcher(new RevoltWatcher()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SilkweaverElite.java b/Mage.Sets/src/mage/cards/s/SilkweaverElite.java index 53f4cd304e8..f3696e1f723 100644 --- a/Mage.Sets/src/mage/cards/s/SilkweaverElite.java +++ b/Mage.Sets/src/mage/cards/s/SilkweaverElite.java @@ -25,23 +25,22 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.s; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.watchers.common.RevoltWatcher; -import java.util.UUID; - /** * @author JRHerlehy */ @@ -59,11 +58,14 @@ public class SilkweaverElite extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Revolt — When Silkweaver Elite enters the battlefield, if a permanent you controlled left the battlefield this turn, draw a card. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), RevoltCondition.getInstance()), - false, "Revolt — "); + Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1), false), RevoltCondition.getInstance(), + "Revolt — When {this} enters the battlefield, if a permanent you controlled left" + + " the battlefield this turn, draw a card."); + ability.setAbilityWord(AbilityWord.REVOLT); ability.addWatcher(new RevoltWatcher()); this.addAbility(ability); + } public SilkweaverElite(final SilkweaverElite card) { From 6625bf86bec4a9ea8c394015f9f8fe7aa61bdb94 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 15 Jan 2017 17:44:02 +0100 Subject: [PATCH 10/13] Xmage 1.4.21V0 --- Mage.Client/pom.xml | 2 +- Mage.Common/pom.xml | 2 +- Mage.Common/src/mage/utils/MageVersion.java | 2 +- Mage.Plugins/Mage.Counter.Plugin/pom.xml | 2 +- Mage.Plugins/pom.xml | 2 +- Mage.Server.Console/pom.xml | 2 +- Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml | 2 +- Mage.Server.Plugins/Mage.Deck.Limited/pom.xml | 2 +- Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml | 2 +- Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml | 2 +- Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml | 2 +- Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml | 2 +- Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml | 2 +- Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml | 2 +- Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml | 2 +- Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml | 2 +- Mage.Server.Plugins/Mage.Player.AI/pom.xml | 2 +- Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml | 2 +- Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml | 2 +- Mage.Server.Plugins/Mage.Player.Human/pom.xml | 2 +- Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml | 2 +- Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml | 2 +- Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml | 2 +- Mage.Server.Plugins/pom.xml | 2 +- Mage.Server/pom.xml | 2 +- Mage.Sets/pom.xml | 2 +- Mage.Stats/pom.xml | 2 +- Mage.Tests/pom.xml | 2 +- Mage.Updater/pom.xml | 2 +- Mage.Verify/pom.xml | 2 +- Mage/pom.xml | 2 +- Mage/src/main/java/mage/cards/repository/CardRepository.java | 2 +- pom.xml | 4 ++-- 33 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index 818f319f927..bf98878f842 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 org.mage diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index e82a698d932..feb4b9b013a 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage-common diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index c90c6912cbe..33185a3fd3e 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -40,7 +40,7 @@ public class MageVersion implements Serializable, Comparable { */ public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; - public final static int MAGE_VERSION_PATCH = 20; + public final static int MAGE_VERSION_PATCH = 21; public final static String MAGE_VERSION_MINOR_PATCH = "V0"; public final static String MAGE_VERSION_INFO = ""; diff --git a/Mage.Plugins/Mage.Counter.Plugin/pom.xml b/Mage.Plugins/Mage.Counter.Plugin/pom.xml index 14c592301c1..3ac80e4339e 100644 --- a/Mage.Plugins/Mage.Counter.Plugin/pom.xml +++ b/Mage.Plugins/Mage.Counter.Plugin/pom.xml @@ -7,7 +7,7 @@ org.mage mage-plugins - 1.4.20 + 1.4.21 mage-counter-plugin diff --git a/Mage.Plugins/pom.xml b/Mage.Plugins/pom.xml index d3103062fbc..e78d03456d1 100644 --- a/Mage.Plugins/pom.xml +++ b/Mage.Plugins/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage-plugins diff --git a/Mage.Server.Console/pom.xml b/Mage.Server.Console/pom.xml index 0beffafde59..fed6ebec66e 100644 --- a/Mage.Server.Console/pom.xml +++ b/Mage.Server.Console/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 org.mage diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml index f0bf68970d3..1a12447c96e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-deck-constructed diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml index 0af678370fc..ceb0213d67b 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-deck-limited diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml index 4f11eea8c43..0ee36bf21e3 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-game-commanderduel diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml index 3e20eb3e960..dee41279516 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-game-commanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml index 3a8f95b6961..d44ee03a052 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-game-freeforall diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml index b7c46693585..65abbf56745 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-game-momirduel diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml index 48a4f3ac524..e088bb47b88 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-game-tinyleadersduel diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml index bb729f5ee93..df364bcfec5 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-game-twoplayerduel diff --git a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml index f55a49adc42..fa651388a71 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-player-ai-draftbot diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml index 791a6036cf0..32cab1a21de 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-player-ai-ma diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index 53c235c45f5..e7cc0f5e5de 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-player-ai diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml index 2ff383a06bd..05077c65e2e 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-player-ai-mcts diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml index ea6281b6747..a707d24b995 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-player-aiminimax diff --git a/Mage.Server.Plugins/Mage.Player.Human/pom.xml b/Mage.Server.Plugins/Mage.Player.Human/pom.xml index 9973b7c2d83..c3161f80753 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.Human/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-player-human diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml index 9f1bf92794c..59d38af82d7 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-tournament-boosterdraft diff --git a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml index 0f0513588a6..a4dbfc5f2d5 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-tournament-constructed diff --git a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml index db716440c0f..4acdc3f9b1e 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.20 + 1.4.21 mage-tournament-sealed diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index a56b5b66803..fa315738557 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage-server-plugins diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 7aa1add141e..8815a14850e 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage-server diff --git a/Mage.Sets/pom.xml b/Mage.Sets/pom.xml index 18096ae963a..f6bd1c16b29 100644 --- a/Mage.Sets/pom.xml +++ b/Mage.Sets/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 org.mage diff --git a/Mage.Stats/pom.xml b/Mage.Stats/pom.xml index 12091c9ccd1..395490b6a91 100644 --- a/Mage.Stats/pom.xml +++ b/Mage.Stats/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 org.mage diff --git a/Mage.Tests/pom.xml b/Mage.Tests/pom.xml index 2ea14d0ee4e..f01a540b853 100644 --- a/Mage.Tests/pom.xml +++ b/Mage.Tests/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage-tests diff --git a/Mage.Updater/pom.xml b/Mage.Updater/pom.xml index a32ecc03324..e96d35a3ae2 100644 --- a/Mage.Updater/pom.xml +++ b/Mage.Updater/pom.xml @@ -5,7 +5,7 @@ mage-root org.mage - 1.4.20 + 1.4.21 4.0.0 diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml index 649f089e9f1..84da9888ae8 100644 --- a/Mage.Verify/pom.xml +++ b/Mage.Verify/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage-verify diff --git a/Mage/pom.xml b/Mage/pom.xml index 481427be7eb..06cde611e36 100644 --- a/Mage/pom.xml +++ b/Mage/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 mage diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index e0b8a494958..41d39928c75 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -60,7 +60,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 50; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 67; + private static final long CARD_CONTENT_VERSION = 68; private final TreeSet landTypes = new TreeSet(); private Dao cardDao; private Set classNames; diff --git a/pom.xml b/pom.xml index 86548cf48cd..1c643d77939 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.20 + 1.4.21 pom Mage Root Mage Root POM @@ -84,7 +84,7 @@ - 1.4.20 + 1.4.21 UTF-8 From 9adabf31eb6d057985d9005193506b35c00a4c93 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 16 Jan 2017 21:01:52 +0100 Subject: [PATCH 11/13] * Archive Trap - Fixed that wrongly also searches of other player'S library were taken into account. --- Mage.Sets/src/mage/cards/a/ArchiveTrap.java | 29 ++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/ArchiveTrap.java b/Mage.Sets/src/mage/cards/a/ArchiveTrap.java index 1c9c1f43313..924278348e7 100644 --- a/Mage.Sets/src/mage/cards/a/ArchiveTrap.java +++ b/Mage.Sets/src/mage/cards/a/ArchiveTrap.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.a; import java.util.HashSet; @@ -53,16 +52,16 @@ import mage.watchers.Watcher; public class ArchiveTrap extends CardImpl { public ArchiveTrap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); + this.subtype.add("Trap"); // If an opponent searched his or her library this turn, you may pay {0} rather than pay Archive Trap's mana cost. this.addAbility(new AlternativeCostSourceAbility(new GenericManaCost(0), OpponentSearchesLibCondition.getInstance()), new ArchiveTrapWatcher()); - + // Target opponent puts the top thirteen cards of his or her library into his or her graveyard. this.getSpellAbility().addTarget(new TargetOpponent()); - this.getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(13)); + this.getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(13)); } public ArchiveTrap(final ArchiveTrap card) { @@ -78,7 +77,7 @@ public class ArchiveTrap extends CardImpl { class ArchiveTrapWatcher extends Watcher { Set playerIds = new HashSet<>(); - + public ArchiveTrapWatcher() { super("LibrarySearched", WatcherScope.GAME); } @@ -95,7 +94,8 @@ class ArchiveTrapWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == EventType.LIBRARY_SEARCHED) { + if (event.getType() == EventType.LIBRARY_SEARCHED + && event.getTargetId().equals(event.getPlayerId())) { // player searched own library playerIds.add(event.getPlayerId()); } } @@ -106,7 +106,6 @@ class ArchiveTrapWatcher extends Watcher { playerIds.clear(); } - public Set getPlayersSearchedLibrary() { return playerIds; } @@ -115,7 +114,7 @@ class ArchiveTrapWatcher extends Watcher { class OpponentSearchesLibCondition implements Condition { private static final OpponentSearchesLibCondition fInstance = new OpponentSearchesLibCondition(); - + public static Condition getInstance() { return fInstance; } @@ -138,5 +137,5 @@ class OpponentSearchesLibCondition implements Condition { public String toString() { return "If an opponent searched his or her library this turn"; } - + } From 6d0eb49ac8a4b840a49b4930fd89f53194845edb Mon Sep 17 00:00:00 2001 From: fireshoes Date: Mon, 16 Jan 2017 21:14:05 -0600 Subject: [PATCH 12/13] Winding Constrictor oracle text update --- Mage.Sets/src/mage/cards/w/WindingConstrictor.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/w/WindingConstrictor.java b/Mage.Sets/src/mage/cards/w/WindingConstrictor.java index a8d5f015610..5d649a3cca6 100644 --- a/Mage.Sets/src/mage/cards/w/WindingConstrictor.java +++ b/Mage.Sets/src/mage/cards/w/WindingConstrictor.java @@ -56,9 +56,10 @@ public class WindingConstrictor extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - // If one or more counters would be placed on an artifact or creature you control, that many of those counters plus one are placed on that permanent instead. + // If one or more counters would be placed on an artifact or creature you control, that many plus one of each of those kinds of counters are placed on that permanent instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WindingConstrictorPermanentEffect())); - // If you would get one or more counters, you get that many of those counters plus one instead. + + // If you would get one or more counters, you get that many plus one of each of those kinds of counters instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WindingConstrictorPlayerEffect())); } @@ -76,7 +77,8 @@ class WindingConstrictorPermanentEffect extends ReplacementEffectImpl { WindingConstrictorPermanentEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); - staticText = "If one or more counters would be placed on an artifact or creature you control, that many of those counters plus one are placed on that permanent instead"; + staticText = "If one or more counters would be placed on an artifact or creature you control, " + + "that many plus one of each of those kinds of counters are placed on that permanent instead"; } WindingConstrictorPermanentEffect(final WindingConstrictorPermanentEffect effect) { @@ -120,7 +122,7 @@ class WindingConstrictorPlayerEffect extends ReplacementEffectImpl { WindingConstrictorPlayerEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); - staticText = "If you would get one or more counters, you get that many of those counters plus one instead"; + staticText = "If you would get one or more counters, you get that many plus one of each of those kinds of counters instead"; } WindingConstrictorPlayerEffect(final WindingConstrictorPlayerEffect effect) { From d690926cef56fef0e925638d79346d002d67e565 Mon Sep 17 00:00:00 2001 From: Styxo Date: Wed, 18 Jan 2017 14:25:58 +0100 Subject: [PATCH 13/13] [AER] Refactored some similar abilities and effects --- .../src/mage/cards/a/AjaniUnyielding.java | 8 +- .../mage/cards/b/BaralChiefOfCompliance.java | 48 +------- .../src/mage/cards/c/ChandrasRevolution.java | 12 +- .../src/mage/cards/c/ChordOfCalling.java | 63 +---------- .../mage/cards/e/EfficientConstruction.java | 4 +- .../src/mage/cards/f/FelidarGuardian.java | 8 +- .../src/mage/cards/g/GreenSunsZenith.java | 73 +++--------- .../src/mage/cards/g/GremlinInfestation.java | 19 +--- .../src/mage/cards/l/LullmageMentor.java | 107 +----------------- Mage.Sets/src/mage/cards/o/OathOfAjani.java | 7 +- Mage.Sets/src/mage/cards/p/ParadoxEngine.java | 7 +- Mage.Sets/src/mage/cards/p/PlanarBridge.java | 7 +- .../src/mage/cards/r/ReleaseTheGremlins.java | 15 +-- Mage.Sets/src/mage/cards/r/RenegadeMap.java | 8 +- Mage.Sets/src/mage/cards/r/Reshape.java | 72 ++---------- .../src/mage/cards/s/SalvageScuttler.java | 47 +------- .../src/mage/cards/s/SlyRequisitioner.java | 9 +- Mage.Sets/src/mage/cards/s/SolemnRecruit.java | 14 ++- .../src/mage/cards/s/SwordsToPlowshares.java | 8 +- Mage.Sets/src/mage/cards/t/TrophyMage.java | 5 +- Mage.Sets/src/mage/cards/v/VengefulRebel.java | 16 +-- Mage.Sets/src/mage/cards/w/Wargate.java | 55 +-------- .../src/mage/cards/w/WeldfastEngineer.java | 8 +- .../src/mage/cards/w/WhirOfInvention.java | 61 +--------- .../mage/cards/y/YahenniUndyingPartisan.java | 20 ++-- ...llCounteredControllerTriggeredAbility.java | 62 ++++++++++ .../common/SwordsToPlowsharesEffect.java | 7 +- ...archLibraryWithLessCMCPutInPlayEffect.java | 90 +++++++++++++++ .../game/permanent/token/GremlinToken.java | 48 ++++++++ 29 files changed, 312 insertions(+), 596 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/GremlinToken.java diff --git a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java index c601b0fea71..ab908ea712a 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java +++ b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java @@ -29,7 +29,6 @@ package mage.cards.a; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; -import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect; import mage.abilities.effects.common.SwordsToPlowsharesEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; @@ -38,7 +37,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterPermanentCard; import mage.filter.common.FilterPlaneswalkerPermanent; import mage.filter.predicate.Predicates; @@ -49,6 +47,7 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; /** * @author JRHerlehy @@ -56,12 +55,10 @@ import mage.constants.Zone; public class AjaniUnyielding extends CardImpl { private static final FilterPermanentCard nonlandPermanentFilter = new FilterPermanentCard("nonland permanent cards"); - private static final FilterCreaturePermanent creatureFilter = new FilterCreaturePermanent("creature you control"); private static final FilterPlaneswalkerPermanent planeswalkerFilter = new FilterPlaneswalkerPermanent("other planeswalker you control"); static { nonlandPermanentFilter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); - creatureFilter.add(new ControllerPredicate(TargetController.YOU)); planeswalkerFilter.add(new ControllerPredicate(TargetController.YOU)); planeswalkerFilter.add(new AnotherPredicate()); } @@ -77,12 +74,11 @@ public class AjaniUnyielding extends CardImpl { // -2: Exile target creature. Its controller gains life equal to its power. LoyaltyAbility ajaniAbility2 = new LoyaltyAbility(new SwordsToPlowsharesEffect(), -2); - ajaniAbility2.addEffect(new ExileTargetEffect()); ajaniAbility2.addTarget(new TargetCreaturePermanent()); this.addAbility(ajaniAbility2); // -9: Put five +1/+1 counters on each creature you control and five loyalty counters on each other planeswalker you control. - LoyaltyAbility ajaniAbility3 = new LoyaltyAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(5), creatureFilter), -9); + LoyaltyAbility ajaniAbility3 = new LoyaltyAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(5), new FilterControlledCreaturePermanent()), -9); ajaniAbility3.addEffect(new AddCountersAllEffect(CounterType.LOYALTY.createInstance(5), planeswalkerFilter)); this.addAbility(ajaniAbility3); } diff --git a/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java b/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java index 4ef4168d43b..c314cb69d42 100644 --- a/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java +++ b/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java @@ -29,8 +29,8 @@ package mage.cards.b; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCounteredControllerTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.cards.CardImpl; @@ -40,11 +40,6 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; /** * @@ -74,7 +69,7 @@ public class BaralChiefOfCompliance extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 1))); // Whenever a spell or ability you control counters a spell, you may draw a card. If you do, discard a card. - this.addAbility(new BaralChiefOfComplianceTriggeredAbility()); + this.addAbility(new SpellCounteredControllerTriggeredAbility(new DrawDiscardControllerEffect(), true)); } public BaralChiefOfCompliance(final BaralChiefOfCompliance card) { @@ -86,42 +81,3 @@ public class BaralChiefOfCompliance extends CardImpl { return new BaralChiefOfCompliance(this); } } - -class BaralChiefOfComplianceTriggeredAbility extends TriggeredAbilityImpl { - - public BaralChiefOfComplianceTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), true); - } - - public BaralChiefOfComplianceTriggeredAbility(final BaralChiefOfComplianceTriggeredAbility ability) { - super(ability); - } - - @Override - public BaralChiefOfComplianceTriggeredAbility copy() { - return new BaralChiefOfComplianceTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.COUNTERED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - StackObject stackObjectThatCountered = (StackObject) game.getStack().getStackObject(event.getSourceId()); - if (stackObjectThatCountered == null) { - stackObjectThatCountered = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK); - } - if (stackObjectThatCountered != null && stackObjectThatCountered.getControllerId().equals(getControllerId())) { - StackObject counteredStackObject = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK); - return counteredStackObject != null && (counteredStackObject instanceof Spell); - } - return false; - } - - @Override - public String getRule() { - return "Whenever a spell or ability you control counters a spell, " + super.getRule(); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChandrasRevolution.java b/Mage.Sets/src/mage/cards/c/ChandrasRevolution.java index 36facecd20b..7099c2b18ee 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasRevolution.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasRevolution.java @@ -36,10 +36,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetLandPermanent; import mage.target.targetpointer.FixedTarget; @@ -53,13 +51,9 @@ public class ChandrasRevolution extends CardImpl { public ChandrasRevolution(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); - // Chandra's Revolution deals 4 damage to target creature. - Target target = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(target); - - // Tap target land. That land doesn't untap during its controller's next untap step. - Target target2 = new TargetLandPermanent(new FilterLandPermanent()); - this.getSpellAbility().addTarget(target2); + // Chandra's Revolution deals 4 damage to target creature. Tap target land. That land doesn't untap during its controller's next untap step. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetLandPermanent()); this.getSpellAbility().addEffect(new ChandrasRevolutionEffect()); } diff --git a/Mage.Sets/src/mage/cards/c/ChordOfCalling.java b/Mage.Sets/src/mage/cards/c/ChordOfCalling.java index b1e87f3c7d1..bd3263ae9c4 100644 --- a/Mage.Sets/src/mage/cards/c/ChordOfCalling.java +++ b/Mage.Sets/src/mage/cards/c/ChordOfCalling.java @@ -28,22 +28,12 @@ package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryWithLessCMCPutInPlayEffect; import mage.abilities.keyword.ConvokeAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.Filter; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; +import mage.filter.common.FilterCreatureCard; /** * @@ -52,13 +42,13 @@ import mage.target.common.TargetCardInLibrary; public class ChordOfCalling extends CardImpl { public ChordOfCalling(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}{G}{G}"); // Convoke (Your creatures can help cast this spell. Each creature you tap while casting this spell pays for {1} or one mana of that creature's color.) this.addAbility(new ConvokeAbility()); // Search your library for a creature card with converted mana cost X or less and put it onto the battlefield. Then shuffle your library. - this.getSpellAbility().addEffect(new ChordofCallingSearchEffect()); + this.getSpellAbility().addEffect(new SearchLibraryWithLessCMCPutInPlayEffect(new FilterCreatureCard())); } public ChordOfCalling(final ChordOfCalling card) { @@ -70,48 +60,3 @@ public class ChordOfCalling extends CardImpl { return new ChordOfCalling(this); } } - -class ChordofCallingSearchEffect extends OneShotEffect { - - ChordofCallingSearchEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Search your library for a creature card with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; - } - - ChordofCallingSearchEffect(final ChordofCallingSearchEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (player == null || sourceCard == null) { - return false; - } - int xCost = source.getManaCostsToPay().getX(); - FilterCard filter = new FilterCard(new StringBuilder("creature card with converted mana cost ").append(xCost).append(" or less").toString()); - filter.add(new CardTypePredicate(CardType.CREATURE)); - //Set the mana cost one higher to 'emulate' a less than or equal to comparison. - filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, xCost + 1)); - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (player.searchLibrary(target, game)) { - if (target.getTargets().size() > 0) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": Put ").append(card.getName()).append(" onto the battlefield").toString()); - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); - } - } - player.shuffleLibrary(source, game); - return true; - } - player.shuffleLibrary(source, game); - return false; - } - - @Override - public ChordofCallingSearchEffect copy() { - return new ChordofCallingSearchEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EfficientConstruction.java b/Mage.Sets/src/mage/cards/e/EfficientConstruction.java index dd6d4423a7e..fd2e6addb8f 100644 --- a/Mage.Sets/src/mage/cards/e/EfficientConstruction.java +++ b/Mage.Sets/src/mage/cards/e/EfficientConstruction.java @@ -42,13 +42,11 @@ import mage.game.permanent.token.ThopterColorlessToken; */ public class EfficientConstruction extends CardImpl { - private static final FilterArtifactSpell filter = new FilterArtifactSpell("an artifact spell"); - public EfficientConstruction(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); // Whenever you cast an artifact spell, create a 1/1 colorless Thopter artifact creature token with flying. - this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken()), filter, false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken()), new FilterArtifactSpell("an artifact spell"), false)); } public EfficientConstruction(final EfficientConstruction card) { diff --git a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java index 39693e481e0..2cb2214b319 100644 --- a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java +++ b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java @@ -47,6 +47,12 @@ import mage.target.common.TargetControlledPermanent; */ public class FelidarGuardian extends CardImpl { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("another target permanent you control"); + + static { + filter.add(new AnotherPredicate()); + } + public FelidarGuardian(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); @@ -60,8 +66,6 @@ public class FelidarGuardian extends CardImpl { effect.setApplyEffectsAfter(); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true)); - FilterControlledPermanent filter = new FilterControlledPermanent("another target permanent you control"); - filter.add(new AnotherPredicate()); ability.addTarget(new TargetControlledPermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GreenSunsZenith.java b/Mage.Sets/src/mage/cards/g/GreenSunsZenith.java index 50e66653ac5..2c98d38df55 100644 --- a/Mage.Sets/src/mage/cards/g/GreenSunsZenith.java +++ b/Mage.Sets/src/mage/cards/g/GreenSunsZenith.java @@ -29,36 +29,34 @@ package mage.cards.g; import java.util.UUID; import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ShuffleSpellEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryWithLessCMCPutInPlayEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; /** * @author Loki */ public class GreenSunsZenith extends CardImpl { - public GreenSunsZenith(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{G}"); + private static final FilterCard filter = new FilterCard("green creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public GreenSunsZenith(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}"); + + // Search your library for a green creature card with converted mana cost X or less, put it onto the battlefield, then shuffle your library. + this.getSpellAbility().addEffect(new SearchLibraryWithLessCMCPutInPlayEffect(filter)); - // Search your library for a green creature card with converted mana cost X or less, - // put it onto the battlefield, then shuffle your library. // Shuffle Green Sun's Zenith into its owner's library. - this.getSpellAbility().addEffect(new GreenSunsZenithSearchEffect()); this.getSpellAbility().addEffect(ShuffleSpellEffect.getInstance()); } @@ -72,48 +70,3 @@ public class GreenSunsZenith extends CardImpl { } } - -class GreenSunsZenithSearchEffect extends OneShotEffect { - - GreenSunsZenithSearchEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Search your library for a green creature card with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; - } - - GreenSunsZenithSearchEffect(final GreenSunsZenithSearchEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - //Set the mana cost one higher to 'emulate' a less than or equal to comparison. - int xValue = source.getManaCostsToPay().getX() + 1; - FilterCard filter = new FilterCard("green creature card with converted mana cost " + xValue + " or less"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, xValue)); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { - if (target.getTargets().size() > 0) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - controller.shuffleLibrary(source, game); - return true; - } - controller.shuffleLibrary(source, game); - return false; - } - - @Override - public GreenSunsZenithSearchEffect copy() { - return new GreenSunsZenithSearchEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/g/GremlinInfestation.java b/Mage.Sets/src/mage/cards/g/GremlinInfestation.java index 499fd8a1108..6aae9b9f781 100644 --- a/Mage.Sets/src/mage/cards/g/GremlinInfestation.java +++ b/Mage.Sets/src/mage/cards/g/GremlinInfestation.java @@ -28,7 +28,6 @@ package mage.cards.g; import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DiesAttachedTriggeredAbility; @@ -42,7 +41,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.game.permanent.token.Token; +import mage.game.permanent.token.GremlinToken; import mage.target.TargetPermanent; import mage.target.common.TargetArtifactPermanent; @@ -70,7 +69,7 @@ public class GremlinInfestation extends CardImpl { this.addAbility(new BeginningOfEndStepTriggeredAbility(new DamageAttachedControllerEffect(2), TargetController.YOU, false)); // When enchanted artifact is put into a graveyard, create a 2/2 red Gremlin creature token. - this.addAbility(new DiesAttachedTriggeredAbility(new CreateTokenEffect(new GremlinInfestationToken()), "enchanted artifact", false, false)); + this.addAbility(new DiesAttachedTriggeredAbility(new CreateTokenEffect(new GremlinToken()), "enchanted artifact", false, false)); } public GremlinInfestation(final GremlinInfestation card) { @@ -82,17 +81,3 @@ public class GremlinInfestation extends CardImpl { return new GremlinInfestation(this); } } - -class GremlinInfestationToken extends Token { - - GremlinInfestationToken() { - super("Gremlin", "2/2 red Gremlin creature token"); - this.setOriginalExpansionSetCode("AER"); - cardType.add(CardType.CREATURE); - color.setRed(true); - subtype.add("Gremlin"); - power = new MageInt(2); - toughness = new MageInt(2); - - } -} diff --git a/Mage.Sets/src/mage/cards/l/LullmageMentor.java b/Mage.Sets/src/mage/cards/l/LullmageMentor.java index 3622dfa66e2..795085f1d16 100644 --- a/Mage.Sets/src/mage/cards/l/LullmageMentor.java +++ b/Mage.Sets/src/mage/cards/l/LullmageMentor.java @@ -27,48 +27,41 @@ */ package mage.cards.l; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCounteredControllerTriggeredAbility; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.token.Token; -import mage.game.stack.StackObject; -import mage.target.Target; import mage.target.TargetSpell; import mage.target.common.TargetControlledCreaturePermanent; -import mage.watchers.Watcher; /** * * @author LevelX2 */ public class LullmageMentor extends CardImpl { + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Merfolk you control"); static { filter.add(new SubtypePredicate("Merfolk")); filter.add(Predicates.not(new TappedPredicate())); } + public LullmageMentor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); this.subtype.add("Merfolk"); this.subtype.add("Wizard"); @@ -76,7 +69,8 @@ public class LullmageMentor extends CardImpl { this.toughness = new MageInt(2); // Whenever a spell or ability you control counters a spell, you may create a 1/1 blue Merfolk creature token. - this.addAbility(new LullmageMentorTriggeredAbility(), new CastedSpellsWithSpellTarget()); + this.addAbility(new SpellCounteredControllerTriggeredAbility(new CreateTokenEffect(new MerfolkToken()), true)); + // Tap seven untapped Merfolk you control: Counter target spell. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(7, 7, filter, true))); ability.addTarget(new TargetSpell()); @@ -94,39 +88,6 @@ public class LullmageMentor extends CardImpl { } } -class LullmageMentorTriggeredAbility extends TriggeredAbilityImpl { - - public LullmageMentorTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new MerfolkToken()), false); - } - - public LullmageMentorTriggeredAbility(final LullmageMentorTriggeredAbility ability) { - super(ability); - } - - @Override - public LullmageMentorTriggeredAbility copy() { - return new LullmageMentorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.COUNTERED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - CastedSpellsWithSpellTarget watcher = (CastedSpellsWithSpellTarget) game.getState().getWatchers().get("CastedSpellsWithSpellTarget"); - UUID controllerIdCounter = watcher.getControllerSpell(event.getSourceId(), event.getTargetId()); - return controllerIdCounter != null && controllerIdCounter.equals(controllerId); - } - - @Override - public String getRule() { - return new StringBuilder("Whenever a spell or ability you control counters a spell, ").append(super.getRule()).toString(); - } -} - class MerfolkToken extends Token { public MerfolkToken() { @@ -138,59 +99,3 @@ class MerfolkToken extends Token { toughness = new MageInt(1); } } - -class CastedSpellsWithSpellTarget extends Watcher { - - private final Map casted = new HashMap<>(); - - public CastedSpellsWithSpellTarget() { - super("CastedSpellsWithSpellTarget", WatcherScope.GAME); - } - - public CastedSpellsWithSpellTarget(final CastedSpellsWithSpellTarget watcher) { - super(watcher); - for (Map.Entry entry: watcher.casted.entrySet()) { - casted.put(entry.getKey(), entry.getValue()); - } - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST || event.getType() == GameEvent.EventType.ACTIVATED_ABILITY) { - StackObject stackObject = game.getStack().getStackObject(event.getTargetId()); - if (stackObject == null) { - stackObject = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK); - } - if (stackObject != null && stackObject.getStackAbility() != null) { - for (Target target: stackObject.getStackAbility().getTargets()) { - if (target instanceof TargetSpell && target.getFirstTarget() != null) { - casted.put(getKey(target.getFirstTarget(), stackObject.getSourceId()), stackObject.getControllerId()); - } - } - } - } - } - - private String getKey(UUID targetId, UUID sourceId) { - return new StringBuilder(targetId.toString()).append("_").append(sourceId.toString()).toString(); - } - - public UUID getControllerSpell(UUID sourceId, UUID counteredSpell) { - if (sourceId != null && counteredSpell != null){ - return casted.get(getKey(counteredSpell, sourceId)); - } - return null; - } - - @Override - public void reset() { - super.reset(); - casted.clear(); - } - - @Override - public CastedSpellsWithSpellTarget copy() { - return new CastedSpellsWithSpellTarget(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/o/OathOfAjani.java b/Mage.Sets/src/mage/cards/o/OathOfAjani.java index 460abcceb3e..096a6b1a0cb 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfAjani.java +++ b/Mage.Sets/src/mage/cards/o/OathOfAjani.java @@ -46,19 +46,16 @@ import java.util.UUID; */ public class OathOfAjani extends CardImpl { - private static final FilterControlledCreaturePermanent creatureFilter = new FilterControlledCreaturePermanent(); - private static final FilterPlaneswalkerCard planeswalkerFilter = new FilterPlaneswalkerCard("Planeswalker spells"); - public OathOfAjani(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{W}"); this.supertype.add("Legendary"); // When Oath of Ajani enters the battlefield, put a +1/+1 counter on each creature you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), creatureFilter))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()))); // Planeswalker spells you cast cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(planeswalkerFilter, 1))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterPlaneswalkerCard("Planeswalker spells"), 1))); } public OathOfAjani(final OathOfAjani card) { diff --git a/Mage.Sets/src/mage/cards/p/ParadoxEngine.java b/Mage.Sets/src/mage/cards/p/ParadoxEngine.java index 68adfa37b68..617624391a9 100644 --- a/Mage.Sets/src/mage/cards/p/ParadoxEngine.java +++ b/Mage.Sets/src/mage/cards/p/ParadoxEngine.java @@ -28,9 +28,7 @@ package mage.cards.p; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.UntapAllControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -49,10 +47,7 @@ public class ParadoxEngine extends CardImpl { this.supertype.add("Legendary"); // Whenever you cast a spell, untap all nonland permanents you control. - Effect effect = new UntapAllControllerEffect(new FilterNonlandPermanent()); - Ability ability = new SpellCastControllerTriggeredAbility(effect, false); - ability.addEffect(effect); - this.addAbility(ability); + this.addAbility(new SpellCastControllerTriggeredAbility(new UntapAllControllerEffect(new FilterNonlandPermanent()), false)); } public ParadoxEngine(final ParadoxEngine card) { diff --git a/Mage.Sets/src/mage/cards/p/PlanarBridge.java b/Mage.Sets/src/mage/cards/p/PlanarBridge.java index 978d11165f2..f50d69d6ab1 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarBridge.java +++ b/Mage.Sets/src/mage/cards/p/PlanarBridge.java @@ -52,8 +52,11 @@ public class PlanarBridge extends CardImpl { this.supertype.add("Legendary"); // {8}, {T}: Search your library for a permanent card, put it onto the battlefield, then shuffle your library. - TargetCardInLibrary target = new TargetCardInLibrary(new FilterPermanentCard()); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(target), new GenericManaCost(8)); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterPermanentCard())), + new GenericManaCost(8) + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java b/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java index 237c39760e5..88b53d08992 100644 --- a/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java +++ b/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java @@ -28,7 +28,6 @@ package mage.cards.r; import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; @@ -38,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.game.Game; -import mage.game.permanent.token.Token; +import mage.game.permanent.token.GremlinToken; import mage.target.common.TargetArtifactPermanent; /** @@ -77,15 +76,3 @@ public class ReleaseTheGremlins extends CardImpl { return new ReleaseTheGremlins(this); } } - -class GremlinToken extends Token { - - public GremlinToken() { - super("Gremlin", "2/2 red Gremlin creature token"); - cardType.add(CardType.CREATURE); - subtype.add("Gremlin"); - color.setRed(true); - power = new MageInt(2); - toughness = new MageInt(2); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RenegadeMap.java b/Mage.Sets/src/mage/cards/r/RenegadeMap.java index b93996d9368..adec1866f88 100644 --- a/Mage.Sets/src/mage/cards/r/RenegadeMap.java +++ b/Mage.Sets/src/mage/cards/r/RenegadeMap.java @@ -50,13 +50,15 @@ public class RenegadeMap extends CardImpl { public RenegadeMap(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); - // Renegade Map enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // {T}, Sacrifice Renegade Map: Search your library for a basic land card, reveal it, put it into your hand, then shuffle your library. - TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(target, true), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterBasicLandCard()), true), + new TapSourceCost() + ); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/Reshape.java b/Mage.Sets/src/mage/cards/r/Reshape.java index c6c51cddd17..e056d49df0d 100644 --- a/Mage.Sets/src/mage/cards/r/Reshape.java +++ b/Mage.Sets/src/mage/cards/r/Reshape.java @@ -28,23 +28,13 @@ package mage.cards.r; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryWithLessCMCPutInPlayEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.Filter; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; +import mage.filter.common.FilterArtifactCard; +import mage.filter.common.FilterControlledArtifactPermanent; import mage.target.common.TargetControlledPermanent; /** @@ -53,19 +43,14 @@ import mage.target.common.TargetControlledPermanent; */ public class Reshape extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact"); - - static { - filter.add(new CardTypePredicate(CardType.ARTIFACT)); - } - public Reshape(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}"); // As an additional cost to cast Reshape, sacrifice an artifact. - this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, false))); + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent("an artifact"), false))); + // Search your library for an artifact card with converted mana cost X or less and put it onto the battlefield. Then shuffle your library. - this.getSpellAbility().addEffect(new ReshapeSearchEffect()); + this.getSpellAbility().addEffect(new SearchLibraryWithLessCMCPutInPlayEffect(new FilterArtifactCard())); } public Reshape(final Reshape card) { @@ -77,46 +62,3 @@ public class Reshape extends CardImpl { return new Reshape(this); } } - -class ReshapeSearchEffect extends OneShotEffect { - - ReshapeSearchEffect() { - super(Outcome.PutCardInPlay); - staticText = "Search your library for an artifact card with converted mana cost X or less and put it onto the battlefield. Then shuffle your library"; - } - - ReshapeSearchEffect(final ReshapeSearchEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - //Set the mana cost one higher to 'emulate' a less than or equal to comparison. - int xValue = source.getManaCostsToPay().getX() + 1; - FilterCard filter = new FilterCard("artifact card with converted mana cost " + xValue + " or less"); - filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, xValue)); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { - if (target.getTargets().size() > 0) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - controller.shuffleLibrary(source, game); - return true; - } - controller.shuffleLibrary(source, game); - return false; - } - - @Override - public ReshapeSearchEffect copy() { - return new ReshapeSearchEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SalvageScuttler.java b/Mage.Sets/src/mage/cards/s/SalvageScuttler.java index dde96b7e14b..457416c9add 100644 --- a/Mage.Sets/src/mage/cards/s/SalvageScuttler.java +++ b/Mage.Sets/src/mage/cards/s/SalvageScuttler.java @@ -29,16 +29,13 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.common.FilterControlledArtifactPermanent; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.common.TargetControlledPermanent; /** @@ -55,7 +52,9 @@ public class SalvageScuttler extends CardImpl { this.toughness = new MageInt(4); // Whenever Salvage Scuttler attacks, return an artifact you control to its owner's hand. - this.addAbility(new SalvageScuttlerAbility()); + Ability ability = new AttacksTriggeredAbility(new ReturnToHandTargetEffect(), false); + ability.addTarget(new TargetControlledPermanent(new FilterControlledArtifactPermanent("an artifact you control"))); + this.addAbility(ability); } public SalvageScuttler(final SalvageScuttler card) { @@ -67,39 +66,3 @@ public class SalvageScuttler extends CardImpl { return new SalvageScuttler(this); } } - -class SalvageScuttlerAbility extends TriggeredAbilityImpl { - - public SalvageScuttlerAbility() { - super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect()); - } - - public SalvageScuttlerAbility(final SalvageScuttlerAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.ATTACKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - TargetControlledPermanent target = new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent("artifact you control"), false); - this.addTarget(target); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} attacks, return an artifact you control to its owner's hand."; - } - - @Override - public SalvageScuttlerAbility copy() { - return new SalvageScuttlerAbility(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java b/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java index 32f8ac27b4b..401ef21fb60 100644 --- a/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java +++ b/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java @@ -46,6 +46,12 @@ import mage.game.permanent.token.ServoToken; */ public class SlyRequisitioner extends CardImpl { + private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("a nontoken artifact you control"); + + static { + filter.add(Predicates.not(new TokenPredicate())); + } + public SlyRequisitioner(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); @@ -56,9 +62,8 @@ public class SlyRequisitioner extends CardImpl { // Improvise this.addAbility(new ImproviseAbility()); + // Whenever a nontoken artifact you control is put into a graveyard from the battlefield, create a 1/1 colorless Servo artifact creature token. - FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("a nontoken artifact you control"); - filter.add(Predicates.not(new TokenPredicate())); this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(new CreateTokenEffect(new ServoToken()), false, filter, false)); } diff --git a/Mage.Sets/src/mage/cards/s/SolemnRecruit.java b/Mage.Sets/src/mage/cards/s/SolemnRecruit.java index f386813c24b..6f01ced58b3 100644 --- a/Mage.Sets/src/mage/cards/s/SolemnRecruit.java +++ b/Mage.Sets/src/mage/cards/s/SolemnRecruit.java @@ -29,7 +29,6 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; @@ -47,9 +46,6 @@ import mage.watchers.common.RevoltWatcher; */ public class SolemnRecruit extends CardImpl { - private static final String ruleText = "Revolt — At the beginning of your end step, if a permanent you controlled left the battlefield this turn, " - + "put a +1/+1 counter on {this}."; - public SolemnRecruit(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); @@ -62,8 +58,14 @@ public class SolemnRecruit extends CardImpl { this.addAbility(DoubleStrikeAbility.getInstance()); // Revolt — At the beginning of your end step, if a permanent you controlled left the battlefield this turn, put a +1/+1 counter on Solemn Recruit. - TriggeredAbility ability = new BeginningOfYourEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); - this.addAbility(new ConditionalTriggeredAbility(ability, RevoltCondition.getInstance(), ruleText), new RevoltWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfYourEndStepTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false + ), + RevoltCondition.getInstance(), + "Revolt — At the beginning of your end step, if a permanent you controlled left the battlefield this turn, put a +1/+1 counter on {this}." + ), new RevoltWatcher()); } public SolemnRecruit(final SolemnRecruit card) { diff --git a/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java b/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java index d821b122739..447ddf7995b 100644 --- a/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java +++ b/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java @@ -27,7 +27,6 @@ */ package mage.cards.s; -import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.SwordsToPlowsharesEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -43,13 +42,10 @@ import java.util.UUID; public class SwordsToPlowshares extends CardImpl { public SwordsToPlowshares(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); - - // Exile target creature. + // Exile target creature. Its controller gains life equal to its power. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new ExileTargetEffect()); - // Its controller gains life equal to its power. this.getSpellAbility().addEffect(new SwordsToPlowsharesEffect()); } diff --git a/Mage.Sets/src/mage/cards/t/TrophyMage.java b/Mage.Sets/src/mage/cards/t/TrophyMage.java index 6345d5c5d22..b313fd0894f 100644 --- a/Mage.Sets/src/mage/cards/t/TrophyMage.java +++ b/Mage.Sets/src/mage/cards/t/TrophyMage.java @@ -30,7 +30,6 @@ package mage.cards.t; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.SearchEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -63,9 +62,7 @@ public class TrophyMage extends CardImpl { this.toughness = new MageInt(2); // When Trophy Mage enters the battlefield, you may search your library for an artifact card with converted mana cost 3, reveal it, put it into your hand, then shuffle your library. - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - SearchEffect effect = new SearchLibraryPutInHandEffect(target, true, true); - this.addAbility(new EntersBattlefieldTriggeredAbility(effect, true)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, filter), true, true), true)); } public TrophyMage(final TrophyMage card) { diff --git a/Mage.Sets/src/mage/cards/v/VengefulRebel.java b/Mage.Sets/src/mage/cards/v/VengefulRebel.java index 81f292df2f4..e92da1cd1fa 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulRebel.java +++ b/Mage.Sets/src/mage/cards/v/VengefulRebel.java @@ -39,10 +39,7 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import mage.watchers.common.RevoltWatcher; /** @@ -51,12 +48,6 @@ import mage.watchers.common.RevoltWatcher; */ public class VengefulRebel extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); - - static { - filter.add(new ControllerPredicate(TargetController.OPPONENT)); - } - public VengefulRebel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -71,8 +62,9 @@ public class VengefulRebel extends CardImpl { new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-3, -3, Duration.EndOfTurn), false), RevoltCondition.getInstance(), "When {this} enters the battlefield, if a permanent you controlled left the battlefield this turn, " - + "target creature an opponent controls gets -3/-3 until end of turn"); - ability.addTarget(new TargetCreaturePermanent(filter)); + + "target creature an opponent controls gets -3/-3 until end of turn" + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); ability.setAbilityWord(AbilityWord.REVOLT); this.addAbility(ability, new RevoltWatcher()); } diff --git a/Mage.Sets/src/mage/cards/w/Wargate.java b/Mage.Sets/src/mage/cards/w/Wargate.java index 2d1a8d406b7..c3b7b95d105 100644 --- a/Mage.Sets/src/mage/cards/w/Wargate.java +++ b/Mage.Sets/src/mage/cards/w/Wargate.java @@ -28,20 +28,11 @@ package mage.cards.w; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryWithLessCMCPutInPlayEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.Filter; import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; /** * @@ -50,10 +41,10 @@ import mage.target.common.TargetCardInLibrary; public class Wargate extends CardImpl { public Wargate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{G}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}{W}{U}"); // Search your library for a permanent card with converted mana cost X or less, put it onto the battlefield, then shuffle your library. - this.getSpellAbility().addEffect(new WargateEffect()); + this.getSpellAbility().addEffect(new SearchLibraryWithLessCMCPutInPlayEffect(new FilterPermanentCard())); } public Wargate(final Wargate card) { @@ -65,43 +56,3 @@ public class Wargate extends CardImpl { return new Wargate(this); } } - -class WargateEffect extends OneShotEffect { - - WargateEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Search your library for a permanent card with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; - } - - WargateEffect(final WargateEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - FilterPermanentCard filter = new FilterPermanentCard("permanent card with converted mana cost X or less"); - //Set the mana cost one higher to 'emulate' a less than or equal to comparison. - filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, source.getManaCostsToPay().getX() + 1)); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { - if (target.getTargets().size() > 0) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - } - controller.shuffleLibrary(source, game); - return false; - } - - @Override - public WargateEffect copy() { - return new WargateEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/w/WeldfastEngineer.java b/Mage.Sets/src/mage/cards/w/WeldfastEngineer.java index dcee8b309ec..6a02f410c8b 100644 --- a/Mage.Sets/src/mage/cards/w/WeldfastEngineer.java +++ b/Mage.Sets/src/mage/cards/w/WeldfastEngineer.java @@ -47,6 +47,12 @@ import mage.target.common.TargetControlledPermanent; */ public class WeldfastEngineer extends CardImpl { + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("artifact creature you control"); + + static { + filter.add(new CardTypePredicate(CardType.ARTIFACT)); + } + public WeldfastEngineer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); @@ -57,8 +63,6 @@ public class WeldfastEngineer extends CardImpl { // At the beginning of combat on your turn, target artifact creature you control gets +2/+0 until end of turn. Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(2, 0, Duration.EndOfTurn), TargetController.YOU, false); - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("artifact creature you control"); - filter.add(new CardTypePredicate(CardType.ARTIFACT)); ability.addTarget(new TargetControlledPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WhirOfInvention.java b/Mage.Sets/src/mage/cards/w/WhirOfInvention.java index a05fbdd92f2..bd06a0b67d3 100644 --- a/Mage.Sets/src/mage/cards/w/WhirOfInvention.java +++ b/Mage.Sets/src/mage/cards/w/WhirOfInvention.java @@ -28,22 +28,12 @@ package mage.cards.w; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryWithLessCMCPutInPlayEffect; import mage.abilities.keyword.ImproviseAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.Filter; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; +import mage.filter.common.FilterArtifactCard; /** * @@ -58,7 +48,7 @@ public class WhirOfInvention extends CardImpl { addAbility(new ImproviseAbility()); // Search your library for an artifact card with converted mana cost X or less, put it onto the battlefield, then shuffle your library. - this.getSpellAbility().addEffect(new WhirOfInventionSearchEffect()); + this.getSpellAbility().addEffect(new SearchLibraryWithLessCMCPutInPlayEffect(new FilterArtifactCard())); } public WhirOfInvention(final WhirOfInvention card) { @@ -70,48 +60,3 @@ public class WhirOfInvention extends CardImpl { return new WhirOfInvention(this); } } - -class WhirOfInventionSearchEffect extends OneShotEffect { - - WhirOfInventionSearchEffect() { - super(Outcome.PutCardInPlay); - staticText = "Search your library for an artifact card with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; - } - - WhirOfInventionSearchEffect(final WhirOfInventionSearchEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (player == null || sourceCard == null) { - return false; - } - int xCost = source.getManaCostsToPay().getX(); - FilterCard filter = new FilterCard(new StringBuilder("artifact card with converted mana cost ").append(xCost).append(" or less").toString()); - filter.add(new CardTypePredicate(CardType.ARTIFACT)); - //Set the mana cost one higher to 'emulate' a less than or equal to comparison. - filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, xCost + 1)); - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (player.searchLibrary(target, game)) { - if (target.getTargets().size() > 0) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": Put ").append(card.getName()).append(" onto the battlefield").toString()); - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); - } - } - player.shuffleLibrary(source, game); - return true; - } - player.shuffleLibrary(source, game); - return false; - } - - @Override - public WhirOfInventionSearchEffect copy() { - return new WhirOfInventionSearchEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java b/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java index a5075b0f952..f1a38f4a96e 100644 --- a/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java +++ b/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java @@ -40,13 +40,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetControlledPermanent; /** @@ -55,15 +53,12 @@ import mage.target.common.TargetControlledPermanent; */ public class YahenniUndyingPartisan extends CardImpl { - private static final FilterCreaturePermanent opponentFilter = new FilterCreaturePermanent("a creature an opponent controls"); - private static final FilterControlledCreaturePermanent ownFilter = new FilterControlledCreaturePermanent("another creature"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature"); static { - opponentFilter.add(new ControllerPredicate(TargetController.OPPONENT)); - ownFilter.add(new AnotherPredicate()); + filter.add(new AnotherPredicate()); } - public YahenniUndyingPartisan(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -77,11 +72,14 @@ public class YahenniUndyingPartisan extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever a creature an opponent controls dies, put a +1/+1 counter on Yahenni, Undying Partisan. - this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, opponentFilter)); + this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, new FilterOpponentsCreaturePermanent())); // Sacrifice another creature: Yahenni gains indestructible until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), - new SacrificeTargetCost(new TargetControlledPermanent(ownFilter)))); + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), + new SacrificeTargetCost(new TargetControlledPermanent(filter))) + ); } public YahenniUndyingPartisan(final YahenniUndyingPartisan card) { diff --git a/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java new file mode 100644 index 00000000000..befb31d4452 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; + +/** + * + * @author fireshoes + */ +public class SpellCounteredControllerTriggeredAbility extends TriggeredAbilityImpl { + + public SpellCounteredControllerTriggeredAbility(Effect effect) { + this(effect, false); + } + + public SpellCounteredControllerTriggeredAbility(Effect effect, boolean optional) { + super(Zone.BATTLEFIELD, effect, optional); + } + + public SpellCounteredControllerTriggeredAbility(final SpellCounteredControllerTriggeredAbility ability) { + super(ability); + } + + @Override + public SpellCounteredControllerTriggeredAbility copy() { + return new SpellCounteredControllerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.COUNTERED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject stackObjectThatCountered = (StackObject) game.getStack().getStackObject(event.getSourceId()); + if (stackObjectThatCountered == null) { + stackObjectThatCountered = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK); + } + if (stackObjectThatCountered != null && stackObjectThatCountered.getControllerId().equals(getControllerId())) { + StackObject counteredStackObject = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK); + return counteredStackObject != null && (counteredStackObject instanceof Spell); + } + return false; + } + + @Override + public String getRule() { + return "Whenever a spell or ability you control counters a spell, " + super.getRule(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java index 7cd7f595295..180d76acf4e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -42,7 +41,7 @@ public class SwordsToPlowsharesEffect extends OneShotEffect { public SwordsToPlowsharesEffect() { super(Outcome.GainLife); - staticText = "Its controller gains life equal to its power"; + staticText = "Exile target creature. Its controller gains life equal to its power"; } public SwordsToPlowsharesEffect(final SwordsToPlowsharesEffect effect) { @@ -60,7 +59,9 @@ public class SwordsToPlowsharesEffect extends OneShotEffect { if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { - player.gainLife(permanent.getPower().getValue(), game); + int creaturePower = permanent.getPower().getValue(); + permanent.moveToExile(null, null, source.getSourceId(), game); + player.gainLife(creaturePower, game); } return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java new file mode 100644 index 00000000000..2096e438436 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java @@ -0,0 +1,90 @@ +/* + * 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.abilities.effects.common.search; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author Styxo + */ +public class SearchLibraryWithLessCMCPutInPlayEffect extends OneShotEffect { + + private FilterCard filter; + + public SearchLibraryWithLessCMCPutInPlayEffect() { + this(new FilterCard()); + } + + public SearchLibraryWithLessCMCPutInPlayEffect(FilterCard filter) { + super(Outcome.PutCreatureInPlay); + this.filter = filter; + staticText = "Search your library for a " + filter.getMessage() + " with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; + } + + public SearchLibraryWithLessCMCPutInPlayEffect(final SearchLibraryWithLessCMCPutInPlayEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, source.getManaCostsToPay().getX() + 1)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + if (controller.searchLibrary(target, game)) { + if (target.getTargets().size() > 0) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } + } + controller.shuffleLibrary(source, game); + } + return true; + } + return false; + } + + @Override + public SearchLibraryWithLessCMCPutInPlayEffect copy() { + return new SearchLibraryWithLessCMCPutInPlayEffect(this); + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java b/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java new file mode 100644 index 00000000000..9a47d9a9a8d --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java @@ -0,0 +1,48 @@ +/* + * 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.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; + +/** + * + * @author Styxo + */ +public class GremlinToken extends Token { + + public GremlinToken() { + super("Gremlin", "2/2 red Gremlin creature token"); + cardType.add(CardType.CREATURE); + this.setOriginalExpansionSetCode("AER"); + subtype.add("Gremlin"); + color.setRed(true); + power = new MageInt(2); + toughness = new MageInt(2); + } +}