diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java index b71eec1910..2cd05794a6 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 7dad26c499..b837e2e3b4 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 a45157cfd6..f98a1421b1 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 6754266212..7a15df5e00 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 8a1c5be48a..234b489a2e 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 0000000000..67c74b94e0 --- /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 088da88167..c2b6e993c4 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 7747a126d0..ca55f4a726 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 1480a16c8a..a757e16c27 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 549863083a..37589a698c 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 8a09e37999..127957787f 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 0000000000..b5db7190ae --- /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 fffff63fb2..ab0dbd2c06 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 bbf2faef5d..736dd293f2 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 0000000000..09a5b75a92 --- /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 a17832e0ee..68133f69ed 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 427095c91b..fc733a970b 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 c4948e4b6e..ab63ce854d 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 a38958c2ea..a554d27655 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 37f2a7efa2..f4071c1214 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 9ff7eb7578..c3ff27de59 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 23f00de982..b8a2194209 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 fe51ad6c62..c190345d9a 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 eedb53d704..57a0fb74f9 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()) {