diff --git a/Mage.Sets/src/mage/cards/m/MarketGnome.java b/Mage.Sets/src/mage/cards/m/MarketGnome.java new file mode 100644 index 00000000000..880a22de5ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarketGnome.java @@ -0,0 +1,81 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +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 java.util.UUID; + +/** + * @author xenohedron + */ +public final class MarketGnome extends CardImpl { + + public MarketGnome(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.GNOME); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // When Market Gnome dies, you gain 1 life and draw a card. + Ability ability = new DiesSourceTriggeredAbility(new GainLifeEffect(1)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + + // When Market Gnome is exiled from the battlefield while you're activating a craft ability, you gain 1 life and draw a card. + this.addAbility(new MarketGnomeTriggeredAbility()); + + } + + private MarketGnome(final MarketGnome card) { + super(card); + } + + @Override + public MarketGnome copy() { + return new MarketGnome(this); + } +} + +class MarketGnomeTriggeredAbility extends TriggeredAbilityImpl { + + MarketGnomeTriggeredAbility() { + super(Zone.BATTLEFIELD, new GainLifeEffect(1)); + this.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + setTriggerPhrase("When {this} is exiled from the battlefield while you're activating a craft ability, "); + // setLeavesTheBattlefieldTrigger(true); // not needed as special event is fired prior to the actual exiling + } + + private MarketGnomeTriggeredAbility(final MarketGnomeTriggeredAbility ability) { + super(ability); + } + + @Override + public MarketGnomeTriggeredAbility copy() { + return new MarketGnomeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.EXILED_WHILE_CRAFTING; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(getSourceId()); + return permanent != null && sourcePermanent != null && permanent.getId().equals(sourcePermanent.getId()); + } +} diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index e6d1c987944..a3cb97d3e6e 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -203,6 +203,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Malcolm, Alluring Scoundrel", 63, Rarity.RARE, mage.cards.m.MalcolmAlluringScoundrel.class)); cards.add(new SetCardInfo("Malicious Eclipse", 111, Rarity.UNCOMMON, mage.cards.m.MaliciousEclipse.class)); cards.add(new SetCardInfo("Marauding Brinefang", 64, Rarity.COMMON, mage.cards.m.MaraudingBrinefang.class)); + cards.add(new SetCardInfo("Market Gnome", 22, Rarity.UNCOMMON, mage.cards.m.MarketGnome.class)); cards.add(new SetCardInfo("Master's Guide-Mural", 233, Rarity.UNCOMMON, mage.cards.m.MastersGuideMural.class)); cards.add(new SetCardInfo("Master's Manufactory", 233, Rarity.UNCOMMON, mage.cards.m.MastersManufactory.class)); cards.add(new SetCardInfo("Mastercraft Raptor", 164, Rarity.UNCOMMON, mage.cards.m.MastercraftRaptor.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CraftTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CraftTest.java index 7e411d4fcdb..1cf12c63f3f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CraftTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CraftTest.java @@ -11,9 +11,9 @@ import org.mage.test.serverside.base.CardTestPlayerBase; */ public class CraftTest extends CardTestPlayerBase { - private static final String sawblades = "Spring-Loaded Sawblades"; - private static final String chariot = "Bladewheel Chariot"; - private static final String relic = "Darksteel Relic"; + private static final String sawblades = "Spring-Loaded Sawblades"; // Craft with artifact {3}{W} + private static final String chariot = "Bladewheel Chariot"; // back side Vehicle + private static final String relic = "Darksteel Relic"; // Artifact {0} Indestructible @Test public void testExilePermanent() { @@ -55,11 +55,13 @@ public class CraftTest extends CardTestPlayerBase { assertExileCount(playerA, relic, 1); } - private static final String standard = "Sunbird Standard"; - private static final String effigy = "Sunbird Effigy"; - private static final String thoctar = "Woolly Thoctar"; - private static final String watchwolf = "Watchwolf"; - private static final String yearling = "Cerodon Yearling"; + private static final String standard = "Sunbird Standard"; // Craft with one or more {5} + private static final String effigy = "Sunbird Effigy"; // back side artifact creature + // Sunbird Effigy’s power and toughness are each equal to the number of colors among the exiled cards used to craft it. + // {T}: For each color among the exiled cards used to craft Sunbird Effigy, add one mana of that color. + private static final String thoctar = "Woolly Thoctar"; // RGW 5/4 + private static final String watchwolf = "Watchwolf"; // GW 3/3 + private static final String yearling = "Cerodon Yearling"; // RW 2/2 Vigilance Haste @Test public void testEffigy() { @@ -109,4 +111,94 @@ public class CraftTest extends CardTestPlayerBase { assertPermanentCount(playerA, thoctar, 1); assertPowerToughness(playerA, effigy, 3, 3); } + + private static final String gnome = "Market Gnome"; + // When Market Gnome is exiled from the battlefield while you’re activating a craft ability, you gain 1 life and draw a card. + + @Test + public void testMarketGnomeExilePermanent() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, sawblades); + addCard(Zone.BATTLEFIELD, playerA, gnome); + + addTarget(playerA, gnome); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, sawblades, 0); + assertPermanentCount(playerA, chariot, 1); + assertPermanentCount(playerA, gnome, 0); + assertExileCount(playerA, gnome, 1); + assertLife(playerA, 21); + assertHandCount(playerA, 1); + } + + @Test + public void testMarketGnomeExileCard() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, sawblades); + addCard(Zone.GRAVEYARD, playerA, gnome); + + addTarget(playerA, gnome); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, sawblades, 0); + assertPermanentCount(playerA, chariot, 1); + assertGraveyardCount(playerA, gnome, 0); + assertExileCount(playerA, gnome, 1); + assertLife(playerA, 20); + assertHandCount(playerA, 0); + } + + @Test + public void testMarketGnomeExiledExileOther() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, sawblades); + addCard(Zone.BATTLEFIELD, playerA, relic); + addCard(Zone.EXILED, playerA, gnome); + + addTarget(playerA, relic); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, sawblades, 0); + assertPermanentCount(playerA, chariot, 1); + assertPermanentCount(playerA, relic, 0); + assertExileCount(playerA, relic, 1); + assertLife(playerA, 20); + assertHandCount(playerA, 0); + } + + @Test + public void testMarketGnomeBattlefieldExileOther() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, sawblades); + addCard(Zone.BATTLEFIELD, playerA, relic); + addCard(Zone.BATTLEFIELD, playerA, gnome); + + addTarget(playerA, relic); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, sawblades, 0); + assertPermanentCount(playerA, chariot, 1); + assertPermanentCount(playerA, relic, 0); + assertExileCount(playerA, relic, 1); + assertLife(playerA, 20); + assertHandCount(playerA, 0); + } + } diff --git a/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java b/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java index eaaa25a5b8f..377f7743323 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java @@ -18,6 +18,7 @@ import mage.filter.common.FilterOwnedCard; import mage.filter.predicate.Predicate; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; @@ -131,6 +132,8 @@ class CraftCost extends CostImpl { .map(uuid -> { Permanent permanent = game.getPermanent(uuid); if (permanent != null) { + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EXILED_WHILE_CRAFTING, + permanent.getId(), source, player.getId())); return permanent; } return game.getCard(uuid); diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 122ef6b731d..ba4881d9a96 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -540,6 +540,12 @@ public class GameEvent implements Serializable { flag not used for this event */ DISCOVERED, + /* Exiled while crafting (see Market Gnome) + targetId the permanent exiled + sourceId of the craft ability + playerId the player crafting + */ + EXILED_WHILE_CRAFTING, //custom events CUSTOM_EVENT }