diff --git a/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java b/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java new file mode 100644 index 00000000000..5a7ab2f11ac --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java @@ -0,0 +1,204 @@ +package mage.cards.t; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseGameTargetPlayerEffect; +import mage.abilities.effects.common.RollDieWithResultTableEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheDeckOfManyThings extends CardImpl { + + public TheDeckOfManyThings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); + + this.addSuperType(SuperType.LEGENDARY); + + // {2}, {T}: Roll a d20 and subtract the number of cards in your hand. If the result is 0 or less, discard your hand. + // 1-9 | Return a card at random from your graveyard to your hand. + // 10-19 | Draw two cards. + // 20 | Put a creature card from any graveyard onto the battlefield under your control. When that creature dies, its owner loses the game. + Ability ability = new SimpleActivatedAbility(new TheDeckOfManyThingsEffect(), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private TheDeckOfManyThings(final TheDeckOfManyThings card) { + super(card); + } + + @Override + public TheDeckOfManyThings copy() { + return new TheDeckOfManyThings(this); + } +} + +class TheDeckOfManyThingsEffect extends RollDieWithResultTableEffect { + + TheDeckOfManyThingsEffect() { + super(20, "roll a d20 and subtract the number of cards in your hand. If the result is 0 or less, discard your hand."); + this.addTableEntry(1, 9, new TheDeckOfManyThingsRandomEffect()); + this.addTableEntry(10, 19, new DrawCardSourceControllerEffect(2)); + this.addTableEntry(20, 20, new TheDeckOfManyThingsReturnEffect()); + } + + private TheDeckOfManyThingsEffect(final TheDeckOfManyThingsEffect effect) { + super(effect); + } + + @Override + public TheDeckOfManyThingsEffect copy() { + return new TheDeckOfManyThingsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int result = player.rollDice(source, game, sides) - player.getHand().size(); + if (result <= 0) { + player.discard(player.getHand(), false, source, game); + } + this.applyResult(result, game, source); + return true; + } +} + +class TheDeckOfManyThingsRandomEffect extends OneShotEffect { + + TheDeckOfManyThingsRandomEffect() { + super(Outcome.ReturnToHand); + staticText = "return a card at random from your graveyard to your hand"; + } + + private TheDeckOfManyThingsRandomEffect(final TheDeckOfManyThingsRandomEffect effect) { + super(effect); + } + + @Override + public TheDeckOfManyThingsRandomEffect copy() { + return new TheDeckOfManyThingsRandomEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || player.getGraveyard().count(StaticFilters.FILTER_CARD, game) < 1) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD); + target.setRandom(true); + target.setNotTarget(true); + player.chooseTarget(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + return card != null && player.moveCards(card, Zone.HAND, source, game); + } +} + +class TheDeckOfManyThingsReturnEffect extends OneShotEffect { + + TheDeckOfManyThingsReturnEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "put a creature card from any graveyard onto the battlefield under your control. " + + "When that creature dies, its owner loses the game"; + } + + private TheDeckOfManyThingsReturnEffect(final TheDeckOfManyThingsReturnEffect effect) { + super(effect); + } + + @Override + public TheDeckOfManyThingsReturnEffect copy() { + return new TheDeckOfManyThingsReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCardInGraveyard target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE); + target.setNotTarget(true); + if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + return false; + } + player.choose(outcome, target, source.getControllerId(), game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + player.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + game.addDelayedTriggeredAbility(new TheDeckOfManyThingsDelayedTriggeredAbility(permanent, game), source); + return true; + } +} + +class TheDeckOfManyThingsDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private final MageObjectReference mor; + + TheDeckOfManyThingsDelayedTriggeredAbility(Permanent permanent, Game game) { + super(new LoseGameTargetPlayerEffect(), Duration.Custom, false, false); + this.mor = new MageObjectReference(permanent, game); + } + + private TheDeckOfManyThingsDelayedTriggeredAbility(final TheDeckOfManyThingsDelayedTriggeredAbility ability) { + super(ability); + this.mor = ability.mor; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (!zEvent.isDiesEvent() || !mor.refersTo(zEvent.getTarget(), game)) { + return false; + } + getEffects().setTargetPointer(new FixedTarget(zEvent.getTarget().getOwnerId(), game)); + return true; + } + + @Override + public TheDeckOfManyThingsDelayedTriggeredAbility copy() { + return new TheDeckOfManyThingsDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "When that creature dies, its owner loses the game."; + } +} diff --git a/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java b/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java index 177af62f39d..7f1f8b1aa0d 100644 --- a/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java +++ b/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java @@ -115,6 +115,7 @@ public final class AdventuresInTheForgottenRealms extends ExpansionSet { cards.add(new SetCardInfo("Swarming Goblins", 162, Rarity.COMMON, mage.cards.s.SwarmingGoblins.class)); cards.add(new SetCardInfo("Targ Nar, Demon-Fang Gnoll", 234, Rarity.UNCOMMON, mage.cards.t.TargNarDemonFangGnoll.class)); cards.add(new SetCardInfo("Tasha's Hideous Laughter", 78, Rarity.RARE, mage.cards.t.TashasHideousLaughter.class)); + cards.add(new SetCardInfo("The Deck of Many Things", 241, Rarity.MYTHIC, mage.cards.t.TheDeckOfManyThings.class)); cards.add(new SetCardInfo("Tiamat", 235, Rarity.MYTHIC, mage.cards.t.Tiamat.class)); cards.add(new SetCardInfo("Trelasarra Moon Dancer", 236, Rarity.UNCOMMON, mage.cards.t.TrelasarraMoonDancer.class)); cards.add(new SetCardInfo("Varis, Silverymoon Ranger", 209, Rarity.RARE, mage.cards.v.VarisSilverymoonRanger.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java index ae3beb3c54c..df6bca614c5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java @@ -19,7 +19,8 @@ import java.util.List; */ public class RollDieWithResultTableEffect extends OneShotEffect { - private final int sides; + protected final int sides; + private final String prefixText; private final List resultsTable = new ArrayList<>(); public RollDieWithResultTableEffect() { @@ -27,13 +28,19 @@ public class RollDieWithResultTableEffect extends OneShotEffect { } public RollDieWithResultTableEffect(int sides) { - super(Outcome.Benefit); - this.sides = sides; + this(sides, null); } - private RollDieWithResultTableEffect(final RollDieWithResultTableEffect effect) { + public RollDieWithResultTableEffect(int sides, String prefixText) { + super(Outcome.Benefit); + this.sides = sides; + this.prefixText = prefixText; + } + + protected RollDieWithResultTableEffect(final RollDieWithResultTableEffect effect) { super(effect); this.sides = effect.sides; + this.prefixText = effect.prefixText; for (TableEntry tableEntry : effect.resultsTable) { this.resultsTable.add(tableEntry.copy()); } @@ -51,18 +58,27 @@ public class RollDieWithResultTableEffect extends OneShotEffect { return false; } int result = player.rollDice(source, game, sides); + this.applyResult(result, game, source); + return true; + } + + protected void applyResult(int result, Game game, Ability source) { for (TableEntry tableEntry : this.resultsTable) { if (tableEntry.matches(result)) { tableEntry.apply(game, source); - return true; + return; } } - return true; } @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder("roll a d").append(sides).append('.'); + StringBuilder sb = new StringBuilder(); + if (prefixText != null) { + sb.append(prefixText); + } else { + sb.append("roll a d").append(sides).append('.'); + } for (TableEntry tableEntry : this.resultsTable) { sb.append("
"); if (tableEntry.min == tableEntry.max) {