diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/CollectedCompany.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/CollectedCompany.java index 047b8885eb..7e2faaf46b 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/CollectedCompany.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/CollectedCompany.java @@ -55,7 +55,8 @@ public class CollectedCompany extends CardImpl { super(ownerId, 177, "Collected Company", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{G}"); this.expansionSetCode = "DTK"; - // Look at the top six cards of your library. Put up to two creature cards with converted mana cost 3 or less from among them onto the battlefield. Put the rest on the bottom of your library in any order. + // Look at the top six cards of your library. Put up to two creature cards with converted mana cost 3 or less from among them onto the battlefield. + // Put the rest on the bottom of your library in any order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(6, 2, filter, false, true, Zone.BATTLEFIELD, false)); } diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/CollectiveResistance.java b/Mage.Sets/src/mage/sets/eldritchmoon/CollectiveResistance.java new file mode 100644 index 0000000000..8ce073c744 --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/CollectiveResistance.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.EscalateAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.FilterPlayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.PlayerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class CollectiveResistance extends CardImpl { + + private static final FilterPlayer filterDiscard = new FilterPlayer("player to discard and then draw cards"); + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creature to be dealt damage"); + private static final FilterPlayer filterDamageOpponent = new FilterPlayer("opponent to be dealt damage"); + + static { + filterDamageOpponent.add(new PlayerPredicate(TargetController.OPPONENT)); + } + + public CollectiveResistance(UUID ownerId) { + super(ownerId, 123, "Collective Resistance", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{1}{R}{R}"); + this.expansionSetCode = "EMN"; + + // Escalate {1} + this.addAbility(new EscalateAbility(new GenericManaCost(1))); + + // Choose one or more — + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(3); + + // Target player discards all cards in his or her hand, then draws that many cards.; + this.getSpellAbility().addEffect(new CollectiveResistanceEffect()); + this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard)); + + // Collective Resistance deals 4 damage to target creature.; + Mode mode = new Mode(); + Effect effect = new DamageTargetEffect(4); + effect.setText("{this} deals 4 damage to target creature"); + mode.getEffects().add(effect); + mode.getTargets().add(new TargetCreaturePermanent(filterCreature)); + this.getSpellAbility().addMode(mode); + + // Collective Resistance deals 3 damage to target opponent. + mode = new Mode(); + effect = new DamageTargetEffect(3); + effect.setText("{this} deals 3 damage to target opponent"); + mode.getEffects().add(effect); + mode.getTargets().add(new TargetPlayer(1, 1, false, filterDamageOpponent)); + this.getSpellAbility().addMode(mode); + } + + public CollectiveResistance(final CollectiveResistance card) { + super(card); + } + + @Override + public CollectiveResistance copy() { + return new CollectiveResistance(this); + } +} + +class CollectiveResistanceEffect extends OneShotEffect { + + public CollectiveResistanceEffect() { + super(Outcome.Discard); + this.staticText = "Target player discards all the cards in his or her hand, then draws that many cards"; + } + + public CollectiveResistanceEffect(final CollectiveResistanceEffect effect) { + super(effect); + } + + @Override + public CollectiveResistanceEffect copy() { + return new CollectiveResistanceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); + if (targetPlayer != null) { + int count = targetPlayer.getHand().size(); + for (Card card : targetPlayer.getHand().getCards(game)) { + targetPlayer.discard(card, source, game); + } + targetPlayer.drawCards(count, game); + return false; + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/DeployTheGatewatch.java b/Mage.Sets/src/mage/sets/eldritchmoon/DeployTheGatewatch.java new file mode 100644 index 0000000000..d9ad257cef --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/DeployTheGatewatch.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +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.TargetCard; + +/** + * + * @author fireshoes + */ +public class DeployTheGatewatch extends CardImpl { + + public DeployTheGatewatch(UUID ownerId) { + super(ownerId, 20, "Deploy the Gatewatch", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{4}{W}{W}"); + this.expansionSetCode = "EMN"; + + // Look at the top seven cards of your library. Put up to two planeswalker cards from among them onto the battlefield. + // Put the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new DeployTheGatewatchEffect()); + } + + public DeployTheGatewatch(final DeployTheGatewatch card) { + super(card); + } + + @Override + public DeployTheGatewatch copy() { + return new DeployTheGatewatch(this); + } +} + +class DeployTheGatewatchEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("up to two planeswalker cards"); + + static { + filter.add(new CardTypePredicate(CardType.PLANESWALKER)); + } + + public DeployTheGatewatchEffect() { + super(Outcome.DrawCard); + this.staticText = "Look at the top seven cards of your library. Put up to two planeswalker cards from among them onto the battlefield. " + + "Put the rest on the bottom of your library in a random order"; + } + + public DeployTheGatewatchEffect(final DeployTheGatewatchEffect effect) { + super(effect); + } + + @Override + public DeployTheGatewatchEffect copy() { + return new DeployTheGatewatchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + // Look at the top seven cards of your library. + Cards cards = new CardsImpl(); + boolean planeswalkerIncluded = false; + for (int i = 0; i < 7; i++) { + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + if (filter.match(card, game)) { + planeswalkerIncluded = true; + } + } + } + player.lookAtCards("Deploy the Gatewatch", cards, game); + + // Put up to two planeswalker cards from among them onto the battlefield. + if (planeswalkerIncluded) { + TargetCard target = new TargetCard(0, 2, Zone.LIBRARY, filter); + if (player.choose(Outcome.DrawCard, cards, target, game)) { + Cards pickedCards = new CardsImpl(target.getTargets()); + cards.removeAll(pickedCards); + player.moveCards(pickedCards.getCards(game), Zone.BATTLEFIELD, source, game); + } + } + + // Put the rest on the bottom of your library in a random order + while (cards.size() > 0) { + Card card = cards.getRandom(game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/IncendiaryFlow.java b/Mage.Sets/src/mage/sets/eldritchmoon/IncendiaryFlow.java new file mode 100644 index 0000000000..b718283422 --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/IncendiaryFlow.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.replacement.DealtDamageToCreatureBySourceDies; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetCreatureOrPlayer; +import mage.watchers.common.DamagedByWatcher; + +/** + * + * @author fireshoes + */ +public class IncendiaryFlow extends CardImpl { + + public IncendiaryFlow(UUID ownerId) { + super(ownerId, 133, "Incendiary Flow", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{R}"); + this.expansionSetCode = "EMN"; + + // Incendiary Flow deals 3 damage to target creature or player. If a creature dealt damage this way would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn); + effect.setText("If a creature dealt damage this way would die this turn, exile it instead"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addWatcher(new DamagedByWatcher()); + } + + public IncendiaryFlow(final IncendiaryFlow card) { + super(card); + } + + @Override + public IncendiaryFlow copy() { + return new IncendiaryFlow(this); + } +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java b/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java new file mode 100644 index 0000000000..e7cac1e1a2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java @@ -0,0 +1,98 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.permanent.token.SpiderToken; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class IshkanahGrafwidow extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each Spider you control"); + + static { + filter.add(new SubtypePredicate("Spider")); + } + + public IshkanahGrafwidow(UUID ownerId) { + super(ownerId, 162, "Ishkanah, Grafwidow", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{4}{G}"); + this.expansionSetCode = "EMN"; + this.supertype.add("Legendary"); + this.subtype.add("Spider"); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Delirium &mdash When Ishkanah, Grafwidow enters the battlefield, if there are four or more card types among cards in your graveyard, + // put three 1/2 green Spider creature tokens with reach onto the battlefield. + Ability ability = new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiderToken(), 3), false), + new DeliriumCondition(), + "Delirium — When {this} enters the battlefield, if there are four or more card types among cards in your graveyard, " + + "put three 1/2 green Spider creature tokens with reach onto the battlefield."); + this.addAbility(ability); + + // {5}{B}: Target opponent loses 1 life for each Spider you control. + PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(count), new ManaCostsImpl("{6}{B}")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public IshkanahGrafwidow(final IshkanahGrafwidow card) { + super(card); + } + + @Override + public IshkanahGrafwidow copy() { + return new IshkanahGrafwidow(this); + } +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/LilianaTheLastHope.java b/Mage.Sets/src/mage/sets/eldritchmoon/LilianaTheLastHope.java new file mode 100644 index 0000000000..e248fb5886 --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/LilianaTheLastHope.java @@ -0,0 +1,173 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.command.Emblem; +import mage.game.permanent.token.ZombieToken; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class LilianaTheLastHope extends CardImpl { + + public LilianaTheLastHope(UUID ownerId) { + super(ownerId, 93, "Liliana, the Last Hope", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{1}{B}{B}"); + this.expansionSetCode = "EMN"; + this.subtype.add("Liliana"); + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); + + // +1: Up to one target creature gets -2/-1 until your next turn. + Effect effect = new BoostTargetEffect(-2, -1, Duration.UntilYourNextTurn); + effect.setText("Up to one target creature gets -2/-1 until your next turn"); + Ability ability = new LoyaltyAbility(effect, 1); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // -2: Put the top two cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand. + ability = new LoyaltyAbility(new PutTopCardOfLibraryIntoGraveControllerEffect(2), -2); + ability.addEffect(new LilianaTheLastHopeEffect()); + this.addAbility(ability); + + // -7: You get an emblem with "At the beginning of your end step, put X 2/2 black Zombie creature tokens onto the battlefield, + // where X is two plus the number of Zombies you control." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new LilianaTheLastHopeEmblem()), -7)); + } + + public LilianaTheLastHope(final LilianaTheLastHope card) { + super(card); + } + + @Override + public LilianaTheLastHope copy() { + return new LilianaTheLastHope(this); + } +} + +class LilianaTheLastHopeEffect extends OneShotEffect { + + public LilianaTheLastHopeEffect() { + super(Outcome.ReturnToHand); + this.staticText = ", then you may return a creature card from your graveyard to your hand"; + } + + public LilianaTheLastHopeEffect(final LilianaTheLastHopeEffect effect) { + super(effect); + } + + @Override + public LilianaTheLastHopeEffect copy() { + return new LilianaTheLastHopeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + target.setNotTarget(true); + if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) + && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + } + } + return true; + } +} +class LilianaTheLastHopeEmblem extends Emblem { + + public LilianaTheLastHopeEmblem() { + this.setName("EMBLEM: Liliana, the Last Hope"); + Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.COMMAND, new CreateTokenEffect(new ZombieToken(), new LilianaZombiesCount()), + TargetController.YOU, null, false); + this.getAbilities().add(ability); + } +} + +class LilianaZombiesCount implements DynamicValue { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new SubtypePredicate("Zombie")); + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int amount = game.getBattlefield().countAll(filter, sourceAbility.getControllerId(), game) + 2; + return amount; + } + + @Override + public DynamicValue copy() { + return new LilianaZombiesCount(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "two plus the number of Zombies you control"; + } +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/OathOfLiliana.java b/Mage.Sets/src/mage/sets/eldritchmoon/OathOfLiliana.java new file mode 100644 index 0000000000..c6db80f4ab --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/OathOfLiliana.java @@ -0,0 +1,144 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.token.ZombieToken; +import mage.watchers.Watcher; + +/** + * + * @author fireshoes + */ +public class OathOfLiliana extends CardImpl { + + public OathOfLiliana(UUID ownerId) { + super(ownerId, 99, "Oath of Liliana", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + this.expansionSetCode = "EMN"; + this.supertype.add("Legendary"); + + // When Oath of Liliana enters the battlefield, each opponent sacrifices a creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeOpponentsEffect(new FilterControlledCreaturePermanent("a creature")), false)); + + // At the beginning of each end step, if a planeswalker entered the battlefield under your control this turn, put a 2/2 black Zombie creature token onto the battlefield. + this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect(new ZombieToken()), + TargetController.ANY, false), OathOfLilianaCondition.getInstance(), + "At the beginning of each end step, if a planeswalker entered the battlefield under your control this turn, " + + "put a 2/2 black Zombie creature token onto the battlefield."), new OathOfLilianaWatcher()); + } + + public OathOfLiliana(final OathOfLiliana card) { + super(card); + } + + @Override + public OathOfLiliana copy() { + return new OathOfLiliana(this); + } +} + +class OathOfLilianaCondition implements Condition { + + private static final OathOfLilianaCondition fInstance = new OathOfLilianaCondition(); + + public static Condition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + OathOfLilianaWatcher watcher = (OathOfLilianaWatcher) game.getState().getWatchers().get("OathOfLilianaWatcher"); + return watcher != null && watcher.enteredPlaneswalkerForPlayer(source.getControllerId()); + } + + @Override + public String toString() { + return "if a planeswalker entered the battlefield under your control this turn"; + } + +} + +class OathOfLilianaWatcher extends Watcher { + + private final Set players = new HashSet<>(); + + public OathOfLilianaWatcher() { + super("OathOfLilianaWatcher", WatcherScope.GAME); + } + + public OathOfLilianaWatcher(final OathOfLilianaWatcher watcher) { + super(watcher); + this.players.addAll(watcher.players); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getToZone().equals(Zone.BATTLEFIELD) + && zEvent.getTarget().getCardType().contains(CardType.PLANESWALKER)) { + players.add(zEvent.getTarget().getControllerId()); + } + } + } + + @Override + public void reset() { + players.clear(); + } + + public boolean enteredPlaneswalkerForPlayer(UUID playerId) { + return players.contains(playerId); + } + + @Override + public OathOfLilianaWatcher copy() { + return new OathOfLilianaWatcher(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/SelflessSoul.java b/Mage.Sets/src/mage/sets/eldritchmoon/SelflessSoul.java new file mode 100644 index 0000000000..ac77c10b81 --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/SelflessSoul.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class SelflessSoul extends CardImpl { + + public SelflessSoul(UUID ownerId) { + super(ownerId, 40, "Selfless Soul", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "EMN"; + this.subtype.add("Spirit"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Sacrifice Selfless Soul: Creatures you control gain indestructible until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, + new FilterControlledCreaturePermanent("creatures you control")), new SacrificeSourceCost())); + } + + public SelflessSoul(final SelflessSoul card) { + super(card); + } + + @Override + public SelflessSoul copy() { + return new SelflessSoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java b/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java new file mode 100644 index 0000000000..7a9a50b9d2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author fireshoes + */ +public class SpiritOfTheHunt extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each other creature you control that's a Wolf or Werewolf"); + + static { + filter.add(Predicates.or(new SubtypePredicate("Wolf"), + new SubtypePredicate("Werewolf"))); + } + + public SpiritOfTheHunt(UUID ownerId) { + super(ownerId, 170, "Spirit of the Hunt", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + this.expansionSetCode = "EMN"; + this.subtype.add("Wolf"); + this.subtype.add("Spirit"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Spirit of the Hunt enters the battlefield, each other creature you control that's a Wolf or a Werewolf gets +0/+3 until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new BoostControlledEffect(0, 3, Duration.EndOfTurn, filter, true), false)); + } + + public SpiritOfTheHunt(final SpiritOfTheHunt card) { + super(card); + } + + @Override + public SpiritOfTheHunt copy() { + return new SpiritOfTheHunt(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java index 98333d8fc9..6cfe350cf0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java @@ -5,6 +5,9 @@ */ package mage.game.permanent.token; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import mage.MageInt; import mage.abilities.keyword.ReachAbility; import mage.constants.CardType; @@ -15,6 +18,12 @@ import mage.constants.CardType; */ public class SpiderToken extends Token { + final static private List tokenImageSets = new ArrayList<>(); + + static { + tokenImageSets.addAll(Arrays.asList("INN", "EMN")); + } + public SpiderToken() { super("Spider", "1/2 green Spider creature token with reach"); cardType.add(CardType.CREATURE); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 0d0a6461ee..bad93e7eca 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -57337,6 +57337,7 @@ Cemetery Recruitment|Eldritch Moon|83|C|{1}{B}|Sorcery|||Return target creature Collective Brutality|Eldritch Moon|85|R|{1}{B}|Sorcery|||Escalate — Discard a card. (Pay this cost for each mode chosen beyond the first.)$Choose one or more — Target opponent reveals his or her hand. You choose an instant or sorcery card from it. That player discards that card.; Target creature gets -2/-2 until end of turn.; Target opponent loses 2 life and you gain 2 life.| Graf Rats|Eldritch Moon|91|C|{1}{B}|Creature - Rat|2|1|At the beginning of combat on your turn, if you both own and control Graf Rats and a creature named Midnight Scavengers, exile them, then meld them into Chittering Host.| Haunted Dead|Eldritch Moon|92|U|{3}{B}|Creature - Zombie|2|2|When Haunted Dead enters the battlefield, put a 1/1 white Spirit creature token with flying onto the battlefield.${1}{B}, Discard two cards: Return Haunted Dead from your graveyard to the battlefield tapped.| +Liliana, the Last Hope|Eldritch Moon|93|M|{1}{B}{B}|Planeswalker - Liliana|||+1: Up to one target creature gets -2/-1 until your next turn.$-2: Put the top two cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand.$-7: You get an emblem with "At the beginning of your end step, put X 2/2 black Zombie creature tokens onto the battlefield, where X is two plus the number of Zombies you control."| Midnight Scavengers|Eldritch Moon|96|C|{4}{B}|Creature - Human Rogue|3|3|When Midnight Scavengers enters the battlefield, you may return target creature card with converted mana cost 3 or less from your graveyard to your hand.$(Melds with Graf Rats.)| Murder|Eldritch Moon|97|U|{1}{B}{B}|Instant|||Destroy target creature.| Noosegraf Mob|Eldritch Moon|98|R|{4}{B}{B}|Creature - Zombie|0|0|Noosegraf Mob enters the battlefield with five +1/+1 counters on it.$Whenever a player casts a spell, remove a +1/+1 counter from Noosegraf Mob. If you do, put a 2/2 black Zombie creature token onto the battlefield.| @@ -57348,7 +57349,7 @@ Abolisher of Bloodlines|Eldritch Moon|111|R||Creature - Eldrazi Vampire|6|5|Flyi Wailing Ghoul|Eldritch Moon|112|C|{1}{B}|Creature - Zombie|1|3|When Wailing Ghoul enters the battlefield, put the top two cards of your library into your graveyard.| Whispers of Emrakul|Eldritch Moon|114|U|{1}{B}|Sorcery|||Target opponent discards a card at random.$Delirium — If there are four or more card types among cards in your graveyard, that player discards two cards at random instead.| Assembled Alphas|Eldritch Moon|117|R|{5}{R}|Creature - Wolf|5|5|Whenever Assembled Alphas blocks or becomes blocked by a creature, Assembled Alphas deals 3 damage to that creature and 3 damage to that creature's controller.| -United Resistance|Eldritch Moon|123|R|{1}{R}{R}|Sorcery|||Escalate {1} (Pay this cost for each mode chosen beyond the first.)$Choose one or more — Target player discards all cards in his or her hand, then draws that many cards.; United Resistance deals 4 damage to target creature.; United Resistance deals 3 damage to target opponent.| +Collective Resistance|Eldritch Moon|123|R|{1}{R}{R}|Sorcery|||Escalate {1} (Pay this cost for each mode chosen beyond the first.)$Choose one or more — Target player discards all cards in his or her hand, then draws that many cards.; Collective Resistance deals 4 damage to target creature.; Collective Resistance deals 3 damage to target opponent.| Galvanic Bombardment|Eldritch Moon|129|C|{R}|Instant|||Galvanic Bombardment deals X damage to target creature, where X is 2 plus the number of cards named Galvanic Bombardment in your graveyard.| Hanweir Garrison|Eldritch Moon|130|R|{2}{R}|Creature - Human Soldier|2|3|Whenever Hanweir Garrison attacks, put two 1/1 red Human creature tokens onto the battlefield tapped and attacking.$(Melds with Hanweir Battlements.)| Hanweir, the Writhing Township|Eldritch Moon|130|R||Legendary Creature - Eldrazi Ooze|7|4|Trample, haste$Whenever Hanweir, the Writhing Township attacks, put two 3/2 colorless Eldrazi Horror creature tokens onto the battlefield tapped and attacking.|