From 0f4e8a740ac9db663a62f23e7853d22b3e1ad55b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 24 May 2025 08:43:21 -0400 Subject: [PATCH] [FIC] Implement Maester Seymour --- .../src/mage/cards/m/MaesterSeymour.java | 102 ++++++++++++++++++ .../src/mage/sets/FinalFantasyCommander.java | 2 + .../abilities/keyword/MonstrosityAbility.java | 40 ++++--- 3 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/m/MaesterSeymour.java diff --git a/Mage.Sets/src/mage/cards/m/MaesterSeymour.java b/Mage.Sets/src/mage/cards/m/MaesterSeymour.java new file mode 100644 index 00000000000..a30bb7635a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaesterSeymour.java @@ -0,0 +1,102 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.MonstrosityAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.counters.Counters; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaesterSeymour extends CardImpl { + + public MaesterSeymour(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // At the beginning of combat on your turn, put a number of +1/+1 counters equal to Maester Seymour's power on another target creature you control. + Ability ability = new BeginningOfCombatTriggeredAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(), SourcePermanentPowerValue.NOT_NEGATIVE + ).setText("put a number of +1/+1 counters equal to {this}'s power on another target creature you control")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + + // {3}{G}{G}: Monstrosity X, where X is the number of counters among creatures you control. + this.addAbility(new MonstrosityAbility( + "{3}{G}{G}", MaesterSeymourValue.instance, null, "" + ).addHint(MaesterSeymourValue.getHint())); + } + + private MaesterSeymour(final MaesterSeymour card) { + super(card); + } + + @Override + public MaesterSeymour copy() { + return new MaesterSeymour(this); + } +} + +enum MaesterSeymourValue implements DynamicValue { + instance; + private static final Hint hint = new ValueHint( + "The number of counters among creatures you control", instance + ); + + public static Hint getHint() { + return hint; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + sourceAbility.getControllerId(), sourceAbility, game + ) + .stream() + .map(permanent -> permanent.getCounters(game)) + .mapToInt(Counters::getTotalCount) + .sum(); + } + + @Override + public MaesterSeymourValue copy() { + return this; + } + + @Override + public String getMessage() { + return "the number of counters among creatures you control"; + } + + @Override + public String toString() { + return "X"; + } +} diff --git a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java index 361101cd11f..3b8595f44f4 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java +++ b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java @@ -216,6 +216,8 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Luminous Broodmoth", 246, Rarity.MYTHIC, mage.cards.l.LuminousBroodmoth.class)); cards.add(new SetCardInfo("Lyse Hext", 178, Rarity.RARE, mage.cards.l.LyseHext.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lyse Hext", 88, Rarity.RARE, mage.cards.l.LyseHext.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maester Seymour", 160, Rarity.RARE, mage.cards.m.MaesterSeymour.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maester Seymour", 68, Rarity.RARE, mage.cards.m.MaesterSeymour.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mask of Memory", 350, Rarity.UNCOMMON, mage.cards.m.MaskOfMemory.class)); cards.add(new SetCardInfo("Meteor Golem", 351, Rarity.UNCOMMON, mage.cards.m.MeteorGolem.class)); cards.add(new SetCardInfo("Millikin", 352, Rarity.UNCOMMON, mage.cards.m.Millikin.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/MonstrosityAbility.java b/Mage/src/main/java/mage/abilities/keyword/MonstrosityAbility.java index e7555cc659e..66dc7b6f87d 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MonstrosityAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MonstrosityAbility.java @@ -4,6 +4,8 @@ import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.hint.common.MonstrousHint; import mage.constants.Outcome; @@ -14,6 +16,8 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.util.CardUtil; +import java.util.Optional; + /** * Monstrosity @@ -43,7 +47,7 @@ import mage.util.CardUtil; public class MonstrosityAbility extends ActivatedAbilityImpl { - private final int monstrosityValue; + private final DynamicValue monstrosityValue; public MonstrosityAbility(String manaString, int monstrosityValue) { this(manaString, monstrosityValue, null, ""); @@ -56,6 +60,10 @@ public class MonstrosityAbility extends ActivatedAbilityImpl { * @param costAdjusterText Clarifies the cost adjusting condition(s). */ public MonstrosityAbility(String manaString, int monstrosityValue, CostAdjuster costAdjuster, String costAdjusterText) { + this(manaString, StaticValue.get(monstrosityValue), costAdjuster, costAdjusterText); + } + + public MonstrosityAbility(String manaString, DynamicValue monstrosityValue, CostAdjuster costAdjuster, String costAdjusterText) { super(Zone.BATTLEFIELD, new BecomeMonstrousSourceEffect(monstrosityValue, costAdjusterText), new ManaCostsImpl<>(manaString)); this.monstrosityValue = monstrosityValue; this.addHint(MonstrousHint.instance); @@ -72,7 +80,7 @@ public class MonstrosityAbility extends ActivatedAbilityImpl { return new MonstrosityAbility(this); } - public int getMonstrosityValue() { + public DynamicValue getMonstrosityValue() { return monstrosityValue; } } @@ -80,11 +88,11 @@ public class MonstrosityAbility extends ActivatedAbilityImpl { class BecomeMonstrousSourceEffect extends OneShotEffect { - public BecomeMonstrousSourceEffect(int monstrosityValue) { + BecomeMonstrousSourceEffect(DynamicValue monstrosityValue) { this(monstrosityValue, ""); } - public BecomeMonstrousSourceEffect(int monstrosityValue, String costAdjusterText) { + BecomeMonstrousSourceEffect(DynamicValue monstrosityValue, String costAdjusterText) { super(Outcome.BoostCreature); this.staticText = setText(monstrosityValue, costAdjusterText); } @@ -104,11 +112,14 @@ class BecomeMonstrousSourceEffect extends OneShotEffect { if (permanent == null || permanent.isMonstrous()) { return false; } - int monstrosityValue = ((MonstrosityAbility) source).getMonstrosityValue(); - // handle monstrosity = X - if (monstrosityValue == Integer.MAX_VALUE) { - monstrosityValue = CardUtil.getSourceCostsTag(game, source, "X", 0); - } + int monstrosityValue = Optional + .ofNullable(source) + .map(MonstrosityAbility.class::cast) + .map(MonstrosityAbility::getMonstrosityValue) + .map(dynamicValue -> dynamicValue.calculate(game, source, this)) + // handle monstrosity = X + .map(i -> i == Integer.MAX_VALUE ? CardUtil.getSourceCostsTag(game, source, "X", 0) : i) + .orElse(0); permanent.addCounters( CounterType.P1P1.createInstance(monstrosityValue), source.getControllerId(), source, game @@ -121,10 +132,15 @@ class BecomeMonstrousSourceEffect extends OneShotEffect { return true; } - private String setText(int monstrosityValue, String costAdjusterText) { - return "Monstrosity " + (monstrosityValue == Integer.MAX_VALUE ? "X" : monstrosityValue) + + private String setText(DynamicValue monstrosityValue, String costAdjusterText) { + if (!(monstrosityValue instanceof StaticValue)) { + return "Monstrosity X, where X is " + monstrosityValue.getMessage() + ". " + costAdjusterText + + "(If this creature isn't monstrous, put X +1/+1 counters on it and it becomes monstrous.)"; + } + int value = ((StaticValue) monstrosityValue).getValue(); + return "Monstrosity " + (value == Integer.MAX_VALUE ? "X" : value) + ". " + costAdjusterText + "(If this creature isn't monstrous, put " + - (monstrosityValue == Integer.MAX_VALUE ? "X" : CardUtil.numberToText(monstrosityValue)) + + (value == Integer.MAX_VALUE ? "X" : CardUtil.numberToText(value)) + " +1/+1 counters on it and it becomes monstrous.)"; } }