From 3e217d992c8b02eea7cf9163e6df4c825bd83d91 Mon Sep 17 00:00:00 2001 From: Vivian Greenslade Date: Sat, 9 Sep 2023 01:28:09 -0230 Subject: [PATCH] [CLB] Implement Dynaheir, Invoker Adept (#11117) --- .../mage/cards/d/DynaheirInvokerAdept.java | 137 ++++++++++++++++++ .../CommanderLegendsBattleForBaldursGate.java | 1 + .../single/clb/DynaheirInvokerAdeptTest.java | 48 ++++++ 3 files changed, 186 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DynaheirInvokerAdept.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/clb/DynaheirInvokerAdeptTest.java diff --git a/Mage.Sets/src/mage/cards/d/DynaheirInvokerAdept.java b/Mage.Sets/src/mage/cards/d/DynaheirInvokerAdept.java new file mode 100644 index 00000000000..e49b7f4d21a --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DynaheirInvokerAdept.java @@ -0,0 +1,137 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackAbility; +import mage.watchers.common.ManaPaidSourceWatcher; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.CopyStackObjectEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; + +/** + * + * @author Xanderhall + */ +public final class DynaheirInvokerAdept extends CardImpl { + + public DynaheirInvokerAdept(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // You may activate abilities of other creatures you control as though those creatures had haste. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DynaheirInvokerAdeptHasteEffect())); + + // {T}: When you next activate an ability that isn't a mana ability this turn by spending four or more mana to activate it, copy that ability. You may choose new targets for the copy. + this.addAbility(new SimpleActivatedAbility(new CreateDelayedTriggeredAbilityEffect(new DynaheirInvokerAdeptTriggeredAbility()), new TapSourceCost())); + + } + + private DynaheirInvokerAdept(final DynaheirInvokerAdept card) { + super(card); + } + + @Override + public DynaheirInvokerAdept copy() { + return new DynaheirInvokerAdept(this); + } +} + +class DynaheirInvokerAdeptHasteEffect extends AsThoughEffectImpl { + + public DynaheirInvokerAdeptHasteEffect() { + super(AsThoughEffectType.ACTIVATE_HASTE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "you may activate abilities of other creatures you control as though those creatures had haste"; + } + + private DynaheirInvokerAdeptHasteEffect(final DynaheirInvokerAdeptHasteEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public DynaheirInvokerAdeptHasteEffect copy() { + return new DynaheirInvokerAdeptHasteEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + Permanent permanent = game.getPermanent(sourceId); + return permanent != null + && permanent.isCreature(game) + && permanent.isControlledBy(source.getControllerId()) + && !permanent.getId().equals(source.getSourceId()); + } +} + +class DynaheirInvokerAdeptTriggeredAbility extends DelayedTriggeredAbility { + + DynaheirInvokerAdeptTriggeredAbility() { + super(new CopyStackObjectEffect(), Duration.EndOfTurn, true); + } + + private DynaheirInvokerAdeptTriggeredAbility(final DynaheirInvokerAdeptTriggeredAbility ability) { + super(ability); + } + + @Override + public DynaheirInvokerAdeptTriggeredAbility copy() { + return new DynaheirInvokerAdeptTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!isControlledBy(event.getPlayerId())) { + return false; + } + StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); + if (stackAbility == null + || stackAbility.getStackAbility() instanceof ActivatedManaAbilityImpl + || ManaPaidSourceWatcher.getTotalPaid(stackAbility.getId(), game) < 4) { + return false; + } + this.getEffects().setValue("stackObject", stackAbility); + return true; + } + + @Override + public String getRule() { + return "When you next activate an ability this turn that isn't a mana ability by spending four or more mana to activate it, " + + "copy that ability. You may choose new targets for the copy."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java index 422ba16afc5..dc0c569b159 100644 --- a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java +++ b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java @@ -206,6 +206,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet { cards.add(new SetCardInfo("Dungeoneer's Pack", 312, Rarity.UNCOMMON, mage.cards.d.DungeoneersPack.class)); cards.add(new SetCardInfo("Dusk // Dawn", 691, Rarity.RARE, mage.cards.d.DuskDawn.class)); cards.add(new SetCardInfo("Dusk Mangler", 751, Rarity.UNCOMMON, mage.cards.d.DuskMangler.class)); + cards.add(new SetCardInfo("Dynaheir, Invoker Adept", 273, Rarity.RARE, mage.cards.d.DynaheirInvokerAdept.class)); cards.add(new SetCardInfo("Earth Tremor", 171, Rarity.COMMON, mage.cards.e.EarthTremor.class)); cards.add(new SetCardInfo("Earthquake Dragon", 228, Rarity.RARE, mage.cards.e.EarthquakeDragon.class)); cards.add(new SetCardInfo("Eight-and-a-Half-Tails", 692, Rarity.RARE, mage.cards.e.EightAndAHalfTails.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/clb/DynaheirInvokerAdeptTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/clb/DynaheirInvokerAdeptTest.java new file mode 100644 index 00000000000..b980eb37ffc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/clb/DynaheirInvokerAdeptTest.java @@ -0,0 +1,48 @@ +package org.mage.test.cards.single.clb; + +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import mage.constants.PhaseStep; +import mage.constants.Zone; + +public class DynaheirInvokerAdeptTest extends CardTestPlayerBase{ + + private static final String DYNA = "Dynaheir, Invoker Adept"; + private static final String BUTCHER = "Battlefield Butcher"; + private static final String ACOLYTE = "Acolyte of Xathrid"; + + /** + * Haste + * You may activate abilities of other creatures you control as though those creatures had haste. + * {T}: When you next activate an ability that isn’t a mana ability this turn by spending four or more mana to activate it, copy that ability. You may choose new targets for the copy. + */ + @Test + public void testEffect() { + + addCard(Zone.BATTLEFIELD, playerA, DYNA); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 15); + addCard(Zone.HAND, playerA, ACOLYTE); + addCard(Zone.HAND, playerA, BUTCHER); + + // Activate Dyna + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: When"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Cast Acolyte, should be able to activate, should not copy. + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ACOLYTE, true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{B}", playerB); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Cast Butcher, should be able to activate, should copy + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, BUTCHER, true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{5}"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + // Opponent should be at 15 life. + assertLife(playerB, 15); + } +}