From 6fa1ad3aaaf6ef5eeea6b8be0e0262467a2cc154 Mon Sep 17 00:00:00 2001 From: htrajan Date: Fri, 26 Jun 2020 17:55:43 -0700 Subject: [PATCH] [M21] Implement more cards (#6730) * EnthrallingHold * ArchfiendsVessel * ConspicuousSnoop * HoodedBlightfang * commit set updates * fix text * fix Archfiend's Vessel cast from graveyard trigger and Enthralling Hold text --- .../src/mage/cards/a/ArchfiendsVessel.java | 131 ++++++++++++++++++ .../src/mage/cards/c/ConspicuousSnoop.java | 54 ++++++++ .../src/mage/cards/e/EnthrallingHold.java | 64 +++++++++ .../src/mage/cards/h/HoodedBlightfang.java | 58 ++++++++ Mage.Sets/src/mage/cards/s/SkillBorrower.java | 67 ++------- Mage.Sets/src/mage/sets/CoreSet2021.java | 4 + ...cksCreatureYouControlTriggeredAbility.java | 4 +- ...aneswalkerWhenDamagedTriggeredAbility.java | 62 +++++++++ ...GainActivatedAbilitiesOfTopCardEffect.java | 56 ++++++++ .../game/permanent/token/AssassinToken2.java | 47 +------ .../watchers/common/SpellsCastWatcher.java | 22 ++- 11 files changed, 465 insertions(+), 104 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/ArchfiendsVessel.java create mode 100644 Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java create mode 100644 Mage.Sets/src/mage/cards/e/EnthrallingHold.java create mode 100644 Mage.Sets/src/mage/cards/h/HoodedBlightfang.java create mode 100644 Mage/src/main/java/mage/abilities/common/DestroyPlaneswalkerWhenDamagedTriggeredAbility.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/GainActivatedAbilitiesOfTopCardEffect.java diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendsVessel.java b/Mage.Sets/src/mage/cards/a/ArchfiendsVessel.java new file mode 100644 index 00000000000..95d0680393e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArchfiendsVessel.java @@ -0,0 +1,131 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.DemonToken; +import mage.game.permanent.token.Token; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.List; +import java.util.UUID; + +/** + * + * @author htrajan + */ +public final class ArchfiendsVessel extends CardImpl { + + public ArchfiendsVessel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Archfiend's Vessel enters the battlefield, if it entered from your graveyard or you cast it from your graveyard, exile it. If you do, create a 5/5 black Demon creature token with flying. + this.addAbility(new ArchfiendsVesselAbility(), new SpellsCastWatcher()); + } + + private ArchfiendsVessel(final ArchfiendsVessel card) { + super(card); + } + + @Override + public ArchfiendsVessel copy() { + return new ArchfiendsVessel(this); + } +} + +class ArchfiendsVesselAbility extends EntersBattlefieldTriggeredAbility { + + ArchfiendsVesselAbility() { + super(new ArchfiendsVesselEffect()); + } + + private ArchfiendsVesselAbility(ArchfiendsVesselAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (super.checkTrigger(event, game)) { + if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) event; + if (entersTheBattlefieldEvent.getTargetId().equals(getSourceId()) && entersTheBattlefieldEvent.getFromZone() == Zone.GRAVEYARD) { + return true; + } else { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + List spellsCastFromGraveyard = watcher.getSpellsCastFromGraveyardThisTurn(getControllerId()); + if (spellsCastFromGraveyard != null) { + return spellsCastFromGraveyard.stream() + .anyMatch(spell -> spell.getMainCard().getId().equals((entersTheBattlefieldEvent.getTarget().getMainCard().getId()))); + } + } + } + } + return false; + } + + @Override + public ArchfiendsVesselAbility copy() { + return new ArchfiendsVesselAbility(this); + } +} + +class ArchfiendsVesselEffect extends OneShotEffect { + + ArchfiendsVesselEffect() { + super(Outcome.Benefit); + staticText = "if it entered from your graveyard or you cast it from your graveyard, exile it. If you do, create a 5/5 black Demon creature token with flying"; + } + + private ArchfiendsVesselEffect(ArchfiendsVesselEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent archfiendsVessel = source.getSourcePermanentIfItStillExists(game); + if (archfiendsVessel != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + boolean moved = controller.moveCards(archfiendsVessel.getMainCard(), Zone.EXILED, source, game); + if (moved) { + Token token = new DemonToken(); + token.putOntoBattlefield(1, game, source.getSourceId(), controller.getId()); + } + return true; + } + } + return false; + } + + @Override + public ArchfiendsVesselEffect copy() { + return new ArchfiendsVesselEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java b/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java new file mode 100644 index 00000000000..1edb15357c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java @@ -0,0 +1,54 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.GainActivatedAbilitiesOfTopCardEffect; +import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; +import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; + +import java.util.UUID; + +/** + * + * @author htrajan + */ +public final class ConspicuousSnoop extends CardImpl { + + private static final FilterCard filter = new FilterCard("cast Goblin spells"); + + static { + filter.add(SubType.GOBLIN.getPredicate()); + } + + public ConspicuousSnoop(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Play with the top card of your library revealed. + this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect())); + + // You may cast Goblin spells from the top of your library. + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + + // As long as the top card of your library is a Goblin card, Conspicuous Snoop has all activated abilities of that card. + this.addAbility(new SimpleStaticAbility(new GainActivatedAbilitiesOfTopCardEffect(filter.copy().withMessage("a Goblin card")))); + } + + private ConspicuousSnoop(final ConspicuousSnoop card) { + super(card); + } + + @Override + public ConspicuousSnoop copy() { + return new ConspicuousSnoop(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnthrallingHold.java b/Mage.Sets/src/mage/cards/e/EnthrallingHold.java new file mode 100644 index 00000000000..9060709592a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnthrallingHold.java @@ -0,0 +1,64 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.ControlEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * + * @author htrajan + */ +public final class EnthrallingHold extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(TappedPredicate.instance); + } + + public EnthrallingHold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.GainControl)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // You can't choose an untapped creature as this spell's target as you cast it. + auraTarget.replaceFilter(filter); + Effect controlEnchantedEffect = new ControlEnchantedEffect(); + controlEnchantedEffect.setText("You can't choose an untapped creature as this spell's target as you cast it.
" + controlEnchantedEffect.getText(null)); + + // You control enchanted creature. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, controlEnchantedEffect)); + } + + private EnthrallingHold(final EnthrallingHold card) { + super(card); + } + + @Override + public EnthrallingHold copy() { + return new EnthrallingHold(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java b/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java new file mode 100644 index 00000000000..f3eb71472d1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java @@ -0,0 +1,58 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.common.DestroyPlaneswalkerWhenDamagedTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; + +/** + * + * @author htrajan + */ +public final class HoodedBlightfang extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature you control with deathtouch"); + + static { + filter.add(new AbilityPredicate(DeathtouchAbility.class)); + } + + public HoodedBlightfang(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.SNAKE); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever a creature you control with deathtouch attacks, each opponent loses 1 life and you gain 1 life. + Ability ability = new AttacksCreatureYouControlTriggeredAbility(new LoseLifeOpponentsEffect(1), false, filter); + ability.addEffect(new GainLifeEffect(1).setText("and you gain 1 life")); + this.addAbility(ability); + + // Whenever a creature you control with deathtouch deals damage to a planeswalker, destroy that planeswalker. + this.addAbility(new DestroyPlaneswalkerWhenDamagedTriggeredAbility(filter)); + } + + private HoodedBlightfang(final HoodedBlightfang card) { + super(card); + } + + @Override + public HoodedBlightfang copy() { + return new HoodedBlightfang(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkillBorrower.java b/Mage.Sets/src/mage/cards/s/SkillBorrower.java index 60f9d873634..0fefe34ec97 100644 --- a/Mage.Sets/src/mage/cards/s/SkillBorrower.java +++ b/Mage.Sets/src/mage/cards/s/SkillBorrower.java @@ -1,26 +1,19 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; import mage.abilities.StaticAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.GainActivatedAbilitiesOfTopCardEffect; import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; import mage.constants.SubType; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; + +import java.util.UUID; /** * @@ -54,8 +47,14 @@ public final class SkillBorrower extends CardImpl { class SkillBorrowerAbility extends StaticAbility { + private static final FilterCard filter = new FilterCard("an artifact or creature card"); + + static { + filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ARTIFACT.getPredicate())); + } + public SkillBorrowerAbility() { - super(Zone.BATTLEFIELD, new SkillBorrowerEffect()); + super(Zone.BATTLEFIELD, new GainActivatedAbilitiesOfTopCardEffect(filter)); } public SkillBorrowerAbility(SkillBorrowerAbility ability) { @@ -66,47 +65,5 @@ class SkillBorrowerAbility extends StaticAbility { public SkillBorrowerAbility copy() { return new SkillBorrowerAbility(this); } - - @Override - public String getRule() { - return "As long as the top card of your library is an artifact or creature card, {this} has all activated abilities of that card"; - } } -class SkillBorrowerEffect extends ContinuousEffectImpl { - - public SkillBorrowerEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "As long as the top card of your library is an artifact or creature card, {this} has all activated abilities of that card"; - } - - public SkillBorrowerEffect(final SkillBorrowerEffect effect) { - super(effect); - } - - @Override - public SkillBorrowerEffect copy() { - return new SkillBorrowerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - Card card = player.getLibrary().getFromTop(game); - if (card != null && (card.isCreature() || card.isArtifact())) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - for (Ability ability : card.getAbilities(game)) { - if (ability instanceof ActivatedAbility) { - permanent.addAbility(ability, source.getSourceId(), game); - } - } - return true; - } - } - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/sets/CoreSet2021.java b/Mage.Sets/src/mage/sets/CoreSet2021.java index 8bb6310bfc6..1c7be8b046b 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2021.java +++ b/Mage.Sets/src/mage/sets/CoreSet2021.java @@ -40,6 +40,7 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Angelic Ascension", 3, Rarity.UNCOMMON, mage.cards.a.AngelicAscension.class)); cards.add(new SetCardInfo("Animal Sanctuary", 242, Rarity.RARE, mage.cards.a.AnimalSanctuary.class)); cards.add(new SetCardInfo("Anointed Chorister", 4, Rarity.COMMON, mage.cards.a.AnointedChorister.class)); + cards.add(new SetCardInfo("Archfiend's Vessel", 88, Rarity.UNCOMMON, mage.cards.a.ArchfiendsVessel.class)); cards.add(new SetCardInfo("Aven Gagglemaster", 5, Rarity.UNCOMMON, mage.cards.a.AvenGagglemaster.class)); cards.add(new SetCardInfo("Azusa, Lost but Seeking", 173, Rarity.RARE, mage.cards.a.AzusaLostButSeeking.class)); cards.add(new SetCardInfo("Bad Deal", 89, Rarity.UNCOMMON, mage.cards.b.BadDeal.class)); @@ -77,6 +78,7 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Colossal Dreadmaw", 176, Rarity.COMMON, mage.cards.c.ColossalDreadmaw.class)); cards.add(new SetCardInfo("Conclave Mentor", 216, Rarity.UNCOMMON, mage.cards.c.ConclaveMentor.class)); cards.add(new SetCardInfo("Concordia Pegasus", 12, Rarity.COMMON, mage.cards.c.ConcordiaPegasus.class)); + cards.add(new SetCardInfo("Conspicuous Snoop", 139, Rarity.RARE, mage.cards.c.ConspicuousSnoop.class)); cards.add(new SetCardInfo("Containment Priest", 13, Rarity.RARE, mage.cards.c.ContainmentPriest.class)); cards.add(new SetCardInfo("Crash Through", 140, Rarity.COMMON, mage.cards.c.CrashThrough.class)); cards.add(new SetCardInfo("Crypt Lurker", 93, Rarity.COMMON, mage.cards.c.CryptLurker.class)); @@ -95,6 +97,7 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Duress", 96, Rarity.COMMON, mage.cards.d.Duress.class)); cards.add(new SetCardInfo("Elder Gargaroth", 179, Rarity.MYTHIC, mage.cards.e.ElderGargaroth.class)); cards.add(new SetCardInfo("Eliminate", 97, Rarity.UNCOMMON, mage.cards.e.Eliminate.class)); + cards.add(new SetCardInfo("Enthralling Hold", 49, Rarity.UNCOMMON, mage.cards.e.EnthrallingHold.class)); cards.add(new SetCardInfo("Epitaph Golem", 230, Rarity.UNCOMMON, mage.cards.e.EpitaphGolem.class)); cards.add(new SetCardInfo("Experimental Overload", 218, Rarity.UNCOMMON, mage.cards.e.ExperimentalOverload.class)); cards.add(new SetCardInfo("Fabled Passage", 246, Rarity.RARE, mage.cards.f.FabledPassage.class)); @@ -137,6 +140,7 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Heroic Intervention", 188, Rarity.RARE, mage.cards.h.HeroicIntervention.class)); cards.add(new SetCardInfo("Historian of Zhalfir", 325, Rarity.UNCOMMON, mage.cards.h.HistorianOfZhalfir.class)); cards.add(new SetCardInfo("Hobblefiend", 152, Rarity.COMMON, mage.cards.h.Hobblefiend.class)); + cards.add(new SetCardInfo("Hooded Blightfang", 104, Rarity.RARE, mage.cards.h.HoodedBlightfang.class)); cards.add(new SetCardInfo("Hunter's Edge", 189, Rarity.COMMON, mage.cards.h.HuntersEdge.class)); cards.add(new SetCardInfo("Igneous Cur", 153, Rarity.COMMON, mage.cards.i.IgneousCur.class)); cards.add(new SetCardInfo("Indulging Patrician", 219, Rarity.UNCOMMON, mage.cards.i.IndulgingPatrician.class)); diff --git a/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java index 36aa72e858c..6f67313da97 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java @@ -76,9 +76,9 @@ public class AttacksCreatureYouControlTriggeredAbility extends TriggeredAbilityI public String getRule() { String an; String who = filter.getMessage(); - if (who.startsWith("another")) { + if (who.startsWith("another") || who.startsWith("a ")) { an = ""; - } else if (who.startsWith("a")) { + } else if (who.length() > 0 && "aeiou".contains(who.charAt(0) + "")) { an = "an "; } else { an = "a "; diff --git a/Mage/src/main/java/mage/abilities/common/DestroyPlaneswalkerWhenDamagedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DestroyPlaneswalkerWhenDamagedTriggeredAbility.java new file mode 100644 index 00000000000..1d8eabc2bd3 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/DestroyPlaneswalkerWhenDamagedTriggeredAbility.java @@ -0,0 +1,62 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +public class DestroyPlaneswalkerWhenDamagedTriggeredAbility extends TriggeredAbilityImpl { + + private final FilterPermanent filter; + + public DestroyPlaneswalkerWhenDamagedTriggeredAbility() { + this((FilterPermanent) null); + } + + public DestroyPlaneswalkerWhenDamagedTriggeredAbility(FilterPermanent filter) { + super(Zone.BATTLEFIELD, null); + this.filter = filter; + } + + private DestroyPlaneswalkerWhenDamagedTriggeredAbility(final DestroyPlaneswalkerWhenDamagedTriggeredAbility effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public DestroyPlaneswalkerWhenDamagedTriggeredAbility copy() { + return new DestroyPlaneswalkerWhenDamagedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLANESWALKER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = getSourcePermanentIfItStillExists(game); + if (permanent != null) { + boolean applies = filter != null ? + filter.match(permanent, game) : event.getSourceId().equals(getSourceId()); + if (applies) { + Effect effect = new DestroyTargetEffect(); + effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); + this.getEffects().clear(); + this.addEffect(effect); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever " + (filter != null ? filter.getMessage() : "this creature") + " deals damage to a planeswalker, destroy that planeswalker."; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/GainActivatedAbilitiesOfTopCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GainActivatedAbilitiesOfTopCardEffect.java new file mode 100644 index 00000000000..2ea7fe132ce --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/GainActivatedAbilitiesOfTopCardEffect.java @@ -0,0 +1,56 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.Card; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +public class GainActivatedAbilitiesOfTopCardEffect extends ContinuousEffectImpl { + + private final FilterCard filter; + + public GainActivatedAbilitiesOfTopCardEffect(FilterCard filter) { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "As long as the top card of your library is " + filter.getMessage() + ", {this} has all activated abilities of that card"; + this.filter = filter; + } + + public GainActivatedAbilitiesOfTopCardEffect(final GainActivatedAbilitiesOfTopCardEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public GainActivatedAbilitiesOfTopCardEffect copy() { + return new GainActivatedAbilitiesOfTopCardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + Card card = player.getLibrary().getFromTop(game); + if (card != null && filter.match(card, game)) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + for (Ability ability : card.getAbilities(game)) { + if (ability instanceof ActivatedAbility) { + permanent.addAbility(ability, source.getSourceId(), game); + } + } + return true; + } + } + } + return false; + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java b/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java index 5f7b4077180..2ddde6e5b40 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java @@ -1,16 +1,10 @@ package mage.game.permanent.token; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.common.DestroyPlaneswalkerWhenDamagedTriggeredAbility; import mage.abilities.keyword.DeathtouchAbility; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.target.targetpointer.FixedTarget; /** * @author TheElk801 @@ -25,7 +19,7 @@ public final class AssassinToken2 extends TokenImpl { power = new MageInt(1); toughness = new MageInt(1); addAbility(DeathtouchAbility.getInstance()); - addAbility(new AssassinToken2TriggeredAbility()); + addAbility(new DestroyPlaneswalkerWhenDamagedTriggeredAbility()); setOriginalExpansionSetCode("WAR"); } @@ -39,40 +33,3 @@ public final class AssassinToken2 extends TokenImpl { } } -class AssassinToken2TriggeredAbility extends TriggeredAbilityImpl { - - AssassinToken2TriggeredAbility() { - super(Zone.BATTLEFIELD, null); - } - - private AssassinToken2TriggeredAbility(final AssassinToken2TriggeredAbility effect) { - super(effect); - } - - @Override - public AssassinToken2TriggeredAbility copy() { - return new AssassinToken2TriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLANESWALKER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(getSourceId())) { - Effect effect = new DestroyTargetEffect(); - effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); - this.getEffects().clear(); - this.addEffect(effect); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever this creature deals damage to a planeswalker, destroy that planeswalker."; - } -} \ No newline at end of file diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java index 883ab6f9ef6..46a1a7fcc01 100644 --- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java @@ -5,8 +5,6 @@ */ package mage.watchers.common; -import java.util.*; - import mage.MageObject; import mage.constants.WatcherScope; import mage.constants.Zone; @@ -17,6 +15,12 @@ import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.watchers.Watcher; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + /** * * @author LevelX2 @@ -24,6 +28,7 @@ import mage.watchers.Watcher; public class SpellsCastWatcher extends Watcher { private final Map> spellsCast = new HashMap<>(); + private final Map> spellsCastFromGraveyard = new HashMap<>(); private int nonCreatureSpells; public SpellsCastWatcher() { @@ -42,13 +47,21 @@ public class SpellsCastWatcher extends Watcher { } if (spell != null) { List spells; + List graveyardSpells; if (!spellsCast.containsKey(spell.getControllerId())) { spells = new ArrayList<>(); spellsCast.put(spell.getControllerId(), spells); + graveyardSpells = new ArrayList<>(); + spellsCastFromGraveyard.put(spell.getControllerId(), graveyardSpells); + } else { spells = spellsCast.get(spell.getControllerId()); + graveyardSpells = spellsCastFromGraveyard.get(spell.getControllerId()); } spells.add(spell.copy()); // copy needed because attributes like color could be changed later + if (event.getZone() == Zone.GRAVEYARD) { + graveyardSpells.add(spell.copy()); + } if (StaticFilters.FILTER_SPELL_NON_CREATURE.match(spell, game)) { nonCreatureSpells++; } @@ -61,12 +74,17 @@ public class SpellsCastWatcher extends Watcher { super.reset(); nonCreatureSpells = 0; spellsCast.clear(); + spellsCastFromGraveyard.clear(); } public List getSpellsCastThisTurn(UUID playerId) { return spellsCast.get(playerId); } + public List getSpellsCastFromGraveyardThisTurn(UUID playerId) { + return spellsCastFromGraveyard.get(playerId); + } + public int getNumberOfNonCreatureSpells() { return nonCreatureSpells; }