diff --git a/Mage.Sets/src/mage/cards/s/ShadowOfTheGoblin.java b/Mage.Sets/src/mage/cards/s/ShadowOfTheGoblin.java new file mode 100644 index 00000000000..74f0000a36e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShadowOfTheGoblin.java @@ -0,0 +1,78 @@ +package mage.cards.s; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * + * @author Jmlundeen + */ +public final class ShadowOfTheGoblin extends CardImpl { + + public ShadowOfTheGoblin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + + // Unreliable Visions -- At the beginning of your first main phase, discard a card. If you do, draw a card. + this.addAbility(new BeginningOfFirstMainTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), false) + .withFlavorWord("Unreliable Visions") + ); + + // Undying Vengeance -- Whenever you play a land or cast a spell from anywhere other than your hand, this enchantment deals 1 damage to each opponent. + this.addAbility(new ShadowOfTheGoblinTriggeredAbility(new DamagePlayersEffect(1, TargetController.OPPONENT)) + .withFlavorWord("Undying Vengeance")); + + } + + private ShadowOfTheGoblin(final ShadowOfTheGoblin card) { + super(card); + } + + @Override + public ShadowOfTheGoblin copy() { + return new ShadowOfTheGoblin(this); + } +} + +class ShadowOfTheGoblinTriggeredAbility extends TriggeredAbilityImpl { + + public ShadowOfTheGoblinTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect, false); + setTriggerPhrase("Whenever you play a land or cast a spell from anywhere other than your hand, "); + } + + protected ShadowOfTheGoblinTriggeredAbility(final ShadowOfTheGoblinTriggeredAbility triggeredAbility) { + super(triggeredAbility); + } + + @Override + public ShadowOfTheGoblinTriggeredAbility copy() { + return new ShadowOfTheGoblinTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PLAY_LAND || + event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return isControlledBy(event.getPlayerId()) && event.getZone() != Zone.HAND; + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 3d405798742..5d29bf8b4f9 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -189,6 +189,8 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Scout the City", 113, Rarity.COMMON, mage.cards.s.ScoutTheCity.class)); cards.add(new SetCardInfo("Secret Identity", 43, Rarity.UNCOMMON, mage.cards.s.SecretIdentity.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); + cards.add(new SetCardInfo("Shadow of the Goblin", 262, Rarity.RARE, mage.cards.s.ShadowOfTheGoblin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shadow of the Goblin", 87, Rarity.RARE, mage.cards.s.ShadowOfTheGoblin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Shocker, Unshakable", 89, Rarity.UNCOMMON, mage.cards.s.ShockerUnshakable.class)); cards.add(new SetCardInfo("Silver Sable, Mercenary Leader", 13, Rarity.UNCOMMON, mage.cards.s.SilverSableMercenaryLeader.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java new file mode 100644 index 00000000000..50312827c11 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java @@ -0,0 +1,123 @@ +package org.mage.test.cards.single.spm; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Jmlundeen + */ +public class ShadowOfTheGoblinTest extends CardTestPlayerBase { + + /* + Shadow of the Goblin + {1}{R} + Enchantment + Unreliable Visions -- At the beginning of your first main phase, discard a card. If you do, draw a card. + Undying Vengeance -- Whenever you play a land or cast a spell from anywhere other than your hand, this enchantment deals 1 damage to each opponent. + */ + private static final String shadowOfTheGoblin = "Shadow of the Goblin"; + + /* + Party Thrasher + {1}{R} + Creature - Lizard Wizard + Noncreature spells you cast from exile have convoke. + At the beginning of your precombat main phase, you may discard a card. If you do, exile the top two cards of your library, then choose one of them. You may play that card this turn. + 1/4 + */ + private static final String partyThrasher = "Party Thrasher"; + + /* + Misthollow Griffin + {2}{U}{U} + Creature - Griffin + Flying + You may cast Misthollow Griffin from exile. + 3/3 + */ + private static final String misthollowGriffin = "Misthollow Griffin"; + + /* + Glarb, Calamity's Augur + {B}{G}{U} + Legendary Creature - Frog Wizard Noble + Deathtouch + You may look at the top card of your library any time. + You may play lands and cast spells with mana value 4 or greater from the top of your library. + {T}: Surveil 2. + 2/4 + */ + private static final String glarbCalamitysAugur = "Glarb, Calamity's Augur"; + + @Test + public void testShadowOfTheGoblinFromHand() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, shadowOfTheGoblin); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Zone.HAND, playerA, "Mountain"); + addCard(Zone.HAND, playerA, partyThrasher); + + setChoice(playerA, false); // shadow trigger + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, partyThrasher); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerB, 20); // no trigger + } + + @Test + public void testShadowOfTheGoblinFromExile() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, shadowOfTheGoblin); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerA, partyThrasher); + addCard(Zone.HAND, playerA, "Mountain"); + addCard(Zone.EXILED, playerA, misthollowGriffin); + + setChoice(playerA, "Unreliable Visions"); + setChoice(playerA, true); // discard + setChoice(playerA, "Mountain", 2); + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, misthollowGriffin); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerB, 20 - 1 - 1); // land + spell from exile + } + + @Test + public void testShadowOfTheGoblinFromLibrary() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, shadowOfTheGoblin); + addCard(Zone.BATTLEFIELD, playerA, glarbCalamitysAugur); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.LIBRARY, playerA, misthollowGriffin); + addCard(Zone.LIBRARY, playerA, "Island"); + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, misthollowGriffin); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerB, 20 - 1 - 1); // land + spell from library + } +} \ No newline at end of file