* Some changes to EnterTheBattlefield events, some other fixes (fixes #2765).

This commit is contained in:
LevelX2 2017-01-15 15:22:33 +01:00
parent dd810f2678
commit 75cbfdf3b9
24 changed files with 562 additions and 319 deletions

View file

@ -35,10 +35,12 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect; import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect;
import mage.abilities.effects.common.enterAttribute.EnterAttributeAddChosenSubtypeEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.EnterEventType;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer; import mage.constants.SubLayer;
@ -61,15 +63,18 @@ public class AdaptiveAutomaton extends CardImpl {
} }
public AdaptiveAutomaton(UUID ownerId, CardSetInfo setInfo) { 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.subtype.add("Construct");
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// As Adaptive Automaton enters the battlefield, choose a creature type. // 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. // 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())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AdaptiveAutomatonAddSubtypeEffect()));
// Other creatures you control of the chosen type get +1/+1. // 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))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllOfChosenSubtypeEffect(1, 1, Duration.WhileOnBattlefield, filter, true)));

View file

@ -32,16 +32,15 @@ import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.abilities.effects.common.enterAttribute.EnterAttributeAddChosenSubtypeEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.EnterEventType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
@ -63,10 +62,10 @@ public class MetallicMimic extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// As Metallic Mimic enters the battlefield, choose a creature type. // As Metallic Mimic enters the battlefield, choose a creature type.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); AsEntersBattlefieldAbility ability = new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature), null, EnterEventType.SELF);
// Metallic Mimic is the chosen type in addition to its other types. // Metallic Mimic is the chosen type in addition to its other types.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MetallicMimicEffect())); 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. // 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())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MetallicMimicReplacementEffect()));
@ -82,34 +81,6 @@ public class MetallicMimic extends CardImpl {
return new MetallicMimic(this); 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 { class MetallicMimicReplacementEffect extends ReplacementEffectImpl {
@ -117,6 +88,7 @@ class MetallicMimicReplacementEffect extends ReplacementEffectImpl {
MetallicMimicReplacementEffect() { MetallicMimicReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.BoostCreature); 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"; 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) { MetallicMimicReplacementEffect(MetallicMimicReplacementEffect effect) {
@ -132,11 +104,14 @@ class MetallicMimicReplacementEffect extends ReplacementEffectImpl {
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
Permanent enteringCreature = ((EntersTheBattlefieldEvent) event).getTarget(); Permanent enteringCreature = ((EntersTheBattlefieldEvent) event).getTarget();
return enteringCreature != null && sourcePermanent != null if (enteringCreature != null && sourcePermanent != null
&& enteringCreature.getControllerId().equals(source.getControllerId()) && enteringCreature.getControllerId().equals(source.getControllerId())
&& enteringCreature.getCardType().contains(CardType.CREATURE) && enteringCreature.getCardType().contains(CardType.CREATURE)
&& enteringCreature.getSubtype(game).contains(game.getState().getValue(sourcePermanent.getId() + "_type")) && !event.getTargetId().equals(source.getSourceId())) {
&& !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 @Override

View file

@ -27,7 +27,7 @@
*/ */
package mage.cards.s; package mage.cards.s;
import mage.constants.CardType; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.RemoveCountersSourceCost;
@ -36,24 +36,23 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.counters.CounterType; import mage.counters.CounterType;
import java.util.UUID;
/** /**
* *
* @author North, Loki, noxx * @author North, Loki, noxx
*/ */
public class SphereOfTheSuns extends CardImpl { 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) { 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. // Sphere of the Suns enters the battlefield tapped and with three charge counters on it.
Ability ability = new EntersBattlefieldTappedAbility(ruleText); 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); this.addAbility(ability);
RemoveCountersSourceCost removeCounterCost = new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()); RemoveCountersSourceCost removeCounterCost = new RemoveCountersSourceCost(CounterType.CHARGE.createInstance());

View file

@ -27,16 +27,21 @@
*/ */
package mage.cards.v; package mage.cards.v;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility; 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.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
@ -49,6 +54,7 @@ import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; 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 class VanishIntoMemory extends CardImpl {
public VanishIntoMemory(UUID ownerId, CardSetInfo setInfo) { 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. // 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. // 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() { public VanishIntoMemoryEffect() {
super(Outcome.Detriment); 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) { public VanishIntoMemoryEffect(final VanishIntoMemoryEffect effect) {
@ -89,20 +95,18 @@ class VanishIntoMemoryEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget()); Permanent permanent = game.getPermanent(source.getFirstTarget());
Player you = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId()); MageObject sourceObject = game.getObject(source.getSourceId());
if (permanent != null && sourceObject != null) { if (controller != null && permanent != null && sourceObject != null) {
if (permanent.moveToExile(source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game)) { if (controller.moveCardsToExile(permanent, source, game, true, source.getSourceId(), sourceObject.getIdName())) {
you.drawCards(permanent.getPower().getValue(), game); controller.drawCards(permanent.getPower().getValue(), game);
ExileZone exile = game.getExile().getExileZone(source.getSourceId()); ExileZone exile = game.getExile().getExileZone(source.getSourceId());
// only if permanent is in exile (tokens would be stop to exist) // only if permanent is in exile (tokens would be stop to exist)
if (exile != null && !exile.isEmpty()) { if (exile != null && !exile.isEmpty()) {
Card card = game.getCard(permanent.getId()); //create delayed triggered ability
if (card != null) { Effect effect = new VanishIntoMemoryReturnFromExileEffect();
//create delayed triggered ability effect.setTargetPointer(new FixedTargets(exile, game));
game.addDelayedTriggeredAbility(new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility( game.addDelayedTriggeredAbility(new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(effect), source);
new VanishIntoMemoryReturnFromExileEffect(new MageObjectReference(card, game))), source);
}
} }
return true; return true;
} }
@ -118,17 +122,13 @@ class VanishIntoMemoryEffect extends OneShotEffect {
class VanishIntoMemoryReturnFromExileEffect extends OneShotEffect { class VanishIntoMemoryReturnFromExileEffect extends OneShotEffect {
MageObjectReference objectToReturn; public VanishIntoMemoryReturnFromExileEffect() {
public VanishIntoMemoryReturnFromExileEffect(MageObjectReference objectToReturn) {
super(Outcome.PutCardInPlay); super(Outcome.PutCardInPlay);
this.objectToReturn = objectToReturn;
staticText = "return that card to the battlefield under its owner's control"; staticText = "return that card to the battlefield under its owner's control";
} }
public VanishIntoMemoryReturnFromExileEffect(final VanishIntoMemoryReturnFromExileEffect effect) { public VanishIntoMemoryReturnFromExileEffect(final VanishIntoMemoryReturnFromExileEffect effect) {
super(effect); super(effect);
this.objectToReturn = effect.objectToReturn;
} }
@Override @Override
@ -138,31 +138,30 @@ class VanishIntoMemoryReturnFromExileEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Card card = game.getCard(objectToReturn.getSourceId()); Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source));
if (card != null && objectToReturn.refersTo(card, game)) { Player controller = game.getPlayer(source.getControllerId());
Player owner = game.getPlayer(card.getOwnerId()); if (controller != null) {
if (owner != null) { Set<Card> cardsToBattlefield = new HashSet<>();
game.addEffect(new VanishIntoMemoryEntersBattlefieldEffect(objectToReturn), source); cardsToBattlefield.addAll(cards.getCards(game));
owner.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); 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; return true;
} }
} }
class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl { class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl {
MageObjectReference objectToReturn; public VanishIntoMemoryEntersBattlefieldEffect() {
super(Duration.EndOfTurn, Outcome.Discard);
public VanishIntoMemoryEntersBattlefieldEffect(MageObjectReference objectToReturn) {
super(Duration.Custom, Outcome.BoostCreature);
this.objectToReturn = objectToReturn;
staticText = "discard cards equal to that creature's toughness."; staticText = "discard cards equal to that creature's toughness.";
} }
public VanishIntoMemoryEntersBattlefieldEffect(VanishIntoMemoryEntersBattlefieldEffect effect) { public VanishIntoMemoryEntersBattlefieldEffect(VanishIntoMemoryEntersBattlefieldEffect effect) {
super(effect); super(effect);
this.objectToReturn = effect.objectToReturn;
} }
@Override @Override
@ -172,10 +171,7 @@ class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { return getTargetPointer().getTargets(game, source).contains(event.getTargetId());
return event.getTargetId().equals(objectToReturn.getSourceId());
}
return false;
} }
@Override @Override
@ -186,7 +182,6 @@ class VanishIntoMemoryEntersBattlefieldEffect extends ReplacementEffectImpl {
if (you != null) { if (you != null) {
you.discard(permanent.getToughness().getValue(), false, source, game); you.discard(permanent.getToughness().getValue(), false, source, game);
} }
discard(); // use only once
} }
return false; return false;
} }

View file

@ -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. // When you cast Bruna, the Fading Light, you may return target Angel or Human creature card from your graveyard to the battlefield.
// Flying, Vigilance // Flying, Vigilance
// <i>(Melds with Gisela, the Broken Blade.)</i> // <i>(Melds with Gisela, the Broken Blade.)</i>
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 // Flying, First strike, Lifelink
// At the beginning of your end step, if you both own and control Gisela, the Broken Blade and a // 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. // 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 // Brisela, Voice of Nightmares 9/10
// Flying, First strike, Vigilance, Lifelink // Flying, First strike, Vigilance, Lifelink
// Your opponents can't cast spells with converted mana cost 3 or less. // 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); assertGraveyardCount(playerB, "Vanish into Memory", 1);
assertPermanentCount(playerB, "Silvercoat Lion", 2); assertPermanentCount(playerB, "Silvercoat Lion", 2);
assertHandCount(playerB, 0); assertHandCount(playerB, 1); // discard 10 upkeep turn 6 ==> 0 + draw 1 at draw phase turn 6
} }

View file

@ -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 dont
* 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
* doesnt 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);
}
}

View file

@ -285,7 +285,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
if (card == null) { if (card == null) {
throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName); 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); p.setTapped(tapped);
getBattlefieldCards(player).add(p); getBattlefieldCards(player).add(p);
} }
@ -466,7 +466,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
+ ", cardName=" + cardName, count > 0); + ", cardName=" + cardName, count > 0);
if (scope.equals(Filter.ComparisonScope.Any)) { 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); + ", cardName=" + cardName + " (found similar: " + found + ", one of them: power=" + foundPower + " toughness=" + foundToughness + ")", fit > 0);
} }
} }

View file

@ -30,6 +30,7 @@ package mage.abilities.common;
import mage.abilities.StaticAbility; import mage.abilities.StaticAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.EntersBattlefieldEffect;
import mage.constants.EnterEventType;
import mage.constants.Zone; import mage.constants.Zone;
/** /**
@ -39,14 +40,18 @@ import mage.constants.Zone;
public class AsEntersBattlefieldAbility extends StaticAbility { public class AsEntersBattlefieldAbility extends StaticAbility {
public AsEntersBattlefieldAbility(Effect effect) { public AsEntersBattlefieldAbility(Effect effect) {
super(Zone.ALL, new EntersBattlefieldEffect(effect)); this(effect, null, EnterEventType.OTHER);
} }
public AsEntersBattlefieldAbility(Effect effect, String text) { 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); super(ability);
} }

View file

@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.other.OwnerIdPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -39,7 +40,6 @@ import mage.game.permanent.Permanent;
* *
* @author emerald000 * @author emerald000
*/ */
public class MeldCondition implements Condition { public class MeldCondition implements Condition {
private final String meldWithName; private final String meldWithName;
@ -57,11 +57,8 @@ public class MeldCondition implements Condition {
&& sourcePermanent.getOwnerId().equals(source.getControllerId())) { && sourcePermanent.getOwnerId().equals(source.getControllerId())) {
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
filter.add(new NamePredicate(this.meldWithName)); filter.add(new NamePredicate(this.meldWithName));
for (Permanent meldWithPermanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { filter.add(new OwnerIdPredicate(source.getControllerId()));
if (meldWithPermanent.getOwnerId().equals(source.getControllerId())) { return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0;
return true;
}
}
} }
} }
return false; return false;

View file

@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.EnterEventType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -50,6 +51,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
protected String text; protected String text;
protected Condition condition; protected Condition condition;
protected boolean optional; protected boolean optional;
protected EnterEventType enterEventType;
public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; 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) { 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); super(Duration.WhileOnBattlefield, baseEffect.getOutcome(), selfScope);
this.baseEffects.add(baseEffect); this.baseEffects.add(baseEffect);
this.enterEventType = enterEventType;
this.text = text; this.text = text;
this.condition = condition; this.condition = condition;
this.optional = optional; this.optional = optional;
} }
public EntersBattlefieldEffect(EntersBattlefieldEffect effect) { public EntersBattlefieldEffect(final EntersBattlefieldEffect effect) {
super(effect); super(effect);
this.baseEffects = effect.baseEffects.copy(); this.baseEffects = effect.baseEffects.copy();
this.text = effect.text; this.text = effect.text;
this.condition = effect.condition; this.condition = effect.condition;
this.optional = effect.optional; this.optional = effect.optional;
this.enterEventType = effect.enterEventType;
} }
public void addEffect(Effect effect) { public void addEffect(Effect effect) {
@ -87,7 +95,17 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { 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 @Override

View file

@ -27,6 +27,7 @@
*/ */
package mage.abilities.effects.common; package mage.abilities.effects.common;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -93,8 +94,10 @@ public class MeldEffect extends OneShotEffect {
Permanent sourcePermanent = game.getPermanent(sourceId); Permanent sourcePermanent = game.getPermanent(sourceId);
Permanent meldWithPermanent = game.getPermanent(meldWithId); Permanent meldWithPermanent = game.getPermanent(meldWithId);
if (sourcePermanent != null && meldWithPermanent != null) { if (sourcePermanent != null && meldWithPermanent != null) {
sourcePermanent.moveToExile(null, "", sourceId, game); Set<Card> toExile = new HashSet<>();
meldWithPermanent.moveToExile(null, "", sourceId, game); toExile.add(sourcePermanent);
toExile.add(meldWithPermanent);
controller.moveCards(toExile, Zone.EXILED, source, game);
// Create the meld card and move it to the battlefield. // Create the meld card and move it to the battlefield.
Card sourceCard = game.getExile().getCard(sourceId, game); Card sourceCard = game.getExile().getCard(sourceId, game);
Card meldWithCard = game.getExile().getCard(meldWithId, game); Card meldWithCard = game.getExile().getCard(meldWithId, game);
@ -106,7 +109,7 @@ public class MeldEffect extends OneShotEffect {
game.addMeldCard(meldCard.getId(), meldCard); game.addMeldCard(meldCard.getId(), meldCard);
game.getState().addCard(meldCard); game.getState().addCard(meldCard);
meldCard.setZone(Zone.EXILED, game); meldCard.setZone(Zone.EXILED, game);
meldCard.moveToZone(Zone.BATTLEFIELD, sourceId, game, false); controller.moveCards(meldCard, Zone.BATTLEFIELD, source, game);
} }
return true; return true;
} }

View file

@ -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;
}
}

View file

@ -27,25 +27,23 @@
*/ */
package mage.abilities.keyword; package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; 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.AttachEffect;
import mage.abilities.effects.common.continuous.SourceEffect;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.repository.CardRepository;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.DependencyType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SpellAbilityType; import mage.constants.SpellAbilityType;
import mage.constants.SubLayer;
import mage.constants.TimingRule; import mage.constants.TimingRule;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -123,7 +121,7 @@ public class BestowAbility extends SpellAbility {
TargetPermanent auraTarget = new TargetCreaturePermanent(); TargetPermanent auraTarget = new TargetCreaturePermanent();
this.addTarget(auraTarget); this.addTarget(auraTarget);
this.addEffect(new AttachEffect(Outcome.BoostCreature)); 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); ability.setRuleVisible(false);
addSubAbility(ability); addSubAbility(ability);
} }
@ -147,64 +145,60 @@ public class BestowAbility extends SpellAbility {
return "Bestow " + getManaCostsToPay().getText() + " <i>(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.)</i>"; return "Bestow " + getManaCostsToPay().getText() + " <i>(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.)</i>";
} }
class BestowTypeChangingEffect extends ContinuousEffectImpl implements SourceEffect { static public void becomeCreature(Permanent permanent, Game game) {
if (permanent != null) {
private boolean wasAttached; MageObject basicObject = permanent.getBasicMageObject(game);
if (basicObject != null) {
public BestowTypeChangingEffect() { basicObject.getSubtype(null).remove("Aura");
super(Duration.WhileOnBattlefield, Outcome.BoostCreature); if (!basicObject.getCardType().contains(CardType.CREATURE)) {
wasAttached = false; basicObject.getCardType().add(CardType.CREATURE);
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;
} }
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 class BestowEntersBattlefieldEffect extends ReplacementEffectImpl {
public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4; 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);
} }
} }

View file

@ -55,13 +55,13 @@ public abstract class MeldCard extends CardImpl {
halves = new CardsImpl(); halves = new CardsImpl();
} }
public MeldCard(MeldCard card) { public MeldCard(final MeldCard card) {
super(card); super(card);
this.topHalfCard = card.topHalfCard; this.topHalfCard = card.topHalfCard;
this.bottomHalfCard = card.bottomHalfCard; this.bottomHalfCard = card.bottomHalfCard;
this.topLastZoneChangeCounter = card.topLastZoneChangeCounter; this.topLastZoneChangeCounter = card.topLastZoneChangeCounter;
this.bottomLastZoneChangeCounter = card.bottomLastZoneChangeCounter; this.bottomLastZoneChangeCounter = card.bottomLastZoneChangeCounter;
this.halves = new CardsImpl(halves); this.halves = new CardsImpl(card.halves);
this.isMelded = card.isMelded; this.isMelded = card.isMelded;
} }
@ -211,4 +211,5 @@ public abstract class MeldCard extends CardImpl {
public Cards getHalves() { public Cards getHalves() {
return halves; return halves;
} }
} }

View file

@ -0,0 +1,12 @@
package mage.constants;
/**
*
* @author LevelX2
*/
public enum EnterEventType {
SELF,
CONTROL,
COPY,
OTHER
}

