From ee1a280410c38f9f107bf60a780af92e25984bf3 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 20 Jan 2026 10:13:25 -0500 Subject: [PATCH] [ECC] Implement Ferrafor, Young Yew --- .../src/mage/cards/e/ElvishVatkeeper.java | 2 +- .../src/mage/cards/f/FerraforYoungYew.java | 94 +++++++++++++++++++ .../src/mage/cards/i/InvigoratingSurge.java | 4 +- .../src/mage/cards/o/OrneryTumblewagg.java | 7 +- Mage.Sets/src/mage/cards/s/SageOfTheFang.java | 3 +- Mage.Sets/src/mage/cards/s/SazhKatzroy.java | 3 +- .../src/mage/cards/s/SeismicTutelage.java | 2 +- .../src/mage/cards/t/TanazirQuandrix.java | 4 +- .../src/mage/cards/v/VisionsOfDominance.java | 4 +- .../mage/sets/LorwynEclipsedCommander.java | 2 + .../common/DoubleCountersTargetEffect.java | 35 ++++++- 11 files changed, 141 insertions(+), 19 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/f/FerraforYoungYew.java diff --git a/Mage.Sets/src/mage/cards/e/ElvishVatkeeper.java b/Mage.Sets/src/mage/cards/e/ElvishVatkeeper.java index 9f705d6455f..92c46271b9a 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishVatkeeper.java +++ b/Mage.Sets/src/mage/cards/e/ElvishVatkeeper.java @@ -46,7 +46,7 @@ public final class ElvishVatkeeper extends CardImpl { // {5}: Transform target Incubator token you control. Double the number of +1/+1 counters on it. Ability ability = new SimpleActivatedAbility(new TransformTargetEffect(), new GenericManaCost(5)); - ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1)); + ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1).withTargetDescription("it")); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FerraforYoungYew.java b/Mage.Sets/src/mage/cards/f/FerraforYoungYew.java new file mode 100644 index 00000000000..0acbb5d356a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FerraforYoungYew.java @@ -0,0 +1,94 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoubleCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.SaprolingToken; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FerraforYoungYew extends CardImpl { + + public FerraforYoungYew(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.TREEFOLK); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(4); + this.toughness = new MageInt(7); + + // When Ferrafor enters, create a number of 1/1 green Saproling creature tokens equal to the number of counters among creatures target player controls. + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect( + new SaprolingToken(), FerraforYoungYewValue.instance + ).setText("create a number of 1/1 green Saproling creature tokens equal " + + "to the number of counters among creatures target player controls")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // {T}: Double the number of each kind of counter on target creature. + ability = new SimpleActivatedAbility(new DoubleCountersTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private FerraforYoungYew(final FerraforYoungYew card) { + super(card); + } + + @Override + public FerraforYoungYew copy() { + return new FerraforYoungYew(this); + } +} + +enum FerraforYoungYewValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player player = game.getPlayer(effect.getTargetPointer().getFirst(game, sourceAbility)); + return player != null + ? game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), sourceAbility, game) + .stream() + .mapToInt(permanent -> permanent.getCounters(game).getTotalCount()) + .sum() + : 0; + } + + @Override + public FerraforYoungYewValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvigoratingSurge.java b/Mage.Sets/src/mage/cards/i/InvigoratingSurge.java index 0ffb169e787..ce419daea41 100644 --- a/Mage.Sets/src/mage/cards/i/InvigoratingSurge.java +++ b/Mage.Sets/src/mage/cards/i/InvigoratingSurge.java @@ -21,8 +21,8 @@ public final class InvigoratingSurge extends CardImpl { // Put a +1/+1 counter on target creature you control, then double the number of +1/+1 counters on that creature. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); this.getSpellAbility().addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) - .setText(", then double the number of +1/+1 counters on that creature") - ); + .withTargetDescription("that creature") + .concatBy(", then")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/o/OrneryTumblewagg.java b/Mage.Sets/src/mage/cards/o/OrneryTumblewagg.java index 5aa5c3cbdbc..1357f31e9a3 100644 --- a/Mage.Sets/src/mage/cards/o/OrneryTumblewagg.java +++ b/Mage.Sets/src/mage/cards/o/OrneryTumblewagg.java @@ -3,10 +3,10 @@ package mage.cards.o; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksWhileSaddledTriggeredAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.common.DoubleCountersTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.SaddleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -37,10 +37,7 @@ public final class OrneryTumblewagg extends CardImpl { this.addAbility(ability); // Whenever Ornery Tumblewagg attacks while saddled, double the number of +1/+1 counters on target creature. - ability = new AttacksWhileSaddledTriggeredAbility( - new DoubleCountersTargetEffect(CounterType.P1P1) - .setText("double the number of +1/+1 counters on target creature") - ); + ability = new AttacksWhileSaddledTriggeredAbility(new DoubleCountersTargetEffect(CounterType.P1P1)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SageOfTheFang.java b/Mage.Sets/src/mage/cards/s/SageOfTheFang.java index 12a152c90d9..e6d2c2fdcf4 100644 --- a/Mage.Sets/src/mage/cards/s/SageOfTheFang.java +++ b/Mage.Sets/src/mage/cards/s/SageOfTheFang.java @@ -36,7 +36,8 @@ public final class SageOfTheFang extends CardImpl { // Renew -- {3}{G}, Exile this card from your graveyard: Put a +1/+1 counter on target creature, then double the number of +1/+1 counters on that creature. ability = new RenewAbility("{3}{G}", CounterType.P1P1.createInstance()); ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) - .setText(", then double the number of +1/+1 counters on that creature")); + .withTargetDescription("that creature") + .concatBy(", then")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SazhKatzroy.java b/Mage.Sets/src/mage/cards/s/SazhKatzroy.java index 471c30bd44e..39e5b383eeb 100644 --- a/Mage.Sets/src/mage/cards/s/SazhKatzroy.java +++ b/Mage.Sets/src/mage/cards/s/SazhKatzroy.java @@ -54,7 +54,8 @@ public final class SazhKatzroy extends CardImpl { // Whenever Sazh Katzroy attacks, put counter on target creature, then double the number of +1/+1 counters on that creature. Ability ability = new AttacksTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) - .setText(", then double the number of +1/+1 counters on that creature")); + .withTargetDescription("that creature") + .concatBy(", then")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SeismicTutelage.java b/Mage.Sets/src/mage/cards/s/SeismicTutelage.java index c93c4e06f2c..1e4a68bfa97 100644 --- a/Mage.Sets/src/mage/cards/s/SeismicTutelage.java +++ b/Mage.Sets/src/mage/cards/s/SeismicTutelage.java @@ -38,7 +38,7 @@ public final class SeismicTutelage extends CardImpl { // Whenever enchanted creature attacks, double the number of +1/+1 counters on it. this.addAbility(new AttacksAttachedTriggeredAbility( - new DoubleCountersTargetEffect(CounterType.P1P1), + new DoubleCountersTargetEffect(CounterType.P1P1).withTargetDescription("it"), AttachmentType.AURA, false, SetTargetPointer.PERMANENT )); } diff --git a/Mage.Sets/src/mage/cards/t/TanazirQuandrix.java b/Mage.Sets/src/mage/cards/t/TanazirQuandrix.java index a7230739e4d..eef19ba0cb6 100644 --- a/Mage.Sets/src/mage/cards/t/TanazirQuandrix.java +++ b/Mage.Sets/src/mage/cards/t/TanazirQuandrix.java @@ -43,9 +43,7 @@ public final class TanazirQuandrix extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Tanazir Quandrix enters the battlefield, double the number of +1/+1 counters on target creature you control. - Ability ability = new EntersBattlefieldTriggeredAbility(new DoubleCountersTargetEffect(CounterType.P1P1) - .setText("double the number of +1/+1 counters on target creature you control") - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new DoubleCountersTargetEffect(CounterType.P1P1)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/v/VisionsOfDominance.java b/Mage.Sets/src/mage/cards/v/VisionsOfDominance.java index 760d60e4679..29c280b64ef 100644 --- a/Mage.Sets/src/mage/cards/v/VisionsOfDominance.java +++ b/Mage.Sets/src/mage/cards/v/VisionsOfDominance.java @@ -24,7 +24,9 @@ public final class VisionsOfDominance extends CardImpl { // Put a +1/+1 counter on target creature, then double the number of +1/+1 counters on it. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - this.getSpellAbility().addEffect(new DoubleCountersTargetEffect(CounterType.P1P1).concatBy(", then")); + this.getSpellAbility().addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) + .withTargetDescription("it") + .concatBy(", then")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Flashback {8}{G}{G}. This spell costs {X} less to cast this way, where X is the greatest mana value of a commander you own on the battlefield or in the command zone. diff --git a/Mage.Sets/src/mage/sets/LorwynEclipsedCommander.java b/Mage.Sets/src/mage/sets/LorwynEclipsedCommander.java index bbf5ae61327..ba7d2034cfe 100644 --- a/Mage.Sets/src/mage/sets/LorwynEclipsedCommander.java +++ b/Mage.Sets/src/mage/sets/LorwynEclipsedCommander.java @@ -69,6 +69,8 @@ public final class LorwynEclipsedCommander extends ExpansionSet { cards.add(new SetCardInfo("Exotic Orchard", 148, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); cards.add(new SetCardInfo("Faeburrow Elder", 53, Rarity.RARE, mage.cards.f.FaeburrowElder.class)); cards.add(new SetCardInfo("Fellwar Stone", 141, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); + cards.add(new SetCardInfo("Ferrafor, Young Yew", 16, Rarity.RARE, mage.cards.f.FerraforYoungYew.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ferrafor, Young Yew", 36, Rarity.RARE, mage.cards.f.FerraforYoungYew.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fertile Ground", 106, Rarity.COMMON, mage.cards.f.FertileGround.class)); cards.add(new SetCardInfo("Festering Thicket", 61, Rarity.RARE, mage.cards.f.FesteringThicket.class)); cards.add(new SetCardInfo("Fire Covenant", 54, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoubleCountersTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoubleCountersTargetEffect.java index bb34719a6bc..1641d9e10fe 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoubleCountersTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoubleCountersTargetEffect.java @@ -1,8 +1,10 @@ package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.counters.Counter; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -14,10 +16,13 @@ public class DoubleCountersTargetEffect extends OneShotEffect { private final CounterType counterType; + public DoubleCountersTargetEffect() { + this((CounterType) null); + } + public DoubleCountersTargetEffect(CounterType counterType) { super(Outcome.Benefit); this.counterType = counterType; - staticText = "double the number of " + counterType.getName() + " counters on it"; } private DoubleCountersTargetEffect(final DoubleCountersTargetEffect effect) { @@ -36,8 +41,30 @@ public class DoubleCountersTargetEffect extends OneShotEffect { if (permanent == null) { return false; } - return permanent.addCounters(counterType.createInstance( - permanent.getCounters(game).getCount(counterType) - ), source.getControllerId(), source, game); + if (counterType != null) { + return permanent.addCounters(counterType.createInstance( + permanent.getCounters(game).getCount(counterType) + ), source.getControllerId(), source, game); + } + for (Counter counter : permanent.getCounters(game).copy().values()) { + permanent.addCounters(counter, source, game); + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder("double the number of "); + if (counterType == null) { + sb.append("each kind of counter on "); + } else { + sb.append(counterType); + sb.append(" counters on "); + } + sb.append(getTargetPointer().describeTargets(mode.getTargets(), "it")); + return sb.toString(); } }