From 7082b86eb38dac436203aacf3d2328ac2252af04 Mon Sep 17 00:00:00 2001 From: Daniel Bomar Date: Tue, 9 Nov 2021 00:12:50 -0600 Subject: [PATCH] [MID] Implemented Disturb mechanic (#8201) * [MID] Implemented Disturb mechanic Co-authored-by: Oleg Agafonov Co-authored-by: Evan Kranzler --- .../src/mage/cards/b/BaithookAngler.java | 4 +- Mage.Sets/src/mage/cards/b/BelovedBeggar.java | 11 +- Mage.Sets/src/mage/cards/b/BindingGeist.java | 2 +- .../src/mage/cards/c/ChaplainOfAlms.java | 4 +- Mage.Sets/src/mage/cards/c/Counterspell.java | 2 +- .../src/mage/cards/c/CovertCutpurse.java | 4 +- .../src/mage/cards/c/CovetousCastaway.java | 4 +- .../mage/cards/d/DennickPiousApprentice.java | 4 +- .../src/mage/cards/d/DevotedGrafkeeper.java | 4 +- .../src/mage/cards/d/DistractingGeist.java | 4 +- .../src/mage/cards/d/DrogskolInfantry.java | 2 +- .../src/mage/cards/f/FaithboundJudge.java | 8 +- Mage.Sets/src/mage/cards/g/Galedrifter.java | 4 +- Mage.Sets/src/mage/cards/g/GutterSkulker.java | 4 +- .../mage/cards/k/KatildaDawnhartMartyr.java | 8 +- .../src/mage/cards/k/KindlyAncestor.java | 2 +- Mage.Sets/src/mage/cards/l/LanternBearer.java | 17 ++- .../src/mage/cards/l/LunarchVeteran.java | 4 +- .../src/mage/cards/m/MalevolentHermit.java | 4 +- .../src/mage/cards/m/MischievousCatgeist.java | 4 +- .../src/mage/cards/m/MourningPatrol.java | 4 +- .../mage/cards/o/OverwhelmedArchivist.java | 4 +- .../src/mage/cards/s/SnapcasterMage.java | 3 +- .../src/mage/cards/t/TwinbladeGeist.java | 4 +- .../src/mage/sets/InnistradCrimsonVow.java | 6 - .../src/mage/sets/InnistradMidnightHunt.java | 7 +- .../main/java/mage/abilities/AbilityImpl.java | 1 + .../abilities/keyword/DisturbAbility.java | 127 ++++++++++++++++-- .../abilities/keyword/TransformAbility.java | 49 ++++++- .../mage/constants/SpellAbilityCastMode.java | 3 +- Mage/src/main/java/mage/game/GameImpl.java | 2 +- .../mage/game/permanent/PermanentCard.java | 2 +- Mage/src/main/java/mage/game/stack/Spell.java | 29 ++-- 33 files changed, 230 insertions(+), 111 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BaithookAngler.java b/Mage.Sets/src/mage/cards/b/BaithookAngler.java index 123f91a139..1c3126ea98 100644 --- a/Mage.Sets/src/mage/cards/b/BaithookAngler.java +++ b/Mage.Sets/src/mage/cards/b/BaithookAngler.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/b/BelovedBeggar.java b/Mage.Sets/src/mage/cards/b/BelovedBeggar.java index 30b98d5340..a07558efdd 100644 --- a/Mage.Sets/src/mage/cards/b/BelovedBeggar.java +++ b/Mage.Sets/src/mage/cards/b/BelovedBeggar.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/b/BindingGeist.java b/Mage.Sets/src/mage/cards/b/BindingGeist.java index a4f84c6be5..df255c2854 100644 --- a/Mage.Sets/src/mage/cards/b/BindingGeist.java +++ b/Mage.Sets/src/mage/cards/b/BindingGeist.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java b/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java index 68e2524ff5..a6dd19da76 100644 --- a/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java +++ b/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/c/Counterspell.java b/Mage.Sets/src/mage/cards/c/Counterspell.java index ec03747be9..b0e269c4c5 100644 --- a/Mage.Sets/src/mage/cards/c/Counterspell.java +++ b/Mage.Sets/src/mage/cards/c/Counterspell.java @@ -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()); } diff --git a/Mage.Sets/src/mage/cards/c/CovertCutpurse.java b/Mage.Sets/src/mage/cards/c/CovertCutpurse.java index 2065b9ee04..25f3911e34 100644 --- a/Mage.Sets/src/mage/cards/c/CovertCutpurse.java +++ b/Mage.Sets/src/mage/cards/c/CovertCutpurse.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/c/CovetousCastaway.java b/Mage.Sets/src/mage/cards/c/CovetousCastaway.java index a92f0b9f97..1fd6304818 100644 --- a/Mage.Sets/src/mage/cards/c/CovetousCastaway.java +++ b/Mage.Sets/src/mage/cards/c/CovetousCastaway.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java b/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java index 862393b75a..086bad1d31 100644 --- a/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java +++ b/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java @@ -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}")); } diff --git a/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java b/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java index 83b9adc4a0..b54e5ad709 100644 --- a/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java +++ b/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/d/DistractingGeist.java b/Mage.Sets/src/mage/cards/d/DistractingGeist.java index c56ceb113d..dbd48e0f47 100644 --- a/Mage.Sets/src/mage/cards/d/DistractingGeist.java +++ b/Mage.Sets/src/mage/cards/d/DistractingGeist.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java b/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java index 85881f557e..c83c5ccffe 100644 --- a/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java +++ b/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java index be8df152ef..96b377b841 100644 --- a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java +++ b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/g/Galedrifter.java b/Mage.Sets/src/mage/cards/g/Galedrifter.java index aff87e6ee3..c76b119844 100644 --- a/Mage.Sets/src/mage/cards/g/Galedrifter.java +++ b/Mage.Sets/src/mage/cards/g/Galedrifter.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/g/GutterSkulker.java b/Mage.Sets/src/mage/cards/g/GutterSkulker.java index 628a453833..674a82f29b 100644 --- a/Mage.Sets/src/mage/cards/g/GutterSkulker.java +++ b/Mage.Sets/src/mage/cards/g/GutterSkulker.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java b/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java index e21cd98a23..57b7680039 100644 --- a/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java +++ b/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/k/KindlyAncestor.java b/Mage.Sets/src/mage/cards/k/KindlyAncestor.java index d8779b7103..a9b64514a7 100644 --- a/Mage.Sets/src/mage/cards/k/KindlyAncestor.java +++ b/Mage.Sets/src/mage/cards/k/KindlyAncestor.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/l/LanternBearer.java b/Mage.Sets/src/mage/cards/l/LanternBearer.java index d6c674a455..4f44b1d854 100644 --- a/Mage.Sets/src/mage/cards/l/LanternBearer.java +++ b/Mage.Sets/src/mage/cards/l/LanternBearer.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/l/LunarchVeteran.java b/Mage.Sets/src/mage/cards/l/LunarchVeteran.java index a446183f23..439bef2eea 100644 --- a/Mage.Sets/src/mage/cards/l/LunarchVeteran.java +++ b/Mage.Sets/src/mage/cards/l/LunarchVeteran.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/m/MalevolentHermit.java b/Mage.Sets/src/mage/cards/m/MalevolentHermit.java index 83cd130ef3..85c609a465 100644 --- a/Mage.Sets/src/mage/cards/m/MalevolentHermit.java +++ b/Mage.Sets/src/mage/cards/m/MalevolentHermit.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java b/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java index 8ff2582e70..2f3a7ac6a8 100644 --- a/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java +++ b/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/m/MourningPatrol.java b/Mage.Sets/src/mage/cards/m/MourningPatrol.java index cf0aad468d..d04ce198bd 100644 --- a/Mage.Sets/src/mage/cards/m/MourningPatrol.java +++ b/Mage.Sets/src/mage/cards/m/MourningPatrol.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java b/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java index 52313b4b83..22e968cb05 100644 --- a/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java +++ b/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/s/SnapcasterMage.java b/Mage.Sets/src/mage/cards/s/SnapcasterMage.java index 58a03c9c02..ed9da04129 100644 --- a/Mage.Sets/src/mage/cards/s/SnapcasterMage.java +++ b/Mage.Sets/src/mage/cards/s/SnapcasterMage.java @@ -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) { diff --git a/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java b/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java index a0a054e6ad..3323597e51 100644 --- a/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java +++ b/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java @@ -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) { diff --git a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java index f397b20a6d..c9f2c4b6da 100644 --- a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java +++ b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java @@ -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 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 } } diff --git a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java index bef4d0a9a0..1728d60fc3 100644 --- a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java +++ b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java @@ -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 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 diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index e9cdf56991..f65ede100e 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -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 can’t pay other alternative costs // (such as that of Foil). (2018-12-07) diff --git a/Mage/src/main/java/mage/abilities/keyword/DisturbAbility.java b/Mage/src/main/java/mage/abilities/keyword/DisturbAbility.java index be956cf33d..7a87c5dea3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DisturbAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DisturbAbility.java @@ -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 + *

+ * 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. + *

+ * 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 + + " (You may cast this card transformed from your graveyard for its disturb cost.)"; } } + +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; + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java index 37223ad614..bd400f6f68 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java @@ -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; diff --git a/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java b/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java index 9fa3da2862..faa191afed 100644 --- a/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java +++ b/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java @@ -12,7 +12,8 @@ public enum SpellAbilityCastMode { NORMAL("Normal"), MADNESS("Madness"), FLASHBACK("Flashback"), - BESTOW("Bestow"); + BESTOW("Bestow"), + DISTURB("Disturb"); private final String text; diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index d21094e545..4d188c997c 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -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) { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 13c4dc60f5..11f9d1321a 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -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); } } } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index cec9147374..db5d6697c2 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -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;