Make Morph a SpellAbility (part 1)

This commit is contained in:
Steven Knipe 2023-09-18 02:48:30 -07:00
parent 9b634d44c6
commit 3e4d439d18
4 changed files with 38 additions and 48 deletions

View file

@ -436,6 +436,7 @@ public abstract class AbilityImpl implements Ability {
case DISTURB: case DISTURB:
case MORE_THAN_MEETS_THE_EYE: case MORE_THAN_MEETS_THE_EYE:
case BESTOW: case BESTOW:
case MORPH:
// from Snapcaster Mage: // from Snapcaster Mage:
// If you cast a spell from a graveyard using its flashback ability, you can't pay other alternative costs // 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) // (such as that of Foil). (2018-12-07)

View file

@ -3,8 +3,8 @@ package mage.abilities.keyword;
import mage.MageObject; import mage.MageObject;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.AlternativeSourceCostsImpl;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs; import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl; import mage.abilities.costs.CostsImpl;
@ -12,13 +12,15 @@ import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType;
import mage.cards.Card;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SpellAbilityCastMode;
import mage.constants.TimingRule;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.EmptyToken; import mage.game.permanent.token.EmptyToken;
import mage.game.permanent.token.Token; import mage.game.permanent.token.Token;
import mage.game.stack.Spell;
import mage.util.CardUtil; import mage.util.CardUtil;
/** /**
@ -62,8 +64,7 @@ import mage.util.CardUtil;
* *
* @author LevelX2 * @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 = "Morph";
protected static final String ABILITY_KEYWORD_MEGA = "Megamorph"; protected static final String ABILITY_KEYWORD_MEGA = "Megamorph";
protected static final String REMINDER_TEXT = "You may cast this card face down as a " 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 // needed to check activation status, if card changes zone after casting it
private final boolean megamorph; private final boolean megamorph;
public MorphAbility(Cost morphCost) { public MorphAbility(Card card, Cost morphCost) {
this(morphCost, false); this(card, morphCost, false);
} }
public MorphAbility(Cost morphCost, boolean megamorph) { public MorphAbility(Card card, Cost morphCost, boolean megamorph) {
super(megamorph ? ABILITY_KEYWORD_MEGA : ABILITY_KEYWORD, megamorph ? REMINDER_TEXT_MEGA : REMINDER_TEXT, new GenericManaCost(3)); super(new GenericManaCost(3), card.getName() + " with " + ABILITY_KEYWORD);
this.morphCosts = new CostsImpl<>(); this.morphCosts = new CostsImpl<>();
this.morphCosts.add(morphCost); this.morphCosts.add(morphCost);
this.megamorph = megamorph; this.megamorph = megamorph;
this.setSpellAbilityCastMode(SpellAbilityCastMode.MORPH);
this.setWorksFaceDown(true); this.setWorksFaceDown(true);
Ability ability = new SimpleStaticAbility(new BecomesFaceDownCreatureEffect( Ability ability = new SimpleStaticAbility(new BecomesFaceDownCreatureEffect(
morphCosts, (megamorph ? FaceDownType.MEGAMORPHED : FaceDownType.MORPHED))); morphCosts, (megamorph ? FaceDownType.MEGAMORPHED : FaceDownType.MORPHED)));
ability.setWorksFaceDown(true); ability.setWorksFaceDown(true);
ability.setRuleVisible(false); ability.setRuleVisible(false);
this.timing = TimingRule.SORCERY;
addSubAbility(ability); addSubAbility(ability);
} }
@ -103,28 +106,6 @@ public class MorphAbility extends AlternativeSourceCostsImpl {
return new MorphAbility(this); 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<Cost> getMorphCosts() { public Costs<Cost> getMorphCosts() {
return morphCosts; return morphCosts;
} }
@ -132,8 +113,10 @@ public class MorphAbility extends AlternativeSourceCostsImpl {
@Override @Override
public String getRule() { public String getRule() {
boolean isMana = morphCosts.get(0) instanceof ManaCost; boolean isMana = morphCosts.get(0) instanceof ManaCost;
return alternativeCost.getName() + (isMana ? " " : "&mdash;") + String name = megamorph ? ABILITY_KEYWORD_MEGA : ABILITY_KEYWORD;
morphCosts.getText() + (isMana ? ' ' : ". ") + alternativeCost.getReminderText(); String reminder = megamorph ? REMINDER_TEXT_MEGA : REMINDER_TEXT;
return name + (isMana ? " " : "&mdash;") +
morphCosts.getText() + (isMana ? ' ' : ". ") + reminder;
} }
/** /**
@ -144,16 +127,7 @@ public class MorphAbility extends AlternativeSourceCostsImpl {
* @param game * @param game
*/ */
public static void setPermanentToFaceDownCreature(MageObject targetObject, Permanent sourcePermanent, Game game) { public static void setPermanentToFaceDownCreature(MageObject targetObject, Permanent sourcePermanent, Game game) {
targetObject.getPower().setModifiedBaseValue(2); setObjectToFaceDownCreature(targetObject, game);
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();
Token emptyImage = new EmptyToken(); 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()); 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();
}
} }

View file

@ -1,6 +1,7 @@
package mage.constants; package mage.constants;
import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.BestowAbility;
import mage.abilities.keyword.MorphAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.game.Game; import mage.game.Game;
@ -12,6 +13,7 @@ public enum SpellAbilityCastMode {
MADNESS("Madness"), MADNESS("Madness"),
FLASHBACK("Flashback"), FLASHBACK("Flashback"),
BESTOW("Bestow"), BESTOW("Bestow"),
MORPH("Morph"),
TRANSFORMED("Transformed", true), TRANSFORMED("Transformed", true),
DISTURB("Disturb", true), DISTURB("Disturb", true),
MORE_THAN_MEETS_THE_EYE("More than Meets the Eye", true); MORE_THAN_MEETS_THE_EYE("More than Meets the Eye", true);
@ -49,6 +51,8 @@ public enum SpellAbilityCastMode {
if (tmp != null) { if (tmp != null) {
cardCopy = tmp.copy(); cardCopy = tmp.copy();
} }
if (this.equals(MORPH)) {
MorphAbility.setObjectToFaceDownCreature(cardCopy, game);
} }
return cardCopy; return cardCopy;
} }

View file

@ -5,7 +5,6 @@ import mage.MageObject;
import mage.Mana; import mage.Mana;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.*; import mage.abilities.*;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.mana.ActivationManaAbilityStep; import mage.abilities.costs.mana.ActivationManaAbilityStep;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts; 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) // simulate another side as new card (another code part in continues effect from disturb ability)
affectedCard = TransformAbility.transformCardSpellStatic(card, card.getSecondCardFace(), game); affectedCard = TransformAbility.transformCardSpellStatic(card, card.getSecondCardFace(), game);
} }
if (ability.getSpellAbilityCastMode() == SpellAbilityCastMode.MORPH){
this.faceDown = true;
}
this.card = affectedCard; this.card = affectedCard;
this.color = affectedCard.getColor(null).copy(); this.color = affectedCard.getColor(null).copy();
@ -182,11 +184,8 @@ public class Spell extends StackObjectImpl implements Card {
} }
public String getSpellCastText(Game game) { public String getSpellCastText(Game game) {
for (Ability spellAbility : getAbilities()) { if (this.getSpellAbility() instanceof MorphAbility) {
if (spellAbility instanceof MorphAbility return "a card face down";
&& ((AlternativeSourceCosts) spellAbility).isActivated(getSpellAbility(), game)) {
return "a card face down";
}
} }
if (card instanceof AdventureCardSpell) { if (card instanceof AdventureCardSpell) {