From 331728c238215d2d1e7706d49977452680941e05 Mon Sep 17 00:00:00 2001 From: Alex Vasile <48962821+Alex-Vasile@users.noreply.github.com> Date: Sat, 5 Feb 2022 14:55:27 -0500 Subject: [PATCH] [VOC] Implemented Donal, Herald of Wings (#8653) * Implemented Donal, Herald of Wings * Made the spell work only once per turn * Made the spell work only once per turn * - Changed based on Nykthos Paragon - Fixed properly adjusting power and toughness - Fixed card text --- .../src/mage/cards/d/DonalHeraldOfWings.java | 138 ++++++++++++++++++ .../src/mage/sets/CrimsonVowCommander.java | 2 + .../main/java/mage/filter/StaticFilters.java | 9 +- 3 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java diff --git a/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java b/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java new file mode 100644 index 00000000000..2df6161f99f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java @@ -0,0 +1,138 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; +import mage.util.functions.StackObjectCopyApplier; + +import java.util.UUID; + +/** + * @author Alex-Vasile + */ +public class DonalHeraldOfWings extends CardImpl { + + public DonalHeraldOfWings(UUID ownderId, CardSetInfo setInfo) { + super(ownderId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + + this.addSubType(SubType.HUMAN); + this.addSubType(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever you cast a nonlegendary creature spell with flying, you may copy it, + // except the copy is a 1/1 Spirit in addition to its other types. + // Do this only once each turn. (The copy becomes a token.) + // TODO: This still triggers and asks if you wanna use it, even if you've used it once this turn. + this.addAbility(new DonalHeraldOfWingsTriggeredAbility()); + } + + private DonalHeraldOfWings(final DonalHeraldOfWings card) { super(card); } + + @Override + public DonalHeraldOfWings copy() { return new DonalHeraldOfWings(this); } +} + +class DonalHeraldOfWingsTriggeredAbility extends SpellCastControllerTriggeredAbility { + + private static final FilterSpell filterSpell = new FilterSpell("a nonlegendary creature spell with flying"); + static { + filterSpell.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + filterSpell.add(CardType.CREATURE.getPredicate()); + } + + DonalHeraldOfWingsTriggeredAbility() { + super(new DonalHeraldOfWingsEffect(), filterSpell, true, true); + } + + private DonalHeraldOfWingsTriggeredAbility(final DonalHeraldOfWingsTriggeredAbility ability) { super(ability); } + + @Override + public DonalHeraldOfWingsTriggeredAbility copy() { + return new DonalHeraldOfWingsTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return abilityAvailableThisTurn(game) && super.checkTrigger(event, game); + } + + @Override + public boolean resolve(Game game) { + if (!(abilityAvailableThisTurn(game) && super.resolve(game))) { return false; } + game.getState().setValue( + CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game), + game.getTurnNum() + ); + + return true; + } + + private boolean abilityAvailableThisTurn(Game game) { + Integer lastTurnResolved = (Integer) game.getState().getValue( + CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game) + ); + // A null result is assumed to mean the this ability has not been used yet. + return lastTurnResolved == null || lastTurnResolved != game.getTurnNum(); + } +} + +class DonalHeraldOfWingsEffect extends OneShotEffect { + + DonalHeraldOfWingsEffect() { + super(Outcome.Copy); + staticText = "you may copy it, except the copy is a 1/1 Spirit in addition to its other types. " + + "Do this only once each turn. (The copy becomes a token.)"; + } + + private DonalHeraldOfWingsEffect(final DonalHeraldOfWingsEffect effect) { super(effect); } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + + // Get the card that was cast + if (this.getTargetPointer() == null) { return false; } + Spell originalSpell = game.getStack().getSpell(((FixedTarget) this.getTargetPointer()).getTarget()); + + // Create a token copy + originalSpell.createCopyOnStack(game, source, controller.getId(), false, 1, DonalHeraldOfWingsApplier.instance); + + return true; + } + + @Override + public Effect copy() { return new DonalHeraldOfWingsEffect(this); } +} + +enum DonalHeraldOfWingsApplier implements StackObjectCopyApplier { + instance; + + @Override + public void modifySpell(StackObject copiedSpell, Game game) { + copiedSpell.addSubType(SubType.SPIRIT); + copiedSpell.getPower().modifyBaseValue(1); + copiedSpell.getToughness().modifyBaseValue(1); + } + + @Override + public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) { return null; } +} diff --git a/Mage.Sets/src/mage/sets/CrimsonVowCommander.java b/Mage.Sets/src/mage/sets/CrimsonVowCommander.java index 419a79379f6..4ae6c908ed9 100644 --- a/Mage.Sets/src/mage/sets/CrimsonVowCommander.java +++ b/Mage.Sets/src/mage/sets/CrimsonVowCommander.java @@ -57,6 +57,8 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Darksteel Mutation", 84, Rarity.UNCOMMON, mage.cards.d.DarksteelMutation.class)); cards.add(new SetCardInfo("Disorder in the Court", 29, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class)); cards.add(new SetCardInfo("Distant Melody", 103, Rarity.COMMON, mage.cards.d.DistantMelody.class)); + cards.add(new SetCardInfo("Donal, Herald of Wings", 3, Rarity.MYTHIC, mage.cards.d.DonalHeraldOfWings.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Donal, Herald of Wings", 41, Rarity.MYTHIC, mage.cards.d.DonalHeraldOfWings.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doom Weaver", 34, Rarity.RARE, mage.cards.d.DoomWeaver.class)); cards.add(new SetCardInfo("Dovin, Grand Arbiter", 153, Rarity.MYTHIC, mage.cards.d.DovinGrandArbiter.class)); cards.add(new SetCardInfo("Drogskol Captain", 154, Rarity.UNCOMMON, mage.cards.d.DrogskolCaptain.class)); diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 0122ade113f..70ce960cf5a 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -699,21 +699,24 @@ public final class StaticFilters { FILTER_SPELL_CREATURE.setLockedFilter(true); } - public static final FilterSpell FILTER_SPELL_NON_CREATURE = (FilterSpell) new FilterSpell("noncreature spell").add(Predicates.not(CardType.CREATURE.getPredicate())); + public static final FilterSpell FILTER_SPELL_NON_CREATURE = (FilterSpell) new FilterSpell("noncreature spell"); static { + FILTER_SPELL_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate())); FILTER_SPELL_NON_CREATURE.setLockedFilter(true); } - public static final FilterSpell FILTER_SPELLS_NON_CREATURE = (FilterSpell) new FilterSpell("noncreature spells").add(Predicates.not(CardType.CREATURE.getPredicate())); + public static final FilterSpell FILTER_SPELLS_NON_CREATURE = (FilterSpell) new FilterSpell("noncreature spells"); static { + FILTER_SPELLS_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate())); FILTER_SPELLS_NON_CREATURE.setLockedFilter(true); } - public static final FilterSpell FILTER_SPELL_A_NON_CREATURE = (FilterSpell) new FilterSpell("a noncreature spell").add(Predicates.not(CardType.CREATURE.getPredicate())); + public static final FilterSpell FILTER_SPELL_A_NON_CREATURE = (FilterSpell) new FilterSpell("a noncreature spell"); static { + FILTER_SPELL_A_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate())); FILTER_SPELL_A_NON_CREATURE.setLockedFilter(true); }