mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
Fix casting Transformed (#10778)
* Combine casting Transformed into a shared SpellAbility, apply transform effect before spell is cast * Minor cleanup * Use effect.apply() rather than game.applyEffects() * Add test with Maskwood Nexus
This commit is contained in:
parent
8859637844
commit
b6dbc782be
9 changed files with 259 additions and 172 deletions
|
|
@ -4,7 +4,6 @@ import mage.ApprovingObject;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -13,9 +12,7 @@ import mage.counters.CounterType;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
|
|
@ -109,39 +106,9 @@ class SiegeDefeatedEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getSecondCardFace().getId(), Boolean.TRUE);
|
||||
if (player.cast(card.getSecondFaceSpellAbility(), game, true, new ApprovingObject(source, game))) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId(), Boolean.TRUE);
|
||||
game.addEffect(new SiegeTransformEffect().setTargetPointer(new FixedTarget(card, game)), source);
|
||||
}
|
||||
SpellTransformedAbility transformedSpell = new SpellTransformedAbility(card.getSecondFaceSpellAbility());
|
||||
player.cast(transformedSpell, game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getSecondCardFace().getId(), null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SiegeTransformEffect extends ContinuousEffectImpl {
|
||||
|
||||
public SiegeTransformEffect() {
|
||||
super(Duration.WhileOnStack, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature);
|
||||
}
|
||||
|
||||
private SiegeTransformEffect(final SiegeTransformEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SiegeTransformEffect copy() {
|
||||
return new SiegeTransformEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Spell spell = game.getSpell(getTargetPointer().getFirst(game, source));
|
||||
if (spell == null || spell.getCard().getSecondCardFace() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// simulate another side as new card (another code part in spell constructor)
|
||||
TransformAbility.transformCardSpellDynamic(spell, spell.getCard().getSecondCardFace(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author weirddan455, JayDi85, notgreat
|
||||
*/
|
||||
public class SpellTransformedAbility extends SpellAbility {
|
||||
|
||||
protected final String manaCost; //This variable is only used for rules text
|
||||
|
||||
public SpellTransformedAbility(Card card, String manaCost) {
|
||||
super(card.getSecondFaceSpellAbility());
|
||||
this.newId();
|
||||
|
||||
// getSecondFaceSpellAbility() already verified that second face exists
|
||||
this.setCardName(card.getSecondCardFace().getName());
|
||||
|
||||
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
this.setSpellAbilityCastMode(SpellAbilityCastMode.TRANSFORMED);
|
||||
|
||||
this.manaCost = manaCost;
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(manaCost));
|
||||
this.addSubAbility(new TransformAbility());
|
||||
}
|
||||
|
||||
public SpellTransformedAbility(final SpellAbility ability) {
|
||||
super(ability);
|
||||
this.newId();
|
||||
|
||||
this.manaCost = null;
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
|
||||
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
this.setSpellAbilityCastMode(SpellAbilityCastMode.TRANSFORMED);
|
||||
//when casting this way, the card must have the TransformAbility from elsewhere
|
||||
}
|
||||
protected SpellTransformedAbility(final SpellTransformedAbility ability) {
|
||||
super(ability);
|
||||
this.manaCost = ability.manaCost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellTransformedAbility copy() {
|
||||
return new SpellTransformedAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
if (super.activate(game, noMana)) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE);
|
||||
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
|
||||
TransformedEffect effect = new TransformedEffect();
|
||||
game.addEffect(effect, this);
|
||||
effect.apply(game, this); //Apply the effect immediately
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game).canActivate()) {
|
||||
Card card = game.getCard(getSourceId());
|
||||
if (card != null) {
|
||||
return card.getSpellAbility().canActivate(playerId, game);
|
||||
}
|
||||
}
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
}
|
||||
|
||||
class TransformedEffect extends ContinuousEffectImpl {
|
||||
|
||||
public TransformedEffect() {
|
||||
super(Duration.WhileOnStack, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature);
|
||||
staticText = "";
|
||||
}
|
||||
|
||||
private TransformedEffect(final TransformedEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedEffect copy() {
|
||||
return new TransformedEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Spell spell = game.getSpell(source.getSourceId());
|
||||
if (spell == null || spell.getCard().getSecondCardFace() == null) {
|
||||
return false;
|
||||
}
|
||||
// simulate another side as new card (another code part in spell constructor)
|
||||
TransformAbility.transformCardSpellDynamic(spell, spell.getCard().getSecondCardFace(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,9 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.common.SpellTransformedAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -22,35 +18,18 @@ import java.util.UUID;
|
|||
* 702.146b A resolving transforming double-faced spell that was cast using its disturb
|
||||
* ability enters the battlefield with its back face up.
|
||||
*
|
||||
* @author weirddan455, JayDi85
|
||||
* @author notgreat, weirddan455, JayDi85
|
||||
*/
|
||||
public class DisturbAbility extends SpellAbility {
|
||||
|
||||
private final String manaCost;
|
||||
private SpellAbility spellAbilityToResolve;
|
||||
|
||||
public class DisturbAbility extends SpellTransformedAbility {
|
||||
public DisturbAbility(Card card, String manaCost) {
|
||||
super(card.getSecondFaceSpellAbility());
|
||||
this.newId();
|
||||
|
||||
// getSecondFaceSpellAbility() already verified that second face exists
|
||||
this.setCardName(card.getSecondCardFace().getName());
|
||||
super(card, manaCost);
|
||||
|
||||
this.zone = Zone.GRAVEYARD;
|
||||
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
this.setSpellAbilityCastMode(SpellAbilityCastMode.DISTURB);
|
||||
|
||||
this.manaCost = manaCost;
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(manaCost));
|
||||
this.addSubAbility(new TransformAbility());
|
||||
}
|
||||
|
||||
private DisturbAbility(final DisturbAbility ability) {
|
||||
super(ability);
|
||||
this.manaCost = ability.manaCost;
|
||||
this.spellAbilityToResolve = ability.spellAbilityToResolve;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -58,17 +37,6 @@ public class DisturbAbility extends SpellAbility {
|
|||
return new DisturbAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
if (super.activate(game, noMana)) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE);
|
||||
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
|
||||
game.addEffect(new DisturbEffect(), this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game).canActivate()) {
|
||||
|
|
@ -91,36 +59,3 @@ public class DisturbAbility extends SpellAbility {
|
|||
+ " <i>(You may cast this card transformed from your graveyard for its disturb cost.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
class DisturbEffect extends ContinuousEffectImpl {
|
||||
|
||||
public DisturbEffect() {
|
||||
super(Duration.WhileOnStack, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature);
|
||||
staticText = "";
|
||||
}
|
||||
|
||||
private DisturbEffect(final DisturbEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisturbEffect copy() {
|
||||
return new DisturbEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Spell spell = game.getSpell(source.getSourceId());
|
||||
if (spell == null || spell.getFromZone() != Zone.GRAVEYARD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spell.getCard().getSecondCardFace() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// simulate another side as new card (another code part in spell constructor)
|
||||
TransformAbility.transformCardSpellDynamic(spell, spell.getCard().getSecondCardFace(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,22 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.common.SpellTransformedAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
/**
|
||||
* @author weirddan455, JayDi85, TheElk801 (based heavily on disturb)
|
||||
* @author notgreat, TheElk801
|
||||
*/
|
||||
public class MoreThanMeetsTheEyeAbility extends SpellAbility {
|
||||
public class MoreThanMeetsTheEyeAbility extends SpellTransformedAbility {
|
||||
|
||||
private final String manaCost;
|
||||
private SpellAbility spellAbilityToResolve;
|
||||
|
||||
public MoreThanMeetsTheEyeAbility(Card card, String manaCost) {
|
||||
super(card.getSecondFaceSpellAbility());
|
||||
this.newId();
|
||||
|
||||
// getSecondFaceSpellAbility() already verified that second face exists
|
||||
this.setCardName(card.getSecondCardFace().getName());
|
||||
|
||||
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
super(card, manaCost);
|
||||
this.setSpellAbilityCastMode(SpellAbilityCastMode.MORE_THAN_MEETS_THE_EYE);
|
||||
|
||||
this.manaCost = manaCost;
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(manaCost));
|
||||
this.addSubAbility(new TransformAbility());
|
||||
}
|
||||
|
||||
private MoreThanMeetsTheEyeAbility(final MoreThanMeetsTheEyeAbility ability) {
|
||||
super(ability);
|
||||
this.manaCost = ability.manaCost;
|
||||
this.spellAbilityToResolve = ability.spellAbilityToResolve;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -45,17 +24,6 @@ public class MoreThanMeetsTheEyeAbility extends SpellAbility {
|
|||
return new MoreThanMeetsTheEyeAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
if (super.activate(game, noMana)) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE);
|
||||
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
|
||||
game.addEffect(new MoreThanMeetsTheEyeEffect(), this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule(boolean all) {
|
||||
return this.getRule();
|
||||
|
|
@ -67,31 +35,3 @@ public class MoreThanMeetsTheEyeAbility extends SpellAbility {
|
|||
+ " <i>(You may cast this card converted for " + this.manaCost + ".)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
class MoreThanMeetsTheEyeEffect extends ContinuousEffectImpl {
|
||||
|
||||
public MoreThanMeetsTheEyeEffect() {
|
||||
super(Duration.WhileOnStack, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature);
|
||||
staticText = "";
|
||||
}
|
||||
|
||||
private MoreThanMeetsTheEyeEffect(final MoreThanMeetsTheEyeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoreThanMeetsTheEyeEffect copy() {
|
||||
return new MoreThanMeetsTheEyeEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Spell spell = game.getSpell(source.getSourceId());
|
||||
if (spell == null || spell.getCard().getSecondCardFace() == null) {
|
||||
return false;
|
||||
}
|
||||
// simulate another side as new card (another code part in spell constructor)
|
||||
TransformAbility.transformCardSpellDynamic(spell, spell.getCard().getSecondCardFace(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@ public enum SpellAbilityCastMode {
|
|||
if (this.equals(BESTOW)) {
|
||||
BestowAbility.becomeAura(cardCopy);
|
||||
}
|
||||
if (this.isTransformed){
|
||||
Card tmp = card.getSecondCardFace();
|
||||
if (tmp != null) {
|
||||
cardCopy = tmp.copy();
|
||||
}
|
||||
}
|
||||
return cardCopy;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -774,7 +774,7 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
|
||||
@Override
|
||||
public Card getSecondCardFace() {
|
||||
return null;
|
||||
return card.getSecondCardFace();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue