From 6d89011e470f54fe47ed3fbd710dd1942f0bb0d1 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 17 Apr 2014 16:40:18 +0200 Subject: [PATCH] [JOU] Added 6 cards. Fixed some bugs for JOU cards. --- .../journeyintonyx/AthreosGodOfPassage.java | 2 +- .../sets/journeyintonyx/BanishingLight.java | 189 +++++++++++++++++ .../mage/sets/journeyintonyx/BrainMaggot.java | 196 ++++++++++++++++++ .../src/mage/sets/journeyintonyx/Deicide.java | 114 ++++++++++ .../sets/journeyintonyx/DictateOfErebos.java | 74 +++++++ .../sets/journeyintonyx/FontOfReturn.java | 2 +- .../src/mage/sets/journeyintonyx/Godsend.java | 40 ++-- .../mage/sets/journeyintonyx/NyxWeaver.java | 82 ++++++++ .../sets/journeyintonyx/RenownedWeaver.java | 91 ++++++++ .../sets/shardsofalara/TidehollowSculler.java | 33 +-- ...ardOfLibraryIntoGraveControllerEffect.java | 10 +- ...dHandLibraryForCardNameAndExileEffect.java | 20 +- Mage/src/mage/players/PlayerImpl.java | 2 +- .../common/TargetCardInYourGraveyard.java | 5 + .../common/TargetEnchantmentPermanent.java | 72 +++++++ Utils/mtg-cards-data.txt | 6 + 16 files changed, 891 insertions(+), 47 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/journeyintonyx/BanishingLight.java create mode 100644 Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java create mode 100644 Mage.Sets/src/mage/sets/journeyintonyx/Deicide.java create mode 100644 Mage.Sets/src/mage/sets/journeyintonyx/DictateOfErebos.java create mode 100644 Mage.Sets/src/mage/sets/journeyintonyx/NyxWeaver.java create mode 100644 Mage.Sets/src/mage/sets/journeyintonyx/RenownedWeaver.java create mode 100644 Mage/src/mage/target/common/TargetEnchantmentPermanent.java diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java b/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java index f33c64fb1eb..6012ab014b1 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java @@ -126,7 +126,7 @@ class AthreosGodOfPassageReturnEffect extends OneShotEffect { + + private final static FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public BanishingLight(UUID ownerId) { + super(ownerId, 5, "Banishing Light", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + this.expansionSetCode = "JOU"; + + this.color.setWhite(true); + + // When Banishing Light enters the battlefield, exile target nonland permanent an opponent controls until Banishing Light leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new BanishingLightExileEffect()); + ability.addTarget(new TargetPermanent(filter, true)); + this.addAbility(ability); + // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature + // has a DiesTriggeredAll ability it triggers for the dying / battlefield leaving source object, what shouldn't happen) + this.addAbility(new BanishingLightReturnExiledAbility()); + } + + public BanishingLight(final BanishingLight card) { + super(card); + } + + @Override + public BanishingLight copy() { + return new BanishingLight(this); + } +} + +class BanishingLightExileEffect extends OneShotEffect { + + public BanishingLightExileEffect() { + super(Outcome.Benefit); + this.staticText = "exile target nonland permanent an opponent controls until {this} leaves the battlefield. (That permanent returns under its owner's control.)"; + } + + public BanishingLightExileEffect(final BanishingLightExileEffect effect) { + super(effect); + } + + @Override + public BanishingLightExileEffect copy() { + return new BanishingLightExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + // If Banishing Light leaves the battlefield before its triggered ability resolves, + // the target won't be exiled. + if (permanent != null) { + return new ExileTargetEffect(source.getSourceId(), permanent.getName()).apply(game, source); + } + return false; + } +} + +/** + * Returns the exiled card as source permanent leaves battlefield + * Uses no stack + * @author LevelX2 + */ + +class BanishingLightReturnExiledAbility extends TriggeredAbilityImpl { + + public BanishingLightReturnExiledAbility() { + super(Zone.BATTLEFIELD, new ReturnExiledCreatureEffect()); + this.usesStack = false; + this.setRuleVisible(false); + } + + public BanishingLightReturnExiledAbility(final BanishingLightReturnExiledAbility ability) { + super(ability); + } + + @Override + public BanishingLightReturnExiledAbility copy() { + return new BanishingLightReturnExiledAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD) { + return true; + } + } + return false; + } +} + +class ReturnExiledCreatureEffect extends OneShotEffect { + + public ReturnExiledCreatureEffect() { + super(Outcome.Benefit); + this.staticText = "Return exiled permanent"; + } + + public ReturnExiledCreatureEffect(final ReturnExiledCreatureEffect effect) { + super(effect); + } + + @Override + public ReturnExiledCreatureEffect copy() { + return new ReturnExiledCreatureEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + ExileZone exile = game.getExile().getExileZone(source.getSourceId()); + Card sourceCard = game.getCard(source.getSourceId()); + if (exile != null && sourceCard != null) { + LinkedList cards = new LinkedList<>(exile); + for (UUID cardId : cards) { + Card card = game.getCard(cardId); + card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); + game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); + } + exile.clear(); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java b/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java new file mode 100644 index 00000000000..ec86c081ca8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java @@ -0,0 +1,196 @@ +/* + * 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.journeyintonyx; + +import java.util.LinkedList; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterNonlandCard; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class BrainMaggot extends CardImpl { + + public BrainMaggot(UUID ownerId) { + super(ownerId, 62, "Brain Maggot", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "JOU"; + this.subtype.add("Insect"); + + this.color.setBlack(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Brain Maggot enters the battlefield, target opponent reveals his or her hand and you choose a nonland card from it. Exile that card until Brain Maggot leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new BrainMaggotExileEffect()); + ability.addTarget(new TargetOpponent(true)); + this.addAbility(ability); + // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature + // has a DiesTriggeredAll ability it triggers for the dying / battlefield leaving source object, what shouldn't happen) + this.addAbility(new BrainMaggotReturnExiledAbility()); + } + + public BrainMaggot(final BrainMaggot card) { + super(card); + } + + @Override + public BrainMaggot copy() { + return new BrainMaggot(this); + } +} + +class BrainMaggotExileEffect extends OneShotEffect { + + public BrainMaggotExileEffect() { + super(Outcome.Benefit); + this.staticText = "target opponent reveals his or her hand and you choose a nonland card from it. Exile that card until {this} leaves the battlefield"; + } + + public BrainMaggotExileEffect(final BrainMaggotExileEffect effect) { + super(effect); + } + + @Override + public BrainMaggotExileEffect copy() { + return new BrainMaggotExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && opponent != null && sourcePermanent != null) { + opponent.revealCards(sourcePermanent.getName(), opponent.getHand(), game); + + TargetCard target = new TargetCard(Zone.HAND, new FilterNonlandCard("nonland card to exile")); + target.setRequired(true); + if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { + Card card = opponent.getHand().get(target.getFirstTarget(), game); + // If source permanent leaves the battlefield before its triggered ability resolves, the target card won't be exiled. + if (card != null && game.getState().getZone(source.getSourceId()) == Zone.BATTLEFIELD) { + controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName(), source.getSourceId(), game, Zone.HAND); + } + } + } + return false; + + } +} + +/** + * Returns the exiled card as source permanent leaves battlefield + * Uses no stack + * @author LevelX2 + */ + +class BrainMaggotReturnExiledAbility extends TriggeredAbilityImpl { + + public BrainMaggotReturnExiledAbility() { + super(Zone.BATTLEFIELD, new BrainMaggotReturnExiledCreatureEffect()); + this.usesStack = false; + this.setRuleVisible(false); + } + + public BrainMaggotReturnExiledAbility(final BrainMaggotReturnExiledAbility ability) { + super(ability); + } + + @Override + public BrainMaggotReturnExiledAbility copy() { + return new BrainMaggotReturnExiledAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD) { + return true; + } + } + return false; + } +} + +class BrainMaggotReturnExiledCreatureEffect extends OneShotEffect { + + public BrainMaggotReturnExiledCreatureEffect() { + super(Outcome.Benefit); + this.staticText = "Return exiled nonland card to its owner's hand"; + } + + public BrainMaggotReturnExiledCreatureEffect(final BrainMaggotReturnExiledCreatureEffect effect) { + super(effect); + } + + @Override + public BrainMaggotReturnExiledCreatureEffect copy() { + return new BrainMaggotReturnExiledCreatureEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + ExileZone exile = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (exile != null && sourcePermanent != null) { + LinkedList cards = new LinkedList<>(exile); + for (UUID cardId : cards) { + Card card = game.getCard(cardId); + controller.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.EXILED); + } + exile.clear(); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/Deicide.java b/Mage.Sets/src/mage/sets/journeyintonyx/Deicide.java new file mode 100644 index 00000000000..5934122b034 --- /dev/null +++ b/Mage.Sets/src/mage/sets/journeyintonyx/Deicide.java @@ -0,0 +1,114 @@ +/* + * 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.journeyintonyx; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetEnchantmentPermanent; + +/** + * + * @author LevelX2 + */ +public class Deicide extends CardImpl { + + + + public Deicide(UUID ownerId) { + super(ownerId, 7, "Deicide", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{1}{W}"); + this.expansionSetCode = "JOU"; + + this.color.setWhite(true); + + // Exile target enchantment. If the exiled card is a God card, search its controller's graveyard, hand, and library for any number of cards with the same name as that card and exile them, then that player shuffles his or her library. + this.getSpellAbility().addEffect(new DeicideExileEffect()); + this.getSpellAbility().addTarget(new TargetEnchantmentPermanent(true)); + } + + public Deicide(final Deicide card) { + super(card); + } + + @Override + public Deicide copy() { + return new Deicide(this); + } +} + +class DeicideExileEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect { + + public DeicideExileEffect() { + super(true, "its controller's","any number of cards with the same name as that card"); + } + + public DeicideExileEffect(final DeicideExileEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Card sourceCard = game.getCard(source.getSourceId()); + if (controller != null && sourceCard != null) { + Permanent targetEnchantment = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetEnchantment != null) { + controller.moveCardToExileWithInfo(targetEnchantment, null, null, source.getSourceId(), game, Zone.BATTLEFIELD); + Card exiledCard = game.getCard(targetEnchantment.getId()); + if (exiledCard.hasSubtype("God")) { + Player enchantmentController = game.getPlayer(targetEnchantment.getControllerId()); + return super.applySearchAndExile(game, source, exiledCard.getName(), enchantmentController.getId()); + } + } + } + return false; + } + + @Override + public DeicideExileEffect copy() { + return new DeicideExileEffect(this); + } + + @Override + public String getText(Mode mode) { + StringBuilder sb = new StringBuilder(); + sb.append("Exile target enchantment. If the exiled card is a God card, "); + sb.append(super.getText(mode)); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfErebos.java b/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfErebos.java new file mode 100644 index 00000000000..b3d0577d8c9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/journeyintonyx/DictateOfErebos.java @@ -0,0 +1,74 @@ +/* + * 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.journeyintonyx; + +import java.util.UUID; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LevelX2 + */ +public class DictateOfErebos extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public DictateOfErebos(UUID ownerId) { + super(ownerId, 63, "Dictate of Erebos", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); + this.expansionSetCode = "JOU"; + + this.color.setBlack(true); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Whenever a creature you control dies, each opponent sacrifices a creature. + this.addAbility(new DiesCreatureTriggeredAbility(new SacrificeOpponentsEffect(new FilterControlledCreaturePermanent("a creature")), false, filter)); + } + + public DictateOfErebos(final DictateOfErebos card) { + super(card); + } + + @Override + public DictateOfErebos copy() { + return new DictateOfErebos(this); + } +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/FontOfReturn.java b/Mage.Sets/src/mage/sets/journeyintonyx/FontOfReturn.java index be7a4b9598c..4ba33960875 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/FontOfReturn.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/FontOfReturn.java @@ -53,7 +53,7 @@ public class FontOfReturn extends CardImpl { this.color.setBlack(true); // {3}{B}, Sacrifice Font of Return: Return up to three target creature cards from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{1}{G}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{3}{B}")); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(0, 3, new FilterCreatureCard("creature cards from your graveyard"))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java b/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java index 803cea5eb49..9c54165cb78 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/Godsend.java @@ -59,6 +59,7 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FirstTargetPointer; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; @@ -118,31 +119,33 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl 0) { - for (CombatGroup group: game.getCombat().getBlockingGroups()) { - if (group.getBlockers().contains(this.getSourceId())) { + targetName = "a creature blocking attacker "; + } else if (equippedPermanent.getBlocking() > 0) { + for (CombatGroup group: game.getCombat().getGroups()) { + if (group.getBlockers().contains(equippedPermanent.getId())) { possibleTargets.addAll(group.getAttackers()); } } - - } - if (possibleTargets.size() > 0) { - if (possibleTargets.size() == 1) { - this.getTargets().clear(); + targetName = "a creature blocked by creature "; + } + if (possibleTargets.size() > 0) { + this.getTargets().clear(); + if (possibleTargets.size() == 1) { this.getEffects().get(0).setTargetPointer(new FixedTarget(possibleTargets.iterator().next())); } else { - FilterCreaturePermanent filter = new FilterCreaturePermanent("one blocking or blocked creature"); + this.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); + targetName = new StringBuilder(targetName).append("equipped by ").append(equipment.getName()).toString(); + FilterCreaturePermanent filter = new FilterCreaturePermanent(targetName); List uuidPredicates = new ArrayList<>(); for (UUID creatureId : possibleTargets) { uuidPredicates.add(new PermanentIdPredicate(creatureId)); @@ -150,6 +153,7 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl { + + public NyxWeaver(UUID ownerId) { + super(ownerId, 153, "Nyx Weaver", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{B}{G}"); + this.expansionSetCode = "JOU"; + this.subtype.add("Spider"); + + this.color.setGreen(true); + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + // At the beginning of your upkeep, put the top two cards of your library into your graveyard. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new PutTopCardOfLibraryIntoGraveControllerEffect(2), TargetController.YOU, false)); + // {1}{B}{G}, Exile Nyx Weaver: Return target card from your graveyard to your hand. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{1}{B}{G}")); + ability.addCost(new ExileSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(true)); + this.addAbility(ability); + } + + public NyxWeaver(final NyxWeaver card) { + super(card); + } + + @Override + public NyxWeaver copy() { + return new NyxWeaver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/RenownedWeaver.java b/Mage.Sets/src/mage/sets/journeyintonyx/RenownedWeaver.java new file mode 100644 index 00000000000..ce31c14a897 --- /dev/null +++ b/Mage.Sets/src/mage/sets/journeyintonyx/RenownedWeaver.java @@ -0,0 +1,91 @@ +/* + * 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.journeyintonyx; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author LevelX2 + */ +public class RenownedWeaver extends CardImpl { + + public RenownedWeaver(UUID ownerId) { + super(ownerId, 137, "Renowned Weaver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{G}"); + this.expansionSetCode = "JOU"; + this.subtype.add("Human"); + this.subtype.add("Shaman"); + + this.color.setGreen(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{G}, Sacrifice Renowned Weaver: Put a 1/3 green Spider enchantment creature token with reach onto the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new RenownedWeaverSpiderToken(), 1), new ManaCostsImpl("{1}{G}")) ; + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + + } + + public RenownedWeaver(final RenownedWeaver card) { + super(card); + } + + @Override + public RenownedWeaver copy() { + return new RenownedWeaver(this); + } +} + +class RenownedWeaverSpiderToken extends Token { + + public RenownedWeaverSpiderToken() { + super("Spider", "1/3 green Spider enchantment creature token with reach"); + this.setOriginalExpansionSetCode("JOU"); + cardType.add(CardType.ENCHANTMENT); + cardType.add(CardType.CREATURE); + color.setColor(ObjectColor.GREEN); + subtype.add("Spider"); + power = new MageInt(1); + toughness = new MageInt(3); + this.addAbility(ReachAbility.getInstance()); + } +} diff --git a/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java b/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java index a700a0d2f19..9abfd44b484 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java @@ -42,6 +42,7 @@ import mage.constants.Zone; import mage.filter.common.FilterNonlandCard; import mage.game.ExileZone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetOpponent; @@ -101,17 +102,18 @@ class TidehollowScullerExileEffect extends OneShotEffect 0) { filter.setMessage("card named " + cardName + " in the graveyard of " + targetPlayer.getName()); TargetCardInGraveyard target = new TargetCardInGraveyard((graveyardExileOptional ? 0 :cardsCount), cardsCount, filter); - if (player.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, game)) { + if (controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, game)) { List targets = target.getTargets(); for (UUID targetId : targets) { Card targetCard = targetPlayer.getGraveyard().get(targetId, game); if (targetCard != null) { targetPlayer.getGraveyard().remove(targetCard); - targetCard.moveToZone(Zone.EXILED, source.getId(), game, false); + controller.moveCardToExileWithInfo(targetCard, null, null, source.getSourceId(), game, Zone.GRAVEYARD); } } } @@ -108,19 +108,19 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect if (cardsCount > 0) { filter.setMessage("card named " + cardName + " in the hand of " + targetPlayer.getName()); TargetCardInHand target = new TargetCardInHand(0, cardsCount, filter); - if (player.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) { + if (controller.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) { List targets = target.getTargets(); for (UUID targetId : targets) { Card targetCard = targetPlayer.getHand().get(targetId, game); if (targetCard != null) { targetPlayer.getHand().remove(targetCard); - targetCard.moveToZone(Zone.EXILED, source.getId(), game, false); + controller.moveCardToExileWithInfo(targetCard, null, null, source.getSourceId(), game, Zone.HAND); } } } } else { if (targetPlayer.getHand().size() > 0) { - player.lookAtCards(targetPlayer.getName() + " hand", targetPlayer.getHand(), game); + controller.lookAtCards(targetPlayer.getName() + " hand", targetPlayer.getHand(), game); } } @@ -131,17 +131,17 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect if (cardsCount > 0) { filter.setMessage("card named " + cardName + " in the library of " + targetPlayer.getName()); TargetCardInLibrary target = new TargetCardInLibrary(0, cardsCount, filter); - if (player.choose(Outcome.Exile, cardsInLibrary, target, game)) { + if (controller.choose(Outcome.Exile, cardsInLibrary, target, game)) { List targets = target.getTargets(); for (UUID targetId : targets) { Card targetCard = targetPlayer.getLibrary().remove(targetId, game); if (targetCard != null) { - targetCard.moveToZone(Zone.EXILED, source.getId(), game, false); + controller.moveCardToExileWithInfo(targetCard, null, null, source.getSourceId(), game, Zone.LIBRARY); } } } } else { - player.lookAtCards(targetPlayer.getName() + " library", cardsInLibrary, game); + controller.lookAtCards(targetPlayer.getName() + " library", cardsInLibrary, game); } targetPlayer.shuffleLibrary(game); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index a31aa9676d3..daba32ed7e3 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -2132,7 +2132,7 @@ public abstract class PlayerImpl> implements Player, Ser game.informPlayers(new StringBuilder(this.getName()) .append(" puts ").append(card.getName()).append(" ") .append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"") - .append("into his or her hand").toString()); + .append(card.getOwnerId().equals(this.getId()) ? "into his or her hand":"into its owner's hand").toString()); result = true; } return result; diff --git a/Mage/src/mage/target/common/TargetCardInYourGraveyard.java b/Mage/src/mage/target/common/TargetCardInYourGraveyard.java index 92d0a3bb1b9..8cf7d174f63 100644 --- a/Mage/src/mage/target/common/TargetCardInYourGraveyard.java +++ b/Mage/src/mage/target/common/TargetCardInYourGraveyard.java @@ -46,6 +46,11 @@ public class TargetCardInYourGraveyard extends TargetCard + */ +public class TargetEnchantmentPermanent> extends TargetPermanent> { + + public TargetEnchantmentPermanent(boolean required) { + this(); + this.setRequired(required); + } + + public TargetEnchantmentPermanent() { + this(1, 1, new FilterEnchantmentPermanent(), false); + } + + public TargetEnchantmentPermanent(FilterEnchantmentPermanent filter) { + this(1, 1, filter, false); + } + + public TargetEnchantmentPermanent(int numTargets) { + this(numTargets, numTargets, new FilterEnchantmentPermanent(), false); + } + + public TargetEnchantmentPermanent(int minNumTargets, int maxNumTargets, FilterEnchantmentPermanent filter, boolean notTarget) { + super(minNumTargets, maxNumTargets, filter, notTarget); + this.targetName = filter.getMessage(); + } + + public TargetEnchantmentPermanent(final TargetEnchantmentPermanent target) { + super(target); + } + + @Override + public TargetEnchantmentPermanent copy() { + return new TargetEnchantmentPermanent(this); + } +} diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index ec6307ac6b0..e6d82f20830 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -23227,3 +23227,9 @@ Font of Return|Journey into Nyx|71|C|{1}{B}|Enchantment|||{3}{B}, Sacrifice Font Golden Hind|Journey into Nyx|124|C|{1}{G}|Creature - Elk|2|1|T: Add {G} to your mana pool.| Harness by Force|Journey into Nyx|100|R|{1}{R}{R}|Sorcery|||Strive - Harness by Force costs 2R more to cast for each target beyond the first.$Gain control of any number of target creatures until end of turn. Untap those creatures. They gain haste until end of turn.| Strength of the Fallen|Journey into Nyx|143|U|{1}{G}|Enchantment|||Constellation - Whenever Strength of the Fallen or another entchantment enters the battlefield under your control, target creature gets +X/+X until end of turn, where X is the number of creature cards in your graveyard.| +Banishing Light|Journey into Nyx|5|U|{2}{W}|Enchantment|||When Banishing Light enters the battlefield, exile target nonland permanent an opponent controls until Banishing Light leaves the battlefield.| +Dictate of Erebos|Journey into Nyx|63|R|{3}{B}{B}|Enchantment|||Flash$Whenever a creature you control dies, each opponent sacrifices a creature.| +Brain Maggot|Journey into Nyx|62|U|{1}{B}|Enchantment Creature - Insect|1|1|When Brain Maggot enters the battlefield, target opponent reveals his or her hand and you choose a nonland card from it. Exile that card until Brain Maggot leaves the battlefield.| +Nyx Weaver|Journey into Nyx|153|U|{1}{B}{G}|Enchantment Creature - Spider|2|3|Reach$At the beginning of your upkeep, put the top two cards of your library into your graveyard.$1BG, Exile Nyx Weaver: Return target card from your graveyard to your hand.| +Renowned Weaver|Journey into Nyx|137|C|{G}|Creature - Human Shaman|1|1|{1}{G}, Sacrifice Renowned Weaver: Put a 1/3 green Spider enchantment creature token with reach onto the battlefield.| +Deicide|Journey into Nyx|7|R|{1}{W}|Instant|||Exile target enchantment. If the exiled card is a God card, search its controller's graveyard, hand, and library for any number of cards with the same name as that card and exile them, then that player shuffles his or her library.|