From d19ca838cace79945b3c06ad6027f6d92cf966f6 Mon Sep 17 00:00:00 2001 From: L_J Date: Thu, 7 Jun 2018 05:37:22 +0200 Subject: [PATCH] Implemented castability check for Word of Command --- Mage.Sets/src/mage/cards/w/WordOfCommand.java | 74 ++++++++++++++++++- .../abilities/costs/mana/ManaCostsImpl.java | 5 ++ .../abilities/effects/ContinuousEffects.java | 2 +- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/cards/w/WordOfCommand.java b/Mage.Sets/src/mage/cards/w/WordOfCommand.java index 54c3a66c79f..dc744bda24b 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfCommand.java +++ b/Mage.Sets/src/mage/cards/w/WordOfCommand.java @@ -4,17 +4,23 @@ import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffect; +import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.ManaPool; @@ -99,10 +105,43 @@ class WordOfCommandEffect extends OneShotEffect { manaPool.storeMana(); int bookmark = game.bookmarkState(); - if ((card.isLand() && (!targetPlayer.canPlayLand() || !game.getActivePlayerId().equals(targetPlayer.getId()))) - || !targetPlayer.playCard(card, game, false, true, new MageObjectReference(source.getSourceObject(game), game))) { - // TODO: needs an automatic check for whether the card is castable (so it can't be cancelled if that's the case) - game.informPlayers(targetPlayer.getLogName() + " didn't play " + card.getLogName()); + // check for card playability (Word of Command allows the chosen card to be played "as if it had flash" so we need to invoke such effect to bypass the check) + boolean canPlay = false; + if (card.isLand()) { // we can't use getPlayableInHand(game) in here because it disallows playing lands outside the main step + if (targetPlayer.canPlayLand() + && game.getActivePlayerId().equals(targetPlayer.getId())) { + canPlay = true; + for (Ability ability : card.getAbilities(game)) { + if (!game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), targetPlayer.getId()), ability, game, true)) { + canPlay &= true; + } + } + } + } else { + AsThoughEffectImpl effect2 = new WordOfCommandTestFlashEffect(); + game.addEffect(effect2, source); + if (targetPlayer.getPlayableInHand(game).contains(card.getId())) { + canPlay = true; + } + for (AsThoughEffect eff : game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.CAST_AS_INSTANT, game)) { + if (eff instanceof WordOfCommandTestFlashEffect) { + eff.discard(); + break; + } + } + } + + if (canPlay) { + while (!targetPlayer.playCard(card, game, false, true, new MageObjectReference(source.getSourceObject(game), game))) { + SpellAbility spellAbility = card.getSpellAbility(); + if (spellAbility != null) { + ((ManaCostsImpl) spellAbility.getManaCosts()).forceManaRollback(game, manaPool); // force rollback if card was deemed playable + } else { + break; + } + } + } else { + game.informPlayers(targetPlayer.getLogName() + " didn't play " + card.getLogName() + (canPlay ? "" : " (card can't be played)")); } manaPool.setForcedToPay(false); // duplicate in case of a new mana pool existing - probably not necessary, but just in case @@ -114,6 +153,7 @@ class WordOfCommandEffect extends OneShotEffect { for (RestrictionEffect eff : game.getContinuousEffects().getRestrictionEffects()) { if (eff instanceof WordOfCommandCantActivateEffect) { eff.discard(); + break; } } game.getContinuousEffects().removeInactiveEffects(game); @@ -161,3 +201,29 @@ class WordOfCommandCantActivateEffect extends RestrictionEffect { return false; } } + +class WordOfCommandTestFlashEffect extends AsThoughEffectImpl { + + public WordOfCommandTestFlashEffect() { + super(AsThoughEffectType.CAST_AS_INSTANT, Duration.EndOfTurn, Outcome.Benefit); + } + + public WordOfCommandTestFlashEffect(final WordOfCommandTestFlashEffect effect) { + super(effect); + } + + @Override + public WordOfCommandTestFlashEffect copy() { + return new WordOfCommandTestFlashEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID affectedSpellId, Ability source, UUID affectedControllerId, Game game) { + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java index 73739a43484..7aa19583676 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java @@ -346,6 +346,11 @@ public class ManaCostsImpl extends ArrayList implements M } } + public void forceManaRollback(Game game, ManaPool pool) { + // for Word of Command + handleForcedToPayOnlyForCurrentPayment(game, pool, this); + } + @Override public final void load(String mana) { this.clear(); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 7c170cc5f6a..54fe6c7c744 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -543,7 +543,7 @@ public class ContinuousEffects implements Serializable { * @param game * @return */ - private List getApplicableAsThoughEffects(AsThoughEffectType type, Game game) { + public List getApplicableAsThoughEffects(AsThoughEffectType type, Game game) { List asThoughEffectsList = new ArrayList<>(); if (asThoughEffectsMap.containsKey(type)) { for (AsThoughEffect effect : asThoughEffectsMap.get(type)) {