diff --git a/Mage.Sets/src/mage/cards/a/AbolethSpawn.java b/Mage.Sets/src/mage/cards/a/AbolethSpawn.java new file mode 100644 index 00000000000..91a870be73d --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AbolethSpawn.java @@ -0,0 +1,105 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CopyStackObjectEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; + +import java.util.UUID; + +/** + * @author Rowan-Gudmundsson, xenohedron + */ +public final class AbolethSpawn extends CardImpl { + + public AbolethSpawn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.FISH); + this.subtype.add(SubType.HORROR); + + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Ward {2} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); + + // Whenever a creature entering the battlefield under an opponent's control causes a triggered ability of that creature to trigger, + // you may copy that ability. You may choose new targets for the copy. + this.addAbility(new AbolethSpawnTriggeredAbility()); + } + + private AbolethSpawn(final AbolethSpawn card) { + super(card); + } + + @Override + public AbolethSpawn copy() { + return new AbolethSpawn(this); + } +} + +class AbolethSpawnTriggeredAbility extends TriggeredAbilityImpl { + + AbolethSpawnTriggeredAbility() { + super(Zone.BATTLEFIELD, new CopyStackObjectEffect(), true); + setTriggerPhrase("Whenever a creature entering the battlefield under an opponent's control causes a triggered ability of that creature to trigger, "); + } + + private AbolethSpawnTriggeredAbility(final AbolethSpawnTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TRIGGERED_ABILITY; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject stackObject = game.getStack().getStackObject(event.getTargetId()); + Permanent permanent = game.getPermanent(event.getSourceId()); + if (stackObject == null || permanent == null || !permanent.isCreature(game)) { + return false; // only creatures + } + if (!game.getOpponents(this.getControllerId()).contains(permanent.getControllerId())) { + return false; // only creatures entering under opponent's control + } + Ability stackAbility = stackObject.getStackAbility(); + if (!(stackAbility instanceof TriggeredAbility)) { + return false; + } + GameEvent triggerEvent = ((TriggeredAbility) stackAbility).getTriggerEvent(); + if (triggerEvent == null || triggerEvent.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + return false; // only ETB triggers + } + if (triggerEvent.getSourceId() != permanent.getId()) { + return false; // only triggered abilities of that creature + } + // CopyStackObjectEffect needs value set + getEffects().setValue("stackObject", stackObject); + return true; + } + + @Override + public AbolethSpawnTriggeredAbility copy() { + return new AbolethSpawnTriggeredAbility(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java index bb77ce6f46d..69fc0e12abb 100644 --- a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java +++ b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java @@ -23,6 +23,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet { cards.add(new SetCardInfo("Aarakocra Sneak", 54, Rarity.COMMON, mage.cards.a.AarakocraSneak.class)); cards.add(new SetCardInfo("Abdel Adrian, Gorion's Ward", 2, Rarity.UNCOMMON, mage.cards.a.AbdelAdrianGorionsWard.class)); + cards.add(new SetCardInfo("Aboleth Spawn", 662, Rarity.RARE, mage.cards.a.AbolethSpawn.class)); cards.add(new SetCardInfo("Acolyte of Bahamut", 212, Rarity.UNCOMMON, mage.cards.a.AcolyteOfBahamut.class)); cards.add(new SetCardInfo("Aether Gale", 712, Rarity.RARE, mage.cards.a.AetherGale.class)); cards.add(new SetCardInfo("Agent of the Iron Throne", 107, Rarity.UNCOMMON, mage.cards.a.AgentOfTheIronThrone.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/clb/AbolethSpawnTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/clb/AbolethSpawnTest.java new file mode 100644 index 00000000000..d305c95b7e5 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/clb/AbolethSpawnTest.java @@ -0,0 +1,77 @@ +package org.mage.test.cards.single.clb; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class AbolethSpawnTest extends CardTestPlayerBase { + + private static final String aboleth = "Aboleth Spawn"; // 2/3 Flash, ward {2} + // Whenever a creature entering the battlefield under an opponent's control + // causes a triggered ability of that creature to trigger, + // you may copy that ability. You may choose new targets for the copy. + private static final String sparkmage = "Sparkmage Apprentice"; // 1/1 + // When Sparkmage Apprentice enters the battlefield, it deals 1 damage to any target. + private static final String attendant = "Soul's Attendant"; // 1/1 + // Whenever another creature enters the battlefield, you may gain 1 life. + private static final String hatchling = "Kraken Hatchling"; // 0/4 + private static final String ridgescale = "Ridgescale Tusker"; // 5/5 + // When Ridgescale Tusker enters the battlefield, put a +1/+1 counter on each other creature you control. + + + @Test + public void testTriggerCopies() { + addCard(Zone.BATTLEFIELD, playerA, aboleth); + addCard(Zone.BATTLEFIELD, playerA, hatchling); + addCard(Zone.BATTLEFIELD, playerB, attendant); + addCard(Zone.HAND, playerB, sparkmage); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, sparkmage); + setChoice(playerB, "Whenever another"); // order triggers + addTarget(playerB, hatchling); // to deal 1 damage + setChoice(playerA, true); // yes to copy sparkmage trigger + setChoice(playerA, true); // yes to change targets + addTarget(playerA, aboleth); // to deal 1 damage + setChoice(playerB, true); // yes to gain 1 life + + setStopAt(2, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + assertDamageReceived(playerA, hatchling, 1); + assertDamageReceived(playerA, aboleth, 1); + assertLife(playerA, 20); + assertLife(playerB, 21); + } + + @Test + public void testTriggerController() { + addCard(Zone.BATTLEFIELD, playerA, aboleth); + addCard(Zone.BATTLEFIELD, playerB, hatchling); + addCard(Zone.BATTLEFIELD, playerA, attendant); + addCard(Zone.HAND, playerB, ridgescale); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 5); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, ridgescale); + setChoice(playerA, "Whenever another"); // order triggers + setChoice(playerA, true); // yes to copy ridgescale trigger + setChoice(playerA, true); // yes to gain 1 life + + setStopAt(2, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + assertCounterCount(playerA, aboleth, CounterType.P1P1, 1); + assertCounterCount(playerA, attendant, CounterType.P1P1, 1); + assertCounterCount(playerB, hatchling, CounterType.P1P1, 1); + assertLife(playerA, 21); + assertLife(playerB, 20); + } + +} diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 609ad36e4a2..880c952fd67 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -632,8 +632,10 @@ public class StackAbility extends StackObjectImpl implements Ability { @Override public void createSingleCopy(UUID newControllerId, StackObjectCopyApplier applier, MageObjectReferencePredicate newTargetFilterPredicate, Game game, Ability source, boolean chooseNewTargets) { - Ability newAbility = this.copy(); + Ability newAbility = this.ability.copy(); newAbility.newId(); + newAbility.setControllerId(newControllerId); + StackAbility newStackAbility = new StackAbility(newAbility, newControllerId); game.getStack().push(newStackAbility);