From ad5d1e498ff21f2d55bbf079e829925493cb5937 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 20 Apr 2021 08:47:41 -0400 Subject: [PATCH] [C21] Implemented Elementalist's Palette --- .../mage/cards/e/ElementalistsPalette.java | 161 ++++++++++++++++++ .../src/mage/cards/f/FrontlineMedic.java | 10 +- .../src/mage/sets/Commander2021Edition.java | 1 + .../mageobject/VariableManaCostPredicate.java | 7 +- 4 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/e/ElementalistsPalette.java diff --git a/Mage.Sets/src/mage/cards/e/ElementalistsPalette.java b/Mage.Sets/src/mage/cards/e/ElementalistsPalette.java new file mode 100644 index 0000000000..435f11e532 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElementalistsPalette.java @@ -0,0 +1,161 @@ +package mage.cards.e; + +import mage.ConditionalMana; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.VariableManaCost; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.mana.ManaEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.SimpleManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.abilities.mana.conditional.ManaCondition; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.VariableManaCostPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElementalistsPalette extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell with {X} in its mana cost"); + + static { + filter.add(VariableManaCostPredicate.instance); + } + + public ElementalistsPalette(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // Whenever you cast a spell with {X} in its mana cost, put two charge counters on Elementalist's Palette. + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2)), filter, false + )); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + + // {T}: Add {C} for each charge counter on Elementalist's Palette. Spend this mana only on costs that contain {X}. + this.addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, new ElementalistsPaletteManaEffect(), new TapSourceCost() + )); + } + + private ElementalistsPalette(final ElementalistsPalette card) { + super(card); + } + + @Override + public ElementalistsPalette copy() { + return new ElementalistsPalette(this); + } +} + +class ElementalistsPaletteManaEffect extends ManaEffect { + + private final ConditionalManaBuilder manaBuilder = new ElementalistsPaletteManaBuilder(); + + ElementalistsPaletteManaEffect() { + this.staticText = "add {C} for each charge counter on {this}. Spend this mana only on costs that contain {X}"; + } + + private ElementalistsPaletteManaEffect(final ElementalistsPaletteManaEffect effect) { + super(effect); + } + + @Override + public ElementalistsPaletteManaEffect copy() { + return new ElementalistsPaletteManaEffect(this); + } + + @Override + public List getNetMana(Game game, Ability source) { + List netMana = new ArrayList<>(); + if (game == null) { + return netMana; + } + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (permanent != null) { + netMana.add(manaBuilder.setMana(Mana.ColorlessMana( + permanent.getCounters(game).getCount(CounterType.CHARGE) + ), source, game).build()); + } + return netMana; + } + + @Override + public Mana produceMana(Game game, Ability source) { + Mana mana = new Mana(); + if (game == null) { + return mana; + } + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (permanent == null) { + return mana; + } + return manaBuilder.setMana(Mana.ColorlessMana( + permanent.getCounters(game).getCount(CounterType.CHARGE) + ), source, game).build(); + } +} + +class ElementalistsPaletteConditionalMana extends ConditionalMana { + + ElementalistsPaletteConditionalMana(Mana mana) { + super(mana); + addCondition(new ElementalistsPaletteManaCondition()); + } +} + +class ElementalistsPaletteManaBuilder extends ConditionalManaBuilder { + @Override + public ConditionalMana build(Object... options) { + return new ElementalistsPaletteConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only on costs that contain {X}"; + } +} + +class ElementalistsPaletteManaCondition extends ManaCondition { + + /* + A “cost that contains {X}” may be a spell’s total cost, an activated ability’s cost, a suspend cost, or a cost you’re + asked to pay as part of the resolution of a spell or ability (such as Condescend). A spell’s total cost includes either + its mana cost (printed in the upper right corner) or its alternative cost (such as flashback), as well as any additional + costs (such as kicker). If it’s something you can spend mana on, it’s a cost. If that cost includes the {X} symbol in it, + you can spend mana generated by Rosheen on that cost. (2017-11-17) + */ + @Override + public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { + boolean result; + if (costToPay instanceof ManaCosts) { + result = !((ManaCosts) costToPay).getVariableCosts().isEmpty(); + } else { + result = costToPay instanceof VariableManaCost; + } + if (!result) { + if (game != null && game.inCheckPlayableState()) { + return true; // TODO: Check the card if there are related abilities with {X} costs. + } + } + return result; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FrontlineMedic.java b/Mage.Sets/src/mage/cards/f/FrontlineMedic.java index d777306806..f3ef1946b1 100644 --- a/Mage.Sets/src/mage/cards/f/FrontlineMedic.java +++ b/Mage.Sets/src/mage/cards/f/FrontlineMedic.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,16 +14,17 @@ import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterSpell; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.VariableManaCostPredicate; import mage.target.TargetSpell; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FrontlineMedic extends CardImpl { @@ -32,11 +32,11 @@ public final class FrontlineMedic extends CardImpl { private static final FilterSpell filter = new FilterSpell("spell with {X} in its mana cost"); static { - filter.add(new VariableManaCostPredicate()); + filter.add(VariableManaCostPredicate.instance); } public FrontlineMedic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); diff --git a/Mage.Sets/src/mage/sets/Commander2021Edition.java b/Mage.Sets/src/mage/sets/Commander2021Edition.java index 9a81f21498..bfb4a5b2fc 100644 --- a/Mage.Sets/src/mage/sets/Commander2021Edition.java +++ b/Mage.Sets/src/mage/sets/Commander2021Edition.java @@ -106,6 +106,7 @@ public final class Commander2021Edition extends ExpansionSet { cards.add(new SetCardInfo("Dualcaster Mage", 165, Rarity.RARE, mage.cards.d.DualcasterMage.class)); cards.add(new SetCardInfo("Duelist's Heritage", 90, Rarity.RARE, mage.cards.d.DuelistsHeritage.class)); cards.add(new SetCardInfo("Duplicant", 242, Rarity.RARE, mage.cards.d.Duplicant.class)); + cards.add(new SetCardInfo("Elementalist's Palette", 76, Rarity.RARE, mage.cards.e.ElementalistsPalette.class)); cards.add(new SetCardInfo("Elite Scaleguard", 91, Rarity.UNCOMMON, mage.cards.e.EliteScaleguard.class)); cards.add(new SetCardInfo("Elixir of Immortality", 243, Rarity.UNCOMMON, mage.cards.e.ElixirOfImmortality.class)); cards.add(new SetCardInfo("Epic Experiment", 216, Rarity.MYTHIC, mage.cards.e.EpicExperiment.class)); diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/VariableManaCostPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/VariableManaCostPredicate.java index ef492472a4..3b159a887d 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/VariableManaCostPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/VariableManaCostPredicate.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.mageobject; import mage.MageObject; @@ -11,12 +10,12 @@ import mage.game.Game; * * @author LevelX2 */ -public class VariableManaCostPredicate implements Predicate { +public enum VariableManaCostPredicate implements Predicate { + instance; @Override public boolean apply(MageObject input, Game game) { - return input.getManaCost().stream().anyMatch(manaCost -> manaCost instanceof VariableManaCost); - + return input.getManaCost().stream().anyMatch(VariableManaCost.class::isInstance); } @Override