foul-magics/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java
Susucre f75b1c9f0a
Code cleanup: protect all copy constructors (#10750)
* apply regex to change public copy constructors to protected
* cleanup code using now protected constructors
* fix manaBuilder weird casting of Mana into ConditionalMana
2023-08-04 19:34:58 -04:00

180 lines
6.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package mage.abilities.keyword;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.SpecialAction;
import mage.abilities.common.SimpleStaticAbility;
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.PermanentsOnBattlefieldCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.mana.ManaOptions;
import mage.constants.AbilityType;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.ManaPool;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetControlledPermanent;
import java.util.UUID;
/**
* 702.125. Improvise
* <p>
* 702.125a Improvise is a static ability that functions while the spell with improvise is on the stack. “Improvise”
* means “For each generic mana in this spells total cost, you may tap an untapped artifact you control rather
* than pay that mana.”
* <p>
* 702.125b The improvise ability isnt an additional or alternative cost and applies only after the total cost of
* the spell with improvise is determined.
* <p>
* 702.125c Multiple instances of improvise on the same spell are redundant.
*
* @author LevelX2, JayDi85
*/
public class ImproviseAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility {
private static final FilterControlledArtifactPermanent filterUntapped = new FilterControlledArtifactPermanent("untapped artifact you control");
static {
filterUntapped.add(TappedPredicate.UNTAPPED);
}
private static final DynamicValue untappedCount = new PermanentsOnBattlefieldCount(filterUntapped);
public ImproviseAbility() {
super(Zone.ALL, null);
this.setRuleAtTheTop(true);
this.addHint(new ValueHint("Untapped artifacts you control", untappedCount));
}
protected ImproviseAbility(final ImproviseAbility ability) {
super(ability);
}
@Override
public ImproviseAbility copy() {
return new ImproviseAbility(this);
}
@Override
public String getRule() {
return "improvise <i>(Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}.)</i>";
}
@Override
public ActivationManaAbilityStep useOnActivationManaAbilityStep() {
return ActivationManaAbilityStep.AFTER;
}
@Override
public void addSpecialAction(Ability source, Game game, ManaCost unpaid) {
Player controller = game.getPlayer(source.getControllerId());
int canPayCount = untappedCount.calculate(game, source, null);
if (controller != null && canPayCount > 0) {
if (source.getAbilityType() == AbilityType.SPELL && unpaid.getMana().getGeneric() > 0) {
SpecialAction specialAction = new ImproviseSpecialAction(unpaid, this);
specialAction.setControllerId(source.getControllerId());
specialAction.setSourceId(source.getSourceId());
// create filter for possible artifacts to tap
Target target = new TargetControlledPermanent(1, unpaid.getMana().getGeneric(), filterUntapped, true);
target.setTargetName("artifact to tap as Improvise's pay");
specialAction.addTarget(target);
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 canPayCount = untappedCount.calculate(game, source, null);
if (controller != null && canPayCount > 0) {
options.addMana(Mana.GenericMana(Math.min(unpaid.getMana().getGeneric(), canPayCount)));
}
return options;
}
}
class ImproviseSpecialAction extends SpecialAction {
public ImproviseSpecialAction(ManaCost unpaid, AlternateManaPaymentAbility manaAbility) {
super(Zone.ALL, manaAbility);
this.abilityType = AbilityType.SPECIAL_MANA_PAYMENT;
setRuleVisible(false);
this.addEffect(new ImproviseEffect(unpaid));
}
protected ImproviseSpecialAction(final ImproviseSpecialAction ability) {
super(ability);
}
@Override
public ImproviseSpecialAction copy() {
return new ImproviseSpecialAction(this);
}
}
class ImproviseEffect extends OneShotEffect {
private final ManaCost unpaid;
public ImproviseEffect(ManaCost unpaid) {
super(Outcome.Benefit);
this.unpaid = unpaid;
this.staticText = "Improvise (Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}.)";
}
protected ImproviseEffect(final ImproviseEffect effect) {
super(effect);
this.unpaid = effect.unpaid;
}
@Override
public ImproviseEffect copy() {
return new ImproviseEffect(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) {
return false;
}
for (UUID artifactId : this.getTargetPointer().getTargets(game, source)) {
Permanent perm = game.getPermanent(artifactId);
if (perm == null) {
continue;
}
if (!perm.isTapped() && perm.tap(source, game)) {
ManaPool manaPool = controller.getManaPool();
manaPool.addMana(Mana.ColorlessMana(1), game, source);
manaPool.unlockManaType(ManaType.COLORLESS);
if (!game.isSimulation()) {
game.informPlayers("Improvise: " + controller.getLogName() + " taps " + perm.getLogName() + " to pay {1}");
}
// can't use mana abilities after that (improvise cost must be payed after mana abilities only)
spell.setCurrentActivatingManaAbilitiesStep(ActivationManaAbilityStep.AFTER);
}
}
return true;
}
}