diff --git a/Mage.Sets/src/mage/cards/c/CracklingDoom.java b/Mage.Sets/src/mage/cards/c/CracklingDoom.java index f0bf828a80e..107510d19af 100644 --- a/Mage.Sets/src/mage/cards/c/CracklingDoom.java +++ b/Mage.Sets/src/mage/cards/c/CracklingDoom.java @@ -7,12 +7,10 @@ import mage.abilities.effects.common.DamagePlayersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.GreatestPowerControlledPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -50,6 +48,10 @@ public final class CracklingDoom extends CardImpl { class CracklingDoomEffect extends OneShotEffect { + static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with the greatest power among creatures you control"); + static { + filter.add(GreatestPowerControlledPredicate.instance); + } public CracklingDoomEffect() { super(Outcome.Sacrifice); this.staticText = "Each opponent sacrifices a creature with the greatest power among creatures that player controls"; @@ -73,31 +75,12 @@ class CracklingDoomEffect extends OneShotEffect { if (controller.hasOpponent(playerId, game)) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - int greatestPower = Integer.MIN_VALUE; - int numberOfCreatures = 0; - Permanent permanentToSacrifice = null; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { - if (permanent.getPower().getValue() > greatestPower) { - greatestPower = permanent.getPower().getValue(); - numberOfCreatures = 1; - permanentToSacrifice = permanent; - } else if (permanent.getPower().getValue() == greatestPower) { - numberOfCreatures++; - } - } - if (numberOfCreatures == 1) { - if (permanentToSacrifice != null) { - toSacrifice.add(permanentToSacrifice); - } - } else if (greatestPower != Integer.MIN_VALUE) { - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature to sacrifice with power equal to " + greatestPower); - filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, greatestPower)); - Target target = new TargetControlledCreaturePermanent(filter); - if (opponent.choose(outcome, target, source, game)) { - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - toSacrifice.add(permanent); - } + Target target = new TargetControlledCreaturePermanent(filter); + target.withNotTarget(true); + if (opponent.choose(outcome, target, source, game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + toSacrifice.add(permanent); } } } diff --git a/Mage.Sets/src/mage/cards/f/FellBeastsShriek.java b/Mage.Sets/src/mage/cards/f/FellBeastsShriek.java new file mode 100644 index 00000000000..092ba4ffa24 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FellBeastsShriek.java @@ -0,0 +1,95 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.effects.common.combat.GoadAllEffect; +import mage.abilities.keyword.SpliceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.PermanentInListPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * + * @author notgreat + */ +public final class FellBeastsShriek extends CardImpl { + + public FellBeastsShriek(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{R}"); + + // Each opponent chooses a creature they control. Tap and goad the chosen creatures. + this.getSpellAbility().addEffect(new FellBeastsShriekEffect()); + // Splice onto instant or sorcery {2}{U}{R} + this.addAbility(new SpliceAbility(SpliceAbility.INSTANT_OR_SORCERY, "{2}{U}{R}")); + } + + private FellBeastsShriek(final FellBeastsShriek card) { + super(card); + } + + @Override + public FellBeastsShriek copy() { + return new FellBeastsShriek(this); + } +} + +class FellBeastsShriekEffect extends OneShotEffect { + + public FellBeastsShriekEffect() { + super(Outcome.Benefit); + this.staticText = "Each opponent chooses a creature they control. Tap and goad the chosen creatures."; + } + + private FellBeastsShriekEffect(final FellBeastsShriekEffect effect) { + super(effect); + } + + @Override + public FellBeastsShriekEffect copy() { + return new FellBeastsShriekEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + List creaturesChosen = new ArrayList<>(); + + // For each opponent, get the creature to tap+goad + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + if (controller.hasOpponent(playerId, game)) { + Player opponent = game.getPlayer(playerId); + if (opponent != null) { + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); + target.withNotTarget(true); + if (opponent.choose(Outcome.Detriment, target, source, game)) { + creaturesChosen.add(game.getPermanent(target.getTargets().get(0))); + } + } + } + } + + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(new PermanentInListPredicate(creaturesChosen)); + new TapAllEffect(filter).apply(game, source); + ContinuousEffect goadEffect = new GoadAllEffect(filter); + game.addEffect(goadEffect, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MordorOnTheMarch.java b/Mage.Sets/src/mage/cards/m/MordorOnTheMarch.java new file mode 100644 index 00000000000..c1085b81d22 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MordorOnTheMarch.java @@ -0,0 +1,108 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.StormAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; + +/** + * + * @author notgreat + */ +public final class MordorOnTheMarch extends CardImpl { + + public MordorOnTheMarch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{R}"); + + // Exile a creature card from your graveyard. Create a token that's a copy of it. It gains haste until end of turn. Exile it at the beginning of the next end step. + this.getSpellAbility().addEffect(new MordorOnTheMarchEffect()); + + // Storm + this.addAbility(new StormAbility()); + + } + + private MordorOnTheMarch(final MordorOnTheMarch card) { + super(card); + } + + @Override + public MordorOnTheMarch copy() { + return new MordorOnTheMarch(this); + } +} + +class MordorOnTheMarchEffect extends OneShotEffect { + + public MordorOnTheMarchEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "exile a creature card from your graveyard. Create a token that's a copy of it. It gains haste until end of turn. Exile it at the beginning of the next end step"; + } + + private MordorOnTheMarchEffect(final MordorOnTheMarchEffect effect) { + super(effect); + } + + @Override + public MordorOnTheMarchEffect copy() { + return new MordorOnTheMarchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); + target.withNotTarget(true); + if (!target.canChoose(source.getControllerId(), source, game)) { + return true; + } + controller.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, false); + effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1)); + controller.moveCards(card, Zone.EXILED, source, game); + effect.apply(game, source); + effect.getAddedPermanents().stream().forEach(permanent -> { + ContinuousEffect continuousEffect = new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.UntilYourNextTurn + ); + continuousEffect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(continuousEffect, source); + }); + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } + + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java b/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java new file mode 100644 index 00000000000..55bb70b121e --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OlorinsSearingLight.java @@ -0,0 +1,104 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.condition.common.SpellMasteryCondition; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.GreatestPowerControlledPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.*; + +/** + * + * @author notgreat + */ +public final class OlorinsSearingLight extends CardImpl { + + public OlorinsSearingLight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{W}"); + + // Each opponent exiles a creature with the greatest power among creatures that player controls. + // Spell mastery -- If there are two or more instant and/or sorcery cards in your graveyard, Olorin's Searing Light deals damage to each opponent equal to the power of the creature they exiled. + this.getSpellAbility().addEffect(new OlorinsSearingLightEffect()); + } + + private OlorinsSearingLight(final OlorinsSearingLight card) { + super(card); + } + + @Override + public OlorinsSearingLight copy() { + return new OlorinsSearingLight(this); + } +} +//See Crackling Doom +class OlorinsSearingLightEffect extends OneShotEffect { + + static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with the greatest power among creatures you control"); + static { + filter.add(GreatestPowerControlledPredicate.instance); + } + public OlorinsSearingLightEffect() { + super(Outcome.Sacrifice); + this.staticText = "Each opponent exiles a creature with the greatest power among creatures that player controls.
" + +"Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, {this} deals damage to each opponent equal to the power of the creature they exiled."; + } + + private OlorinsSearingLightEffect(final OlorinsSearingLightEffect effect) { + super(effect); + } + + @Override + public OlorinsSearingLightEffect copy() { + return new OlorinsSearingLightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + List toExile = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + if (controller.hasOpponent(playerId, game)) { + Player opponent = game.getPlayer(playerId); + if (opponent != null) { + Target target = new TargetControlledCreaturePermanent(filter); + target.withNotTarget(true); + if (opponent.choose(outcome, target, source, game)) { + Permanent permanentChosen = game.getPermanent(target.getFirstTarget()); + if (permanentChosen != null) { + toExile.add(permanentChosen); + } + } + } + } + } + List> damageList = new ArrayList<>(); + for (Permanent permanent : toExile) { + Player opponent = game.getPlayer(permanent.getControllerId()); + if (opponent != null) { + damageList.add(new AbstractMap.SimpleImmutableEntry<>(opponent, permanent.getPower().getValue())); + opponent.moveCards(permanent, Zone.EXILED, source, game); + } + } + if (SpellMasteryCondition.instance.apply(game, source)){ + game.getState().processAction(game); + for (Map.Entry entry : damageList) { + entry.getKey().damage(entry.getValue(), source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SorcerousSquall.java b/Mage.Sets/src/mage/cards/s/SorcerousSquall.java new file mode 100644 index 00000000000..9fc9aeb1a79 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SorcerousSquall.java @@ -0,0 +1,87 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.MayCastTargetThenExileEffect; +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect; +import mage.abilities.keyword.DelveAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.card.OwnerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * + * @author notgreat + */ +public final class SorcerousSquall extends CardImpl { + + public SorcerousSquall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{U}{U}{U}"); + + // Delve + this.addAbility(new DelveAbility()); + + // Target opponent mills nine cards, then you may cast an instant or sorcery spell from that player's graveyard without paying its mana cost. If that spell would be put into a graveyard, exile it instead. + this.getSpellAbility().addEffect(new MillCardsTargetEffect(9)); + this.getSpellAbility().addEffect(new SorcerousSquallEffect().concatBy(", then")); + this.getSpellAbility().addTarget(new TargetOpponent()); + + } + + private SorcerousSquall(final SorcerousSquall card) { + super(card); + } + + @Override + public SorcerousSquall copy() { + return new SorcerousSquall(this); + } +} + + +class SorcerousSquallEffect extends OneShotEffect { + + SorcerousSquallEffect() { + super(Outcome.Detriment); + setText("you may cast an instant or sorcery spell from that player's graveyard without paying its mana cost. "+ ThatSpellGraveyardExileReplacementEffect.RULE_A); + } + + private SorcerousSquallEffect(final SorcerousSquallEffect effect) { + super(effect); + } + + @Override + public SorcerousSquallEffect copy() { + return new SorcerousSquallEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card from that player's graveyard"); + filter.add(new OwnerIdPredicate(source.getFirstTarget())); + Target target = new TargetCardInGraveyard(1, 1, filter, true); + player.choose(outcome, target, source, game); + Effect effect = new MayCastTargetThenExileEffect(true); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); + effect.apply(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java b/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java index b2ab71baf59..9cf7e7e091a 100644 --- a/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java +++ b/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java @@ -114,6 +114,7 @@ public final class TalesOfMiddleEarthCommander extends ExpansionSet { cards.add(new SetCardInfo("Feasting Hobbit", 37, Rarity.RARE, mage.cards.f.FeastingHobbit.class)); cards.add(new SetCardInfo("Feed the Swarm", 200, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); cards.add(new SetCardInfo("Fell Beast of Mordor", 513, Rarity.RARE, mage.cards.f.FellBeastOfMordor.class)); + cards.add(new SetCardInfo("Fell Beast's Shriek", 508, Rarity.RARE, mage.cards.f.FellBeastsShriek.class)); cards.add(new SetCardInfo("Fell the Mighty", 167, Rarity.RARE, mage.cards.f.FellTheMighty.class)); cards.add(new SetCardInfo("Field of Ruin", 308, Rarity.UNCOMMON, mage.cards.f.FieldOfRuin.class)); cards.add(new SetCardInfo("Field-Tested Frying Pan", 11, Rarity.RARE, mage.cards.f.FieldTestedFryingPan.class)); @@ -204,6 +205,7 @@ public final class TalesOfMiddleEarthCommander extends ExpansionSet { cards.add(new SetCardInfo("Mists of Lorien", 501, Rarity.RARE, mage.cards.m.MistsOfLorien.class)); cards.add(new SetCardInfo("Model of Unity", 78, Rarity.RARE, mage.cards.m.ModelOfUnity.class)); cards.add(new SetCardInfo("Monstrosity of the Lake", 22, Rarity.RARE, mage.cards.m.MonstrosityOfTheLake.class)); + cards.add(new SetCardInfo("Mordor on the March", 512, Rarity.RARE, mage.cards.m.MordorOnTheMarch.class)); cards.add(new SetCardInfo("Moria Scavenger", 63, Rarity.RARE, mage.cards.m.MoriaScavenger.class)); cards.add(new SetCardInfo("Mortify", 269, Rarity.UNCOMMON, mage.cards.m.Mortify.class)); cards.add(new SetCardInfo("Motivated Pony", 42, Rarity.RARE, mage.cards.m.MotivatedPony.class)); @@ -218,6 +220,7 @@ public final class TalesOfMiddleEarthCommander extends ExpansionSet { cards.add(new SetCardInfo("Oath of Eorl", 64, Rarity.RARE, mage.cards.o.OathOfEorl.class)); cards.add(new SetCardInfo("Oboro, Palace in the Clouds", 371, Rarity.MYTHIC, mage.cards.o.OboroPalaceInTheClouds.class)); cards.add(new SetCardInfo("Of Herbs and Stewed Rabbit", 17, Rarity.RARE, mage.cards.o.OfHerbsAndStewedRabbit.class)); + cards.add(new SetCardInfo("Olorin's Searing Light", 503, Rarity.RARE, mage.cards.o.OlorinsSearingLight.class)); cards.add(new SetCardInfo("Opt", 194, Rarity.COMMON, mage.cards.o.Opt.class)); cards.add(new SetCardInfo("Orchard Strider", 253, Rarity.COMMON, mage.cards.o.OrchardStrider.class)); cards.add(new SetCardInfo("Orcish Siegemaster", 33, Rarity.RARE, mage.cards.o.OrcishSiegemaster.class)); @@ -280,6 +283,7 @@ public final class TalesOfMiddleEarthCommander extends ExpansionSet { cards.add(new SetCardInfo("Smoldering Marsh", 332, Rarity.RARE, mage.cards.s.SmolderingMarsh.class)); cards.add(new SetCardInfo("Sol Ring", 284, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Song of Earendil", 69, Rarity.RARE, mage.cards.s.SongOfEarendil.class)); + cards.add(new SetCardInfo("Sorcerous Squall", 504, Rarity.RARE, mage.cards.s.SorcerousSquall.class)); cards.add(new SetCardInfo("Soul's Attendant", 520, Rarity.UNCOMMON, mage.cards.s.SoulsAttendant.class)); cards.add(new SetCardInfo("Stonehewer Giant", 521, Rarity.RARE, mage.cards.s.StonehewerGiant.class)); cards.add(new SetCardInfo("Subjugate the Hobbits", 24, Rarity.RARE, mage.cards.s.SubjugateTheHobbits.class));