diff --git a/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java b/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java index 782302bb39..35badc4c43 100644 --- a/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java +++ b/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java @@ -1,27 +1,22 @@ - package mage.cards.a; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCardTypeEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.choices.ChoiceImpl; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; +import java.util.Arrays; import java.util.UUID; /** @@ -46,7 +41,10 @@ public final class ArchonOfValorsReach extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // As Archon of Valor's Reach enters the battlefield, choose artifact, enchantment, instant, sorcery, or planeswalker. - this.addAbility(new AsEntersBattlefieldAbility(new ArchonOfValorsReachChooseEffect())); + this.addAbility(new AsEntersBattlefieldAbility( + new ChooseCardTypeEffect(Outcome.Benefit, Arrays.asList(CardType.ARTIFACT, CardType.ENCHANTMENT, CardType.INSTANT, CardType.PLANESWALKER)) + .setText("choose artifact, enchantment, instant, sorcery, or planeswalker") + )); // Players can't cast spells of the chosen type. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ArchonOfValorsReachReplacementEffect())); @@ -62,85 +60,6 @@ public final class ArchonOfValorsReach extends CardImpl { } } -class ArchonOfValorsReachChooseEffect extends OneShotEffect { - - ArchonOfValorsReachChooseEffect() { - super(Outcome.Benefit); - this.staticText = "choose artifact, enchantment, instant, sorcery, or planeswalker"; - } - - private ArchonOfValorsReachChooseEffect(final ArchonOfValorsReachChooseEffect effect) { - super(effect); - } - - @Override - public ArchonOfValorsReachChooseEffect copy() { - return new ArchonOfValorsReachChooseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getPermanentEntering(source.getSourceId()); - if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); - } - if (controller != null && mageObject != null) { - ArchonOfValorsReachChoice choices = new ArchonOfValorsReachChoice(); - if (controller.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(mageObject.getName() + ": Chosen card type is " + choices.getChoice()); - System.out.println(mageObject.getId()); - game.getState().setValue(mageObject.getId().toString() + "_cardtype", choices.getChoice()); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen card type: " + choices.getChoice()), game); - } - return true; - } - } - return false; - } -} - -class ArchonOfValorsReachChoice extends ChoiceImpl { - - ArchonOfValorsReachChoice() { - super(true); - this.choices.add("Artifact"); - this.choices.add("Enchantment"); - this.choices.add("Instant"); - this.choices.add("Sorcery"); - this.choices.add("Planeswalker"); - this.message = "Choose artifact, enchantment, instant, sorcery, or planeswalker"; - } - - private ArchonOfValorsReachChoice(final ArchonOfValorsReachChoice choice) { - super(choice); - } - - public static CardType getType(String ch) { - switch (ch) { - case "Artifact": - return CardType.ARTIFACT; - case "Enchantment": - return CardType.ENCHANTMENT; - case "Instant": - return CardType.INSTANT; - case "Sorcery": - return CardType.SORCERY; - case "Planeswalker": - return CardType.PLANESWALKER; - default: - return null; - } - } - - @Override - public ArchonOfValorsReachChoice copy() { - return new ArchonOfValorsReachChoice(this); - } - -} - class ArchonOfValorsReachReplacementEffect extends ContinuousRuleModifyingEffectImpl { ArchonOfValorsReachReplacementEffect() { @@ -154,10 +73,11 @@ class ArchonOfValorsReachReplacementEffect extends ContinuousRuleModifyingEffect @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - CardType cardType = (CardType) game.getState().getValue(source.getSourceId().toString() + "_cardtype"); - MageObject mageObject = game.getObject(source.getSourceId()); - if (mageObject != null && cardType != null) { - return "You can't cast " + cardType.toString() + " spells (" + mageObject.getIdName() + ")."; + Object savedType = game.getState().getValue(source.getSourceId() + "_type"); + Card sourceCard = game.getCard(source.getSourceId()); + if (savedType instanceof String && sourceCard != null) { + CardType cardType = CardType.fromString((String) savedType); + return "You can't cast " + cardType.toString() + " spells (" + sourceCard.getIdName() + ")."; } return null; } @@ -169,15 +89,13 @@ class ArchonOfValorsReachReplacementEffect extends ContinuousRuleModifyingEffect @Override public boolean applies(GameEvent event, Ability source, Game game) { - - if ((String) game.getState().getValue(source.getSourceId().toString() + "_cardtype") == null){ - return false; + Object savedType = game.getState().getValue(source.getSourceId() + "_type"); + Card sourceCard = game.getCard(source.getSourceId()); + if (savedType instanceof String && sourceCard != null) { + CardType cardType = CardType.fromString((String) savedType); + return cardType != null && sourceCard != null && sourceCard.getCardType().contains(cardType); } - - CardType cardType = ArchonOfValorsReachChoice.getType((String) game.getState().getValue(source.getSourceId().toString() + "_cardtype")); - // spell is not on the stack yet, so we have to check the card - Card card = game.getCard(event.getSourceId()); - return cardType != null && card != null && card.getCardType().contains(cardType); + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/c/CloudKey.java b/Mage.Sets/src/mage/cards/c/CloudKey.java index 78d18090cf..ef63d2a9f7 100644 --- a/Mage.Sets/src/mage/cards/c/CloudKey.java +++ b/Mage.Sets/src/mage/cards/c/CloudKey.java @@ -1,42 +1,37 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.cards.c; -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.ChooseCardTypeEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionAllOfChosenCardTypeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.choices.ChoiceImpl; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.players.Player; -import mage.util.CardUtil; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; + +import java.util.Arrays; +import java.util.UUID; /** - * * @author nick.myers */ public final class CloudKey extends CardImpl { public CloudKey(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // As Cloud Key enters the battlefield, choose artifact, creature, enchantment, instant, or sorcery. - this.addAbility(new AsEntersBattlefieldAbility(new CloudKeyChooseTypeEffect())); + this.addAbility(new AsEntersBattlefieldAbility( + new ChooseCardTypeEffect(Outcome.Benefit, Arrays.asList(CardType.ARTIFACT, CardType.CREATURE, CardType.ENCHANTMENT, CardType.INSTANT, CardType.SORCERY)) + .setText("choose artifact, creature, enchantment, instant, or sorcery") + )); // Spells you cast of the chosen type cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CloudKeyCostModificationEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostReductionAllOfChosenCardTypeEffect(new FilterCard("Spells you cast of the chosen type"), 1, true) + )); } @Override @@ -48,84 +43,3 @@ public final class CloudKey extends CardImpl { super(card); } } - -class CloudKeyChooseTypeEffect extends OneShotEffect { - - public CloudKeyChooseTypeEffect() { - super(Outcome.Neutral); - this.staticText = "choose artifact, creature, enchantment, instant, or sorcery."; - } - - public CloudKeyChooseTypeEffect(final CloudKeyChooseTypeEffect effect) { - super(effect); - } - - @Override - public CloudKeyChooseTypeEffect copy() { - return new CloudKeyChooseTypeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getPermanentEntering(source.getSourceId()); - if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); - } - if (mageObject != null && controller != null) { - ChoiceImpl choices = new ChoiceImpl(true); - choices.setMessage("Choose a spell type"); - choices.getChoices().add(CardType.ARTIFACT.toString()); - choices.getChoices().add(CardType.CREATURE.toString()); - choices.getChoices().add(CardType.ENCHANTMENT.toString()); - choices.getChoices().add(CardType.INSTANT.toString()); - choices.getChoices().add(CardType.SORCERY.toString()); - if (controller.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(mageObject.getLogName() + ": chosen spell type is " + choices.getChoice()); - game.getState().setValue(source.getSourceId().toString() + "_CloudKey", choices.getChoice()); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosenCardType", CardUtil.addToolTipMarkTags("Chosen card type: " + choices.getChoice()), game); - } - return true; - } - } - return false; - } - -} - -class CloudKeyCostModificationEffect extends CostModificationEffectImpl { - - public CloudKeyCostModificationEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - this.staticText = "Spells you cast of the chosen type cost {1} less to cast"; - } - - public CloudKeyCostModificationEffect(final CloudKeyCostModificationEffect effect) { - super(effect); - } - - @Override - public CloudKeyCostModificationEffect copy() { - return new CloudKeyCostModificationEffect(this); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, 1); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility && abilityToModify.isControlledBy(source.getControllerId())) { - Spell spell = game.getStack().getSpell(abilityToModify.getSourceId()); - if (spell != null && spell.getCardType().toString().contains((String) game.getState().getValue(source.getSourceId().toString() + "_CloudKey"))) { - return true; - } - } - - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HelmOfAwakening.java b/Mage.Sets/src/mage/cards/h/HelmOfAwakening.java index a9192b1bbb..1f0f9f4659 100644 --- a/Mage.Sets/src/mage/cards/h/HelmOfAwakening.java +++ b/Mage.Sets/src/mage/cards/h/HelmOfAwakening.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; import mage.cards.CardImpl; @@ -9,15 +7,15 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HelmOfAwakening extends CardImpl { - public HelmOfAwakening(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Spells cost {1} less to cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionAllEffect(1))); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostReduceForEachTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostReduceForEachTest.java index ef5ad19477..7d7e7be62d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostReduceForEachTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostReduceForEachTest.java @@ -213,4 +213,35 @@ public class CostReduceForEachTest extends CardTestPlayerBaseWithAIHelps { assertPermanentCount(playerA, "Balduvian Bears", 1); } + + @Test + public void test_CloudKey_ChooseCardTypeForCostReduce() { + // {3} + // As Cloud Key enters the battlefield, choose artifact, creature, enchantment, instant, or sorcery. + // Spells you cast of the chosen type cost {1} less to cast. + addCard(Zone.HAND, playerA, "Cloud Key", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + // + addCard(Zone.HAND, playerA, "Balduvian Bears", 1); // {1}{G} + addCard(Zone.HAND, playerA, "Forest", 1); + + // prepare cloud key to reduce + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloud Key"); + setChoice(playerA, "Creature"); + + // prepare lands + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPlayableAbility("can't with no mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Balduvian Bears", false); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); + checkPlayableAbility("can play with mana and reduce", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Balduvian Bears", true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Balduvian Bears", 1); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java index 6041004401..52d0b8e466 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java @@ -5,24 +5,38 @@ import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.choices.Choice; import mage.choices.ChoiceCardType; +import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + /** * @author emerald000 */ public class ChooseCardTypeEffect extends OneShotEffect { + List cardTypes = Arrays.stream(CardType.values()).collect(Collectors.toList()); + public ChooseCardTypeEffect(Outcome outcome) { + this(outcome, Arrays.stream(CardType.values()).collect(Collectors.toList())); + } + + public ChooseCardTypeEffect(Outcome outcome, List cardTypes) { super(outcome); - staticText = "choose a card type"; + this.staticText = "choose a card type"; + this.cardTypes = new ArrayList<>(cardTypes); } private ChooseCardTypeEffect(final ChooseCardTypeEffect effect) { super(effect); + this.cardTypes = new ArrayList<>(effect.cardTypes); } @Override diff --git a/Mage/src/main/java/mage/choices/ChoiceCardType.java b/Mage/src/main/java/mage/choices/ChoiceCardType.java index 45463124c4..40c752c58e 100644 --- a/Mage/src/main/java/mage/choices/ChoiceCardType.java +++ b/Mage/src/main/java/mage/choices/ChoiceCardType.java @@ -3,6 +3,7 @@ package mage.choices; import mage.constants.CardType; import java.util.Arrays; +import java.util.List; import java.util.stream.Collectors; /** @@ -11,12 +12,12 @@ import java.util.stream.Collectors; public class ChoiceCardType extends ChoiceImpl { public ChoiceCardType() { - this(true); + this(true, Arrays.stream(CardType.values()).collect(Collectors.toList())); } - public ChoiceCardType(boolean required) { + public ChoiceCardType(boolean required, List cardTypes) { super(required); - this.choices.addAll(Arrays.stream(CardType.values()).map(CardType::toString).collect(Collectors.toList())); + this.choices.addAll(cardTypes.stream().map(CardType::toString).collect(Collectors.toList())); this.message = "Choose a card type"; }