From a93026b770e55e6a71fe2e3422a4df7ad0759825 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sun, 18 May 2025 15:30:33 -0400 Subject: [PATCH] [FIN] Implement Serah Farron / Crystallized Serah --- .../src/mage/cards/c/CrystallizedSerah.java | 45 ++++++ Mage.Sets/src/mage/cards/s/SerahFarron.java | 138 ++++++++++++++++++ Mage.Sets/src/mage/sets/FinalFantasy.java | 4 + 3 files changed, 187 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CrystallizedSerah.java create mode 100644 Mage.Sets/src/mage/cards/s/SerahFarron.java diff --git a/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java b/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java new file mode 100644 index 00000000000..aa2e88a4097 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java @@ -0,0 +1,45 @@ +package mage.cards.c; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.s.SerahFarron; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrystallizedSerah extends CardImpl { + + public CrystallizedSerah(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); + + this.supertype.add(SuperType.LEGENDARY); + this.nightCard = true; + this.color.setGreen(true); + this.color.setWhite(true); + + // The first legendary creature spell you cast each turn costs {2} less to cast. + this.addAbility(SerahFarron.makeAbility()); + + // Legendary creatures you control get +2/+2. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 2, 2, Duration.WhileControlled, StaticFilters.FILTER_CREATURES_LEGENDARY + ))); + } + + private CrystallizedSerah(final CrystallizedSerah card) { + super(card); + } + + @Override + public CrystallizedSerah copy() { + return new CrystallizedSerah(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerahFarron.java b/Mage.Sets/src/mage/cards/s/SerahFarron.java new file mode 100644 index 00000000000..5e77209c353 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SerahFarron.java @@ -0,0 +1,138 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueConditionHint; +import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.WatcherScope; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SerahFarron extends CardImpl { + + private static final FilterCard filter + = new FilterCreatureCard("the first legendary creature spell you cast each turn"); + private static final FilterPermanent filter2 + = new FilterControlledCreaturePermanent("you control two or more other legendary creatures"); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + filter.add(SerahFarronPredicate.instance); + filter2.add(AnotherPredicate.instance); + filter2.add(SuperType.LEGENDARY.getPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter2); + private static final Hint hint = new ValueConditionHint( + "You control two or more other legendary creatures", + new PermanentsOnBattlefieldCount(filter2), condition + ); + + public SerahFarron(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.secondSideCardClazz = mage.cards.c.CrystallizedSerah.class; + + // The first legendary creature spell you cast each turn costs {2} less to cast. + this.addAbility(makeAbility(), new SerahFarronWatcher()); + + // At the beginning of combat on your turn, if you control two or more other legendary creatures, you may transform Serah Farron. + this.addAbility(new TransformAbility()); + this.addAbility(new BeginningOfCombatTriggeredAbility( + new TransformSourceEffect(), true + ).withInterveningIf(condition).addHint(hint)); + } + + private SerahFarron(final SerahFarron card) { + super(card); + } + + @Override + public SerahFarron copy() { + return new SerahFarron(this); + } + + public static Ability makeAbility() { + return new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2)); + } + +} + +enum SerahFarronPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return !SerahFarronWatcher.checkPlayer(input.getPlayerId(), game); + } + + @Override + public String toString() { + return "The first creature spell you cast each turn"; + } +} + +class SerahFarronWatcher extends Watcher { + + private final Set set = new HashSet<>(); + + public SerahFarronWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell != null && spell.isCreature(game) && spell.isLegendary(game)) { + set.add(event.getPlayerId()); + } + } + + @Override + public void reset() { + super.reset(); + set.clear(); + } + + static boolean checkPlayer(UUID playerId, Game game) { + return game.getState().getWatcher(SerahFarronWatcher.class).set.contains(playerId); + } +} diff --git a/Mage.Sets/src/mage/sets/FinalFantasy.java b/Mage.Sets/src/mage/sets/FinalFantasy.java index a1d120d9761..7f99503caa6 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasy.java +++ b/Mage.Sets/src/mage/sets/FinalFantasy.java @@ -94,6 +94,8 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Coeurl", 12, Rarity.COMMON, mage.cards.c.Coeurl.class)); cards.add(new SetCardInfo("Commune with Beavers", 182, Rarity.COMMON, mage.cards.c.CommuneWithBeavers.class)); cards.add(new SetCardInfo("Cooking Campsite", 31, Rarity.UNCOMMON, mage.cards.c.CookingCampsite.class)); + cards.add(new SetCardInfo("Crystallized Serah", 240, Rarity.RARE, mage.cards.c.CrystallizedSerah.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crystallized Serah", 506, Rarity.RARE, mage.cards.c.CrystallizedSerah.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark Confidant", 334, Rarity.MYTHIC, mage.cards.d.DarkConfidant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark Confidant", 94, Rarity.MYTHIC, mage.cards.d.DarkConfidant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deadly Embrace", 557, Rarity.RARE, mage.cards.d.DeadlyEmbrace.class)); @@ -236,6 +238,8 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Sephiroth, One-Winged Angel", 527, Rarity.MYTHIC, mage.cards.s.SephirothOneWingedAngel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Planet's Heir", 505, Rarity.MYTHIC, mage.cards.s.SephirothPlanetsHeir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Planet's Heir", 553, Rarity.MYTHIC, mage.cards.s.SephirothPlanetsHeir.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Serah Farron", 240, Rarity.RARE, mage.cards.s.SerahFarron.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Serah Farron", 506, Rarity.RARE, mage.cards.s.SerahFarron.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seymour Flux", 452, Rarity.RARE, mage.cards.s.SeymourFlux.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seymour Flux", 558, Rarity.RARE, mage.cards.s.SeymourFlux.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Shambling Cie'th", 117, Rarity.UNCOMMON, mage.cards.s.ShamblingCieth.class));