From fd2078a4d6ca8dc1b85e36a6447c9a445159a08e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sun, 7 Nov 2021 09:19:20 -0500 Subject: [PATCH] [VOW] Implemented Innocent Traveler / Malicious Invader --- .../src/mage/cards/c/ClackbridgeTroll.java | 11 +- .../src/mage/cards/i/InnocentTraveler.java | 102 ++++++++++++++++++ .../src/mage/cards/m/MaliciousInvader.java | 61 +++++++++++ .../src/mage/sets/InnistradCrimsonVow.java | 2 + 4 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/i/InnocentTraveler.java create mode 100644 Mage.Sets/src/mage/cards/m/MaliciousInvader.java diff --git a/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java b/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java index d92918efb0..0388d41c92 100644 --- a/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java +++ b/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -65,6 +66,8 @@ public final class ClackbridgeTroll extends CardImpl { class ClackbridgeTrollEffect extends OneShotEffect { + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("creature to sacrifice"); + ClackbridgeTrollEffect() { super(Outcome.Benefit); staticText = "any opponent may sacrifice a creature. If a player does, " + @@ -83,19 +86,12 @@ class ClackbridgeTrollEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePerm = game.getPermanent(source.getSourceId()); - if (controller == null) { - return false; - } boolean flag = false; for (UUID opponentId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(opponentId); if (opponent == null) { continue; } - FilterControlledPermanent filter = new FilterControlledPermanent("creature to sacrifice"); - filter.add(CardType.CREATURE.getPredicate()); - filter.add(TargetController.YOU.getControllerPredicate()); TargetControlledPermanent target = new TargetControlledPermanent(filter); target.setNotTarget(true); if (!target.canChoose(source.getSourceId(), opponent.getId(), game) @@ -110,6 +106,7 @@ class ClackbridgeTrollEffect extends OneShotEffect { flag = true; } if (flag) { + Permanent sourcePerm = source.getSourcePermanentIfItStillExists(game); if (sourcePerm != null) { sourcePerm.tap(source, game); } diff --git a/Mage.Sets/src/mage/cards/i/InnocentTraveler.java b/Mage.Sets/src/mage/cards/i/InnocentTraveler.java new file mode 100644 index 0000000000..8e6d2edf04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InnocentTraveler.java @@ -0,0 +1,102 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InnocentTraveler extends CardImpl { + + public InnocentTraveler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + this.secondSideCardClazz = mage.cards.m.MaliciousInvader.class; + + // At the beginning of your upkeep, any opponent may sacrifice a creature. If no one does, transform Innocent Traveler. + this.addAbility(new TransformAbility()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new InnocentTravelerEffect(), TargetController.YOU, false + )); + } + + private InnocentTraveler(final InnocentTraveler card) { + super(card); + } + + @Override + public InnocentTraveler copy() { + return new InnocentTraveler(this); + } +} + +class InnocentTravelerEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creature to sacrifice"); + + InnocentTravelerEffect() { + super(Outcome.Benefit); + staticText = "any opponent may sacrifice a creature. If no one does, transform {this}"; + } + + private InnocentTravelerEffect(final InnocentTravelerEffect effect) { + super(effect); + } + + @Override + public InnocentTravelerEffect copy() { + return new InnocentTravelerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + boolean flag = false; + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + if (!target.canChoose(source.getSourceId(), opponent.getId(), game) + || !opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature?", source, game) + || !opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + continue; + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + continue; + } + flag = true; + } + if (flag) { + return true; + } + Permanent sourcePerm = source.getSourcePermanentIfItStillExists(game); + if (sourcePerm != null) { + sourcePerm.transform(source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaliciousInvader.java b/Mage.Sets/src/mage/cards/m/MaliciousInvader.java new file mode 100644 index 0000000000..5584bcf88c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaliciousInvader.java @@ -0,0 +1,61 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaliciousInvader extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.HUMAN, ""); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "An opponent controls a Human"); + + public MaliciousInvader(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Malicious Invader gets +2/+0 as long as an opponent controls a Human. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield), + condition, "{this} gets +2/+0 as long as an opponent controls a Human" + )).addHint(hint)); + } + + private MaliciousInvader(final MaliciousInvader card) { + super(card); + } + + @Override + public MaliciousInvader copy() { + return new MaliciousInvader(this); + } +} diff --git a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java index ac71a22490..49b974a0e8 100644 --- a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java +++ b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java @@ -161,6 +161,7 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Hungry Ridgewolf", 161, Rarity.COMMON, mage.cards.h.HungryRidgewolf.class)); cards.add(new SetCardInfo("Infestation Expert", 206, Rarity.UNCOMMON, mage.cards.i.InfestationExpert.class)); cards.add(new SetCardInfo("Infested Werewolf", 206, Rarity.UNCOMMON, mage.cards.i.InfestedWerewolf.class)); + cards.add(new SetCardInfo("Innocent Traveler", 121, Rarity.UNCOMMON, mage.cards.i.InnocentTraveler.class)); cards.add(new SetCardInfo("Inspired Idea", 64, Rarity.RARE, mage.cards.i.InspiredIdea.class)); cards.add(new SetCardInfo("Into the Night", 163, Rarity.UNCOMMON, mage.cards.i.IntoTheNight.class)); cards.add(new SetCardInfo("Investigator's Journal", 258, Rarity.RARE, mage.cards.i.InvestigatorsJournal.class)); @@ -180,6 +181,7 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Lanterns' Lift", 66, Rarity.COMMON, mage.cards.l.LanternsLift.class)); cards.add(new SetCardInfo("Lightning Wolf", 168, Rarity.COMMON, mage.cards.l.LightningWolf.class)); cards.add(new SetCardInfo("Lunar Rejection", 67, Rarity.UNCOMMON, mage.cards.l.LunarRejection.class)); + cards.add(new SetCardInfo("Malicious Invader", 121, Rarity.UNCOMMON, mage.cards.m.MaliciousInvader.class)); cards.add(new SetCardInfo("Manaform Hellkite", 170, Rarity.MYTHIC, mage.cards.m.ManaformHellkite.class)); cards.add(new SetCardInfo("Markov Purifier", 241, Rarity.UNCOMMON, mage.cards.m.MarkovPurifier.class)); cards.add(new SetCardInfo("Markov Retribution", 171, Rarity.UNCOMMON, mage.cards.m.MarkovRetribution.class));