From 757c01343fd492df4f50d19edea9ebc263a4af9d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 7 May 2017 10:46:01 +0200 Subject: [PATCH] * Ravnica: City of Guilds - Added 3 cards. --- Mage.Sets/src/mage/cards/g/GriftersBlade.java | 118 +++++++++++++++++ .../src/mage/cards/l/LeoninScimitar.java | 8 +- .../src/mage/cards/m/MarkOfEviction.java | 120 ++++++++++++++++++ .../src/mage/cards/n/NullstoneGargoyle.java | 111 ++++++++++++++++ .../src/mage/sets/RavnicaCityOfGuilds.java | 3 + .../main/java/mage/filter/StaticFilters.java | 2 + .../watchers/common/SpellsCastWatcher.java | 10 ++ 7 files changed, 369 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/g/GriftersBlade.java create mode 100644 Mage.Sets/src/mage/cards/m/MarkOfEviction.java create mode 100644 Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java diff --git a/Mage.Sets/src/mage/cards/g/GriftersBlade.java b/Mage.Sets/src/mage/cards/g/GriftersBlade.java new file mode 100644 index 0000000000..856be7a4e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GriftersBlade.java @@ -0,0 +1,118 @@ +/* + * 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.g; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class GriftersBlade extends CardImpl { + + public GriftersBlade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add("Equipment"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // As Grifter's Blade enters the battlefield, choose a creature you control it could be attached to. If you do, it enters the battlefield attached to that creature. + this.addAbility(new AsEntersBattlefieldAbility(new GriftersBladeChooseCreatureEffect(Outcome.BoostCreature))); + + // Equipped creature gets +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 1))); + + // Equip {1} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1))); + + } + + public GriftersBlade(final GriftersBlade card) { + super(card); + } + + @Override + public GriftersBlade copy() { + return new GriftersBlade(this); + } +} + +class GriftersBladeChooseCreatureEffect extends OneShotEffect { + + public GriftersBladeChooseCreatureEffect(Outcome outcome) { + super(outcome); + this.staticText = "choose a creature you control it could be attached to. If you do, it enters the battlefield attached to that creature"; + } + + public GriftersBladeChooseCreatureEffect(final GriftersBladeChooseCreatureEffect effect) { + super(effect); + } + + @Override + public GriftersBladeChooseCreatureEffect copy() { + return new GriftersBladeChooseCreatureEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + if (controller != null && mageObject != null) { + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + Permanent attachToCreature = game.getPermanent(target.getFirstTarget()); + if (attachToCreature != null) { + attachToCreature.addAttachment(mageObject.getId(), game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeoninScimitar.java b/Mage.Sets/src/mage/cards/l/LeoninScimitar.java index 51cb215e1d..6fb220e5ab 100644 --- a/Mage.Sets/src/mage/cards/l/LeoninScimitar.java +++ b/Mage.Sets/src/mage/cards/l/LeoninScimitar.java @@ -28,14 +28,13 @@ package mage.cards.l; import java.util.UUID; - -import mage.constants.CardType; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -45,9 +44,12 @@ import mage.constants.Zone; public class LeoninScimitar extends CardImpl { public LeoninScimitar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); this.subtype.add("Equipment"); + + // Equipped creature gets +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 1))); + // Equip {1} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1))); } diff --git a/Mage.Sets/src/mage/cards/m/MarkOfEviction.java b/Mage.Sets/src/mage/cards/m/MarkOfEviction.java new file mode 100644 index 0000000000..a9d77f4993 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarkOfEviction.java @@ -0,0 +1,120 @@ +/* + * 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.m; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class MarkOfEviction extends CardImpl { + + public MarkOfEviction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of your upkeep, return enchanted creature and all Auras attached to that creature to their owners' hands. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MarkOfEvictionEffect(), TargetController.YOU, false)); + } + + public MarkOfEviction(final MarkOfEviction card) { + super(card); + } + + @Override + public MarkOfEviction copy() { + return new MarkOfEviction(this); + } +} + +class MarkOfEvictionEffect extends OneShotEffect { + + public MarkOfEvictionEffect() { + super(Outcome.Benefit); + this.staticText = "return enchanted creature and all Auras attached to that creature to their owners' hands"; + } + + public MarkOfEvictionEffect(final MarkOfEvictionEffect effect) { + super(effect); + } + + @Override + public MarkOfEvictionEffect copy() { + return new MarkOfEvictionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourceObject != null && sourceObject.getAttachedTo() != null) { + Permanent enchanted = game.getPermanent(sourceObject.getAttachedTo()); + if (enchanted != null) { + Set toHand = new HashSet<>(); + toHand.add(enchanted); + for (UUID attachmentId : enchanted.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.getSubtype(game).contains("Aura")) { + toHand.add(attachment); + } + } + controller.moveCards(toHand, Zone.HAND, source, game); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java b/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java new file mode 100644 index 0000000000..abb1d32a20 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java @@ -0,0 +1,111 @@ +/* + * 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.n; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author LevelX2 + */ +public class NullstoneGargoyle extends CardImpl { + + public NullstoneGargoyle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{9}"); + + this.subtype.add("Gargoyle"); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever the first noncreature spell of a turn is cast, counter that spell. + this.addAbility(new NullstoneGargoyleTriggeredAbility(), new SpellsCastWatcher()); + } + + public NullstoneGargoyle(final NullstoneGargoyle card) { + super(card); + } + + @Override + public NullstoneGargoyle copy() { + return new NullstoneGargoyle(this); + } +} + +class NullstoneGargoyleTriggeredAbility extends TriggeredAbilityImpl { + + public NullstoneGargoyleTriggeredAbility() { + super(Zone.BATTLEFIELD, new CounterTargetEffect(), false); + } + + public NullstoneGargoyleTriggeredAbility(NullstoneGargoyleTriggeredAbility ability) { + super(ability); + } + + @Override + public NullstoneGargoyleTriggeredAbility copy() { + return new NullstoneGargoyleTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + if (watcher != null && watcher.getNumberOfNonCreatureSpells() == 1) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever the first noncreature spell of a turn is cast, counter that spell."; + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java b/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java index ae72b23ddf..f3d48eff60 100644 --- a/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java +++ b/Mage.Sets/src/mage/sets/RavnicaCityOfGuilds.java @@ -175,6 +175,7 @@ public class RavnicaCityOfGuilds extends ExpansionSet { cards.add(new SetCardInfo("Grayscaled Gharial", 52, Rarity.COMMON, mage.cards.g.GrayscaledGharial.class)); cards.add(new SetCardInfo("Greater Forgeling", 129, Rarity.UNCOMMON, mage.cards.g.GreaterForgeling.class)); cards.add(new SetCardInfo("Greater Mossdog", 169, Rarity.COMMON, mage.cards.g.GreaterMossdog.class)); + cards.add(new SetCardInfo("Grifter's Blade", 263, Rarity.UNCOMMON, mage.cards.g.GriftersBlade.class)); cards.add(new SetCardInfo("Grozoth", 53, Rarity.RARE, mage.cards.g.Grozoth.class)); cards.add(new SetCardInfo("Guardian of Vitu-Ghazi", 212, Rarity.COMMON, mage.cards.g.GuardianOfVituGhazi.class)); cards.add(new SetCardInfo("Halcyon Glaze", 54, Rarity.UNCOMMON, mage.cards.h.HalcyonGlaze.class)); @@ -207,6 +208,7 @@ public class RavnicaCityOfGuilds extends ExpansionSet { cards.add(new SetCardInfo("Loxodon Gatekeeper", 25, Rarity.RARE, mage.cards.l.LoxodonGatekeeper.class)); cards.add(new SetCardInfo("Loxodon Hierarch", 214, Rarity.RARE, mage.cards.l.LoxodonHierarch.class)); cards.add(new SetCardInfo("Lurking Informant", 249, Rarity.COMMON, mage.cards.l.LurkingInformant.class)); + cards.add(new SetCardInfo("Mark of Eviction", 58, Rarity.UNCOMMON, mage.cards.m.MarkOfEviction.class)); cards.add(new SetCardInfo("Mausoleum Turnkey", 94, Rarity.UNCOMMON, mage.cards.m.MausoleumTurnkey.class)); cards.add(new SetCardInfo("Mindleech Mass", 215, Rarity.RARE, mage.cards.m.MindleechMass.class)); cards.add(new SetCardInfo("Mindmoil", 135, Rarity.RARE, mage.cards.m.Mindmoil.class)); @@ -227,6 +229,7 @@ public class RavnicaCityOfGuilds extends ExpansionSet { cards.add(new SetCardInfo("Nightguard Patrol", 26, Rarity.COMMON, mage.cards.n.NightguardPatrol.class)); cards.add(new SetCardInfo("Nightmare Void", 100, Rarity.UNCOMMON, mage.cards.n.NightmareVoid.class)); cards.add(new SetCardInfo("Nullmage Shepherd", 174, Rarity.UNCOMMON, mage.cards.n.NullmageShepherd.class)); + cards.add(new SetCardInfo("Nullstone Gargoyle", 266, Rarity.RARE, mage.cards.n.NullstoneGargoyle.class)); cards.add(new SetCardInfo("Oathsworn Giant", 27, Rarity.UNCOMMON, mage.cards.o.OathswornGiant.class)); cards.add(new SetCardInfo("Ordruun Commando", 137, Rarity.COMMON, mage.cards.o.OrdruunCommando.class)); cards.add(new SetCardInfo("Overgrown Tomb", 279, Rarity.RARE, mage.cards.o.OvergrownTomb.class)); diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 94e9a610f2..cd00c03bd6 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -39,6 +39,8 @@ public final class StaticFilters { public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_SLIVERS = new FilterCreaturePermanent("Sliver", "Sliver creatures"); public static final FilterCreatureSpell FILTER_SPELL_A_CREATURE = new FilterCreatureSpell("a creature spell"); + public static final FilterSpell FILTER_SPELL_NON_CREATURE + = (FilterSpell) new FilterSpell("noncreature spell").add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); public static final FilterPermanent FILTER_CREATURE_TOKENS = new FilterCreaturePermanent("creature tokens"); diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java index 34c2fcd1ae..c40f0e0f07 100644 --- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java @@ -12,6 +12,7 @@ import java.util.UUID; import mage.MageObject; import mage.constants.WatcherScope; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -25,6 +26,7 @@ import mage.watchers.Watcher; public class SpellsCastWatcher extends Watcher { private final HashMap> spellsCast = new HashMap<>(); + private int nonCreatureSpells; public SpellsCastWatcher() { super(SpellsCastWatcher.class.getSimpleName(), WatcherScope.GAME); @@ -59,6 +61,9 @@ public class SpellsCastWatcher extends Watcher { spells = spellsCast.get(spell.getControllerId()); } spells.add(spell.copy()); // copy needed because attributes like color could be changed later + if (StaticFilters.FILTER_SPELL_NON_CREATURE.match(spell, game)) { + nonCreatureSpells++; + } } } } @@ -66,10 +71,15 @@ public class SpellsCastWatcher extends Watcher { @Override public void reset() { super.reset(); + nonCreatureSpells = 0; spellsCast.clear(); } public List getSpellsCastThisTurn(UUID playerId) { return spellsCast.get(playerId); } + + public int getNumberOfNonCreatureSpells() { + return nonCreatureSpells; + } }