diff --git a/Mage.Sets/src/mage/cards/d/DrudgeSentinel.java b/Mage.Sets/src/mage/cards/d/DrudgeSentinel.java new file mode 100644 index 0000000000..3bec34e324 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DrudgeSentinel.java @@ -0,0 +1,72 @@ +/* + * 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.cards.d; + +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.TapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +/** + * @author JRHerlehy + * Created on 4/7/18. + */ +public class DrudgeSentinel extends CardImpl { + + public DrudgeSentinel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.SKELETON, SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {3}: Tap Drudge Sentinel. It gains indestructible until end of turn. + Ability ability = new SimpleActivatedAbility(new TapSourceEffect(), new ManaCostsImpl("{3}")); + ability.addEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn)); + this.addAbility(ability); + } + + public DrudgeSentinel(final DrudgeSentinel card) { + super(card); + } + + @Override + public DrudgeSentinel copy() { + return new DrudgeSentinel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GenesisWave.java b/Mage.Sets/src/mage/cards/g/GenesisWave.java index aa0073d3ab..5fe9bc7693 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisWave.java +++ b/Mage.Sets/src/mage/cards/g/GenesisWave.java @@ -25,11 +25,13 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ + package mage.cards.g; import java.util.LinkedHashSet; import java.util.Set; import java.util.UUID; + import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -39,21 +41,19 @@ import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; /** - * * @author BetaSteward_at_googlemail.com */ public class GenesisWave extends CardImpl { public GenesisWave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{G}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}{G}{G}"); // Reveal the top X cards of your library. You may put any number of permanent cards with converted mana // cost X or less from among them onto the battlefield. Then put all cards revealed this way that weren't @@ -99,15 +99,9 @@ class GenesisWaveEffect extends OneShotEffect { } if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); - FilterCard filter = new FilterCard("cards with converted mana cost " + xValue + " or less to put onto the battlefield"); + FilterCard filter = new FilterPermanentCard("cards with converted mana cost " + xValue + " or less to put onto the battlefield"); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); - filter.add( - Predicates.or(new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.ENCHANTMENT), - new CardTypePredicate(CardType.LAND), - new CardTypePredicate(CardType.PLANESWALKER) - )); + TargetCard target1 = new TargetCard(0, Integer.MAX_VALUE, Zone.LIBRARY, filter); target1.setRequired(false); diff --git a/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java b/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java new file mode 100644 index 0000000000..9af594c660 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java @@ -0,0 +1,44 @@ +package mage.cards.j; + +import java.util.UUID; + +import mage.abilities.common.LegendarySpellAbility; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.target.common.TargetAnyTarget; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class JayasImmolatingInferno extends CardImpl { + + public JayasImmolatingInferno(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}"); + this.addSuperType(SuperType.LEGENDARY); + + // (You may cast a legendary sorcery only if you control a legendary creature or planeswalker.) + this.addAbility(new LegendarySpellAbility()); + + // Jaya’s Immolating Inferno deals X damage to each of up to three targets. + Effect effect = new DamageTargetEffect(new ManacostVariableValue()); + effect.setText("{this} deals X damage to each of up to three targets"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetAnyTarget(1, 3)); + } + + public JayasImmolatingInferno(final JayasImmolatingInferno card) { + super(card); + } + + @Override + public JayasImmolatingInferno copy() { + return new JayasImmolatingInferno(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KamahlsDruidicVow.java b/Mage.Sets/src/mage/cards/k/KamahlsDruidicVow.java new file mode 100644 index 0000000000..198624e5bd --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KamahlsDruidicVow.java @@ -0,0 +1,117 @@ +package mage.cards.k; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.LegendarySpellAbility; +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.SuperType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class KamahlsDruidicVow extends CardImpl { + + public KamahlsDruidicVow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}{G}"); + this.addSuperType(SuperType.LEGENDARY); + + // (You may cast a legendary sorcery only if you control a legendary creature or planeswalker.) + this.addAbility(new LegendarySpellAbility()); + + // Look at the top X cards of your library. + // You may put any number of land and/or legendary permanent cards with converted mana cost X or less from among them onto the battlefield. + // Put the rest into your graveyard. + this.getSpellAbility().addEffect(new KamahlsDruidicVowEffect()); + } + + public KamahlsDruidicVow(final KamahlsDruidicVow card) { + super(card); + } + + @Override + public KamahlsDruidicVow copy() { + return new KamahlsDruidicVow(this); + } + +} + +class KamahlsDruidicVowEffect extends OneShotEffect { + + public KamahlsDruidicVowEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "Look at the top X cards of your library. You may put any number of land and/or legendary permanent cards with converted mana cost X or less from among them onto the battlefield. Put the rest into your graveyard"; + } + + public KamahlsDruidicVowEffect(final KamahlsDruidicVowEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller == null || sourceObject == null) { + return false; + } + + Cards cards = new CardsImpl(); + int xValue = source.getManaCostsToPay().getX(); + int numCards = Math.min(controller.getLibrary().size(), xValue); + for (int i = 0; i < numCards; i++) { + Card card = controller.getLibrary().removeFromTop(game); + cards.add(card); + } + if (!cards.isEmpty()) { + FilterCard filter = new FilterPermanentCard("land and/or legendary permanent cards with converted mana cost " + xValue + " or less to put onto the battlefield"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + filter.add( + Predicates.or( + new CardTypePredicate(CardType.LAND), + new SupertypePredicate(SuperType.LEGENDARY) + )); + TargetCard target1 = new TargetCard(0, Integer.MAX_VALUE, Zone.LIBRARY, filter); + target1.setRequired(false); + + controller.choose(Outcome.PutCardInPlay, cards, target1, game); + Set toBattlefield = new LinkedHashSet<>(); + for (UUID cardId : target1.getTargets()) { + Card card = cards.get(cardId, game); + if (card != null) { + cards.remove(card); + toBattlefield.add(card); + } + } + controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, false, false, false, null); + controller.moveCards(cards, Zone.GRAVEYARD, source, game); + } + return true; + } + + @Override + public KamahlsDruidicVowEffect copy() { + return new KamahlsDruidicVowEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java b/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java new file mode 100644 index 0000000000..94a6e8e3c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java @@ -0,0 +1,85 @@ +package mage.cards.k; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.LegendarySpellAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.turn.TurnMod; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetNonlandPermanent; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class KarnsTemporalSundering extends CardImpl { + + public KarnsTemporalSundering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); + this.addSuperType(SuperType.LEGENDARY); + + // (You may cast a legendary sorcery only if you control a legendary creature or planeswalker.) + this.addAbility(new LegendarySpellAbility()); + + // Target player takes an extra turn after this one. Return up to one target nonland permanent to its owner’s hand. Exile Karn’s Temporal Sundering. + this.getSpellAbility().addEffect(new KarnsTemporalSunderingEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + } + + public KarnsTemporalSundering(final KarnsTemporalSundering card) { + super(card); + } + + @Override + public KarnsTemporalSundering copy() { + return new KarnsTemporalSundering(this); + } +} + +class KarnsTemporalSunderingEffect extends OneShotEffect { + + public KarnsTemporalSunderingEffect() { + super(Outcome.ExtraTurn); + this.staticText = "Target player takes an extra turn after this one. Return up to one target nonland permanent to its owner’s hand"; + } + + public KarnsTemporalSunderingEffect(final KarnsTemporalSunderingEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + game.getState().getTurnMods().add(new TurnMod(source.getTargets().getFirstTarget(), false)); + + Permanent returnPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + + if (returnPermanent != null) { + Card returnCard = returnPermanent.getMainCard(); + Player cardOwner = game.getPlayer(returnCard.getOwnerId()); + cardOwner.moveCards(returnCard, Zone.HAND, source, game); + } + + return true; + } + + @Override + public KarnsTemporalSunderingEffect copy() { + return new KarnsTemporalSunderingEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PrimevalsGloriousRebirth.java b/Mage.Sets/src/mage/cards/p/PrimevalsGloriousRebirth.java new file mode 100644 index 0000000000..9e1963d270 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrimevalsGloriousRebirth.java @@ -0,0 +1,77 @@ +package mage.cards.p; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.LegendarySpellAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class PrimevalsGloriousRebirth extends CardImpl { + + public PrimevalsGloriousRebirth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{W}{B}"); + this.addSuperType(SuperType.LEGENDARY); + + // (You may cast a legendary sorcery only if you control a legendary creature or planeswalker.) + this.addAbility(new LegendarySpellAbility()); + + // Return all legendary permanent cards from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new PrimevalsGloriousRebirthEffect()); + } + + public PrimevalsGloriousRebirth(final PrimevalsGloriousRebirth card) { + super(card); + } + + @Override + public PrimevalsGloriousRebirth copy() { + return new PrimevalsGloriousRebirth(this); + } + +} + +class PrimevalsGloriousRebirthEffect extends OneShotEffect { + + private static final FilterPermanentCard filter = new FilterPermanentCard(); + + static { + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public PrimevalsGloriousRebirthEffect() { + super(Outcome.Benefit); + this.staticText = "Return all legendary permanent cards from your graveyard to the battlefield"; + } + + public PrimevalsGloriousRebirthEffect(final PrimevalsGloriousRebirthEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + for (Card card : player.getGraveyard().getCards(filter, game)) { + card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); + } + } + return false; + } + + @Override + public PrimevalsGloriousRebirthEffect copy() { + return new PrimevalsGloriousRebirthEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UrzasRuinousBlast.java b/Mage.Sets/src/mage/cards/u/UrzasRuinousBlast.java new file mode 100644 index 0000000000..145e993132 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UrzasRuinousBlast.java @@ -0,0 +1,48 @@ +package mage.cards.u; + +import java.util.UUID; + +import mage.abilities.common.LegendarySpellAbility; +import mage.abilities.effects.common.ExileAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class UrzasRuinousBlast extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("nonland permanents that aren’t legendary"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY))); + } + + public UrzasRuinousBlast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + this.addSuperType(SuperType.LEGENDARY); + + // (You may cast a legendary sorcery only if you control a legendary creature or planeswalker.) + this.addAbility(new LegendarySpellAbility()); + + // Exile all nonland permanents that aren’t legendary. + this.getSpellAbility().addEffect(new ExileAllEffect(filter)); + } + + public UrzasRuinousBlast(final UrzasRuinousBlast card) { + super(card); + } + + @Override + public UrzasRuinousBlast copy() { + return new UrzasRuinousBlast(this); + } +} diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java b/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java new file mode 100644 index 0000000000..12654c0636 --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java @@ -0,0 +1,99 @@ +package mage.cards.y; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.LegendarySpellAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCreatureOrPlaneswalker; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class YawgmothsVileOffering extends CardImpl { + + private static final FilterPermanentCard cardFilter = new FilterPermanentCard(); + + static { + cardFilter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + public YawgmothsVileOffering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + this.addSuperType(SuperType.LEGENDARY); + + // (You may cast a legendary sorcery only if you control a legendary creature or planeswalker.) + this.addAbility(new LegendarySpellAbility()); + + // Put up to one target creature or planeswalker from a graveyard onto the battlefield under your control. + // Destroy up to one target creature or planeswalker. Exile Yawgmoth’s Vile Offering. + this.getSpellAbility().addEffect(new YawgmothsVireOfferingEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(0, 1, cardFilter)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + } + + public YawgmothsVileOffering(final YawgmothsVileOffering card) { + super(card); + } + + @Override + public YawgmothsVileOffering copy() { + return new YawgmothsVileOffering(this); + } +} + +class YawgmothsVireOfferingEffect extends OneShotEffect { + + public YawgmothsVireOfferingEffect() { + super(Outcome.Benefit); + this.staticText = "Put up to one target creature or planeswalker from a graveyard onto the battlefield under your control. Destroy up to one target creature or planeswalker"; + } + + public YawgmothsVireOfferingEffect(final YawgmothsVireOfferingEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + Card returnCard = game.getCard(source.getTargets().getFirstTarget()); + + if (returnCard != null) { + controller.moveCards(returnCard, Zone.BATTLEFIELD, source, game); + } + + Permanent permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + + if (permanent != null) { + permanent.destroy(source.getId(), game, false); + } + + return false; + } + + @Override + public YawgmothsVireOfferingEffect copy() { + return new YawgmothsVireOfferingEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Dominaria.java b/Mage.Sets/src/mage/sets/Dominaria.java index 9ef785c892..82706c6b0b 100644 --- a/Mage.Sets/src/mage/sets/Dominaria.java +++ b/Mage.Sets/src/mage/sets/Dominaria.java @@ -65,6 +65,7 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Clifftop Retreat", 239, Rarity.RARE, mage.cards.c.ClifftopRetreat.class)); cards.add(new SetCardInfo("Damping Sphere", 213, Rarity.UNCOMMON, mage.cards.d.DampingSphere.class)); cards.add(new SetCardInfo("Divest", 87, Rarity.COMMON, mage.cards.d.Divest.class)); + cards.add(new SetCardInfo("Drudge Sentinel", 89, Rarity.COMMON, mage.cards.d.DrudgeSentinel.class)); cards.add(new SetCardInfo("Dub", 999, Rarity.SPECIAL, mage.cards.d.Dub.class)); //TODO: Update once full spoiler cards.add(new SetCardInfo("Fire Elemental", 120, Rarity.COMMON, mage.cards.f.FireElemental.class)); cards.add(new SetCardInfo("Ghitu Lavarunner", 127, Rarity.COMMON, mage.cards.g.GhituLavarunner.class)); //TODO: Update once full spoiler @@ -76,11 +77,14 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Icy Manipulator", 219, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); cards.add(new SetCardInfo("Invoke the Divine", 13, Rarity.COMMON, mage.cards.i.InvokeTheDivine.class)); cards.add(new SetCardInfo("Isolated Chapel", 241, Rarity.RARE, mage.cards.i.IsolatedChapel.class)); + cards.add(new SetCardInfo("Jaya's Immolating Inferno", 133, Rarity.RARE, mage.cards.j.JayasImmolatingInferno.class)); cards.add(new SetCardInfo("Jhoira, Weatherlight Captain", 200, Rarity.MYTHIC, mage.cards.j.JhoiraWeatherlightCaptain.class)); cards.add(new SetCardInfo("Jodah, Archmage Eternal", 198, Rarity.RARE, mage.cards.j.JodahArchmageEternal.class)); cards.add(new SetCardInfo("Josu Vess, Lich Knight",95, Rarity.RARE, mage.cards.j.JosuVessLichKnight.class)); cards.add(new SetCardInfo("Juggernaut", 222, Rarity.UNCOMMON, mage.cards.j.Juggernaut.class)); + cards.add(new SetCardInfo("Kamahl's Druidic Vow", 166, Rarity.RARE, mage.cards.k.KamahlsDruidicVow.class)); cards.add(new SetCardInfo("Karn, Scion of Urza", 554, Rarity.MYTHIC, mage.cards.k.KarnScionOfUrza.class)); + cards.add(new SetCardInfo("Karn's Temporal Sundering", 55, Rarity.RARE, mage.cards.k.KarnsTemporalSundering.class)); cards.add(new SetCardInfo("Knight of Grace", 23, Rarity.UNCOMMON, mage.cards.k.KnightOfGrace.class)); cards.add(new SetCardInfo("Knight of Malice", 52, Rarity.UNCOMMON, mage.cards.k.KnightOfMalice.class)); cards.add(new SetCardInfo("Llanowar Elves", 168, Rarity.COMMON, mage.cards.l.LlanowarElves.class)); @@ -89,6 +93,7 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Meandering River", 274, Rarity.COMMON, mage.cards.m.MeanderingRiver.class)); cards.add(new SetCardInfo("Naru Meha, Master Wizard", 59, Rarity.MYTHIC, mage.cards.n.NaruMehaMasterWizard.class)); cards.add(new SetCardInfo("Opt", 60, Rarity.COMMON, mage.cards.o.Opt.class)); + cards.add(new SetCardInfo("Primevals' Glorious Rebirth", 201, Rarity.RARE, mage.cards.p.PrimevalsGloriousRebirth.class)); cards.add(new SetCardInfo("Seal Away", 31, Rarity.UNCOMMON, mage.cards.s.SealAway.class)); cards.add(new SetCardInfo("Serra Angel", 33, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); cards.add(new SetCardInfo("Serra Disciple", 34, Rarity.COMMON, mage.cards.s.SerraDisciple.class)); @@ -100,10 +105,12 @@ public class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Tetsuko Umezawa, Fugitive", 69, Rarity.UNCOMMON, mage.cards.t.TetsukoUmezawaFugitive.class)); cards.add(new SetCardInfo("Thorn Elemental", 185, Rarity.UNCOMMON, mage.cards.t.ThornElemental.class)); cards.add(new SetCardInfo("Unwind", 72, Rarity.COMMON, mage.cards.u.Unwind.class)); + cards.add(new SetCardInfo("Urza's Ruinous Blast", 39, Rarity.RARE, mage.cards.u.UrzasRuinousBlast.class)); cards.add(new SetCardInfo("Verix Bladewing", 149, Rarity.MYTHIC, mage.cards.v.VerixBladewing.class)); cards.add(new SetCardInfo("Wizard's Lightning", 152, Rarity.UNCOMMON, mage.cards.w.WizardsLightning.class)); cards.add(new SetCardInfo("Wizard's Retort", 75, Rarity.UNCOMMON, mage.cards.w.WizardsRetort.class)); cards.add(new SetCardInfo("Woodland Cemetery", 248, Rarity.RARE, mage.cards.w.WoodlandCemetery.class)); //TODO: Check number once full spoiler rolls out + cards.add(new SetCardInfo("Yawgmoth's Vile Offering", 114, Rarity.RARE, mage.cards.y.YawgmothsVileOffering.class)); cards.add(new SetCardInfo("Zhalfirin Void", 249, Rarity.UNCOMMON, mage.cards.z.ZhalfirinVoid.class)); } } diff --git a/Mage/src/main/java/mage/abilities/common/LegendarySpellAbility.java b/Mage/src/main/java/mage/abilities/common/LegendarySpellAbility.java new file mode 100644 index 0000000000..ca0604d846 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/LegendarySpellAbility.java @@ -0,0 +1,26 @@ +package mage.abilities.common; + +import mage.abilities.condition.common.LegendaryCondition; +import mage.constants.Zone; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class LegendarySpellAbility extends SimpleStaticAbility { + + public LegendarySpellAbility() { + super(Zone.ALL, new CastOnlyIfConditionIsTrueEffect(LegendaryCondition.instance)); + this.setRuleAtTheTop(true); + this.getEffects().get(0).setText("(You may cast a legendary sorcery only if you control a legendary creature or planeswalker.)"); + } + + private LegendarySpellAbility(final LegendarySpellAbility ability) { + super(ability); + } + + @Override + public LegendarySpellAbility copy() { + return new LegendarySpellAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/LegendaryCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LegendaryCondition.java new file mode 100644 index 0000000000..1dc607643d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/LegendaryCondition.java @@ -0,0 +1,46 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; + +/** + * @author JRHerlehy + * Created on 4/7/18. + */ +public enum LegendaryCondition implements Condition { + + instance; + + private static final FilterPermanent filter = new FilterPermanent("legendary creature or planeswalker"); + + static { + filter.add( + Predicates.and( + new SupertypePredicate(SuperType.LEGENDARY), + Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + ) + ) + ); + } + + + @Override + public boolean apply(Game game, Ability source) { + return game.getBattlefield().contains(filter, source.getControllerId(), 1, game); + } + + + @Override + public String toString() { + return super.toString(); + } +} diff --git a/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java b/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java new file mode 100644 index 0000000000..c52a1dfbb6 --- /dev/null +++ b/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java @@ -0,0 +1,87 @@ +package mage.filter.common; + +import java.util.UUID; + +import mage.MageItem; +import mage.filter.FilterImpl; +import mage.filter.FilterInPlay; +import mage.filter.FilterPlayer; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class FilterCreaturePlayerOrPlaneswalker extends FilterImpl implements FilterInPlay { + protected FilterCreaturePermanent creatureFilter; + protected FilterPlaneswalkerPermanent planeswalkerFilter; + protected final FilterPlayer playerFilter; + + public FilterCreaturePlayerOrPlaneswalker() { + this("any target"); + } + + public FilterCreaturePlayerOrPlaneswalker(String name) { + super(name); + creatureFilter = new FilterCreaturePermanent(); + playerFilter = new FilterPlayer(); + planeswalkerFilter = new FilterPlaneswalkerPermanent(); + } + + public FilterCreaturePlayerOrPlaneswalker(final FilterCreaturePlayerOrPlaneswalker filter) { + super(filter); + this.creatureFilter = filter.creatureFilter.copy(); + this.playerFilter = filter.playerFilter.copy(); + this.planeswalkerFilter = filter.planeswalkerFilter.copy(); + } + + @Override + public boolean checkObjectClass(Object object) { + return true; + } + + @Override + public boolean match(MageItem o, Game game) { + if (o instanceof Player) { + return playerFilter.match((Player) o, game); + } else if (o instanceof Permanent) { + return creatureFilter.match((Permanent) o, game) || + planeswalkerFilter.match((Permanent) o, game); + } + return false; + } + + @Override + public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) { + if (o instanceof Player) { + return playerFilter.match((Player) o, sourceId, playerId, game); + } else if (o instanceof Permanent) { + return creatureFilter.match((Permanent) o, sourceId, playerId, game) || + planeswalkerFilter.match((Permanent) o, sourceId, playerId, game); + } + return false; + } + + public FilterCreaturePermanent getCreatureFilter() { + return this.creatureFilter; + } + + public FilterPlayer getPlayerFilter() { + return this.playerFilter; + } + + public FilterPlaneswalkerPermanent getPlaneswalkerFilter() { + return this.planeswalkerFilter; + } + + public void setCreatureFilter(FilterCreaturePermanent creatureFilter) { + this.creatureFilter = creatureFilter; + } + + @Override + public FilterCreaturePlayerOrPlaneswalker copy() { + return new FilterCreaturePlayerOrPlaneswalker(this); + } +} diff --git a/Mage/src/main/java/mage/target/common/TargetAnyTarget.java b/Mage/src/main/java/mage/target/common/TargetAnyTarget.java new file mode 100644 index 0000000000..3ebf6eee11 --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetAnyTarget.java @@ -0,0 +1,221 @@ +package mage.target.common; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.common.FilterCreaturePlayerOrPlaneswalker; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetImpl; + +/** + * @author JRHerlehy + * Created on 4/8/18. + */ +public class TargetAnyTarget extends TargetImpl { + + protected FilterCreaturePlayerOrPlaneswalker filter; + + public TargetAnyTarget() { + this(1, 1, new FilterCreaturePlayerOrPlaneswalker()); + } + + public TargetAnyTarget(int numTargets) { + this(numTargets, numTargets, new FilterCreaturePlayerOrPlaneswalker()); + } + + public TargetAnyTarget(FilterCreaturePlayerOrPlaneswalker filter) { + this(1, 1, filter); + } + + public TargetAnyTarget(int numTargets, int maxNumTargets) { + this(numTargets, maxNumTargets, new FilterCreaturePlayerOrPlaneswalker()); + } + + public TargetAnyTarget(int minNumTargets, int maxNumTargets, FilterCreaturePlayerOrPlaneswalker filter) { + this.minNumberOfTargets = minNumTargets; + this.maxNumberOfTargets = maxNumTargets; + this.zone = Zone.ALL; + this.filter = filter; + this.targetName = filter.getMessage(); + } + + public TargetAnyTarget(final TargetAnyTarget target) { + super(target); + this.filter = target.filter.copy(); + } + + @Override + public Filter getFilter() { + return this.filter; + } + + @Override + public boolean canTarget(UUID id, Game game) { + Permanent permanent = game.getPermanent(id); + if (permanent != null) { + return filter.match(permanent, game); + } + Player player = game.getPlayer(id); + return player != null && filter.match(player, game); + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + return canTarget(source.getControllerId(), id, source, game); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + Permanent permanent = game.getPermanent(id); + Player player = game.getPlayer(id); + + if (source != null) { + MageObject targetSource = game.getObject(source.getSourceId()); + if (permanent != null) { + return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + } + if (player != null) { + return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game); + } + } + + if (permanent != null) { + return filter.match(permanent, game); + } + return player != null && filter.match(player, game); + } + + /** + * Checks if there are enough {@link Permanent} or {@link Player} that can + * be chosen. Should only be used for Ability targets since this checks for + * protection, shroud etc. + * + * @param sourceId - the target event source + * @param sourceControllerId - controller of the target event source + * @param game + * @return - true if enough valid {@link Permanent} or {@link Player} exist + */ + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + int count = 0; + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + return false; + } + + /** + * Checks if there are enough {@link Permanent} or {@link Player} that can + * be selected. Should not be used for Ability targets since this does not + * check for protection, shroud etc. + * + * @param sourceControllerId - controller of the select event + * @param game + * @return - true if enough valid {@link Permanent} or {@link Player} exist + */ + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + int count = 0; + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null && filter.match(player, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { + if (filter.match(permanent, null, sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null + && player.canBeTargetedBy(targetSource, sourceControllerId, game) + && filter.getPlayerFilter().match(player, sourceId, sourceControllerId, game)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) + && filter.getCreatureFilter().match(permanent, sourceId, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null && filter.getPlayerFilter().match(player, game)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { + if (filter.getCreatureFilter().match(permanent, null, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + + @Override + public String getTargetedName(Game game) { + StringBuilder sb = new StringBuilder(); + for (UUID targetId : getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + sb.append(permanent.getLogName()).append(' '); + } else { + Player player = game.getPlayer(targetId); + if (player != null) { + sb.append(player.getLogName()).append(' '); + } + } + } + return sb.toString(); + } + + @Override + public TargetAnyTarget copy() { + return new TargetAnyTarget(this); + } + +}