[MID] Implemented Disturb mechanic (#8201)

* [MID] Implemented Disturb mechanic

Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
Co-authored-by: Evan Kranzler <theelk801@gmail.com>
This commit is contained in:
Daniel Bomar 2021-11-09 00:12:50 -06:00 committed by GitHub
parent 1195016399
commit 7082b86eb3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 230 additions and 111 deletions

View file

@ -3,7 +3,6 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -26,8 +25,7 @@ public final class BaithookAngler extends CardImpl {
this.secondSideCardClazz = mage.cards.h.HookHauntDrifter.class;
// Disturb {1}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{1}{U}")));
this.addAbility(new DisturbAbility(this, "{1}{U}"));
}
private BaithookAngler(final BaithookAngler card) {

View file

@ -1,18 +1,16 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TimingRule;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author weirddan455
*/
public final class BelovedBeggar extends CardImpl {
@ -28,8 +26,7 @@ public final class BelovedBeggar extends CardImpl {
this.secondSideCardClazz = mage.cards.g.GenerousSoul.class;
// Disturb {4}{W}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{4}{W}{W}")));
this.addAbility(new DisturbAbility(this, "{4}{W}{W}"));
}
private BelovedBeggar(final BelovedBeggar card) {

View file

@ -33,7 +33,7 @@ public final class BindingGeist extends CardImpl {
this.addAbility(ability);
// Disturb {1}{U}
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{1}{U}")));
this.addAbility(new DisturbAbility(this, "{1}{U}"));
}
private BindingGeist(final BindingGeist card) {

View file

@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.TransformAbility;
import mage.abilities.keyword.WardAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -34,8 +33,7 @@ public final class ChaplainOfAlms extends CardImpl {
this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}")));
// Disturb {3}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{W}")));
this.addAbility(new DisturbAbility(this, "{3}{W}"));
}
private ChaplainOfAlms(final ChaplainOfAlms card) {

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import java.util.UUID;
@ -17,6 +16,7 @@ public final class Counterspell extends CardImpl {
public Counterspell(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}{U}");
// Counter target spell.
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addTarget(new TargetSpell());
}

View file

@ -6,7 +6,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -47,8 +46,7 @@ public final class CovertCutpurse extends CardImpl {
this.addAbility(ability);
// Disturb {4}{B}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{4}{B}")));
this.addAbility(new DisturbAbility(this, "{4}{B}"));
}
private CovertCutpurse(final CovertCutpurse card) {

View file

@ -5,7 +5,6 @@ import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.MillCardsControllerEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -30,8 +29,7 @@ public final class CovetousCastaway extends CardImpl {
this.addAbility(new DiesSourceTriggeredAbility(new MillCardsControllerEffect(3)));
// Disturb {3}{U}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{U}{U}")));
this.addAbility(new DisturbAbility(this, "{3}{U}{U}"));
}
private CovetousCastaway(final CovetousCastaway card) {

View file

@ -6,7 +6,6 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CantBeTargetedCardsGraveyardsEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -38,8 +37,7 @@ public final class DennickPiousApprentice extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedCardsGraveyardsEffect()));
// Disturb {2}{W}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{2}{W}{U}")));
this.addAbility(new DisturbAbility(this, "{2}{W}{U}"));
}

View file

@ -7,7 +7,6 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.MillCardsControllerEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -41,8 +40,7 @@ public final class DevotedGrafkeeper extends CardImpl {
this.addAbility(new DevotedGrafkeeperTriggeredAbility());
// Disturb {1}{W}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{1}{W}{U}")));
this.addAbility(new DisturbAbility(this, "{1}{W}{U}"));
}
private DevotedGrafkeeper(final DevotedGrafkeeper card) {

View file

@ -6,7 +6,6 @@ import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -44,8 +43,7 @@ public final class DistractingGeist extends CardImpl {
this.addAbility(ability);
// Disturb {4}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{4}{W}")));
this.addAbility(new DisturbAbility(this, "{4}{W}"));
}
private DistractingGeist(final DistractingGeist card) {

View file

@ -25,7 +25,7 @@ public final class DrogskolInfantry extends CardImpl {
this.secondSideCardClazz = mage.cards.d.DrogskolArmaments.class;
// Disturb {3}{W}
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{W}")));
this.addAbility(new DisturbAbility(this, "{3}{W}"));
}
private DrogskolInfantry(final DrogskolInfantry card) {

View file

@ -10,7 +10,10 @@ import mage.abilities.decorator.ConditionalAsThoughEffect;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.*;
import mage.abilities.keyword.DefenderAbility;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -63,8 +66,7 @@ public final class FaithboundJudge extends CardImpl {
" it can attack as though it didn't have defender")));
// Disturb {5}{W}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{5}{W}{W}")));
this.addAbility(new DisturbAbility(this, "{5}{W}{W}"));
}
private FaithboundJudge(final FaithboundJudge card) {

View file

@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -29,8 +28,7 @@ public final class Galedrifter extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Disturb {4}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{4}{U}")));
this.addAbility(new DisturbAbility(this, "{4}{U}"));
}
private Galedrifter(final Galedrifter card) {

View file

@ -7,7 +7,6 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalRestrictionEffect;
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -37,8 +36,7 @@ public final class GutterSkulker extends CardImpl {
)));
// Disturb {3}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{U}")));
this.addAbility(new DisturbAbility(this, "{3}{U}"));
}
private GutterSkulker(final GutterSkulker card) {

View file

@ -8,7 +8,10 @@ import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.*;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.ProtectionAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@ -63,8 +66,7 @@ public final class KatildaDawnhartMartyr extends CardImpl {
).addHint(hint));
// Disturb {3}{W}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{W}{W}")));
this.addAbility(new DisturbAbility(this, "{3}{W}{W}"));
}
private KatildaDawnhartMartyr(final KatildaDawnhartMartyr card) {

View file

@ -28,7 +28,7 @@ public final class KindlyAncestor extends CardImpl {
this.addAbility(LifelinkAbility.getInstance());
// Disturb {1}{W}
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{1}{W}")));
this.addAbility(new DisturbAbility(this, "{1}{W}"));
}
private KindlyAncestor(final KindlyAncestor card) {

View file

@ -1,35 +1,34 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.keyword.TransformAbility;
import mage.constants.SubType;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class LanternBearer extends CardImpl {
public LanternBearer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}");
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(1);
this.toughness = new MageInt(1);this.secondSideCardClazz=mage.cards.l.LanternsLift.class;
this.toughness = new MageInt(1);
this.secondSideCardClazz = mage.cards.l.LanternsLift.class;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Disturb {2}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{2}{U}")));
this.addAbility(new DisturbAbility(this, "{2}{U}"));
}
private LanternBearer(final LanternBearer card) {

View file

@ -5,7 +5,6 @@ import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -34,8 +33,7 @@ public final class LunarchVeteran extends CardImpl {
));
// Disturb {1}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{1}{W}")));
this.addAbility(new DisturbAbility(this, "{1}{W}"));
}
private LunarchVeteran(final LunarchVeteran card) {

View file

@ -8,7 +8,6 @@ import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -41,8 +40,7 @@ public final class MalevolentHermit extends CardImpl {
this.addAbility(ability);
// Disturb {2}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{2}{U}")));
this.addAbility(new DisturbAbility(this, "{2}{U}"));
}
private MalevolentHermit(final MalevolentHermit card) {

View file

@ -5,7 +5,6 @@ import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -33,8 +32,7 @@ public final class MischievousCatgeist extends CardImpl {
));
// Disturb {2}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{2}{U}")));
this.addAbility(new DisturbAbility(this, "{2}{U}"));
}
private MischievousCatgeist(final MischievousCatgeist card) {

View file

@ -3,7 +3,6 @@ package mage.cards.m;
import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -30,8 +29,7 @@ public final class MourningPatrol extends CardImpl {
this.addAbility(VigilanceAbility.getInstance());
// Disturb {3}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{W}")));
this.addAbility(new DisturbAbility(this, "{3}{W}"));
}
private MourningPatrol(final MourningPatrol card) {

View file

@ -5,7 +5,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -31,8 +30,7 @@ public final class OverwhelmedArchivist extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(1, 1)));
// Disturb {3}{U}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{3}{U}")));
this.addAbility(new DisturbAbility(this, "{3}{U}"));
}
private OverwhelmedArchivist(final OverwhelmedArchivist card) {

View file

@ -1,4 +1,3 @@
package mage.cards.s;
import mage.MageInt;
@ -41,11 +40,11 @@ public final class SnapcasterMage extends CardImpl {
// Flash
this.addAbility(FlashAbility.getInstance());
// When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost.
Ability ability = new EntersBattlefieldTriggeredAbility(new SnapcasterMageEffect());
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
}
private SnapcasterMage(final SnapcasterMage card) {

View file

@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -30,8 +29,7 @@ public final class TwinbladeGeist extends CardImpl {
this.addAbility(DoubleStrikeAbility.getInstance());
// Disturb {2}{W}
this.addAbility(new TransformAbility());
this.addAbility(new DisturbAbility(new ManaCostsImpl<>("{2}{W}")));
this.addAbility(new DisturbAbility(this, "{2}{W}"));
}
private TwinbladeGeist(final TwinbladeGeist card) {

View file

@ -4,15 +4,11 @@ import mage.cards.ExpansionSet;
import mage.constants.Rarity;
import mage.constants.SetType;
import java.util.Arrays;
import java.util.List;
/**
* @author TheElk801
*/
public final class InnistradCrimsonVow extends ExpansionSet {
private static final List<String> unfinished = Arrays.asList("Binding Geist", "Spectral Binding", "Brine Comber", "Brinebound Gift", "Distracting Geist", "Clever Distraction", "Dorothea, Vengeful Victim", "Dorothea's Retribution", "Drogskol Infantry", "Drogskol Armaments", "Faithbound Judge", "Sinner's Judgment", "Gutter Skulker", "Gutter Shortcut", "Katilda, Dawnhart Martyr", "Katilda's Rising Dawn", "Kindly Ancestor", "Ancestor's Embrace", "Lantern Bearer", "Lanterns' Lift", "Mirrorhall Mimic", "Ghastly Mimicry", "Mischievous Catgeist", "Catlike Curiosity", "Twinblade Geist", "Twinblade Invocation");
private static final InnistradCrimsonVow instance = new InnistradCrimsonVow();
public static InnistradCrimsonVow getInstance() {
@ -319,7 +315,5 @@ public final class InnistradCrimsonVow extends ExpansionSet {
cards.add(new SetCardInfo("Wolfkin Outcast", 229, Rarity.UNCOMMON, mage.cards.w.WolfkinOutcast.class));
cards.add(new SetCardInfo("Wrathful Jailbreaker", 184, Rarity.COMMON, mage.cards.w.WrathfulJailbreaker.class));
cards.add(new SetCardInfo("Wretched Throng", 91, Rarity.COMMON, mage.cards.w.WretchedThrong.class));
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is fully implemented
}
}

View file

@ -9,7 +9,6 @@ import mage.constants.Rarity;
import mage.constants.SetType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -17,7 +16,6 @@ import java.util.List;
*/
public final class InnistradMidnightHunt extends ExpansionSet {
private static final List<String> unfinished = Arrays.asList("Baithook Angler", "Hook-Haunt Drifter", "Beloved Beggar", "Generous Soul", "Chaplain of Alms", "Chapel Shieldgeist", "Covert Cutpurse", "Covetous Geist", "Covetous Castaway", "Ghostly Castigator", "Dennick, Pious Apprentice", "Dennick, Pious Apparition", "Devoted Grafkeeper", "Departed Soulkeeper", "Galedrifter", "Waildrifter", "Lunarch Veteran", "Luminous Phantom", "Malevolent Hermit", "Benevolent Geist", "Mourning Patrol", "Morning Apparition", "Overwhelmed Archivist", "Archive Haunt", "Phantom Carriage", "Shipwreck Sifters", "Thraben Exorcism", "Unblinking Observer");
private static final InnistradMidnightHunt instance = new InnistradMidnightHunt();
public static InnistradMidnightHunt getInstance() {
@ -506,15 +504,12 @@ public final class InnistradMidnightHunt extends ExpansionSet {
cards.add(new SetCardInfo("Winterthorn Blessing", 251, Rarity.UNCOMMON, mage.cards.w.WinterthornBlessing.class));
cards.add(new SetCardInfo("Wrenn and Seven", 208, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wrenn and Seven", 278, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS));
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is fully implemented
}
/*
@Override
public BoosterCollator createCollator() {
return new InnistradMidnightHuntCollator();
}
*/
}
// Booster collation info from https://www.lethe.xyz/mtg/collation/mid.html

View file

@ -432,6 +432,7 @@ public abstract class AbilityImpl implements Ability {
case FLASHBACK:
case MADNESS:
case DISTURB:
// from Snapcaster Mage:
// If you cast a spell from a graveyard using its flashback ability, you cant pay other alternative costs
// (such as that of Foil). (2018-12-07)

View file

@ -1,22 +1,129 @@
package mage.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.costs.Cost;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.Card;
import mage.constants.*;
import mage.game.Game;
import mage.game.stack.Spell;
import java.util.UUID;
/**
* @author weirddan455
* TODO: this is currently implemented in a pull request
* 702.146. Disturb
* <p>
* 702.146a Disturb is an ability found on the front face of some transforming double-faced cards
* (see rule 712, Double-Faced Cards). Disturb [cost] means You may cast this card
* transformed from your graveyard by paying [cost] rather than its mana cost. See
* rule 712.4b.
* <p>
* 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
*/
public class DisturbAbility extends SpellAbility {
public DisturbAbility(Cost cost) {
this(cost, TimingRule.SORCERY);
private final String manaCost;
private SpellAbility spellAbilityToResolve;
public DisturbAbility(Card card, String manaCost) {
super(card.getSpellAbility());
this.newId();
// verify check
if (card.getSecondCardFace() == null || card.getSecondCardFace().getClass().equals(card.getClass())) {
throw new IllegalArgumentException("Wrong code usage. Disturb ability can be added to double faces card only (main side).");
}
this.setCardName(card.getSecondCardFace().getName() + " with Disturb");
this.zone = Zone.GRAVEYARD;
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
this.spellAbilityCastMode = SpellAbilityCastMode.DISTURB;
this.manaCost = manaCost;
this.getManaCosts().clear();
this.getManaCostsToPay().clear();
this.addManaCost(new ManaCostsImpl(manaCost));
this.addSubAbility(new TransformAbility());
}
public DisturbAbility(Cost cost, TimingRule timingRule) {
super(null, "", Zone.GRAVEYARD, SpellAbilityType.BASE_ALTERNATE);
private DisturbAbility(final DisturbAbility ability) {
super(ability);
this.manaCost = ability.manaCost;
this.spellAbilityToResolve = ability.spellAbilityToResolve;
}
@Override
public DisturbAbility copy() {
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()) {
Card card = game.getCard(getSourceId());
if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) {
return card.getSpellAbility().canActivate(playerId, game);
}
}
return ActivationStatus.getFalse();
}
@Override
public String getRule(boolean all) {
return this.getRule();
}
@Override
public String getRule() {
return "Disturb " + this.manaCost
+ " <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;
}
}

View file

@ -7,7 +7,9 @@ import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.Card;
import mage.constants.*;
import mage.game.Game;
import mage.game.MageObjectAttribute;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
/**
* @author nantuko
@ -35,8 +37,7 @@ public class TransformAbility extends SimpleStaticAbility {
return "";
}
public static void transform(Permanent permanent, Card sourceCard, Game game, Ability source) {
public static void transformPermanent(Permanent permanent, Card sourceCard, Game game, Ability source) {
if (sourceCard == null) {
return;
}
@ -65,6 +66,48 @@ public class TransformAbility extends SimpleStaticAbility {
permanent.getPower().modifyBaseValue(sourceCard.getPower().getValue());
permanent.getToughness().modifyBaseValue(sourceCard.getToughness().getValue());
}
public static Card transformCardSpellStatic(Card mainSide, Card otherSide, Game game) {
// workaround to simulate transformed card on the stack (example: disturb ability)
// prepare static attributes
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
Card newCard = mainSide.copy();
newCard.setName(otherSide.getName());
newCard.getSuperType().clear();
// mana value must be from main side only
newCard.getManaCost().clear();
newCard.getManaCost().add(mainSide.getManaCost().copy());
for (SuperType type : otherSide.getSuperType()) {
newCard.addSuperType(type);
}
game.getState().getCardState(newCard.getId()).clearAbilities();
for (Ability ability : otherSide.getAbilities()) {
game.getState().addOtherAbility(newCard, ability);
}
newCard.getPower().modifyBaseValue(otherSide.getPower().getValue());
newCard.getToughness().modifyBaseValue(otherSide.getToughness().getValue());
return newCard;
}
public static void transformCardSpellDynamic(Spell spell, Card otherSide, Game game) {
// workaround to simulate transformed card on the stack (example: disturb ability)
// prepare dynamic attributes
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
MageObjectAttribute moa = game.getState().getCreateMageObjectAttribute(spell.getCard(), game);
moa.getColor().setColor(otherSide.getColor(game));
moa.getCardType().clear();
moa.getCardType().addAll(otherSide.getCardType(game));
moa.getSubtype().clear();
moa.getSubtype().addAll(otherSide.getSubtype(game));
game.getState().getCardState(spell.getCard().getId()).clearAbilities();
for (Ability ability : otherSide.getAbilities()) {
game.getState().addOtherAbility(spell.getCard(), ability);
}
}
}
class TransformEffect extends ContinuousEffectImpl {
@ -101,7 +144,7 @@ class TransformEffect extends ContinuousEffectImpl {
return false;
}
TransformAbility.transform(permanent, card, game, source);
TransformAbility.transformPermanent(permanent, card, game, source);
return true;

View file

@ -12,7 +12,8 @@ public enum SpellAbilityCastMode {
NORMAL("Normal"),
MADNESS("Madness"),
FLASHBACK("Flashback"),
BESTOW("Bestow");
BESTOW("Bestow"),
DISTURB("Disturb");
private final String text;

View file

@ -1889,7 +1889,7 @@ public abstract class GameImpl implements Game {
}
newBluePrint.assignNewId();
if (copyFromPermanent.isTransformed()) {
TransformAbility.transform(newBluePrint, newBluePrint.getSecondCardFace(), this, source);
TransformAbility.transformPermanent(newBluePrint, newBluePrint.getSecondCardFace(), this, source);
}
}
if (applier != null) {

View file

@ -75,7 +75,7 @@ public class PermanentCard extends PermanentImpl {
|| NightboundAbility.checkCard(this, game)) {
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId(), null);
setTransformed(true);
TransformAbility.transform(this, getSecondCardFace(), game, null);
TransformAbility.transformPermanent(this, getSecondCardFace(), game, null);
}
}
}

View file

@ -11,6 +11,7 @@ import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.keyword.BestowAbility;
import mage.abilities.keyword.MorphAbility;
import mage.abilities.keyword.TransformAbility;
import mage.abilities.text.TextPart;
import mage.cards.*;
import mage.constants.*;
@ -66,21 +67,29 @@ public class Spell extends StackObjectImpl implements Card {
private ActivationManaAbilityStep currentActivatingManaAbilitiesStep = ActivationManaAbilityStep.BEFORE;
public Spell(Card card, SpellAbility ability, UUID controllerId, Zone fromZone, Game game) {
this.card = card;
this.color = card.getColor(null).copy();
this.frameColor = card.getFrameColor(null).copy();
this.frameStyle = card.getFrameStyle();
Card affectedCard = card;
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
if (ability.getSpellAbilityCastMode() == SpellAbilityCastMode.DISTURB && affectedCard.getSecondCardFace() != null) {
// simulate another side as new card (another code part in continues effect from disturb ability)
affectedCard = TransformAbility.transformCardSpellStatic(card, card.getSecondCardFace(), game);
}
this.card = affectedCard;
this.color = affectedCard.getColor(null).copy();
this.frameColor = affectedCard.getFrameColor(null).copy();
this.frameStyle = affectedCard.getFrameStyle();
this.id = ability.getId();
this.zoneChangeCounter = card.getZoneChangeCounter(game); // sync card's ZCC with spell (copy spell settings)
this.zoneChangeCounter = affectedCard.getZoneChangeCounter(game); // sync card's ZCC with spell (copy spell settings)
this.ability = ability;
this.ability.setControllerId(controllerId);
if (ability.getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
spellCards.add(((SplitCard) card).getLeftHalfCard());
spellAbilities.add(((SplitCard) card).getLeftHalfCard().getSpellAbility().copy());
spellCards.add(((SplitCard) card).getRightHalfCard());
spellAbilities.add(((SplitCard) card).getRightHalfCard().getSpellAbility().copy());
spellCards.add(((SplitCard) affectedCard).getLeftHalfCard());
spellAbilities.add(((SplitCard) affectedCard).getLeftHalfCard().getSpellAbility().copy());
spellCards.add(((SplitCard) affectedCard).getRightHalfCard());
spellAbilities.add(((SplitCard) affectedCard).getRightHalfCard().getSpellAbility().copy());
} else {
spellCards.add(card);
spellCards.add(affectedCard);
spellAbilities.add(ability);
}
this.controllerId = controllerId;