View file

@ -57,6 +57,7 @@ import mage.abilities.effects.ContinuousEffects;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.CopyEffect;
import mage.abilities.keyword.BestowAbility;
import mage.abilities.keyword.MorphAbility; import mage.abilities.keyword.MorphAbility;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.TransformAbility;
import mage.abilities.mana.DelayedTriggeredManaAbility; import mage.abilities.mana.DelayedTriggeredManaAbility;
@ -1787,7 +1788,7 @@ public abstract class GameImpl implements Game, Serializable {
} }
} else { } else {
SpellAbility spellAbility = perm.getSpellAbility(); SpellAbility spellAbility = perm.getSpellAbility();
if (perm.getSpellAbility().getTargets().isEmpty()) { if (spellAbility.getTargets().isEmpty()) {
for (Ability ability : perm.getAbilities(this)) { for (Ability ability : perm.getAbilities(this)) {
if ((ability instanceof SpellAbility) if ((ability instanceof SpellAbility)
&& SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType()) && 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)) { if (card != null && card.getCardType().contains(CardType.CREATURE)) {
UUID wasAttachedTo = perm.getAttachedTo(); UUID wasAttachedTo = perm.getAttachedTo();
perm.attachTo(null, this); perm.attachTo(null, this);
BestowAbility.becomeCreature(perm, this);
fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId()));
} else if (movePermanentToGraveyardWithInfo(perm)) { } else if (movePermanentToGraveyardWithInfo(perm)) {
somethingHappened = true; somethingHappened = true;
@ -2675,17 +2677,17 @@ public abstract class GameImpl implements Game, Serializable {
card.setZone(Zone.GRAVEYARD, this); card.setZone(Zone.GRAVEYARD, this);
player.getGraveyard().add(card); player.getGraveyard().add(card);
} }
for (PermanentCard card : battlefield) { for (PermanentCard permanentCard : battlefield) {
card.setZone(Zone.BATTLEFIELD, this); permanentCard.setZone(Zone.BATTLEFIELD, this);
card.setOwnerId(ownerId); permanentCard.setOwnerId(ownerId);
PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this); PermanentCard newPermanent = new PermanentCard(permanentCard.getCard(), ownerId, this);
getPermanentsEntering().put(permanent.getId(), permanent); getPermanentsEntering().put(newPermanent.getId(), newPermanent);
permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false); newPermanent.entersBattlefield(newPermanent.getId(), this, Zone.OUTSIDE, false);
getBattlefield().addPermanent(permanent); getBattlefield().addPermanent(newPermanent);
getPermanentsEntering().remove(permanent.getId()); getPermanentsEntering().remove(newPermanent.getId());
permanent.removeSummoningSickness(); newPermanent.removeSummoningSickness();
if (card.isTapped()) { if (permanentCard.isTapped()) {
permanent.setTapped(true); newPermanent.setTapped(true);
} }
} }
applyEffects(); applyEffects();

View file

@ -204,8 +204,7 @@ public class ZonesHandler {
// If we can't find the card we can't remove it. // If we can't find the card we can't remove it.
return false; return false;
} }
// If needed take attributes from the spell (e.g. color of spell was changed)
card = takeAttributesFromSpell(card, event, game);
boolean success = false; boolean success = false;
if (info.faceDown) { if (info.faceDown) {
card.setFaceDown(true, game); card.setFaceDown(true, game);
@ -213,6 +212,8 @@ public class ZonesHandler {
if (!game.replaceEvent(event)) { if (!game.replaceEvent(event)) {
Zone fromZone = event.getFromZone(); Zone fromZone = event.getFromZone();
if (event.getToZone() == Zone.BATTLEFIELD) { 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 // controlling player can be replaced so use event player now
Permanent permanent; Permanent permanent;
if (card instanceof MeldCard) { if (card instanceof MeldCard) {
@ -232,7 +233,6 @@ public class ZonesHandler {
if (info.faceDown) { if (info.faceDown) {
card.setFaceDown(false, game); card.setFaceDown(false, game);
} }
// make sure the controller of all continuous effects of this card are switched to the current controller // make sure the controller of all continuous effects of this card are switched to the current controller
game.setScopeRelevant(true); game.setScopeRelevant(true);
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId()); game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
@ -282,16 +282,12 @@ public class ZonesHandler {
} }
private static Card takeAttributesFromSpell(Card card, ZoneChangeEvent event, Game game) { private static Card takeAttributesFromSpell(Card card, ZoneChangeEvent event, Game game) {
card = card.copy();
if (Zone.STACK.equals(event.getFromZone())) { if (Zone.STACK.equals(event.getFromZone())) {
Spell spell = game.getStack().getSpell(event.getTargetId()); Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && !spell.isFaceDown(game)) { if (spell != null && !spell.isFaceDown(game)) {
boolean doCopy = false;
if (!card.getColor(game).equals(spell.getColor(game))) { 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 // 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)); card.getColor(game).setColor(spell.getColor(game));
} }
} }

View file

@ -24,12 +24,12 @@
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.game.events; package mage.game.events;
import java.util.ArrayList;
import java.util.UUID; import java.util.UUID;
import mage.constants.EnterEventType;
import static mage.constants.EnterEventType.SELF;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -43,17 +43,24 @@ public class EntersTheBattlefieldEvent extends GameEvent {
private Permanent target; private Permanent target;
public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone) { public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone) {
super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId); this(target, sourceId, playerId, fromZone, EnterEventType.OTHER);
this.fromZone = fromZone;
this.target = target;
} }
public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, ArrayList<UUID> appliedEffects) { public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, EnterEventType enterType) {
super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId); super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId);
this.fromZone = fromZone; switch (enterType) {
if (appliedEffects != null) { case SELF:
this.appliedEffects = appliedEffects; 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() { public Zone getFromZone() {

View file

@ -229,7 +229,10 @@ public class GameEvent implements Serializable {
PAID_CUMULATIVE_UPKEEP, PAID_CUMULATIVE_UPKEEP,
DIDNT_PAY_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP,
//permanent events //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, TAP, TAPPED, TAPPED_FOR_MANA,
UNTAP, UNTAPPED, UNTAP, UNTAPPED,
FLIP, FLIPPED, FLIP, FLIPPED,

View file

@ -149,6 +149,8 @@ public interface Permanent extends Card, Controllable {
void reset(Game game); void reset(Game game);
MageObject getBasicMageObject(Game game);
boolean destroy(UUID sourceId, Game game, boolean noRegen); boolean destroy(UUID sourceId, Game game, boolean noRegen);
boolean sacrifice(UUID sourceId, Game game); boolean sacrifice(UUID sourceId, Game game);

View file

@ -28,6 +28,7 @@
package mage.game.permanent; package mage.game.permanent;
import java.util.UUID; import java.util.UUID;
import mage.MageObject;
import mage.abilities.Abilities; import mage.abilities.Abilities;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
@ -44,6 +45,7 @@ import mage.game.events.ZoneChangeEvent;
public class PermanentCard extends PermanentImpl { public class PermanentCard extends PermanentImpl {
protected int maxLevelCounters; 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; protected Card card;
// the number this permanent instance had // the number this permanent instance had
protected int zoneChangeCounter; protected int zoneChangeCounter;
@ -141,6 +143,11 @@ public class PermanentCard extends PermanentImpl {
this.flipCardName = card.getFlipCardName(); this.flipCardName = card.getFlipCardName();
} }
@Override
public MageObject getBasicMageObject(Game game) {
return card;
}
public Card getCard() { public Card getCard() {
return card; return card;
} }

View file

@ -59,6 +59,7 @@ import mage.cards.CardImpl;
import mage.constants.AsThoughEffectType; import mage.constants.AsThoughEffectType;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.EffectType; import mage.constants.EffectType;
import mage.constants.EnterEventType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.Counter; 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 // remove some attributes here, because first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger
MorphAbility.setPermanentToFaceDownCreature(this); 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 (!game.replaceEvent(event)) {
if (fireEvent) { if (fireEvent) {
game.addSimultaneousEvent(event); game.addSimultaneousEvent(event);
return true; return true;
} }
} }
return false; return false;
} }

View file

@ -28,6 +28,7 @@
package mage.game.permanent; package mage.game.permanent;
import java.util.UUID; import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.game.Game; import mage.game.Game;
@ -92,6 +93,11 @@ public class PermanentToken extends PermanentImpl {
this.tokenDescriptor = token.getTokenDescriptor(); this.tokenDescriptor = token.getTokenDescriptor();
} }
@Override
public MageObject getBasicMageObject(Game game) {
return token;
}
public Token getToken() { public Token getToken() {
return token; return token;
} }

View file

@ -257,8 +257,8 @@ public class Spell extends StackObjImpl implements Card {
Permanent permanent = game.getPermanent(card.getId()); Permanent permanent = game.getPermanent(card.getId());
if (permanent != null && permanent instanceof PermanentCard) { if (permanent != null && permanent instanceof PermanentCard) {
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE); card.getCardType().add(CardType.CREATURE);
((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura"); card.getSubtype(game).remove("Aura");
} }
} }
return ability.resolve(game); 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 // Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature
if (this.getSpellAbility() instanceof BestowAbility) { if (this.getSpellAbility() instanceof BestowAbility) {
updateOptionalCosts(0); 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 { } else {
//20091005 - 608.2b //20091005 - 608.2b
if (!game.isSimulation()) { if (!game.isSimulation()) {