diff --git a/Mage.Sets/src/mage/cards/b/BorealOutrider.java b/Mage.Sets/src/mage/cards/b/BorealOutrider.java index ff16459bcd0..0a1a4c441d9 100644 --- a/Mage.Sets/src/mage/cards/b/BorealOutrider.java +++ b/Mage.Sets/src/mage/cards/b/BorealOutrider.java @@ -36,7 +36,7 @@ public final class BorealOutrider extends CardImpl { // Whenever you cast a creature spell, if {S} of any of that spell's color was spent to cast it, that creature enters the battlefield with an additional +1/+1 counter on it. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new SpellCastControllerTriggeredAbility( - new BorealOutriderEffect(), StaticFilters.FILTER_SPELL_A_CREATURE, false + new BorealOutriderEffect(), StaticFilters.FILTER_SPELL_A_CREATURE, false, true ), BorealOutriderCondition.instance, "Whenever you cast a creature spell, " + "if {S} of any of that spell's color was spent to cast it, that creature " + "enters the battlefield with an additional +1/+1 counter on it." diff --git a/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java b/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java new file mode 100644 index 00000000000..d5b087f42c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java @@ -0,0 +1,156 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.DiscardedByOpponentTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.keyword.ChangelingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class OrvarTheAllForm extends CardImpl { + + public OrvarTheAllForm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Changeling + this.setIsAllCreatureTypes(true); + this.addAbility(ChangelingAbility.getInstance()); + + // Whenever you cast an instant or sorcery spell, if it targets one or more other permanents you control, create a token that's a copy of one of those permanents. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new SpellCastControllerTriggeredAbility( + new OrvarTheAllFormEffect(), + StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, + false, true + ), OrvarTheAllFormCondition.instance, "Whenever you cast an instant or sorcery spell, " + + "if it targets one or more other permanents you control, " + + "create a token that's a copy of one of those permanents." + )); + + // When a spell or ability an opponent controls causes you to discard this card, create a token that's a copy of target permanent. + Ability ability = new DiscardedByOpponentTriggeredAbility(new CreateTokenCopyTargetEffect()); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + } + + private OrvarTheAllForm(final OrvarTheAllForm card) { + super(card); + } + + @Override + public OrvarTheAllForm copy() { + return new OrvarTheAllForm(this); + } +} + +enum OrvarTheAllFormCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell) source.getEffects().get(0).getValue("spellCast"); + return spell != null && spell + .getSpellAbility() + .getModes() + .values() + .stream() + .map(Mode::getTargets) + .flatMap(Collection::stream) + .map(Target::getTargets) + .flatMap(Collection::stream) + .filter(uuid -> uuid != source.getSourceId()) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(Controllable::getControllerId) + .anyMatch(source::isControlledBy); + } +} + +class OrvarTheAllFormEffect extends OneShotEffect { + + OrvarTheAllFormEffect() { + super(Outcome.Benefit); + } + + private OrvarTheAllFormEffect(final OrvarTheAllFormEffect effect) { + super(effect); + } + + @Override + public OrvarTheAllFormEffect copy() { + return new OrvarTheAllFormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Spell spell = (Spell) this.getValue("spellCast"); + if (spell == null) { + return false; + } + List> predicates = spell + .getSpellAbility() + .getModes() + .values() + .stream() + .map(Mode::getTargets) + .flatMap(Collection::stream) + .map(Target::getTargets) + .flatMap(Collection::stream) + .filter(uuid -> uuid != source.getSourceId()) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(Controllable::getControllerId) + .filter(source::isControlledBy) + .map(PermanentIdPredicate::new) + .collect(Collectors.toList()); + if (predicates.isEmpty()) { + return false; + } + FilterPermanent filter = new FilterPermanent("a permanent targeted by this spell"); + filter.add(Predicates.or(predicates)); + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + player.choose(outcome, target, source.getSourceId(), game); + return new CreateTokenCopyTargetEffect() + .setTargetPointer(new FixedTarget(target.getFirstTarget(), game)) + .apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/sets/Kaldheim.java b/Mage.Sets/src/mage/sets/Kaldheim.java index 957c45c16e2..9fee3a793e3 100644 --- a/Mage.Sets/src/mage/sets/Kaldheim.java +++ b/Mage.Sets/src/mage/sets/Kaldheim.java @@ -239,6 +239,7 @@ public final class Kaldheim extends ExpansionSet { cards.add(new SetCardInfo("Narfi, Betrayer King", 224, Rarity.UNCOMMON, mage.cards.n.NarfiBetrayerKing.class)); cards.add(new SetCardInfo("Niko Aris", 225, Rarity.MYTHIC, mage.cards.n.NikoAris.class)); cards.add(new SetCardInfo("Old-Growth Troll", 185, Rarity.RARE, mage.cards.o.OldGrowthTroll.class)); + cards.add(new SetCardInfo("Orvar, the All-Form", 70, Rarity.MYTHIC, mage.cards.o.OrvarTheAllForm.class)); cards.add(new SetCardInfo("Path to the World Tree", 186, Rarity.UNCOMMON, mage.cards.p.PathToTheWorldTree.class)); cards.add(new SetCardInfo("Pilfering Hawk", 71, Rarity.COMMON, mage.cards.p.PilferingHawk.class)); cards.add(new SetCardInfo("Plains", 394, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));