From ce0b647a362c10d2c66a85f3db2466f00d7816c8 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 18 Sep 2018 14:47:42 -0400 Subject: [PATCH] Implemented Etrata, the Silencer --- .../src/mage/cards/e/EtrataTheSilencer.java | 151 ++++++++++++++++++ Mage.Sets/src/mage/sets/GuildsOfRavnica.java | 1 + .../main/java/mage/counters/CounterType.java | 2 +- .../predicate/permanent/CounterPredicate.java | 7 +- 4 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java diff --git a/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java new file mode 100644 index 00000000000..19276ee723f --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java @@ -0,0 +1,151 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.cards.Card; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class EtrataTheSilencer extends CardImpl { + + public EtrataTheSilencer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Etrata, the Silencer can't be blocked. + this.addAbility(new CantBeBlockedSourceAbility()); + + // Whenever Etrata deals combat damage to a player, exile target creature that player controls and put a hit counter on that card. That player loses the game if they own three or more exiled card with hit counters on them. Etrata's owner shuffles Etrata into their library. + this.addAbility(new EtrataTheSilencerTriggeredAbility()); + } + + public EtrataTheSilencer(final EtrataTheSilencer card) { + super(card); + } + + @Override + public EtrataTheSilencer copy() { + return new EtrataTheSilencer(this); + } +} + +class EtrataTheSilencerTriggeredAbility extends TriggeredAbilityImpl { + + public EtrataTheSilencerTriggeredAbility() { + super(Zone.BATTLEFIELD, new EtrataTheSilencerEffect()); + } + + public EtrataTheSilencerTriggeredAbility(final EtrataTheSilencerTriggeredAbility ability) { + super(ability); + } + + @Override + public EtrataTheSilencerTriggeredAbility copy() { + return new EtrataTheSilencerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; + if (damageEvent.isCombatDamage() && event.getSourceId().equals(this.getSourceId())) { + Player opponent = game.getPlayer(event.getPlayerId()); + if (opponent != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); + filter.add(new ControllerIdPredicate(opponent.getId())); + this.getTargets().clear(); + this.addTarget(new TargetCreaturePermanent(filter)); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} deals combat damage to a player, " + + "exile target creature that player controls " + + "and put a hit counter on that card. " + + "That player loses the game if they own three or more " + + "exiled cards with hit counters on them. " + + "{this}'s owner shuffles {this} into their library."; + } +} + +class EtrataTheSilencerEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(new CounterPredicate(CounterType.HIT)); + } + + public EtrataTheSilencerEffect() { + super(Outcome.Benefit); + } + + public EtrataTheSilencerEffect(final EtrataTheSilencerEffect effect) { + super(effect); + } + + @Override + public EtrataTheSilencerEffect copy() { + return new EtrataTheSilencerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (creature == null) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(creature.getControllerId()); + if (controller == null || player == null) { + return false; + } + controller.moveCards(creature, Zone.EXILED, source, game); + Card card = game.getCard(source.getFirstTarget()); + if (card != null) { + card.addCounters(CounterType.HIT.createInstance(), source, game); + } + if (game.getExile().getExileZone(player.getId()).count(filter, game) > 2) { + player.lost(game); + } + return new ShuffleIntoLibrarySourceEffect().apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java index ee1ee9d0be2..fd76fefa984 100644 --- a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java +++ b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java @@ -72,6 +72,7 @@ public final class GuildsOfRavnica extends ExpansionSet { cards.add(new SetCardInfo("Emmara, Soul of the Accord", 168, Rarity.RARE, mage.cards.e.EmmaraSoulOfTheAccord.class)); cards.add(new SetCardInfo("Enhanced Surveillance", 40, Rarity.UNCOMMON, mage.cards.e.EnhancedSurveillance.class)); cards.add(new SetCardInfo("Erratic Cyclops", 98, Rarity.RARE, mage.cards.e.ErraticCyclops.class)); + cards.add(new SetCardInfo("Etrata, the Silencer", 170, Rarity.RARE, mage.cards.e.EtrataTheSilencer.class)); cards.add(new SetCardInfo("Expansion // Explosion", 224, Rarity.RARE, mage.cards.e.ExpansionExplosion.class)); cards.add(new SetCardInfo("Find // Finality", 225, Rarity.RARE, mage.cards.f.FindFinality.class)); cards.add(new SetCardInfo("Firemind's Research", 171, Rarity.RARE, mage.cards.f.FiremindsResearch.class)); diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 2ded9a796bc..865cab23a53 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -1,4 +1,3 @@ - package mage.counters; /** @@ -54,6 +53,7 @@ public enum CounterType { GROWTH("growth"), HATCHLING("hatchling"), HEALING("healing"), + HIT("hit"), HOOFPRINT("hoofprint"), HOUR("hour"), HOURGLASS("hourglass"), diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java index ed505b2cd2f..75469d4dc17 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/CounterPredicate.java @@ -1,16 +1,15 @@ - package mage.filter.predicate.permanent; +import mage.cards.Card; import mage.counters.CounterType; import mage.filter.predicate.Predicate; import mage.game.Game; -import mage.game.permanent.Permanent; /** * * @author jeffwadsworth */ -public class CounterPredicate implements Predicate { +public class CounterPredicate implements Predicate { private final CounterType counter; @@ -23,7 +22,7 @@ public class CounterPredicate implements Predicate { } @Override - public boolean apply(Permanent input, Game game) { + public boolean apply(Card input, Game game) { if (counter == null) { return !input.getCounters(game).keySet().isEmpty(); } else {