diff --git a/Mage.Sets/src/mage/cards/f/FiresOfMountDoom.java b/Mage.Sets/src/mage/cards/f/FiresOfMountDoom.java index 6d6f7826de3..c2de242fe6b 100644 --- a/Mage.Sets/src/mage/cards/f/FiresOfMountDoom.java +++ b/Mage.Sets/src/mage/cards/f/FiresOfMountDoom.java @@ -1,5 +1,6 @@ package mage.cards.f; +import mage.MageIdentifier; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -50,7 +51,8 @@ public final class FiresOfMountDoom extends CardImpl { this.addAbility(new SimpleActivatedAbility( Zone.BATTLEFIELD, new FiresOfMountDoomEffect(), - new ManaCostsImpl<>("{2}{R}"))); + new ManaCostsImpl<>("{2}{R}") + ).setIdentifier(MageIdentifier.FiresOfMountDoomAlternateCast)); } private FiresOfMountDoom(final FiresOfMountDoom card) { @@ -68,7 +70,7 @@ class FiresOfMountDoomEffect extends OneShotEffect { FiresOfMountDoomEffect() { super(Outcome.Benefit); this.staticText = "exile the top card of your library. You may play that card this turn. " + - "When you play a card this way, Fires of Mount Doom deals 2 damage to each player"; + "When you play a card this way, {this} deals 2 damage to each player"; } private FiresOfMountDoomEffect(final FiresOfMountDoomEffect effect) { @@ -100,19 +102,9 @@ class FiresOfMountDoomEffect extends OneShotEffect { } } -// TODO: this is not quite right in corner cases. -// Inspired by Havengul Lich which I feel has similar problems. -// For instance what if the card is [[Squee, the Immortal]] and -// is cast with squee AsThought. -// Or if the card is played with the AsThought, then replayed -// during the same turn. With current code, that would trigger -// incorrectly again. -// Is mor the solution there? Or having a way to get the specific -// used AsThought and having a way to identify that it was the -// same one as the FiresOfMountDoomEffect makeCardPlayable. class FiresOfMountDoomDelayedTriggeredAbility extends DelayedTriggeredAbility { - private UUID cardId; + private final UUID cardId; public FiresOfMountDoomDelayedTriggeredAbility(UUID cardId) { super(new DamagePlayersEffect(2, TargetController.ANY), Duration.EndOfTurn); @@ -133,6 +125,9 @@ class FiresOfMountDoomDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { + if (!event.hasApprovingIdentifier(MageIdentifier.FiresOfMountDoomAlternateCast)){ + return false; + } return event.getSourceId().equals(cardId); } diff --git a/Mage.Sets/src/mage/cards/t/TheRuinousPowers.java b/Mage.Sets/src/mage/cards/t/TheRuinousPowers.java new file mode 100644 index 00000000000..8b8383956bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheRuinousPowers.java @@ -0,0 +1,138 @@ +package mage.cards.t; + +import java.util.*; + +import mage.MageIdentifier; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.util.CardUtil; +import mage.util.RandomUtil; + +/** + * + * @author jimga150 + */ +public final class TheRuinousPowers extends CardImpl { + + public TheRuinousPowers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{R}"); + + + // At the beginning of your upkeep, choose an opponent at random. Exile the top card of that player's library. + // Until end of turn, you may play that card and you may spend mana as though it were mana of any color to cast it. + // When you cast a spell this way, its owner loses life equal to its mana value. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new TheRuinousPowersEffect(), TargetController.YOU, false) + .setIdentifier(MageIdentifier.TheRuinousPowersAlternateCast); + this.addAbility(ability); + } + + private TheRuinousPowers(final TheRuinousPowers card) { + super(card); + } + + @Override + public TheRuinousPowers copy() { + return new TheRuinousPowers(this); + } +} + +// Based on YouFindSomePrisonersEffect +class TheRuinousPowersEffect extends OneShotEffect { + + TheRuinousPowersEffect() { + super(Outcome.Benefit); + staticText = "choose an opponent at random. Exile the top card of that player's library. Until end of turn, " + + "you may play that card and you may spend mana as though it were mana of any color to cast it. " + + "When you cast a spell this way, its owner loses life equal to its mana value."; + } + + private TheRuinousPowersEffect(final TheRuinousPowersEffect effect) { + super(effect); + } + + @Override + public TheRuinousPowersEffect copy() { + return new TheRuinousPowersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null){ + return false; + } + List opponents = new ArrayList<>(game.getOpponents(source.getControllerId())); + if (opponents.isEmpty()) { + return false; + } + Player opponent = game.getPlayer(opponents.get(RandomUtil.nextInt(opponents.size()))); + if (opponent == null) { + return false; + } + Card card = opponent.getLibrary().getFromTop(game); + player.moveCards(card, Zone.EXILED, source, game); + if (card != null) { + CardUtil.makeCardPlayable(game, source, card, false, Duration.EndOfTurn, true); + game.addDelayedTriggeredAbility(new TheRuinousPowersTriggeredAbility(card.getId()), source); + } + return true; + } +} + +// Based on FiresOfMountDoomDelayedTriggeredAbility +class TheRuinousPowersTriggeredAbility extends DelayedTriggeredAbility { + + private final UUID cardId; + + public TheRuinousPowersTriggeredAbility(UUID cardId) { + super(null, Duration.EndOfTurn); + this.cardId = cardId; + } + + private TheRuinousPowersTriggeredAbility(final TheRuinousPowersTriggeredAbility ability) { + super(ability); + this.cardId = ability.cardId; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getSourceId().equals(cardId)){ + return false; + } + if (!event.hasApprovingIdentifier(MageIdentifier.TheRuinousPowersAlternateCast)){ + return false; + } + Card card = game.getCard(cardId); + if (card == null){ + return false; + } + Player owner = game.getPlayer(card.getOwnerId()); + if (owner == null){ + return false; + } + owner.loseLife(card.getManaValue(), game, this, false); + return true; + } + + @Override + public TheRuinousPowersTriggeredAbility copy() { + return new TheRuinousPowersTriggeredAbility(this); + } + + @Override + public String getRule() { + return "When you cast a spell this way, its owner loses life equal to its mana value."; + } +} diff --git a/Mage.Sets/src/mage/sets/Warhammer40000.java b/Mage.Sets/src/mage/sets/Warhammer40000.java index b08d1cf8c48..a633814d40d 100644 --- a/Mage.Sets/src/mage/sets/Warhammer40000.java +++ b/Mage.Sets/src/mage/sets/Warhammer40000.java @@ -265,6 +265,7 @@ public final class Warhammer40000 extends ExpansionSet { cards.add(new SetCardInfo("The Golden Throne", 157, Rarity.RARE, mage.cards.t.TheGoldenThrone.class)); cards.add(new SetCardInfo("The Horus Heresy", 126, Rarity.RARE, mage.cards.t.TheHorusHeresy.class)); cards.add(new SetCardInfo("The Lost and the Damned", 129, Rarity.UNCOMMON, mage.cards.t.TheLostAndTheDamned.class)); + cards.add(new SetCardInfo("The Ruinous Powers", 139, Rarity.RARE, mage.cards.t.TheRuinousPowers.class)); cards.add(new SetCardInfo("The Swarmlord", 4, Rarity.MYTHIC, mage.cards.t.TheSwarmlord.class)); cards.add(new SetCardInfo("The War in Heaven", 69, Rarity.RARE, mage.cards.t.TheWarInHeaven.class)); cards.add(new SetCardInfo("Their Name Is Death", 62, Rarity.RARE, mage.cards.t.TheirNameIsDeath.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/FiresOfMountDoomTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/FiresOfMountDoomTest.java new file mode 100644 index 00000000000..db60c4de562 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/FiresOfMountDoomTest.java @@ -0,0 +1,64 @@ +package org.mage.test.cards.single.ltr; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author jimga150 + */ +public class FiresOfMountDoomTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.f.FiresOfMountDoom Fires of Mount Doom} + * Legendary Enchantment + * When Fires of Mount Doom enters the battlefield, it deals 2 damage to target creature an opponent controls. + * Destroy all Equipment attached to that creature. + * {2}{R}: Exile the top card of your library. You may play that card this turn. + * When you play a card this way, Fires of Mount Doom deals 2 damage to each player. + */ + private static final String fires = "Fires of Mount Doom"; + + @Test + public void test_castWithDamage() { + // Test the damaging triggered ability + + addCard(Zone.BATTLEFIELD, playerA, fires, 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.LIBRARY, playerA, "Squee, the Immortal", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{R}"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Squee, the Immortal"); + setChoice(playerA, fires); // Choose Fires as the approving object + + skipInitShuffling(); + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Squee, the Immortal", 1); + assertLife(playerB, currentGame.getStartingLife() - 2); + } + + @Test + public void test_castNoDamage() { + // Test that the damaging triggered ability doesnt trigger if something else allows the exiled card to be cast + + addCard(Zone.BATTLEFIELD, playerA, fires, 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.LIBRARY, playerA, "Squee, the Immortal", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{R}"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Squee, the Immortal"); + setChoice(playerA, "Squee"); // Choose Squee as the approving object (which casts it normally) + + skipInitShuffling(); + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Squee, the Immortal", 1); + assertLife(playerB, currentGame.getStartingLife()); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/TheRuinousPowersTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/TheRuinousPowersTest.java new file mode 100644 index 00000000000..7a4307e2a68 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/TheRuinousPowersTest.java @@ -0,0 +1,39 @@ +package org.mage.test.cards.single.ltr; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author jimga150 + */ +public class TheRuinousPowersTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.t.TheRuinousPowers The Ruinous Powers} + * Enchantment + * At the beginning of your upkeep, choose an opponent at random. Exile the top card of that player’s library. + * Until end of turn, you may play that card and you may spend mana as though it were mana of any color to cast it. + * When you cast a spell this way, its owner loses life equal to its mana value. + */ + private static final String powers = "The Ruinous Powers"; + + @Test + public void test_castWithDamage() { + + addCard(Zone.BATTLEFIELD, playerA, powers, 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.LIBRARY, playerB, "Squee, the Immortal", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Squee, the Immortal"); + + skipInitShuffling(); + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Squee, the Immortal", 1); + assertLife(playerB, currentGame.getStartingLife() - 3); + } +} diff --git a/Mage/src/main/java/mage/MageIdentifier.java b/Mage/src/main/java/mage/MageIdentifier.java index fe62619f236..15d41e51527 100644 --- a/Mage/src/main/java/mage/MageIdentifier.java +++ b/Mage/src/main/java/mage/MageIdentifier.java @@ -72,6 +72,8 @@ public enum MageIdentifier { WithoutPayingManaCostAlternateCast, AlurenAlternateCast, OfferingAlternateCast, + TheRuinousPowersAlternateCast, + FiresOfMountDoomAlternateCast, PrimalPrayersAlternateCast; /**