Cloud Key - fixed that it doesn't allow to cast cards without full mana available (#6698);

This commit is contained in:
Oleg Agafonov 2020-07-05 19:39:05 +04:00
parent 74ceac7322
commit f9a9a55f7b
6 changed files with 87 additions and 211 deletions

View file

@ -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

View file

@ -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;
}
}

View file

@ -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)));

View file

@ -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);
}
}

View file

@ -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<CardType> 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<CardType> 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

View file

@ -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<CardType> 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";
}