diff --git a/Mage.Sets/src/mage/cards/a/AssaultOnOsgiliath.java b/Mage.Sets/src/mage/cards/a/AssaultOnOsgiliath.java index f7d7537f195..b38b06d67cd 100644 --- a/Mage.Sets/src/mage/cards/a/AssaultOnOsgiliath.java +++ b/Mage.Sets/src/mage/cards/a/AssaultOnOsgiliath.java @@ -1,7 +1,6 @@ package mage.cards.a; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.keyword.AmassEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -10,11 +9,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; -import mage.game.Game; import java.util.UUID; @@ -36,7 +33,7 @@ public final class AssaultOnOsgiliath extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}{R}"); // Amass Orcs X, then Goblins and Orcs you control gain double strike and haste until end of turn. - this.getSpellAbility().addEffect(new AssaultOnOsgiliathEffect()); + this.getSpellAbility().addEffect(new AmassEffect(ManacostVariableValue.REGULAR, SubType.ORC)); this.getSpellAbility().addEffect(new GainAbilityControlledEffect( DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, filter ).setText(", then Goblins and Orcs you control gain double strike")); @@ -53,26 +50,4 @@ public final class AssaultOnOsgiliath extends CardImpl { public AssaultOnOsgiliath copy() { return new AssaultOnOsgiliath(this); } -} - -class AssaultOnOsgiliathEffect extends OneShotEffect { - - AssaultOnOsgiliathEffect() { - super(Outcome.Benefit); - staticText = "amass Orcs X"; - } - - private AssaultOnOsgiliathEffect(final AssaultOnOsgiliathEffect effect) { - super(effect); - } - - @Override - public AssaultOnOsgiliathEffect copy() { - return new AssaultOnOsgiliathEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return AmassEffect.doAmass(source.getManaCostsToPay().getX(), SubType.ORC, game, source) != null; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BaradDur.java b/Mage.Sets/src/mage/cards/b/BaradDur.java index 3cd97aec633..da8bcd4d1f0 100644 --- a/Mage.Sets/src/mage/cards/b/BaradDur.java +++ b/Mage.Sets/src/mage/cards/b/BaradDur.java @@ -9,7 +9,7 @@ import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.keyword.AmassEffect; import mage.abilities.hint.ConditionHint; @@ -20,7 +20,6 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.game.Game; import java.util.UUID; @@ -55,7 +54,10 @@ public final class BaradDur extends CardImpl { // {X}{X}{B}, {T}: Amass Orcs X. Activate only if a creature died this turn. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, new BaradDurEffect(), new ManaCostsImpl<>("{X}{X}{B}"), MorbidCondition.instance + Zone.BATTLEFIELD, + new AmassEffect(ManacostVariableValue.REGULAR, SubType.ORC, false), + new ManaCostsImpl<>("{X}{X}{B}"), + MorbidCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -69,26 +71,4 @@ public final class BaradDur extends CardImpl { public BaradDur copy() { return new BaradDur(this); } -} - -class BaradDurEffect extends OneShotEffect { - - BaradDurEffect() { - super(Outcome.Benefit); - staticText = "amass Orcs X"; - } - - private BaradDurEffect(final BaradDurEffect effect) { - super(effect); - } - - @Override - public BaradDurEffect copy() { - return new BaradDurEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return AmassEffect.doAmass(source.getManaCostsToPay().getX(), SubType.ORC, game, source) != null; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/InvadeTheCity.java b/Mage.Sets/src/mage/cards/i/InvadeTheCity.java index 12d531af5fc..513645c2c25 100644 --- a/Mage.Sets/src/mage/cards/i/InvadeTheCity.java +++ b/Mage.Sets/src/mage/cards/i/InvadeTheCity.java @@ -1,19 +1,14 @@ package mage.cards.i; -import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.keyword.AmassEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -31,7 +26,14 @@ public final class InvadeTheCity extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{R}"); // Amass X, where X is the number of instant and sorcery cards in your graveyard. - this.getSpellAbility().addEffect(new InvadeTheCityEffect()); + this.getSpellAbility().addEffect( + new AmassEffect( + new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY), + SubType.ZOMBIE + ).setText("amass Zombies X, where X is the number of instant and sorcery cards in your graveyard. " + + "(Put X +1/+1 counters on an Army you control. It's also a Zombie. If you don't control an Army, " + + "create a 0/0 black Zombie Army creature token first.)") + ); } private InvadeTheCity(final InvadeTheCity card) { @@ -42,34 +44,4 @@ public final class InvadeTheCity extends CardImpl { public InvadeTheCity copy() { return new InvadeTheCity(this); } -} - -class InvadeTheCityEffect extends OneShotEffect { - - InvadeTheCityEffect() { - super(Outcome.Benefit); - staticText = "amass Zombies X, where X is the number of instant and sorcery cards in your graveyard. " + - "(Put X +1/+1 counterson an Army you control. It's also a Zombie. If you don't control an Army, " + - "create a 0/0 black Zombie Army creature token first.)"; - } - - private InvadeTheCityEffect(final InvadeTheCityEffect effect) { - super(effect); - } - - @Override - public InvadeTheCityEffect copy() { - return new InvadeTheCityEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - return AmassEffect.doAmass(player.getGraveyard().count( - StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game - ), SubType.ZOMBIE, game, source) != null; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SummonsOfSaruman.java b/Mage.Sets/src/mage/cards/s/SummonsOfSaruman.java new file mode 100644 index 00000000000..bef6dd512f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SummonsOfSaruman.java @@ -0,0 +1,118 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.ExileXFromYourGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author Susucr + */ +public final class SummonsOfSaruman extends CardImpl { + + public SummonsOfSaruman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{R}"); + + // Amass Orcs X. Mill X cards. You may cast an instant or sorcery spell with mana value X or less from among them without paying its mana cost. (To amass Orcs X, put X +1/+1 counters on an Army you control. It’s also an Orc. If you don’t control an Army, create a 0/0 black Orc Army creature token first.) + this.getSpellAbility().addEffect(new AmassEffect(SummonsOfSarumanVariableValue.instance, SubType.ORC, false)); + this.getSpellAbility().addEffect(new SummonsOfSarumanEffect()); + + // Flashback--{3}{U}{R}, Exile X cards from your graveyard. + Ability flashback = new FlashbackAbility(this, new ManaCostsImpl<>("{3}{U}{R}")); + flashback.addCost(new ExileXFromYourGraveCost(StaticFilters.FILTER_CARD_CARDS)); + this.addAbility(flashback); + } + + private SummonsOfSaruman(final SummonsOfSaruman card) { + super(card); + } + + @Override + public SummonsOfSaruman copy() { + return new SummonsOfSaruman(this); + } +} + +enum SummonsOfSarumanVariableValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int xValue = sourceAbility.getManaCostsToPay().getX(); + for (Cost cost : sourceAbility.getCosts()) { + if (cost instanceof ExileXFromYourGraveCost) { + xValue = ((ExileXFromYourGraveCost) cost).getAmount(); + } + } + return xValue; + } + + @Override + public SummonsOfSarumanVariableValue copy() { + return this; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} + +class SummonsOfSarumanEffect extends OneShotEffect { + + SummonsOfSarumanEffect() { + super(Outcome.Benefit); + staticText = "Mill X cards. You may cast an instant or sorcery spell with mana value X " + + "or less from among them without paying its mana cost." + + " (To amass Orcs X, put X +1/+1 counters on an Army you control. It's also an Orc. " + + "If you don't control an Army, create a 0/0 black Orc Army creature token first.)"; + } + + private SummonsOfSarumanEffect(final SummonsOfSarumanEffect effect) { + super(effect); + } + + @Override + public SummonsOfSarumanEffect copy() { + return new SummonsOfSarumanEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + int xValue = SummonsOfSarumanVariableValue.instance.calculate(game, source, this); + if (player == null || xValue < 1) { + return false; + } + Cards cards = player.millCards(xValue, source, game); + cards.retainZone(Zone.GRAVEYARD, game); + FilterCard filter = new FilterInstantOrSorceryCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter); + + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java b/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java index 43965d2f779..ce1131a703d 100644 --- a/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java +++ b/Mage.Sets/src/mage/sets/TalesOfMiddleEarthCommander.java @@ -250,6 +250,7 @@ public final class TalesOfMiddleEarthCommander extends ExpansionSet { cards.add(new SetCardInfo("Subjugate the Hobbits", 24, Rarity.RARE, mage.cards.s.SubjugateTheHobbits.class)); cards.add(new SetCardInfo("Sulfur Falls", 333, Rarity.RARE, mage.cards.s.SulfurFalls.class)); cards.add(new SetCardInfo("Sulfurous Springs", 334, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); + cards.add(new SetCardInfo("Summons of Saruman", 70, Rarity.RARE, mage.cards.s.SummonsOfSaruman.class)); cards.add(new SetCardInfo("Sunken Hollow", 335, Rarity.RARE, mage.cards.s.SunkenHollow.class)); cards.add(new SetCardInfo("Sunpetal Grove", 336, Rarity.RARE, mage.cards.s.SunpetalGrove.class)); cards.add(new SetCardInfo("Sunset Revelry", 177, Rarity.UNCOMMON, mage.cards.s.SunsetRevelry.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/MillCardsControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MillCardsControllerEffect.java index 58de3c44e54..36eb567759c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MillCardsControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MillCardsControllerEffect.java @@ -1,7 +1,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; @@ -28,7 +27,7 @@ public class MillCardsControllerEffect extends OneShotEffect { setText(); } - public MillCardsControllerEffect(final MillCardsControllerEffect effect) { + private MillCardsControllerEffect(final MillCardsControllerEffect effect) { super(effect); this.numberCards = effect.numberCards; } diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java index e2e441f8bc9..325d042c4ad 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java @@ -1,6 +1,8 @@ package mage.abilities.effects.keyword; import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; import mage.constants.Duration; @@ -33,22 +35,34 @@ public class AmassEffect extends OneShotEffect { filter.add(SubType.ARMY.getPredicate()); } - private final int amount; + private final DynamicValue amount; private final SubType subType; public AmassEffect(int amount, SubType subType) { + this(StaticValue.get(amount), subType); + } + + public AmassEffect(DynamicValue amount, SubType subType) { + this(amount, subType, true); + } + + public AmassEffect(DynamicValue amount, SubType subType, boolean withReminder) { super(Outcome.BoostCreature); - this.amount = amount; + this.amount = amount.copy(); this.subType = subType; - staticText = "amass " + subType + "s " + amount + ". (Put " + CardUtil.numberToText(amount) + - " +1/+1 counter" + (amount > 1 ? "s " : " ") + "on an Army you control. It's also " + - subType.getIndefiniteArticle() + ' ' + subType + ". If you don't control an Army, " + - "create a 0/0 black " + subType + " Army creature token first.)"; + + staticText = "amass " + subType + "s " + amount + "."; + if (withReminder) { + staticText += " (Put " + CardUtil.numberToText(amount.toString(), "a") + + " +1/+1 counter" + (amount.toString().equals("1") ? " " : "s ") + "on an Army you control. It's also " + + subType.getIndefiniteArticle() + ' ' + subType + ". If you don't control an Army, " + + "create a 0/0 black " + subType + " Army creature token first.)"; + } } private AmassEffect(final AmassEffect effect) { super(effect); - this.amount = effect.amount; + this.amount = effect.amount.copy(); this.subType = effect.subType; } @@ -59,7 +73,7 @@ public class AmassEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - return doAmass(amount, subType, game, source) != null; + return doAmass(amount.calculate(game, source, this), subType, game, source) != null; } private static Token makeToken(SubType subType) {