From 803676268c43a8ef7b8404b9b32516d3335c09ea Mon Sep 17 00:00:00 2001 From: fireshoes Date: Tue, 10 Mar 2015 01:35:57 -0500 Subject: [PATCH] [DTK] Added Ojutai Exemplars; updated mtg-cards-data.txt for 3/9 spoilers. Added TargetCreatureOrPlaneswalkerAmount --- .../sets/dragonsoftarkir/OjutaiExemplars.java | 136 +++++++++++++ .../TargetCreatureOrPlaneswalkerAmount.java | 178 ++++++++++++++++++ Utils/mtg-cards-data.txt | 1 + 3 files changed, 315 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/dragonsoftarkir/OjutaiExemplars.java create mode 100644 Mage/src/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/OjutaiExemplars.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/OjutaiExemplars.java new file mode 100644 index 00000000000..a6f534e7851 --- /dev/null +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/OjutaiExemplars.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.dragonsoftarkir; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.LifelinkAbility; +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.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author fireshoes + */ +public class OjutaiExemplars extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("creature spell"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + } + + public OjutaiExemplars(UUID ownerId) { + super(ownerId, 27, "Ojutai Exemplars", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + this.expansionSetCode = "DTK"; + this.subtype.add("Human"); + this.subtype.add("Monk"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever you cast a noncreature spell, choose one - Tap target creature; + Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), filter, false); + ability.addTarget(new TargetCreaturePermanent()); + + // Ojutai Exemplars gain first strike and lifelink until end of turn; + Mode mode = new Mode(); + Effect effect = new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); + effect.setText("{this} gains first strike"); + mode.getEffects().add(effect); + Effect effect2 = new GainAbilitySourceEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); + effect2.setText("and lifelink"); + mode.getEffects().add(effect2); + ability.addMode(mode); + + // or Exile Ojutai Exemplars, then return it to the battlefield tapped under its owner's control. + mode = new Mode(); + mode.getEffects().add(new OjutaiExemplarsEffect()); + ability.addMode(mode); + + this.addAbility(ability); + } + + public OjutaiExemplars(final OjutaiExemplars card) { + super(card); + } + + @Override + public OjutaiExemplars copy() { + return new OjutaiExemplars(this); + } +} + +class OjutaiExemplarsEffect extends OneShotEffect { + + public OjutaiExemplarsEffect() { + super(Outcome.Neutral); + this.staticText = "Exile {this}, then return it to the battlefield tapped under its owner's control"; + } + + public OjutaiExemplarsEffect(final OjutaiExemplarsEffect effect) { + super(effect); + } + + @Override + public OjutaiExemplarsEffect copy() { + return new OjutaiExemplarsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent ojutaiExemplars = game.getPermanent(source.getSourceId()); + if (ojutaiExemplars != null) { + if (ojutaiExemplars.moveToExile(source.getSourceId(), "Ojutai Exemplars", source.getSourceId(), game)) { + Card card = game.getExile().getCard(source.getSourceId(), game); + if (card != null) { + return card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, true); + } + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage/src/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java b/Mage/src/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java new file mode 100644 index 00000000000..e21c763d71c --- /dev/null +++ b/Mage/src/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java @@ -0,0 +1,178 @@ + /* + * 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.target.common; + + import java.util.HashSet; + import java.util.Set; + import java.util.UUID; + import mage.constants.Zone; + import mage.MageObject; + import mage.abilities.Ability; + import mage.abilities.dynamicvalue.DynamicValue; + import mage.abilities.dynamicvalue.common.StaticValue; + import mage.filter.Filter; + import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; + import mage.filter.common.FilterCreaturePermanent; + import mage.game.Game; + import mage.game.permanent.Permanent; + import mage.target.TargetAmount; + + /** + * + * @author BetaSteward_at_googlemail.com + */ + public class TargetCreatureOrPlaneswalkerAmount extends TargetAmount { + + protected FilterCreatureOrPlaneswalkerPermanent filter; + + public TargetCreatureOrPlaneswalkerAmount(int amount) { + // 107.1c If a rule or ability instructs a player to choose “any number,” that player may choose + // any positive number or zero, unless something (such as damage or counters) is being divided + // or distributed among “any number” of players and/or objects. In that case, a nonzero number + // of players and/or objects must be chosen if possible. + this(new StaticValue(amount)); + this.minNumberOfTargets = 1; + } + + public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount) { + super(amount); + this.zone = Zone.ALL; + this.filter = new FilterCreatureOrPlaneswalkerPermanent(); + this.targetName = filter.getMessage(); + } + + public TargetCreatureOrPlaneswalkerAmount(final TargetCreatureOrPlaneswalkerAmount 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); + } + return false; + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + Permanent permanent = game.getPermanent(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 (permanent != null) { + return filter.match(permanent, game); + } + return false; + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + return canTarget(id, source, game); + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + int count = 0; + MageObject targetSource = game.getObject(sourceId); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + } + return false; + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + int count = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), 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 (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { + if (filter.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("(").append(getTargetAmount(targetId)).append(") "); + } + } + return sb.toString(); + } + + @Override + public TargetCreatureOrPlaneswalkerAmount copy() { + return new TargetCreatureOrPlaneswalkerAmount(this); + } + + } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index c8ce7577d1f..a2b40b1f334 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -25746,6 +25746,7 @@ Savage Ventmaw|Dragons of Tarkir|231|U|{4}{R}{G}|Creature - Dragon|4|4|Flying$Wh Silumgar's Command|Dragons of Tarkir|232|R|{3}{U}{B}|Instant|||Choose two - Counter target noncreature spell; or Return target permanent to its owner's hand; or Target creature gets -3/-3 until end of turn; or Destroy target planeswalker.| Swift Warkite|Dragons of Tarkir|233|U|{4}{B}{R}|Creature - Dragon|4|4|Flying$When Swift Warkite enters the battlefield, you may put a creature card with converted mana cost 3 or less from your hand or graveyard onto the battlefield. That creature gains haste. Return it to your hand at the beginning of the next end step.| Evolving Wilds|Dragons of Tarkir|248|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.| +Haven of the Spirit Dragon|Dragons of Tarkir|249|R||Land|||{T}: Add {1} to your mana pool.${T}: add one mana of any color to your mana pool. Spend this mana only to cast a Dragon creature spell.${2}, {T}, Sacrifice Haven of the Spirit Dragon: Return target Dragon creature card or Ugin planeswalker card from your graveyard to your hand.| Emrakul, the Aeons Torn|Modern Masters 2015|3|M|{15}|Legendary Creature - Eldrazi|15|15|Emrakul, the Aeons Torn can't be countered.$When you cast Emrakul, take an extra turn after this one.$Flying, protection from colored spells, annihilator 6$When Emrakul is put into a graveyard from anywhere, its owner shuffles his or her graveyard into his or her library.| Karn Liberated|Modern Masters 2015|4|M|{7}|Planeswalker - Karn|||+4: Target player exiles a card from his or her hand.$-3: Exile target permanent.$-14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control.| Tarmogoyf|Modern Masters 2015|165|M|{1}{G}|Creature - Lhurgoyf|*|1+*|Tarmogoyf's power is equal to the number of card types among cards in all graveyards and its toughness is equal to that number plus 1. (Artifact, creature, enchantment, instant, land, planeswalker, sorcery, and tribal are card types.)|