From bf2e90feaead6f96babc0538b37b34aa174fc1b0 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 28 Apr 2021 09:21:39 -0400 Subject: [PATCH] [C21] Implemented Yedora, Grave Gardener --- .../mage/cards/m/MetamorphicAlteration.java | 2 +- .../mage/cards/t/TezzeretCruelMachinist.java | 121 ++++++---------- .../src/mage/cards/y/YedoraGraveGardener.java | 129 ++++++++++++++++++ .../src/mage/sets/Commander2021Edition.java | 1 + .../abilities/effects/ContinuousEffects.java | 8 +- .../effects/common/CopyTokenEffect.java | 2 +- .../abilities/keyword/TransformAbility.java | 2 +- .../main/java/mage/constants/SubLayer.java | 3 +- .../target/targetpointer/FixedTargets.java | 12 +- 9 files changed, 193 insertions(+), 87 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/y/YedoraGraveGardener.java diff --git a/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java b/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java index 5f9deb33f3..f9a2336b6c 100644 --- a/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java +++ b/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java @@ -100,7 +100,7 @@ class ChooseACreature extends OneShotEffect { class MetamorphicAlterationEffect extends ContinuousEffectImpl { public MetamorphicAlterationEffect() { - super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.Copy); + super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.Copy); this.staticText = "Enchanted creature is a copy of the chosen creature."; } diff --git a/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java b/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java index 8b20398e3c..bcd04fe050 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java @@ -1,14 +1,18 @@ package mage.cards.t; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; @@ -17,9 +21,10 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCardInHand; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 @@ -38,9 +43,7 @@ public final class TezzeretCruelMachinist extends CardImpl { // 0: Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types. Ability ability = new LoyaltyAbility(new AddCardTypeTargetEffect( - Duration.UntilYourNextTurn, - CardType.ARTIFACT, - CardType.CREATURE + Duration.UntilYourNextTurn, CardType.ARTIFACT, CardType.CREATURE ).setText("Until your next turn, target artifact you control becomes an artifact creature"), 0); ability.addEffect(new SetPowerToughnessTargetEffect( 5, 5, Duration.UntilYourNextTurn @@ -85,41 +88,30 @@ class TezzeretCruelMachinistEffect extends OneShotEffect { return false; } Target target = new TargetCardInHand(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + player.choose(outcome, target, source.getSourceId(), game); + Cards cardsToMove = new CardsImpl(target.getTargets()); + if (cardsToMove.isEmpty()) { return false; } - Cards cardsToMove = new CardsImpl(); - - for (UUID cardId : target.getTargets()) { - Card card = game.getCard(cardId); - if (card == null) { - continue; - } - cardsToMove.add(card); - - ContinuousEffect effectCardType = new TezzeretCruelMachinistCardTypeEffect(); - effectCardType.setTargetPointer(new FixedTarget( - card.getId(), - card.getZoneChangeCounter(game) + 1 - )); - game.addEffect(effectCardType, source); - - ContinuousEffect effectPowerToughness = new TezzeretCruelMachinistPowerToughnessEffect(); - effectPowerToughness.setTargetPointer(new FixedTarget( - card.getId(), - card.getZoneChangeCounter(game) + 1 - )); - game.addEffect(effectPowerToughness, source); - } - - return player.moveCards(cardsToMove.getCards(game), Zone.BATTLEFIELD, source, game, false, true, true, null); + game.addEffect(new TezzeretCruelMachinistCardTypeEffect().setTargetPointer(new FixedTargets( + cardsToMove + .getCards(game) + .stream() + .map(card -> new MageObjectReference(card, game, 1)) + .collect(Collectors.toSet()), game + )), source); + player.moveCards( + cardsToMove.getCards(game), Zone.BATTLEFIELD, source, game, + false, true, true, null + ); + return true; } } -class TezzeretCruelMachinistCardTypeEffect extends AddCardTypeTargetEffect { +class TezzeretCruelMachinistCardTypeEffect extends ContinuousEffectImpl { public TezzeretCruelMachinistCardTypeEffect() { - super(Duration.WhileOnBattlefield, CardType.ARTIFACT, CardType.CREATURE); + super(Duration.Custom, Layer.CopyEffects_1, SubLayer.FaceDownEffects_1b, Outcome.Neutral); } public TezzeretCruelMachinistCardTypeEffect(final TezzeretCruelMachinistCardTypeEffect effect) { @@ -132,53 +124,26 @@ class TezzeretCruelMachinistCardTypeEffect extends AddCardTypeTargetEffect { } @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + public boolean apply(Game game, Ability source) { + boolean flag = false; for (UUID targetId : targetPointer.getTargets(game, source)) { Permanent target = game.getPermanent(targetId); - if (target != null - && target.isFaceDown(game)) { - switch (layer) { - case TypeChangingEffects_4: - target.getSuperType().clear(); - target.getCardType().clear(); - target.removeAllSubTypes(game); - target.addCardType(CardType.ARTIFACT); - target.addCardType(CardType.CREATURE); - break; - } - return true; + if (target == null || !target.isFaceDown(game)) { + continue; } + flag = true; + target.getSuperType().clear(); + target.getCardType().clear(); + target.removeAllSubTypes(game); + target.addCardType(CardType.ARTIFACT); + target.addCardType(CardType.CREATURE); + target.getPower().setValue(5); + target.getToughness().setValue(5); } - return false; - } -} - -class TezzeretCruelMachinistPowerToughnessEffect extends SetPowerToughnessTargetEffect { - - public TezzeretCruelMachinistPowerToughnessEffect() { - super(5, 5, Duration.WhileOnBattlefield); - } - - public TezzeretCruelMachinistPowerToughnessEffect(final TezzeretCruelMachinistPowerToughnessEffect effect) { - super(effect); - } - - @Override - public TezzeretCruelMachinistPowerToughnessEffect copy() { - return new TezzeretCruelMachinistPowerToughnessEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { - Permanent target = game.getPermanent(targetId); - if (target != null - && target.isFaceDown(game)) { - target.getPower().setValue(5); - target.getToughness().setValue(5); - return true; - } - } - return false; + if (!flag) { + discard(); + return false; + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/y/YedoraGraveGardener.java b/Mage.Sets/src/mage/cards/y/YedoraGraveGardener.java new file mode 100644 index 0000000000..21980b0fa5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YedoraGraveGardener.java @@ -0,0 +1,129 @@ +package mage.cards.y; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YedoraGraveGardener extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another nontoken creature you control"); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); + } + + public YedoraGraveGardener(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TREEFOLK); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Whenever another nontoken creature you control dies, you may return it to the battlefield face down under its owner's control. It's a Forest land. + this.addAbility(new DiesCreatureTriggeredAbility( + new YedoraGraveGardenerEffect(), true, filter, true + )); + } + + private YedoraGraveGardener(final YedoraGraveGardener card) { + super(card); + } + + @Override + public YedoraGraveGardener copy() { + return new YedoraGraveGardener(this); + } +} + +class YedoraGraveGardenerEffect extends OneShotEffect { + + YedoraGraveGardenerEffect() { + super(Outcome.Benefit); + staticText = "you may return it to the battlefield face down under its owner's control. " + + "It's a Forest land. (It has no other types or abilities.)"; + } + + private YedoraGraveGardenerEffect(final YedoraGraveGardenerEffect effect) { + super(effect); + } + + @Override + public YedoraGraveGardenerEffect copy() { + return new YedoraGraveGardenerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { + return false; + } + game.addEffect(new YedoraGraveGardenerContinuousEffect().setTargetPointer( + new FixedTarget(new MageObjectReference(card, game, 1)) + ), source); + player.moveCards( + card, Zone.BATTLEFIELD, source, game, + false, true, true, null + ); + return true; + } +} + +class YedoraGraveGardenerContinuousEffect extends ContinuousEffectImpl { + + public YedoraGraveGardenerContinuousEffect() { + super(Duration.Custom, Layer.CopyEffects_1, SubLayer.FaceDownEffects_1b, Outcome.Neutral); + } + + public YedoraGraveGardenerContinuousEffect(final YedoraGraveGardenerContinuousEffect effect) { + super(effect); + } + + @Override + public YedoraGraveGardenerContinuousEffect copy() { + return new YedoraGraveGardenerContinuousEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + if (target == null || !target.isFaceDown(game)) { + discard(); + return false; + } + target.getSuperType().clear(); + target.getCardType().clear(); + target.removeAllSubTypes(game); + target.addCardType(CardType.LAND); + target.addSubType(game, SubType.FOREST); + target.removeAllAbilities(source.getSourceId(), game); + target.addAbility(new GreenManaAbility()); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2021Edition.java b/Mage.Sets/src/mage/sets/Commander2021Edition.java index fc34410269..d5c3aaafd4 100644 --- a/Mage.Sets/src/mage/sets/Commander2021Edition.java +++ b/Mage.Sets/src/mage/sets/Commander2021Edition.java @@ -345,6 +345,7 @@ public final class Commander2021Edition extends ExpansionSet { cards.add(new SetCardInfo("Windborn Muse", 111, Rarity.RARE, mage.cards.w.WindbornMuse.class)); cards.add(new SetCardInfo("Witch's Clinic", 81, Rarity.RARE, mage.cards.w.WitchsClinic.class)); cards.add(new SetCardInfo("Yavimaya Coast", 409, Rarity.RARE, mage.cards.y.YavimayaCoast.class)); + cards.add(new SetCardInfo("Yedora, Grave Gardener", 70, Rarity.RARE, mage.cards.y.YedoraGraveGardener.class)); cards.add(new SetCardInfo("Zaffai, Thunder Conductor", 4, Rarity.MYTHIC, mage.cards.z.ZaffaiThunderConductor.class)); cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 112, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 776b6912f4..10be750f0c 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -991,7 +991,13 @@ public class ContinuousEffects implements Serializable { for (ContinuousEffect effect : layer) { Set abilities = layeredEffects.getAbility(effect.getId()); for (Ability ability : abilities) { - effect.apply(Layer.CopyEffects_1, SubLayer.NA, ability, game); + effect.apply(Layer.CopyEffects_1, SubLayer.CopyEffects_1a, ability, game); + } + } + for (ContinuousEffect effect : layer) { + Set abilities = layeredEffects.getAbility(effect.getId()); + for (Ability ability : abilities) { + effect.apply(Layer.CopyEffects_1, SubLayer.FaceDownEffects_1b, ability, game); } } //Reload layerEffect if copy effects were applied diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyTokenEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyTokenEffect.java index 4f7894c997..f50173c6a9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyTokenEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyTokenEffect.java @@ -12,7 +12,7 @@ public class CopyTokenEffect extends ContinuousEffectImpl { protected Token token; public CopyTokenEffect(Token token) { - super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); + super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature); this.token = token.copy(); staticText = "You may have {this} enter the battlefield as a copy of " + token.getDescription() + " on the battlefield"; } diff --git a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java index 056c48fd0e..5d598234ec 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java @@ -71,7 +71,7 @@ public class TransformAbility extends SimpleStaticAbility { class TransformEffect extends ContinuousEffectImpl { TransformEffect() { - super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); + super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.CopyEffects_1a, Outcome.BecomeCreature); staticText = ""; } diff --git a/Mage/src/main/java/mage/constants/SubLayer.java b/Mage/src/main/java/mage/constants/SubLayer.java index 242aa769b1..008c21aaf9 100644 --- a/Mage/src/main/java/mage/constants/SubLayer.java +++ b/Mage/src/main/java/mage/constants/SubLayer.java @@ -1,10 +1,11 @@ package mage.constants; /** - * * @author North */ public enum SubLayer { + CopyEffects_1a, + FaceDownEffects_1b, CharacteristicDefining_7a, SetPT_7b, ModifyPT_7c, diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java index 81e91e1809..d0d9abdd0b 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java @@ -9,10 +9,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; /** * @author LevelX2 @@ -61,6 +58,13 @@ public class FixedTargets extends TargetPointerImpl { this.initialized = true; } + public FixedTargets(Collection morSet, Game game) { + super(); + + targets.addAll(morSet); + this.initialized = true; + } + private FixedTargets(final FixedTargets targetPointer) { super(targetPointer);