* 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.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)));

View file

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

View file

@ -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());

View file

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

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.
// Flying, Vigilance
// <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
// 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
}

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) {
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);
}
}

View file

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

View file

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

View file

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

View file

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

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;
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() + " <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 {
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);
}
}

View file

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

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.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();

View file

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

View file

@ -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<UUID> 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() {

View file

@ -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,

View file

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

View file

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

View file

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

View file

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

View file

@ -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()) {