diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DelveTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DelveTest.java new file mode 100644 index 00000000000..fe9a4533824 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DelveTest.java @@ -0,0 +1,84 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; + +/** + * @author JayDi85 + */ + +public class DelveTest extends CardTestPlayerBaseWithAIHelps { + + // no simple playable tests for delve, it's same as ConvokeTest + + @Test + public void test_PlayDelve_Manual() { + // {4}{U}{U} creature + // Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) + addCard(Zone.HAND, playerA, "Ethereal Forager", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.GRAVEYARD, playerA, "Balduvian Bears", 4); // delve pay + + // use special action to pay (need disabled auto-payment and prepared mana pool) + disableManaAutoPayment(playerA); + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 2); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ethereal Forager"); + setChoice(playerA, "Blue"); // pay 1 + setChoice(playerA, "Blue"); // pay 2 + // delve can be payed in test only by one card + setChoice(playerA, "Exile cards"); + setChoice(playerA, "Balduvian Bears"); // pay 3 as delve + setChoice(playerA, "Exile cards"); + setChoice(playerA, "Balduvian Bears"); // pay 4 as delve + setChoice(playerA, "Exile cards"); + setChoice(playerA, "Balduvian Bears"); // pay 5 as delve + setChoice(playerA, "Exile cards"); + setChoice(playerA, "Balduvian Bears"); // pay 6 as delve + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Ethereal Forager", 1); + } + + @Test + public void test_PlayDelve_AI_AutoPay() { + // {4}{U}{U} creature + // Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) + addCard(Zone.HAND, playerA, "Ethereal Forager", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.GRAVEYARD, playerA, "Balduvian Bears", 4); // delve pay + + // AI must use special actions to pay as delve + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ethereal Forager"); + + //setStrictChooseMode(true); AI must choose targets + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Ethereal Forager", 1); + } + + @Test + public void test_PlayDelve_AI_FullPlay() { + // {4}{U}{U} creature + // Delve (Each card you exile from your graveyard while casting this spell pays for {1}.) + addCard(Zone.HAND, playerA, "Ethereal Forager", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.GRAVEYARD, playerA, "Balduvian Bears", 4); // delve pay + + aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Ethereal Forager", 1); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java index 2855262cdb0..6f8002ed78e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java @@ -5,9 +5,14 @@ import mage.abilities.Ability; import mage.abilities.SpecialAction; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.mana.ActivationManaAbilityStep; import mage.abilities.costs.mana.AlternateManaPaymentAbility; import mage.abilities.costs.mana.ManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.ValueHint; +import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; @@ -17,6 +22,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; +import mage.game.stack.Spell; import mage.players.ManaPool; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -25,35 +31,42 @@ import mage.util.CardUtil; import java.util.List; /** - * 702.65. Delve 702.65a Delve is a static ability that functions while the - * spell with delve is on the stack. “Delve” means “For each generic mana in - * this spell's total cost, you may exile a card from your graveyard rather than - * pay that mana.” The delve ability isn't an additional or alternative cost and - * applies only after the total cost of the spell with delve is determined. - * 702.65b Multiple instances of delve on the same spell are redundant. + * 702.65. Delve *
- * The rules for delve have changed slightly since it was last in an expansion. - * Previously, delve reduced the cost to cast a spell. Under the current rules, - * you exile cards from your graveyard at the same time you pay the spell's - * cost. Exiling a card this way is simply another way to pay that cost. * Delve - * doesn't change a spell's mana cost or converted mana cost. For example, Dead - * Drop's converted mana cost is 10 even if you exiled three cards to cast it. * - * You can't exile cards to pay for the colored mana requirements of a spell - * with delve. * You can't exile more cards than the generic mana requirement of - * a spell with delve. For example, you can't exile more than nine cards from - * your graveyard to cast Dead Drop. * Because delve isn't an alternative cost, - * it can be used in conjunction with alternative costs. + * 702.65a Delve is a static ability that functions while the spell with delve is on the stack. “Delve” means “For + * each generic mana in this spell’s total cost, you may exile a card from your graveyard rather than pay that mana.” + *
+ * 702.65b The delve ability isn’t an additional or alternative cost and applies only after the total cost of the spell + * with delve is determined. + *
+ * 702.65c Multiple instances of delve on the same spell are redundant. + *
+ * The rules for delve have changed slightly since it was last in an expansion. Previously, delve reduced the cost + * to cast a spell. Under the current rules, you exile cards from your graveyard at the same time you pay the spell’s + * cost. Exiling a card this way is simply another way to pay that cost. (This is similar to the change made to + * convoke for the Magic 2015 Core Set.) + *
+ * You can’t exile cards to pay for the colored mana requirements of a spell with delve. + *
+ * You can’t exile more cards than the generic mana requirement of a spell with delve. For example, you can’t exile more + * than nine cards from your graveyard to cast Dead Drop. + *
+ * Because delve isn’t an alternative cost, it can be used in conjunction with alternative costs. * - * @author LevelX2 + * @author LevelX2, JayDi85 *
* TODO: Change card exiling to a way to pay mana costs, now it's maybe not
* possible to pay costs from effects that increase the mana costs.
+ * If it real bug then possible fix: choose cards on apply like convoke and improvise, not as cost
*/
public class DelveAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility {
+ private static final DynamicValue cardsInGraveyard = new CardsInControllerGraveyardCount();
+
public DelveAbility() {
- super(Zone.STACK, null);
+ super(Zone.ALL, null);
this.setRuleAtTheTop(true);
+ this.addHint(new ValueHint("Cards in your graveyard", cardsInGraveyard));
}
public DelveAbility(final DelveAbility ability) {
@@ -70,12 +83,17 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa
return "Delve (Each card you exile from your graveyard while casting this spell pays for {1}.)";
}
+ @Override
+ public ActivationManaAbilityStep useOnActivationManaAbilityStep() {
+ return ActivationManaAbilityStep.AFTER;
+ }
+
@Override
public void addSpecialAction(Ability source, Game game, ManaCost unpaid) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && !controller.getGraveyard().isEmpty()) {
- if (unpaid.getMana().getGeneric() > 0 && source.getAbilityType() == AbilityType.SPELL) {
- SpecialAction specialAction = new DelveSpecialAction();
+ if (source.getAbilityType() == AbilityType.SPELL && unpaid.getMana().getGeneric() > 0) {
+ SpecialAction specialAction = new DelveSpecialAction(this);
specialAction.setControllerId(source.getControllerId());
specialAction.setSourceId(source.getSourceId());
int unpaidAmount = unpaid.getMana().getGeneric();
@@ -84,19 +102,30 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa
}
specialAction.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(
0, Math.min(controller.getGraveyard().size(), unpaidAmount),
- new FilterCard("cards to exile for delve's pay from your graveyard"), true)));
+ new FilterCard("cards from your graveyard"), true)));
if (specialAction.canActivate(source.getControllerId(), game).canActivate()) {
game.getState().getSpecialActions().add(specialAction);
}
}
}
}
+
+ @Override
+ public ManaOptions getManaOptions(Ability source, Game game, ManaCost unpaid) {
+ ManaOptions options = new ManaOptions();
+ Player controller = game.getPlayer(source.getControllerId());
+ int graveCount = cardsInGraveyard.calculate(game, source, null);
+ if (controller != null && graveCount > 0) {
+ options.addMana(Mana.GenericMana(Math.min(unpaid.getMana().getGeneric(), graveCount)));
+ }
+ return options;
+ }
}
class DelveSpecialAction extends SpecialAction {
- public DelveSpecialAction() {
- super(Zone.ALL, true);
+ public DelveSpecialAction(AlternateManaPaymentAbility manaAbility) {
+ super(Zone.ALL, manaAbility);
this.addEffect(new DelveEffect());
}
@@ -129,9 +158,9 @@ class DelveEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
- if (controller != null) {
+ Spell spell = game.getStack().getSpell(source.getSourceId());
+ if (controller != null && spell != null) {
ExileFromGraveCost exileFromGraveCost = (ExileFromGraveCost) source.getCosts().get(0);
-
List