From 4e5dea5097567b101cf34ffbe7b252a9d9d69cc7 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sun, 19 Apr 2020 12:54:25 -0400 Subject: [PATCH] made some abilities properly copiable --- Mage.Sets/src/mage/cards/s/SilverWyvern.java | 84 ++++++++--------- Mage.Sets/src/mage/cards/t/Torchling.java | 97 ++++++++++---------- 2 files changed, 85 insertions(+), 96 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SilverWyvern.java b/Mage.Sets/src/mage/cards/s/SilverWyvern.java index 42e7c731b18..58b69e9e093 100644 --- a/Mage.Sets/src/mage/cards/s/SilverWyvern.java +++ b/Mage.Sets/src/mage/cards/s/SilverWyvern.java @@ -1,54 +1,62 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; +import mage.MageItem; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ChooseNewTargetsTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterStackObject; -import mage.filter.predicate.Predicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.stack.StackObject; import mage.target.Target; import mage.target.TargetStackObject; -import mage.target.Targets; + +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Stream; /** - * * @author LevelX2 */ public final class SilverWyvern extends CardImpl { - + + private static final FilterStackObject filter = new FilterStackObject(); + + static { + filter.add(SilverWyvernPredicate.instance); + } + public SilverWyvern(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.DRAKE); + this.power = new MageInt(4); this.toughness = new MageInt(3); // Flying this.addAbility(FlyingAbility.getInstance()); // {U}: Change the target of target spell or ability that targets only Silver Wyvern. The new target must be a creature. - Effect effect = new ChooseNewTargetsTargetEffect(true, true); - effect.setText("Change the target of target spell or ability that targets only {this}. The new target must be a creature"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{U}")); - FilterStackObject filter = new FilterStackObject(); - filter.add(new TargetsOnlySourcePredicate(getId())); + Ability ability = new SimpleActivatedAbility( + new ChooseNewTargetsTargetEffect(true, true) + .setText("Change the target of target spell or ability that targets only {this}. " + + "The new target must be a creature"), + new ManaCostsImpl("{U}") + ); ability.addTarget(new TargetStackObject(filter)); this.addAbility(ability); - + } - public SilverWyvern(final SilverWyvern card) { + private SilverWyvern(final SilverWyvern card) { super(card); } @@ -58,35 +66,21 @@ public final class SilverWyvern extends CardImpl { } } -class TargetsOnlySourcePredicate implements Predicate { - - private final UUID sourceId; - - public TargetsOnlySourcePredicate(UUID sourceId) { - this.sourceId = sourceId; - } +enum SilverWyvernPredicate implements ObjectSourcePlayerPredicate> { + instance; @Override - public boolean apply(MageObject input, Game game) { - StackObject stackObject = game.getStack().getStackObject(input.getId()); - if (stackObject != null) { - Targets spellTargets = stackObject.getStackAbility().getTargets(); - int numberOfTargets = 0; - for (Target target : spellTargets) { - if (target.getFirstTarget() == null || !target.getFirstTarget().toString().equals(sourceId.toString())) { // UUID != UUID does not work - it's always false - return false; - } - numberOfTargets += target.getTargets().size(); - } - if (numberOfTargets == 1) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return "target spell or ability that targets only source"; + public boolean apply(ObjectSourcePlayer input, Game game) { + Stream stream = input.getObject() + .getStackAbility() + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(MageItem::getId); + return stream.allMatch(input.getSourceId()::equals) + && stream.anyMatch(input.getSourceId()::equals); } } diff --git a/Mage.Sets/src/mage/cards/t/Torchling.java b/Mage.Sets/src/mage/cards/t/Torchling.java index 1982ee257f3..2de726dc712 100644 --- a/Mage.Sets/src/mage/cards/t/Torchling.java +++ b/Mage.Sets/src/mage/cards/t/Torchling.java @@ -1,12 +1,8 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; +import mage.MageItem; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.costs.mana.GenericManaCost; @@ -17,50 +13,68 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.FilterSpell; -import mage.filter.predicate.Predicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.stack.Spell; +import mage.game.stack.StackObject; import mage.target.Target; import mage.target.TargetSpell; import mage.target.common.TargetCreaturePermanent; +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Stream; + /** - * * @author emerald000 */ public final class Torchling extends CardImpl { + private static final FilterSpell filter = new FilterSpell(); + + static { + filter.add(TorchlingPredicate.instance); + } + public Torchling(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(3); this.toughness = new MageInt(3); // {R}: Untap Torchling. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new ColoredManaCost(ColoredManaSymbol.R))); + this.addAbility(new SimpleActivatedAbility(new UntapSourceEffect(), new ColoredManaCost(ColoredManaSymbol.R))); // {R}: Target creature blocks Torchling this turn if able. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(), new ColoredManaCost(ColoredManaSymbol.R)); + Ability ability = new SimpleActivatedAbility( + new MustBeBlockedByTargetSourceEffect(), new ColoredManaCost(ColoredManaSymbol.R) + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // {R}: Change the target of target spell that targets only Torchling. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChooseNewTargetsTargetEffect(true, true), new ColoredManaCost(ColoredManaSymbol.R)); - FilterSpell filter = new FilterSpell("spell that targets only " + this.getName()); - filter.add(new TorchlingTargetPredicate(this.getId())); + ability = new SimpleActivatedAbility( + new ChooseNewTargetsTargetEffect(true, true) + .setText("change the target of target spell that targets only {this}"), + new ColoredManaCost(ColoredManaSymbol.R) + ); ability.addTarget(new TargetSpell(filter)); this.addAbility(ability); // {1}: Torchling gets +1/-1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, -1, Duration.EndOfTurn), new GenericManaCost(1))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, -1, Duration.EndOfTurn), new GenericManaCost(1) + )); // {1}: Torchling gets -1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(-1, 1, Duration.EndOfTurn), new GenericManaCost(1))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(-1, 1, Duration.EndOfTurn), new GenericManaCost(1) + )); } public Torchling(final Torchling card) { @@ -73,40 +87,21 @@ public final class Torchling extends CardImpl { } } -class TorchlingTargetPredicate implements Predicate { - - private final UUID sourceId; - - TorchlingTargetPredicate(UUID sourceId) { - this.sourceId = sourceId; - } +enum TorchlingPredicate implements ObjectSourcePlayerPredicate> { + instance; @Override - public boolean apply(MageObject input, Game game) { - Spell spell = game.getStack().getSpell(input.getId()); - if (spell != null) { - int numberOfTargets = 0; - for (SpellAbility spellAbility : spell.getSpellAbilities()) { - for (UUID modeId : spellAbility.getModes().getSelectedModes()) { - Mode mode = spellAbility.getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetId : target.getTargets()) { - if (!targetId.equals(sourceId)) { - return false; - } else { - numberOfTargets++; - } - } - } - } - } - return numberOfTargets > 0; - } - return false; - } - - @Override - public String toString() { - return "target spell that targets only {this}"; + public boolean apply(ObjectSourcePlayer input, Game game) { + Stream stream = input.getObject() + .getStackAbility() + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(MageItem::getId); + return stream.allMatch(input.getSourceId()::equals) + && stream.anyMatch(input.getSourceId()::equals); } }