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

View file

@ -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<Cost> 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 ? " " : "&mdash;") +
morphCosts.getText() + (isMana ? ' ' : ". ") + alternativeCost.getReminderText();
String name = megamorph ? ABILITY_KEYWORD_MEGA : ABILITY_KEYWORD;
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
*/
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();
}
}

View file

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

View file

@ -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,12 +184,9 @@ 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)) {
if (this.getSpellAbility() instanceof MorphAbility) {
return "a card face down";
}
}
if (card instanceof AdventureCardSpell) {
AdventureCard adventureCard = ((AdventureCardSpell) card).getParentCard();