mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 11:32:00 -08:00
Rework face down effect to layer 1b (#11689)
* add test case for face-down permanent losing abilities * rework BecomesFaceDownCreatureEffect to layer 1b * add test for becoming Treasure * small refactor: Minimus Containment * add mycosynth lattice test
This commit is contained in:
parent
ba0c3baf6c
commit
e431cd90ab
3 changed files with 161 additions and 81 deletions
|
|
@ -2,12 +2,10 @@ package mage.cards.m;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.Cost;
|
|
||||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
import mage.abilities.mana.AnyColorManaAbility;
|
import mage.abilities.token.TreasureAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
|
|
@ -51,16 +49,10 @@ public final class MinimusContainment extends CardImpl {
|
||||||
|
|
||||||
class MinimusContainmentEffect extends ContinuousEffectImpl {
|
class MinimusContainmentEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
private static final Ability ability = new AnyColorManaAbility();
|
private static final Ability ability = new TreasureAbility(false);
|
||||||
|
|
||||||
static {
|
|
||||||
Cost cost = new SacrificeSourceCost();
|
|
||||||
cost.setText("sacrifice this artifact");
|
|
||||||
ability.addCost(cost);
|
|
||||||
}
|
|
||||||
|
|
||||||
MinimusContainmentEffect() {
|
MinimusContainmentEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.Benefit);
|
super(Duration.WhileOnBattlefield, Outcome.LoseAbility);
|
||||||
staticText = "enchanted permanent is a Treasure artifact with " +
|
staticText = "enchanted permanent is a Treasure artifact with " +
|
||||||
"\"{T}, Sacrifice this artifact: Add one mana of any color,\" and it loses all other abilities";
|
"\"{T}, Sacrifice this artifact: Add one mana of any color,\" and it loses all other abilities";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -418,7 +418,7 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
for (Card card : currentGame.getExile().getAllCards(currentGame)) {
|
for (Card card : currentGame.getExile().getAllCards(currentGame)) {
|
||||||
if (card.getName().equals("Birchlore Rangers")) {
|
if (card.getName().equals("Birchlore Rangers")) {
|
||||||
Assert.assertEquals("Birchlore Rangers has to be face up in exile", false, card.isFaceDown(currentGame));
|
Assert.assertFalse("Birchlore Rangers has to be face up in exile", card.isFaceDown(currentGame));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -457,7 +457,7 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
for (Card card : playerA.getGraveyard().getCards(currentGame)) {
|
for (Card card : playerA.getGraveyard().getCards(currentGame)) {
|
||||||
if (card.getName().equals("Ashcloud Phoenix")) {
|
if (card.getName().equals("Ashcloud Phoenix")) {
|
||||||
Assert.assertEquals("Ashcloud Phoenix has to be face up in graveyard", false, card.isFaceDown(currentGame));
|
Assert.assertFalse("Ashcloud Phoenix has to be face up in graveyard", card.isFaceDown(currentGame));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -493,7 +493,7 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
for (Card card : playerA.getGraveyard().getCards(currentGame)) {
|
for (Card card : playerA.getGraveyard().getCards(currentGame)) {
|
||||||
if (card.getName().equals("Ashcloud Phoenix")) {
|
if (card.getName().equals("Ashcloud Phoenix")) {
|
||||||
Assert.assertEquals("Ashcloud Phoenix has to be face up in graveyard", false, card.isFaceDown(currentGame));
|
Assert.assertFalse("Ashcloud Phoenix has to be face up in graveyard", card.isFaceDown(currentGame));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -772,7 +772,7 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Brine Elemental", 1);
|
assertPermanentCount(playerA, "Brine Elemental", 1);
|
||||||
assertPermanentCount(playerB, "Brine Elemental", 1);
|
assertPermanentCount(playerB, "Brine Elemental", 1);
|
||||||
Assert.assertTrue("Skip next turn has to be added to TurnMods", currentGame.getState().getTurnMods().size() == 1);
|
Assert.assertEquals("Skip next turn has to be added to TurnMods", 1, currentGame.getState().getTurnMods().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -963,7 +963,6 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_LandWithMorph_MorphAfterLand() {
|
public void test_LandWithMorph_MorphAfterLand() {
|
||||||
removeAllCardsFromHand(playerA);
|
|
||||||
|
|
||||||
// Morph {2}
|
// Morph {2}
|
||||||
addCard(Zone.HAND, playerA, "Zoetic Cavern");
|
addCard(Zone.HAND, playerA, "Zoetic Cavern");
|
||||||
|
|
@ -1118,4 +1117,108 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2);
|
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoseAbilities() {
|
||||||
|
addCard(Zone.HAND, playerA, "Monastery Flock");
|
||||||
|
addCard(Zone.HAND, playerA, "Tamiyo's Compleation");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Secret Plans"); // face-down creatures get +0/+1
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Monastery Flock using Morph");
|
||||||
|
|
||||||
|
checkPT("face down", 1, PhaseStep.BEGIN_COMBAT, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3);
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.BEGIN_COMBAT, playerA, "{U}: Turn this", true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tamiyo's Compleation", EmptyNames.FACE_DOWN_CREATURE.toString());
|
||||||
|
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{U}: Turn this", false);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertTapped(EmptyNames.FACE_DOWN_CREATURE.toString(), true);
|
||||||
|
assertAttachedTo(playerA, "Tamiyo's Compleation", EmptyNames.FACE_DOWN_CREATURE.toString(), true);
|
||||||
|
assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBecomeTreasure() {
|
||||||
|
addCard(Zone.HAND, playerA, "Sage-Eye Harrier"); // 1/5 Flying, Morph 3W
|
||||||
|
addCard(Zone.HAND, playerA, "Minimus Containment"); // 2W Aura
|
||||||
|
// Enchant nonland permanent
|
||||||
|
// Enchanted permanent is a Treasure artifact with “{T},Sacrifice this artifact: Add one mana of any color,”
|
||||||
|
// and it loses all other abilities. (If it was a creature, it’s no longer a creature.)
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 7);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sage-Eye Harrier using Morph");
|
||||||
|
|
||||||
|
checkPT("face down", 1, PhaseStep.BEGIN_COMBAT, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2);
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.BEGIN_COMBAT, playerA, "{3}{W}: Turn this", true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Minimus Containment", EmptyNames.FACE_DOWN_CREATURE.toString());
|
||||||
|
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{3}{W}: Turn this", false);
|
||||||
|
|
||||||
|
checkPlayableAbility("treasure", 1, PhaseStep.END_TURN, playerA, "{T}, Sacrifice ", true);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(2, PhaseStep.UPKEEP);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertSubtype(EmptyNames.FACE_DOWN_CREATURE.toString(), SubType.TREASURE);
|
||||||
|
assertType(EmptyNames.FACE_DOWN_CREATURE.toString(), CardType.ARTIFACT, true);
|
||||||
|
assertType(EmptyNames.FACE_DOWN_CREATURE.toString(), CardType.CREATURE, false);
|
||||||
|
assertAttachedTo(playerA, "Minimus Containment", EmptyNames.FACE_DOWN_CREATURE.toString(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMycosynthAfter() {
|
||||||
|
addCard(Zone.HAND, playerA, "Monastery Flock");
|
||||||
|
addCard(Zone.HAND, playerA, "Mycosynth Lattice");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Secret Plans"); // face-down creatures get +0/+1
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Monastery Flock using Morph");
|
||||||
|
|
||||||
|
checkPT("face down", 1, PhaseStep.BEGIN_COMBAT, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3);
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.BEGIN_COMBAT, playerA, "{U}: Turn this", true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Mycosynth Lattice");
|
||||||
|
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{U}: Turn this", true);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertType(EmptyNames.FACE_DOWN_CREATURE.toString(), CardType.ARTIFACT, true);
|
||||||
|
assertType(EmptyNames.FACE_DOWN_CREATURE.toString(), CardType.CREATURE, true);
|
||||||
|
assertNotSubtype(EmptyNames.FACE_DOWN_CREATURE.toString(), SubType.BIRD);
|
||||||
|
assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMycosynthBefore() {
|
||||||
|
addCard(Zone.HAND, playerA, "Monastery Flock");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mycosynth Lattice");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Secret Plans"); // face-down creatures get +0/+1
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Monastery Flock using Morph");
|
||||||
|
|
||||||
|
checkPT("face down", 1, PhaseStep.BEGIN_COMBAT, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3);
|
||||||
|
checkPlayableAbility("unmorph", 1, PhaseStep.BEGIN_COMBAT, playerA, "{U}: Turn this", true);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertType(EmptyNames.FACE_DOWN_CREATURE.toString(), CardType.ARTIFACT, true);
|
||||||
|
assertType(EmptyNames.FACE_DOWN_CREATURE.toString(), CardType.CREATURE, true);
|
||||||
|
assertNotSubtype(EmptyNames.FACE_DOWN_CREATURE.toString(), SubType.BIRD);
|
||||||
|
assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
MANIFESTED,
|
MANIFESTED,
|
||||||
MANUAL,
|
MANUAL,
|
||||||
MEGAMORPHED,
|
MEGAMORPHED,
|
||||||
MORPHED
|
MORPHED,
|
||||||
|
DISGUISED,
|
||||||
|
CLOAKED
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int zoneChangeCounter;
|
protected int zoneChangeCounter;
|
||||||
|
|
@ -55,7 +57,7 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BecomesFaceDownCreatureEffect(Costs<Cost> turnFaceUpCosts, MageObjectReference objectReference, Duration duration, FaceDownType faceDownType) {
|
public BecomesFaceDownCreatureEffect(Costs<Cost> turnFaceUpCosts, MageObjectReference objectReference, Duration duration, FaceDownType faceDownType) {
|
||||||
super(duration, Outcome.BecomeCreature);
|
super(duration, Layer.CopyEffects_1, SubLayer.FaceDownEffects_1b, Outcome.BecomeCreature);
|
||||||
this.objectReference = objectReference;
|
this.objectReference = objectReference;
|
||||||
this.zoneChangeCounter = Integer.MIN_VALUE;
|
this.zoneChangeCounter = Integer.MIN_VALUE;
|
||||||
if (turnFaceUpCosts != null) {
|
if (turnFaceUpCosts != null) {
|
||||||
|
|
@ -77,20 +79,20 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
this.faceDownType = effect.faceDownType;
|
this.faceDownType = effect.faceDownType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BecomesFaceDownCreatureEffect copy() {
|
|
||||||
return new BecomesFaceDownCreatureEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Costs<Cost> createCosts(Cost cost) {
|
private static Costs<Cost> createCosts(Cost cost) {
|
||||||
if (cost == null) {
|
if (cost == null) {
|
||||||
return null;
|
return null; // ignore warning, null is used specifically
|
||||||
}
|
}
|
||||||
Costs<Cost> costs = new CostsImpl<>();
|
Costs<Cost> costs = new CostsImpl<>();
|
||||||
costs.add(cost);
|
costs.add(cost);
|
||||||
return costs;
|
return costs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BecomesFaceDownCreatureEffect copy() {
|
||||||
|
return new BecomesFaceDownCreatureEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
|
|
@ -108,7 +110,7 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent;
|
Permanent permanent;
|
||||||
if (objectReference != null) {
|
if (objectReference != null) {
|
||||||
permanent = objectReference.getPermanent(game);
|
permanent = objectReference.getPermanent(game);
|
||||||
|
|
@ -128,21 +130,19 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
case MEGAMORPHED:
|
case MEGAMORPHED:
|
||||||
permanent.setMorphed(true);
|
permanent.setMorphed(true);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("FaceDownType not yet supported: " + faceDownType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (layer) {
|
|
||||||
case TypeChangingEffects_4:
|
permanent.setName(EmptyNames.FACE_DOWN_CREATURE.toString());
|
||||||
permanent.setName("");
|
|
||||||
permanent.removeAllSuperTypes(game);
|
permanent.removeAllSuperTypes(game);
|
||||||
permanent.removeAllCardTypes(game);
|
permanent.removeAllCardTypes(game);
|
||||||
permanent.addCardType(game, CardType.CREATURE);
|
permanent.addCardType(game, CardType.CREATURE);
|
||||||
permanent.removeAllSubTypes(game);
|
permanent.removeAllSubTypes(game);
|
||||||
break;
|
permanent.getColor(game).setColor(ObjectColor.COLORLESS);
|
||||||
case ColorChangingEffects_5:
|
Card card = game.getCard(permanent.getId());
|
||||||
permanent.getColor(game).setColor(new ObjectColor());
|
|
||||||
break;
|
|
||||||
case AbilityAddingRemovingEffects_6:
|
|
||||||
Card card = game.getCard(permanent.getId()); //
|
|
||||||
List<Ability> abilitiesToRemove = new ArrayList<>();
|
List<Ability> abilitiesToRemove = new ArrayList<>();
|
||||||
for (Ability ability : permanent.getAbilities()) {
|
for (Ability ability : permanent.getAbilities()) {
|
||||||
|
|
||||||
|
|
@ -170,30 +170,15 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
abilitiesToRemove.add(ability);
|
abilitiesToRemove.add(ability);
|
||||||
}
|
}
|
||||||
permanent.removeAbilities(abilitiesToRemove, source.getSourceId(), game);
|
permanent.removeAbilities(abilitiesToRemove, source.getSourceId(), game);
|
||||||
if (turnFaceUpAbility != null) {
|
if (turnFaceUpAbility != null) { // TODO: shouldn't be added by this effect, but separately
|
||||||
permanent.addAbility(turnFaceUpAbility, source.getSourceId(), game);
|
permanent.addAbility(turnFaceUpAbility, source.getSourceId(), game);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case PTChangingEffects_7:
|
|
||||||
if (sublayer == SubLayer.SetPT_7b) {
|
|
||||||
permanent.getPower().setModifiedBaseValue(2);
|
permanent.getPower().setModifiedBaseValue(2);
|
||||||
permanent.getToughness().setModifiedBaseValue(2);
|
permanent.getToughness().setModifiedBaseValue(2);
|
||||||
}
|
} else if (duration == Duration.Custom && foundPermanent) {
|
||||||
}
|
|
||||||
} else if (duration == Duration.Custom && foundPermanent == true) {
|
|
||||||
discard();
|
discard();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasLayer(Layer layer) {
|
|
||||||
return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue