diff --git a/Mage.Sets/src/mage/cards/f/FullBore.java b/Mage.Sets/src/mage/cards/f/FullBore.java index 77b88483b32..d29a26cfc1d 100644 --- a/Mage.Sets/src/mage/cards/f/FullBore.java +++ b/Mage.Sets/src/mage/cards/f/FullBore.java @@ -1,6 +1,5 @@ package mage.cards.f; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -17,7 +16,6 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import java.util.Collections; import java.util.UUID; /** @@ -63,11 +61,7 @@ class FullBoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null - || !game - .getPermanentCostsTags() - .getOrDefault(new MageObjectReference(permanent, game, -1), Collections.emptyMap()) - .containsKey(WarpAbility.WARP_ACTIVATION_VALUE_KEY)) { + if (permanent == null || !WarpAbility.checkIfPermanentWarped(permanent, game)) { return false; } game.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()) diff --git a/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java b/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java index f3de58b05e7..10b18f10d98 100644 --- a/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java @@ -1,6 +1,7 @@ package mage.abilities.keyword; import mage.MageIdentifier; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -10,14 +11,33 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.*; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import mage.watchers.Watcher; +import java.util.Collections; import java.util.Set; import java.util.UUID; /** + * 702.185. Warp + *

+ * 702.185a Warp represents two static abilities that function while the card with warp is on the stack, + * one of which may create a delayed triggered ability. “Warp [cost]” means + * “You may cast this card from your hand by paying [cost] rather than its mana cost” and + * “If this spell’s warp cost was paid, exile the permanent this spell becomes at the beginning of the next end step. + * Its owner may cast this card after the current turn has ended for as long as it remains exiled.” + * Casting a spell for its warp cost follows the rules for paying alternative costs in rules 601.2b and 601.2f–h. + *

+ * 702.185b Some effects refer to “warped” cards in exile. A warped card in exile is one + * that was exiled by the delayed triggered ability created by a warp ability. + *

+ * 702.185c Some effects refer to whether “a spell was warped this turn.” + * This means that a spell was cast for its warp cost this turn. + * * @author TheElk801 */ public class WarpAbility extends SpellAbility { @@ -41,6 +61,7 @@ public class WarpAbility extends SpellAbility { this.addCost(new ManaCostsImpl<>(manaString)); this.setAdditionalCostsRuleVisible(false); this.allowGraveyard = allowGraveyard; + this.addWatcher(new WarpAbilityWatcher()); } private WarpAbility(final WarpAbility ability) { @@ -48,15 +69,6 @@ public class WarpAbility extends SpellAbility { this.allowGraveyard = ability.allowGraveyard; } - // The ability sets up a delayed trigger which can't be set up using the cost tag system - public static void addDelayedTrigger(SpellAbility spellAbility, Game game) { - if (spellAbility instanceof WarpAbility) { - game.addDelayedTriggeredAbility( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new WarpExileEffect()), spellAbility - ); - } - } - @Override public ActivationStatus canActivate(UUID playerId, Game game) { switch (game.getState().getZone(getSourceId())) { @@ -104,6 +116,13 @@ public class WarpAbility extends SpellAbility { public static String makeWarpString(UUID playerId) { return playerId + "- Warped"; } + + public static boolean checkIfPermanentWarped(Permanent permanent, Game game) { + return permanent != null + && game.getPermanentCostsTags() + .getOrDefault(new MageObjectReference(permanent, game, -1), Collections.emptyMap()) + .containsKey(WarpAbility.WARP_ACTIVATION_VALUE_KEY); + } } class WarpExileEffect extends OneShotEffect { @@ -122,8 +141,9 @@ class WarpExileEffect extends OneShotEffect { } } - WarpExileEffect() { + WarpExileEffect(Permanent permanent, Game game) { super(Outcome.Benefit); + this.setTargetPointer(new FixedTarget(permanent, game)); staticText = "exile this creature if it was cast for its warp cost"; } @@ -138,9 +158,12 @@ class WarpExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null || permanent.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter() + 1) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getOwnerId()); + if (player == null) { return false; } player.moveCardsToExile( @@ -155,3 +178,23 @@ class WarpExileEffect extends OneShotEffect { return true; } } + +class WarpAbilityWatcher extends Watcher { + + WarpAbilityWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + return; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + if (WarpAbility.checkIfPermanentWarped(permanent, game)) { + game.addDelayedTriggeredAbility( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new WarpExileEffect(permanent, game)), permanent.getSpellAbility() + ); + } + } +} diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 70e66ba58ce..7cc905df6b6 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -8,7 +8,6 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.PrototypeAbility; import mage.abilities.keyword.TransformAbility; -import mage.abilities.keyword.WarpAbility; import mage.cards.*; import mage.constants.*; import mage.counters.Counter; @@ -422,7 +421,6 @@ public class Spell extends StackObjectImpl implements Card { } else { MageObjectReference mor = new MageObjectReference(getSpellAbility()); game.storePermanentCostsTags(mor, getSpellAbility()); - WarpAbility.addDelayedTrigger(getSpellAbility(), game); return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } }