diff --git a/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java b/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java index ee9932b32d..0aac5aa974 100644 --- a/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java +++ b/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java @@ -13,15 +13,13 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.predicate.mageobject.SharesColorPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.FractalToken; -import mage.game.permanent.token.Token; +import mage.game.permanent.token.QuandrixToken; import mage.players.Player; import mage.target.common.TargetCardInLibrary; @@ -48,7 +46,9 @@ public final class KasminaEnigmaSage extends CardImpl { this.addAbility(new LoyaltyAbility(new ScryEffect(1), 2)); // −X: Create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it. - this.addAbility(new LoyaltyAbility(new KasminaEnigmaSageTokenEffect())); + this.addAbility(new LoyaltyAbility(QuandrixToken.getEffect( + GetXLoyaltyValue.instance, "Put X +1/+1 counters on it" + ))); // −8: Search your library for an instant or sorcery card that shares a color with this planeswalker, exile that card, then shuffle. You may cast that card without paying its mana cost. this.addAbility(new LoyaltyAbility(new KasminaEnigmaSageSearchEffect(), -8)); @@ -106,40 +106,6 @@ class KasminaEnigmaSageGainAbilitiesEffect extends ContinuousEffectImpl { } } -class KasminaEnigmaSageTokenEffect extends OneShotEffect { - - KasminaEnigmaSageTokenEffect() { - super(Outcome.Benefit); - staticText = "create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it"; - } - - private KasminaEnigmaSageTokenEffect(final KasminaEnigmaSageTokenEffect effect) { - super(effect); - } - - @Override - public KasminaEnigmaSageTokenEffect copy() { - return new KasminaEnigmaSageTokenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Token token = new FractalToken(); - token.putOntoBattlefield(1, game, source, source.getControllerId()); - int loyalty = GetXLoyaltyValue.instance.calculate(game, source, this); - if (loyalty < 1) { - return true; - } - for (UUID tokenId : token.getLastAddedTokenIds()) { - Permanent permanent = game.getPermanent(tokenId); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(loyalty), source.getControllerId(), source, game); - } - } - return true; - } -} - class KasminaEnigmaSageSearchEffect extends OneShotEffect { KasminaEnigmaSageSearchEffect() { diff --git a/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java b/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java index be7cb06e18..b2bf373309 100644 --- a/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java +++ b/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java @@ -5,7 +5,10 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.Hint; import mage.abilities.keyword.FlyingAbility; import mage.cards.*; import mage.constants.*; @@ -13,15 +16,15 @@ import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterOwnedCard; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.FractalToken; -import mage.game.permanent.token.Token; +import mage.game.permanent.token.QuandrixToken; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInExile; +import java.util.List; import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 @@ -45,9 +48,10 @@ public final class KianneDeanOfSubstance extends ModalDoubleFacesCard { )); // {4}{G}: Create a 0/0 green and blue Fractal creature token. Put a +1/+1 counter on it for each different mana value among nonland cards you own in exile with study counters on them. - this.getLeftHalfCard().addAbility(new SimpleActivatedAbility( - new KianneDeanOfSubstanceTokenEffect(), new ManaCostsImpl("{4}{G}") - )); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(QuandrixToken.getEffect( + KianneDeanOfSubstanceValue.instance, "Put a +1/+1 counter on it for each different mana value " + + "among nonland cards you own in exile with study counters on them" + ), new ManaCostsImpl("{4}{G}")).addHint(KianneDeanOfSubstanceHint.instance)); // 2. // Imbraham, Dean of Theory @@ -114,48 +118,62 @@ class KianneDeanOfSubstanceExileEffect extends OneShotEffect { } } -class KianneDeanOfSubstanceTokenEffect extends OneShotEffect { - - KianneDeanOfSubstanceTokenEffect() { - super(Outcome.Benefit); - staticText = "create a 0/0 green and blue Fractal creature token. Put a +1/+1 counter on it " + - "for each different mana value among nonland cards you own in exile with study counters on them"; - } - - private KianneDeanOfSubstanceTokenEffect(final KianneDeanOfSubstanceTokenEffect effect) { - super(effect); - } +enum KianneDeanOfSubstanceValue implements DynamicValue { + instance; @Override - public KianneDeanOfSubstanceTokenEffect copy() { - return new KianneDeanOfSubstanceTokenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Token token = new FractalToken(); - token.putOntoBattlefield(1, game, source, source.getControllerId()); - int exileCount = game + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game .getExile() .getAllCards(game) .stream() .filter(Objects::nonNull) - .filter(card -> card.isOwnedBy(source.getControllerId())) + .filter(card -> card.isOwnedBy(sourceAbility.getControllerId())) + .filter(card -> card.getCounters(game).containsKey(CounterType.STUDY)) .map(MageObject::getConvertedManaCost) .distinct() .mapToInt(x -> 1) .sum(); - if (exileCount < 1) { - return true; + } + + @Override + public KianneDeanOfSubstanceValue copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} + +enum KianneDeanOfSubstanceHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + List values = game.getExile() + .getAllCards(game) + .stream() + .filter(Objects::nonNull) + .filter(card -> card.isOwnedBy(ability.getControllerId())) + .filter(card -> card.getCounters(game).containsKey(CounterType.STUDY)) + .map(MageObject::getConvertedManaCost) + .distinct() + .sorted() + .collect(Collectors.toList()); + String message = "" + values.size(); + if (values.size() > 0) { + message += " ("; + message += values.stream().map(i -> "" + i).reduce((a, b) -> a + ", " + b).orElse(""); + message += ')'; } - for (UUID tokenId : token.getLastAddedTokenIds()) { - Permanent permanent = game.getPermanent(tokenId); - if (permanent == null) { - continue; - } - permanent.addCounters(CounterType.P1P1.createInstance(exileCount), source.getControllerId(), source, game); - } - return true; + return "Mana values of cards exiled with study counters: " + message; + } + + @Override + public KianneDeanOfSubstanceHint copy() { + return instance; } } diff --git a/Mage.Sets/src/mage/cards/m/ManifestationSage.java b/Mage.Sets/src/mage/cards/m/ManifestationSage.java new file mode 100644 index 0000000000..93a4fd74fe --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/ManifestationSage.java @@ -0,0 +1,42 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.QuandrixToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ManifestationSage extends CardImpl { + + public ManifestationSage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G/U}{G/U}{G/U}{G/U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Manifestation Sage enters the battlefield, create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it, where X is the number of cards in your hand. + this.addAbility(new EntersBattlefieldTriggeredAbility(QuandrixToken.getEffect( + CardsInControllerHandCount.instance, "Put X +1/+1 counters on it, " + + "where X is the number of cards in your hand" + ))); + } + + private ManifestationSage(final ManifestationSage card) { + super(card); + } + + @Override + public ManifestationSage copy() { + return new ManifestationSage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java b/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java index 5d5c3f9513..eb7a67ba76 100644 --- a/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java +++ b/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java @@ -83,6 +83,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet { cards.add(new SetCardInfo("Lorehold Pledgemage", 201, Rarity.COMMON, mage.cards.l.LoreholdPledgemage.class)); cards.add(new SetCardInfo("Mage Hunter", 76, Rarity.UNCOMMON, mage.cards.m.MageHunter.class)); cards.add(new SetCardInfo("Magma Opus", 203, Rarity.MYTHIC, mage.cards.m.MagmaOpus.class)); + cards.add(new SetCardInfo("Manifestation Sage", 205, Rarity.RARE, mage.cards.m.ManifestationSage.class)); cards.add(new SetCardInfo("Mountain", 372, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Multiple Choice", 48, Rarity.RARE, mage.cards.m.MultipleChoice.class)); cards.add(new SetCardInfo("Necroblossom Snarl", 269, Rarity.RARE, mage.cards.n.NecroblossomSnarl.class)); diff --git a/Mage/src/main/java/mage/game/permanent/token/FractalToken.java b/Mage/src/main/java/mage/game/permanent/token/FractalToken.java deleted file mode 100644 index fbe83a0e0f..0000000000 --- a/Mage/src/main/java/mage/game/permanent/token/FractalToken.java +++ /dev/null @@ -1,33 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.Arrays; - -/** - * @author TheElk801 - */ -public final class FractalToken extends TokenImpl { - - public FractalToken() { - super("Fractal", "0/0 green and blue Fractal creature token"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.FRACTAL); - color.setGreen(true); - color.setBlue(true); - power = new MageInt(0); - toughness = new MageInt(0); - - availableImageSetCodes = Arrays.asList("STX"); - } - - private FractalToken(final FractalToken token) { - super(token); - } - - public FractalToken copy() { - return new FractalToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/QuandrixToken.java b/Mage/src/main/java/mage/game/permanent/token/QuandrixToken.java new file mode 100644 index 0000000000..88a3b218ea --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/QuandrixToken.java @@ -0,0 +1,85 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.OneShotEffect; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Arrays; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class QuandrixToken extends TokenImpl { + + public QuandrixToken() { + super("Fractal", "0/0 green and blue Fractal creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.FRACTAL); + color.setGreen(true); + color.setBlue(true); + power = new MageInt(0); + toughness = new MageInt(0); + + availableImageSetCodes = Arrays.asList("STX"); + } + + private QuandrixToken(final QuandrixToken token) { + super(token); + } + + public QuandrixToken copy() { + return new QuandrixToken(this); + } + + public static QuandrixTokenEffect getEffect(DynamicValue xValue, String text) { + return new QuandrixTokenEffect(xValue, text); + } + + private static final class QuandrixTokenEffect extends OneShotEffect { + + private final DynamicValue xValue; + + private QuandrixTokenEffect(DynamicValue xValue, String text) { + super(Outcome.Benefit); + this.xValue = xValue; + this.staticText = "create a 0/0 green and blue Fractal creature token. " + text; + } + + private QuandrixTokenEffect(final QuandrixTokenEffect effect) { + super(effect); + this.xValue = effect.xValue; + } + + @Override + public QuandrixTokenEffect copy() { + return new QuandrixTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new QuandrixToken(); + token.putOntoBattlefield(1, game, source, source.getControllerId()); + int value = xValue.calculate(game, source, this); + if (value < 1) { + return true; + } + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent permanent = game.getPermanent(tokenId); + if (permanent == null) { + continue; + } + permanent.addCounters(CounterType.P1P1.createInstance(value), source.getControllerId(), source, game); + } + return true; + } + } + +}