package mage.abilities.keyword; import mage.Mana; 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; import mage.constants.AbilityType; import mage.constants.ManaType; 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; 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.” *
* 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, 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.ALL, null);
this.setRuleAtTheTop(true);
this.addHint(new ValueHint("Cards in your graveyard", cardsInGraveyard));
}
public DelveAbility(final DelveAbility ability) {
super(ability);
}
@Override
public DelveAbility copy() {
return new DelveAbility(this);
}
@Override
public String getRule() {
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 (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();
if (!controller.getManaPool().isAutoPayment() && unpaidAmount > 1) {
unpaidAmount = 1;
}
specialAction.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(
0, Math.min(controller.getGraveyard().size(), unpaidAmount),
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(AlternateManaPaymentAbility manaAbility) {
super(Zone.ALL, manaAbility);
this.abilityType = AbilityType.SPECIAL_MANA_PAYMENT;
this.addEffect(new DelveEffect());
}
public DelveSpecialAction(final DelveSpecialAction ability) {
super(ability);
}
@Override
public DelveSpecialAction copy() {
return new DelveSpecialAction(this);
}
}
class DelveEffect extends OneShotEffect {
public DelveEffect() {
super(Outcome.Benefit);
this.staticText = "Delve (Each card you exile from your graveyard while casting this spell pays for {1}.)";
}
public DelveEffect(final DelveEffect effect) {
super(effect);
}
@Override
public DelveEffect copy() {
return new DelveEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Spell spell = game.getStack().getSpell(source.getSourceId());
if (controller != null && spell != null) {
ExileFromGraveCost exileFromGraveCost = (ExileFromGraveCost) source.getCosts().get(0);
List