mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
[J22] Implement Preston, the Vanisher (#9860)
This commit is contained in:
parent
eaa001aa14
commit
242490373e
9 changed files with 214 additions and 27 deletions
|
@ -14,7 +14,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.CreatureWasCastWatcher;
|
||||
import mage.watchers.common.PermanentWasCastWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -34,7 +34,8 @@ public final class ContainmentPriest extends CardImpl {
|
|||
// Flash
|
||||
this.addAbility(FlashAbility.getInstance());
|
||||
// If a nontoken creature would enter the battlefield and it wasn't cast, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ContainmentPriestReplacementEffect()), new CreatureWasCastWatcher());
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ContainmentPriestReplacementEffect()),
|
||||
new PermanentWasCastWatcher());
|
||||
}
|
||||
|
||||
private ContainmentPriest(final ContainmentPriest card) {
|
||||
|
@ -96,8 +97,8 @@ class ContainmentPriestReplacementEffect extends ReplacementEffectImpl {
|
|||
card = card.getSecondCardFace();
|
||||
}
|
||||
if (card != null && card.isCreature(game)) { // TODO: Bestow Card cast as Enchantment probably not handled correctly
|
||||
CreatureWasCastWatcher watcher = game.getState().getWatcher(CreatureWasCastWatcher.class);
|
||||
return watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId());
|
||||
PermanentWasCastWatcher watcher = game.getState().getWatcher(PermanentWasCastWatcher.class);
|
||||
return watcher != null && !watcher.wasPermanentCastThisTurn(event.getTargetId());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -16,7 +16,7 @@ import mage.game.Game;
|
|||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.CreatureWasCastWatcher;
|
||||
import mage.watchers.common.PermanentWasCastWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -29,7 +29,7 @@ public final class HallowedMoonlight extends CardImpl {
|
|||
|
||||
// Until end of turn, if a creature would enter the battlefield and it wasn't cast, exile it instead.
|
||||
this.getSpellAbility().addEffect(new HallowedMoonlightEffect());
|
||||
this.getSpellAbility().addWatcher(new CreatureWasCastWatcher());
|
||||
this.getSpellAbility().addWatcher(new PermanentWasCastWatcher());
|
||||
// Draw a card.
|
||||
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
|
||||
}
|
||||
|
@ -83,8 +83,8 @@ class HallowedMoonlightEffect extends ReplacementEffectImpl {
|
|||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) event;
|
||||
if (entersTheBattlefieldEvent.getTarget().isCreature(game)) {
|
||||
CreatureWasCastWatcher watcher = game.getState().getWatcher(CreatureWasCastWatcher.class);
|
||||
if (watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId())) {
|
||||
PermanentWasCastWatcher watcher = game.getState().getWatcher(PermanentWasCastWatcher.class);
|
||||
if (watcher != null && !watcher.wasPermanentCastThisTurn(event.getTargetId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.CreatureWasCastWatcher;
|
||||
import mage.watchers.common.PermanentWasCastWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -35,7 +35,7 @@ public final class Mistcaller extends CardImpl {
|
|||
this.addAbility(new SimpleActivatedAbility(
|
||||
new ContainmentPriestReplacementEffect(),
|
||||
new SacrificeSourceCost()
|
||||
), new CreatureWasCastWatcher());
|
||||
), new PermanentWasCastWatcher());
|
||||
}
|
||||
|
||||
private Mistcaller(final Mistcaller card) {
|
||||
|
@ -98,8 +98,8 @@ class ContainmentPriestReplacementEffect extends ReplacementEffectImpl {
|
|||
card = card.getSecondCardFace();
|
||||
}
|
||||
if (card != null && card.isCreature(game)) { // TODO: Bestow Card cast as Enchantment probably not handled correctly
|
||||
CreatureWasCastWatcher watcher = game.getState().getWatcher(CreatureWasCastWatcher.class);
|
||||
return watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId());
|
||||
PermanentWasCastWatcher watcher = game.getState().getWatcher(PermanentWasCastWatcher.class);
|
||||
return watcher != null && !watcher.wasPermanentCastThisTurn(event.getTargetId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
82
Mage.Sets/src/mage/cards/p/PrestonTheVanisher.java
Normal file
82
Mage.Sets/src/mage/cards/p/PrestonTheVanisher.java
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
package mage.cards.p;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldCastTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
import mage.filter.predicate.permanent.TokenPredicate;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
import mage.target.common.TargetNonlandPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author alexander-novo
|
||||
*/
|
||||
public final class PrestonTheVanisher extends CardImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent triggerFilter = new FilterControlledCreaturePermanent(
|
||||
"another nontoken creature");
|
||||
private static final FilterControlledPermanent activeCostFilter = new FilterControlledCreaturePermanent(
|
||||
SubType.ILLUSION, "Illusions");
|
||||
|
||||
static {
|
||||
triggerFilter.add(TokenPredicate.FALSE);
|
||||
triggerFilter.add(AnotherPredicate.instance);
|
||||
}
|
||||
|
||||
public PrestonTheVanisher(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{3}{W}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.RABBIT);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(5);
|
||||
|
||||
// Whenever another nontoken creature enters the battlefield under your control,
|
||||
// if it wasn’t cast, create a token that’s a copy of that creature, except it’s
|
||||
// a 0/1 white Illusion.
|
||||
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(
|
||||
null, null, false, 1, false, false,
|
||||
null, 0, 1, false);
|
||||
effect.setOnlyColor(ObjectColor.WHITE);
|
||||
effect.setOnlySubType(SubType.ILLUSION);
|
||||
effect.setText("create a token that's a copy of that creature, except it's a 0/1 white Illusion");
|
||||
this.addAbility(
|
||||
new EntersBattlefieldCastTriggeredAbility(Zone.BATTLEFIELD, effect, triggerFilter, false, false,
|
||||
SetTargetPointer.PERMANENT, null,
|
||||
true));
|
||||
|
||||
// {1}{W}, Sacrifice five Illusions: Exile target nonland permanent.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(),
|
||||
new ManaCostsImpl<>("{1}{W}"));
|
||||
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(5, activeCostFilter)));
|
||||
ability.addTarget(new TargetNonlandPermanent());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private PrestonTheVanisher(final PrestonTheVanisher card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrestonTheVanisher copy() {
|
||||
return new PrestonTheVanisher(this);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ import mage.game.events.EntersTheBattlefieldEvent;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.Watcher;
|
||||
import mage.watchers.common.CreatureWasCastWatcher;
|
||||
import mage.watchers.common.PermanentWasCastWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -29,7 +29,7 @@ public final class UphillBattle extends CardImpl {
|
|||
|
||||
// Creatures played by your opponents enter the battlefield tapped.
|
||||
Ability tapAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new UphillBattleTapEffect());
|
||||
tapAbility.addWatcher(new CreatureWasCastWatcher());
|
||||
tapAbility.addWatcher(new PermanentWasCastWatcher());
|
||||
tapAbility.addWatcher(new PlayCreatureLandWatcher());
|
||||
addAbility(tapAbility);
|
||||
}
|
||||
|
@ -97,11 +97,11 @@ class UphillBattleTapEffect extends ReplacementEffectImpl {
|
|||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent target = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
CreatureWasCastWatcher creatureSpellWatcher = game.getState().getWatcher(CreatureWasCastWatcher.class);
|
||||
PermanentWasCastWatcher creatureSpellWatcher = game.getState().getWatcher(PermanentWasCastWatcher.class);
|
||||
PlayCreatureLandWatcher landWatcher = game.getState().getWatcher(PlayCreatureLandWatcher.class);
|
||||
|
||||
if (target != null
|
||||
&& ((creatureSpellWatcher != null && creatureSpellWatcher.wasCreatureCastThisTurn(target.getId()))
|
||||
&& ((creatureSpellWatcher != null && creatureSpellWatcher.wasPermanentCastThisTurn(target.getId()))
|
||||
|| (landWatcher != null && landWatcher.wasLandPlayed(target.getId())))) {
|
||||
target.setTapped(true);
|
||||
}
|
||||
|
|
|
@ -557,6 +557,7 @@ public final class Jumpstart2022 extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Preordain", 63, Rarity.COMMON, mage.cards.p.Preordain.class));
|
||||
cards.add(new SetCardInfo("Presence of Gond", 709, Rarity.COMMON, mage.cards.p.PresenceOfGond.class));
|
||||
cards.add(new SetCardInfo("Press for Answers", 337, Rarity.COMMON, mage.cards.p.PressForAnswers.class));
|
||||
cards.add(new SetCardInfo("Preston, the Vanisher", 8, Rarity.RARE, mage.cards.p.PrestonTheVanisher.class));
|
||||
cards.add(new SetCardInfo("Prey Upon", 710, Rarity.COMMON, mage.cards.p.PreyUpon.class));
|
||||
cards.add(new SetCardInfo("Prickly Marmoset", 580, Rarity.COMMON, mage.cards.p.PricklyMarmoset.class));
|
||||
cards.add(new SetCardInfo("Pridemalkin", 711, Rarity.COMMON, mage.cards.p.Pridemalkin.class));
|
||||
|
|
|
@ -109,7 +109,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return super.getRule();
|
||||
}
|
||||
|
||||
private String generateTriggerPhrase() {
|
||||
protected String generateTriggerPhrase() {
|
||||
StringBuilder sb = new StringBuilder("Whenever ");
|
||||
if (thisOrAnother) {
|
||||
sb.append("{this} or another ");
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.watchers.common.PermanentWasCastWatcher;
|
||||
|
||||
/**
|
||||
* An extension of triggered abilities that trigger when permanents enter the
|
||||
* battlefield, but this time they either must be cast or must not be cast.
|
||||
*
|
||||
* @author alexander-novo
|
||||
*/
|
||||
public class EntersBattlefieldCastTriggeredAbility extends EntersBattlefieldAllTriggeredAbility {
|
||||
private final boolean mustCast;
|
||||
|
||||
/**
|
||||
* zone = BATTLEFIELD optional = false
|
||||
*
|
||||
* @param effect
|
||||
* @param filter
|
||||
*/
|
||||
public EntersBattlefieldCastTriggeredAbility(Effect effect, FilterPermanent filter, boolean mustCast) {
|
||||
this(Zone.BATTLEFIELD, effect, filter, mustCast, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(Effect effect, FilterPermanent filter, boolean mustCast, String rule) {
|
||||
this(Zone.BATTLEFIELD, effect, filter, mustCast, false, rule);
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean mustCast,
|
||||
boolean optional) {
|
||||
this(zone, effect, filter, mustCast, optional, SetTargetPointer.NONE, null, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean mustCast,
|
||||
boolean optional,
|
||||
String rule) {
|
||||
this(zone, effect, filter, mustCast, optional, rule, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean mustCast,
|
||||
boolean optional,
|
||||
String rule, boolean controlledText) {
|
||||
this(zone, effect, filter, mustCast, optional, SetTargetPointer.NONE, rule, controlledText);
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean mustCast,
|
||||
boolean optional,
|
||||
SetTargetPointer setTargetPointer, String rule) {
|
||||
this(zone, effect, filter, mustCast, optional, setTargetPointer, rule, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean mustCast,
|
||||
boolean optional,
|
||||
SetTargetPointer setTargetPointer, String rule, boolean controlledText) {
|
||||
this(zone, effect, filter, mustCast, optional, setTargetPointer, rule, controlledText, false);
|
||||
}
|
||||
|
||||
protected EntersBattlefieldCastTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean mustCast,
|
||||
boolean optional,
|
||||
SetTargetPointer setTargetPointer, String rule, boolean controlledText, boolean thisOrAnother) {
|
||||
super(zone, effect, filter, optional, setTargetPointer, rule, controlledText, thisOrAnother);
|
||||
|
||||
this.mustCast = mustCast;
|
||||
this.addWatcher(new PermanentWasCastWatcher());
|
||||
|
||||
StringBuilder triggerPhrase = new StringBuilder(this.generateTriggerPhrase());
|
||||
if (mustCast) {
|
||||
triggerPhrase.append("if it was cast, ");
|
||||
} else {
|
||||
triggerPhrase.append("if it wasn't cast, ");
|
||||
}
|
||||
this.setTriggerPhrase(triggerPhrase.toString());
|
||||
}
|
||||
|
||||
public EntersBattlefieldCastTriggeredAbility(final EntersBattlefieldCastTriggeredAbility ability) {
|
||||
super(ability);
|
||||
|
||||
this.mustCast = ability.mustCast;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!super.checkTrigger(event, game))
|
||||
return false;
|
||||
|
||||
PermanentWasCastWatcher watcher = game.getState().getWatcher(PermanentWasCastWatcher.class);
|
||||
UUID targetId = event.getTargetId();
|
||||
|
||||
return watcher.wasPermanentCastThisTurn(targetId) == this.mustCast;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntersBattlefieldCastTriggeredAbility copy() {
|
||||
return new EntersBattlefieldCastTriggeredAbility(this);
|
||||
}
|
||||
}
|
|
@ -17,11 +17,11 @@ import mage.watchers.Watcher;
|
|||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CreatureWasCastWatcher extends Watcher {
|
||||
public class PermanentWasCastWatcher extends Watcher {
|
||||
|
||||
private final Set<UUID> creaturesCasted = new HashSet<>();
|
||||
private final Set<UUID> permanentsCasted = new HashSet<>();
|
||||
|
||||
public CreatureWasCastWatcher() {
|
||||
public PermanentWasCastWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
|
@ -31,27 +31,27 @@ public class CreatureWasCastWatcher extends Watcher {
|
|||
Spell spell = (Spell) game.getObject(event.getTargetId());
|
||||
if (spell != null) {
|
||||
Card card = game.getCard(spell.getSourceId());
|
||||
if (card != null && card.isCreature(game)) {
|
||||
creaturesCasted.add(card.getId());
|
||||
if (card != null && card.isPermanent(game)) {
|
||||
permanentsCasted.add(card.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.getType() == GameEvent.EventType.ZONE_CHANGE
|
||||
&& ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isCreature(game)) {
|
||||
creaturesCasted.remove(card.getId());
|
||||
if (card != null && card.isPermanent(game)) {
|
||||
permanentsCasted.remove(card.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean wasCreatureCastThisTurn(UUID creatureSourceId) {
|
||||
return creaturesCasted.contains(creatureSourceId);
|
||||
public boolean wasPermanentCastThisTurn(UUID permanentSourceId) {
|
||||
return permanentsCasted.contains(permanentSourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
creaturesCasted.clear();
|
||||
permanentsCasted.clear();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue