forked from External/mage
[LTC] Implement Summons of Saruman (#10720)
* [LTC] Implement Summons of Saruman * fix constructor for Assault on Osgiliath * fix verify failure * refactoring a couple more Amass X
This commit is contained in:
parent
1c5829f16b
commit
241226cd83
7 changed files with 160 additions and 101 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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. "
|
||||
+ "<i>(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.)</i>")
|
||||
);
|
||||
}
|
||||
|
||||
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. " +
|
||||
"<i>(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.)</i>";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
Mage.Sets/src/mage/cards/s/SummonsOfSaruman.java
Normal file
118
Mage.Sets/src/mage/cards/s/SummonsOfSaruman.java
Normal file
|
|
@ -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."
|
||||
+ " <i>(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.)</i>";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 + ". <i>(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.)</i>";
|
||||
|
||||
staticText = "amass " + subType + "s " + amount + ".";
|
||||
if (withReminder) {
|
||||
staticText += " <i>(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.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue