diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 3d0a830b964..df87f2be97f 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -436,6 +436,7 @@ public abstract class AbilityImpl implements Ability { case DISTURB: case MORE_THAN_MEETS_THE_EYE: case BESTOW: + case MORPH: // from Snapcaster Mage: // If you cast a spell from a graveyard using its flashback ability, you can't pay other alternative costs // (such as that of Foil). (2018-12-07) diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index c0a0084c2a5..8dbacc1f4cf 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -3,8 +3,8 @@ package mage.abilities.keyword; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.AlternativeSourceCostsImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; @@ -12,13 +12,15 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType; +import mage.cards.Card; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.SpellAbilityCastMode; +import mage.constants.TimingRule; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; import mage.game.permanent.token.Token; -import mage.game.stack.Spell; import mage.util.CardUtil; /** @@ -62,8 +64,7 @@ import mage.util.CardUtil; * * @author LevelX2 */ -public class MorphAbility extends AlternativeSourceCostsImpl { - +public class MorphAbility extends SpellAbility { protected static final String ABILITY_KEYWORD = "Morph"; protected static final String ABILITY_KEYWORD_MEGA = "Megamorph"; protected static final String REMINDER_TEXT = "You may cast this card face down as a " @@ -75,20 +76,22 @@ public class MorphAbility extends AlternativeSourceCostsImpl { // needed to check activation status, if card changes zone after casting it private final boolean megamorph; - public MorphAbility(Cost morphCost) { - this(morphCost, false); + public MorphAbility(Card card, Cost morphCost) { + this(card, morphCost, false); } - public MorphAbility(Cost morphCost, boolean megamorph) { - super(megamorph ? ABILITY_KEYWORD_MEGA : ABILITY_KEYWORD, megamorph ? REMINDER_TEXT_MEGA : REMINDER_TEXT, new GenericManaCost(3)); + public MorphAbility(Card card, Cost morphCost, boolean megamorph) { + super(new GenericManaCost(3), card.getName() + " with " + ABILITY_KEYWORD); this.morphCosts = new CostsImpl<>(); this.morphCosts.add(morphCost); this.megamorph = megamorph; + this.setSpellAbilityCastMode(SpellAbilityCastMode.MORPH); this.setWorksFaceDown(true); Ability ability = new SimpleStaticAbility(new BecomesFaceDownCreatureEffect( morphCosts, (megamorph ? FaceDownType.MEGAMORPHED : FaceDownType.MORPHED))); ability.setWorksFaceDown(true); ability.setRuleVisible(false); + this.timing = TimingRule.SORCERY; addSubAbility(ability); } @@ -103,28 +106,6 @@ public class MorphAbility extends AlternativeSourceCostsImpl { return new MorphAbility(this); } - @Override - public boolean askToActivateAlternativeCosts(Ability ability, Game game) { - switch (ability.getAbilityType()) { - case SPELL: - Spell spell = game.getStack().getSpell(ability.getId()); - if (spell != null) { - spell.setFaceDown(true, game); - if (handleActivatingAlternativeCosts(ability, game)) { - game.getState().setValue("MorphAbility" + ability.getSourceId(), "activated"); - spell.getColor(game).setColor(null); - game.getState().getCreateMageObjectAttribute(spell.getCard(), game).getSubtype().clear(); - } else { - spell.setFaceDown(false, game); - } - } - break; - case PLAY_LAND: - handleActivatingAlternativeCosts(ability, game); - } - return isActivated(ability, game); - } - public Costs getMorphCosts() { return morphCosts; } @@ -132,8 +113,10 @@ public class MorphAbility extends AlternativeSourceCostsImpl { @Override public String getRule() { boolean isMana = morphCosts.get(0) instanceof ManaCost; - return alternativeCost.getName() + (isMana ? " " : "—") + - morphCosts.getText() + (isMana ? ' ' : ". ") + alternativeCost.getReminderText(); + String name = megamorph ? ABILITY_KEYWORD_MEGA : ABILITY_KEYWORD; + String reminder = megamorph ? REMINDER_TEXT_MEGA : REMINDER_TEXT; + return name + (isMana ? " " : "—") + + morphCosts.getText() + (isMana ? ' ' : ". ") + reminder; } /** @@ -144,16 +127,7 @@ public class MorphAbility extends AlternativeSourceCostsImpl { * @param game */ public static void setPermanentToFaceDownCreature(MageObject targetObject, Permanent sourcePermanent, Game game) { - targetObject.getPower().setModifiedBaseValue(2); - targetObject.getToughness().setModifiedBaseValue(2); - targetObject.getAbilities().clear(); - targetObject.getColor(game).setColor(new ObjectColor()); - targetObject.setName(""); - targetObject.removeAllCardTypes(game); - targetObject.addCardType(game, CardType.CREATURE); - targetObject.removeAllSubTypes(game); - targetObject.removeAllSuperTypes(game); - targetObject.getManaCost().clear(); + setObjectToFaceDownCreature(targetObject, game); Token emptyImage = new EmptyToken(); @@ -169,4 +143,16 @@ public class MorphAbility extends AlternativeSourceCostsImpl { throw new IllegalArgumentException("Wrong code usage: un-supported targetObject in face down method: " + targetObject.getClass().getSimpleName()); } } + public static void setObjectToFaceDownCreature(MageObject targetObject, Game game) { + targetObject.getPower().setModifiedBaseValue(2); + targetObject.getToughness().setModifiedBaseValue(2); + targetObject.getAbilities().clear(); + targetObject.getColor(game).setColor(new ObjectColor()); + targetObject.setName(""); + targetObject.removeAllCardTypes(game); + targetObject.addCardType(game, CardType.CREATURE); + targetObject.removeAllSubTypes(game); + targetObject.removeAllSuperTypes(game); + targetObject.getManaCost().clear(); + } } diff --git a/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java b/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java index 30ed5de09a7..1f4515f88d5 100644 --- a/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java +++ b/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java @@ -1,6 +1,7 @@ package mage.constants; import mage.abilities.keyword.BestowAbility; +import mage.abilities.keyword.MorphAbility; import mage.cards.Card; import mage.game.Game; @@ -12,6 +13,7 @@ public enum SpellAbilityCastMode { MADNESS("Madness"), FLASHBACK("Flashback"), BESTOW("Bestow"), + MORPH("Morph"), TRANSFORMED("Transformed", true), DISTURB("Disturb", true), MORE_THAN_MEETS_THE_EYE("More than Meets the Eye", true); @@ -49,6 +51,8 @@ public enum SpellAbilityCastMode { if (tmp != null) { cardCopy = tmp.copy(); } + if (this.equals(MORPH)) { + MorphAbility.setObjectToFaceDownCreature(cardCopy, game); } return cardCopy; } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index bd7c7e6e0c1..7bc08303fb3 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -5,7 +5,6 @@ import mage.MageObject; import mage.Mana; import mage.ObjectColor; import mage.abilities.*; -import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.mana.ActivationManaAbilityStep; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; @@ -80,6 +79,9 @@ public class Spell extends StackObjectImpl implements Card { // simulate another side as new card (another code part in continues effect from disturb ability) affectedCard = TransformAbility.transformCardSpellStatic(card, card.getSecondCardFace(), game); } + if (ability.getSpellAbilityCastMode() == SpellAbilityCastMode.MORPH){ + this.faceDown = true; + } this.card = affectedCard; this.color = affectedCard.getColor(null).copy(); @@ -182,11 +184,8 @@ public class Spell extends StackObjectImpl implements Card { } public String getSpellCastText(Game game) { - for (Ability spellAbility : getAbilities()) { - if (spellAbility instanceof MorphAbility - && ((AlternativeSourceCosts) spellAbility).isActivated(getSpellAbility(), game)) { - return "a card face down"; - } + if (this.getSpellAbility() instanceof MorphAbility) { + return "a card face down"; } if (card instanceof AdventureCardSpell) {