diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 008a3b654ab..34377722947 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -538,7 +538,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { // Always hide not hidden popup window or enlarged card view if a frame is set to active try { ActionCallback callback = Plugins.instance.getActionCallback(); - if (callback != null && callback instanceof MageActionCallback) { + if (callback instanceof MageActionCallback) { ((MageActionCallback) callback).hideEnlargedCard(); } Component container = MageFrame.getUI().getComponent(MageComponents.POPUP_CONTAINER); diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java index 2f7f69998e4..329ff3ec0ed 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java @@ -319,7 +319,7 @@ public class DialogManager extends JComponent implements MouseListener, if (e.getButton() == MouseEvent.BUTTON1) { j = (JComponent) getComponentAt(e.getX(), e.getY()); - if (j != null && j instanceof DialogContainer) { + if (j instanceof DialogContainer) { rec = j.getBounds(); bDragged = true; mx = e.getX(); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java index bea5f97b111..fd53051191c 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -530,7 +530,7 @@ public class MageBook extends JComponent { Class c = Class.forName(className); Constructor cons = c.getConstructor(); Object newToken = cons.newInstance(); - if (newToken != null && newToken instanceof mage.game.permanent.token.Token) { + if (newToken instanceof Token) { ((Token) newToken).setExpansionSetCodeForImage(set); ((Token) newToken).setOriginalExpansionSetCode(set); ((Token) newToken).setTokenType(token.getType()); @@ -580,7 +580,7 @@ public class MageBook extends JComponent { Class c = Class.forName(className); Constructor cons = c.getConstructor(); Object newEmblem = cons.newInstance(); - if (newEmblem != null && newEmblem instanceof mage.game.command.Emblem) { + if (newEmblem instanceof Emblem) { ((Emblem) newEmblem).setExpansionSetCodeForImage(set); emblems.add((Emblem) newEmblem); @@ -637,7 +637,7 @@ public class MageBook extends JComponent { Class c = Class.forName(className); Constructor cons = c.getConstructor(); Object newPlane = cons.newInstance(); - if (newPlane != null && newPlane instanceof mage.game.command.Plane) { + if (newPlane instanceof Plane) { ((Plane) newPlane).setExpansionSetCodeForImage(set); planes.add((Plane) newPlane); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java b/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java index c2b24748e35..20e6513c1de 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java @@ -369,7 +369,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid { if (!card.getId().equals(bigCard.getCardId())) { if (!MageFrame.isLite()) { Image image = Plugins.instance.getOriginalImage(card); - if (image != null && image instanceof BufferedImage) { + if (image instanceof BufferedImage) { // XXX: scaled to fit width bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, new ArrayList<>(), false); } else { diff --git a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java index 4d69a16ce86..344e62c1b6e 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java +++ b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java @@ -617,7 +617,7 @@ public class MageActionCallback implements ActionCallback { } private void displayCardInfo(MageCard mageCard, Image image, BigCard bigCard) { - if (image != null && image instanceof BufferedImage) { + if (image instanceof BufferedImage) { // XXX: scaled to fit width bigCard.setCard(mageCard.getOriginal().getId(), enlargeMode, image, mageCard.getOriginal().getRules(), mageCard.getOriginal().isToRotate()); // if it's an ability, show only the ability text as overlay diff --git a/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryItemEditor.java b/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryItemEditor.java index b7f476bc272..75f66353242 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryItemEditor.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryItemEditor.java @@ -47,7 +47,7 @@ public class CountryItemEditor extends BasicComboBoxEditor { @Override public void setItem(Object item) { - if (item == null || !(item instanceof String[])) { + if (!(item instanceof String[])) { return; } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java index a124d63fa05..9c670224dd8 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java @@ -800,7 +800,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, // this update removes the isChoosable mark from targetCardsInLibrary // so only done for permanents because it's needed to redraw counters in different size, if window size was changed // no perfect solution yet (maybe also other not wanted effects for PermanentView objects) - if (updateCard != null && (updateCard instanceof PermanentView)) { + if ((updateCard instanceof PermanentView)) { update(updateCard); } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java index fbd58ee16cd..86f80a6fea5 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java @@ -231,8 +231,9 @@ public enum MythicspoilerComSource implements CardImageSource { supportedSets.add("DOM"); supportedSets.add("BBD"); supportedSets.add("M19"); -// supportedSets.add("C18"); -// supportedSets.add("CM2"); + supportedSets.add("C18"); + supportedSets.add("CM2"); + supportedSets.add("GRN"); sets = new LinkedHashMap<>(); setsAliases = new HashMap<>(); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java index 6dbc42c5c75..a69354ecf85 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java @@ -230,6 +230,7 @@ public enum ScryfallImageSource implements CardImageSource { supportedSets.add("CM2"); supportedSets.add("M19"); supportedSets.add("GS1"); + supportedSets.add("GRN"); } @Override diff --git a/Mage.Common/src/main/java/mage/remote/Connection.java b/Mage.Common/src/main/java/mage/remote/Connection.java index 6022fcad8dc..ecc7dd44166 100644 --- a/Mage.Common/src/main/java/mage/remote/Connection.java +++ b/Mage.Common/src/main/java/mage/remote/Connection.java @@ -225,7 +225,7 @@ public class Connection { for (InterfaceAddress addr : iface.getInterfaceAddresses()) { if (addr != null) { InetAddress iaddr = addr.getAddress(); - if (iaddr != null && iaddr instanceof Inet4Address) { + if (iaddr instanceof Inet4Address) { return iaddr; } } diff --git a/Mage.Common/src/main/java/mage/utils/CompressUtil.java b/Mage.Common/src/main/java/mage/utils/CompressUtil.java index 39fa5fdf6d9..eeef7533de1 100644 --- a/Mage.Common/src/main/java/mage/utils/CompressUtil.java +++ b/Mage.Common/src/main/java/mage/utils/CompressUtil.java @@ -39,7 +39,7 @@ public final class CompressUtil { * @return Decompressed object */ public static Object decompress(Object data) { - if (data == null || !(data instanceof ZippedObject)) { + if (!(data instanceof ZippedObject)) { return data; } return ((ZippedObject) data).unzip(); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java index c3c8934fa1e..545851185a8 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java @@ -27,7 +27,7 @@ public class LevelUpOptimizer extends BaseTreeOptimizer { for (Ability ability : actions) { if (ability instanceof LevelUpAbility) { Permanent permanent = game.getPermanent(ability.getSourceId()); - if (permanent != null && permanent instanceof PermanentCard) { + if (permanent instanceof PermanentCard) { PermanentCard leveler = (PermanentCard) permanent; // check already existing Level counters and compare to maximum that make sense if (permanent.getCounters(game).getCount(CounterType.LEVEL) >= leveler.getMaxLevelCounters()) { diff --git a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java index 0d0941623e1..395becdf947 100644 --- a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java @@ -408,7 +408,7 @@ public final class SystemUtil { Class c = Class.forName("mage.game.permanent.token." + command.cardName); Constructor cons = c.getConstructor(); Object token = cons.newInstance(); - if (token != null && token instanceof mage.game.permanent.token.Token) { + if (token instanceof mage.game.permanent.token.Token) { ((mage.game.permanent.token.Token) token).putOntoBattlefield(command.Amount, game, null, player.getId(), false, false); continue; } @@ -417,7 +417,7 @@ public final class SystemUtil { Class c = Class.forName("mage.game.command.emblems." + command.cardName); Constructor cons = c.getConstructor(); Object emblem = cons.newInstance(); - if (emblem != null && emblem instanceof mage.game.command.Emblem) { + if (emblem instanceof mage.game.command.Emblem) { ((mage.game.command.Emblem) emblem).setControllerId(player.getId()); game.addEmblem((mage.game.command.Emblem) emblem, null, player.getId()); continue; @@ -427,7 +427,7 @@ public final class SystemUtil { Class c = Class.forName("mage.game.command.planes." + command.cardName); Constructor cons = c.getConstructor(); Object plane = cons.newInstance(); - if (plane != null && plane instanceof mage.game.command.Plane) { + if (plane instanceof mage.game.command.Plane) { ((mage.game.command.Plane) plane).setControllerId(player.getId()); game.addPlane((mage.game.command.Plane) plane, null, player.getId()); continue; diff --git a/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java b/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java new file mode 100644 index 00000000000..da4b64f4049 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AffectionateIndrik.java @@ -0,0 +1,56 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.FightTargetSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class AffectionateIndrik extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public AffectionateIndrik(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Affectionate Indrik enters the battlefield, you may have it fight target creature you don't control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new FightTargetSourceEffect() + .setText("you may have it fight " + + "target creature you don't control"), + true + ); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public AffectionateIndrik(final AffectionateIndrik card) { + super(card); + } + + @Override + public AffectionateIndrik copy() { + return new AffectionateIndrik(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java b/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java new file mode 100644 index 00000000000..8ca0e64be47 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java @@ -0,0 +1,121 @@ +package mage.cards.a; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +/** + * + * @author TheElk801 + */ +public final class ArclightPhoenix extends CardImpl { + + public ArclightPhoenix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.PHOENIX); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // At the beginning of combat on your turn, if you cast 3 or more instants and/or sorceries this turn, you may return Arclight Phoenix from your graveyard to the battlefield. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfCombatTriggeredAbility( + new ReturnSourceFromGraveyardToBattlefieldEffect(), + TargetController.YOU, true + ), ArclightPhoenixCondition.instance, + "At the beginning of combat on your turn, " + + "if you've cast three or more instant " + + "and sorcery spells this turn, you may return {this} " + + "from your graveyard to the battlefield." + ), new ArclightPhoenixWatcher()); + } + + public ArclightPhoenix(final ArclightPhoenix card) { + super(card); + } + + @Override + public ArclightPhoenix copy() { + return new ArclightPhoenix(this); + } +} + +enum ArclightPhoenixCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + ArclightPhoenixWatcher watcher + = (ArclightPhoenixWatcher) game.getState().getWatchers().get( + ArclightPhoenixWatcher.class.getSimpleName() + ); + return watcher != null && watcher.getInstantSorceryCount(source.getControllerId()) > 2; + } +} + +class ArclightPhoenixWatcher extends Watcher { + + private Map instantSorceryCount = new HashMap(); + + public ArclightPhoenixWatcher() { + super(ArclightPhoenixWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public ArclightPhoenixWatcher(final ArclightPhoenixWatcher watcher) { + super(watcher); + this.instantSorceryCount.putAll(watcher.instantSorceryCount); + } + + @Override + public ArclightPhoenixWatcher copy() { + return new ArclightPhoenixWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell == null || !spell.isInstantOrSorcery()) { + return; + } + this.instantSorceryCount.putIfAbsent(spell.getControllerId(), 0); + this.instantSorceryCount.compute( + spell.getControllerId(), (k, a) -> a + 1 + ); + } + } + + @Override + public void reset() { + super.reset(); + this.instantSorceryCount.clear(); + } + + public int getInstantSorceryCount(UUID playerId) { + return this.instantSorceryCount.getOrDefault(playerId, 0); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AssureAssemble.java b/Mage.Sets/src/mage/cards/a/AssureAssemble.java new file mode 100644 index 00000000000..dabe55520de --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AssureAssemble.java @@ -0,0 +1,56 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SpellAbilityType; +import mage.counters.CounterType; +import mage.game.permanent.token.ElfKnightToken; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class AssureAssemble extends SplitCard { + + public AssureAssemble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G/W}{G/W}", "{4}{G}{W}", SpellAbilityType.SPLIT); + + // Assure + // Put a +1/+1 counter on target creature. It gains indestructible until end of turn. + this.getLeftHalfCard().getSpellAbility().addEffect( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + this.getLeftHalfCard().getSpellAbility().addEffect( + new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), + Duration.EndOfTurn + ).setText("It gains indestructible until end of turn.") + ); + this.getLeftHalfCard().getSpellAbility().addTarget( + new TargetCreaturePermanent() + ); + + // Assemble + // Create three 2/2 green and white Elf Knight creature tokens with vigilance. + this.getRightHalfCard().getSpellAbility().addEffect( + new CreateTokenEffect(new ElfKnightToken(), 3) + ); + } + + public AssureAssemble(final AssureAssemble card) { + super(card); + } + + @Override + public AssureAssemble copy() { + return new AssureAssemble(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AureliaExemplarOfJustice.java b/Mage.Sets/src/mage/cards/a/AureliaExemplarOfJustice.java new file mode 100644 index 00000000000..255859b4d31 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AureliaExemplarOfJustice.java @@ -0,0 +1,103 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.MentorAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class AureliaExemplarOfJustice extends CardImpl { + + public AureliaExemplarOfJustice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Mentor + this.addAbility(new MentorAbility()); + + // At the beginning of combat on your turn, choose up to one target creature you control. Until end of turn, that creature gets +2/+0, gains trample if it's red, and gains vigilance if it's white. + Ability ability = new BeginningOfCombatTriggeredAbility( + new AureliaExemplarOfJusticeEffect(), + TargetController.YOU, false + ); + ability.addTarget(new TargetControlledCreaturePermanent(0, 1)); + this.addAbility(ability); + } + + public AureliaExemplarOfJustice(final AureliaExemplarOfJustice card) { + super(card); + } + + @Override + public AureliaExemplarOfJustice copy() { + return new AureliaExemplarOfJustice(this); + } +} + +class AureliaExemplarOfJusticeEffect extends OneShotEffect { + + public AureliaExemplarOfJusticeEffect() { + super(Outcome.Benefit); + this.staticText = "choose up to one target creature you control. " + + "Until end of turn, that creature gets +2/+0, " + + "gains trample if it's red, " + + "and gains vigilance if it's white."; + } + + public AureliaExemplarOfJusticeEffect(final AureliaExemplarOfJusticeEffect effect) { + super(effect); + } + + @Override + public AureliaExemplarOfJusticeEffect copy() { + return new AureliaExemplarOfJusticeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (creature == null) { + return false; + } + game.addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn), source); + if (creature.getColor(game).isRed()) { + game.addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ), source); + } + if (creature.getColor(game).isWhite()) { + game.addEffect(new GainAbilityTargetEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn + ), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BarrierOfBones.java b/Mage.Sets/src/mage/cards/b/BarrierOfBones.java new file mode 100644 index 00000000000..bde2f7fbf33 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BarrierOfBones.java @@ -0,0 +1,44 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class BarrierOfBones extends CardImpl { + + public BarrierOfBones(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.SKELETON); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // When Barrier of Bones enters the battlefield, surveil 1. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SurveilEffect(1), false + )); + } + + public BarrierOfBones(final BarrierOfBones card) { + super(card); + } + + @Override + public BarrierOfBones copy() { + return new BarrierOfBones(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BartizanBats.java b/Mage.Sets/src/mage/cards/b/BartizanBats.java new file mode 100644 index 00000000000..7f9efcaf93f --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BartizanBats.java @@ -0,0 +1,36 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class BartizanBats extends CardImpl { + + public BartizanBats(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.BAT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public BartizanBats(final BartizanBats card) { + super(card); + } + + @Override + public BartizanBats copy() { + return new BartizanBats(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BeaconBolt.java b/Mage.Sets/src/mage/cards/b/BeaconBolt.java new file mode 100644 index 00000000000..39ec31e518e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BeaconBolt.java @@ -0,0 +1,39 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.abilities.dynamicvalue.common.InstantSorceryExileGraveyardCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.JumpStartAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class BeaconBolt extends CardImpl { + + public BeaconBolt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{R}"); + + // Beacon Bolt deals damage to target creature equal to the total number of instant and sorcery cards you own in exile and in your graveyard. + this.getSpellAbility().addEffect(new DamageTargetEffect( + InstantSorceryExileGraveyardCount.instance + ).setText("{this} deals damage to target creature equal to " + + "the total number of instant and sorcery cards " + + "you own in exile and in your graveyard")); + + // Jump-start + this.addAbility(new JumpStartAbility(this)); + } + + public BeaconBolt(final BeaconBolt card) { + super(card); + } + + @Override + public BeaconBolt copy() { + return new BeaconBolt(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Berserk.java b/Mage.Sets/src/mage/cards/b/Berserk.java index f193dcae694..3d38da94d83 100644 --- a/Mage.Sets/src/mage/cards/b/Berserk.java +++ b/Mage.Sets/src/mage/cards/b/Berserk.java @@ -171,7 +171,7 @@ class BerserkDelayedDestroyEffect extends OneShotEffect { Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (permanent != null) { Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { + if (watcher instanceof AttackedThisTurnWatcher) { if (((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { return permanent.destroy(source.getSourceId(), game, false); } diff --git a/Mage.Sets/src/mage/cards/b/BloodOperative.java b/Mage.Sets/src/mage/cards/b/BloodOperative.java new file mode 100644 index 00000000000..f1e43565b15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BloodOperative.java @@ -0,0 +1,97 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.abilities.keyword.LifelinkAbility; +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.players.Player; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author LevelX2 + */ +public final class BloodOperative extends CardImpl { + + public BloodOperative(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Blood Operative enters the battlefield, you may exile target card from a graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect(), true); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + + // Whenever you surveil, if Blood Operative is in your graveyard, you may pay 3 life. If you do, return Blood Operative to your hand. + this.addAbility(new BloodOperativeTriggeredAbility()); + } + + public BloodOperative(final BloodOperative card) { + super(card); + } + + @Override + public BloodOperative copy() { + return new BloodOperative(this); + } +} + +class BloodOperativeTriggeredAbility extends TriggeredAbilityImpl { + + public BloodOperativeTriggeredAbility() { + super(Zone.BATTLEFIELD, new DoIfCostPaid(new ReturnSourceFromGraveyardToHandEffect(), new PayLifeCost(3)), false); + } + + public BloodOperativeTriggeredAbility(final BloodOperativeTriggeredAbility ability) { + super(ability); + } + + @Override + public BloodOperativeTriggeredAbility copy() { + return new BloodOperativeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SURVEILED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(getControllerId()); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + Player controller = game.getPlayer(getControllerId()); + if (controller != null && controller.getGraveyard().contains(getSourceId())) { + return super.checkInterveningIfClause(game); + } + return false; + } + + @Override + public String getRule() { + return "Whenever you surveil, if {this} is in your graveyard, you may pay 3 life. If you do, return {this} to your hand."; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BookDevourer.java b/Mage.Sets/src/mage/cards/b/BookDevourer.java new file mode 100644 index 00000000000..cb48929f47d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BookDevourer.java @@ -0,0 +1,45 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.discard.DiscardHandDrawSameNumberSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class BookDevourer extends CardImpl { + + public BookDevourer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Book Devourer deals combat damage to a player, you may discard all the cards in your hand. If you do, draw that many cards. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DiscardHandDrawSameNumberSourceEffect() + .setText("discard all the cards in your hand. " + + "If you do, draw that many cards"), true + )); + } + + public BookDevourer(final BookDevourer card) { + super(card); + } + + @Override + public BookDevourer copy() { + return new BookDevourer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BroodingSaurian.java b/Mage.Sets/src/mage/cards/b/BroodingSaurian.java index 135bbcff7c9..9b71bf2e91c 100644 --- a/Mage.Sets/src/mage/cards/b/BroodingSaurian.java +++ b/Mage.Sets/src/mage/cards/b/BroodingSaurian.java @@ -55,7 +55,7 @@ class BroodingSaurianControlEffect extends ContinuousEffectImpl { public BroodingSaurianControlEffect() { super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); - this.staticText = "each player gains control of all nontoken permanents he or she owns"; + this.staticText = "each player gains control of all nontoken permanents they own"; } public BroodingSaurianControlEffect(final BroodingSaurianControlEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BurglarRat.java b/Mage.Sets/src/mage/cards/b/BurglarRat.java new file mode 100644 index 00000000000..f6efa16d72a --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BurglarRat.java @@ -0,0 +1,44 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; + +/** + * + * @author TheElk801 + */ +public final class BurglarRat extends CardImpl { + + public BurglarRat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.RAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Burglar Rat enters the battlefield, each opponent discards a card. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DiscardEachPlayerEffect( + new StaticValue(1), false, + TargetController.OPPONENT + ) + )); + } + + public BurglarRat(final BurglarRat card) { + super(card); + } + + @Override + public BurglarRat copy() { + return new BurglarRat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java b/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java index 48c26262d3e..1c2b59519b3 100644 --- a/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java +++ b/Mage.Sets/src/mage/cards/b/BuzzingWhackADoodle.java @@ -136,7 +136,7 @@ class WhackCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { Object object = game.getState().getValue("whack" + source.getSourceId()); - if (object != null && object instanceof Boolean && (Boolean) object) { + if (object instanceof Boolean && (Boolean) object) { return 1; } return 0; @@ -157,7 +157,7 @@ class DoodleCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { Object object = game.getState().getValue("doodle" + source.getSourceId()); - if (object != null && object instanceof Boolean && (Boolean) object) { + if (object instanceof Boolean && (Boolean) object) { return 1; } return 0; @@ -178,7 +178,7 @@ class BuzzCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { Object object = game.getState().getValue("buzz" + source.getSourceId()); - if (object != null && object instanceof Boolean && (Boolean) object) { + if (object instanceof Boolean && (Boolean) object) { return 1; } return 0; diff --git a/Mage.Sets/src/mage/cards/c/Camaraderie.java b/Mage.Sets/src/mage/cards/c/Camaraderie.java new file mode 100644 index 00000000000..505d1de53f6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Camaraderie.java @@ -0,0 +1,72 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class Camaraderie extends CardImpl { + + public Camaraderie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{W}"); + + // You gain X life and draw X cards, where X is the number of creatures you control. Creatures you control get +1/+1 until end of turn. + this.getSpellAbility().addEffect(new CamaraderieEffect()); + } + + public Camaraderie(final Camaraderie card) { + super(card); + } + + @Override + public Camaraderie copy() { + return new Camaraderie(this); + } +} + +class CamaraderieEffect extends OneShotEffect { + + public CamaraderieEffect() { + super(Outcome.Benefit); + this.staticText = "You gain X life and draw X cards, " + + "where X is the number of creatures you control. " + + "Creatures you control get +1/+1 until end of turn."; + } + + public CamaraderieEffect(final CamaraderieEffect effect) { + super(effect); + } + + @Override + public CamaraderieEffect copy() { + return new CamaraderieEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getSourceId()); + if (player == null) { + return false; + } + int xValue = game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getSourceId(), source.getControllerId(), game + ); + player.gainLife(xValue, game, source); + player.drawCards(xValue, game); + game.addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java b/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java new file mode 100644 index 00000000000..d99c19d9775 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java @@ -0,0 +1,73 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; + +/** + * + * @author TheElk801 + */ +public final class CentaurPeacemaker extends CardImpl { + + public CentaurPeacemaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.subtype.add(SubType.CENTAUR); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Centaur Mediator enters the battlefield, each player gains 4 life. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CentaurMediatorEffect() + )); + } + + public CentaurPeacemaker(final CentaurPeacemaker card) { + super(card); + } + + @Override + public CentaurPeacemaker copy() { + return new CentaurPeacemaker(this); + } +} + +class CentaurMediatorEffect extends OneShotEffect { + + public CentaurMediatorEffect() { + super(Outcome.GainLife); + staticText = "each player gains 4 life."; + } + + public CentaurMediatorEffect(final CentaurMediatorEffect effect) { + super(effect); + } + + @Override + public CentaurMediatorEffect copy() { + return new CentaurMediatorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getState().getPlayersInRange( + source.getControllerId(), game + ).stream().map((playerId) -> game.getPlayer(playerId)).filter( + (player) -> (player != null) + ).forEachOrdered((player) -> { + player.gainLife(4, game, source); + }); + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/c/ChainOfSilence.java b/Mage.Sets/src/mage/cards/c/ChainOfSilence.java index 92d48f1e294..b9848d13baf 100644 --- a/Mage.Sets/src/mage/cards/c/ChainOfSilence.java +++ b/Mage.Sets/src/mage/cards/c/ChainOfSilence.java @@ -81,7 +81,7 @@ class ChainOfSilenceEffect extends OneShotEffect { Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { StackObject newStackObject = spell.createCopyOnStack(game, source, player.getId(), true); - if (newStackObject != null && newStackObject instanceof Spell) { + if (newStackObject instanceof Spell) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6); diff --git a/Mage.Sets/src/mage/cards/c/ChainOfVapor.java b/Mage.Sets/src/mage/cards/c/ChainOfVapor.java index f5abf3ace48..d6b94d8838c 100644 --- a/Mage.Sets/src/mage/cards/c/ChainOfVapor.java +++ b/Mage.Sets/src/mage/cards/c/ChainOfVapor.java @@ -78,7 +78,7 @@ class ChainOfVaporEffect extends OneShotEffect { Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { StackObject newStackObject = spell.createCopyOnStack(game, source, player.getId(), true); - if (newStackObject != null && newStackObject instanceof Spell) { + if (newStackObject instanceof Spell) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6); diff --git a/Mage.Sets/src/mage/cards/c/ChainStasis.java b/Mage.Sets/src/mage/cards/c/ChainStasis.java index f49ea83cc09..295f1bffa14 100644 --- a/Mage.Sets/src/mage/cards/c/ChainStasis.java +++ b/Mage.Sets/src/mage/cards/c/ChainStasis.java @@ -80,7 +80,7 @@ class ChainStasisEffect extends OneShotEffect { Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { StackObject newStackObject = spell.createCopyOnStack(game, source, player.getId(), true); - if (newStackObject != null && newStackObject instanceof Spell) { + if (newStackObject instanceof Spell) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6); diff --git a/Mage.Sets/src/mage/cards/c/ChanceForGlory.java b/Mage.Sets/src/mage/cards/c/ChanceForGlory.java new file mode 100644 index 00000000000..c630431bd6f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChanceForGlory.java @@ -0,0 +1,36 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +/** + * + * @author TheElk801 + */ +public final class ChanceForGlory extends CardImpl { + + public ChanceForGlory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{W}"); + + // Creatures you control gain indestructible. Take an extra turn after this one. At the beginning of that turn's end step, you lose the game. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfGame + ).setText("Creatures you control gain indestructible.")); + this.getSpellAbility().addEffect(new AddExtraTurnControllerEffect(true)); + } + + public ChanceForGlory(final ChanceForGlory card) { + super(card); + } + + @Override + public ChanceForGlory copy() { + return new ChanceForGlory(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CharnelTroll.java b/Mage.Sets/src/mage/cards/c/CharnelTroll.java new file mode 100644 index 00000000000..07fb56ebac1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CharnelTroll.java @@ -0,0 +1,76 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class CharnelTroll extends CardImpl { + + public CharnelTroll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); + + this.subtype.add(SubType.TROLL); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // At the beginning of your upkeep, exile a creature card from your graveyard. If you do, put a +1/+1 counter on Morgue Troll. Otherwise sacrifice it. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + new SacrificeSourceEffect(), + new ExileFromGraveCost(new TargetCardInYourGraveyard( + StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD + )), false + ).setText("exile a creature card from your graveyard. " + + "If you do, put a +1/+1 counter on {this}." + + " Otherwise sacrifice it."), + TargetController.YOU, false + )); + + // {B}{G}, Discard a creature card: Put a +1/+1 counter on Morgue Troll. + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + new ManaCostsImpl("{B}{G}") + ); + ability.addCost(new DiscardTargetCost( + new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A) + )); + this.addAbility(ability); + } + + public CharnelTroll(final CharnelTroll card) { + super(card); + } + + @Override + public CharnelTroll copy() { + return new CharnelTroll(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChimeOfNight.java b/Mage.Sets/src/mage/cards/c/ChimeOfNight.java index b1ea89b6f3d..5f3a207f0b7 100644 --- a/Mage.Sets/src/mage/cards/c/ChimeOfNight.java +++ b/Mage.Sets/src/mage/cards/c/ChimeOfNight.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -46,6 +45,7 @@ public final class ChimeOfNight extends CardImpl { // When Chime of Night is put into a graveyard from the battlefield, destroy target nonblack creature. ability = new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DestroyTargetEffect(), false); ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } public ChimeOfNight(final ChimeOfNight card) { diff --git a/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java b/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java index f49e01f4599..31bb27a1931 100644 --- a/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java @@ -98,7 +98,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { // save the x value to be available for ETB replacement effect Object object = game.getState().getValue("spellX" + source.getSourceId()); Map spellX; - if (object != null && object instanceof Map) { + if (object instanceof Map) { spellX = (Map) object; } else { spellX = new HashMap<>(); diff --git a/Mage.Sets/src/mage/cards/c/CircuitousRoute.java b/Mage.Sets/src/mage/cards/c/CircuitousRoute.java new file mode 100644 index 00000000000..0b77d6b6597 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CircuitousRoute.java @@ -0,0 +1,52 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author TheElk801 + */ +public final class CircuitousRoute extends CardImpl { + + private static final FilterCard filter + = new FilterCard("basic land cards and/or Gate cards"); + + static { + filter.add(Predicates.or( + Predicates.and( + new CardTypePredicate(CardType.LAND), + new SupertypePredicate(SuperType.BASIC) + ), new SubtypePredicate(SubType.GATE) + )); + } + + public CircuitousRoute(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); + + // Search your library for up to two basic lands and/or Gates and put them onto the battlefield tapped. + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(0, 2, filter), true + )); + } + + public CircuitousRoute(final CircuitousRoute card) { + super(card); + } + + @Override + public CircuitousRoute copy() { + return new CircuitousRoute(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CitywatchSphinx.java b/Mage.Sets/src/mage/cards/c/CitywatchSphinx.java new file mode 100644 index 00000000000..3bfe96bc8db --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CitywatchSphinx.java @@ -0,0 +1,41 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class CitywatchSphinx extends CardImpl { + + public CitywatchSphinx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Citywatch Sphinx dies, surveil 2. + this.addAbility(new DiesTriggeredAbility(new SurveilEffect(2))); + } + + public CitywatchSphinx(final CitywatchSphinx card) { + super(card); + } + + @Override + public CitywatchSphinx copy() { + return new CitywatchSphinx(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CitywideBust.java b/Mage.Sets/src/mage/cards/c/CitywideBust.java new file mode 100644 index 00000000000..3658e4ea0e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CitywideBust.java @@ -0,0 +1,40 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ToughnessPredicate; + +/** + * + * @author TheElk801 + */ +public final class CitywideBust extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures with toughness 4 or greater"); + + static { + filter.add(new ToughnessPredicate(ComparisonType.MORE_THAN, 3)); + } + + public CitywideBust(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}{W}"); + + // Destroy all creatures with toughness 4 or greater. + this.getSpellAbility().addEffect(new DestroyAllEffect(filter)); + } + + public CitywideBust(final CitywideBust card) { + super(card); + } + + @Override + public CitywideBust copy() { + return new CitywideBust(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CommandTheStorm.java b/Mage.Sets/src/mage/cards/c/CommandTheStorm.java new file mode 100644 index 00000000000..2ef8b958453 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CommandTheStorm.java @@ -0,0 +1,32 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class CommandTheStorm extends CardImpl { + + public CommandTheStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); + + // Govern the Storm deals 5 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public CommandTheStorm(final CommandTheStorm card) { + super(card); + } + + @Override + public CommandTheStorm copy() { + return new CommandTheStorm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConclaveCavalier.java b/Mage.Sets/src/mage/cards/c/ConclaveCavalier.java new file mode 100644 index 00000000000..f8035d718c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConclaveCavalier.java @@ -0,0 +1,45 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.ElfKnightToken; + +/** + * + * @author TheElk801 + */ +public final class ConclaveCavalier extends CardImpl { + + public ConclaveCavalier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}{W}{W}"); + + this.subtype.add(SubType.CENTAUR); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Conclave Cavalier dies, create two green and white 2/2 Elf Knight creature tokens with vigilance. + this.addAbility(new DiesTriggeredAbility( + new CreateTokenEffect(new ElfKnightToken(), 2) + )); + } + + public ConclaveCavalier(final ConclaveCavalier card) { + super(card); + } + + @Override + public ConclaveCavalier copy() { + return new ConclaveCavalier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConclaveGuildmage.java b/Mage.Sets/src/mage/cards/c/ConclaveGuildmage.java new file mode 100644 index 00000000000..67b6aab842a --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConclaveGuildmage.java @@ -0,0 +1,62 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.game.permanent.token.ElfKnightToken; + +/** + * + * @author TheElk801 + */ +public final class ConclaveGuildmage extends CardImpl { + + public ConclaveGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {G}, {T}: Creatures you control gain trample until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilityControlledEffect( + TrampleAbility.getInstance(), + Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + ), new ManaCostsImpl("{G}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {5}{W}, {T}: Create a 2/2 green and white Elf Knight creature token with vigilance. + ability = new SimpleActivatedAbility( + new CreateTokenEffect(new ElfKnightToken()), + new ManaCostsImpl("{5}{W}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public ConclaveGuildmage(final ConclaveGuildmage card) { + super(card); + } + + @Override + public ConclaveGuildmage copy() { + return new ConclaveGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConniveConcoct.java b/Mage.Sets/src/mage/cards/c/ConniveConcoct.java new file mode 100644 index 00000000000..8441c314a00 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConniveConcoct.java @@ -0,0 +1,103 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class ConniveConcoct extends SplitCard { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public ConniveConcoct(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U/B}{U/B}", "{3}{U}{B}", SpellAbilityType.SPLIT); + + // Connive + // Gain control of target creature with power 2 or less. + this.getLeftHalfCard().getSpellAbility().addEffect( + new GainControlTargetEffect(Duration.Custom) + ); + this.getLeftHalfCard().getSpellAbility().addTarget( + new TargetCreaturePermanent(filter) + ); + + // Concoct + // Surveil 3, then return a creature card from your graveyard to the battlefield. + this.getRightHalfCard().getSpellAbility().addEffect(new ConcoctEffect()); + } + + public ConniveConcoct(final ConniveConcoct card) { + super(card); + } + + @Override + public ConniveConcoct copy() { + return new ConniveConcoct(this); + } +} + +class ConcoctEffect extends OneShotEffect { + + private static final FilterCard filter + = new FilterCreatureCard("creature card in your graveyard"); + + public ConcoctEffect() { + super(Outcome.Benefit); + this.staticText = "Surveil 3, then return a creature card " + + "from your graveyard to the battlefield."; + } + + public ConcoctEffect(final ConcoctEffect effect) { + super(effect); + } + + @Override + public ConcoctEffect copy() { + return new ConcoctEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.surveil(3, source, game); + Target target = new TargetCardInYourGraveyard(filter); + target.setNotTarget(true); + if (player.choose(outcome, target, source.getSourceId(), game)) { + Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); + effect.apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CracklingDrake.java b/Mage.Sets/src/mage/cards/c/CracklingDrake.java new file mode 100644 index 00000000000..bfe02721df1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CracklingDrake.java @@ -0,0 +1,90 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.InstantSorceryExileGraveyardCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class CracklingDrake extends CardImpl { + + public CracklingDrake(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}{R}{R}"); + + this.subtype.add(SubType.DRAKE); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Crackling Drake's power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SetPowerSourceEffect( + InstantSorceryExileGraveyardCount.instance, Duration.EndOfGame + ).setText("{this}'s power is equal to the total number " + + "of instant and sorcery cards you own " + + "in exile and in your graveyard.") + )); + + // When Crackling Drake enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1) + )); + } + + public CracklingDrake(final CracklingDrake card) { + super(card); + } + + @Override + public CracklingDrake copy() { + return new CracklingDrake(this); + } +} + +class CracklingDrakeCount implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player player = game.getPlayer(sourceAbility.getControllerId()); + if (player != null) { + return player.getGraveyard().count( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game + ) + game.getExile().getExileZone(player.getId()).count( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game + ); + } + return 0; + } + + @Override + public CracklingDrakeCount copy() { + return new CracklingDrakeCount(); + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CreepingChill.java b/Mage.Sets/src/mage/cards/c/CreepingChill.java new file mode 100644 index 00000000000..84aa12a754a --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CreepingChill.java @@ -0,0 +1,74 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class CreepingChill extends CardImpl { + + public CreepingChill(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Creeping Chill deals 3 damage to each opponent and you gain 3 life. + this.getSpellAbility().addEffect( + new DamagePlayersEffect(3, TargetController.OPPONENT) + ); + this.getSpellAbility().addEffect( + new GainLifeEffect(3).setText("and you gain 3 life") + ); + + // When Creeping Chill is put into your graveyard from your library, you may exile it. If you do, Creeping Chill deals 3 damage to each opponent and you gain 3 life. + this.addAbility(new CreepingChillAbility()); + } + + public CreepingChill(final CreepingChill card) { + super(card); + } + + @Override + public CreepingChill copy() { + return new CreepingChill(this); + } +} + +class CreepingChillAbility extends ZoneChangeTriggeredAbility { + + public CreepingChillAbility() { + super( + Zone.LIBRARY, Zone.GRAVEYARD, + new DoIfCostPaid( + new DamagePlayersEffect(3, TargetController.OPPONENT), + new ExileSourceFromGraveCost() + ).addEffect(new GainLifeEffect(3)), + "", true + ); + } + + public CreepingChillAbility(final CreepingChillAbility ability) { + super(ability); + } + + @Override + public CreepingChillAbility copy() { + return new CreepingChillAbility(this); + } + + @Override + public String getRule() { + return "When {this} is put into your graveyard from your library, " + + "you may exile it. If you do, {this} deals 3 damage " + + "to each opponent and you gain 3 life."; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java b/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java new file mode 100644 index 00000000000..62610350a32 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java @@ -0,0 +1,123 @@ +package mage.cards.d; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author TheElk801 + */ +public final class DarkbladeAgent extends CardImpl { + + public DarkbladeAgent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // As long as you've surveilled this turn, Darkblade Agent has deathtouch and "Whenever this creature deals combat damage to a player, draw a card." + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), + Duration.WhileOnBattlefield + ), DarkbladeAgentCondition.instance, + "As long as you've surveilled this turn, " + + "{this} has deathtouch" + ) + ); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ), Duration.WhileOnBattlefield + ), DarkbladeAgentCondition.instance, + "and \"Whenever this creature deals " + + "combat damage to a player, draw a card.\"" + )); + this.addAbility(ability, new SpellsCastWatcher()); + } + + public DarkbladeAgent(final DarkbladeAgent card) { + super(card); + } + + @Override + public DarkbladeAgent copy() { + return new DarkbladeAgent(this); + } +} + +enum DarkbladeAgentCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + DarkbladeAgentWatcher watcher + = (DarkbladeAgentWatcher) game.getState().getWatchers().get( + DarkbladeAgentWatcher.class.getSimpleName() + ); + return watcher != null + && watcher.getSurveiledThisTurn(source.getControllerId()); + } +} + +class DarkbladeAgentWatcher extends Watcher { + + private final Set surveiledThisTurn = new HashSet(); + + public DarkbladeAgentWatcher() { + super(DarkbladeAgentWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public DarkbladeAgentWatcher(final DarkbladeAgentWatcher watcher) { + super(watcher); + this.surveiledThisTurn.addAll(watcher.surveiledThisTurn); + } + + @Override + public DarkbladeAgentWatcher copy() { + return new DarkbladeAgentWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SURVEILED) { + this.surveiledThisTurn.add(event.getPlayerId()); + } + } + + @Override + public void reset() { + super.reset(); + this.surveiledThisTurn.clear(); + } + + public boolean getSurveiledThisTurn(UUID playerId) { + return this.surveiledThisTurn.contains(playerId); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DawnOfHope.java b/Mage.Sets/src/mage/cards/d/DawnOfHope.java new file mode 100644 index 00000000000..c65faba3be4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DawnOfHope.java @@ -0,0 +1,49 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.permanent.token.SoldierLifelinkToken; + +/** + * + * @author TheElk801 + */ +public final class DawnOfHope extends CardImpl { + + public DawnOfHope(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + // Whenever you gain life, you may pay {2}. If you do, draw a card. + this.addAbility(new GainLifeControllerTriggeredAbility( + new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), + new GenericManaCost(2)), false + )); + + // {3}{W}: Create a 1/1 white Soldier creature token with lifelink. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new CreateTokenEffect(new SoldierLifelinkToken()), + new ManaCostsImpl("{3}{W}") + )); + } + + public DawnOfHope(final DawnOfHope card) { + super(card); + } + + @Override + public DawnOfHope copy() { + return new DawnOfHope(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DazzlingLights.java b/Mage.Sets/src/mage/cards/d/DazzlingLights.java new file mode 100644 index 00000000000..eb398cf7e6b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DazzlingLights.java @@ -0,0 +1,37 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class DazzlingLights extends CardImpl { + + public DazzlingLights(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Target creature gets -3/-0 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(-3, 0, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Surveil 2. + this.getSpellAbility().addEffect(new SurveilEffect(2)); + } + + public DazzlingLights(final DazzlingLights card) { + super(card); + } + + @Override + public DazzlingLights copy() { + return new DazzlingLights(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DevkarinDissident.java b/Mage.Sets/src/mage/cards/d/DevkarinDissident.java new file mode 100644 index 00000000000..95b4baaba70 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DevkarinDissident.java @@ -0,0 +1,45 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class DevkarinDissident extends CardImpl { + + public DevkarinDissident(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {4}{G}: Devkarin Dissident gets +2/+2 until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(2, 2, Duration.EndOfTurn), + new ManaCostsImpl("{4}{G}") + )); + } + + public DevkarinDissident(final DevkarinDissident card) { + super(card); + } + + @Override + public DevkarinDissident copy() { + return new DevkarinDissident(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DimirSpybug.java b/Mage.Sets/src/mage/cards/d/DimirSpybug.java new file mode 100644 index 00000000000..4a4e4662e17 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DimirSpybug.java @@ -0,0 +1,82 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author TheElk801 + */ +public final class DimirSpybug extends CardImpl { + + public DimirSpybug(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever you surveil, put a +1/+1 counter on Dimir Spybug. + this.addAbility(new DimirSpybugTriggeredAbility()); + } + + public DimirSpybug(final DimirSpybug card) { + super(card); + } + + @Override + public DimirSpybug copy() { + return new DimirSpybug(this); + } +} + +class DimirSpybugTriggeredAbility extends TriggeredAbilityImpl { + + public DimirSpybugTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect( + CounterType.P1P1.createInstance() + ), false); + } + + public DimirSpybugTriggeredAbility(final DimirSpybugTriggeredAbility ability) { + super(ability); + } + + @Override + public DimirSpybugTriggeredAbility copy() { + return new DimirSpybugTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SURVEIL; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()); + } + + @Override + public String getRule() { + return "Whenever you surveil, put a +1/+1 counter on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java b/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java new file mode 100644 index 00000000000..762421895e5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java @@ -0,0 +1,126 @@ +package mage.cards.d; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class DiscoveryDispersal extends SplitCard { + + public DiscoveryDispersal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, new CardType[]{CardType.INSTANT}, "{1}{U/B}", "{3}{U}{B}", SpellAbilityType.SPLIT); + + // Discovery + // Surveil 2, then draw a card. + this.getLeftHalfCard().getSpellAbility().addEffect( + new SurveilEffect(2).setText("Surveil 2,") + ); + this.getLeftHalfCard().getSpellAbility().addEffect( + new DrawCardSourceControllerEffect(1 + ).setText("then draw a card. (To surveil 2, " + + "look at the top two cards of your library, " + + "then put any number of them into your graveyard " + + "and the rest on top of your library " + + "in any order.)") + ); + + // Dispersal + // Each opponent returns a nonland permanent they control with the highest converted mana cost among permanents they control to its owner’s hand, then discards a card. + this.getLeftHalfCard().getSpellAbility().addEffect(new DispersalEffect()); + } + + public DiscoveryDispersal(final DiscoveryDispersal card) { + super(card); + } + + @Override + public DiscoveryDispersal copy() { + return new DiscoveryDispersal(this); + } +} + +class DispersalEffect extends OneShotEffect { + + public DispersalEffect() { + super(Outcome.Benefit); + this.staticText = "Each opponent returns a nonland permanent " + + "they control with the highest converted mana cost " + + "among permanents they control to its owner’s hand, " + + "then discards a card."; + } + + public DispersalEffect(final DispersalEffect effect) { + super(effect); + } + + @Override + public DispersalEffect copy() { + return new DispersalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set permsToReturn = new HashSet(); + for (UUID opponentId : game.getOpponents(player.getId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + int highestCMC = 0; + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(opponentId)) { + if (permanent != null && !permanent.isLand()) { + highestCMC = Math.max(highestCMC, permanent.getConvertedManaCost()); + } + } + FilterPermanent filter = new FilterNonlandPermanent("permanent you control with converted mana cost " + highestCMC); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, highestCMC)); + filter.add(new ControllerIdPredicate(opponentId)); + Target target = new TargetPermanent(1, 1, filter, true); + if (opponent.choose(outcome, target, source.getSourceId(), game)) { + if (target.getFirstTarget() == null) { + continue; + } + permsToReturn.add(new PermanentIdPredicate(target.getFirstTarget())); + } + } + FilterPermanent filter = new FilterPermanent(); + filter.add(Predicates.or(permsToReturn)); + new ReturnToHandFromBattlefieldAllEffect(filter).apply(game, source); + new DiscardEachPlayerEffect( + new StaticValue(1), false, TargetController.OPPONENT + ).apply(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java b/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java new file mode 100644 index 00000000000..ab9a61804ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java @@ -0,0 +1,80 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +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; + +/** + * + * @author TheElk801 + */ +public final class DisinformationCampaign extends CardImpl { + + public DisinformationCampaign(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{B}"); + + // When Disinformation Campaign enters the battlefield, you draw a card and each opponent discards a card. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1).setText("you draw a card") + ); + ability.addEffect(new DiscardEachPlayerEffect( + new StaticValue(1), false, TargetController.OPPONENT + ).setText("and each opponent discards a card")); + this.addAbility(ability); + + // Whenever you surveil, return Disinformation Campaign to its owner's hand. + this.addAbility(new DisinformationCampaignTriggeredAbility()); + } + + public DisinformationCampaign(final DisinformationCampaign card) { + super(card); + } + + @Override + public DisinformationCampaign copy() { + return new DisinformationCampaign(this); + } +} + +class DisinformationCampaignTriggeredAbility extends TriggeredAbilityImpl { + + public DisinformationCampaignTriggeredAbility() { + super(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), false); + } + + public DisinformationCampaignTriggeredAbility(final DisinformationCampaignTriggeredAbility ability) { + super(ability); + } + + @Override + public DisinformationCampaignTriggeredAbility copy() { + return new DisinformationCampaignTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SURVEILED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()); + } + + @Override + public String getRule() { + return "Whenever you surveil, return {this} to its owner's hand."; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DivineVisitation.java b/Mage.Sets/src/mage/cards/d/DivineVisitation.java new file mode 100644 index 00000000000..f7914a8e972 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DivineVisitation.java @@ -0,0 +1,85 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CopyEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; +import mage.game.permanent.token.AngelVigilanceToken; + +/** + * + * @author TheElk801 + */ +public final class DivineVisitation extends CardImpl { + + public DivineVisitation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); + + // TODO: This implementation is not entirely correct, see https://twitter.com/EliShffrn/status/1042145606582591490 + // If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, new DivineVisitationEffect() + )); + } + + public DivineVisitation(final DivineVisitation card) { + super(card); + } + + @Override + public DivineVisitation copy() { + return new DivineVisitation(this); + } +} + +class DivineVisitationEffect extends ReplacementEffectImpl { + + public DivineVisitationEffect() { + super(Duration.WhileOnBattlefield, Outcome.Copy, false); + staticText = "If one or more creature tokens would be created " + + "under your control, that many 4/4 white Angel creature " + + "tokens with flying and vigilance are created instead."; + } + + public DivineVisitationEffect(DivineVisitationEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent perm = ((EntersTheBattlefieldEvent) event).getTarget(); + return perm != null + && perm.isCreature() + && perm instanceof PermanentToken + && perm.isControlledBy(source.getControllerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + game.addEffect(new CopyEffect(Duration.Custom, new AngelVigilanceToken(), event.getTargetId()), source); + return false; + } + + @Override + public DivineVisitationEffect copy() { + return new DivineVisitationEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/d/DoomWhisperer.java b/Mage.Sets/src/mage/cards/d/DoomWhisperer.java new file mode 100644 index 00000000000..cb8176b27b1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DoomWhisperer.java @@ -0,0 +1,49 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class DoomWhisperer extends CardImpl { + + public DoomWhisperer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.DEMON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Pay 2 life: Surveil 2. + this.addAbility(new SimpleActivatedAbility( + new SurveilEffect(2), new PayLifeCost(2) + )); + } + + public DoomWhisperer(final DoomWhisperer card) { + super(card); + } + + @Override + public DoomWhisperer copy() { + return new DoomWhisperer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DouserOfLights.java b/Mage.Sets/src/mage/cards/d/DouserOfLights.java new file mode 100644 index 00000000000..cc4b449eb53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DouserOfLights.java @@ -0,0 +1,32 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class DouserOfLights extends CardImpl { + + public DouserOfLights(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.HORROR); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + } + + public DouserOfLights(final DouserOfLights card) { + super(card); + } + + @Override + public DouserOfLights copy() { + return new DouserOfLights(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DrownedSecrets.java b/Mage.Sets/src/mage/cards/d/DrownedSecrets.java new file mode 100644 index 00000000000..50c5e63527c --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DrownedSecrets.java @@ -0,0 +1,46 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPlayer; + +/** + * + * @author TheElk801 + */ +public final class DrownedSecrets extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a blue spell"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + public DrownedSecrets(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + // Whenever you cast a blue spell, target player puts the top two cards if their library into their graveyard. + Ability ability = new SpellCastControllerTriggeredAbility( + new PutLibraryIntoGraveTargetEffect(2), filter, false + ); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public DrownedSecrets(final DrownedSecrets card) { + super(card); + } + + @Override + public DrownedSecrets copy() { + return new DrownedSecrets(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElectrostaticField.java b/Mage.Sets/src/mage/cards/e/ElectrostaticField.java new file mode 100644 index 00000000000..39347660eae --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElectrostaticField.java @@ -0,0 +1,46 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class ElectrostaticField extends CardImpl { + + public ElectrostaticField(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // When you cast an instant or sorcery spell, Electrostatic Field deals 1 damage to each opponent. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DamagePlayersEffect(1, TargetController.OPPONENT), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); + } + + public ElectrostaticField(final ElectrostaticField card) { + super(card); + } + + @Override + public ElectrostaticField copy() { + return new ElectrostaticField(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java b/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java index def0376ffce..936d8387677 100644 --- a/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java +++ b/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java @@ -70,7 +70,7 @@ class EngineeredExplosivesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { MageObject engineeredExplosives = game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); - if(engineeredExplosives != null && engineeredExplosives instanceof Permanent){ + if(engineeredExplosives instanceof Permanent){ int count = ((Permanent)engineeredExplosives).getCounters(game).getCount(CounterType.CHARGE); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { if(permanent.getConvertedManaCost() == count){ diff --git a/Mage.Sets/src/mage/cards/e/EnhancedSurveillance.java b/Mage.Sets/src/mage/cards/e/EnhancedSurveillance.java new file mode 100644 index 00000000000..6784a38dedc --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnhancedSurveillance.java @@ -0,0 +1,113 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.ExileSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class EnhancedSurveillance extends CardImpl { + + public EnhancedSurveillance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + // You may look at an additional two cards each time you surveil. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, new EnhancedSurveillanceReplacementEffect() + )); + + // Exile Enhanced Surveillance: Shuffle your graveyard into your library. + this.addAbility(new SimpleActivatedAbility( + new EnhancedSurveillanceShuffleEffect(), new ExileSourceCost() + )); + } + + public EnhancedSurveillance(final EnhancedSurveillance card) { + super(card); + } + + @Override + public EnhancedSurveillance copy() { + return new EnhancedSurveillance(this); + } +} + +class EnhancedSurveillanceReplacementEffect extends ReplacementEffectImpl { + + public EnhancedSurveillanceReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "You may look at an additional " + + "two cards each time you surveil."; + } + + public EnhancedSurveillanceReplacementEffect(final EnhancedSurveillanceReplacementEffect effect) { + super(effect); + } + + @Override + public EnhancedSurveillanceReplacementEffect copy() { + return new EnhancedSurveillanceReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SURVEIL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(event.getAmount() + 2); + return false; + } +} + +class EnhancedSurveillanceShuffleEffect extends OneShotEffect { + + public EnhancedSurveillanceShuffleEffect() { + super(Outcome.Neutral); + this.staticText = "Shuffle your graveyard into your library"; + } + + public EnhancedSurveillanceShuffleEffect(final EnhancedSurveillanceShuffleEffect effect) { + super(effect); + } + + @Override + public EnhancedSurveillanceShuffleEffect copy() { + return new EnhancedSurveillanceShuffleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (Card card : controller.getGraveyard().getCards(game)) { + controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.GRAVEYARD, true, true); + } + controller.shuffleLibrary(source, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ErraticCyclops.java b/Mage.Sets/src/mage/cards/e/ErraticCyclops.java new file mode 100644 index 00000000000..ab18fc9a074 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ErraticCyclops.java @@ -0,0 +1,89 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; + +/** + * + * @author TheElk801 + */ +public final class ErraticCyclops extends CardImpl { + + public ErraticCyclops(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.CYCLOPS); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(0); + this.toughness = new MageInt(8); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever you cast an instant or sorcery spell, Erratic Cyclops gets +X/+0 until end of turn, where X is that spell's converted mana cost. + this.addAbility(new ErraticCyclopsTriggeredAbility()); + } + + public ErraticCyclops(final ErraticCyclops card) { + super(card); + } + + @Override + public ErraticCyclops copy() { + return new ErraticCyclops(this); + } +} + +class ErraticCyclopsTriggeredAbility extends TriggeredAbilityImpl { + + public ErraticCyclopsTriggeredAbility() { + super(Zone.BATTLEFIELD, null, false); + } + + public ErraticCyclopsTriggeredAbility(final ErraticCyclopsTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.isControlledBy(controllerId) + && spell.isInstantOrSorcery()) { + this.getEffects().clear(); + this.addEffect(new BoostSourceEffect( + spell.getConvertedManaCost(), 0, Duration.EndOfTurn + )); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast an instant or sorcery spell, " + + "{this} gets +X/+X until end of turn, " + + "where X is that spell's converted mana cost"; + } + + @Override + public ErraticCyclopsTriggeredAbility copy() { + return new ErraticCyclopsTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ErstwhileTrooper.java b/Mage.Sets/src/mage/cards/e/ErstwhileTrooper.java new file mode 100644 index 00000000000..07146818834 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ErstwhileTrooper.java @@ -0,0 +1,58 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInHand; + +/** + * + * @author TheElk801 + */ +public final class ErstwhileTrooper extends CardImpl { + + public ErstwhileTrooper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Discard a creature card: Erstwhile Trooper gets +2/+2 and gains trample until end of turn. Activate this ability only once each turn. + Ability ability = new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect( + 2, 2, Duration.EndOfTurn + ).setText("{this} gets +2/+2"), + new DiscardTargetCost(new TargetCardInHand( + StaticFilters.FILTER_CARD_CREATURE_A + )) + ); + ability.addEffect(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample until end of turn")); + this.addAbility(ability); + } + + public ErstwhileTrooper(final ErstwhileTrooper card) { + super(card); + } + + @Override + public ErstwhileTrooper copy() { + return new ErstwhileTrooper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EssenceFlux.java b/Mage.Sets/src/mage/cards/e/EssenceFlux.java index f2802fc6b1f..8364d113e65 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceFlux.java +++ b/Mage.Sets/src/mage/cards/e/EssenceFlux.java @@ -77,7 +77,7 @@ class EssenceFluxEffect extends OneShotEffect { cardsToBattlefield.add(targetId); } else { Card card = game.getCard(targetId); - if (card != null && card instanceof MeldCard) { + if (card instanceof MeldCard) { MeldCard meldCard = (MeldCard) card; Card topCard = meldCard.getTopHalfCard(); Card bottomCard = meldCard.getBottomHalfCard(); diff --git a/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java new file mode 100644 index 00000000000..19276ee723f --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java @@ -0,0 +1,151 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.cards.Card; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class EtrataTheSilencer extends CardImpl { + + public EtrataTheSilencer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Etrata, the Silencer can't be blocked. + this.addAbility(new CantBeBlockedSourceAbility()); + + // Whenever Etrata deals combat damage to a player, exile target creature that player controls and put a hit counter on that card. That player loses the game if they own three or more exiled card with hit counters on them. Etrata's owner shuffles Etrata into their library. + this.addAbility(new EtrataTheSilencerTriggeredAbility()); + } + + public EtrataTheSilencer(final EtrataTheSilencer card) { + super(card); + } + + @Override + public EtrataTheSilencer copy() { + return new EtrataTheSilencer(this); + } +} + +class EtrataTheSilencerTriggeredAbility extends TriggeredAbilityImpl { + + public EtrataTheSilencerTriggeredAbility() { + super(Zone.BATTLEFIELD, new EtrataTheSilencerEffect()); + } + + public EtrataTheSilencerTriggeredAbility(final EtrataTheSilencerTriggeredAbility ability) { + super(ability); + } + + @Override + public EtrataTheSilencerTriggeredAbility copy() { + return new EtrataTheSilencerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; + if (damageEvent.isCombatDamage() && event.getSourceId().equals(this.getSourceId())) { + Player opponent = game.getPlayer(event.getPlayerId()); + if (opponent != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); + filter.add(new ControllerIdPredicate(opponent.getId())); + this.getTargets().clear(); + this.addTarget(new TargetCreaturePermanent(filter)); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} deals combat damage to a player, " + + "exile target creature that player controls " + + "and put a hit counter on that card. " + + "That player loses the game if they own three or more " + + "exiled cards with hit counters on them. " + + "{this}'s owner shuffles {this} into their library."; + } +} + +class EtrataTheSilencerEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(new CounterPredicate(CounterType.HIT)); + } + + public EtrataTheSilencerEffect() { + super(Outcome.Benefit); + } + + public EtrataTheSilencerEffect(final EtrataTheSilencerEffect effect) { + super(effect); + } + + @Override + public EtrataTheSilencerEffect copy() { + return new EtrataTheSilencerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (creature == null) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(creature.getControllerId()); + if (controller == null || player == null) { + return false; + } + controller.moveCards(creature, Zone.EXILED, source, game); + Card card = game.getCard(source.getFirstTarget()); + if (card != null) { + card.addCounters(CounterType.HIT.createInstance(), source, game); + } + if (game.getExile().getExileZone(player.getId()).count(filter, game) > 2) { + player.lost(game); + } + return new ShuffleIntoLibrarySourceEffect().apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java b/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java index 841c4906ab1..81603a49a88 100644 --- a/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java +++ b/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java @@ -71,6 +71,7 @@ class ExplosiveRevelationEffect extends OneShotEffect { toReveal.add(card); if (!card.isLand()) { nonLandCard = card; + break; } } // reveal cards diff --git a/Mage.Sets/src/mage/cards/f/FearlessHalberdier.java b/Mage.Sets/src/mage/cards/f/FearlessHalberdier.java new file mode 100644 index 00000000000..c066ad4cbb9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FearlessHalberdier.java @@ -0,0 +1,33 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class FearlessHalberdier extends CardImpl { + + public FearlessHalberdier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + } + + public FearlessHalberdier(final FearlessHalberdier card) { + super(card); + } + + @Override + public FearlessHalberdier copy() { + return new FearlessHalberdier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FeldonsCane.java b/Mage.Sets/src/mage/cards/f/FeldonsCane.java index d343b48226d..18ffbb30a5b 100644 --- a/Mage.Sets/src/mage/cards/f/FeldonsCane.java +++ b/Mage.Sets/src/mage/cards/f/FeldonsCane.java @@ -45,7 +45,7 @@ class FeldonsCaneEffect extends OneShotEffect { FeldonsCaneEffect() { super(Outcome.Neutral); - this.staticText = "Shuffles your graveyard into your library"; + this.staticText = "Shuffle your graveyard into your library"; } FeldonsCaneEffect(final FeldonsCaneEffect effect) { diff --git a/Mage.Sets/src/mage/cards/f/FireUrchin.java b/Mage.Sets/src/mage/cards/f/FireUrchin.java new file mode 100644 index 00000000000..1dcb78b5030 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireUrchin.java @@ -0,0 +1,46 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class FireUrchin extends CardImpl { + + public FireUrchin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever you cast an instant or sorcery spell, Fire Urchin gets +1/+0 until end of turn. + this.addAbility(new SpellCastControllerTriggeredAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); + } + + public FireUrchin(final FireUrchin card) { + super(card); + } + + @Override + public FireUrchin copy() { + return new FireUrchin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FiresongAndSunspeaker.java b/Mage.Sets/src/mage/cards/f/FiresongAndSunspeaker.java index 9c4dcf83fcc..3d396bc5643 100644 --- a/Mage.Sets/src/mage/cards/f/FiresongAndSunspeaker.java +++ b/Mage.Sets/src/mage/cards/f/FiresongAndSunspeaker.java @@ -87,7 +87,7 @@ class FiresongAndSunspeakerTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object instanceof Spell) { + if (object instanceof Spell) { if (event.getTargetId().equals(this.getControllerId()) && object.getColor(game).contains(ObjectColor.WHITE) && (object.isInstant() diff --git a/Mage.Sets/src/mage/cards/f/FlightOfEquenauts.java b/Mage.Sets/src/mage/cards/f/FlightOfEquenauts.java new file mode 100644 index 00000000000..57c3e935476 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlightOfEquenauts.java @@ -0,0 +1,41 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.ConvokeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class FlightOfEquenauts extends CardImpl { + + public FlightOfEquenauts(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public FlightOfEquenauts(final FlightOfEquenauts card) { + super(card); + } + + @Override + public FlightOfEquenauts copy() { + return new FlightOfEquenauts(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlowerFlourish.java b/Mage.Sets/src/mage/cards/f/FlowerFlourish.java new file mode 100644 index 00000000000..47df1408bc8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlowerFlourish.java @@ -0,0 +1,62 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SpellAbilityType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author TheElk801 + */ +public final class FlowerFlourish extends SplitCard { + + private static final FilterCard filter + = new FilterCard("basic Forest or Plains card"); + + static { + filter.add(new SupertypePredicate(SuperType.BASIC)); + filter.add(Predicates.or( + new SubtypePredicate(SubType.FOREST), + new SubtypePredicate(SubType.PLAINS) + )); + } + + public FlowerFlourish(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G/W}", "{4}{G}{W}", SpellAbilityType.SPLIT); + + // Flower + // Search your library for a basic Forest or Plains card, reveal it, put it into your hand, then shuffle your library. + this.getLeftHalfCard().getSpellAbility().addEffect( + new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filter), true, true + ) + ); + + // Flourish + // Creatures you control get +2/+2 until end of turn. + this.getRightHalfCard().getSpellAbility().addEffect( + new BoostControlledEffect(2, 2, Duration.EndOfTurn) + ); + } + + public FlowerFlourish(final FlowerFlourish card) { + super(card); + } + + @Override + public FlowerFlourish copy() { + return new FlowerFlourish(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java b/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java index 06678f2232e..3f1471760d6 100644 --- a/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java +++ b/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java @@ -151,7 +151,7 @@ class ForbiddenCryptPutIntoYourGraveyardReplacementEffect extends ReplacementEff Card card = game.getCard(event.getTargetId()); if (card != null && card.isOwnedBy(source.getControllerId())) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); - if (permanent == null || !(permanent instanceof PermanentToken)) { + if (!(permanent instanceof PermanentToken)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/f/ForsakenWastes.java b/Mage.Sets/src/mage/cards/f/ForsakenWastes.java index 0939aab1703..6fb1308f391 100644 --- a/Mage.Sets/src/mage/cards/f/ForsakenWastes.java +++ b/Mage.Sets/src/mage/cards/f/ForsakenWastes.java @@ -73,7 +73,7 @@ class ForsakenWastesTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject eventSourceObject = game.getObject(event.getSourceId()); - if (eventSourceObject != null && event.getTargetId().equals(this.getSourceId())&& eventSourceObject instanceof Spell ) { + if (event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } diff --git a/Mage.Sets/src/mage/cards/g/GOTOJAIL.java b/Mage.Sets/src/mage/cards/g/GOTOJAIL.java index bd29803529f..a7977281ffb 100644 --- a/Mage.Sets/src/mage/cards/g/GOTOJAIL.java +++ b/Mage.Sets/src/mage/cards/g/GOTOJAIL.java @@ -150,7 +150,7 @@ class GoToJailUpkeepEffect extends OneShotEffect { Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game); - if (sourceObject != null && sourceObject instanceof Permanent && permanent != null) { + if (sourceObject instanceof Permanent && permanent != null) { UUID opponentId = (UUID) game.getState().getValue(sourceObject.getId().toString() + ChooseOpponentEffect.VALUE_KEY); Player opponent = game.getPlayer(opponentId); diff --git a/Mage.Sets/src/mage/cards/g/GarrisonSergeant.java b/Mage.Sets/src/mage/cards/g/GarrisonSergeant.java new file mode 100644 index 00000000000..5a2c7738f1b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarrisonSergeant.java @@ -0,0 +1,61 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author TheElk801 + */ +public final class GarrisonSergeant extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public GarrisonSergeant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{W}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Garrison Sergeant has double strike as long as you control a Gate. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), + Duration.WhileOnBattlefield + ), new PermanentsOnTheBattlefieldCondition(filter), + "{this} has double strike as long as you control a Gate." + ) + )); + } + + public GarrisonSergeant(final GarrisonSergeant card) { + super(card); + } + + @Override + public GarrisonSergeant copy() { + return new GarrisonSergeant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java b/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java new file mode 100644 index 00000000000..bc1dc584880 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java @@ -0,0 +1,57 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author TheElk801 + */ +public final class GatekeeperGargoyle extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public GatekeeperGargoyle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); + + this.subtype.add(SubType.GARGOYLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Gargoyle Guardian enters the battlefield with a +1/+1 counter on it for each Gate you control. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect( + CounterType.P1P1.createInstance(), + new PermanentsOnBattlefieldCount(filter), true + ), "with a +1/+1 counter on it for each Gate you control" + )); + } + + public GatekeeperGargoyle(final GatekeeperGargoyle card) { + super(card); + } + + @Override + public GatekeeperGargoyle copy() { + return new GatekeeperGargoyle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GenerousStray.java b/Mage.Sets/src/mage/cards/g/GenerousStray.java new file mode 100644 index 00000000000..6657cb089c9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GenerousStray.java @@ -0,0 +1,39 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class GenerousStray extends CardImpl { + + public GenerousStray(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // When Generous Stray enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1) + )); + } + + public GenerousStray(final GenerousStray card) { + super(card); + } + + @Override + public GenerousStray copy() { + return new GenerousStray(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GenesisHydra.java b/Mage.Sets/src/mage/cards/g/GenesisHydra.java index 1a9527827f5..be84c1942d8 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisHydra.java +++ b/Mage.Sets/src/mage/cards/g/GenesisHydra.java @@ -71,7 +71,7 @@ class GenesisHydraPutOntoBattlefieldEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Object obj = getValue(CastSourceTriggeredAbility.SOURCE_CAST_SPELL_ABILITY); - if (controller != null && obj != null && obj instanceof SpellAbility) { + if (controller != null && obj instanceof SpellAbility) { int count = ((SpellAbility) obj).getManaCostsToPay().getX(); if (count > 0) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, count)); diff --git a/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java b/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java index 313fd418cac..58c1bc35534 100644 --- a/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java +++ b/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -16,13 +15,15 @@ import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.TargetAdjustment; +import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.other.OwnerPredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.common.TargetCardInGraveyard; /** * @author nantuko @@ -32,6 +33,7 @@ public final class GethLordOfTheVault extends CardImpl { private static final FilterCard filter = new FilterCard("artifact or creature card with converted mana cost X from an opponent's graveyard"); static { + filter.add(new OwnerPredicate(TargetController.OPPONENT)); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE))); @@ -51,7 +53,7 @@ public final class GethLordOfTheVault extends CardImpl { // Then that player puts the top X cards of their library into their graveyard. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GethLordOfTheVaultEffect(), new ManaCostsImpl("{X}{B}")); ability.setTargetAdjustment(TargetAdjustment.X_CMC_EQUAL_GY_CARD); - ability.addTarget(new TargetCardInOpponentsGraveyard(filter)); + ability.addTarget(new TargetCardInGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Ghoultree.java b/Mage.Sets/src/mage/cards/g/Ghoultree.java index e815e948cdd..63a9982da0b 100644 --- a/Mage.Sets/src/mage/cards/g/Ghoultree.java +++ b/Mage.Sets/src/mage/cards/g/Ghoultree.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -10,7 +9,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; /** * @@ -27,7 +26,7 @@ public final class Ghoultree extends CardImpl { this.toughness = new MageInt(10); // Ghoultree costs {1} less to cast for each creature card in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(new FilterCreatureCard()))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_CREATURE))); } public Ghoultree(final Ghoultree card) { diff --git a/Mage.Sets/src/mage/cards/g/GirdForBattle.java b/Mage.Sets/src/mage/cards/g/GirdForBattle.java new file mode 100644 index 00000000000..7b2338edf1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GirdForBattle.java @@ -0,0 +1,35 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class GirdForBattle extends CardImpl { + + public GirdForBattle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); + + // Put a +1/+1 counter on each of up to two target creatures. + this.getSpellAbility().addEffect(new AddCountersTargetEffect( + CounterType.P1P1.createInstance() + ).setText("Put a +1/+1 counter on each of up to two target creatures")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + } + + public GirdForBattle(final GirdForBattle card) { + super(card); + } + + @Override + public GirdForBattle copy() { + return new GirdForBattle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java b/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java new file mode 100644 index 00000000000..58c62ade5d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java @@ -0,0 +1,68 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author TheElk801 + */ +public final class GlaiveOfTheGuildpact extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent("Gate you control"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public GlaiveOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +1/+0 for each Gate you control and has vigilance and menace. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new BoostEquippedEffect( + new PermanentsOnBattlefieldCount(filter), + new StaticValue(0) + ) + ); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has vigilance")); + ability.addEffect(new GainAbilityAttachedEffect( + new MenaceAbility(), AttachmentType.EQUIPMENT + ).setText("and menace")); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + public GlaiveOfTheGuildpact(final GlaiveOfTheGuildpact card) { + super(card); + } + + @Override + public GlaiveOfTheGuildpact copy() { + return new GlaiveOfTheGuildpact(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java b/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java new file mode 100644 index 00000000000..68b831134c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java @@ -0,0 +1,88 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterLandCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class GlowsporeShaman extends CardImpl { + + public GlowsporeShaman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Glowspore Shaman enters the battlefield, put the top three cards of your library into your graveyard. You may put a land card from your graveyard on top of your library. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new PutTopCardOfLibraryIntoGraveControllerEffect(3), false + )); + } + + public GlowsporeShaman(final GlowsporeShaman card) { + super(card); + } + + @Override + public GlowsporeShaman copy() { + return new GlowsporeShaman(this); + } +} + +class GlowsporeShamanEffect extends OneShotEffect { + + public static final FilterLandCard filter + = new FilterLandCard("a land card from your graveyard"); + + public GlowsporeShamanEffect() { + super(Outcome.Benefit); + this.staticText = "You may put a land card from your graveyard " + + "on top of your library."; + } + + public GlowsporeShamanEffect(final GlowsporeShamanEffect effect) { + super(effect); + } + + @Override + public GlowsporeShamanEffect copy() { + return new GlowsporeShamanEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Target target = new TargetCardInYourGraveyard(0, 1, filter, true); + if (player.chooseUse(outcome, "Put a land card on top of your library?", source, game) + && player.choose(outcome, target, source.getSourceId(), game)) { + Effect effect = new PutOnLibraryTargetEffect(true); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); + effect.apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinBanneret.java b/Mage.Sets/src/mage/cards/g/GoblinBanneret.java new file mode 100644 index 00000000000..8491d472259 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinBanneret.java @@ -0,0 +1,49 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.MentorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class GoblinBanneret extends CardImpl { + + public GoblinBanneret(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Mentor + this.addAbility(new MentorAbility()); + + // {1}{R}: Goblin Banneret gets +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(2, 0, Duration.EndOfTurn), + new ManaCostsImpl("{1}{R}") + )); + } + + public GoblinBanneret(final GoblinBanneret card) { + super(card); + } + + @Override + public GoblinBanneret copy() { + return new GoblinBanneret(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinLocksmith.java b/Mage.Sets/src/mage/cards/g/GoblinLocksmith.java new file mode 100644 index 00000000000..9fa25f47df2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinLocksmith.java @@ -0,0 +1,51 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.combat.CantBlockAllEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; + +/** + * + * @author TheElk801 + */ +public final class GoblinLocksmith extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with defender"); + + static { + filter.add(new AbilityPredicate(DefenderAbility.class)); + } + + public GoblinLocksmith(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Goblin Locksmith attacks, creatures with defender can't block this turn. + this.addAbility(new AttacksTriggeredAbility( + new CantBlockAllEffect(filter, Duration.EndOfTurn), false + )); + } + + public GoblinLocksmith(final GoblinLocksmith card) { + super(card); + } + + @Override + public GoblinLocksmith copy() { + return new GoblinLocksmith(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GolgariFindbroker.java b/Mage.Sets/src/mage/cards/g/GolgariFindbroker.java new file mode 100644 index 00000000000..e95d580c617 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GolgariFindbroker.java @@ -0,0 +1,49 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class GolgariFindbroker extends CardImpl { + + private static final FilterCard filter + = new FilterPermanentCard("permanent card from your graveyard"); + + public GolgariFindbroker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{G}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When Golgari Findbroker enters the battlefield, return target permanent card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility( + new ReturnFromGraveyardToHandTargetEffect(), false + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + public GolgariFindbroker(final GolgariFindbroker card) { + super(card); + } + + @Override + public GolgariFindbroker copy() { + return new GolgariFindbroker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GolgariRaiders.java b/Mage.Sets/src/mage/cards/g/GolgariRaiders.java new file mode 100644 index 00000000000..c6e60fe183c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GolgariRaiders.java @@ -0,0 +1,57 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class GolgariRaiders extends CardImpl { + + public GolgariRaiders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Undergrowth — Golgari Raiders enters the battlefield with a +1/+1 counter on it for each creature card in your graveyard. + Ability ability = new EntersBattlefieldAbility( + new AddCountersSourceEffect( + CounterType.P1P1.createInstance(0), + new CardsInControllerGraveyardCount( + StaticFilters.FILTER_CARD_CREATURE + ), true + ), "with a +1/+1 counter on it " + + "for each creature card in your graveyard" + ); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); + this.addAbility(ability); + } + + public GolgariRaiders(final GolgariRaiders card) { + super(card); + } + + @Override + public GolgariRaiders copy() { + return new GolgariRaiders(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrapplingSundew.java b/Mage.Sets/src/mage/cards/g/GrapplingSundew.java new file mode 100644 index 00000000000..961af9c160b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrapplingSundew.java @@ -0,0 +1,55 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class GrapplingSundew extends CardImpl { + + public GrapplingSundew(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.PLANT); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // {4}{G}: Grappling Sundew gains indestructible until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), + Duration.EndOfTurn + ), new ManaCostsImpl("{4}{G}") + )); + } + + public GrapplingSundew(final GrapplingSundew card) { + super(card); + } + + @Override + public GrapplingSundew copy() { + return new GrapplingSundew(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java b/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java new file mode 100644 index 00000000000..6f907138688 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java @@ -0,0 +1,109 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class GruesomeMenagerie extends CardImpl { + + public GruesomeMenagerie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); + + // Choose a creature card with converted mana cost 1 in your graveyard, then do the same for creature cards with converted mana costs 2 and 3. Return those cards to the battlefield. + this.getSpellAbility().addEffect(new GruesomeMenagerieEffect()); + } + + public GruesomeMenagerie(final GruesomeMenagerie card) { + super(card); + } + + @Override + public GruesomeMenagerie copy() { + return new GruesomeMenagerie(this); + } +} + +class GruesomeMenagerieEffect extends OneShotEffect { + + private static final FilterCard filter1 + = new FilterCreatureCard("creature card with converted mana cost 1"); + private static final FilterCard filter2 + = new FilterCreatureCard("creature card with converted mana cost 2"); + private static final FilterCard filter3 + = new FilterCreatureCard("creature card with converted mana cost 3"); + + static { + filter1.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, 1)); + filter2.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, 2)); + filter3.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, 3)); + } + + public GruesomeMenagerieEffect() { + super(Outcome.Benefit); + this.staticText = "Choose a creature card with converted mana cost 1 " + + "in your graveyard, then do the same for creature cards " + + "with converted mana costs 2 and 3. " + + "Return those cards to the battlefield."; + } + + public GruesomeMenagerieEffect(final GruesomeMenagerieEffect effect) { + super(effect); + } + + @Override + public GruesomeMenagerieEffect copy() { + return new GruesomeMenagerieEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Target target; + target = new TargetCardInYourGraveyard(filter1); + if (player.choose(outcome, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + cards.add(card); + } + } + target = new TargetCardInYourGraveyard(filter2); + if (player.choose(outcome, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + cards.add(card); + } + } + target = new TargetCardInYourGraveyard(filter3); + if (player.choose(outcome, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + cards.add(card); + } + } + return player.moveCards(cards, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HaazdaMarshal.java b/Mage.Sets/src/mage/cards/h/HaazdaMarshal.java new file mode 100644 index 00000000000..fde0b161308 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HaazdaMarshal.java @@ -0,0 +1,75 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.SoldierLifelinkToken; + +/** + * + * @author TheElk801 + */ +public final class HaazdaMarshal extends CardImpl { + + public HaazdaMarshal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Haazda Marshal and at least two other creatures attack, create a 1/1 white Solider creature token with lifelink. + this.addAbility(new HaazdaMarshalTriggeredAbility()); + } + + public HaazdaMarshal(final HaazdaMarshal card) { + super(card); + } + + @Override + public HaazdaMarshal copy() { + return new HaazdaMarshal(this); + } +} + +class HaazdaMarshalTriggeredAbility extends TriggeredAbilityImpl { + + public HaazdaMarshalTriggeredAbility() { + super(Zone.BATTLEFIELD, new CreateTokenEffect(new SoldierLifelinkToken())); + } + + public HaazdaMarshalTriggeredAbility(final HaazdaMarshalTriggeredAbility ability) { + super(ability); + } + + @Override + public HaazdaMarshalTriggeredAbility copy() { + return new HaazdaMarshalTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getCombat().getAttackers().size() >= 3 + && game.getCombat().getAttackers().contains(this.sourceId); + } + + @Override + public String getRule() { + return "Whenever {this} and at least two other creatures attack, " + + "create a 1/1 white Solider creature token with lifelink."; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HatcherySpider.java b/Mage.Sets/src/mage/cards/h/HatcherySpider.java new file mode 100644 index 00000000000..ac3d189cc34 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HatcherySpider.java @@ -0,0 +1,121 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.constants.SubType; +import mage.abilities.keyword.ReachAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author TheElk801 + */ +public final class HatcherySpider extends CardImpl { + + public HatcherySpider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); + + this.subtype.add(SubType.SPIDER); + this.power = new MageInt(5); + this.toughness = new MageInt(7); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Undergrowth — When you cast this spell, reveal the top X cards of your library, where X is the number of creature cards in your graveyard. You may put a green permanent card with converted mana cost X or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. + this.addAbility(new CastSourceTriggeredAbility( + new HatcherySpiderEffect(), false, + "Undergrowth — " + )); + } + + public HatcherySpider(final HatcherySpider card) { + super(card); + } + + @Override + public HatcherySpider copy() { + return new HatcherySpider(this); + } +} + +class HatcherySpiderEffect extends OneShotEffect { + + public HatcherySpiderEffect() { + super(Outcome.Benefit); + this.staticText = "reveal the top X cards of your library, " + + "where X is the number of creature cards in your graveyard. " + + "You may put a green permanent card with converted mana cost " + + "X or less from among them onto the battlefield. " + + "Put the rest on the bottom of your library " + + "in a random order."; + } + + public HatcherySpiderEffect(final HatcherySpiderEffect effect) { + super(effect); + } + + @Override + public HatcherySpiderEffect copy() { + return new HatcherySpiderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + int xValue = new CardsInControllerGraveyardCount( + StaticFilters.FILTER_CARD_CREATURE + ).calculate(game, source, this); + FilterCard filter = new FilterPermanentCard( + "green permanent card with converted mana cost " + + xValue + " or less" + ); + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(new ConvertedManaCostPredicate( + ComparisonType.FEWER_THAN, xValue + 1 + )); + TargetCard target = new TargetCardInLibrary(filter); + Cards cards = new CardsImpl( + player.getLibrary().getTopCards(game, xValue) + ); + if (player.chooseUse(outcome, "Put a card onto the battlefield?", source, game) + && player.choose(outcome, cards, target, game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null + && player.moveCards(card, Zone.BATTLEFIELD, source, game)) { + cards.remove(card); + } + } + while (!cards.isEmpty()) { + Card card = cards.getRandom(game); + player.getLibrary().putOnBottom(card, game); + cards.remove(card); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java b/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java new file mode 100644 index 00000000000..a96308cbdba --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java @@ -0,0 +1,57 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class HellkiteWhelp extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature defending player controls"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(new DefendingPlayerControlsPredicate()); + } + + public HellkiteWhelp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(3); + this.toughness = new MageInt(34); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Hellkite Whelp attacks, it deals 1 damage to target creature defending player controls. + Ability ability = new AttacksTriggeredAbility( + new DamageTargetEffect(1, "it"), false + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + public HellkiteWhelp(final HellkiteWhelp card) { + super(card); + } + + @Override + public HellkiteWhelp copy() { + return new HellkiteWhelp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HiredPoisoner.java b/Mage.Sets/src/mage/cards/h/HiredPoisoner.java new file mode 100644 index 00000000000..13a1d2a9f2c --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HiredPoisoner.java @@ -0,0 +1,37 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class HiredPoisoner extends CardImpl { + + public HiredPoisoner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + public HiredPoisoner(final HiredPoisoner card) { + super(card); + } + + @Override + public HiredPoisoner copy() { + return new HiredPoisoner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java index 0a31b9a4fbf..5df2aeefb87 100644 --- a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java +++ b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java @@ -184,7 +184,7 @@ class HopeOfGhirapurCombatDamageWatcher extends Watcher { public boolean playerGotCombatDamage(UUID objectId, UUID playerId, Game game) { StackObject stackObject = game.getState().getStack().getStackObject(objectId); MageObjectReference mor; - if (stackObject != null && stackObject instanceof StackAbility) { + if (stackObject instanceof StackAbility) { // This is neccessary because the source object was sacrificed as cost and the correct zone change counter for target calid check can only be get from stack mor = new MageObjectReference(objectId, ((StackAbility) stackObject).getSourceObjectZoneChangeCounter(), game); } else { diff --git a/Mage.Sets/src/mage/cards/h/HouseGuildmage.java b/Mage.Sets/src/mage/cards/h/HouseGuildmage.java new file mode 100644 index 00000000000..d416597337a --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HouseGuildmage.java @@ -0,0 +1,57 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class HouseGuildmage extends CardImpl { + + public HouseGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}{U}, {T}: Target creature doesn't untap during its controller's next untap step. + Ability ability = new SimpleActivatedAbility( + new DontUntapInControllersNextUntapStepTargetEffect(), + new ManaCostsImpl("{1}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // {2}{B}, {T}: Surveil 2. + ability = new SimpleActivatedAbility( + new SurveilEffect(2), + new ManaCostsImpl("{2}{B}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public HouseGuildmage(final HouseGuildmage card) { + super(card); + } + + @Override + public HouseGuildmage copy() { + return new HouseGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HuntedWitness.java b/Mage.Sets/src/mage/cards/h/HuntedWitness.java new file mode 100644 index 00000000000..33c60a31772 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HuntedWitness.java @@ -0,0 +1,40 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.SoldierLifelinkToken; + +/** + * + * @author TheElk801 + */ +public final class HuntedWitness extends CardImpl { + + public HuntedWitness(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Hunted Witness dies, create a 1/1 white Soldier creature token with lifelink. + this.addAbility(new DiesTriggeredAbility( + new CreateTokenEffect(new SoldierLifelinkToken()) + )); + } + + public HuntedWitness(final HuntedWitness card) { + super(card); + } + + @Override + public HuntedWitness copy() { + return new HuntedWitness(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IceCauldron.java b/Mage.Sets/src/mage/cards/i/IceCauldron.java index e0adbe1386c..bacaf44c115 100644 --- a/Mage.Sets/src/mage/cards/i/IceCauldron.java +++ b/Mage.Sets/src/mage/cards/i/IceCauldron.java @@ -265,7 +265,7 @@ class IceCauldronManaCondition implements Condition { public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { Card card = game.getCard(source.getSourceId()); - if (card != null && exiledCard != null && card.equals(exiledCard)) { + if (card != null && card.equals(exiledCard)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/i/InescapableBlaze.java b/Mage.Sets/src/mage/cards/i/InescapableBlaze.java new file mode 100644 index 00000000000..ddb5da25ab9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InescapableBlaze.java @@ -0,0 +1,36 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.abilities.common.CantBeCounteredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetAnyTarget; + +/** + * + * @author TheElk801 + */ +public final class InescapableBlaze extends CardImpl { + + public InescapableBlaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}{R}"); + + // This spell can't be countered. + this.addAbility(new CantBeCounteredAbility()); + + // Inescapable Flame deals 6 damage to any target. + this.getSpellAbility().addEffect(new DamageTargetEffect(6)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + } + + public InescapableBlaze(final InescapableBlaze card) { + super(card); + } + + @Override + public InescapableBlaze copy() { + return new InescapableBlaze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InspiringUnicorn.java b/Mage.Sets/src/mage/cards/i/InspiringUnicorn.java new file mode 100644 index 00000000000..dd1d9a9e569 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiringUnicorn.java @@ -0,0 +1,40 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +/** + * + * @author TheElk801 + */ +public final class InspiringUnicorn extends CardImpl { + + public InspiringUnicorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + + this.subtype.add(SubType.UNICORN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Inspiring Unicorn attacks, creatures you control get +1/+1 until end of turn. + this.addAbility(new AttacksTriggeredAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn), false + )); + } + + public InspiringUnicorn(final InspiringUnicorn card) { + super(card); + } + + @Override + public InspiringUnicorn copy() { + return new InspiringUnicorn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java b/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java new file mode 100644 index 00000000000..0948c19d2fd --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IntegrityIntervention.java @@ -0,0 +1,54 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SpellAbilityType; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class IntegrityIntervention extends SplitCard { + + public IntegrityIntervention(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R/W}", "{2}{R}{W}", SpellAbilityType.SPLIT); + + // Integrity + // Target creature gets +2/+2 until end of turn. + this.getLeftHalfCard().getSpellAbility().addEffect( + new BoostTargetEffect(2, 2, Duration.EndOfTurn) + ); + this.getLeftHalfCard().getSpellAbility().addTarget( + new TargetCreaturePermanent() + ); + + // Intervention + // Intervention deals 3 damage to any target and you gain 3 life. + this.getRightHalfCard().getSpellAbility().addEffect( + new DamageTargetEffect(3) + ); + this.getRightHalfCard().getSpellAbility().addEffect( + new GainLifeEffect(3).setText("and you gain 3 life") + ); + this.getRightHalfCard().getSpellAbility().addTarget( + new TargetAnyTarget() + ); + } + + public IntegrityIntervention(final IntegrityIntervention card) { + super(card); + } + + @Override + public IntegrityIntervention copy() { + return new IntegrityIntervention(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvertInvent.java b/Mage.Sets/src/mage/cards/i/InvertInvent.java new file mode 100644 index 00000000000..9c957b4b044 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvertInvent.java @@ -0,0 +1,135 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SwitchPowerToughnessTargetEffect; +import mage.cards.Card; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class InvertInvent extends SplitCard { + + public InvertInvent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U/R}", "{4}{U}{R}", SpellAbilityType.SPLIT); + + // Invert + // Switch the power and toughness of each of up to two target creatures until end of turn. + this.getLeftHalfCard().getSpellAbility().addEffect(new InvertEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + + // Invent + // Search your library for an instant card and/or a sorcery card, reveal them, put them into your hand, then shuffle your library. + this.getRightHalfCard().getSpellAbility().addEffect(new InventEffect()); + } + + public InvertInvent(final InvertInvent card) { + super(card); + } + + @Override + public InvertInvent copy() { + return new InvertInvent(this); + } +} + +class InvertEffect extends OneShotEffect { + + public InvertEffect() { + super(Outcome.Benefit); + this.staticText = "Switch the power and toughness of " + + "each of up to two target creatures until end of turn."; + } + + public InvertEffect(final InvertEffect effect) { + super(effect); + } + + @Override + public InvertEffect copy() { + return new InvertEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : source.getTargets().get(0).getTargets()) { + ContinuousEffect effect = new SwitchPowerToughnessTargetEffect(Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(targetId, game)); + game.addEffect(effect, source); + } + return true; + } +} + +class InventEffect extends OneShotEffect { + + private static final FilterCard filter1 = new FilterCard("instant card"); + private static final FilterCard filter2 = new FilterCard("sorcery card"); + + static { + filter1.add(new CardTypePredicate(CardType.INSTANT)); + filter2.add(new CardTypePredicate(CardType.SORCERY)); + } + + public InventEffect() { + super(Outcome.Benefit); + this.staticText = "Search your library for an instant card " + + "and/or a sorcery card, reveal them, " + + "put them into your hand, then shuffle your library."; + } + + public InventEffect(final InventEffect effect) { + super(effect); + } + + @Override + public InventEffect copy() { + return new InventEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + TargetCardInLibrary target = new TargetCardInLibrary(filter1); + if (player.searchLibrary(target, game, false)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + cards.add(card); + } + } + target = new TargetCardInLibrary(filter2); + if (player.searchLibrary(target, game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + cards.add(card); + } + } + player.revealCards(source, cards, game); + player.moveCards(cards, Zone.HAND, source, game); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JoinShields.java b/Mage.Sets/src/mage/cards/j/JoinShields.java new file mode 100644 index 00000000000..f2aac62ca92 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JoinShields.java @@ -0,0 +1,45 @@ +package mage.cards.j; + +import java.util.UUID; +import mage.abilities.effects.common.UntapAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class JoinShields extends CardImpl { + + public JoinShields(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}{W}"); + + // Untap all creatures you control. They gain hexproof and indestructible until end of turn. + this.getSpellAbility().addEffect(new UntapAllEffect( + StaticFilters.FILTER_CONTROLLED_CREATURES + )); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + ).setText("They gain hexproof")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + ).setText("and indestructible until end of turn")); + } + + public JoinShields(final JoinShields card) { + super(card); + } + + @Override + public JoinShields copy() { + return new JoinShields(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JusticeStrike.java b/Mage.Sets/src/mage/cards/j/JusticeStrike.java new file mode 100644 index 00000000000..db01871ddb1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JusticeStrike.java @@ -0,0 +1,62 @@ +package mage.cards.j; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class JusticeStrike extends CardImpl { + + public JusticeStrike(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{W}"); + + // Target creature deals damage to itself equal to its power. + this.getSpellAbility().addEffect(new JusticeStrikeEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public JusticeStrike(final JusticeStrike card) { + super(card); + } + + @Override + public JusticeStrike copy() { + return new JusticeStrike(this); + } +} + +class JusticeStrikeEffect extends OneShotEffect { + + public JusticeStrikeEffect() { + super(Outcome.Benefit); + this.staticText = "Target creature deals damage to itself equal to its power."; + } + + public JusticeStrikeEffect(final JusticeStrikeEffect effect) { + super(effect); + } + + @Override + public JusticeStrikeEffect copy() { + return new JusticeStrikeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + return permanent.damage(permanent.getPower().getValue(), permanent.getId(), game, false, true) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnightOfAutumn.java b/Mage.Sets/src/mage/cards/k/KnightOfAutumn.java new file mode 100644 index 00000000000..b8197f4fb85 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightOfAutumn.java @@ -0,0 +1,61 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class KnightOfAutumn extends CardImpl { + + public KnightOfAutumn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.subtype.add(SubType.DRYAD); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Knight of Autumn enters the battlefield, choose one — + // • Put two +1/+1 counters on Knight of Autumn. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersSourceEffect( + CounterType.P1P1.createInstance(2) + ), false + ); + + // • Destroy target artifact or enchantment. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent( + StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT + )); + ability.addMode(mode); + + // • You gain 4 life. + ability.addMode(new Mode(new GainLifeEffect(4))); + this.addAbility(ability); + } + + public KnightOfAutumn(final KnightOfAutumn card) { + super(card); + } + + @Override + public KnightOfAutumn copy() { + return new KnightOfAutumn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java b/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java index b5caaf86666..f2eb1cd069b 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java @@ -47,6 +47,7 @@ public final class KnightOfTheMists extends CardImpl { // When Knight of the Mists enters the battlefield, you may pay {U}. If you don't, destroy target Knight and it can't be regenerated. Ability ability = new EntersBattlefieldTriggeredAbility(new KnightOfTheMistsEffect()); ability.addTarget(new TargetCreaturePermanent(filter)); + addAbility(ability); } public KnightOfTheMists(final KnightOfTheMists card) { diff --git a/Mage.Sets/src/mage/cards/k/KraulForagers.java b/Mage.Sets/src/mage/cards/k/KraulForagers.java new file mode 100644 index 00000000000..ffb5e6200fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KraulForagers.java @@ -0,0 +1,42 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class KraulForagers extends CardImpl { + + public KraulForagers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.INSECT); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Undergrowth — When Kraul Foragers enters the battlefield, you gain 1 life for each creature card in your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new GainLifeEffect(new CardsInControllerGraveyardCount()), + false, "Undergrowth — " + )); + } + + public KraulForagers(final KraulForagers card) { + super(card); + } + + @Override + public KraulForagers copy() { + return new KraulForagers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KraulHarpooner.java b/Mage.Sets/src/mage/cards/k/KraulHarpooner.java new file mode 100644 index 00000000000..d3a2e8575f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KraulHarpooner.java @@ -0,0 +1,105 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.SubType; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class KraulHarpooner extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with flying you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public KraulHarpooner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.INSECT); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Undergrowth — When Kraul Harpooner enters the battlefield, choose up to one target creature with flying you don't control. Kraul Harpooner gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard, then you may have Kraul Harpooner fight that creature. + Ability ability = new EntersBattlefieldTriggeredAbility( + new KraulHarpoonerEffect(), false, + "Undergrowth — " + ); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + this.addAbility(ability); + } + + public KraulHarpooner(final KraulHarpooner card) { + super(card); + } + + @Override + public KraulHarpooner copy() { + return new KraulHarpooner(this); + } +} + +class KraulHarpoonerEffect extends OneShotEffect { + + public KraulHarpoonerEffect() { + super(Outcome.Benefit); + this.staticText = "choose up to one target creature with flying " + + "you don't control. {this} gets +X/+0 until end of turn, " + + "where X is the number of creature cards in your graveyard, " + + "then you may have {this} fight that creature."; + } + + public KraulHarpoonerEffect(final KraulHarpoonerEffect effect) { + super(effect); + } + + @Override + public KraulHarpoonerEffect copy() { + return new KraulHarpoonerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePerm = game.getPermanent(source.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + if (sourcePerm == null || player == null) { + return false; + } + int xValue = player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game); + game.addEffect(new BoostSourceEffect(xValue, 0, Duration.EndOfTurn), source); + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (creature == null || !player.chooseUse(outcome, "Have " + sourcePerm.getLogName() + " fight " + creature.getLogName() + "?", source, game)) { + return true; + } + return creature.fight(sourcePerm, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java b/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java index bbc39d2bad1..691561a52f1 100644 --- a/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java +++ b/Mage.Sets/src/mage/cards/l/LabyrinthGuardian.java @@ -74,7 +74,7 @@ class LabyrinthGuardianTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject eventSourceObject = game.getObject(event.getSourceId()); - if (eventSourceObject != null && event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { + if (event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } diff --git a/Mage.Sets/src/mage/cards/l/LavaCoil.java b/Mage.Sets/src/mage/cards/l/LavaCoil.java new file mode 100644 index 00000000000..218daefe6d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LavaCoil.java @@ -0,0 +1,34 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class LavaCoil extends CardImpl { + + public LavaCoil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Lava Coil deals 4 damage to target creature. If that creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public LavaCoil(final LavaCoil card) { + super(card); + } + + @Override + public LavaCoil copy() { + return new LavaCoil(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java b/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java new file mode 100644 index 00000000000..835106f467f --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java @@ -0,0 +1,160 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopyEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetAdjustment; +import mage.constants.TargetController; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.util.functions.ApplyToPermanent; + +/** + * + * @author TheElk801 + */ +public final class LazavTheMultifarious extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card in your graveyard with converted mana cost X"); + + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + public LazavTheMultifarious(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When Lazav, the Multifarious enters the battlefield, surveil 1. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SurveilEffect(1), false + )); + + // {X}: Lazav, the Multifarious becomes a copy of target creature card in your graveyard with converted mana cost X, except its name is Lazav, the Multifarious, it's legendary in addition to its other types, and it has this ability. + Ability ability = new SimpleActivatedAbility( + new LazavTheMultifariousEffect(), + new ManaCostsImpl("{X}") + ); + ability.addTarget(new TargetCardInGraveyard(filter)); + ability.setTargetAdjustment(TargetAdjustment.X_CMC_EQUAL_GY_CARD); + this.addAbility(ability); + } + + public LazavTheMultifarious(final LazavTheMultifarious card) { + super(card); + } + + @Override + public LazavTheMultifarious copy() { + return new LazavTheMultifarious(this); + } +} + +class LazavTheMultifariousEffect extends OneShotEffect { + + LazavTheMultifariousEffect() { + super(Outcome.Copy); + staticText = "{this} becomes a copy of target creature card " + + "in your graveyard with converted mana cost X, " + + "except its name is Lazav, the Multifarious, " + + "it's legendary in addition to its other types, " + + "and it has this ability"; + } + + LazavTheMultifariousEffect(final LazavTheMultifariousEffect effect) { + super(effect); + } + + @Override + public LazavTheMultifariousEffect copy() { + return new LazavTheMultifariousEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent lazavTheMultifarious = game.getPermanent(source.getSourceId()); + Permanent newBluePrint = null; + if (controller != null + && lazavTheMultifarious != null) { + Card copyFromCard = game.getCard(((FixedTarget) getTargetPointer()).getTarget()); + if (copyFromCard != null) { + newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game); + newBluePrint.assignNewId(); + ApplyToPermanent applier = new LazavTheMultifariousApplier(); + applier.apply(game, newBluePrint, source, lazavTheMultifarious.getId()); + CopyEffect copyEffect = new CopyEffect(Duration.Custom, newBluePrint, lazavTheMultifarious.getId()); + copyEffect.newId(); + copyEffect.setApplier(applier); + Ability newAbility = source.copy(); + copyEffect.init(newAbility, game); + game.addEffect(copyEffect, newAbility); + } + return true; + } + return false; + } +} + +class LazavTheMultifariousApplier extends ApplyToPermanent { + + private static final FilterCard filter = new FilterCreatureCard("creature card in your graveyard with converted mana cost X"); + + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + @Override + public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) { + Ability ability = new SimpleActivatedAbility( + new LazavTheMultifariousEffect(), + new ManaCostsImpl("{X}") + ); + ability.addTarget(new TargetCardInGraveyard(filter)); + ability.setTargetAdjustment(TargetAdjustment.X_CMC_EQUAL_GY_CARD); + permanent.getAbilities().add(ability); + permanent.setName("Lazav, the Multifarious"); + permanent.addSuperType(SuperType.LEGENDARY); + return true; + } + + @Override + public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) { + Ability ability = new SimpleActivatedAbility( + new LazavTheMultifariousEffect(), + new ManaCostsImpl("{X}") + ); + ability.addTarget(new TargetCardInGraveyard(filter)); + ability.setTargetAdjustment(TargetAdjustment.X_CMC_EQUAL_GY_CARD); + mageObject.getAbilities().add(ability); + mageObject.setName("Lazav, the Multifarious"); + mageObject.addSuperType(SuperType.LEGENDARY); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeagueGuildmage.java b/Mage.Sets/src/mage/cards/l/LeagueGuildmage.java new file mode 100644 index 00000000000..3ff66776aac --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LeagueGuildmage.java @@ -0,0 +1,67 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.FilterSpell; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.TargetSpell; + +/** + * + * @author TheElk801 + */ +public final class LeagueGuildmage extends CardImpl { + + private static final FilterSpell filter = new FilterInstantOrSorcerySpell("instant or sorcery you control with converted mana cost X"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public LeagueGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {3}{U}, {T}: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), + new ManaCostsImpl("{3}{U}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {X}{R}, {T}: Copy target instant or sorcery spell you control with converted mana cost X. You may choose new targets for the copy. + ability = new SimpleActivatedAbility( + new CopyTargetSpellEffect(), + new ManaCostsImpl("{X}{R}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public LeagueGuildmage(final LeagueGuildmage card) { + super(card); + } + + @Override + public LeagueGuildmage copy() { + return new LeagueGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LedevChampion.java b/Mage.Sets/src/mage/cards/l/LedevChampion.java new file mode 100644 index 00000000000..8c5d59ecaed --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LedevChampion.java @@ -0,0 +1,109 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.token.SoldierLifelinkToken; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class LedevChampion extends CardImpl { + + public LedevChampion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Ledev Champion attacks, you may tap any number of untapped creatures you control. Ledev Champion gets +1/+1 until end of turn for each creature tapped this way. + this.addAbility(new AttacksTriggeredAbility( + new LedevChampionEffect(), false + )); + + // {3}{G}{W}: Create a 1/1 white soldier creature token with lifelink. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new CreateTokenEffect(new SoldierLifelinkToken()), + new ManaCostsImpl("{3}{G}{W}") + )); + } + + public LedevChampion(final LedevChampion card) { + super(card); + } + + @Override + public LedevChampion copy() { + return new LedevChampion(this); + } +} + +class LedevChampionEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creatures you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(Predicates.not(new TappedPredicate())); + } + + public LedevChampionEffect() { + super(Outcome.GainLife); + staticText = "you may tap any number of untapped creatures you control. " + + "{this} gets +1/+1 until end of turn for each creature tapped this way."; + } + + public LedevChampionEffect(LedevChampionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + int tappedAmount = 0; + TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + if (target.canChoose(source.getControllerId(), game) + && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { + for (UUID creature : target.getTargets()) { + if (creature != null) { + game.getPermanent(creature).tap(game); + tappedAmount++; + } + } + } + if (tappedAmount > 0) { + game.addEffect(new BoostSourceEffect(tappedAmount, tappedAmount, Duration.EndOfTurn), source); + return true; + } + return false; + } + + @Override + public LedevChampionEffect copy() { + return new LedevChampionEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/l/LedevGuardian.java b/Mage.Sets/src/mage/cards/l/LedevGuardian.java new file mode 100644 index 00000000000..b5624e13f1d --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LedevGuardian.java @@ -0,0 +1,37 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class LedevGuardian extends CardImpl { + + public LedevGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Convoke + this.addAbility(new ConvokeAbility()); + } + + public LedevGuardian(final LedevGuardian card) { + super(card); + } + + @Override + public LedevGuardian copy() { + return new LedevGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LegionGuildmage.java b/Mage.Sets/src/mage/cards/l/LegionGuildmage.java new file mode 100644 index 00000000000..f0ef4685372 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LegionGuildmage.java @@ -0,0 +1,67 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class LegionGuildmage extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("another creature"); + + static { + filter.add(new AnotherPredicate()); + } + + public LegionGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {5}{R}, {T}: Legion Guildmage deals 3 damage to each opponent. + Ability ability = new SimpleActivatedAbility( + new DamagePlayersEffect(3, TargetController.OPPONENT), + new ManaCostsImpl("{5}{R}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {2}{W}, {T}: Tap another target creature. + ability = new SimpleActivatedAbility( + new TapTargetEffect("another target creature"), + new ManaCostsImpl("{2}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public LegionGuildmage(final LegionGuildmage card) { + super(card); + } + + @Override + public LegionGuildmage copy() { + return new LegionGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LightOfTheLegion.java b/Mage.Sets/src/mage/cards/l/LightOfTheLegion.java new file mode 100644 index 00000000000..c9581e39495 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightOfTheLegion.java @@ -0,0 +1,58 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.MentorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author TheElk801 + */ +public final class LightOfTheLegion extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("white creature you control"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public LightOfTheLegion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Mentor + this.addAbility(new MentorAbility()); + + // When Light of the Legion dies, put a +1/+1 counter on each white creature you control. + this.addAbility(new DiesTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), filter + ))); + } + + public LightOfTheLegion(final LightOfTheLegion card) { + super(card); + } + + @Override + public LightOfTheLegion copy() { + return new LightOfTheLegion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LotlethGiant.java b/Mage.Sets/src/mage/cards/l/LotlethGiant.java new file mode 100644 index 00000000000..f87c98c1f1d --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LotlethGiant.java @@ -0,0 +1,48 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 + */ +public final class LotlethGiant extends CardImpl { + + public LotlethGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.GIANT); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Undergrowth — When Lotleth Giant enters the battlefield, it deals 1 damage to target opponent for each creature card in your graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(new CardsInControllerGraveyardCount( + StaticFilters.FILTER_CARD_CREATURE + ), "it"), false, "Undergrowth — " + ); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public LotlethGiant(final LotlethGiant card) { + super(card); + } + + @Override + public LotlethGiant copy() { + return new LotlethGiant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LoxodonRestorer.java b/Mage.Sets/src/mage/cards/l/LoxodonRestorer.java new file mode 100644 index 00000000000..32476ca1a8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoxodonRestorer.java @@ -0,0 +1,44 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.constants.SubType; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class LoxodonRestorer extends CardImpl { + + public LoxodonRestorer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // When Loxodon Restorer enters the battlefield, you gain 4 life. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new GainLifeEffect(4), false + )); + } + + public LoxodonRestorer(final LoxodonRestorer card) { + super(card); + } + + @Override + public LoxodonRestorer copy() { + return new LoxodonRestorer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SecretsOfTheMausoleum.java b/Mage.Sets/src/mage/cards/m/MausoleumSecrets.java similarity index 75% rename from Mage.Sets/src/mage/cards/s/SecretsOfTheMausoleum.java rename to Mage.Sets/src/mage/cards/m/MausoleumSecrets.java index fe8f5c1ee78..ba1d00f6096 100644 --- a/Mage.Sets/src/mage/cards/s/SecretsOfTheMausoleum.java +++ b/Mage.Sets/src/mage/cards/m/MausoleumSecrets.java @@ -1,4 +1,4 @@ -package mage.cards.s; +package mage.cards.m; import java.util.UUID; import mage.ObjectColor; @@ -22,28 +22,28 @@ import mage.target.common.TargetCardInLibrary; * * @author TheElk801 */ -public final class SecretsOfTheMausoleum extends CardImpl { +public final class MausoleumSecrets extends CardImpl { - public SecretsOfTheMausoleum(UUID ownerId, CardSetInfo setInfo) { + public MausoleumSecrets(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Undergrowth — Search your library for a black card with converted mana cost equal to or less than the number of creature cards in your graveyard, reveal it, put it into your hand, then shuffle your library. - this.getSpellAbility().addEffect(new SecretsOfTheMausoleumEffect()); + this.getSpellAbility().addEffect(new MausoleumSecretsEffect()); } - public SecretsOfTheMausoleum(final SecretsOfTheMausoleum card) { + public MausoleumSecrets(final MausoleumSecrets card) { super(card); } @Override - public SecretsOfTheMausoleum copy() { - return new SecretsOfTheMausoleum(this); + public MausoleumSecrets copy() { + return new MausoleumSecrets(this); } } -class SecretsOfTheMausoleumEffect extends OneShotEffect { +class MausoleumSecretsEffect extends OneShotEffect { - public SecretsOfTheMausoleumEffect() { + public MausoleumSecretsEffect() { super(Outcome.Benefit); this.staticText = "Undergrowth — Search your library " + "for a black card with converted mana cost less than " @@ -51,13 +51,13 @@ class SecretsOfTheMausoleumEffect extends OneShotEffect { + "reveal it, put it into your hand, then shuffle your library."; } - public SecretsOfTheMausoleumEffect(final SecretsOfTheMausoleumEffect effect) { + public MausoleumSecretsEffect(final MausoleumSecretsEffect effect) { super(effect); } @Override - public SecretsOfTheMausoleumEffect copy() { - return new SecretsOfTheMausoleumEffect(this); + public MausoleumSecretsEffect copy() { + return new MausoleumSecretsEffect(this); } @Override diff --git a/Mage.Sets/src/mage/cards/m/MaximizeAltitude.java b/Mage.Sets/src/mage/cards/m/MaximizeAltitude.java new file mode 100644 index 00000000000..308b860ad55 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaximizeAltitude.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.JumpStartAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class MaximizeAltitude extends CardImpl { + + public MaximizeAltitude(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); + + // Target creature gets +1/+1 and flying until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 1, Duration.EndOfTurn + ).setText("Target creature gets +1/+1")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Jump-start + this.addAbility(new JumpStartAbility(this)); + + } + + public MaximizeAltitude(final MaximizeAltitude card) { + super(card); + } + + @Override + public MaximizeAltitude copy() { + return new MaximizeAltitude(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaximizeVelocity.java b/Mage.Sets/src/mage/cards/m/MaximizeVelocity.java new file mode 100644 index 00000000000..7b512ae24ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaximizeVelocity.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.JumpStartAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class MaximizeVelocity extends CardImpl { + + public MaximizeVelocity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Target creature gets +1/+1 and gains haste until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 1, Duration.EndOfTurn + ).setText("Target creature gets +1/+1")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Jump-start + this.addAbility(new JumpStartAbility(this)); + + } + + public MaximizeVelocity(final MaximizeVelocity card) { + super(card); + } + + @Override + public MaximizeVelocity copy() { + return new MaximizeVelocity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeletisCharlatan.java b/Mage.Sets/src/mage/cards/m/MeletisCharlatan.java index 32170f2ac65..d88bb2b928c 100644 --- a/Mage.Sets/src/mage/cards/m/MeletisCharlatan.java +++ b/Mage.Sets/src/mage/cards/m/MeletisCharlatan.java @@ -71,7 +71,7 @@ class MeletisCharlatanCopyTargetSpellEffect extends OneShotEffect { if (spell != null) { StackObject newStackObject = spell.createCopyOnStack(game, source, spell.getControllerId(), true); Player player = game.getPlayer(spell.getControllerId()); - if (player != null && newStackObject != null && newStackObject instanceof Spell) { + if (player != null && newStackObject instanceof Spell) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6); diff --git a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java index 562ca786fa3..0b77db95408 100644 --- a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java +++ b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java @@ -91,7 +91,7 @@ class MetzaliTowerOfTriumphEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { + if (watcher instanceof AttackedThisTurnWatcher) { Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); List available = new ArrayList<>(); for (MageObjectReference mor : attackedThisTurn) { diff --git a/Mage.Sets/src/mage/cards/m/MidnightReaper.java b/Mage.Sets/src/mage/cards/m/MidnightReaper.java new file mode 100644 index 00000000000..5af4535203d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MidnightReaper.java @@ -0,0 +1,60 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; + +/** + * + * @author TheElk801 + */ +public final class MidnightReaper extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("nontoken creature you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(Predicates.not(new TokenPredicate())); + } + + public MidnightReaper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever a nontoken creature you control dies, Midnight Reaper deals 1 damage to you and you draw a card. + Ability ability = new DiesCreatureTriggeredAbility( + new DamageControllerEffect(1), false, filter + ); + ability.addEffect( + new DrawCardSourceControllerEffect(1) + .setText("and you draw a card") + ); + this.addAbility(ability); + } + + public MidnightReaper(final MidnightReaper card) { + super(card); + } + + @Override + public MidnightReaper copy() { + return new MidnightReaper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MirrorGolem.java b/Mage.Sets/src/mage/cards/m/MirrorGolem.java index 96aa5fb00e7..c5e918fd2ff 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorGolem.java +++ b/Mage.Sets/src/mage/cards/m/MirrorGolem.java @@ -9,11 +9,10 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.ProtectionAbility; import mage.cards.Card; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.ExileZone; import mage.game.Game; @@ -30,7 +29,7 @@ public final class MirrorGolem extends CardImpl { public MirrorGolem(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); - + this.subtype.add(SubType.GOLEM); this.power = new MageInt(3); this.toughness = new MageInt(4); @@ -109,18 +108,18 @@ class MirrorGolemEffect extends ContinuousEffectImpl { return false; } - for (UUID imprinted : sourceObject.getImprinted()){ - if (imprinted != null && exileZone.contains(imprinted)){ + for (UUID imprinted : sourceObject.getImprinted()) { + if (imprinted != null && exileZone.contains(imprinted)) { Card card = game.getCard(imprinted); if (card != null) { - for (CardType cardType : card.getCardType()){ + for (CardType cardType : card.getCardType()) { FilterCard filterCard; - if (cardType.equals(CardType.SORCERY)){ + if (cardType.equals(CardType.SORCERY)) { filterCard = new FilterCard("sorceries"); - } else if (cardType.equals(CardType.TRIBAL)){ + } else if (cardType.equals(CardType.TRIBAL)) { filterCard = new FilterCard("tribal"); } else { - filterCard = new FilterCard(cardType.toString()+"s"); + filterCard = new FilterCard(cardType.toString() + "s"); } filterCard.add(new CardTypePredicate(cardType)); sourceObject.addAbility(new ProtectionAbility(filterCard)); @@ -135,4 +134,4 @@ class MirrorGolemEffect extends ContinuousEffectImpl { public MirrorGolemEffect copy() { return new MirrorGolemEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MissionBriefing.java b/Mage.Sets/src/mage/cards/m/MissionBriefing.java new file mode 100644 index 00000000000..128cecbc494 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MissionBriefing.java @@ -0,0 +1,165 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class MissionBriefing extends CardImpl { + + public MissionBriefing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); + + // Surveil 2, then choose an instant or sorcery card in your graveyard. You may cast that card this turn. If that card would be put into your graveyard this turn, exile it instead. + this.getSpellAbility().addEffect(new MissionBriefingEffect()); + } + + public MissionBriefing(final MissionBriefing card) { + super(card); + } + + @Override + public MissionBriefing copy() { + return new MissionBriefing(this); + } +} + +class MissionBriefingEffect extends OneShotEffect { + + public static final FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); + + public MissionBriefingEffect() { + super(Outcome.Benefit); + this.staticText = "Surveil 2, then choose an instant or sorcery card " + + "in your graveyard. You may cast that card this turn. " + + "If that card would be put into your graveyard this turn, " + + "exile it instead."; + } + + public MissionBriefingEffect(final MissionBriefingEffect effect) { + super(effect); + } + + @Override + public MissionBriefingEffect copy() { + return new MissionBriefingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.surveil(2, source, game); + Target target = new TargetCardInYourGraveyard(filter); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + ContinuousEffect effect = new MissionBriefingCastFromGraveyardEffect(); + effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); + game.addEffect(effect, source); + effect = new MissionBriefingReplacementEffect(card.getId()); + game.addEffect(effect, source); + return true; + } + return false; + } +} + +class MissionBriefingCastFromGraveyardEffect extends AsThoughEffectImpl { + + public MissionBriefingCastFromGraveyardEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + } + + public MissionBriefingCastFromGraveyardEffect(final MissionBriefingCastFromGraveyardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public MissionBriefingCastFromGraveyardEffect copy() { + return new MissionBriefingCastFromGraveyardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return objectId.equals(this.getTargetPointer().getFirst(game, source)) + && affectedControllerId.equals(source.getControllerId()); + } +} + +class MissionBriefingReplacementEffect extends ReplacementEffectImpl { + + private final UUID cardId; + + public MissionBriefingReplacementEffect(UUID cardId) { + super(Duration.EndOfTurn, Outcome.Exile); + this.cardId = cardId; + staticText = "If that card would be put into your graveyard this turn, " + + "exile it instead"; + } + + public MissionBriefingReplacementEffect(final MissionBriefingReplacementEffect effect) { + super(effect); + this.cardId = effect.cardId; + } + + @Override + public MissionBriefingReplacementEffect copy() { + return new MissionBriefingReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = game.getCard(this.cardId); + if (controller != null && card != null) { + controller.moveCardsToExile(card, source, game, true, null, ""); + return true; + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD + && zEvent.getTargetId().equals(this.cardId); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Molderhulk.java b/Mage.Sets/src/mage/cards/m/Molderhulk.java new file mode 100644 index 00000000000..9f65632312c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Molderhulk.java @@ -0,0 +1,59 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class Molderhulk extends CardImpl { + + private static final FilterCard filter + = new FilterLandCard("land card from your graveyard"); + + public Molderhulk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{B}{G}"); + + this.subtype.add(SubType.FUNGUS); + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Undergrowth — This spell costs {1} less to cast for each creature card in your graveyard. + Ability ability = new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_CREATURE)); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); + this.addAbility(ability); + + // When Molderhulk enters the battlefield, return target land card from your graveyard to the battlefield. + ability = new EntersBattlefieldTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), false + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + public Molderhulk(final Molderhulk card) { + super(card); + } + + @Override + public Molderhulk copy() { + return new Molderhulk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MuseDrake.java b/Mage.Sets/src/mage/cards/m/MuseDrake.java new file mode 100644 index 00000000000..fda50bc5a94 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MuseDrake.java @@ -0,0 +1,43 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class MuseDrake extends CardImpl { + + public MuseDrake(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.DRAKE); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Muse Drake enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1) + )); + } + + public MuseDrake(final MuseDrake card) { + super(card); + } + + @Override + public MuseDrake copy() { + return new MuseDrake(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NeverHappened.java b/Mage.Sets/src/mage/cards/n/NeverHappened.java new file mode 100644 index 00000000000..0350e967f46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NeverHappened.java @@ -0,0 +1,87 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 + */ +public final class NeverHappened extends CardImpl { + + public NeverHappened(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Target opponent reveals their hand. You choose a nonland card from that player's graveyard or hand and exile it. + this.getSpellAbility().addEffect(new NeverHappenedEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public NeverHappened(final NeverHappened card) { + super(card); + } + + @Override + public NeverHappened copy() { + return new NeverHappened(this); + } +} + +class NeverHappenedEffect extends OneShotEffect { + + public NeverHappenedEffect() { + super(Outcome.Benefit); + this.staticText = "Target opponent reveals their hand. " + + "You choose a nonland card from that player's graveyard " + + "or hand and exile it."; + } + + public NeverHappenedEffect(final NeverHappenedEffect effect) { + super(effect); + } + + @Override + public NeverHappenedEffect copy() { + return new NeverHappenedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; + } + opponent.revealCards(source, opponent.getHand(), game); + Target target; + if (controller.chooseUse(outcome, "Exile a card from hand or graveyard?", null, "Hand", "Graveyard", source, game)) { + FilterCard filter = new FilterNonlandCard("nonland card in " + opponent.getName() + "'s hand"); + filter.add(new OwnerIdPredicate(opponent.getId())); + target = new TargetCardInHand(filter); + target.setNotTarget(true); + } else { + FilterCard filter = new FilterNonlandCard("nonland card in " + opponent.getName() + "'s graveyard"); + filter.add(new OwnerIdPredicate(opponent.getId())); + target = new TargetCardInGraveyard(filter); + target.setNotTarget(true); + } + if (controller.choose(outcome, target, source.getSourceId(), game)) { + controller.moveCardsToExile(game.getCard(target.getFirstTarget()), source, game, false, null, null); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NightveilPredator.java b/Mage.Sets/src/mage/cards/n/NightveilPredator.java new file mode 100644 index 00000000000..acdb6dd8cb1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NightveilPredator.java @@ -0,0 +1,44 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class NightveilPredator extends CardImpl { + + public NightveilPredator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}{B}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Hexproof + this.addAbility(HexproofAbility.getInstance()); + } + + public NightveilPredator(final NightveilPredator card) { + super(card); + } + + @Override + public NightveilPredator copy() { + return new NightveilPredator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NightveilFaerie.java b/Mage.Sets/src/mage/cards/n/NightveilSprite.java similarity index 77% rename from Mage.Sets/src/mage/cards/n/NightveilFaerie.java rename to Mage.Sets/src/mage/cards/n/NightveilSprite.java index 46f197cbc52..6495bfe954b 100644 --- a/Mage.Sets/src/mage/cards/n/NightveilFaerie.java +++ b/Mage.Sets/src/mage/cards/n/NightveilSprite.java @@ -14,9 +14,9 @@ import mage.constants.CardType; * * @author TheElk801 */ -public final class NightveilFaerie extends CardImpl { +public final class NightveilSprite extends CardImpl { - public NightveilFaerie(UUID ownerId, CardSetInfo setInfo) { + public NightveilSprite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.FAERIE); @@ -31,12 +31,12 @@ public final class NightveilFaerie extends CardImpl { this.addAbility(new AttacksTriggeredAbility(new SurveilEffect(1), false)); } - public NightveilFaerie(final NightveilFaerie card) { + public NightveilSprite(final NightveilSprite card) { super(card); } @Override - public NightveilFaerie copy() { - return new NightveilFaerie(this); + public NightveilSprite copy() { + return new NightveilSprite(this); } } diff --git a/Mage.Sets/src/mage/cards/r/RainOfNotions.java b/Mage.Sets/src/mage/cards/n/NotionRain.java similarity index 77% rename from Mage.Sets/src/mage/cards/r/RainOfNotions.java rename to Mage.Sets/src/mage/cards/n/NotionRain.java index 14df944e0e5..171706396c1 100644 --- a/Mage.Sets/src/mage/cards/r/RainOfNotions.java +++ b/Mage.Sets/src/mage/cards/n/NotionRain.java @@ -1,4 +1,4 @@ -package mage.cards.r; +package mage.cards.n; import java.util.UUID; import mage.abilities.effects.common.DamageControllerEffect; @@ -12,9 +12,9 @@ import mage.constants.CardType; * * @author TheElk801 */ -public final class RainOfNotions extends CardImpl { +public final class NotionRain extends CardImpl { - public RainOfNotions(UUID ownerId, CardSetInfo setInfo) { + public NotionRain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{B}"); // Surveil 2, then draw two cards. Rain of Notions deals 2 damage to you. @@ -28,12 +28,12 @@ public final class RainOfNotions extends CardImpl { this.getSpellAbility().addEffect(new DamageControllerEffect(2)); } - public RainOfNotions(final RainOfNotions card) { + public NotionRain(final NotionRain card) { super(card); } @Override - public RainOfNotions copy() { - return new RainOfNotions(this); + public NotionRain copy() { + return new NotionRain(this); } } diff --git a/Mage.Sets/src/mage/cards/o/OchranAssassin.java b/Mage.Sets/src/mage/cards/o/OchranAssassin.java new file mode 100644 index 00000000000..8e97cb80265 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OchranAssassin.java @@ -0,0 +1,45 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.MustBeBlockedByAllSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class OchranAssassin extends CardImpl { + + public OchranAssassin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // All creatures able to block Ochran Assassin do so. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, new MustBeBlockedByAllSourceEffect() + )); + } + + public OchranAssassin(final OchranAssassin card) { + super(card); + } + + @Override + public OchranAssassin copy() { + return new OchranAssassin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OmnispellAdept.java b/Mage.Sets/src/mage/cards/o/OmnispellAdept.java new file mode 100644 index 00000000000..d9c700d5314 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OmnispellAdept.java @@ -0,0 +1,101 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInHand; + +/** + * + * @author TheElk801 + */ +public final class OmnispellAdept extends CardImpl { + + public OmnispellAdept(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // {2}{U}, {T}: You may cast an instant or sorcery card from your hand without paying its mana cost. + Ability ability = new SimpleActivatedAbility( + new OmnispellAdeptEffect(), new ManaCostsImpl("{2}{U}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public OmnispellAdept(final OmnispellAdept card) { + super(card); + } + + @Override + public OmnispellAdept copy() { + return new OmnispellAdept(this); + } +} + +class OmnispellAdeptEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card from your hand"); + + public OmnispellAdeptEffect() { + super(Outcome.PlayForFree); + this.staticText = "you may cast an instant or sorcery card from your hand without paying its mana cost"; + } + + public OmnispellAdeptEffect(final OmnispellAdeptEffect effect) { + super(effect); + } + + @Override + public OmnispellAdeptEffect copy() { + return new OmnispellAdeptEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Target target = new TargetCardInHand(filter); + if (target.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Cast an instant or sorcery card from your hand without paying its mana cost?", source, game)) { + Card cardToCast = null; + boolean cancel = false; + while (controller.canRespond() && !cancel) { + if (controller.chooseTarget(outcome, target, source, game)) { + cardToCast = game.getCard(target.getFirstTarget()); + if (cardToCast != null && cardToCast.getSpellAbility().canChooseTarget(game)) { + cancel = true; + } + } else { + cancel = true; + } + } + if (cardToCast != null) { + controller.cast(cardToCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PacksFavor.java b/Mage.Sets/src/mage/cards/p/PacksFavor.java new file mode 100644 index 00000000000..8fe4c69a04e --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PacksFavor.java @@ -0,0 +1,39 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class PacksFavor extends CardImpl { + + public PacksFavor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // Target creature gets +3/+3 until end of turn. + this.getSpellAbility().addEffect( + new BoostTargetEffect(3, 3, Duration.EndOfTurn) + ); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public PacksFavor(final PacksFavor card) { + super(card); + } + + @Override + public PacksFavor copy() { + return new PacksFavor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ParhelionPatrol.java b/Mage.Sets/src/mage/cards/p/ParhelionPatrol.java new file mode 100644 index 00000000000..8116644418b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParhelionPatrol.java @@ -0,0 +1,45 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.MentorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class ParhelionPatrol extends CardImpl { + + public ParhelionPatrol(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Mentor + this.addAbility(new MentorAbility()); + } + + public ParhelionPatrol(final ParhelionPatrol card) { + super(card); + } + + @Override + public ParhelionPatrol copy() { + return new ParhelionPatrol(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PasswallAdept.java b/Mage.Sets/src/mage/cards/p/PasswallAdept.java new file mode 100644 index 00000000000..ceb38fad51e --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PasswallAdept.java @@ -0,0 +1,48 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class PasswallAdept extends CardImpl { + + public PasswallAdept(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {2}{U}: Target creature can't be blocked this turn. + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new CantBeBlockedTargetEffect(), + new ManaCostsImpl("{2}{U}") + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public PasswallAdept(final PasswallAdept card) { + super(card); + } + + @Override + public PasswallAdept copy() { + return new PasswallAdept(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PauseForReflection.java b/Mage.Sets/src/mage/cards/p/PauseForReflection.java new file mode 100644 index 00000000000..cb347f93ed9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PauseForReflection.java @@ -0,0 +1,35 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +/** + * + * @author TheElk801 + */ +public final class PauseForReflection extends CardImpl { + + public PauseForReflection(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // Precent all combat damage that would be dealt this turn. + this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); + } + + public PauseForReflection(final PauseForReflection card) { + super(card); + } + + @Override + public PauseForReflection copy() { + return new PauseForReflection(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java b/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java index 0ef7b2de1c2..7c10dd12713 100644 --- a/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java +++ b/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java @@ -70,7 +70,7 @@ class PawnOfUlamogTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { UUID targetId = event.getTargetId(); MageObject card = game.getLastKnownInformation(targetId, Zone.BATTLEFIELD); - if (card != null && card instanceof Permanent && !(card instanceof PermanentToken)) { + if (card instanceof Permanent && !(card instanceof PermanentToken)) { Permanent permanent = (Permanent) card; ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java index 545e7787114..eb4d598ecf0 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java @@ -99,7 +99,7 @@ class PhyrexianProcessorCreateTokenEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { String key = CardUtil.getCardZoneString("lifePaid", source.getSourceId(), game); Object object = game.getState().getValue(key); - if(object != null && object instanceof Integer) { + if(object instanceof Integer) { int lifePaid = (int) object; MinionToken token = new MinionToken(); token.getPower().modifyBaseValue(lifePaid); diff --git a/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java b/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java new file mode 100644 index 00000000000..2aa04190912 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java @@ -0,0 +1,85 @@ +package mage.cards.p; + +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author TheElk801 + */ +public final class PistonFistCyclops extends CardImpl { + + public PistonFistCyclops(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U/R}{U/R}"); + + this.subtype.add(SubType.CYCLOPS); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // As long as you've cast an instant or sorcery spell this turn, Piston-Fist Cyclops can attack as though it didn't have defender. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new CanAttackAsThoughItDidntHaveDefenderSourceEffect( + Duration.WhileOnBattlefield + ), PistonFistCyclopsCondition.instance, + "As long as you've cast an instant or sorcery spell this turn, " + + "{this} can attack as though it didn't have defender." + ) + ), new SpellsCastWatcher()); + } + + public PistonFistCyclops(final PistonFistCyclops card) { + super(card); + } + + @Override + public PistonFistCyclops copy() { + return new PistonFistCyclops(this); + } +} + +enum PistonFistCyclopsCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + SpellsCastWatcher watcher + = (SpellsCastWatcher) game.getState().getWatchers().get( + SpellsCastWatcher.class.getSimpleName() + ); + if (watcher == null) { + return false; + } + List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); + if (spells == null) { + return false; + } + for (Spell spell : spells) { + if (!spell.getSourceId().equals(source.getSourceId()) + && spell.isInstantOrSorcery()) { + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PitilessGorgon.java b/Mage.Sets/src/mage/cards/p/PitilessGorgon.java new file mode 100644 index 00000000000..62a499ddd62 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PitilessGorgon.java @@ -0,0 +1,36 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class PitilessGorgon extends CardImpl { + + public PitilessGorgon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B/G}{B/G}"); + + this.subtype.add(SubType.GORGON); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + public PitilessGorgon(final PitilessGorgon card) { + super(card); + } + + @Override + public PitilessGorgon copy() { + return new PitilessGorgon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/Preordain.java b/Mage.Sets/src/mage/cards/p/Preordain.java index 519fd4a4f48..4eae38cd40d 100644 --- a/Mage.Sets/src/mage/cards/p/Preordain.java +++ b/Mage.Sets/src/mage/cards/p/Preordain.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -18,8 +17,17 @@ public final class Preordain extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Scry 2, then draw a card. (To scry 2, look at the top two cards of your library, then put any number of them on the bottom of your library and the rest on top in any order.) - this.getSpellAbility().addEffect(new ScryEffect(2)); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect( + new ScryEffect(2).setText("Scry 2, ") + ); + this.getSpellAbility().addEffect( + new DrawCardSourceControllerEffect(1) + .setText("then draw a card. (To scry 2, " + + "look at the top two cards of your library, " + + "then put any number of them on the " + + "bottom of your library and the rest on " + + "top in any order.)") + ); } public Preordain(final Preordain card) { diff --git a/Mage.Sets/src/mage/cards/p/PriceOfFame.java b/Mage.Sets/src/mage/cards/p/PriceOfFame.java new file mode 100644 index 00000000000..1ea93d7af95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PriceOfFame.java @@ -0,0 +1,75 @@ +package mage.cards.p; + +import java.util.Iterator; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class PriceOfFame extends CardImpl { + + public PriceOfFame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); + + // This spell costs {2} less to cast if it targets a legendary creature. + this.addAbility(new SimpleStaticAbility(Zone.STACK, + new SpellCostReductionSourceEffect(2, PriceOfFameCondition.instance)) + .setRuleAtTheTop(true)); + + // Destroy target creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Surveil 2. + this.getSpellAbility().addEffect(new SurveilEffect(2)); + } + + public PriceOfFame(final PriceOfFame card) { + super(card); + } + + @Override + public PriceOfFame copy() { + return new PriceOfFame(this); + } +} + +enum PriceOfFameCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); + if (sourceSpell != null) { + Iterator targets = sourceSpell.getStackAbility().getTargets().iterator(); + while (targets.hasNext()) { + Permanent permanent = game.getPermanentOrLKIBattlefield(targets.next().getFirstTarget()); + if (permanent != null && permanent.isCreature() && permanent.isLegendary()) { + return true; + } + } + } + return false; + } + + @Override + public String toString() { + return "it targets a legendary creature"; + } + +} diff --git a/Mage.Sets/src/mage/cards/p/PrimordialMist.java b/Mage.Sets/src/mage/cards/p/PrimordialMist.java index ee917e9486e..364db608db3 100644 --- a/Mage.Sets/src/mage/cards/p/PrimordialMist.java +++ b/Mage.Sets/src/mage/cards/p/PrimordialMist.java @@ -121,7 +121,7 @@ class PrimordialMistCastFromExileEffect extends AsThoughEffectImpl { public PrimordialMistCastFromExileEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "Exile a face-down permanent you control face-up. You may play the card from exile"; + staticText = "Exile a face-down permanent you control face up: You may play that card this turn."; } public PrimordialMistCastFromExileEffect(final PrimordialMistCastFromExileEffect effect) { diff --git a/Mage.Sets/src/mage/cards/p/PsychicRebuttal.java b/Mage.Sets/src/mage/cards/p/PsychicRebuttal.java index 78ed585a423..1e85aba50da 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicRebuttal.java +++ b/Mage.Sets/src/mage/cards/p/PsychicRebuttal.java @@ -85,7 +85,7 @@ class PsychicRebuttalEffect extends OneShotEffect { && controller.chooseUse(Outcome.PlayForFree, "Copy " + spell.getName() + " (you may choose new targets for the copy)?", source, game)) { StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true); - if (newStackObject != null && newStackObject instanceof Spell) { + if (newStackObject instanceof Spell) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6); diff --git a/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java b/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java index 8c6055dc4bb..6c6c1c9b4cd 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersGauntlet.java @@ -62,7 +62,7 @@ class PyromancersGauntletReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object instanceof Spell) { + if (object instanceof Spell) { if (((Spell) object).isControlledBy(source.getControllerId()) && (object.isInstant() || object.isSorcery())){ diff --git a/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java b/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java index 99bc8263508..9c7e5e2455e 100644 --- a/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java +++ b/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java @@ -73,7 +73,7 @@ class PyxisOfPandemoniumExileEffect extends OneShotEffect { Map exileIds; String valueKey = CardUtil.getObjectZoneString("exileIds", sourceObject, game); Object object = game.getState().getValue(valueKey); - if (object != null && object instanceof Map) { + if (object instanceof Map) { exileIds = (Map) object; } else { exileIds = new HashMap<>(); @@ -123,7 +123,7 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { Map exileIds; String valueKey = CardUtil.getObjectZoneString("exileIds", sourceObject, game); Object object = game.getState().getValue(valueKey); - if (object != null && object instanceof Map) { + if (object instanceof Map) { exileIds = (Map) object; } else { return true; diff --git a/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java b/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java index 45f603a1b59..556963a5905 100644 --- a/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java +++ b/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java @@ -4,9 +4,8 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; -import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.InstantSorceryExileGraveyardCount; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; @@ -17,9 +16,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; import mage.game.command.emblems.RalIzzetViceroyEmblem; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -44,13 +41,11 @@ public final class RalIzzetViceroy extends CardImpl { )); // -3: Ral, Izzet Viceroy deals damage to target creature equal to the total number of instant and sorcery cards you own in exile and in your graveyard. - Ability ability = new LoyaltyAbility( - new DamageTargetEffect(new RalIzzetViceroyCount()) - .setText("{this} deals damage to target creature " - + "equal to the total number of instant " - + "and sorcery cards you own in exile " - + "and in your graveyard"), -3 - ); + Ability ability = new LoyaltyAbility(new DamageTargetEffect( + InstantSorceryExileGraveyardCount.instance + ).setText("{this} deals damage to target creature equal to " + + "the total number of instant and sorcery cards " + + "you own in exile and in your graveyard"), -3); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); @@ -69,29 +64,3 @@ public final class RalIzzetViceroy extends CardImpl { return new RalIzzetViceroy(this); } } - -class RalIzzetViceroyCount implements DynamicValue { - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Player player = game.getPlayer(sourceAbility.getControllerId()); - if (player != null) { - return player.getGraveyard().count( - StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game - ) + game.getExile().getExileZone(player.getId()).count( - StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game - ); - } - return 0; - } - - @Override - public RalIzzetViceroyCount copy() { - return new RalIzzetViceroyCount(); - } - - @Override - public String getMessage() { - return ""; - } -} diff --git a/Mage.Sets/src/mage/cards/r/ResplendentAngel.java b/Mage.Sets/src/mage/cards/r/ResplendentAngel.java index ef40284b699..86160a7236b 100644 --- a/Mage.Sets/src/mage/cards/r/ResplendentAngel.java +++ b/Mage.Sets/src/mage/cards/r/ResplendentAngel.java @@ -20,7 +20,7 @@ import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.permanent.token.AngelToken2; +import mage.game.permanent.token.AngelVigilanceToken; import mage.watchers.common.PlayerGainedLifeWatcher; /** @@ -42,7 +42,7 @@ public final class ResplendentAngel extends CardImpl { // At the beginning of each end step, if you gained 5 or more life this turn, create a 4/4 white Angel creature token with flying and vigilance. this.addAbility(new BeginningOfEndStepTriggeredAbility( Zone.BATTLEFIELD, - new CreateTokenEffect(new AngelToken2()), + new CreateTokenEffect(new AngelVigilanceToken()), TargetController.ANY, new YouGainedLifeCondition(ComparisonType.MORE_THAN, 4), false diff --git a/Mage.Sets/src/mage/cards/r/RhizomeLurcher.java b/Mage.Sets/src/mage/cards/r/RhizomeLurcher.java new file mode 100644 index 00000000000..bfa45116495 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhizomeLurcher.java @@ -0,0 +1,53 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class RhizomeLurcher extends CardImpl { + + public RhizomeLurcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}"); + + this.subtype.add(SubType.FUNGUS); + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Undergrowth — Rhizome Lurcher enters the battlefield with a number of +1/+1 counters on it equal to the number of creature cards in your graveyard. + Ability ability = new EntersBattlefieldAbility( + new AddCountersSourceEffect( + CounterType.P1P1.createInstance(0), + new CardsInControllerGraveyardCount( + StaticFilters.FILTER_CARD_CREATURE + ), true + ), "with a number of +1/+1 counters on it equal to " + + "the number of creature cards in your graveyard" + ); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); + this.addAbility(ability); + } + + public RhizomeLurcher(final RhizomeLurcher card) { + super(card); + } + + @Override + public RhizomeLurcher copy() { + return new RhizomeLurcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiskFactor.java b/Mage.Sets/src/mage/cards/r/RiskFactor.java new file mode 100644 index 00000000000..593af6728f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiskFactor.java @@ -0,0 +1,74 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.JumpStartAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 + */ +public final class RiskFactor extends CardImpl { + + public RiskFactor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Target opponent may have Risk Factor deal 4 damage to them. If that player doesn't, you draw three cards. + this.getSpellAbility().addEffect(new RiskFactorEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // Jump-start + this.addAbility(new JumpStartAbility(this)); + + } + + public RiskFactor(final RiskFactor card) { + super(card); + } + + @Override + public RiskFactor copy() { + return new RiskFactor(this); + } +} + +class RiskFactorEffect extends OneShotEffect { + + public RiskFactorEffect() { + super(Outcome.Benefit); + this.staticText = "Target opponent may have {this} deal 4 damage to them. " + + "If that player doesn't, you draw three cards."; + } + + public RiskFactorEffect(final RiskFactorEffect effect) { + super(effect); + } + + @Override + public RiskFactorEffect copy() { + return new RiskFactorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; + } + if (opponent.chooseUse(outcome, "Do you choose to take the damage?", source, game)) { + opponent.damage(4, source.getSourceId(), game, false, true); + } else { + controller.drawCards(3, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RitualOfSoot.java b/Mage.Sets/src/mage/cards/r/RitualOfSoot.java new file mode 100644 index 00000000000..bf5eb888b7e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RitualOfSoot.java @@ -0,0 +1,42 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; + +/** + * + * @author TheElk801 + */ +public final class RitualOfSoot extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures with converted mana cost 3 or less"); + + static { + filter.add(new ConvertedManaCostPredicate( + ComparisonType.FEWER_THAN, 4 + )); + } + + public RitualOfSoot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + + // Destroy all creatures with converted mana cost 3 or less. + this.getSpellAbility().addEffect(new DestroyAllEffect(filter)); + } + + public RitualOfSoot(final RitualOfSoot card) { + super(card); + } + + @Override + public RitualOfSoot copy() { + return new RitualOfSoot(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RocCharger.java b/Mage.Sets/src/mage/cards/r/RocCharger.java new file mode 100644 index 00000000000..d9b5f7911d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RocCharger.java @@ -0,0 +1,61 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class RocCharger extends CardImpl { + + static final FilterAttackingCreature filter + = new FilterAttackingCreature("attacking creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public RocCharger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Roc Charger attacks, target attacking creature without flying gains flying until end of turn. + Ability ability = new AttacksTriggeredAbility( + new GainAbilityTargetEffect( + FlyingAbility.getInstance(), + Duration.EndOfTurn + ), false + ); + ability.addTarget(new TargetCreaturePermanent(filter)); + addAbility(ability); + } + + public RocCharger(final RocCharger card) { + super(card); + } + + @Override + public RocCharger copy() { + return new RocCharger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltBoar.java b/Mage.Sets/src/mage/cards/r/RubblebeltBoar.java new file mode 100644 index 00000000000..e627e8674c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RubblebeltBoar.java @@ -0,0 +1,44 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class RubblebeltBoar extends CardImpl { + + public RubblebeltBoar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.BOAR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Rubblebelt Boar enters the battlefield, target creature gets +2/+0 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility( + new BoostTargetEffect(2, 0, Duration.EndOfTurn) + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public RubblebeltBoar(final RubblebeltBoar card) { + super(card); + } + + @Override + public RubblebeltBoar copy() { + return new RubblebeltBoar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilentDart.java b/Mage.Sets/src/mage/cards/s/SilentDart.java new file mode 100644 index 00000000000..652d65c427c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SilentDart.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class SilentDart extends CardImpl { + + public SilentDart(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // {4}, {T}, Sacrifice Silent Dart: It deals 3 damage to target creature. + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new DamageTargetEffect(3, "it"), + new GenericManaCost(4) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public SilentDart(final SilentDart card) { + super(card); + } + + @Override + public SilentDart copy() { + return new SilentDart(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilverfurPartisan.java b/Mage.Sets/src/mage/cards/s/SilverfurPartisan.java index 4caebce8f99..82648348dab 100644 --- a/Mage.Sets/src/mage/cards/s/SilverfurPartisan.java +++ b/Mage.Sets/src/mage/cards/s/SilverfurPartisan.java @@ -77,7 +77,7 @@ class CreaturesYouControlBecomesTargetTriggeredAbility extends TriggeredAbilityI Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.isControlledBy(this.controllerId) && (permanent.hasSubtype(SubType.WOLF, game) || permanent.hasSubtype(SubType.WEREWOLF, game))) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object instanceof Spell) { + if (object instanceof Spell) { Card c = (Spell) object; if (c.isInstant() || c.isSorcery()) { if (getTargets().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/s/Solemnity.java b/Mage.Sets/src/mage/cards/s/Solemnity.java index b930f65297f..0ce74644dac 100644 --- a/Mage.Sets/src/mage/cards/s/Solemnity.java +++ b/Mage.Sets/src/mage/cards/s/Solemnity.java @@ -123,7 +123,7 @@ class SolemnityEffect2 extends ReplacementEffectImpl { Permanent permanent2 = game.getPermanent(event.getTargetId()); Permanent permanent3 = game.getPermanentEntering(event.getTargetId()); - if (object != null && object instanceof Permanent) { + if (object instanceof Permanent) { if (filter.match((Permanent) object, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java index 015af98ca9c..abd70447d89 100644 --- a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java @@ -111,7 +111,7 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { MageObject mageObject = game.getObject(spellId); - if (mageObject == null || !(mageObject instanceof Spell) || ((Spell) mageObject).isCopiedSpell()) { + if (!(mageObject instanceof Spell) || ((Spell) mageObject).isCopiedSpell()) { return false; } else { Card sourceCard = game.getCard(spellId); diff --git a/Mage.Sets/src/mage/cards/s/SparkFiend.java b/Mage.Sets/src/mage/cards/s/SparkFiend.java index 0de02f16fdb..3f55cc67b3f 100644 --- a/Mage.Sets/src/mage/cards/s/SparkFiend.java +++ b/Mage.Sets/src/mage/cards/s/SparkFiend.java @@ -69,7 +69,7 @@ class SparkFiendEffect extends OneShotEffect { if (controller != null) { int roll = controller.rollDice(game, 6) + controller.rollDice(game, 6); MageObject mageObject = game.getObject(source.getSourceId()); - if (mageObject != null && mageObject instanceof Permanent) { + if (mageObject instanceof Permanent) { Permanent sourcePermanent = (Permanent) mageObject; if (roll == 2 || roll == 3 || roll == 12) { // sacrifice @@ -114,7 +114,7 @@ class SparkFiendUpkeepEffect extends OneShotEffect { && (Integer) game.getState().getValue("SparkFiend" + source.getSourceId().toString()) != 0) { int roll = controller.rollDice(game, 6) + controller.rollDice(game, 6); MageObject mageObject = game.getObject(source.getSourceId()); - if (mageObject != null && mageObject instanceof Permanent) { + if (mageObject instanceof Permanent) { Permanent sourcePermanent = (Permanent) mageObject; if (roll == 7) { // sacrifice diff --git a/Mage.Sets/src/mage/cards/s/SpectralPrison.java b/Mage.Sets/src/mage/cards/s/SpectralPrison.java index bac2d6a6b64..f502fd33e08 100644 --- a/Mage.Sets/src/mage/cards/s/SpectralPrison.java +++ b/Mage.Sets/src/mage/cards/s/SpectralPrison.java @@ -80,7 +80,7 @@ class SpectralPrisonAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject eventSourceObject = game.getObject(event.getSourceId()); - if (eventSourceObject != null && eventSourceObject instanceof Spell) { + if (eventSourceObject instanceof Spell) { Permanent enchantment = game.getPermanent(sourceId); if (enchantment != null && enchantment.getAttachedTo() != null) { if (event.getTargetId().equals(enchantment.getAttachedTo())) { diff --git a/Mage.Sets/src/mage/cards/s/SpellShrivel.java b/Mage.Sets/src/mage/cards/s/SpellShrivel.java index 9da3aaafe41..6ab606a1991 100644 --- a/Mage.Sets/src/mage/cards/s/SpellShrivel.java +++ b/Mage.Sets/src/mage/cards/s/SpellShrivel.java @@ -66,7 +66,7 @@ class SpellShrivelCounterUnlessPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { StackObject spell = game.getStack().getStackObject(targetPointer.getFirst(game, source)); MageObject sourceObject = source.getSourceObject(game); - if (spell != null && (spell instanceof Spell) && sourceObject != null) { + if ((spell instanceof Spell) && sourceObject != null) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int amount = 4; diff --git a/Mage.Sets/src/mage/cards/s/SpinalCentipede.java b/Mage.Sets/src/mage/cards/s/SpinalCentipede.java new file mode 100644 index 00000000000..9d5073b48bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpinalCentipede.java @@ -0,0 +1,44 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class SpinalCentipede extends CardImpl { + + public SpinalCentipede(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Spinal Centipede dies, put a +1/+1 counter on target creature you control. + Ability ability = new DiesTriggeredAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance() + ), false); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + public SpinalCentipede(final SpinalCentipede card) { + super(card); + } + + @Override + public SpinalCentipede copy() { + return new SpinalCentipede(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SproutingRenewal.java b/Mage.Sets/src/mage/cards/s/SproutingRenewal.java new file mode 100644 index 00000000000..4a9e9c4285c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SproutingRenewal.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Mode; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.ElfKnightToken; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class SproutingRenewal extends CardImpl { + + public SproutingRenewal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // Choose one — + // • Create a 2/2 green and white Elf Knight creature token with vigilance. + this.getSpellAbility().addEffect(new CreateTokenEffect(new ElfKnightToken())); + + // • Destroy target artifact or enchantment. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent( + StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT + )); + this.getSpellAbility().addMode(mode); + } + + public SproutingRenewal(final SproutingRenewal card) { + super(card); + } + + @Override + public SproutingRenewal copy() { + return new SproutingRenewal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SummoningTrap.java b/Mage.Sets/src/mage/cards/s/SummoningTrap.java index 31be77a83f6..8bc4391c423 100644 --- a/Mage.Sets/src/mage/cards/s/SummoningTrap.java +++ b/Mage.Sets/src/mage/cards/s/SummoningTrap.java @@ -90,8 +90,7 @@ class SummoningTrapWatcher extends Watcher { if (counteredSpell == null) { counteredSpell = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK); } - if (counteredSpell != null - && counteredSpell instanceof Spell + if (counteredSpell instanceof Spell && !players.contains(counteredSpell.getControllerId()) && counteredSpell.isCreature()) { StackObject counteringStackObject = game.getStack().getStackObject(event.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/s/SwarmGuildmage.java b/Mage.Sets/src/mage/cards/s/SwarmGuildmage.java new file mode 100644 index 00000000000..17e0ee5dcaf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwarmGuildmage.java @@ -0,0 +1,64 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class SwarmGuildmage extends CardImpl { + + public SwarmGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {4}{B}, {T}: Creatures you control get +1/+0 and gain menace until end of turn. + Ability ability = new SimpleActivatedAbility( + new BoostControlledEffect(1, 0, Duration.EndOfTurn) + .setText("creatures you control get +1/+0"), + new ManaCostsImpl("{4}{B}") + ); + ability.addEffect(new GainAbilityControlledEffect( + new MenaceAbility(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + ).setText("and gain menace until end of turn")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {1}{G}, {T}: You gain 2 life. + ability = new SimpleActivatedAbility( + new GainLifeEffect(2), + new ManaCostsImpl("{1}{G}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public SwarmGuildmage(final SwarmGuildmage card) { + super(card); + } + + @Override + public SwarmGuildmage copy() { + return new SwarmGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwathcutterGiant.java b/Mage.Sets/src/mage/cards/s/SwathcutterGiant.java new file mode 100644 index 00000000000..3113d45bd05 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwathcutterGiant.java @@ -0,0 +1,75 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.constants.SubType; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; + +/** + * + * @author TheElk801 + */ +public final class SwathcutterGiant extends CardImpl { + + public SwathcutterGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{W}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever Swathcutter Giant attacks, it deals 1 damage to each creature defending player controls. + this.addAbility(new AttacksTriggeredAbility(new SwathcutterGiantEffect(), false)); + } + + public SwathcutterGiant(final SwathcutterGiant card) { + super(card); + } + + @Override + public SwathcutterGiant copy() { + return new SwathcutterGiant(this); + } +} + +class SwathcutterGiantEffect extends OneShotEffect { + + public SwathcutterGiantEffect() { + super(Outcome.Benefit); + this.staticText = "it deals 1 damage to each creature " + + "defending player controls."; + } + + public SwathcutterGiantEffect(final SwathcutterGiantEffect effect) { + super(effect); + } + + @Override + public SwathcutterGiantEffect copy() { + return new SwathcutterGiantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new ControllerIdPredicate( + game.getCombat().getDefenderId(source.getSourceId()) + )); + return new DamageAllEffect(1, filter).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwiftbladeVindicator.java b/Mage.Sets/src/mage/cards/s/SwiftbladeVindicator.java new file mode 100644 index 00000000000..d75c001f8d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwiftbladeVindicator.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class SwiftbladeVindicator extends CardImpl { + + public SwiftbladeVindicator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + } + + public SwiftbladeVindicator(final SwiftbladeVindicator card) { + super(card); + } + + @Override + public SwiftbladeVindicator copy() { + return new SwiftbladeVindicator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwornCompanions.java b/Mage.Sets/src/mage/cards/s/SwornCompanions.java new file mode 100644 index 00000000000..52a743c21c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwornCompanions.java @@ -0,0 +1,33 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.SoldierLifelinkToken; + +/** + * + * @author TheElk801 + */ +public final class SwornCompanions extends CardImpl { + + public SwornCompanions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + + // Creature two 1/1 white Soldier creature tokens with lifelink. + this.getSpellAbility().addEffect( + new CreateTokenEffect(new SoldierLifelinkToken(), 2) + ); + } + + public SwornCompanions(final SwornCompanions card) { + super(card); + } + + @Override + public SwornCompanions copy() { + return new SwornCompanions(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Syncopate.java b/Mage.Sets/src/mage/cards/s/Syncopate.java index c2ff8016d86..01dd9e88258 100644 --- a/Mage.Sets/src/mage/cards/s/Syncopate.java +++ b/Mage.Sets/src/mage/cards/s/Syncopate.java @@ -61,7 +61,7 @@ class SyncopateCounterUnlessPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { StackObject spell = game.getStack().getStackObject(targetPointer.getFirst(game, source)); MageObject sourceObject = source.getSourceObject(game); - if (spell != null && (spell instanceof Spell) && sourceObject != null) { + if ((spell instanceof Spell) && sourceObject != null) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int amount = source.getManaCostsToPay().getX(); diff --git a/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java b/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java new file mode 100644 index 00000000000..faa291400c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java @@ -0,0 +1,77 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.PreventAllNonCombatDamageToAllEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.MentorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; + +/** + * + * @author TheElk801 + */ +public final class TajicLegionsEdge extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("other creatures you control"); + + static { + filter.add(new AnotherPredicate()); + } + + public TajicLegionsEdge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Mentor + this.addAbility(new MentorAbility()); + + // Prevent all noncombat damage that would be dealt to other creatures you control. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new PreventAllNonCombatDamageToAllEffect( + Duration.WhileOnBattlefield, filter + ) + )); + + // {R}{W}: Tajic, Legion's Edge gains first strike until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), + Duration.EndOfTurn + ), new ManaCostsImpl("{R}{W}") + )); + } + + public TajicLegionsEdge(final TajicLegionsEdge card) { + super(card); + } + + @Override + public TajicLegionsEdge copy() { + return new TajicLegionsEdge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TawnossCoffin.java b/Mage.Sets/src/mage/cards/t/TawnossCoffin.java index 6bd80db5c56..af280935ff3 100644 --- a/Mage.Sets/src/mage/cards/t/TawnossCoffin.java +++ b/Mage.Sets/src/mage/cards/t/TawnossCoffin.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.HashSet; @@ -171,7 +170,7 @@ class TawnossCoffinReturnEffect extends OneShotEffect { if (controller == null) { return false; } - UUID exileZoneId = CardUtil.getCardExileZoneId(game, source); + UUID exileZoneId = CardUtil.getCardExileZoneId(game, source.getSourceId(), source.getSourcePermanentIfItStillExists(game) == null); ExileZone exileZone = game.getExile().getExileZone(exileZoneId); if (exileZone == null) { return true; diff --git a/Mage.Sets/src/mage/cards/t/ThoughtPrison.java b/Mage.Sets/src/mage/cards/t/ThoughtPrison.java index 8a5e27bc067..7eef4e4083c 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtPrison.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtPrison.java @@ -137,7 +137,7 @@ class ThoughtPrisonTriggeredAbility extends TriggeredAbilityImpl { Spell spell = (Spell) game.getObject(event.getTargetId()); Permanent sourcePermanent = game.getPermanent(this.getSourceId()); - if (spell != null && spell instanceof Spell) { + if (spell instanceof Spell) { if (sourcePermanent == null) { sourcePermanent = (Permanent) game.getLastKnownInformation(event.getSourceId(), Zone.BATTLEFIELD); } diff --git a/Mage.Sets/src/mage/cards/t/ThoughtboundPhantasm.java b/Mage.Sets/src/mage/cards/t/ThoughtboundPhantasm.java new file mode 100644 index 00000000000..1c0041ff36c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThoughtboundPhantasm.java @@ -0,0 +1,96 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author TheElk801 + */ +public final class ThoughtboundPhantasm extends CardImpl { + + public ThoughtboundPhantasm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Whenever you surveil, put a +1/+1 counter on Thoughtbound Phantasm. + this.addAbility(new ThoughtboundPhantasmTriggeredAbility()); + + // As long as Thoughtbound Phantasm has three or more +1/+1 counters on it, it can attack as though it didn't have defender. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalAsThoughEffect( + new CanAttackAsThoughItDidntHaveDefenderSourceEffect( + Duration.WhileOnBattlefield + ), new SourceHasCounterCondition(CounterType.P1P1, 3) + ).setText("As long as {this} has three " + + "or more +1/+1 counters on it, " + + "it can attack as though it " + + "didn't have defender.") + )); + } + + public ThoughtboundPhantasm(final ThoughtboundPhantasm card) { + super(card); + } + + @Override + public ThoughtboundPhantasm copy() { + return new ThoughtboundPhantasm(this); + } +} + +class ThoughtboundPhantasmTriggeredAbility extends TriggeredAbilityImpl { + + public ThoughtboundPhantasmTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect( + CounterType.P1P1.createInstance() + ), false); + } + + public ThoughtboundPhantasmTriggeredAbility(final ThoughtboundPhantasmTriggeredAbility ability) { + super(ability); + } + + @Override + public ThoughtboundPhantasmTriggeredAbility copy() { + return new ThoughtboundPhantasmTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SURVEILED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()); + } + + @Override + public String getRule() { + return "Whenever you surveil, put a +1/+1 counter on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TitaniaProtectorOfArgoth.java b/Mage.Sets/src/mage/cards/t/TitaniaProtectorOfArgoth.java index c953ca9f252..2b732adc5e3 100644 --- a/Mage.Sets/src/mage/cards/t/TitaniaProtectorOfArgoth.java +++ b/Mage.Sets/src/mage/cards/t/TitaniaProtectorOfArgoth.java @@ -41,7 +41,7 @@ public final class TitaniaProtectorOfArgoth extends CardImpl { this.toughness = new MageInt(3); // When Titania, Protector of Argoth enters the battlefield, return target land card from your graveyard to the battlefield. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(new FilterLandCard("land card from your graveyard"))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TreacherousPitDweller.java b/Mage.Sets/src/mage/cards/t/TreacherousPitDweller.java index d99891cb1f6..876e1d9be12 100644 --- a/Mage.Sets/src/mage/cards/t/TreacherousPitDweller.java +++ b/Mage.Sets/src/mage/cards/t/TreacherousPitDweller.java @@ -102,8 +102,7 @@ class TreacherousPitDwellerEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { MageObject permanent = source.getSourceObjectIfItStillExists(game); // it can also return Card object Player targetOpponent = game.getPlayer(source.getFirstTarget()); - if (permanent != null - && (permanent instanceof Permanent) + if ((permanent instanceof Permanent) && targetOpponent != null) { return ((Permanent) permanent).changeControllerId(targetOpponent.getId(), game); } else { diff --git a/Mage.Sets/src/mage/cards/t/TritonTactics.java b/Mage.Sets/src/mage/cards/t/TritonTactics.java index d400a0fd42d..1823c39c192 100644 --- a/Mage.Sets/src/mage/cards/t/TritonTactics.java +++ b/Mage.Sets/src/mage/cards/t/TritonTactics.java @@ -89,7 +89,7 @@ class TritonTacticsUntapTargetEffect extends OneShotEffect { // save the targets for the watcher in a map with zone change counter (as the card is recast during combat it's neccessary to save with zone change counter) Map> targetMap; Object object = game.getState().getValue("targets" + source.getSourceId()); - if (object != null && object instanceof Map) { + if (object instanceof Map) { targetMap = (Map>) object; } else { targetMap = new HashMap<>(); @@ -155,7 +155,7 @@ class TritonTacticsEndOfCombatEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Map> attackerMap = null; Object object = game.getState().getValue("blockedAttackers" + source.getSourceId()); - if (object != null && object instanceof Map) { + if (object instanceof Map) { attackerMap = (Map>) object; for (Set attackerSet : attackerMap.values()) { List doNotUntapNextUntapStep = new ArrayList<>(); @@ -197,7 +197,7 @@ class BlockedCreaturesWatcher extends Watcher { if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { Map> targetMap; Object object = game.getState().getValue("targets" + this.getSourceId().toString()); - if (object != null && object instanceof Map) { + if (object instanceof Map) { Permanent blocker = game.getPermanent(event.getSourceId()); if (blocker != null) { targetMap = (Map>) object; @@ -217,7 +217,7 @@ class BlockedCreaturesWatcher extends Watcher { Set attackers; Map> attackerMap; Object object = game.getState().getValue("blockedAttackers" + getSourceId()); - if (object != null && object instanceof Map) { + if (object instanceof Map) { attackerMap = (Map>) object; } else { attackerMap = new HashMap<>(); diff --git a/Mage.Sets/src/mage/cards/t/TrostaniDiscordant.java b/Mage.Sets/src/mage/cards/t/TrostaniDiscordant.java new file mode 100644 index 00000000000..d7dfd63b478 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrostaniDiscordant.java @@ -0,0 +1,125 @@ +package mage.cards.t; + +import java.util.Iterator; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SoldierLifelinkToken; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class TrostaniDiscordant extends CardImpl { + + public TrostaniDiscordant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DRYAD); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Other creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, true + ) + )); + + // When Trostani Discordant enters the battlefield, create two 1/1 white Soldier creature tokens with lifelink. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new SoldierLifelinkToken(), 2) + )); + + // At the beginning of your end step, each player gains control of all creatures they own. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new TrostaniDiscordantEffect(), TargetController.YOU, false + )); + } + + public TrostaniDiscordant(final TrostaniDiscordant card) { + super(card); + } + + @Override + public TrostaniDiscordant copy() { + return new TrostaniDiscordant(this); + } +} + +class TrostaniDiscordantEffect extends ContinuousEffectImpl { + + public TrostaniDiscordantEffect() { + super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + this.staticText = "each player gains control of all creatures they own"; + } + + public TrostaniDiscordantEffect(final TrostaniDiscordantEffect effect) { + super(effect); + } + + @Override + public TrostaniDiscordantEffect copy() { + return new TrostaniDiscordantEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + // add all creatures in range + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + FilterPermanent playerFilter = new FilterCreaturePermanent(); + playerFilter.add(new OwnerIdPredicate(playerId)); + for (Permanent permanent : game.getBattlefield().getActivePermanents(playerFilter, playerId, game)) { + affectedObjectList.add(new MageObjectReference(permanent, game)); + } + } + } + } + + @Override + public boolean apply(Game game, Ability source) { + for (Iterator it = affectedObjectList.iterator(); it.hasNext();) { + Permanent creature = it.next().getPermanent(game); + if (creature != null) { + if (!creature.isControlledBy(creature.getOwnerId())) { + creature.changeControllerId(creature.getOwnerId(), game); + } + } else { + it.remove(); + } + } + if (affectedObjectList.isEmpty()) { + this.discard(); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TruefireCaptain.java b/Mage.Sets/src/mage/cards/t/TruefireCaptain.java new file mode 100644 index 00000000000..657392ec9f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TruefireCaptain.java @@ -0,0 +1,76 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealtDamageToSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.abilities.keyword.MentorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.target.TargetPlayer; + +/** + * + * @author TheElk801 + */ +public final class TruefireCaptain extends CardImpl { + + public TruefireCaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}{W}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Mentor + this.addAbility(new MentorAbility()); + + // Whenever Truefire Captain is dealt damage, it deals that much damage to target player. + Ability ability = new DealtDamageToSourceTriggeredAbility( + Zone.BATTLEFIELD, new TruefireCaptainEffect(), + false, false, true + ); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public TruefireCaptain(final TruefireCaptain card) { + super(card); + } + + @Override + public TruefireCaptain copy() { + return new TruefireCaptain(this); + } +} + +class TruefireCaptainEffect extends OneShotEffect { + + public TruefireCaptainEffect() { + super(Outcome.Damage); + this.staticText = "it deals that much damage to target player"; + } + + public TruefireCaptainEffect(final TruefireCaptainEffect effect) { + super(effect); + } + + @Override + public TruefireCaptainEffect copy() { + return new TruefireCaptainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int amount = (Integer) getValue("damage"); + return new DamageTargetEffect(amount).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UndercityUprising.java b/Mage.Sets/src/mage/cards/u/UndercityUprising.java new file mode 100644 index 00000000000..86eb2368340 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UndercityUprising.java @@ -0,0 +1,52 @@ +package mage.cards.u; + +import java.util.UUID; +import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class UndercityUprising extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public UndercityUprising(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{G}"); + + // Creatures you control gain deathtouch until end of turn. Target creature you control fights target creature you don't control. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + )); + this.getSpellAbility().addEffect(new FightTargetsEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public UndercityUprising(final UndercityUprising card) { + super(card); + } + + @Override + public UndercityUprising copy() { + return new UndercityUprising(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UrbanUtopia.java b/Mage.Sets/src/mage/cards/u/UrbanUtopia.java new file mode 100644 index 00000000000..a6b67b50bb0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UrbanUtopia.java @@ -0,0 +1,63 @@ +package mage.cards.u; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetLandPermanent; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class UrbanUtopia extends CardImpl { + + public UrbanUtopia(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant Land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When Urban Utopia enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1) + )); + + // Enchanted land has "{T}: Add one mana of any color." + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAttachedEffect( + new AnyColorManaAbility(), AttachmentType.AURA + ).setText("Enchanted land has " + + "\"{T}: Add one mana of any color.\"") + )); + } + + public UrbanUtopia(final UrbanUtopia card) { + super(card); + } + + @Override + public UrbanUtopia copy() { + return new UrbanUtopia(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeiledShade.java b/Mage.Sets/src/mage/cards/v/VeiledShade.java new file mode 100644 index 00000000000..9a9e8df4a70 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeiledShade.java @@ -0,0 +1,44 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author TheElk801 + */ +public final class VeiledShade extends CardImpl { + + public VeiledShade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.SHADE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}{B}: Veiled Shade gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new ManaCostsImpl("{1}{B}") + )); + } + + public VeiledShade(final VeiledShade card) { + super(card); + } + + @Override + public VeiledShade copy() { + return new VeiledShade(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java b/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java new file mode 100644 index 00000000000..34a41b9ab46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java @@ -0,0 +1,145 @@ +package mage.cards.v; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public final class VeneratedLoxodon extends CardImpl { + + public VeneratedLoxodon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // When Venerated Loxodon enters the battlefield, put a +1/+1 counter on each creature that convoked it. + this.addAbility(new EntersBattlefieldTriggeredAbility(new VeneratedLoxodonEffect(), false), new VeneratedLoxodonWatcher()); + } + + public VeneratedLoxodon(final VeneratedLoxodon card) { + super(card); + } + + @Override + public VeneratedLoxodon copy() { + return new VeneratedLoxodon(this); + } +} + +class VeneratedLoxodonEffect extends OneShotEffect { + + public VeneratedLoxodonEffect() { + super(Outcome.BoostCreature); + this.staticText = "put a +1/+1 counter on each creature that convoked it"; + } + + public VeneratedLoxodonEffect(final VeneratedLoxodonEffect effect) { + super(effect); + } + + @Override + public VeneratedLoxodonEffect copy() { + return new VeneratedLoxodonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + VeneratedLoxodonWatcher watcher = (VeneratedLoxodonWatcher) game.getState().getWatchers().get(VeneratedLoxodonWatcher.class.getSimpleName()); + if (watcher != null) { + MageObjectReference mor = new MageObjectReference(source.getSourceId(), source.getSourceObjectZoneChangeCounter() - 1, game); // -1 because of spell on the stack + Set creatures = watcher.getConvokingCreatures(mor); + if (creatures != null) { + for (MageObjectReference creatureMOR : creatures) { + Permanent creature = creatureMOR.getPermanent(game); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game); + } + } + } + return true; + } + return false; + } +} + +class VeneratedLoxodonWatcher extends Watcher { + + private final Map> convokingCreatures = new HashMap<>(); + + public VeneratedLoxodonWatcher() { + super(VeneratedLoxodonWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public VeneratedLoxodonWatcher(final VeneratedLoxodonWatcher watcher) { + super(watcher); + for (Entry> entry : watcher.convokingCreatures.entrySet()) { + Set creatures = new HashSet<>(); + creatures.addAll(entry.getValue()); + convokingCreatures.put(entry.getKey(), creatures); + } + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.CONVOKED) { + Spell spell = game.getSpell(event.getSourceId()); + Permanent tappedCreature = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (spell != null && tappedCreature != null) { + MageObjectReference convokedSpell = new MageObjectReference(spell.getSourceId(), game); + Set creatures; + if (convokingCreatures.containsKey(convokedSpell)) { + creatures = convokingCreatures.get(convokedSpell); + } else { + creatures = new HashSet<>(); + convokingCreatures.put(convokedSpell, creatures); + } + creatures.add(new MageObjectReference(tappedCreature, game)); + } + } + } + + public Set getConvokingCreatures(MageObjectReference mor) { + return convokingCreatures.get(mor); + } + + @Override + public void reset() { + super.reset(); + convokingCreatures.clear(); + } + + @Override + public VeneratedLoxodonWatcher copy() { + return new VeneratedLoxodonWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VernadiShieldmate.java b/Mage.Sets/src/mage/cards/v/VernadiShieldmate.java new file mode 100644 index 00000000000..37f95d9a57d --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VernadiShieldmate.java @@ -0,0 +1,37 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class VernadiShieldmate extends CardImpl { + + public VernadiShieldmate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G/W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + } + + public VernadiShieldmate(final VernadiShieldmate card) { + super(card); + } + + @Override + public VernadiShieldmate copy() { + return new VernadiShieldmate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java b/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java new file mode 100644 index 00000000000..9f3646cdb0a --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java @@ -0,0 +1,78 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.command.emblems.VraskaGolgariQueenEmblem; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author TheElk801 + */ +public final class VraskaGolgariQueen extends CardImpl { + + private static final FilterControlledPermanent filter1 + = new FilterControlledPermanent("another permanent"); + private static final FilterPermanent filter2 + = new FilterNonlandPermanent("nonland permanent with converted mana cost 3 or less"); + + static { + filter1.add(new AnotherPredicate()); + filter2.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public VraskaGolgariQueen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VRASKA); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); + + // +2: You may sacrifice another permanent. If you do, you gain 1 life and draw a card. + DoIfCostPaid effect = new DoIfCostPaid( + new GainLifeEffect(1), + new SacrificeTargetCost(new TargetControlledPermanent(filter1)) + ); + effect.addEffect(new DrawCardSourceControllerEffect(1)); + this.addAbility(new LoyaltyAbility(effect, 2)); + + // -3: Destroy target nonland permanent with converted mana cost 3 or less. + Ability ability = new LoyaltyAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + + // -9: You get an emblem with "Whenever a creature you control deals combat damage to a player, that player loses the game." + this.addAbility(new LoyaltyAbility( + new GetEmblemEffect(new VraskaGolgariQueenEmblem()), -9 + )); + } + + public VraskaGolgariQueen(final VraskaGolgariQueen card) { + super(card); + } + + @Override + public VraskaGolgariQueen copy() { + return new VraskaGolgariQueen(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WandOfVertebrae.java b/Mage.Sets/src/mage/cards/w/WandOfVertebrae.java new file mode 100644 index 00000000000..0328b935864 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WandOfVertebrae.java @@ -0,0 +1,92 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class WandOfVertebrae extends CardImpl { + + public WandOfVertebrae(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // {T}: Put the top card of your library into your graveyard. + this.addAbility(new SimpleActivatedAbility( + new PutTopCardOfLibraryIntoGraveControllerEffect(1), + new TapSourceCost() + )); + + // {2}, {T}, Exile Wand of Vertebrae: Shuffle up to five target cards from your graveyard into your library. + Ability ability = new SimpleActivatedAbility( + new WandOfVertebraeEffect(), + new GenericManaCost(2) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new ExileSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(0, 5)); + this.addAbility(ability); + } + + public WandOfVertebrae(final WandOfVertebrae card) { + super(card); + } + + @Override + public WandOfVertebrae copy() { + return new WandOfVertebrae(this); + } +} + +class WandOfVertebraeEffect extends OneShotEffect { + + public WandOfVertebraeEffect() { + super(Outcome.Benefit); + this.staticText = "Shuffle up to five target cards " + + "from your graveyard into your library."; + } + + public WandOfVertebraeEffect(final WandOfVertebraeEffect effect) { + super(effect); + } + + @Override + public WandOfVertebraeEffect copy() { + return new WandOfVertebraeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + for (UUID targetId : targetPointer.getTargets(game, source)) { + Card card = game.getCard(targetId); + if (card != null) { + cards.add(card); + } + } + player.getLibrary().addAll(cards.getCards(game), game); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WatcherInTheMist.java b/Mage.Sets/src/mage/cards/w/WatcherInTheMist.java new file mode 100644 index 00000000000..0214f13d879 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WatcherInTheMist.java @@ -0,0 +1,43 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class WatcherInTheMist extends CardImpl { + + public WatcherInTheMist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Watcher in the Mist enters the battlefield, surveil 2. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SurveilEffect(2), false + )); + } + + public WatcherInTheMist(final WatcherInTheMist card) { + super(card); + } + + @Override + public WatcherInTheMist copy() { + return new WatcherInTheMist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WhisperingSpy.java b/Mage.Sets/src/mage/cards/w/WhisperingSnitch.java similarity index 62% rename from Mage.Sets/src/mage/cards/w/WhisperingSpy.java rename to Mage.Sets/src/mage/cards/w/WhisperingSnitch.java index 6454069e7c3..c28daf08416 100644 --- a/Mage.Sets/src/mage/cards/w/WhisperingSpy.java +++ b/Mage.Sets/src/mage/cards/w/WhisperingSnitch.java @@ -22,9 +22,9 @@ import mage.watchers.Watcher; * * @author TheElk801 */ -public final class WhisperingSpy extends CardImpl { +public final class WhisperingSnitch extends CardImpl { - public WhisperingSpy(UUID ownerId, CardSetInfo setInfo) { + public WhisperingSnitch(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.VAMPIRE); @@ -33,45 +33,45 @@ public final class WhisperingSpy extends CardImpl { this.toughness = new MageInt(3); // When you surveil for the first time in a turn, Whispering Spy deals 1 damage to each opponent and you gain 1 life. - this.addAbility(new WhisperingSpyTriggeredAbility()); + this.addAbility(new WhisperingSnitchTriggeredAbility()); } - public WhisperingSpy(final WhisperingSpy card) { + public WhisperingSnitch(final WhisperingSnitch card) { super(card); } @Override - public WhisperingSpy copy() { - return new WhisperingSpy(this); + public WhisperingSnitch copy() { + return new WhisperingSnitch(this); } } -class WhisperingSpyTriggeredAbility extends TriggeredAbilityImpl { +class WhisperingSnitchTriggeredAbility extends TriggeredAbilityImpl { - public WhisperingSpyTriggeredAbility() { + public WhisperingSnitchTriggeredAbility() { super(Zone.BATTLEFIELD, new DamagePlayersEffect(1, TargetController.OPPONENT), false); this.addEffect(new GainLifeEffect(1)); - this.addWatcher(new WhisperingSpyWatcher()); + this.addWatcher(new WhisperingSnitchWatcher()); } - public WhisperingSpyTriggeredAbility(final WhisperingSpyTriggeredAbility ability) { + public WhisperingSnitchTriggeredAbility(final WhisperingSnitchTriggeredAbility ability) { super(ability); } @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SURVEIL; + return event.getType() == GameEvent.EventType.SURVEILED; } @Override public boolean checkTrigger(GameEvent event, Game game) { - WhisperingSpyWatcher watcher = (WhisperingSpyWatcher) game.getState().getWatchers().get(WhisperingSpyWatcher.class.getSimpleName()); + WhisperingSnitchWatcher watcher = (WhisperingSnitchWatcher) game.getState().getWatchers().get(WhisperingSnitchWatcher.class.getSimpleName()); return watcher != null && watcher.getTimesSurveiled(getControllerId()) == 1; } @Override - public WhisperingSpyTriggeredAbility copy() { - return new WhisperingSpyTriggeredAbility(this); + public WhisperingSnitchTriggeredAbility copy() { + return new WhisperingSnitchTriggeredAbility(this); } @Override @@ -81,26 +81,26 @@ class WhisperingSpyTriggeredAbility extends TriggeredAbilityImpl { } } -class WhisperingSpyWatcher extends Watcher { +class WhisperingSnitchWatcher extends Watcher { private final Map timesSurveiled = new HashMap<>(); - public WhisperingSpyWatcher() { - super(WhisperingSpyWatcher.class.getSimpleName(), WatcherScope.GAME); + public WhisperingSnitchWatcher() { + super(WhisperingSnitchWatcher.class.getSimpleName(), WatcherScope.GAME); } - public WhisperingSpyWatcher(final WhisperingSpyWatcher watcher) { + public WhisperingSnitchWatcher(final WhisperingSnitchWatcher watcher) { super(watcher); } @Override - public WhisperingSpyWatcher copy() { - return new WhisperingSpyWatcher(this); + public WhisperingSnitchWatcher copy() { + return new WhisperingSnitchWatcher(this); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SURVEIL) { + if (event.getType() == GameEvent.EventType.SURVEILED) { timesSurveiled.put(event.getPlayerId(), getTimesSurveiled(event.getPlayerId()) + 1); } } diff --git a/Mage.Sets/src/mage/cards/w/WildCeratok.java b/Mage.Sets/src/mage/cards/w/WildCeratok.java new file mode 100644 index 00000000000..9d651116654 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildCeratok.java @@ -0,0 +1,32 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class WildCeratok extends CardImpl { + + public WildCeratok(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.RHINO); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + } + + public WildCeratok(final WildCeratok card) { + super(card); + } + + @Override + public WildCeratok copy() { + return new WildCeratok(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildDefiance.java b/Mage.Sets/src/mage/cards/w/WildDefiance.java index 6d2fd536150..25dcefa7581 100644 --- a/Mage.Sets/src/mage/cards/w/WildDefiance.java +++ b/Mage.Sets/src/mage/cards/w/WildDefiance.java @@ -65,7 +65,7 @@ class CreaturesYouControlBecomesTargetTriggeredAbility extends TriggeredAbilityI Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.isControlledBy(this.controllerId) && permanent.isCreature()) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object instanceof Spell) { + if (object instanceof Spell) { Card c = (Spell) object; if (c.isInstant() || c.isSorcery()) { if (getTargets().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/w/WishcoinCrab.java b/Mage.Sets/src/mage/cards/w/WishcoinCrab.java new file mode 100644 index 00000000000..37c886fe7a0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WishcoinCrab.java @@ -0,0 +1,32 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class WishcoinCrab extends CardImpl { + + public WishcoinCrab(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.CRAB); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + } + + public WishcoinCrab(final WishcoinCrab card) { + super(card); + } + + @Override + public WishcoinCrab copy() { + return new WishcoinCrab(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java index ca7fe9245a9..e52cbe13d4a 100644 --- a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java +++ b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java @@ -96,7 +96,7 @@ class WispweaverAngelEffect extends OneShotEffect { cardsToBattlefield.add(targetId); } else { Card card = game.getCard(targetId); - if (card != null && card instanceof MeldCard) { + if (card instanceof MeldCard) { MeldCard meldCard = (MeldCard) card; Card topCard = meldCard.getTopHalfCard(); Card bottomCard = meldCard.getBottomHalfCard(); diff --git a/Mage.Sets/src/mage/cards/w/WojekBodyguard.java b/Mage.Sets/src/mage/cards/w/WojekBodyguard.java new file mode 100644 index 00000000000..4b00e5a48bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WojekBodyguard.java @@ -0,0 +1,43 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.CantAttackAloneAbility; +import mage.abilities.keyword.CantBlockAloneAbility; +import mage.constants.SubType; +import mage.abilities.keyword.MentorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author TheElk801 + */ +public final class WojekBodyguard extends CardImpl { + + public WojekBodyguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Mentor + this.addAbility(new MentorAbility()); + + // Wojek Bodyguard can't attack or block alone. + this.addAbility(new CantAttackAloneAbility()); + this.addAbility(CantBlockAloneAbility.getInstance()); + } + + public WojekBodyguard(final WojekBodyguard card) { + super(card); + } + + @Override + public WojekBodyguard copy() { + return new WojekBodyguard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WorldAtWar.java b/Mage.Sets/src/mage/cards/w/WorldAtWar.java index 3bd876d6c19..0658ecda702 100644 --- a/Mage.Sets/src/mage/cards/w/WorldAtWar.java +++ b/Mage.Sets/src/mage/cards/w/WorldAtWar.java @@ -143,7 +143,7 @@ class UntapAttackingThisTurnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { + if (watcher instanceof AttackedThisTurnWatcher) { Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); for (MageObjectReference mor : attackedThisTurn) { Permanent permanent = mor.getPermanent(game); diff --git a/Mage.Sets/src/mage/cards/w/WorldsoulColossus.java b/Mage.Sets/src/mage/cards/w/WorldsoulColossus.java new file mode 100644 index 00000000000..0f87ed598a4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WorldsoulColossus.java @@ -0,0 +1,46 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; +import mage.constants.SubType; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; + +/** + * + * @author TheElk801 + */ +public final class WorldsoulColossus extends CardImpl { + + public WorldsoulColossus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{G}{W}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // Worldsoul Colossus enters the battlefield with X +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility( + new EntersBattlefieldWithXCountersEffect( + CounterType.P1P1.createInstance() + ) + )); + } + + public WorldsoulColossus(final WorldsoulColossus card) { + super(card); + } + + @Override + public WorldsoulColossus copy() { + return new WorldsoulColossus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java b/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java index fbf46de1dab..d36dfbe7421 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java @@ -137,7 +137,7 @@ class YawgmothsAgendaReplacementEffect extends ReplacementEffectImpl { Card card = game.getCard(event.getTargetId()); if (card != null && card.isOwnedBy(source.getControllerId())) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); - if (permanent == null || !(permanent instanceof PermanentToken)) { + if (!(permanent instanceof PermanentToken)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsWill.java b/Mage.Sets/src/mage/cards/y/YawgmothsWill.java index 8690dbd141a..cfdb0d77e18 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothsWill.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothsWill.java @@ -127,7 +127,7 @@ class YawgmothsWillReplacementEffect extends ReplacementEffectImpl { Card card = game.getCard(event.getTargetId()); if (card != null && card.isOwnedBy(source.getControllerId())) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); - if (permanent == null || !(permanent instanceof PermanentToken)) { + if (!(permanent instanceof PermanentToken)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index bbf2c671de2..486c71ea689 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -38,7 +38,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); cards.add(new SetCardInfo("Azorius Chancery", 233, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); cards.add(new SetCardInfo("Azorius Guildgate", 234, Rarity.COMMON, mage.cards.a.AzoriusGuildgate.class)); - cards.add(new SetCardInfo("Azorius Signet", 196, Rarity.COMMON, mage.cards.a.AzoriusSignet.class)); + cards.add(new SetCardInfo("Azorius Signet", 196, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class)); cards.add(new SetCardInfo("Baloth Woodcrasher", 130, Rarity.UNCOMMON, mage.cards.b.BalothWoodcrasher.class)); cards.add(new SetCardInfo("Banishing Stroke", 63, Rarity.UNCOMMON, mage.cards.b.BanishingStroke.class)); cards.add(new SetCardInfo("Bant Charm", 169, Rarity.UNCOMMON, mage.cards.b.BantCharm.class)); @@ -87,7 +87,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Dictate of Kruphix", 86, Rarity.RARE, mage.cards.d.DictateOfKruphix.class)); cards.add(new SetCardInfo("Dimir Aqueduct", 242, Rarity.UNCOMMON, mage.cards.d.DimirAqueduct.class)); cards.add(new SetCardInfo("Dimir Guildgate", 243, Rarity.COMMON, mage.cards.d.DimirGuildgate.class)); - cards.add(new SetCardInfo("Dimir Signet", 203, Rarity.COMMON, mage.cards.d.DimirSignet.class)); + cards.add(new SetCardInfo("Dimir Signet", 203, Rarity.UNCOMMON, mage.cards.d.DimirSignet.class)); cards.add(new SetCardInfo("Dismal Backwater", 244, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Dismantling Blow", 66, Rarity.COMMON, mage.cards.d.DismantlingBlow.class)); cards.add(new SetCardInfo("Djinn of Wishes", 87, Rarity.RARE, mage.cards.d.DjinnOfWishes.class)); @@ -159,7 +159,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Isolated Watchtower", 59, Rarity.RARE, mage.cards.i.IsolatedWatchtower.class)); cards.add(new SetCardInfo("Izzet Boilerworks", 256, Rarity.UNCOMMON, mage.cards.i.IzzetBoilerworks.class)); cards.add(new SetCardInfo("Izzet Guildgate", 257, Rarity.COMMON, mage.cards.i.IzzetGuildgate.class)); - cards.add(new SetCardInfo("Izzet Signet", 207, Rarity.COMMON, mage.cards.i.IzzetSignet.class)); + cards.add(new SetCardInfo("Izzet Signet", 207, Rarity.UNCOMMON, mage.cards.i.IzzetSignet.class)); cards.add(new SetCardInfo("Jeskai Infiltrator", 93, Rarity.RARE, mage.cards.j.JeskaiInfiltrator.class)); cards.add(new SetCardInfo("Jund Panorama", 258, Rarity.COMMON, mage.cards.j.JundPanorama.class)); cards.add(new SetCardInfo("Jungle Hollow", 259, Rarity.COMMON, mage.cards.j.JungleHollow.class)); @@ -259,7 +259,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Serra Avatar", 73, Rarity.MYTHIC, mage.cards.s.SerraAvatar.class)); cards.add(new SetCardInfo("Sharding Sphinx", 101, Rarity.RARE, mage.cards.s.ShardingSphinx.class)); cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); - cards.add(new SetCardInfo("Sigiled Starfish", 102, Rarity.COMMON, mage.cards.s.SigiledStarfish.class)); + cards.add(new SetCardInfo("Sigiled Starfish", 102, Rarity.UNCOMMON, mage.cards.s.SigiledStarfish.class)); cards.add(new SetCardInfo("Silent Sentinel", 75, Rarity.RARE, mage.cards.s.SilentSentinel.class)); cards.add(new SetCardInfo("Silent-Blade Oni", 191, Rarity.RARE, mage.cards.s.SilentBladeOni.class)); cards.add(new SetCardInfo("Simic Growth Chamber", 282, Rarity.UNCOMMON, mage.cards.s.SimicGrowthChamber.class)); diff --git a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java index 1e5a9fcb250..f7a15336120 100644 --- a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java +++ b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java @@ -22,98 +22,237 @@ public final class GuildsOfRavnica extends ExpansionSet { this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + cards.add(new SetCardInfo("Affectionate Indrik", 121, Rarity.UNCOMMON, mage.cards.a.AffectionateIndrik.class)); cards.add(new SetCardInfo("Arboretum Elemental", 122, Rarity.UNCOMMON, mage.cards.a.ArboretumElemental.class)); + cards.add(new SetCardInfo("Arclight Phoenix", 91, Rarity.MYTHIC, mage.cards.a.ArclightPhoenix.class)); cards.add(new SetCardInfo("Artful Takedown", 151, Rarity.COMMON, mage.cards.a.ArtfulTakedown.class)); cards.add(new SetCardInfo("Assassin's Trophy", 152, Rarity.RARE, mage.cards.a.AssassinsTrophy.class)); + cards.add(new SetCardInfo("Assure // Assemble", 221, Rarity.RARE, mage.cards.a.AssureAssemble.class)); cards.add(new SetCardInfo("Attendant of Vraska", 271, Rarity.UNCOMMON, mage.cards.a.AttendantOfVraska.class)); + cards.add(new SetCardInfo("Aurelia, Exemplar of Justice", 153, Rarity.MYTHIC, mage.cards.a.AureliaExemplarOfJustice.class)); cards.add(new SetCardInfo("Barging Sergeant", 92, Rarity.COMMON, mage.cards.b.BargingSergeant.class)); + cards.add(new SetCardInfo("Barrier of Bones", 61, Rarity.COMMON, mage.cards.b.BarrierOfBones.class)); + cards.add(new SetCardInfo("Bartizan Bats", 62, Rarity.COMMON, mage.cards.b.BartizanBats.class)); + cards.add(new SetCardInfo("Beacon Bolt", 154, Rarity.UNCOMMON, mage.cards.b.BeaconBolt.class)); cards.add(new SetCardInfo("Beast Whisperer", 123, Rarity.RARE, mage.cards.b.BeastWhisperer.class)); cards.add(new SetCardInfo("Blade Instructor", 1, Rarity.COMMON, mage.cards.b.BladeInstructor.class)); + cards.add(new SetCardInfo("Blood Operative", 63, Rarity.RARE, mage.cards.b.BloodOperative.class)); + cards.add(new SetCardInfo("Book Devourer", 93, Rarity.UNCOMMON, mage.cards.b.BookDevourer.class)); cards.add(new SetCardInfo("Boros Challenger", 156, Rarity.UNCOMMON, mage.cards.b.BorosChallenger.class)); cards.add(new SetCardInfo("Boros Guildgate", 243, Rarity.COMMON, mage.cards.b.BorosGuildgate.class)); cards.add(new SetCardInfo("Boros Guildgate", 244, Rarity.COMMON, mage.cards.b.BorosGuildgate.class)); cards.add(new SetCardInfo("Boros Locket", 231, Rarity.COMMON, mage.cards.b.BorosLocket.class)); cards.add(new SetCardInfo("Bounty Agent", 2, Rarity.RARE, mage.cards.b.BountyAgent.class)); + cards.add(new SetCardInfo("Burglar Rat", 64, Rarity.COMMON, mage.cards.b.BurglarRat.class)); + cards.add(new SetCardInfo("Camaraderie", 157, Rarity.RARE, mage.cards.c.Camaraderie.class)); + cards.add(new SetCardInfo("Centaur Peacemaker", 158, Rarity.COMMON, mage.cards.c.CentaurPeacemaker.class)); + cards.add(new SetCardInfo("Chance for Glory", 159, Rarity.MYTHIC, mage.cards.c.ChanceForGlory.class)); + cards.add(new SetCardInfo("Charnel Troll", 160, Rarity.RARE, mage.cards.c.CharnelTroll.class)); cards.add(new SetCardInfo("Chemister's Insight", 32, Rarity.UNCOMMON, mage.cards.c.ChemistersInsight.class)); + cards.add(new SetCardInfo("Child of Night", 65, Rarity.COMMON, mage.cards.c.ChildOfNight.class)); cards.add(new SetCardInfo("Chromatic Lantern", 233, Rarity.RARE, mage.cards.c.ChromaticLantern.class)); + cards.add(new SetCardInfo("Circuitous Route", 125, Rarity.UNCOMMON, mage.cards.c.CircuitousRoute.class)); + cards.add(new SetCardInfo("Citywatch Sphinx", 33, Rarity.UNCOMMON, mage.cards.c.CitywatchSphinx.class)); + cards.add(new SetCardInfo("Citywide Bust", 4, Rarity.RARE, mage.cards.c.CitywideBust.class)); + cards.add(new SetCardInfo("Command the Storm", 94, Rarity.COMMON, mage.cards.c.CommandTheStorm.class)); + cards.add(new SetCardInfo("Conclave Cavalier", 161, Rarity.UNCOMMON, mage.cards.c.ConclaveCavalier.class)); + cards.add(new SetCardInfo("Conclave Guildmage", 162, Rarity.UNCOMMON, mage.cards.c.ConclaveGuildmage.class)); cards.add(new SetCardInfo("Conclave Tribunal", 6, Rarity.UNCOMMON, mage.cards.c.ConclaveTribunal.class)); + cards.add(new SetCardInfo("Connive // Concoct", 222, Rarity.RARE, mage.cards.c.ConniveConcoct.class)); + cards.add(new SetCardInfo("Crackling Drake", 163, Rarity.UNCOMMON, mage.cards.c.CracklingDrake.class)); + cards.add(new SetCardInfo("Creeping Chill", 66, Rarity.UNCOMMON, mage.cards.c.CreepingChill.class)); + cards.add(new SetCardInfo("Crushing Canopy", 126, Rarity.COMMON, mage.cards.c.CrushingCanopy.class)); + cards.add(new SetCardInfo("Darkblade Agent", 164, Rarity.COMMON, mage.cards.d.DarkbladeAgent.class)); + cards.add(new SetCardInfo("Dawn of Hope", 8, Rarity.RARE, mage.cards.d.DawnOfHope.class)); + cards.add(new SetCardInfo("Dazzling Lights", 34, Rarity.COMMON, mage.cards.d.DazzlingLights.class)); + cards.add(new SetCardInfo("Dead Weight", 67, Rarity.COMMON, mage.cards.d.DeadWeight.class)); cards.add(new SetCardInfo("Deadly Visit", 68, Rarity.COMMON, mage.cards.d.DeadlyVisit.class)); cards.add(new SetCardInfo("Deafening Clarion", 165, Rarity.RARE, mage.cards.d.DeafeningClarion.class)); + cards.add(new SetCardInfo("Devkarin Dissident", 127, Rarity.COMMON, mage.cards.d.DevkarinDissident.class)); cards.add(new SetCardInfo("Dimir Guildgate", 245, Rarity.COMMON, mage.cards.d.DimirGuildgate.class)); cards.add(new SetCardInfo("Dimir Guildgate", 246, Rarity.COMMON, mage.cards.d.DimirGuildgate.class)); cards.add(new SetCardInfo("Dimir Informant", 36, Rarity.COMMON, mage.cards.d.DimirInformant.class)); cards.add(new SetCardInfo("Dimir Locket", 234, Rarity.COMMON, mage.cards.d.DimirLocket.class)); + cards.add(new SetCardInfo("Dimir Spybug", 166, Rarity.UNCOMMON, mage.cards.d.DimirSpybug.class)); cards.add(new SetCardInfo("Direct Current", 96, Rarity.COMMON, mage.cards.d.DirectCurrent.class)); + cards.add(new SetCardInfo("Discovery // Dispersal", 223, Rarity.UNCOMMON, mage.cards.d.DiscoveryDispersal.class)); cards.add(new SetCardInfo("Disdainful Stroke", 37, Rarity.COMMON, mage.cards.d.DisdainfulStroke.class)); + cards.add(new SetCardInfo("Disinformation Campaign", 167, Rarity.UNCOMMON, mage.cards.d.DisinformationCampaign.class)); cards.add(new SetCardInfo("District Guide", 128, Rarity.UNCOMMON, mage.cards.d.DistrictGuide.class)); + cards.add(new SetCardInfo("Divine Visitation", 10, Rarity.MYTHIC, mage.cards.d.DivineVisitation.class)); + cards.add(new SetCardInfo("Doom Whisperer", 69, Rarity.MYTHIC, mage.cards.d.DoomWhisperer.class)); + cards.add(new SetCardInfo("Douser of Lights", 70, Rarity.COMMON, mage.cards.d.DouserOfLights.class)); cards.add(new SetCardInfo("Dream Eater", 38, Rarity.MYTHIC, mage.cards.d.DreamEater.class)); + cards.add(new SetCardInfo("Drowned Secrets", 39, Rarity.RARE, mage.cards.d.DrownedSecrets.class)); + cards.add(new SetCardInfo("Electrostatic Field", 97, Rarity.UNCOMMON, mage.cards.e.ElectrostaticField.class)); cards.add(new SetCardInfo("Emmara, Soul of the Accord", 168, Rarity.RARE, mage.cards.e.EmmaraSoulOfTheAccord.class)); + cards.add(new SetCardInfo("Enhanced Surveillance", 40, Rarity.UNCOMMON, mage.cards.e.EnhancedSurveillance.class)); + cards.add(new SetCardInfo("Erratic Cyclops", 98, Rarity.RARE, mage.cards.e.ErraticCyclops.class)); + cards.add(new SetCardInfo("Erstwhile Trooper", 169, Rarity.COMMON, mage.cards.e.ErstwhileTrooper.class)); + cards.add(new SetCardInfo("Etrata, the Silencer", 170, Rarity.RARE, mage.cards.e.EtrataTheSilencer.class)); cards.add(new SetCardInfo("Expansion // Explosion", 224, Rarity.RARE, mage.cards.e.ExpansionExplosion.class)); + cards.add(new SetCardInfo("Fearless Halberdier", 100, Rarity.COMMON, mage.cards.f.FearlessHalberdier.class)); cards.add(new SetCardInfo("Find // Finality", 225, Rarity.RARE, mage.cards.f.FindFinality.class)); + cards.add(new SetCardInfo("Fire Urchin", 101, Rarity.COMMON, mage.cards.f.FireUrchin.class)); cards.add(new SetCardInfo("Firemind's Research", 171, Rarity.RARE, mage.cards.f.FiremindsResearch.class)); + cards.add(new SetCardInfo("Flight of Equenauts", 11, Rarity.UNCOMMON, mage.cards.f.FlightOfEquenauts.class)); + cards.add(new SetCardInfo("Flower // Flourish", 226, Rarity.UNCOMMON, mage.cards.f.FlowerFlourish.class)); cards.add(new SetCardInfo("Forest", 264, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fresh-Faced Recruit", 216, Rarity.COMMON, mage.cards.f.FreshFacedRecruit.class)); + cards.add(new SetCardInfo("Garrison Sergeant", 172, Rarity.COMMON, mage.cards.g.GarrisonSergeant.class)); + cards.add(new SetCardInfo("Gatekeeper Gargoyle", 235, Rarity.UNCOMMON, mage.cards.g.GatekeeperGargoyle.class)); cards.add(new SetCardInfo("Gateway Plaza", 247, Rarity.COMMON, mage.cards.g.GatewayPlaza.class)); + cards.add(new SetCardInfo("Generous Stray", 129, Rarity.COMMON, mage.cards.g.GenerousStray.class)); + cards.add(new SetCardInfo("Gird for Battle", 12, Rarity.UNCOMMON, mage.cards.g.GirdForBattle.class)); + cards.add(new SetCardInfo("Glaive of the Guildpact", 236, Rarity.UNCOMMON, mage.cards.g.GlaiveOfTheGuildpact.class)); + cards.add(new SetCardInfo("Glowspore Shaman", 173, Rarity.UNCOMMON, mage.cards.g.GlowsporeShaman.class)); + cards.add(new SetCardInfo("Goblin Banneret", 102, Rarity.UNCOMMON, mage.cards.g.GoblinBanneret.class)); cards.add(new SetCardInfo("Goblin Cratermaker", 103, Rarity.UNCOMMON, mage.cards.g.GoblinCratermaker.class)); cards.add(new SetCardInfo("Goblin Electromancer", 174, Rarity.COMMON, mage.cards.g.GoblinElectromancer.class)); + cards.add(new SetCardInfo("Goblin Locksmith", 104, Rarity.COMMON, mage.cards.g.GoblinLocksmith.class)); + cards.add(new SetCardInfo("Golgari Findbroker", 175, Rarity.UNCOMMON, mage.cards.g.GolgariFindbroker.class)); cards.add(new SetCardInfo("Golgari Guildgate", 248, Rarity.COMMON, mage.cards.g.GolgariGuildgate.class)); cards.add(new SetCardInfo("Golgari Guildgate", 249, Rarity.COMMON, mage.cards.g.GolgariGuildgate.class)); cards.add(new SetCardInfo("Golgari Locket", 237, Rarity.COMMON, mage.cards.g.GolgariLocket.class)); + cards.add(new SetCardInfo("Golgari Raiders", 130, Rarity.UNCOMMON, mage.cards.g.GolgariRaiders.class)); + cards.add(new SetCardInfo("Grappling Sundew", 131, Rarity.UNCOMMON, mage.cards.g.GrapplingSundew.class)); + cards.add(new SetCardInfo("Gruesome Menagerie", 71, Rarity.RARE, mage.cards.g.GruesomeMenagerie.class)); cards.add(new SetCardInfo("Guild Summit", 41, Rarity.UNCOMMON, mage.cards.g.GuildSummit.class)); + cards.add(new SetCardInfo("Haazda Marshal", 13, Rarity.UNCOMMON, mage.cards.h.HaazdaMarshal.class)); cards.add(new SetCardInfo("Hammer Dropper", 176, Rarity.COMMON, mage.cards.h.HammerDropper.class)); + cards.add(new SetCardInfo("Hatchery Spider", 132, Rarity.RARE, mage.cards.h.HatcherySpider.class)); cards.add(new SetCardInfo("Healer's Hawk", 14, Rarity.COMMON, mage.cards.h.HealersHawk.class)); + cards.add(new SetCardInfo("Hellkite Whelp", 106, Rarity.UNCOMMON, mage.cards.h.HellkiteWhelp.class)); + cards.add(new SetCardInfo("Hired Poisoner", 72, Rarity.COMMON, mage.cards.h.HiredPoisoner.class)); + cards.add(new SetCardInfo("Hitchclaw Recluse", 133, Rarity.COMMON, mage.cards.h.HitchclawRecluse.class)); + cards.add(new SetCardInfo("House Guildmage", 177, Rarity.UNCOMMON, mage.cards.h.HouseGuildmage.class)); + cards.add(new SetCardInfo("Hunted Witness", 15, Rarity.COMMON, mage.cards.h.HuntedWitness.class)); cards.add(new SetCardInfo("Hypothesizzle", 178, Rarity.COMMON, mage.cards.h.Hypothesizzle.class)); cards.add(new SetCardInfo("Impervious Greatwurm", 273, Rarity.MYTHIC, mage.cards.i.ImperviousGreatwurm.class)); + cards.add(new SetCardInfo("Inescapable Blaze", 107, Rarity.UNCOMMON, mage.cards.i.InescapableBlaze.class)); + cards.add(new SetCardInfo("Integrity // Intervention", 227, Rarity.UNCOMMON, mage.cards.i.IntegrityIntervention.class)); + cards.add(new SetCardInfo("Invert // Invent", 228, Rarity.UNCOMMON, mage.cards.i.InvertInvent.class)); + cards.add(new SetCardInfo("Inspiring Unicorn", 16, Rarity.UNCOMMON, mage.cards.i.InspiringUnicorn.class)); cards.add(new SetCardInfo("Ionize", 179, Rarity.RARE, mage.cards.i.Ionize.class)); + cards.add(new SetCardInfo("Ironshell Beetle", 134, Rarity.COMMON, mage.cards.i.IronshellBeetle.class)); cards.add(new SetCardInfo("Island", 261, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Izoni, Thousand-Eyed", 180, Rarity.RARE, mage.cards.i.IzoniThousandEyed.class)); cards.add(new SetCardInfo("Izzet Guildgate", 251, Rarity.COMMON, mage.cards.i.IzzetGuildgate.class)); cards.add(new SetCardInfo("Izzet Guildgate", 252, Rarity.COMMON, mage.cards.i.IzzetGuildgate.class)); cards.add(new SetCardInfo("Izzet Locket", 238, Rarity.COMMON, mage.cards.i.IzzetLocket.class)); + cards.add(new SetCardInfo("Join Shields", 181, Rarity.UNCOMMON, mage.cards.j.JoinShields.class)); + cards.add(new SetCardInfo("Justice Strike", 182, Rarity.UNCOMMON, mage.cards.j.JusticeStrike.class)); + cards.add(new SetCardInfo("Knight of Autumn", 183, Rarity.RARE, mage.cards.k.KnightOfAutumn.class)); + cards.add(new SetCardInfo("Kraul Foragers", 135, Rarity.COMMON, mage.cards.k.KraulForagers.class)); + cards.add(new SetCardInfo("Kraul Harpooner", 136, Rarity.UNCOMMON, mage.cards.k.KraulHarpooner.class)); + cards.add(new SetCardInfo("Lava Coil", 108, Rarity.UNCOMMON, mage.cards.l.LavaCoil.class)); + cards.add(new SetCardInfo("Lazav, the Multifarious", 184, Rarity.MYTHIC, mage.cards.l.LazavTheMultifarious.class)); + cards.add(new SetCardInfo("League Guildmage", 185, Rarity.UNCOMMON, mage.cards.l.LeagueGuildmage.class)); + cards.add(new SetCardInfo("Ledev Champion", 186, Rarity.UNCOMMON, mage.cards.l.LedevChampion.class)); + cards.add(new SetCardInfo("Ledev Guardian", 18, Rarity.COMMON, mage.cards.l.LedevGuardian.class)); + cards.add(new SetCardInfo("Legion Guildmage", 187, Rarity.UNCOMMON, mage.cards.l.LegionGuildmage.class)); cards.add(new SetCardInfo("Legion Warboss", 109, Rarity.RARE, mage.cards.l.LegionWarboss.class)); + cards.add(new SetCardInfo("Light of the Legion", 19, Rarity.RARE, mage.cards.l.LightOfTheLegion.class)); + cards.add(new SetCardInfo("Lotleth Giant", 74, Rarity.UNCOMMON, mage.cards.l.LotlethGiant.class)); + cards.add(new SetCardInfo("Loxodon Restorer", 20, Rarity.COMMON, mage.cards.l.LoxodonRestorer.class)); + cards.add(new SetCardInfo("Luminous Bonds", 21, Rarity.COMMON, mage.cards.l.LuminousBonds.class)); + cards.add(new SetCardInfo("Maniacal Rage", 110, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); cards.add(new SetCardInfo("March of the Multitudes", 188, Rarity.MYTHIC, mage.cards.m.MarchOfTheMultitudes.class)); + cards.add(new SetCardInfo("Mausoleum Secrets", 75, Rarity.RARE, mage.cards.m.MausoleumSecrets.class)); + cards.add(new SetCardInfo("Maximize Altitude", 43, Rarity.COMMON, mage.cards.m.MaximizeAltitude.class)); + cards.add(new SetCardInfo("Maximize Velocity", 111, Rarity.COMMON, mage.cards.m.MaximizeVelocity.class)); + cards.add(new SetCardInfo("Midnight Reaper", 77, Rarity.RARE, mage.cards.m.MidnightReaper.class)); + cards.add(new SetCardInfo("Might of the Masses", 137, Rarity.UNCOMMON, mage.cards.m.MightOfTheMasses.class)); + cards.add(new SetCardInfo("Mission Briefing", 44, Rarity.RARE, mage.cards.m.MissionBriefing.class)); + cards.add(new SetCardInfo("Molderhulk", 190, Rarity.UNCOMMON, mage.cards.m.Molderhulk.class)); cards.add(new SetCardInfo("Moodmark Painter", 78, Rarity.COMMON, mage.cards.m.MoodmarkPainter.class)); cards.add(new SetCardInfo("Mountain", 263, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Murmuring Mystic", 45, Rarity.UNCOMMON, mage.cards.m.MurmuringMystic.class)); + cards.add(new SetCardInfo("Muse Drake", 46, Rarity.COMMON, mage.cards.m.MuseDrake.class)); cards.add(new SetCardInfo("Narcomoeba", 47, Rarity.RARE, mage.cards.n.Narcomoeba.class)); cards.add(new SetCardInfo("Necrotic Wound", 79, Rarity.UNCOMMON, mage.cards.n.NecroticWound.class)); - cards.add(new SetCardInfo("Nightveil Faerie", 48, Rarity.UNCOMMON, mage.cards.n.NightveilFaerie.class)); + cards.add(new SetCardInfo("Never Happened", 80, Rarity.COMMON, mage.cards.n.NeverHappened.class)); + cards.add(new SetCardInfo("Nightveil Predator", 191, Rarity.UNCOMMON, mage.cards.n.NightveilPredator.class)); + cards.add(new SetCardInfo("Nightveil Sprite", 48, Rarity.UNCOMMON, mage.cards.n.NightveilSprite.class)); cards.add(new SetCardInfo("Niv-Mizzet, Parun", 192, Rarity.RARE, mage.cards.n.NivMizzetParun.class)); + cards.add(new SetCardInfo("Notion Rain", 193, Rarity.COMMON, mage.cards.n.NotionRain.class)); cards.add(new SetCardInfo("Nullhide Ferox", 138, Rarity.MYTHIC, mage.cards.n.NullhideFerox.class)); + cards.add(new SetCardInfo("Ochran Assassin", 194, Rarity.UNCOMMON, mage.cards.o.OchranAssassin.class)); + cards.add(new SetCardInfo("Omnispell Adept", 49, Rarity.RARE, mage.cards.o.OmnispellAdept.class)); cards.add(new SetCardInfo("Overgrown Tomb", 253, Rarity.RARE, mage.cards.o.OvergrownTomb.class)); + cards.add(new SetCardInfo("Pack's Favor", 139, Rarity.COMMON, mage.cards.p.PacksFavor.class)); + cards.add(new SetCardInfo("Parhelion Patrol", 22, Rarity.COMMON, mage.cards.p.ParhelionPatrol.class)); + cards.add(new SetCardInfo("Passwall Adept", 50, Rarity.COMMON, mage.cards.p.PasswallAdept.class)); + cards.add(new SetCardInfo("Pause for Reflection", 140, Rarity.COMMON, mage.cards.p.PauseForReflection.class)); + cards.add(new SetCardInfo("Piston-Fist Cyclops", 217, Rarity.COMMON, mage.cards.p.PistonFistCyclops.class)); + cards.add(new SetCardInfo("Pitiless Gorgon", 218, Rarity.COMMON, mage.cards.p.PitilessGorgon.class)); cards.add(new SetCardInfo("Plains", 260, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Prey Upon", 143, Rarity.COMMON, mage.cards.p.PreyUpon.class)); + cards.add(new SetCardInfo("Price of Fame", 83, Rarity.UNCOMMON, mage.cards.p.PriceOfFame.class)); cards.add(new SetCardInfo("Quasiduplicate", 51, Rarity.RARE, mage.cards.q.Quasiduplicate.class)); cards.add(new SetCardInfo("Radical Idea", 52, Rarity.COMMON, mage.cards.r.RadicalIdea.class)); - cards.add(new SetCardInfo("Rain of Notions", 193, Rarity.COMMON, mage.cards.r.RainOfNotions.class)); cards.add(new SetCardInfo("Ral's Dispersal", 266, Rarity.RARE, mage.cards.r.RalsDispersal.class)); cards.add(new SetCardInfo("Ral's Staticaster", 268, Rarity.UNCOMMON, mage.cards.r.RalsStaticaster.class)); cards.add(new SetCardInfo("Ral, Caller of Storms", 265, Rarity.MYTHIC, mage.cards.r.RalCallerOfStorms.class)); cards.add(new SetCardInfo("Ral, Izzet Viceroy", 195, Rarity.MYTHIC, mage.cards.r.RalIzzetViceroy.class)); cards.add(new SetCardInfo("Response // Resurgence", 229, Rarity.RARE, mage.cards.r.ResponseResurgence.class)); + cards.add(new SetCardInfo("Rhizome Lurcher", 196, Rarity.COMMON, mage.cards.r.RhizomeLurcher.class)); + cards.add(new SetCardInfo("Righteous Blow", 23, Rarity.COMMON, mage.cards.r.RighteousBlow.class)); + cards.add(new SetCardInfo("Risk Factor", 113, Rarity.RARE, mage.cards.r.RiskFactor.class)); + cards.add(new SetCardInfo("Ritual of Soot", 84, Rarity.RARE, mage.cards.r.RitualOfSoot.class)); + cards.add(new SetCardInfo("Roc Charger", 24, Rarity.UNCOMMON, mage.cards.r.RocCharger.class)); cards.add(new SetCardInfo("Rosemane Centaur", 197, Rarity.COMMON, mage.cards.r.RosemaneCentaur.class)); + cards.add(new SetCardInfo("Rubblebelt Boar", 114, Rarity.COMMON, mage.cards.r.RubblebeltBoar.class)); cards.add(new SetCardInfo("Runaway Steam-Kin", 115, Rarity.RARE, mage.cards.r.RunawaySteamKin.class)); cards.add(new SetCardInfo("Sacred Foundry", 254, Rarity.RARE, mage.cards.s.SacredFoundry.class)); - cards.add(new SetCardInfo("Secrets of the Mausoleum", 75, Rarity.RARE, mage.cards.s.SecretsOfTheMausoleum.class)); cards.add(new SetCardInfo("Selesnya Guildgate", 255, Rarity.COMMON, mage.cards.s.SelesnyaGuildgate.class)); cards.add(new SetCardInfo("Selesnya Guildgate", 256, Rarity.COMMON, mage.cards.s.SelesnyaGuildgate.class)); cards.add(new SetCardInfo("Selesnya Locket", 240, Rarity.COMMON, mage.cards.s.SelesnyaLocket.class)); + cards.add(new SetCardInfo("Siege Wurm", 144, Rarity.COMMON, mage.cards.s.SiegeWurm.class)); + cards.add(new SetCardInfo("Silent Dart", 241, Rarity.UNCOMMON, mage.cards.s.SilentDart.class)); cards.add(new SetCardInfo("Sinister Sabotage", 54, Rarity.UNCOMMON, mage.cards.s.SinisterSabotage.class)); + cards.add(new SetCardInfo("Skyknight Legionnaire", 198, Rarity.COMMON, mage.cards.s.SkyknightLegionnaire.class)); cards.add(new SetCardInfo("Sonic Assault", 199, Rarity.COMMON, mage.cards.s.SonicAssault.class)); + cards.add(new SetCardInfo("Spinal Centipede", 86, Rarity.COMMON, mage.cards.s.SpinalCentipede.class)); + cards.add(new SetCardInfo("Sprouting Renewal", 145, Rarity.UNCOMMON, mage.cards.s.SproutingRenewal.class)); cards.add(new SetCardInfo("Status // Statue", 230, Rarity.UNCOMMON, mage.cards.s.StatusStatue.class)); cards.add(new SetCardInfo("Steam Vents", 257, Rarity.RARE, mage.cards.s.SteamVents.class)); cards.add(new SetCardInfo("Sumala Woodshaper", 200, Rarity.COMMON, mage.cards.s.SumalaWoodshaper.class)); cards.add(new SetCardInfo("Sunhome Stalwart", 26, Rarity.UNCOMMON, mage.cards.s.SunhomeStalwart.class)); + cards.add(new SetCardInfo("Sure Strike", 118, Rarity.COMMON, mage.cards.s.SureStrike.class)); cards.add(new SetCardInfo("Swamp", 262, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swarm Guildmage", 201, Rarity.UNCOMMON, mage.cards.s.SwarmGuildmage.class)); + cards.add(new SetCardInfo("Swathcutter Giant", 202, Rarity.UNCOMMON, mage.cards.s.SwathcutterGiant.class)); + cards.add(new SetCardInfo("Swiftblade Vindicator", 203, Rarity.RARE, mage.cards.s.SwiftbladeVindicator.class)); + cards.add(new SetCardInfo("Sworn Companions", 27, Rarity.COMMON, mage.cards.s.SwornCompanions.class)); + cards.add(new SetCardInfo("Tajic, Legion's Edge", 204, Rarity.RARE, mage.cards.t.TajicLegionsEdge.class)); cards.add(new SetCardInfo("Temple Garden", 258, Rarity.RARE, mage.cards.t.TempleGarden.class)); cards.add(new SetCardInfo("Thought Erasure", 206, Rarity.UNCOMMON, mage.cards.t.ThoughtErasure.class)); + cards.add(new SetCardInfo("Thoughtbound Phantasm", 55, Rarity.UNCOMMON, mage.cards.t.ThoughtboundPhantasm.class)); + cards.add(new SetCardInfo("Trostani Discordant", 208, Rarity.MYTHIC, mage.cards.t.TrostaniDiscordant.class)); + cards.add(new SetCardInfo("Truefire Captain", 209, Rarity.UNCOMMON, mage.cards.t.TruefireCaptain.class)); + cards.add(new SetCardInfo("Undercity Uprising", 210, Rarity.COMMON, mage.cards.u.UndercityUprising.class)); cards.add(new SetCardInfo("Underrealm Lich", 211, Rarity.MYTHIC, mage.cards.u.UnderrealmLich.class)); cards.add(new SetCardInfo("Unexplained Disappearance", 56, Rarity.COMMON, mage.cards.u.UnexplainedDisappearance.class)); + cards.add(new SetCardInfo("Urban Utopia", 146, Rarity.COMMON, mage.cards.u.UrbanUtopia.class)); + cards.add(new SetCardInfo("Veiled Shade", 88, Rarity.COMMON, mage.cards.v.VeiledShade.class)); + cards.add(new SetCardInfo("Venerated Loxodon", 30, Rarity.RARE, mage.cards.v.VeneratedLoxodon.class)); + cards.add(new SetCardInfo("Vernadi Shieldmate", 219, Rarity.COMMON, mage.cards.v.VernadiShieldmate.class)); cards.add(new SetCardInfo("Vivid Revival", 148, Rarity.RARE, mage.cards.v.VividRevival.class)); cards.add(new SetCardInfo("Vraska's Stoneglare", 272, Rarity.RARE, mage.cards.v.VraskasStoneglare.class)); + cards.add(new SetCardInfo("Vraska, Golgari Queen", 213, Rarity.MYTHIC, mage.cards.v.VraskaGolgariQueen.class)); cards.add(new SetCardInfo("Vraska, Regal Gorgon", 269, Rarity.MYTHIC, mage.cards.v.VraskaRegalGorgon.class)); + cards.add(new SetCardInfo("Wall of Mist", 58, Rarity.COMMON, mage.cards.w.WallOfMist.class)); + cards.add(new SetCardInfo("Wand of Vertebrae", 242, Rarity.UNCOMMON, mage.cards.w.WandOfVertebrae.class)); cards.add(new SetCardInfo("Wary Okapi", 149, Rarity.COMMON, mage.cards.w.WaryOkapi.class)); + cards.add(new SetCardInfo("Watcher in the Mist", 59, Rarity.COMMON, mage.cards.w.WatcherInTheMist.class)); cards.add(new SetCardInfo("Watery Grave", 259, Rarity.RARE, mage.cards.w.WateryGrave.class)); + cards.add(new SetCardInfo("Wee Dragonauts", 214, Rarity.UNCOMMON, mage.cards.w.WeeDragonauts.class)); cards.add(new SetCardInfo("Whisper Agent", 220, Rarity.COMMON, mage.cards.w.WhisperAgent.class)); - cards.add(new SetCardInfo("Whispering Spy", 90, Rarity.UNCOMMON, mage.cards.w.WhisperingSpy.class)); + cards.add(new SetCardInfo("Whispering Snitch", 90, Rarity.UNCOMMON, mage.cards.w.WhisperingSnitch.class)); + cards.add(new SetCardInfo("Wild Ceratok", 150, Rarity.COMMON, mage.cards.w.WildCeratok.class)); + cards.add(new SetCardInfo("Wishcoin Crab", 60, Rarity.COMMON, mage.cards.w.WishcoinCrab.class)); + cards.add(new SetCardInfo("Wojek Bodyguard", 120, Rarity.COMMON, mage.cards.w.WojekBodyguard.class)); + cards.add(new SetCardInfo("Worldsoul Colossus", 215, Rarity.UNCOMMON, mage.cards.w.WorldsoulColossus.class)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java index 3950fa971b1..5427cb84607 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java @@ -7,7 +7,6 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.permanent.Permanent; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -162,7 +161,6 @@ public class BestowTest extends CardTestPlayerBase { * Bestowed creature can be used to sacrifice a creature for the Away part. * http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/513828-bestow-far-away */ - @Ignore // TODO: make fused targeting support @Test public void bestowWithFusedSpell() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java index ff27aed08cb..7a802e59d0f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.oneshot.exile; import mage.abilities.keyword.ReachAbility; @@ -116,4 +115,36 @@ public class ExileAndReturnTest extends CardTestPlayerBase { assertHandCount(playerB, 3); // 1 from Turn 2 and 2 from Frog Tongue } + + @Test + public void testExileAndReturnIfTawnosLeftBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); + // You may choose not to untap Tawnos's Coffin during your untap step. + // {3}, {T}: Exile target creature and all Auras attached to it. Note the number and kind of counters that were on that creature. + // When Tawnos's Coffin leaves the battlefield or becomes untapped, return the exiled card to the battlefield under + // its owner's control tapped with the noted number and kind of counters on it, and if you do, return the exiled Aura + // cards to the battlefield under their owner's control attached to that permanent. + addCard(Zone.HAND, playerA, "Tawnos's Coffin"); // Artifact {4} + + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + addCard(Zone.HAND, playerB, "Disenchant"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tawnos's Coffin"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}", "Silvercoat Lion"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Disenchant", "Tawnos's Coffin"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerB, "Disenchant", 1); + + assertPermanentCount(playerA, "Tawnos's Coffin", 0); + assertGraveyardCount(playerA, "Tawnos's Coffin", 1); + + assertPermanentCount(playerB, "Silvercoat Lion", 1); + + } } diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index 1ce4f4b56d2..b65f1721739 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -86,10 +86,10 @@ public interface MageObject extends MageItem, Serializable { void setZoneChangeCounter(int value, Game game); - default boolean isHistoric(){ + default boolean isHistoric() { return getCardType().contains(CardType.ARTIFACT) || getSuperType().contains(SuperType.LEGENDARY) - || hasSubtype(SubType.SAGA, null ); + || hasSubtype(SubType.SAGA, null); } default boolean isCreature() { @@ -116,6 +116,10 @@ public interface MageObject extends MageItem, Serializable { return getCardType().contains(CardType.SORCERY); } + default boolean isInstantOrSorcery() { + return this.isInstant() || this.isSorcery(); + } + default boolean isPlaneswalker() { return getCardType().contains(CardType.PLANESWALKER); } diff --git a/Mage/src/main/java/mage/abilities/Mode.java b/Mage/src/main/java/mage/abilities/Mode.java index 0c336d121ad..02e9d9144e5 100644 --- a/Mage/src/main/java/mage/abilities/Mode.java +++ b/Mage/src/main/java/mage/abilities/Mode.java @@ -1,9 +1,10 @@ - package mage.abilities; import java.io.Serializable; import java.util.UUID; +import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; +import mage.target.Target; import mage.target.Targets; /** @@ -13,16 +14,23 @@ import mage.target.Targets; public class Mode implements Serializable { protected UUID id; - protected Targets targets; - protected Effects effects; + protected final Targets targets; + protected final Effects effects; public Mode() { + this((Effect) null); + } + + public Mode(Effect effect) { this.id = UUID.randomUUID(); this.targets = new Targets(); this.effects = new Effects(); + if (effect != null) { + this.effects.add(effect); + } } - public Mode(Mode mode) { + public Mode(final Mode mode) { this.id = mode.id; this.targets = mode.targets.copy(); this.effects = mode.effects.copy(); @@ -44,7 +52,15 @@ public class Mode implements Serializable { return targets; } + public void addTarget(Target target) { + targets.add(target); + } + public Effects getEffects() { return effects; } + + public void addEffect(Effect effect) { + effects.add(effect); + } } diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToOneOrMoreCreaturesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToOneOrMoreCreaturesTriggeredAbility.java index 19fb7eacfde..7d4a85629ce 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToOneOrMoreCreaturesTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToOneOrMoreCreaturesTriggeredAbility.java @@ -31,7 +31,7 @@ public class DealsDamageToOneOrMoreCreaturesTriggeredAbility extends DealsDamage || game.getTurn().getStepType() == PhaseStep.FIRST_COMBAT_DAMAGE) { String stepHash = (String) game.getState().getValue("damageStep" + getOriginalId()); String newStepHash = game.getStep().getType().toString() + game.getTurnNum(); - if (stepHash == null || !newStepHash.equals(stepHash)) { + if (!newStepHash.equals(stepHash)) { // this ability did not trigger during this damage step game.getState().setValue("damageStep" + getOriginalId(), game.getStep().getType().toString() + game.getTurnNum()); return true; diff --git a/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java index a0d3c0f0e84..b41e1001bb6 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCounteredControllerTriggeredAbility.java @@ -1,62 +1,62 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package mage.abilities.common; - -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; - -/** - * - * @author fireshoes - */ -public class SpellCounteredControllerTriggeredAbility extends TriggeredAbilityImpl { - - public SpellCounteredControllerTriggeredAbility(Effect effect) { - this(effect, false); - } - - public SpellCounteredControllerTriggeredAbility(Effect effect, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - } - - public SpellCounteredControllerTriggeredAbility(final SpellCounteredControllerTriggeredAbility ability) { - super(ability); - } - - @Override - public SpellCounteredControllerTriggeredAbility copy() { - return new SpellCounteredControllerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.COUNTERED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - StackObject stackObjectThatCountered = game.getStack().getStackObject(event.getSourceId()); - if (stackObjectThatCountered == null) { - stackObjectThatCountered = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK); - } - if (stackObjectThatCountered != null && stackObjectThatCountered.isControlledBy(getControllerId())) { - StackObject counteredStackObject = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK); - return counteredStackObject != null && (counteredStackObject instanceof Spell); - } - return false; - } - - @Override - public String getRule() { - return "Whenever a spell or ability you control counters a spell, " + super.getRule(); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; + +/** + * + * @author fireshoes + */ +public class SpellCounteredControllerTriggeredAbility extends TriggeredAbilityImpl { + + public SpellCounteredControllerTriggeredAbility(Effect effect) { + this(effect, false); + } + + public SpellCounteredControllerTriggeredAbility(Effect effect, boolean optional) { + super(Zone.BATTLEFIELD, effect, optional); + } + + public SpellCounteredControllerTriggeredAbility(final SpellCounteredControllerTriggeredAbility ability) { + super(ability); + } + + @Override + public SpellCounteredControllerTriggeredAbility copy() { + return new SpellCounteredControllerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.COUNTERED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject stackObjectThatCountered = game.getStack().getStackObject(event.getSourceId()); + if (stackObjectThatCountered == null) { + stackObjectThatCountered = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK); + } + if (stackObjectThatCountered != null && stackObjectThatCountered.isControlledBy(getControllerId())) { + StackObject counteredStackObject = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK); + return (counteredStackObject instanceof Spell); + } + return false; + } + + @Override + public String getRule() { + return "Whenever a spell or ability you control counters a spell, " + super.getRule(); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java index 4b95507e5a6..603d43cc69f 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java @@ -1,40 +1,40 @@ - -package mage.abilities.condition.common; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.other.OwnerIdPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; - -/** - * - * @author emerald000 - */ -public class MeldCondition implements Condition { - - private final String meldWithName; - - public MeldCondition(String meldWithName) { - this.meldWithName = meldWithName; - } - - @Override - public boolean apply(Game game, Ability source) { - MageObject sourceMageObject = source.getSourceObjectIfItStillExists(game); - if (sourceMageObject != null && sourceMageObject instanceof Permanent) { - Permanent sourcePermanent = (Permanent) sourceMageObject; - if (sourcePermanent.isControlledBy(source.getControllerId()) - && sourcePermanent.isOwnedBy(source.getControllerId())) { - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(new NamePredicate(this.meldWithName)); - filter.add(new OwnerIdPredicate(source.getControllerId())); - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; - } - } - return false; - } -} + +package mage.abilities.condition.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author emerald000 + */ +public class MeldCondition implements Condition { + + private final String meldWithName; + + public MeldCondition(String meldWithName) { + this.meldWithName = meldWithName; + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject sourceMageObject = source.getSourceObjectIfItStillExists(game); + if (sourceMageObject instanceof Permanent) { + Permanent sourcePermanent = (Permanent) sourceMageObject; + if (sourcePermanent.isControlledBy(source.getControllerId()) + && sourcePermanent.isOwnedBy(source.getControllerId())) { + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + filter.add(new NamePredicate(this.meldWithName)); + filter.add(new OwnerIdPredicate(source.getControllerId())); + return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; + } + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/InstantSorceryExileGraveyardCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/InstantSorceryExileGraveyardCount.java new file mode 100644 index 00000000000..744ae371f46 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/InstantSorceryExileGraveyardCount.java @@ -0,0 +1,38 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.filter.StaticFilters; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public enum InstantSorceryExileGraveyardCount implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player player = game.getPlayer(sourceAbility.getControllerId()); + if (player != null) { + return player.getGraveyard().count( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game + ) + game.getExile().getExileZone(player.getId()).count( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game + ); + } + return 0; + } + + @Override + public InstantSorceryExileGraveyardCount copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java index 9948b486a39..d42cc3f5281 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java @@ -24,7 +24,7 @@ public class SunburstCount implements DynamicValue { int count = 0; if (!game.getStack().isEmpty()) { StackObject spell = game.getStack().getFirst(); - if (spell != null && spell instanceof Spell && ((Spell) spell).getSourceId().equals(source.getSourceId())) { + if (spell instanceof Spell && ((Spell) spell).getSourceId().equals(source.getSourceId())) { Mana mana = ((Spell) spell).getSpellAbility().getManaCostsToPay().getPayment(); if (mana.getBlack() > 0) { count++; diff --git a/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java index 60b9b9468d0..b9b552d762c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -16,18 +15,25 @@ import mage.game.stack.Spell; public class CastSourceTriggeredAbility extends TriggeredAbilityImpl { public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; + private final String rulePrefix; public CastSourceTriggeredAbility(Effect effect) { this(effect, false); } public CastSourceTriggeredAbility(Effect effect, boolean optional) { + this(effect, optional, ""); + } + + public CastSourceTriggeredAbility(Effect effect, boolean optional, String rulePrefix) { super(Zone.STACK, effect, optional); this.ruleAtTheTop = true; + this.rulePrefix = rulePrefix; } public CastSourceTriggeredAbility(final CastSourceTriggeredAbility ability) { super(ability); + this.rulePrefix = ability.rulePrefix; } @Override @@ -44,7 +50,7 @@ public class CastSourceTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getSourceId().equals(this.getSourceId())) { MageObject spellObject = game.getObject(sourceId); - if (spellObject != null && (spellObject instanceof Spell)) { + if ((spellObject instanceof Spell)) { Spell spell = (Spell) spellObject; if (spell.getSpellAbility() != null) { for (Effect effect : getEffects()) { @@ -59,6 +65,6 @@ public class CastSourceTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "When you cast {source}, " + super.getRule(); + return rulePrefix + "When you cast this spell, " + super.getRule(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java index 9278af43743..040be4c85d7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java @@ -54,7 +54,7 @@ public class CopyTargetSpellEffect extends OneShotEffect { if (spell != null) { StackObject newStackObject = spell.createCopyOnStack(game, source, useController ? spell.getControllerId() : source.getControllerId(), true); Player player = game.getPlayer(source.getControllerId()); - if (player != null && newStackObject != null && newStackObject instanceof Spell) { + if (player != null && newStackObject instanceof Spell) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6); diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java index a68dc8e27f4..845fe9e5a43 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java @@ -27,7 +27,10 @@ public class DoIfCostPaid extends OneShotEffect { } public DoIfCostPaid(Effect effect, Effect effect2, Cost cost) { - this(effect, cost, null, true); + this(effect,effect2,cost,true); + } + public DoIfCostPaid(Effect effect, Effect effect2, Cost cost,boolean optional) { + this(effect, cost, null, optional); this.otherwiseEffects.add(effect2); } @@ -54,8 +57,9 @@ public class DoIfCostPaid extends OneShotEffect { this.optional = effect.optional; } - public void addEffect(Effect effect) { + public DoIfCostPaid addEffect(Effect effect) { executingEffects.add(effect); + return this; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java index 75848513757..ff587be44f1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlAttachedEffect.java @@ -37,7 +37,7 @@ public class ReturnToBattlefieldUnderOwnerControlAttachedEffect extends OneShotE return false; } Object object = getValue("attachedTo"); - if (object != null && object instanceof Permanent) { + if (object instanceof Permanent) { Card card = game.getCard(((Permanent) object).getId()); if (card != null) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java index b23a11e1d0c..657a347d2bc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderOwnerControlTargetEffect.java @@ -66,7 +66,7 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff } else { Card card = game.getCard(targetId); - if (card != null && card instanceof MeldCard) { + if (card instanceof MeldCard) { MeldCard meldCard = (MeldCard) card; Card topCard = meldCard.getTopHalfCard(); Card bottomCard = meldCard.getBottomHalfCard(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java index 55130c8f3b3..c3156147b86 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java @@ -43,7 +43,7 @@ public class ReturnToBattlefieldUnderYourControlAttachedEffect extends OneShotEf public boolean apply(Game game, Ability source) { Object object = getValue("attachedTo"); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && object != null && object instanceof Permanent) { + if (controller != null && object instanceof Permanent) { Card card = game.getCard(((Permanent) object).getId()); // Move the card only, if it is still in the next zone after the battlefield if (card != null && card.getZoneChangeCounter(game) == ((Permanent) object).getZoneChangeCounter(game) + 1) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java index 05787cfd2f7..e8bd4ab47ae 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java @@ -64,7 +64,7 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe } else { Card card = game.getCard(targetId); - if (card != null && card instanceof MeldCard) { + if (card instanceof MeldCard) { MeldCard meldCard = (MeldCard) card; Card topCard = meldCard.getTopHalfCard(); Card bottomCard = meldCard.getBottomHalfCard(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java index ff3dce414b2..368788d3f28 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java @@ -33,7 +33,7 @@ public class ReturnToHandAttachedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Object object = getValue("attachedTo"); - if (object != null && object instanceof Permanent) { + if (object instanceof Permanent) { Card card = game.getCard(((Permanent)object).getId()); if (card != null) { if (card.moveToZone(Zone.HAND, source.getSourceId(), game, false)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/TransformSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TransformSourceEffect.java index 5e70a7f70f3..e3636ad5883 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TransformSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TransformSourceEffect.java @@ -47,7 +47,7 @@ public class TransformSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { MageObject sourceObject = source.getSourceObjectIfItStillExists(game); // Transform only if it's the same object as the effect was put on the stack - if (sourceObject != null && sourceObject instanceof Permanent) { + if (sourceObject instanceof Permanent) { Permanent sourcePermanent = (Permanent) sourceObject; if (sourcePermanent.canTransform(source, game)) { // check not to transform twice the same side diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java index 4b95b39ace9..78834f82ae7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java @@ -37,7 +37,7 @@ public class UntapAllThatAttackedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - if (watcher != null && watcher instanceof AttackedThisTurnWatcher) { + if (watcher instanceof AttackedThisTurnWatcher) { Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); for (MageObjectReference mor : attackedThisTurn) { Permanent permanent = mor.getPermanent(game); diff --git a/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java b/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java index 419b78a1552..d661dea2150 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java @@ -149,7 +149,7 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl { // wants to do that in the future. UUID sourceId = source.getSourceId(); Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null && sourceCard instanceof SplitCardHalf) { + if (sourceCard instanceof SplitCardHalf) { sourceCard = ((SplitCardHalf) sourceCard).getParentCard(); sourceId = sourceCard.getId(); } @@ -170,7 +170,7 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { UUID sourceId = source.getSourceId(); Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null && sourceCard instanceof SplitCardHalf) { + if (sourceCard instanceof SplitCardHalf) { sourceCard = ((SplitCardHalf) sourceCard).getParentCard(); sourceId = sourceCard.getId(); } diff --git a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java index 212d940a9fa..30778d34e2f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java @@ -272,7 +272,7 @@ class ConspireEffect extends OneShotEffect { Card card = game.getCard(conspiredSpell.getSourceId()); if (card != null) { StackObject newStackObject = conspiredSpell.createCopyOnStack(game, source, source.getControllerId(), true); - if (newStackObject != null && newStackObject instanceof Spell && !game.isSimulation()) { + if (newStackObject instanceof Spell && !game.isSimulation()) { game.informPlayers(controller.getLogName() + ((Spell) newStackObject).getActivatedMessage(game)); } return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java index a863da01c28..afba2dcd995 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import java.util.ArrayList; @@ -25,6 +24,7 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.ManaPool; import mage.players.Player; @@ -223,6 +223,7 @@ class ConvokeEffect extends OneShotEffect { manaPool.unlockManaType(ManaType.COLORLESS); manaName = "colorless"; } + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CONVOKED, perm.getId(), source.getSourceId(), source.getControllerId())); game.informPlayers("Convoke: " + controller.getLogName() + " taps " + perm.getLogName() + " to pay one " + manaName + " mana"); } diff --git a/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java b/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java index 3320589b453..9e08681fb94 100644 --- a/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java @@ -83,7 +83,7 @@ public class HauntAbility extends TriggeredAbilityImpl { if (card != null) { String key = new StringBuilder("Haunting_").append(getSourceId().toString()).append('_').append(card.getZoneChangeCounter(game)).toString(); Object object = game.getState().getValue(key); - if (object != null && object instanceof FixedTarget) { + if (object instanceof FixedTarget) { FixedTarget target = (FixedTarget) object; if (target.getTarget() != null && target.getTarget().equals(event.getTargetId())) { usedFromExile = true; diff --git a/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java index bd29bffab27..3f0c3037ddc 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java @@ -222,7 +222,7 @@ class ReplicateCopyEffect extends OneShotEffect { // create the copies for (int i = 0; i < replicateCount; i++) { StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true); - if (newStackObject != null && newStackObject instanceof Spell && !game.isSimulation()) { + if (newStackObject instanceof Spell && !game.isSimulation()) { game.informPlayers(controller.getLogName() + ((Spell) newStackObject).getActivatedMessage(game)); } } diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 4130242ad79..158a7dfa538 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -1,4 +1,3 @@ - package mage.cards; import mage.MageObject; @@ -21,6 +20,8 @@ import mage.filter.FilterMana; import mage.filter.FilterPermanent; import mage.filter.FilterSpell; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.filter.predicate.mageobject.NamePredicate; @@ -35,7 +36,6 @@ import mage.game.stack.StackObject; import mage.target.TargetCard; import mage.target.TargetPermanent; import mage.target.TargetSpell; -import mage.target.common.TargetCardInOpponentsGraveyard; import mage.target.common.TargetCreaturePermanent; import mage.util.GameLog; import mage.util.SubTypeList; @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; +import mage.target.common.TargetCardInGraveyard; public abstract class CardImpl extends MageObjectImpl implements Card { @@ -394,13 +395,13 @@ public abstract class CardImpl extends MageObjectImpl implements Card { ability.addTarget(new TargetPermanent(0, xValue, permanentFilter, false)); } break; - case X_CMC_EQUAL_GY_CARD: //Geth, Lord of the Vault only + case X_CMC_EQUAL_GY_CARD: xValue = ability.getManaCostsToPay().getX(); - TargetCard oldTarget = (TargetCard) ability.getTargets().get(0); - FilterCard filterCard = oldTarget.getFilter().copy(); + FilterCard filterCard = ((TargetCard) ability.getTargets().get(0)).getFilter().copy(); filterCard.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + filterCard.setMessage(filterCard.getMessage().replace('X', (char) xValue)); ability.getTargets().clear(); - ability.getTargets().add(new TargetCardInOpponentsGraveyard(filterCard)); + ability.getTargets().add(new TargetCardInGraveyard(filterCard)); break; case CHOSEN_NAME: //Declaration of Naught only ability.getTargets().clear(); @@ -454,6 +455,14 @@ public abstract class CardImpl extends MageObjectImpl implements Card { ability.getTargets().clear(); ability.addTarget(new TargetCreaturePermanent(filterCreaturePermanent)); break; + case X_CMC_EQUAL_SPELL_CONTROLLED: // League Guildmage + xValue = ability.getManaCostsToPay().getX(); + FilterSpell spellFilter = new FilterInstantOrSorcerySpell("instant or sorcery you control with converted mana cost " + xValue); + spellFilter.add(new ControllerPredicate(TargetController.YOU)); + spellFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.getTargets().clear(); + ability.addTarget(new TargetSpell(spellFilter)); + break; } } diff --git a/Mage/src/main/java/mage/constants/TargetAdjustment.java b/Mage/src/main/java/mage/constants/TargetAdjustment.java index 04543a991d6..675b2fed05e 100644 --- a/Mage/src/main/java/mage/constants/TargetAdjustment.java +++ b/Mage/src/main/java/mage/constants/TargetAdjustment.java @@ -9,10 +9,12 @@ public enum TargetAdjustment { X_TARGETS, X_CMC_EQUAL_PERM, X_CMC_EQUAL_GY_CARD, - X_POWER_LEQ, CHOSEN_NAME, + X_POWER_LEQ, + CHOSEN_NAME, CHOSEN_COLOR, VERSE_COUNTER_TARGETS, TREASURE_COUNTER_POWER, SIMIC_MANIPULATOR, - CREATURE_POWER_X_OR_LESS + CREATURE_POWER_X_OR_LESS, + X_CMC_EQUAL_SPELL_CONTROLLED } diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 2ded9a796bc..865cab23a53 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -1,4 +1,3 @@ - package mage.counters; /** @@ -54,6 +53,7 @@ public enum CounterType { GROWTH("growth"), HATCHLING("hatchling"), HEALING("healing"), + HIT("hit"), HOOFPRINT("hoofprint"), HOUR("hour"), HOURGLASS("hourglass"), diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java index ed505b2cd2f..75469d4dc17 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java @@ -1,16 +1,15 @@ - package mage.filter.predicate.permanent; +import mage.cards.Card; import mage.counters.CounterType; import mage.filter.predicate.Predicate; import mage.game.Game; -import mage.game.permanent.Permanent; /** * * @author jeffwadsworth */ -public class CounterPredicate implements Predicate { +public class CounterPredicate implements Predicate { private final CounterType counter; @@ -23,7 +22,7 @@ public class CounterPredicate implements Predicate { } @Override - public boolean apply(Permanent input, Game game) { + public boolean apply(Card input, Game game) { if (counter == null) { return !input.getCounters(game).keySet().isEmpty(); } else { diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 20f6284b9b9..1d73eb4ca42 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1987,7 +1987,8 @@ public abstract class GameImpl implements Game, Serializable { if (card != null && card.isCreature()) { UUID wasAttachedTo = perm.getAttachedTo(); perm.attachTo(null, this); - BestowAbility.becomeCreature(perm, this); + //moved to mage.game.permanent.PermanentImpl::detachAllAttachments + //BestowAbility.becomeCreature(perm, this); fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index a21f0a27dd3..b6a3768c298 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -286,7 +286,7 @@ public class Plane implements CommandObject { Class c = Class.forName(planeName); Constructor cons = c.getConstructor(); Object plane = cons.newInstance(); - if (plane != null && plane instanceof mage.game.command.Plane) { + if (plane instanceof Plane) { return (Plane) plane; } } catch (Exception ex) { diff --git a/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java b/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java new file mode 100644 index 00000000000..5e97b8c7453 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java @@ -0,0 +1,25 @@ +package mage.game.command.emblems; + +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.effects.common.LoseGameTargetPlayerEffect; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; +import mage.game.command.Emblem; + +/** + * + * @author TheElk801 + */ +public class VraskaGolgariQueenEmblem extends Emblem { + + // -9: You get an emblem with "Whenever a creature you control deals combat damage to a player, that player loses the game." + public VraskaGolgariQueenEmblem() { + this.setName("Emblem Vraska"); + this.setExpansionSetCodeForImage("GRN"); + this.getAbilities().add(new DealsDamageToAPlayerAllTriggeredAbility( + new LoseGameTargetPlayerEffect(), + StaticFilters.FILTER_CONTROLLED_A_CREATURE, + false, SetTargetPointer.NONE, true + )); + } +} diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 5afa0fe839d..eeb746ce952 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -72,6 +72,12 @@ public class GameEvent implements Serializable { MADNESS_CARD_EXILED, INVESTIGATED, KICKED, + /* CONVOKED + targetId id of the creature that was taped to convoke the sourceId + sourceId sourceId of the convoked spell + playerId controller of the convoked spell + */ + CONVOKED, DISCARD_CARD, DISCARDED_CARD, CYCLE_CARD, CYCLED_CARD, @@ -209,7 +215,7 @@ public class GameEvent implements Serializable { SHUFFLE_LIBRARY, LIBRARY_SHUFFLED, ENCHANT_PLAYER, ENCHANTED_PLAYER, CAN_TAKE_MULLIGAN, - FLIP_COIN, COIN_FLIPPED, SCRY, SURVEIL, FATESEAL, + FLIP_COIN, COIN_FLIPPED, SCRY, SURVEIL, SURVEILED, FATESEAL, ROLL_DICE, DICE_ROLLED, ROLL_PLANAR_DIE, PLANAR_DIE_ROLLED, PLANESWALK, PLANESWALKED, diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 74739b25a37..776f0b775dd 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1437,6 +1437,24 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return color; } + //20180810 - 701.3d + //If an object leaves the zone it's in, all attached permanents become unattached + //note that this code doesn't actually detach anything, and is a bit of a bandaid + public void detachAllAttachments(Game game) { + for(UUID attachmentId : getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + Card attachmentCard = game.getCard(attachmentId); + if(attachment != null && attachmentCard != null) { + //make bestow cards and licids into creatures + //aura test to stop bludgeon brawl shenanigans from using this code + //consider adding code to handle that case? + if(attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature()) { + BestowAbility.becomeCreature(attachment, game); + } + } + } + } + @Override public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { Zone fromZone = game.getState().getZone(objectId); @@ -1449,7 +1467,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } else { zoneChangeInfo = new ZoneChangeInfo(event); } - return ZonesHandler.moveCard(zoneChangeInfo, game); + boolean successfullyMoved = ZonesHandler.moveCard(zoneChangeInfo, game); + //20180810 - 701.3d + detachAllAttachments(game); + return successfullyMoved; } return false; } @@ -1459,7 +1480,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { Zone fromZone = game.getState().getZone(objectId); ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); - return ZonesHandler.moveCard(info, game); + + boolean successfullyMoved = ZonesHandler.moveCard(info, game); + //20180810 - 701.3d + detachAllAttachments(game); + return successfullyMoved; } } diff --git a/Mage/src/main/java/mage/game/permanent/token/AngelToken2.java b/Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java similarity index 71% rename from Mage/src/main/java/mage/game/permanent/token/AngelToken2.java rename to Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java index 9369b05c36f..0167c1a2bb2 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AngelToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java @@ -6,9 +6,9 @@ import mage.abilities.keyword.VigilanceAbility; import mage.constants.CardType; import mage.constants.SubType; -public final class AngelToken2 extends TokenImpl { +public final class AngelVigilanceToken extends TokenImpl { - public AngelToken2() { + public AngelVigilanceToken() { super("Angel", "4/4 white Angel creature token with flying and vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); @@ -19,11 +19,11 @@ public final class AngelToken2 extends TokenImpl { addAbility(VigilanceAbility.getInstance()); } - public AngelToken2(final AngelToken2 token) { + public AngelVigilanceToken(final AngelVigilanceToken token) { super(token); } - public AngelToken2 copy() { - return new AngelToken2(this); + public AngelVigilanceToken copy() { + return new AngelVigilanceToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java new file mode 100644 index 00000000000..ecb2764cdaa --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java @@ -0,0 +1,35 @@ +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; + +/** + * + * @author TheElk801 + */ +public final class ElfKnightToken extends TokenImpl { + + public ElfKnightToken() { + super("Knight Ally", "2/2 green and white Elf Knight creature token with vigilance"); + this.setExpansionSetCodeForImage("GRN"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + color.setWhite(true); + subtype.add(SubType.ELF); + subtype.add(SubType.KNIGHT); + power = new MageInt(2); + toughness = new MageInt(2); + this.addAbility(VigilanceAbility.getInstance()); + } + + public ElfKnightToken(final ElfKnightToken token) { + super(token); + } + + public ElfKnightToken copy() { + return new ElfKnightToken(this); + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java index 26f809f941f..d4dd3a6c8ab 100644 --- a/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java @@ -63,7 +63,7 @@ class IllusionTokenTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject eventSourceObject = game.getObject(event.getSourceId()); - if (eventSourceObject != null && event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { + if (event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index a7901dd0684..bfc87919f69 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -3914,9 +3914,13 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean surveil(int value, Ability source, Game game) { - game.informPlayers(getLogName() + " surveils " + value); + GameEvent event = new GameEvent(GameEvent.EventType.SURVEIL, getId(), source == null ? null : source.getSourceId(), getId(), value, true); + if (game.replaceEvent(event)) { + return false; + } + game.informPlayers(getLogName() + " surveils " + event.getAmount()); Cards cards = new CardsImpl(); - cards.addAll(getLibrary().getTopCards(game, value)); + cards.addAll(getLibrary().getTopCards(game, event.getAmount())); if (!cards.isEmpty()) { String text; if (cards.size() == 1) { @@ -3930,7 +3934,7 @@ public abstract class PlayerImpl implements Player, Serializable { cards.removeAll(target.getTargets()); putCardsOnTopOfLibrary(cards, game, source, true); } - game.fireEvent(new GameEvent(GameEvent.EventType.SURVEIL, getId(), source == null ? null : source.getSourceId(), getId(), value, true)); + game.fireEvent(new GameEvent(GameEvent.EventType.SURVEILED, getId(), source == null ? null : source.getSourceId(), getId(), event.getAmount(), true)); return true; } diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index 4f95f3287d2..110b67203ca 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -149,7 +149,7 @@ public abstract class TargetImpl implements Target { @Override public boolean isRequired(UUID sourceId, Game game) { MageObject object = game.getObject(sourceId); - if (!requiredExplicitlySet && object != null && object instanceof Ability) { + if (!requiredExplicitlySet && object instanceof Ability) { return isRequired((Ability) object); } else { return isRequired(); diff --git a/Mage/src/main/java/mage/target/TargetSource.java b/Mage/src/main/java/mage/target/TargetSource.java index b65bc14aba3..e0dae36e505 100644 --- a/Mage/src/main/java/mage/target/TargetSource.java +++ b/Mage/src/main/java/mage/target/TargetSource.java @@ -60,7 +60,7 @@ public class TargetSource extends TargetObject { public void addTarget(UUID id, Ability source, Game game) { if (targets.size() < maxNumberOfTargets) { MageObject object = game.getObject(id); - if (object != null && object instanceof StackObject) { + if (object instanceof StackObject) { addTarget(((StackObject) object).getSourceId(), source, game, notTarget); } else { diff --git a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java index a30eba6dee7..e596adce261 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java @@ -1,4 +1,3 @@ - package mage.target.common; import java.util.HashSet; @@ -33,6 +32,10 @@ public class TargetCardInYourGraveyard extends TargetCard { this(numTargets, numTargets, filter); } + public TargetCardInYourGraveyard(int minNumTargets, int maxNumTargets) { + this(minNumTargets, maxNumTargets, StaticFilters.FILTER_CARD_FROM_YOUR_GRAVEYARD); + } + public TargetCardInYourGraveyard(int minNumTargets, int maxNumTargets, FilterCard filter) { this(minNumTargets, maxNumTargets, filter, false); } diff --git a/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java index 51ce34bcd31..97a51a225d9 100644 --- a/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java @@ -37,7 +37,7 @@ public class CastSpellYourLastTurnWatcher extends Watcher { lastActivePlayer = game.getActivePlayerId(); if (event.getType() == GameEvent.EventType.SPELL_CAST) { UUID playerId = event.getPlayerId(); - if (playerId != null && lastActivePlayer != null && playerId.equals(lastActivePlayer)) { + if (playerId != null && playerId.equals(lastActivePlayer)) { amountOfSpellsCastOnCurrentTurn.putIfAbsent(playerId, 0); amountOfSpellsCastOnCurrentTurn.compute(playerId, (k, a) -> a + 1); } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index a4eb3b9f442..baaac838bf9 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33932,11 +33932,11 @@ Loyal Unicorn|Commander 2018|4|U|{3}{W}|Creature - Unicorn|3|4|Vigilance$Lieuten Magus of the Balance|Commander 2018|5|R|{1}{W}|Creature - Human Wizard|2|2|{4}{W}, {T}, Sacrifice Magus of the Balance: Each player chooses a number of lands they control equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way.| Aminatou's Augury|Commander 2018|6|R|{6}{U}{U}|Sorcery|||Exile the top eight cards of your library. You may put a land card from among them onto the battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from among the exiled cards without paying its mana cost.| Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| -Estrid's Invocation|Commander 2018|8|R|{2}{U}|Enchantment|||You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it gains "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control."| +Estrid's Invocation|Commander 2018|8|R|{2}{U}|Enchantment|||You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it has "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control."| Ever-Watching Threshold|Commander 2018|9|R|{2}{U}|Enchantment|||Whenever an opponent attacks you and/or a planeswalker you control with one or more creatures, draw a card.| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Octopus Umbra|Commander 2018|11|R|{3}{U}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less."$Totem armor| -Primordial Mist|Commander 2018|12|R|{4}{U}|Enchantment|||At the beginning of your end step, you may manifest the top card of your library.| +Primordial Mist|Commander 2018|12|R|{4}{U}|Enchantment|||At the beginning of your end step, you may manifest the top card of your library.$Exile a face-down permanent you control face up: You may play that card this turn.| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker.$When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it.| Entreat the Dead|Commander 2018|15|R|{X}{X}{B}{B}{B}|Sorcery|||Return X target creature cards from your graveyard to the battlefield.$Miracle {X}{B}{B}| @@ -33961,21 +33961,21 @@ Nylea's Colossus|Commander 2018|33|R|{6}{G}|Enchantment Creature - Giant|6|6|Con Ravenous Slime|Commander 2018|34|R|{2}{G}|Creature - Ooze|1|1|Ravenous Slime can't be blocked by creatures with power 2 or less.$If a creature an opponent controls would die, instead exile it and put a number of +1/+1 counters equal to that creature's power on Ravenous Slime.| Turntimber Sower|Commander 2018|35|R|{2}{G}|Creature - Elf Druid|3|3|Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.${G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| -Aminatou, the Fateshifter|Commander 2018|37|M|{W}{U}{B}|Legendary Planeswalker - Aminatou|3|+1: Draw a card, then put a card from your hand on top of your library.$-1: Exile another target permanent you own, then return it to the battlefield under your control.$-6: Choose left or right. Each player gains control of all nonland permanents other than Aminatou, the Fateshifter controlled by the next player in the chosen direction.$Aminatou, the Fateshifter can be your commander.| +Aminatou, the Fateshifter|Commander 2018|37|M|{W}{U}{B}|Legendary Planeswalker - Aminatou|3|+1: Draw a card, then put a card from your hand on top of your library.$−1: Exile another target permanent you own, then return it to the battlefield under your control.$−6: Choose left or right. Each player gains control of all nonland permanents other than Aminatou, the Fateshifter controlled by the next player in the chosen direction.$Aminatou, the Fateshifter can be your commander.| Arixmethes, Slumbering Isle|Commander 2018|38|R|{2}{G}{U}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| -Estrid, the Masked|Commander 2018|40|M|{1}{G}{W}{U}|Legendary Planeswalker - Estrid|3|+2: Untap each enchanted permanent you control.$-1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchant permanent and totem armor.$-7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards.$Estrid, the Masked can be your commander.| -Gyrus, Waker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at the end of combat.| +Estrid, the Masked|Commander 2018|40|M|{1}{G}{W}{U}|Legendary Planeswalker - Estrid|3|+2: Untap each enchanted permanent you control.$−1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchant permanent and totem armor.$−7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards.$Estrid, the Masked can be your commander.| +Gyrus, Waker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Waker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at end of combat.| Kestia, the Cultivator|Commander 2018|42|M|{1}{G}{W}{U}|Legendary Enchantment Creature - Nymph|4|4|Bestow {3}{G}{W}{U}$Enchanted creature gets +4/+4.$Whenever an enchanted creature or enchantment creature you control attacks, draw a card.| -Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| -Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| +Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$−3: Return up to two target land cards from your graveyard to the battlefield.$−11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| +Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$−7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| -Thantis the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spider|5|5|Vigilance, reach$All creatures attack each combat if able.$Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver.| +Thantis, the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spider|5|5|Vigilance, reach$All creatures attack each combat if able.$Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis, the Warweaver.| Tuvasa the Sunlit|Commander 2018|47|M|{G}{W}{U}|Legendary Creature - Merfolk Shaman|1|1|Tuvasa the Sunlit gets +1/+1 for each enchantment you control.$Whenever you cast your first enchantment spell each turn, draw a card.| Varina, Lich Queen|Commander 2018|48|M|{1}{W}{U}{B}|Legendary Creature - Zombie Wizard|4|4|Whenever you attack with one or more Zombies, draw that many cards, then discard that many cards. You gain that much life.${2}, Exile two cards from your graveyard: Create a tapped 2/2 black Zombie creature token.| Windgrace's Judgment|Commander 2018|49|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| Xantcha, Sleeper Agent|Commander 2018|50|R|{1}{B}{R}|Legendary Creature - Minion|5|5|As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it.$Xantcha attacks each combat if able and can't attack its owner or planeswalkers its owner controls.${3}: Xantcha's controller loses 2 life and you draw a card. Any player may activate this ability.| -Yennet, Crypt Sovereign|Commander 2018|51|M|{2}{W}{U}{B}|Legendary Creature - Sphinx|3|5|Flying, vigilance, menace$Whenever Yennet, Crypt Sovereign attacks, reveal the top card of your library. If that card's converted mana cost is odd, you may cast it without paying its mana cost. Otherwise, draw a card.| +Yennett, Cryptic Sovereign|Commander 2018|51|M|{2}{W}{U}{B}|Legendary Creature - Sphinx|3|5|Flying, vigilance, menace$Whenever Yennett, Cryptic Sovereign attacks, reveal the top card of your library. If that card's converted mana cost is odd, you may cast it without paying its mana cost. Otherwise, draw a card.| Yuriko, the Tiger's Shadow|Commander 2018|52|R|{1}{U}{B}|Legendary Creature - Human Ninja|1|3|Commander ninjutsu {U}{B}$Whenever a Ninja you control deals combat damage to a player, reveal the top card of your library and put that card into your hand. Each opponent loses life equal to that card's converted mana cost.| Ancient Stone Idol|Commander 2018|53|R|{10}|Artifact Creature - Golem|12|12|Flash$This spell costs {1} less to cast for each attacking creature.$Trample$When Ancient Stone Idol dies, create a 6/12 colorless Construct artifact creature token with trample.| Coveted Jewel|Commander 2018|54|R|{6}|Artifact|||When Coveted Jewel enters the battlefield, draw three cards.${T}: Add three mana of any one color.$Whenever one or more creatures an opponent controls attack you and aren't blocked, that player draws three cards and gains control of Coveted Jewel. Untap it.| @@ -34013,9 +34013,9 @@ Devastation Tide|Commander 2018|85|R|{3}{U}{U}|Sorcery|||Return all nonland perm Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| Djinn of Wishes|Commander 2018|87|R|{3}{U}{U}|Creature - Djinn|4|4|Flying$Djinn of Wishes enters the battlefield with three wish counters on it.${2}{U}{U}, Remove a wish counter from Djinn of Wishes: Reveal the top card of your library. You may play that card without paying its mana cost. If you don't, exile it.| Dream Cache|Commander 2018|88|C|{2}{U}|Sorcery|||Draw three cards, then put two cards from your hand both on top of your library or both on the bottom of your library.| -Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| +Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +1/+1.$Totem armor| Etherium Sculptor|Commander 2018|90|C|{1}{U}|Artifact Creature - Vedalken Artificer|1|2|Artifact spells you cast cost {1} less to cast.| -Inkwell Leviathan|Commander 2018|91|R|{7}{U}{U}|Artifact Creature - Leviathan|7|11|Islandwalk| +Inkwell Leviathan|Commander 2018|91|R|{7}{U}{U}|Artifact Creature - Leviathan|7|11|Trample$Islandwalk$Shroud| Into the Roil|Commander 2018|92|C|{1}{U}|Instant|||Kicker {1}{U}$Return target nonland permanent to its owner's hand. If this spell was kicked, draw a card.| Jeskai Infiltrator|Commander 2018|93|R|{2}{U}|Creature - Human Monk|2|3|Jeskai Infiltrator can't be blocked as long as you control no other creatures.$When Jeskai Infiltrator deals combat damage to a player, exile it and the top card of your library in a face-down pile, shuffle that pile, then manifest those cards.| Mulldrifter|Commander 2018|94|U|{4}{U}|Creature - Elemental|2|2|Flying$When Mulldrifter enters the battlefield, draw two cards.$Evoke {2}{U}| @@ -34026,8 +34026,8 @@ Predict|Commander 2018|98|U|{1}{U}|Instant|||Choose a card name, then target pla Reverse Engineer|Commander 2018|99|U|{3}{U}{U}|Sorcery|||Improvise$Draw three cards.| Saheeli's Artistry|Commander 2018|100|R|{4}{U}{U}|Sorcery|||Choose one or both —$• Create a token that's a copy of target artifact.$• Create a token that's a copy of target creature, except it's an artifact in addition to its other types.| Sharding Sphinx|Commander 2018|101|R|{4}{U}{U}|Artifact Creature - Sphinx|4|4|Flying$Whenever an artifact creature you control deals combat damage to a player, you may create a 1/1 blue Thopter artifact creature token with flying.| -Sigiled Starfish|Commander 2018|102|C|{1}{U}|Creature - Starfish|0|3|{T}: Scry 1.| -Sphinx of Jwar Isle|Commander 2018|103|R|{4}{U}{U}|Creature - Sphinx|5|5|Flying$Shroud| +Sigiled Starfish|Commander 2018|102|U|{1}{U}|Creature - Starfish|0|3|{T}: Scry 1.| +Sphinx of Jwar Isle|Commander 2018|103|R|{4}{U}{U}|Creature - Sphinx|5|5|Flying$Shroud$You may look at the top card of your library.| Sphinx of Uthuun|Commander 2018|104|R|{5}{U}{U}|Creature - Sphinx|5|6|Flying$When Sphinx of Uthuun enters the battlefield, reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.| Telling Time|Commander 2018|105|C|{1}{U}|Instant|||Look at the top three cards of your library. Put one of those cards into your hand, one on top of your library, and one on the bottom of your library.| Thirst for Knowledge|Commander 2018|106|U|{2}{U}|Instant|||Draw three cards. Then discard two cards unless you discard an artifact card.| @@ -34068,15 +34068,15 @@ Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit Enchantress's Presence|Commander 2018|141|R|{2}{G}|Enchantment|||Whenever you cast an enchantment spell, draw a card.| Epic Proportions|Commander 2018|142|R|{4}{G}{G}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +5/+5 and has trample.| Explore|Commander 2018|143|C|{1}{G}|Sorcery|||You may play an additional land this turn.$Draw a card.| -Explosive Vegetation|Commander 2018|144|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Explosive Vegetation|Commander 2018|144|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library.| Far Wanderings|Commander 2018|145|C|{2}{G}|Sorcery|||Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle your library.$Threshold — If seven or more cards are in your graveyard, instead search your library for up to three basic land cards, put them onto the battlefield tapped, then shuffle your library.| -Farhaven Elf|Commander 2018|146|C|{2}{G}|Creature - Elf Druid|1|1|When Farhaven Elf enters the battlefield, you may search your library for a basic land card and put it onto the battlefield tapped. If you do, shuffle your library.| +Farhaven Elf|Commander 2018|146|C|{2}{G}|Creature - Elf Druid|1|1|When Farhaven Elf enters the battlefield, you may search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| Fertile Ground|Commander 2018|147|C|{1}{G}|Enchantment - Aura|||Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional one mana of any color.| Grapple with the Past|Commander 2018|148|C|{1}{G}|Instant|||Put the top three cards of your library into your graveyard, then you may return a creature or land card from your graveyard to your hand.| Ground Seal|Commander 2018|149|R|{1}{G}|Enchantment|||When Ground Seal enters the battlefield, draw a card.$Cards in graveyards can't be the targets of spells or abilities.| -Harrow|Commander 2018|150|C|{2}{G}|Instant|||As an additional cost to cast this spell, sacrifice a land.$Search your library for up to two basic land cards and put them onto the battlefield. Then shuffle your library.| +Harrow|Commander 2018|150|C|{2}{G}|Instant|||As an additional cost to cast this spell, sacrifice a land.$Search your library for up to two basic land cards, put them onto the battlefield, then shuffle your library.| Herald of the Pantheon|Commander 2018|151|R|{1}{G}|Creature - Centaur Shaman|2|2|Enchantment spells you cast cost {1} less to cast.$Whenever you cast an enchantment spell, you gain 1 life.| -Hunting Wilds|Commander 2018|152|U|{3}{G}|Sorcery|||Kicker {3}{G}$Search your library for up to two Forest cards and put them onto the battlefield tapped. Then shuffle your library.$If this spell was kicked, untap all Forests put onto the battlefield this way. They become 3/3 green creatures with haste that are still lands.| +Hunting Wilds|Commander 2018|152|U|{3}{G}|Sorcery|||Kicker {3}{G}$Search your library for up to two Forest cards, put them onto the battlefield tapped, then shuffle your library.$If this spell was kicked, untap all Forests put onto the battlefield this way. They become 3/3 green creatures with haste that are still lands.| Hydra Omnivore|Commander 2018|153|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever Hydra Omnivore deals combat damage to an opponent, it deals that much damage to each other opponent.| Khalni Heart Expedition|Commander 2018|154|C|{1}{G}|Enchantment|||Landfall — Whenever a land enters the battlefield under your control, you may put a quest counter on Khalni Heart Expedition.$Remove three quest counters from Khalni Heart Expedition and sacrifice it: Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library.| Kruphix's Insight|Commander 2018|155|C|{2}{G}|Sorcery|||Reveal the top six cards of your library. Put up to three enchantment cards from among them into your hand and the rest of the revealed cards into your graveyard.| @@ -34090,7 +34090,7 @@ Snake Umbra|Commander 2018|162|C|{2}{G}|Enchantment - Aura|||Enchant creature$En Spawning Grounds|Commander 2018|163|R|{6}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 5/5 green Beast creature token with trample."| Vow of Wildness|Commander 2018|164|U|{2}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +3/+3, has trample, and can't attack you or a planeswalker you control.| Wild Growth|Commander 2018|165|C|{G}|Enchantment - Aura|||Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional {G}.| -Yavimaya Elder|Commander 2018|166|C|{1}{G}{G}|Creature - Human Druid|2|1|When Yavimaya Elder dies, you may search your library for up to two basic land cards, reveal them, and put them into your hand. If you do, shuffle your library.${2}, Sacrifice Yavimaya Elder: Draw a card.| +Yavimaya Elder|Commander 2018|166|C|{1}{G}{G}|Creature - Human Druid|2|1|When Yavimaya Elder dies, you may search your library for up to two basic land cards, reveal them, put them into your hand, then shuffle your library.${2}, Sacrifice Yavimaya Elder: Draw a card.| Yavimaya Enchantress|Commander 2018|167|C|{2}{G}|Creature - Human Druid|2|2|Yavimaya Enchantress gets +1/+1 for each enchantment on the battlefield.| Aethermage's Touch|Commander 2018|168|R|{2}{W}{U}|Instant|||Reveal the top four cards of your library. You may put a creature card from among them onto the battlefield. It gains "At the beginning of your end step, return this creature to its owner's hand." Then put the rest of the cards revealed this way on the bottom of your library in any order.| Bant Charm|Commander 2018|169|U|{G}{W}{U}|Instant|||Choose one —$• Destroy target artifact.$• Put target creature on the bottom of its owner's library.$• Counter target instant spell.| @@ -34137,14 +34137,14 @@ Mimic Vat|Commander 2018|209|R|{3}|Artifact|||Imprint — Whenever a nontoken cr Mind Stone|Commander 2018|210|C|{2}|Artifact|||{T}: Add {C}.${1}, {T}, Sacrifice Mind Stone: Draw a card.| Mirrorworks|Commander 2018|211|R|{5}|Artifact|||Whenever another nontoken artifact enters the battlefield under your control, you may pay {2}. If you do, create a token that's a copy of that artifact.| Myr Battlesphere|Commander 2018|212|R|{7}|Artifact Creature - Myr Construct|4|7|When Myr Battlesphere enters the battlefield, create four 1/1 colorless Myr artifact creature tokens.$Whenever Myr Battlesphere attacks, you may tap X untapped Myr you control. If you do, Myr Battlesphere gets +X/+0 until end of turn and deals X damage to the player or planeswalker it's attacking.| -Orzhov Signet|Commander 2018|213|U|{2}|Artifact|||{1}, {T}: Add {W}{B}.| +Orzhov Signet|Commander 2018|213|C|{2}|Artifact|||{1}, {T}: Add {W}{B}.| Pilgrim's Eye|Commander 2018|214|C|{3}|Artifact Creature - Thopter|1|1|Flying$When Pilgrim's Eye enters the battlefield, you may search your library for a basic land card, reveal it, put it into your hand, then shuffle your library.| Prismatic Lens|Commander 2018|215|U|{2}|Artifact|||{T}: Add {C}.${1}, {T}: Add one mana of any color.| Prototype Portal|Commander 2018|216|R|{4}|Artifact|||Imprint — When Prototype Portal enters the battlefield, you may exile an artifact card from your hand.${X}, {T}: Create a token that's a copy of the exiled card. X is the converted mana cost of that card.| Psychosis Crawler|Commander 2018|217|R|{5}|Artifact Creature - Horror|*|*|Psychosis Crawler's power and toughness are each equal to the number of cards in your hand.$Whenever you draw a card, each opponent loses 1 life.| Scrabbling Claws|Commander 2018|218|U|{1}|Artifact|||{T}: Target player exiles a card from their graveyard.${1}, Sacrifice Scrabbling Claws: Exile target card from a graveyard. Draw a card.| Scuttling Doom Engine|Commander 2018|219|R|{6}|Artifact Creature - Construct|6|6|Scuttling Doom Engine can't be blocked by creatures with power 2 or less.$When Scuttling Doom Engine dies, it deals 6 damage to target opponent or planeswalker.| -Seer's Lantern|Commander 2018|220|C|{3}|Artifact|||{T}: Add {C}.| +Seer's Lantern|Commander 2018|220|C|{3}|Artifact|||{T}: Add {C}.${2}, {T}: Scry 1.| Seer's Sundial|Commander 2018|221|R|{4}|Artifact|||Landfall — Whenever a land enters the battlefield under your control, you may pay {2}. If you do, draw a card.| Sol Ring|Commander 2018|222|U|{1}|Artifact|||{T}: Add {C}{C}.| Soul of New Phyrexia|Commander 2018|223|M|{6}|Artifact Creature - Avatar|6|6|Trample${5}: Permanents you control gain indestructible until end of turn.${5}, Exile Soul of New Phyrexia from your graveyard: Permanents you control gain indestructible until end of turn.| @@ -34160,7 +34160,7 @@ Arcane Sanctum|Commander 2018|232|U||Land|||Arcane Sanctum enters the battlefiel Azorius Chancery|Commander 2018|233|U||Land|||Azorius Chancery enters the battlefield tapped.$When Azorius Chancery enters the battlefield, return a land you control to its owner's hand.${T}: Add {W}{U}.| Azorius Guildgate|Commander 2018|234|C||Land - Gate|||Azorius Guildgate enters the battlefield tapped.${T}: Add {W} or {U}.| Barren Moor|Commander 2018|235|C||Land|||Barren Moor enters the battlefield tapped.${T}: Add {B}.$Cycling {B}| -Blighted Woodland|Commander 2018|236|U||Land|||{T}: Add {C}.${3}{G}, {T}, Sacrifice Blighted Woodland: Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Blighted Woodland|Commander 2018|236|U||Land|||{T}: Add {C}.${3}{G}, {T}, Sacrifice Blighted Woodland: Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library.| Blossoming Sands|Commander 2018|237|C||Land|||Blossoming Sands enters the battlefield tapped.$When Blossoming Sands enters the battlefield, you gain 1 life.${T}: Add {G} or {W}.| Bojuka Bog|Commander 2018|238|C||Land|||Bojuka Bog enters the battlefield tapped.$When Bojuka Bog enters the battlefield, exile all cards from target player's graveyard.${T}: Add {B}.| Buried Ruin|Commander 2018|239|U||Land|||{T}: Add {C}.${2}, {T}, Sacrifice Buried Ruin: Return target artifact card from your graveyard to your hand.| @@ -34187,18 +34187,18 @@ Jungle Hollow|Commander 2018|259|C||Land|||Jungle Hollow enters the battlefield Jwar Isle Refuge|Commander 2018|260|U||Land|||Jwar Isle Refuge enters the battlefield tapped.$When Jwar Isle Refuge enters the battlefield, you gain 1 life.${T}: Add {U} or {B}.| Kazandu Refuge|Commander 2018|261|U||Land|||Kazandu Refuge enters the battlefield tapped.$When Kazandu Refuge enters the battlefield, you gain 1 life.${T}: Add {R} or {G}.| Khalni Garden|Commander 2018|262|C||Land|||Khalni Garden enters the battlefield tapped.$When Khalni Garden enters the battlefield, create a 0/1 green Plant creature token.${T}: Add {G}.| -Krosan Verge|Commander 2018|263|U||Land|||Krosan Verge enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Krosan Verge: Search your library for a Forest card and a Plains card and put them onto the battlefield tapped. Then shuffle your library.| +Krosan Verge|Commander 2018|263|U||Land|||Krosan Verge enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Krosan Verge: Search your library for a Forest card and a Plains card, put them onto the battlefield tapped, then shuffle your library.| Lonely Sandbar|Commander 2018|264|C||Land|||Lonely Sandbar enters the battlefield tapped.${T}: Add {U}.$Cycling {U}| Meandering River|Commander 2018|265|U||Land|||Meandering River enters the battlefield tapped.${T}: Add {W} or {U}.| Mortuary Mire|Commander 2018|266|C||Land|||Mortuary Mire enters the battlefield tapped.$When Mortuary Mire enters the battlefield, you may put target creature card from your graveyard on top of your library.${T}: Add {B}.| Mosswort Bridge|Commander 2018|267|R||Land|||Hideaway${T}: Add {G}.${G}, {T}: You may play the exiled card without paying its mana cost if creatures you control have total power 10 or greater.| -Mountain Valley|Commander 2018|268|U||Land|||Mountain Valley enters the battlefield tapped.${T}, Sacrifice Mountain Valley: Search your library for a Mountain or Forest card and put it onto the battlefield. Then shuffle your library.| +Mountain Valley|Commander 2018|268|U||Land|||Mountain Valley enters the battlefield tapped.${T}, Sacrifice Mountain Valley: Search your library for a Mountain or Forest card, put it onto the battlefield, then shuffle your library.| Myriad Landscape|Commander 2018|269|U||Land|||Myriad Landscape enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Myriad Landscape: Search your library for up to two basic land cards that share a land type, put them onto the battlefield tapped, then shuffle your library.| New Benalia|Commander 2018|270|U||Land|||New Benalia enters the battlefield tapped.$When New Benalia enters the battlefield, scry 1.${T}: Add {W}.| Orzhov Basilica|Commander 2018|271|U||Land|||Orzhov Basilica enters the battlefield tapped.$When Orzhov Basilica enters the battlefield, return a land you control to its owner's hand.${T}: Add {W}{B}.| Orzhov Guildgate|Commander 2018|272|C||Land - Gate|||Orzhov Guildgate enters the battlefield tapped.${T}: Add {W} or {B}.| Rakdos Carnarium|Commander 2018|273|C||Land|||Rakdos Carnarium enters the battlefield tapped.$When Rakdos Carnarium enters the battlefield, return a land you control to its owner's hand.${T}: Add {B}{R}.| -Rocky Tar Pit|Commander 2018|274|U||Land|||Rocky Tar Pit enters the battlefield tapped.${T}, Sacrifice Rocky Tar Pit: Search your library for a Swamp or Mountain card and put it onto the battlefield. Then shuffle your library.| +Rocky Tar Pit|Commander 2018|274|U||Land|||Rocky Tar Pit enters the battlefield tapped.${T}, Sacrifice Rocky Tar Pit: Search your library for a Swamp or Mountain card, put it onto the battlefield, then shuffle your library.| Savage Lands|Commander 2018|275|U||Land|||Savage Lands enters the battlefield tapped.${T}: Add {B}, {R}, or {G}.| Scoured Barrens|Commander 2018|276|C||Land|||Scoured Barrens enters the battlefield tapped.$When Scoured Barrens enters the battlefield, you gain 1 life.${T}: Add {W} or {B}.| Seaside Citadel|Commander 2018|277|U||Land|||Seaside Citadel enters the battlefield tapped.${T}: Add {G}, {W}, or {U}.| @@ -34210,12 +34210,12 @@ Simic Growth Chamber|Commander 2018|282|U||Land|||Simic Growth Chamber enters th Submerged Boneyard|Commander 2018|283|U||Land|||Submerged Boneyard enters the battlefield tapped.${T}: Add {U} or {B}.| Swiftwater Cliffs|Commander 2018|284|C||Land|||Swiftwater Cliffs enters the battlefield tapped.$When Swiftwater Cliffs enters the battlefield, you gain 1 life.${T}: Add {U} or {R}.| Temple of the False God|Commander 2018|285|U||Land|||{T}: Add {C}{C}. Activate this ability only if you control five or more lands.| -Terramorphic Expanse|Commander 2018|286|C||Land|||{T}, Sacrifice Terramorphic Expanse: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.| +Terramorphic Expanse|Commander 2018|286|C||Land|||{T}, Sacrifice Terramorphic Expanse: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| Thornwood Falls|Commander 2018|287|C||Land|||Thornwood Falls enters the battlefield tapped.$When Thornwood Falls enters the battlefield, you gain 1 life.${T}: Add {G} or {U}.| Tranquil Cove|Commander 2018|288|C||Land|||Tranquil Cove enters the battlefield tapped.$When Tranquil Cove enters the battlefield, you gain 1 life.${T}: Add {W} or {U}.| Tranquil Expanse|Commander 2018|289|U||Land|||Tranquil Expanse enters the battlefield tapped.${T}: Add {G} or {W}.| Tranquil Thicket|Commander 2018|290|C||Land|||Tranquil Thicket enters the battlefield tapped.${T}: Add {G}.$Cycling {G}| -Warped Landscape|Commander 2018|291|C||Land|||{T}: Add {C}.${2}, {T}, Sacrifice Warped Landscape: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.| +Warped Landscape|Commander 2018|291|C||Land|||{T}: Add {C}.${2}, {T}, Sacrifice Warped Landscape: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| Woodland Stream|Commander 2018|292|C||Land|||Woodland Stream enters the battlefield tapped.${T}: Add {G} or {U}.| Plains|Commander 2018|293|C||Basic Land - Plains|||({T}: Add {W}.)| Plains|Commander 2018|294|C||Basic Land - Plains|||({T}: Add {W}.)| @@ -34300,77 +34300,261 @@ Tobias Beckett|Star Wars|614|R|{3}{B}|Legendary Creature - Human Hunter|4|3|When Underground Forum|Star Wars|615|U||Land|||T: Add {1}.${1}, {T}: Add {B}, {R}, or {G}.${2}, {T}: Put a bounty counter on target creature.| Blade Instructor|Guilds of Ravnica|1|C|{2}{W}|Creature - Human Soldier|3|1|Mentor| Bounty Agent|Guilds of Ravnica|2|R|{1}{W}|Creature - Human Soldier|2|2|Vigilance${T}, Sacrifice Bounty Agent: Destroy target legendary permanent that's an artifact, creature, or enchantment.| +Candlelight Vigil|Guilds of Ravnica|3|C|{3}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +3/+2 and has vigilance.| +Citywide Bust|Guilds of Ravnica|4|R|{1}{W}{W}|Sorcery|||Destroy all creatures with toughness 4 or greater.| +Collar the Culprit|Guilds of Ravnica|5|C|{3}{W}|Instant|||Destroy target creature with toughness 4 or greater.| Conclave Tribunal|Guilds of Ravnica|6|U|{3}{W}|Enchantment|||Convoke$When Conclave Tribunal enters the battlefield, exile target nonland permanent an opponent controls until Conclave Tribunal leaves the battlefield.| +Crush Contraband|Guilds of Ravnica|7|U|{3}{W}|Instant|||Choose one or both —$• Exile target artifact.$• Exile target enchantment.| +Dawn of Hope|Guilds of Ravnica|8|R|{1}{W}|Enchantment|||Whenever you gain life, you may pay {2}. If you do, draw a card.${3}{W}: Create a 1/1 white Soldier creature token with lifelink.| +Demotion|Guilds of Ravnica|9|U|{W}|Enchantment - Aura|||Enchant creature$Enchanted creature can't block and its activated abilities can't be activated.| +Divine Visitation|Guilds of Ravnica|10|M|{3}{W}{W}|Enchantment|||If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead.| +Flight of Equenauts|Guilds of Ravnica|11|U|{7}{W}|Creature - Human Knight|4|5|Convoke$Flying| +Gird for Battle|Guilds of Ravnica|12|U|{W}|Sorcery|||Put a +1/+1 counter on each of up to two target creatures.| +Haazda Marshal|Guilds of Ravnica|13|U|{W}|Creature - Human Soldier|1|1|Whenever Haazda Marshal and at least two other creatures attack, create a 1/1 white Soldier creature token with lifelink.| Healer's Hawk|Guilds of Ravnica|14|C|{W}|Creature - Bird|1|1|Flying, lifelink| +Hunted Witness|Guilds of Ravnica|15|C|{W}|Creature - Human|1|1|When Hunted Witness dies, create a 1/1 white Soldier creature token with lifelink.| +Inspiring Unicorn|Guilds of Ravnica|16|U|{2}{W}{W}|Creature - Unicorn|2|2|Whenever Inspiring Unicorn attacks, creatures you control get +1/+1 until end of turn.| +Intrusive Packbeast|Guilds of Ravnica|17|C|{4}{W}|Creature - Beast|3|3|Vigilance$When Intrusive Packbeast enters the battlefield, tap up to two target creatures your opponents control.| +Ledev Guardian|Guilds of Ravnica|18|C|{3}{W}|Creature - Human Knight|2|4|Convoke| +Light of the Legion|Guilds of Ravnica|19|R|{4}{W}{W}|Creature - Angel|5|5|Flying$Mentor$When Light of the Legion dies, put a +1/+1 counter on each white creature you control.| +Loxodon Restorer|Guilds of Ravnica|20|C|{4}{W}{W}|Creature - Elephant Cleric|3|4|Convoke$When Loxodon Restorer enters the battlefield, you gain 4 life.| +Luminous Bonds|Guilds of Ravnica|21|C|{2}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature can't attack or block.| +Parhelion Patrol|Guilds of Ravnica|22|C|{3}{W}|Creature - Human Knight|2|3|Flying, vigilance$Mentor| +Righteous Blow|Guilds of Ravnica|23|C|{W}|Instant|||Righteous Blow deals 2 damage to target attacking or blocking creature.| +Roc Charger|Guilds of Ravnica|24|U|{2}{W}|Creature - Bird|1|3|Flying$Whenever Roc Charger attacks, target attacking creature without flying gains flying until end of turn.| +Skyline Scout|Guilds of Ravnica|25|C|{1}{W}|Creature - Human Scout|2|1|Whenever Skyline Scout attacks, you may pay {1}{W}. If you do, it gains flying until end of turn.| Sunhome Stalwart|Guilds of Ravnica|26|U|{1}{W}|Creature - Human Soldier|2|2|First strike$Mentor| +Sworn Companions|Guilds of Ravnica|27|C|{2}{W}|Sorcery|||Creature two 1/1 white Soldier creature tokens with lifelink.| +Take Heart|Guilds of Ravnica|28|C|{W}|Instant|||Target creature gets +2/+2 until end of turn. You gain 1 life for each attacking creature you control.| +Tenth District Guard|Guilds of Ravnica|29|C|{1}{W}|Creature - Human Soldier|2|2|When Tenth District Guard enters the battlefield, target creature gets +0/+1 until end of turn.| +Venerated Loxodon|Guilds of Ravnica|30|R|{4}{W}|Creature - Elephant Cleric|4|4|Convoke$When Venerated Loxodon enters the battlefield, put a +1/+1 counter on each creature that convoked it.| +Capture Sphere|Guilds of Ravnica|31|C|{3}{U}|Enchantment - Aura|||Flash$Enchant creature$When Capture Sphere enters the battlefield, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.| Chemister's Insight|Guilds of Ravnica|32|U|{3}{U}|Instant|||Draw two cards.$Jump-start| +Citywatch Sphinx|Guilds of Ravnica|33|U|{5}{U}|Creature - Sphinx|5|4|Flying$When Citywatch Sphinx dies, surveil 2.| +Dazzling Lights|Guilds of Ravnica|34|C|{U}|Instant|||Target creature gets -3/-0 until end of turn.$Surveil 2.| +Devious Cover-up|Guilds of Ravnica|35|C|{2}{U}{U}|Instant|||Counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard.$You may shuffle up to four target cards from your graveyard into your library.| Dimir Informant|Guilds of Ravnica|36|C|{2}{U}|Creature - Human Rogue|1|4|When Dimir Informant enters the battlefield, surveil 2.| Disdainful Stroke|Guilds of Ravnica|37|C|{1}{U}|Instant|||Counter target spell with converted mana cost 4 or greater.| Dream Eater|Guilds of Ravnica|38|M|{4}{U}{U}|Creature - Nightmare Sphinx|4|3|Flash$Flying$When Dream Eater enters the battlefield, surveil 4. When you do, you may return target nonland permanent an opponent controls to its owner's hand.| +Drowned Secrets|Guilds of Ravnica|39|R|{1}{U}|Enchantment|||Whenever you cast a blue spell, target player puts the top two cards if their library into their graveyard.| +Enhanced Surveillance|Guilds of Ravnica|40|U|{1}{U}|Enchantment|||You may look at an additional two cards each time you surveil.$Exile Enhanced Surveillance: Shuffle your graveyard into your library.| Guild Summit|Guilds of Ravnica|41|U|{2}{U}|Enchantment|||When Guild Summit enters the battlefield, you may tap any number of untapped Gates you control. Draw a card for each Gate tapped this way.$Whenever a Gate enters the battlefield under your control, draw a card.| +Leapfrog|Guilds of Ravnica|42|C|{2}{U}|Creature - Frog|3|1|Leapfrog has flying as long as you've cast and instant or sorcery spell this turn.| +Maximize Altitude|Guilds of Ravnica|43|C|{U}|Sorcery|||Target creature gets +1/+1 and gains flying until end of turn.$Jump-start| +Mission Briefing|Guilds of Ravnica|44|R|{U}{U}|Instant|||Surveil 2, then choose an instant or sorcery card in your graveyard. You may cast that card this turn. If that card would be put into your graveyard this turn, exile it instead.| Murmuring Mystic|Guilds of Ravnica|45|U|{3}{U}|Creature - Human Wizard|1|5|Whenever you cast an instant or sorcery spell, create a 1/1 blue Bird Illusion creature token with flying.| +Muse Drake|Guilds of Ravnica|46|C|{3}{U}|Creature - Drake|1|3|Flying$When Muse Drake enters the battlefield, draw a card.| Narcomoeba|Guilds of Ravnica|47|R|{1}{U}|Creature - Illusion|1|1|Flying$When Narcomoeba is put into your graveyard from your library, you may put it onto the battlefield.| -Nightveil Faerie|Guilds of Ravnica|48|U|{1}{U}|Creature - Faerie Rogue|1|2|Flying$Whenever Nightveil Faerie attacks, surveil 1.| +Nightveil Sprite|Guilds of Ravnica|48|U|{1}{U}|Creature - Faerie Rogue|1|2|Flying$Whenever Nightveil Sprite attacks, surveil 1.| +Omnispell Adept|Guilds of Ravnica|49|R|{4}{U}|Creature - Human Wizard|3|4|{2}{U}, {T}: You may cast an instant or sorcery card from your hand without paying its mana cost.| +Passwall Adept|Guilds of Ravnica|50|C|{1}{U}|Creature - Human Wizard|1|3|{2}{U}: Target creature can't be blocked this turn.| Quasiduplicate|Guilds of Ravnica|51|R|{1}{U}{U}|Sorcery|||Create a token that's a copy of target creature you control.$Jump-start| Radical Idea|Guilds of Ravnica|52|C|{1}{U}|Instant|||Draw a card.$Jump-start| +Selective Snare|Guilds of Ravnica|53|U|{X}{U}|Sorcery|||Return X target creatures of the creature type of your choice to their owner's hand.| Sinister Sabotage|Guilds of Ravnica|54|U|{1}{U}{U}|Instant|||Counter target spell.$Surveil 1.| +Thoughtbound Phantasm|Guilds of Ravnica|55|U|{U}|Creature - Spirit|2|2|Defender$Whenever you surveil, put a +1/+1 counter on Thoughtbound Phantasm.$As long as Thoughtbound Phantasm has three or more +1/+1 counters on it, it can attack as though it didn't have defender.| Unexplained Disappearance|Guilds of Ravnica|56|C|{1}{U}|Instant|||Return target creature to its owner's hand.$Surveil 1.| +Vedalken Mesmerist|Guilds of Ravnica|57|C|{1}{U}|Creature - Vedalken Wizard|2|1|Whenever Vedalken Mesmerist attacks, target creature an opponent controls gets -2/-0 until end of turn.| +Wall of Mist|Guilds of Ravnica|58|C|{1}{U}|Creature - Wall|0|5|Defender| +Watcher in the Mist|Guilds of Ravnica|59|C|{3}{U}{U}|Creature - Spirit|3|4|Flying$When Watcher in the Mist enters the battlefield, surveil 2.| +Wishcoin Crab|Guilds of Ravnica|60|C|{3}{U}|Creature - Crab|2|5|| +Barrier of Bones|Guilds of Ravnica|61|C|{B}|Creature - Skeleton Wall|0|3|Defender$When Barrier of Bones enters the battlefield, surveil 1.| +Bartizan Bats|Guilds of Ravnica|62|C|{3}{B}|Creature - Bat|3|1|Flying| +Blood Operative|Guilds of Ravnica|63|R|{1}{B}{B}|Creature - Vampire Assassin|3|1|Lifelink$When Blood Operative enters the battlefield, you may exile target card from a graveyard.$Whenever you surveil, if Blood Operative is in your graveyard, you may pay 3 life. If you do, return Blood Operative to your hand.| +Burglar Rat|Guilds of Ravnica|64|C|{1}{B}|Creature - Rat|1|1|When Burglar Rat enters the battlefield, each opponent discards a card.| +Child of Night|Guilds of Ravnica|65|C|{1}{B}|Creature - Vampire|2|1|Lifelink| +Creeping Chill|Guilds of Ravnica|66|U|{3}{B}|Sorcery|||Creeping Chill deals 3 damage to each opponent and you gain 3 life.$When Creeping Chill is put into your graveyard from your library, you may exile it. If you do, Creeping Chill deals 3 damage to each opponent and you gain 3 life.| +Dead Weight|Guilds of Ravnica|67|C|{B}|Enchantment - Aura|||Enchant creature$Enchanted creature gets -2/-2.| Deadly Visit|Guilds of Ravnica|68|C|{3}{B}{B}|Sorcery|||Destroy target creature.$Surveil 2.| -Secrets of the Mausoleum|Guilds of Ravnica|75|R|{1}{B}|Instant|||Undergrowth — Search your library for a black card with converted mana cost less than or equal to the number of creature cards in your graveyard, reveal it, put it into your hand, then shuffle your library.| +Doom Whisperer|Guilds of Ravnica|69|M|{3}{B}{B}|Creature - Nightmare Demon|6|6|Flying, trample$Pay 2 life: Surveil 2.| +Douser of Lights|Guilds of Ravnica|70|C|{4}{B}|Creature - Horror|4|5|| +Gruesome Menagerie|Guilds of Ravnica|71|R|{3}{B}{B}|Sorcery|||Choose a creature card with converted mana cost 1 in your graveyard, then do the same for creature cards with converted mana costs 2 and 3. Return those cards to the battlefield.| +Hired Poisoner|Guilds of Ravnica|72|C|{B}|Creature - Human Assassin|1|1|Deathtouch| +Kraul Swarm|Guilds of Ravnica|73|U|{4}{B}|Creature - Insect Warrior|4|1|Flying${2}{B}, Discard a creature card: Return Kraul Swarm from your graveyard to your hand.| +Lotleth Giant|Guilds of Ravnica|74|U|{6}{B}|Creature - Zombie Giant|6|5|Undergrowth — When Lotleth Giant enters the battlefield, it deals 1 damage to target opponent for each creature card in your graveyard.| +Mausoleum Secrets|Guilds of Ravnica|75|R|{1}{B}|Instant|||Undergrowth — Search your library for a black card with converted mana cost less than or equal to the number of creature cards in your graveyard, reveal it, put it into your hand, then shuffle your library.| +Mephitic Vapors|Guilds of Ravnica|76|C|{2}{B}|Sorcery|||All creatures get -1/-1 until end of turn.$Surveil 2.| +Midnight Reaper|Guilds of Ravnica|77|R|{2}{B}|Creature - Zombie Knight|3|2|Whenever a nontoken creature you control dies, Midnight Reaper deals 1 damage to you and you draw a card.| Moodmark Painter|Guilds of Ravnica|78|C|{2}{B}{B}|Creature - Human Shaman|2|3|Undergrowth — When Moodmark Painter enters the battlefield, target creature gains menace and gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard.| Necrotic Wound|Guilds of Ravnica|79|U|{B}|Instant|||Undergrowth — Target creature gets -X/-X until end of turn, where X is the number of creature cards in your graveyard. If that creature would die this turn, exile it instead.| -Whispering Spy|Guilds of Ravnica|90|U|{1}{B}|Creature - Vampire Rogue|1|3|Whenever you surveil for the first time each turn, Whispering Spy deals 1 damage to each opponent and you gain 1 life.| +Never Happened|Guilds of Ravnica|80|C|{2}{B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from that player's graveyard or hand and exile it.| +Pilfering Imp|Guilds of Ravnica|81|U|{B}|Creature - Imp|||Flying${1}{B}, {T}, Sacrifice Pilfering Imp: Target opponent reveals their hand| +Plaguecrafter|Guilds of Ravnica|82|U|{2}{B}|Creature - Human Shaman|3|2|When Plaguecrafter enters the battlefield, each player sacrifices a creature or planeswalker. Each player who can't discards a card.| +Price of Fame|Guilds of Ravnica|83|U|{3}{B}|Instant|||This spell costs {2} less to cast if it targets a legendary creature.$Destroy target creature.$Surveil 2.| +Ritual of Soot|Guilds of Ravnica|84|R|{2}{B}{B}|Sorcery|||Destroy all creatures with converted mana cost 3 or less.| +Severed Strands|Guilds of Ravnica|85|C|{1}{B}|Sorcery|||As an additional cost to cast this spell, sacrifice a creature.$You gain life equal to that sacrificed creature's toughness. Destroy target creature an opponent controls.| +Spinal Centipede|Guilds of Ravnica|86|C|{2}{B}|Creature - Insect|3|2|When Spinal Centipede dies, put a +1/+1 counter on target creature you control.| +Undercity Necrolisk|Guilds of Ravnica|87|U|{3}{B}|Creature - Zombie Lizard|3|3|{1}, Sacrifice another creature: Put a +1/+1 counter on Undercity Necrolisk. It gains menace until end of turn. Activate this ability only any time you could cast a sorcery.| +Veiled Shade|Guilds of Ravnica|88|C|{2}{B}|Creature - Shade|2|2|{1}{B}: Veiled Shade gets +1/+1 until end of turn.| +Vicious Rumors|Guilds of Ravnica|89|C|{B}|Sorcery|||Vicious Rumors deals 1 damage to each opponent. Each opponent discards a card, the puts the top card of their library into their graveyard. You gain 1 life.| +Whispering Snitch|Guilds of Ravnica|90|U|{1}{B}|Creature - Vampire Rogue|1|3|Whenever you surveil for the first time each turn, Whispering Snitch deals 1 damage to each opponent and you gain 1 life.| +Arclight Phoenix|Guilds of Ravnica|91|M|{3}{R}|Creature - Phoenix|3|2|Flying, haste$At the beginning of combat on your turn, if you've cast three or more instant and sorcery spells this turn, you may return Arclight Phoenix from your graveyard to the battlefield.| Barging Sergeant|Guilds of Ravnica|92|C|{4}{R}|Creature - Minotaur Soldier|4|2|Haste$Mentor| +Book Devourer|Guilds of Ravnica|93|U|{5}{R}|Creature - Beast|4|5|Trample$Whenever Book Devourer deals combat damage to a player, you may discard all the cards in your hand. If you do, draw that many cards.| +Command the Storm|Guilds of Ravnica|94|C|{4}{R}|Instant|||Command the Storm deals 5 damage to target creature.| +Cosmotronic Wave|Guilds of Ravnica|95|C|{3}{B}|Sorcery|||Cosmotronic Wave deals 1 damage to each creature your opponents control. Creatures your opponents control can't block this turn.| Direct Current|Guilds of Ravnica|96|C|{1}{R}{R}|Sorcery|||Direct Current deals 2 damage to any target.$Jump-start| +Electrostatic Field|Guilds of Ravnica|97|U|{1}{R}|Creature - Wall|0|4|Defender$When you cast an instant or sorcery spell, Electrostatic Field deals 1 damage to each opponent.| +Erratic Cyclops|Guilds of Ravnica|98|R|{3}{R}|Creature - Cyclops Shaman|0|8|Trample$Whenever you cast an instant or sorcery spell, Erratic Cyclops gets +X/+0 until end of turn, where X is that spell's converted mana cost.| +Experimental Frenzy|Guilds of Ravnica|99|R|{3}{R}|Enchantment|||You may look at the top card of your library any time.$You may play the top card of your library.$You can't play cards from your hand.${3}{R}: Destroy Experimental Frenzy.| +Fearless Halberdier|Guilds of Ravnica|100|C|{2}{R}|Creature - Human Warrior|3|2|| +Fire Urchin|Guilds of Ravnica|101|C|{1}{R}|Creature - Elemental|1|3|Trample$Whenever you cast an instant or sorcery spell, Fire Urchin gets +1/+0 until end of turn.| +Goblin Banneret|Guilds of Ravnica|102|U|{R}|Creature - Goblin Soldier|1|1|Mentor${1}{R}: Goblin Banneret gets +2/+0 until end of turn.| Goblin Cratermaker|Guilds of Ravnica|103|U|{1}{R}|Creature - Goblin Warrior|2|2|{1}, Sacrifice Goblin Cratermaker: Choose one —$• Goblin Cratermaker deals 2 damage to target creature.$• Destroy target colorless nonland permanent.| +Goblin Locksmith|Guilds of Ravnica|104|C|{1}{R}|Creature - Goblin Rogue|2|1|Whenever Goblin Locksmith attacks, creatures with defender can't block this turn.| +Gravitic Punch|Guilds of Ravnica|105|C|{3}{R}|Sorcery|||Target creature you control deals damage equal to its power to target player.$Jump-start| +Hellkite Whelp|Guilds of Ravnica|106|U|{4}{R}|Creature - Dragon|3|34|Flying$Whenever Hellkite Whelp attacks, it deals 1 damage to target creature defending player controls.| +Inescapable Blaze|Guilds of Ravnica|107|U|{4}{R}{R}|Instant|||This spell can't be countered.$Inescapable Flame deals 6 damage to any target.| +Lava Coil|Guilds of Ravnica|108|U|{1}{R}|Sorcery|||Lava Coil deals 4 damage to target creature. If that creature would die this turn, exile it instead.| Legion Warboss|Guilds of Ravnica|109|R|{2}{R}|Creature - Goblin Soldier|2|2|Mentor$At the beginning of combat on your turn, create a 1/1 red Goblin creature token. That token gains haste until end of turn and attacks this combat if able.| +Maniacal Rage|Guilds of Ravnica|110|C|{1}{R}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+2 and can't block.| +Maximize Velocity|Guilds of Ravnica|111|C|{R}|Sorcery|||Target creature gets +1/+1 and gains haste until end of turn.$Jump-start| +Ornery Goblin|Guilds of Ravnica|112|C|{1}{R}|Creature - Goblin Warrior|2|1|Whenever Ornery Goblin blocks or becomes blocked by a creature, Ornery Goblin deals 1 damage to that creature.| +Risk Factor|Guilds of Ravnica|113|R|{2}{R}|Instant|||Target opponent may have Risk Factor deal 4 damage to them. If that player doesn't, you draw three cards.$Jump-start| +Rubblebelt Boar|Guilds of Ravnica|114|C|{3}{R}|Creature - Boar|3|3|When Rubblebelt Boar enters the battlefield, target creature gets +2/+0 until end of turn.| Runaway Steam-Kin|Guilds of Ravnica|115|R|{1}{R}|Creature - Elemental|1|1|Whenever you cast a red spell, if Runaway Steam-Kin has fewer than three +1/+1 counters on it, put a +1/+1 counter on Runaway Steam-Kin.$Remove three +1/+1 counters from Runaway Steam-Kin: Add {R}{R}{R}.| +Smelt-War Minotaur|Guilds of Ravnica|116|U|{2}{R}|Creature - Minotaur Warrior|2|3|Whenever you cast an instant or sorcery spell, target creature an opponent controls can't block this turn.| +Street Riot|Guilds of Ravnica|117|U|{4}{R}|Enchantment|||As long as it's your turn, creatures you control get +1/+0 and have trample.| +Sure Strike|Guilds of Ravnica|118|C|{1}{R}|Instant|||Target creature gets +3/+0 and gains first strike until end of turn.| +Torch Courier|Guilds of Ravnica|119|C|{R}|Creature - Goblin|1|1|Haste$Sacrifice Torch Courier: Another target creature gains haste until end of turn.| +Wojek Bodyguard|Guilds of Ravnica|120|C|{2}{R}|Creature - Human Soldier|3|3|Mentor$Wojek Bodyguard can't attack or block alone.| +Affectionate Indrik|Guilds of Ravnica|121|U|{5}{G}|Creature - Beast|4|4|When Affectionate Indrik enters the battlefield, you may have it fight target creature you don't control.| Arboretum Elemental|Guilds of Ravnica|122|U|{7}{G}{G}|Creature - Elemental|7|5|Convoke$Hexproof| Beast Whisperer|Guilds of Ravnica|123|R|{2}{G}{G}|Creature - Elf Druid|2|3|Whenever you cast a creature spell, draw a card.| +Bounty of Might|Guilds of Ravnica|124|R|{4}{G}{G}|Instant|||Target creature gets +3/+3 until end of turn.$Target creature gets +3/+3 until end of turn.$Target creature gets +3/+3 until end of turn.| +Circuitous Route|Guilds of Ravnica|125|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards and/or Gate cards and put them onto the battlefield tapped, then shuffle your library.| +Crushing Canopy|Guilds of Ravnica|126|C|{2}{G}|Instant|||Choose one —$• Destroy target creature with flying.$• Destroy target enchantment.| +Devkarin Dissident|Guilds of Ravnica|127|C|{1}{G}|Creature - Elf Warrior|2|2|{4}{G}: Devkarin Dissident gets +2/+2 until end of turn.| District Guide|Guilds of Ravnica|128|U|{2}{G}|Creature - Elf Scout|2|2|When District Guide enters the battlefield, you may search your library for a basic land card or Gate card, reveal it, put it into your hand, then shuffle your library.| +Generous Stray|Guilds of Ravnica|129|C|{2}{G}|Creature - Cat|1|2|When Generous Stray enters the battlefield, draw a card.| +Golgari Raiders|Guilds of Ravnica|130|U|{3}{G}|Creature - Elf Warrior|0|0|Haste$Undergrowth — Golgari Raiders enters the battlefield with a +1/+1 counter on it for each creature card in your graveyard.| +Grappling Sundew|Guilds of Ravnica|131|U|{1}{G}|Creature - Plant|0|4|Defender, reach${4}{G}: Grappling Sundew gains indestructible until end of turn.| +Hatchery Spider|Guilds of Ravnica|132|R|{5}{G}{G}|Creature - Spider|5|7|Reach$Undergrowth — When you cast this spell, reveal the top X cards of your library, where X is the number of creature cards in your graveyard. You may put a green permanent card with converted mana cost X or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.| +Hitchclaw Recluse|Guilds of Ravnica|133|C|{2}{G}|Creature - Spider|1|4|Reach| +Ironshell Beetle|Guilds of Ravnica|134|C|{1}{G}|Creature - Insect|1|1|When Ironshell Beetle enters the battlefield, put a +1/+1 counter on target creature.| +Kraul Foragers|Guilds of Ravnica|135|C|{4}{G}|Creature - Insect Scout|4|4|Undergrowth — When Kraul Foragers enters the battlefield, you gain 1 life for each creature card in your graveyard.| +Kraul Harpooner|Guilds of Ravnica|136|U|{1}{G}|Creature - Insect Warrior|3|2|Reach$Undergrowth — When Kraul Harpooner enters the battlefield, choose up to one target creature with flying you don't control. Kraul Harpooner gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard, then you may have Kraul Harpooner fight that creature.| +Might of the Masses|Guilds of Ravnica|137|U|{G}|Instant|||Target creature gets +1/+1 until end of turn for each creature you control.| Nullhide Ferox|Guilds of Ravnica|138|M|{2}{G}{G}|Creature - Beast|6|6|Hexproof$You can't cast noncreature spells.${2}: Nullhide Ferox loses all abilities until end of turn. Any player may activate this ability.$If a spell or ability an opponent controls causes you to discard Nullhide Ferox, put it onto the battlefield instead of putting it into your graveyard.| +Pack's Favor|Guilds of Ravnica|139|C|{2}{G}|Instant|||Convoke$Target creature gets +3/+3 until end of turn.| +Pause for Reflection|Guilds of Ravnica|140|C|{2}{G}|Instant|||Convoke$Precent all combat damage that would be dealt this turn.| +Pelt Collector|Guilds of Ravnica|141|R|{G}|Creature - Elf Warrior|1|1|Whenever another creature you control enters the battlefield or dies, if that creature's power is greater than Pelt Collector's, put a +1/+1 counter on Pelt Collector.$As long as Pelt Collector has three or more +1/+1 counters on it, it has trample.| +Portcullis Vine|Guilds of Ravnica|142|C|{G}|Creature - Plant Wall|0|3|Defender${2}, {T}, Sacrifice a creature with defender: Draw a card.| +Prey Upon|Guilds of Ravnica|143|C|{G}|Sorcery|||Target creature you control fights target creature you don't control.| +Siege Wurm|Guilds of Ravnica|144|C|{5}{G}{G}|Creature - Wurm|5|5|Convoke$Trample| +Sprouting Renewal|Guilds of Ravnica|145|U|{2}{G}|Sorcery|||Convoke$Choose one —$• Create a 2/2 green and white Elf Knight creature token with vigilance.$• Destroy target artifact or enchantment.| +Urban Utopia|Guilds of Ravnica|146|C|{1}{G}|Enchantment - Aura|||Enchant Land$When Urban Utopia enters the battlefield, draw a card.$Enchanted land has "{T}: Add one mana of any color."| +Vigorspore Wurm|Guilds of Ravnica|147|C|{5}{G}|Creature - Wurm|6|4|Undergrowth — When Vigorspore Wurm enters the battlefield, target creature gains vigilance and gets +X/+X until end of turn, where X is the number of creature cards in your graveyard.$Vigorspore Wurm can't be blocked by more than one creature.| Vivid Revival|Guilds of Ravnica|148|R|{4}{G}|Sorcery|||Return up to three target multicolor cards from your graveyard to your hand. Exile Vivid Revival.| Wary Okapi|Guilds of Ravnica|149|C|{2}{G}|Creature - Antelope|3|2|Vigilance| +Wild Ceratok|Guilds of Ravnica|150|C|{3}{G}|Creature - Rhino|4|3|| Artful Takedown|Guilds of Ravnica|151|C|{2}{U}{B}|Instant|||Choose one or both —$• Tap target creature.$• Target creature gets -2/-4 until end of turn.| Assassin's Trophy|Guilds of Ravnica|152|R|{B}{G}|Instant|||Destroy target permanent an opponent controls. Its controller may search their library for a basic land card, put it onto the battlefield, then shuffle their library.| +Aurelia, Exemplar of Justice|Guilds of Ravnica|153|M|{2}{R}{W}|Legendary Creature - Angel|2|5|Flying$Mentor$At the beginning of combat on your turn, choose up to one target creature you control. Until end of turn, that creature gets +2/+0, gains trample if it's red, and gains vigilance if it's white.| +Beacon Bolt|Guilds of Ravnica|154|U|{1}{U}{R}|Sorcery|||Beacon Bolt deals damage to target creature equal to the total number of instant and sorcery cards you own in exile and in your graveyard.$Jump-start| +Beamsplitter Mage|Guilds of Ravnica|155|U|{U}{R}|Creature - Vedalken Wizard|2|2|Whenever you cast an instant or sorcery that targets only Beamsplitter Mage, if you control one or more creatures that the spell could target, choose one of them. Copy the spell and it targets the chosen creature.| Boros Challenger|Guilds of Ravnica|156|U|{R}{W}|Creature - Human Soldier|2|3|Mentor${2}{R}{W}: Boros Challenger gets +1/+1 until end of turn.| +Camaraderie|Guilds of Ravnica|157|R|{4}{G}{W}|Sorcery|||You gain X life and draw X cards, where X is the number of creatures you control. Creatures you control get +1/+1 until end of turn.| +Centaur Peacemaker|Guilds of Ravnica|158|C|{1}{G}{W}|Creature - Centaur Cleric|3|3|When Centaur Peacemaker enters the battlefield, each player gains 4 life.| +Chance for Glory|Guilds of Ravnica|159|M|{1}{R}{W}|Instant|||Creatures you control gain indestructible. Take an extra turn after this one. At the beginning of that turn's end step, you lose the game.| +Charnel Troll|Guilds of Ravnica|160|R|{1}{B}{G}|Creature - Troll|4|4|Trample$At the beginning of your upkeep, exile a creature card from your graveyard. If you do, put a +1/+1 counter on Charnel Troll. Otherwise sacrifice it.${B}{G}, Discard a creature card: Put a +1/+1 counter on Charnel Troll.| +Conclave Cavalier|Guilds of Ravnica|161|U|{G}{G}{W}{W}|Creature - Centaur Knight|4|4|Vigilance$When Conclave Cavalier dies, create two green and white 2/2 Elf Knight creature tokens with vigilance.| +Conclave Guildmage|Guilds of Ravnica|162|U|{G}{W}|Creature - Elf Cleric|2|2|{G}, {T}: Creatures you control gain trample until end of turn.${5}{W}, {T}: Create a 2/2 green and white Elf Knight creature token with vigilance.| +Crackling Drake|Guilds of Ravnica|163|U|{U}{U}{R}{R}|Creature - Drake|*|4|Flying$Crackling Drake's power is equal to the total number of instant and sorcery cards you own in exile and in your graveyard.$When Crackling Drake enters the battlefield, draw a card.| +Darkblade Agent|Guilds of Ravnica|164|C|{1}{U}{B}|Creature - Human Assassin|2|3|As long as you've surveilled this turn, Darkblade Agent has deathtouch and "Whenever this creature deals combat damage to a player, draw a card."| Deafening Clarion|Guilds of Ravnica|165|R|{1}{R}{W}|Sorcery|||Choose one or both —$• Deafening Clarion deals 3 damage to each creature.$• Creatures you control gain lifelink until end of turn.| +Dimir Spybug|Guilds of Ravnica|166|U|{U}{B}|Creature - Insect|1|1|Flying$Menace$Whenever you surveil, put a +1/+1 counter on Dimir Spybug.| +Disinformation Campaign|Guilds of Ravnica|167|U|{1}{U}{B}|Enchantment|||When Disinformation Campaign enters the battlefield, you draw a card and each opponent discards a card.$Whenever you surveil, return Disinformation Campaign to its owner's hand.| Emmara, Soul of the Accord|Guilds of Ravnica|168|R|{G}{W}|Legendary Creature - Elf Cleric|2|2|Whenever Emmara, Soul of the Accord becomes tapped, create a 1/1 white Soldier creature token with lifelink.| +Erstwhile Trooper|Guilds of Ravnica|169|C|{1}{B}{G}|Creature - Zombie Soldier|2|2|Discard a creature card: Erstwhile Trooper gets +2/+2 and gains trample until end of turn. Activate this ability only once each turn.| +Etrata, the Silencer|Guilds of Ravnica|170|R|{2}{U}{B}|Legendary Creature - Vampire Assassin|3|5|Etrata, the Silencer can't be blocked.$Whenever Etrata deals combat damage to a player, exile target creature that player controls and put a hit counter on that card. That player loses the game if they own three or more exiled cards with hit counters on them. Etrata's owner shuffles Etrata into their library.| Firemind's Research|Guilds of Ravnica|171|R|{U}{R}|Enchantment|||Whenever you cast an instant or sorcery spell, put a charge counter on Firemind's Research.${1}{U}, Remove two charge counters from Firemind's Research: Draw a card.${1}{R}, Remove five charge counters from Firemind's Research: It deals 5 damage to any target.| +Garrison Sergeant|Guilds of Ravnica|172|C|{3}{R}{W}|Creature - Viashino Soldier|3|3|Garrison Sergeant has double strike as long as you control a Gate.| +Glowspore Shaman|Guilds of Ravnica|173|U|{B}{G}|Creature - Elf Shaman|3|1|When Glowspore Shaman enters the battlefield, put the top three cards of your library into your graveyard. You may put a land card from your graveyard on top of your library.| Goblin Electromancer|Guilds of Ravnica|174|C|{U}{R}|Creature - Goblin Wizard|2|2|Instant and sorcery spells you cast cost {1} less to cast.| +Golgari Findbroker|Guilds of Ravnica|175|U|{B}{B}{G}{G}|Creature - Elf Shaman|3|4|When Golgari Findbroker enters the battlefield, return target permanent card from your graveyard to your hand.| Hammer Dropper|Guilds of Ravnica|176|C|{2}{R}{W}|Creature - Giant Soldier|5|2|Mentor| +House Guildmage|Guilds of Ravnica|177|U|{U}{B}|Creature - Human Wizard|2|2|{1}{U}, {T}: Target creature doesn't untap during its controller's next untap step.${2}{B}, {T}: Surveil 2.| Hypothesizzle|Guilds of Ravnica|178|C|{3}{U}{R}|Instant|||Draw two cards. Then you may discard a nonland card. When you do, Hypothesizzle deals 4 damage to target creature.| Ionize|Guilds of Ravnica|179|R|{1}{U}{R}|Instant|||Counter target spell. Ionize deals 2 damage to that spell's controller.| Izoni, Thousand-Eyed|Guilds of Ravnica|180|R|{2}{B}{B}{G}{G}|Legendary Creature - Elf Shaman|2|3|Undergrowth — When Izoni, Thousand-Eyed enters the battlefield, create a 1/1 black and green Insect creature token for each creature card in your graveyard.${B}{G}, Sacrifice another creature: You gain 1 life and draw a card.| +Join Shields|Guilds of Ravnica|181|U|{3}{G}{W}|Instant|||Untap all creatures you control. They gain hexproof and indestructible until end of turn.| +Justice Strike|Guilds of Ravnica|182|U|{R}{W}|Instant|||Target creature deals damage to itself equal to its power.| +Knight of Autumn|Guilds of Ravnica|183|R|{1}{G}{W}|Creature - Dryad Knight|2|1|When Knight of Autumn enters the battlefield, choose one —$• Put two +1/+1 counters on Knight of Autumn.$• Destroy target artifact or enchantment.$• You gain 4 life.| +Lazav, the Multifarious|Guilds of Ravnica|184|M|{U}{B}|Legendary Creature - Shapeshifter|1|3|When Lazav, the Multifarious enters the battlefield, surveil 1.${X}: Lazav, the Multifarious becomes a copy of target creature card in your graveyard with converted mana cost X, except its name is Lazav, the Multifarious, it's legendary in addition to its other types, and it has this ability.| +League Guildmage|Guilds of Ravnica|185|U|{U}{R}|Creature - Human Wizard|2|2|{3}{U}, {T}: Draw a card.${X}{R}, {T}: Copy target instant or sorcery spell you control with converted mana cost X. You may choose new targets for the copy.| +Ledev Champion|Guilds of Ravnica|186|U|{1}{G}{W}|Creature - Elf Knight|2|2|Whenever Ledev Champion attacks, you may tap any number of untapped creatures you control. Ledev Champion gets +1/+1 until end of turn for each creature tapped this way.${3}{G}{W}: Create a 1/1 white soldier creature token with lifelink.| +Legion Guildmage|Guilds of Ravnica|187|U|{R}{W}|Creature - Human Wizard|2|2|{5}{R}, {T}: Legion Guildmage deals 3 damage to each opponent.${2}{W}, {T}: Tap another target creature.| March of the Multitudes|Guilds of Ravnica|188|M|{X}{G}{W}{W}|Instant|||Convoke$Create X 1/1 white Soldier creature tokens with lifelink.| +Mnemonic Betrayal|Guilds of Ravnica|189|M|{1}{U}{B}|Sorcery|||Exile all card from all opponents' graveyards. You may cast those cards this turn, and you may spend mana as though it were mana of any type to cast those spells. At the beginning of the next end step, if any of those cards remain exiled, return them to their owner's graveyards.$Exile Mnemonic Betrayal.| +Molderhulk|Guilds of Ravnica|190|U|{7}{B}{G}|Creature - Fungus Zombie|6|6|Undergrowth — This spell costs {1} less to cast for each creature card in your graveyard.$When Molderhulk enters the battlefield, return target land card from your graveyard to the battlefield.| +Nightveil Predator|Guilds of Ravnica|191|U|{U}{U}{B}{B}|Creature - Vampire|3|3|Flying, deathtouch$Hexproof| Niv-Mizzet, Parun|Guilds of Ravnica|192|R|{U}{U}{U}{R}{R}{R}|Legendary Creature - Dragon Wizard|5|5|This spell can't be countered.$Flying$Whenever you draw a card, Niv-Mizzet, Parun deals 1 damage to any target.$Whenever a player casts an instant or sorcery spell, you draw a card.| -Rain of Notions|Guilds of Ravnica|193|C|{1}{U}{B}|Sorcery|||Surveil 2, then draw two cards. Rain of Notions deals 2 damage to you.| +Notion Rain|Guilds of Ravnica|193|C|{1}{U}{B}|Sorcery|||Surveil 2, then draw two cards. Notion Rain deals 2 damage to you.| +Ochran Assassin|Guilds of Ravnica|194|U|{1}{B}{G}|Creature - Elf Assassin|1|1|Deathtouch$All creatures able to block Ochran Assassin do so.| Ral, Izzet Viceroy|Guilds of Ravnica|195|M|{3}{U}{R}|Legendary Planeswalker - Ral|5|+1: Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard.$-3: Ral, Izzet Viceroy deals damage to target creature equal to the total number of instant and sorcery cards you own in exile and in your graveyard.$-8: You get an emblem with "Whenever you cast an instant or sorcery spell, this emblem deals 4 damage to any target and you draw two cards."| +Rhizome Lurcher|Guilds of Ravnica|196|C|{2}{B}{G}|Creature - Fungus Zombie|2|2|Undergrowth — Rhizome Lurcher enters the battlefield with a number of +1/+1 counters on it equal to the number of creature cards in your graveyard.| Rosemane Centaur|Guilds of Ravnica|197|C|{3}{G}{W}|Creature - Centaur Soldier|4|4|Convoke$Vigilance| +Skyknight Legionnaire|Guilds of Ravnica|198|C|{1}{R}{W}|Creature - Human Knight|2|2|Flying, haste| Sonic Assault|Guilds of Ravnica|199|C|{1}{U}{R}|Instant|||Tap target creature. Sonic Assault deals 2 damage to that creature's controller.$Jump-start| Sumala Woodshaper|Guilds of Ravnica|200|C|{2}{G}{W}|Creature - Elf Druid|2|1|When Sumala Woodshaper enters the battlefield, look at the top four cards of your library. You may reveal a creature or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Swarm Guildmage|Guilds of Ravnica|201|U|{B}{G}|Creature - Elf Shaman|2|2|{4}{B}, {T}: Creatures you control get +1/+0 and gain menace until end of turn.${1}{G}, {T}: You gain 2 life.| +Swathcutter Giant|Guilds of Ravnica|202|U|{4}{R}{W}|Creature - Giant Soldier|5|5|Vigilance$Whenever Swathcutter Giant attacks, it deals 1 damage to each creature defending player controls.| +Swiftblade Vindicator|Guilds of Ravnica|203|R|{R}{W}|Creature - Human Soldier|1|1|Double strike, vigilance, trample| +Tajic, Legion's Edge|Guilds of Ravnica|204|R|{1}{R}{W}|Legendary Creature - Human Soldier|3|2|Haste$Mentor$Prevent all noncombat damage that would be dealt to other creatures you control.${R}{W}: Tajic, Legion's Edge gains first strike until end of turn.| +Thief of Sanity|Guilds of Ravnica|205|R|{1}{U}{B}|Creature - Specter|2|2|Flying$Whenever Thief of Sanity deals combat damage to a player, look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it.| Thought Erasure|Guilds of Ravnica|206|U|{U}{B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from it. That player discards that card.$Surveil 1.| +Thousand-Year Storm|Guilds of Ravnica|207|M|{4}{U}{R}|Enchantment|||Whenever you cast an instant or sorcery spell, copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies.| +Trostani Discordant|Guilds of Ravnica|208|M|{3}{G}{W}|Legendary Creature - Dryad|1|4|Other creatures you control get +1/+1.$When Trostani Discordant enters the battlefield, create two 1/1 white Soldier creature tokens with lifelink.$At the beginning of your end step, each player gains control of all creatures they own.| +Truefire Captain|Guilds of Ravnica|209|U|{R}{R}{W}{W}|Creature - Human Knight|4|3|Mentor$Whenever Truefire Captain is dealt damage, it deals that much damage to target player.| +Undercity Uprising|Guilds of Ravnica|210|C|{2}{B}{G}|Sorcery|||Creatures you control gain deathtouch until end of turn. Target creature you control fights target creature you don't control.| Underrealm Lich|Guilds of Ravnica|211|M|{3}{B}{G}|Creature - Zombie Elf Shaman|4|3|If you would draw a card, instead look at the top three cards of your library, then put one into your hand and the rest into your graveyard.$Pay 4 life: Underrealm Lich gains indestructible until end of turn. Tap it.| -Fresh-Faced Recruit|Guilds of Ravnica|216|C|{1}{R/W}|Creature - Human Solider|2|1|As long as it's your turn, Fresh-Faced Recruit has first strike.| +Unmoored Ego|Guilds of Ravnica|212|R|{1}{U}{B}|Sorcery|||Choose a card name. Search target opponent's graveyard, hand, and library for up to four cards with that name and exile them. That player shuffles their library, then draws a card for each card exiled from their hand this way.| +Vraska, Golgari Queen|Guilds of Ravnica|213|M|{2}{B}{G}|Legendary Planeswalker - Vraska|4|+2: You may sacrifice another permanent. If you do, you gain 1 life and draw a card.$-3: Destroy target nonland permanent with converted mana cost 3 or less.$-9: You get an emblem with "Whenever a creature you control deals combat damage to a player, that player loses the game."| +Wee Dragonauts|Guilds of Ravnica|214|U|{1}{U}{R}|Creature - Faerie Wizard|1|3|Flying$Whenever you cast an instant or sorcery spell, Wee Dragonauts gets +2/+0 until end of turn.| +Worldsoul Colossus|Guilds of Ravnica|215|U|{X}{G}{W}|Creature - Elemental|0|0|Convoke$Worldsoul Colossus enters the battlefield with X +1/+1 counters on it.| +Fresh-Faced Recruit|Guilds of Ravnica|216|C|{1}{R/W}|Creature - Human Soldier|2|1|As long as it's your turn, Fresh-Faced Recruit has first strike.| +Piston-Fist Cyclops|Guilds of Ravnica|217|C|{1}{U/R}{U/R}|Creature - Cyclops|4|3|Defender$As long as you've cast an instant or sorcery spell this turn, Piston-Fist Cyclops can attack as though it didn't have defender.| +Pitiless Gorgon|Guilds of Ravnica|218|C|{1}{B/G}{B/G}|Creature - Gorgon|2|2|Deathtouch| +Vernadi Shieldmate|Guilds of Ravnica|219|C|{1}{G/W}|Creature - Human Soldier|2|2|Vigilance| Whisper Agent|Guilds of Ravnica|220|C|{1}{U/B}{U/B}|Creature - Human Rogue|3|2|Flash$When Whisper Agent enters the battlefield, surveil 1.| +Assemble|Guilds of Ravnica|221|R|{4}{G}{W}|Instant|||Create three 2/2 green and white Elf Knight creature tokens with vigilance.| +Assure|Guilds of Ravnica|221|R|{G/W}{G/W}|Instant|||Put a +1/+1 counter on target creature. It gains indestructible until end of turn.| +Concoct|Guilds of Ravnica|222|R|{3}{U}{B}|Sorcery|||Surveil 3, then return a creature card from your graveyard to the battlefield.| +Connive|Guilds of Ravnica|222|R|{2}{U/B}{U/B}|Sorcery|||Gain control of target creature with power 2 or less.| +Discovery|Guilds of Ravnica|223|U|{1}{U/B}|Sorcery|||Surveil 2, then draw a card.| +Dispersal|Guilds of Ravnica|223|U|{3}{U}{B}|Instant|||Each opponent returns a nonland permanent they control with the highest converted mana cost among permanents they control to its owner's hand, then discards a card.| Expansion|Guilds of Ravnica|224|R|{U/R}{U/R}|Instant|||Copy target instant or sorcery spell with converted mana cost 4 or less. You may choose new targets for the copy.| Explosion|Guilds of Ravnica|224|R|{X}{U}{U}{R}{R}|Instant|||Explosion deals X damage to any target. Target player draws X cards.| Finality|Guilds of Ravnica|225|R|{4}{B}{G}|Sorcery|||You may put two +1/+1 counters on a creature you control. Then all creatures get -4/-4 until end of turn.| Find|Guilds of Ravnica|225|R|{B/G}{B/G}|Sorcery|||Return up to two target creature cards from your graveyard to your hand.| +Flourish|Guilds of Ravnica|226|U|{4}{G}{W}|Sorcery|||Creatures you control get +2/+2 until end of turn.| +Flower|Guilds of Ravnica|226|U|{G/W}|Sorcery|||Search your library for a basic Forest or Plains card, reveal it, put it into your hand, then shuffle your library.| +Integrity|Guilds of Ravnica|227|U|{R/W}|Instant|||Target creature gets +2/+2 until end of turn.| +Intervention|Guilds of Ravnica|227|U|{2}{R}{W}|Instant|||Intervention deals 3 damage to any target and you gain 3 life.| +Invent|Guilds of Ravnica|228|U|{4}{U}{R}|Instant|||Search your library for an instant card and/or a sorcery card, reveal them, put them into your hand, then shuffle your library.| +Invert|Guilds of Ravnica|228|U|{U/R}|Instant|||Switch the power and toughness of each of up to two target creatures until end of turn.| Response|Guilds of Ravnica|229|R|{R/W}{R/W}|Instant|||Response deals 5 damage to target attacking or blocking creature.| Resurgence|Guilds of Ravnica|229|R|{3}{R}{W}|Sorcery|||Creatures you control gain first strike and vigilance until end of turn. After this main phase, there is an additional combat phase followed by an additional main phase.| Statue|Guilds of Ravnica|230|U|{2}{B}{G}|Instant|||Destroy target artifact, creature, or enchantment.| Status|Guilds of Ravnica|230|U|{B/G}|Instant|||Target creature gets +1/+1 and gains deathtouch until end of turn.| Boros Locket|Guilds of Ravnica|231|C|{3}|Artifact|||{T}: Add {R} or {W}.${R/W}{R/W}{R/W}{R/W}, {T}, Sacrifice Boros Locket: Draw two cards.| +Chamber Sentry|Guilds of Ravnica|232|R|{X}|Artifact Creature - Construct|0|0|Chamber Sentry enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.${X}, {T}, Remove X +1/+1 counters from Chamber Sentry: It deals X damage to any target.${W}{U}{B}{R}{G}: Return Chamber Sentry from your graveyard to your hand.| Chromatic Lantern|Guilds of Ravnica|233|R|{3}|Artifact|||Lands you control have "{T}: Add one mana of any color."${T}: Add one mana of any color.| Dimir Locket|Guilds of Ravnica|234|C|{3}|Artifact|||{T}: Add {U} or {B}.${U/B}{U/B}{U/B}{U/B}, {T}, Sacrifice Dimir Locket: Draw two cards.| +Gatekeeper Gargoyle|Guilds of Ravnica|235|U|{6}|Artifact Creature - Gargoyle|3|3|Flying$Gargoyle Guardian enters the battlefield with a +1/+1 counter on it for each Gate you control.| +Glaive of the Guildpact|Guilds of Ravnica|236|U|{2}|Artifact - Equipment|||Equipped creature gets +1/+0 for each Gate you control and has vigilance and menace.$Equip {3}| Golgari Locket|Guilds of Ravnica|237|C|{3}|Artifact|||{T}: Add {B} or {G}.${B/G}{B/G}{B/G}{B/G}, {T}, Sacrifice Golgari Locket: Draw two cards.| Izzet Locket|Guilds of Ravnica|238|C|{3}|Artifact|||{T}: Add {U} or {R}.${U/R}{U/R}{U/R}{U/R}, {T}, Sacrifice Izzet Locket: Draw two cards.| +Rampaging Monument|Guilds of Ravnica|239|U|{4}|Artifact Creature - Cleric|0|0|Trample$Rampaging Monument enters the battlefield with three +1/+1 counters on it.$Whenever you cast a multicolored spell, put a +1/+1 counter on Rampaging Monument.| Selesnya Locket|Guilds of Ravnica|240|C|{3}|Artifact|||{T}: Add {G} or {W}.${G/W}{G/W}{G/W}{G/W}, {T}, Sacrifice Selesnya Locket: Draw two cards.| +Silent Dart|Guilds of Ravnica|241|U|{1}|Artifact|||{4}, {T}, Sacrifice Silent Dart: It deals 3 damage to target creature.| +Wand of Vertebrae|Guilds of Ravnica|242|U|{1}|Artifact|||{T}: Put the top card of your library into your graveyard.${2}, {T}, Exile Wand of Vertebrae: Shuffle up to five target cards from your graveyard into your library.| Boros Guildgate|Guilds of Ravnica|243|C||Land - Gate|||Boros Guildgate enters the battlefield tapped.${T}: Add {R} or {W}.| Dimir Guildgate|Guilds of Ravnica|245|C||Land - Gate|||Dimir Guildgate enters the battlefield tapped.${T}: Add {U} or {B}.| Gateway Plaza|Guilds of Ravnica|247|C||Land - Gate|||Gateway Plaza enters the battlefield tapped.$When Gateway Plaza enters the battlefield, sacrifice it unless you pay {1}.${T}: Add one mana of any color.| Golgari Guildgate|Guilds of Ravnica|248|C||Land - Gate|||Golgari Guildgate enters the battlefield tapped.${T}: Add {B} or {G}.| +Guildmages' Forum|Guilds of Ravnica|250|R||Land|||{T}: Add {C}.${1}, {T}: Add one mana of any color. If that mana is spent on a multicolored creature spell, that creature enters the battlefield with an additional +1/+1 counter on it.| Izzet Guildgate|Guilds of Ravnica|251|C||Land - Gate|||Izzet Guildgate enters the battlefield tapped.${T}: Add {U} or {R}.| Overgrown Tomb|Guilds of Ravnica|253|R||Land - Swamp Forest|||({T}: Add {B} or {G}.)$As Overgrown Tomb enters the battlefield, you may pay 2 life. If you don't, Overgrown Tomb enters the battlefield tapped.| Sacred Foundry|Guilds of Ravnica|254|R||Land - Mountain Plains|||({T}: Add {R} or {W}.)$As Sacred Foundry enters the battlefield, you may pay 2 life. If you don't, Sacred Foundry enters the battlefield tapped.|