mirror of
https://github.com/magefree/mage.git
synced 2025-12-27 05:52:06 -08:00
Additional and alternative costs improved:
* Now player must choose additional costs before ability's modes;
* Fixed broken kicker ability from ZNR (see comments from d4ca287f0f);
* Improved compatibility of additional cost with cost modification effects (fixed that optional multi-costs doesn't affected by cost modification);
* Improved compatibility of additional cost with alternative cost (some cards ignores additional cost on alternative usage, e.g. on play free);
This commit is contained in:
parent
586538a66c
commit
6e0c7e868c
17 changed files with 504 additions and 156 deletions
|
|
@ -1,9 +1,5 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.costs.*;
|
||||
|
|
@ -36,6 +32,11 @@ import mage.util.ThreadLocalStringBuilder;
|
|||
import mage.watchers.Watcher;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -227,22 +228,10 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
game.applyEffects();
|
||||
|
||||
/* 20130201 - 601.2b
|
||||
* If the spell is modal the player announces the mode choice (see rule 700.2).
|
||||
*/
|
||||
if (!getModes().choose(game, this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MageObject sourceObject = getSourceObject(game);
|
||||
if (getSourceObjectZoneChangeCounter() == 0) {
|
||||
setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(getSourceId()));
|
||||
}
|
||||
if (controller.isTestMode()) {
|
||||
if (!controller.addTargets(this, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* 20130201 - 601.2b
|
||||
* If the player wishes to splice any cards onto the spell (see rule 702.45), he
|
||||
|
|
@ -268,9 +257,6 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
if (getModes().getAdditionalCost() != null) {
|
||||
getModes().getAdditionalCost().addOptionalAdditionalModeCosts(this, game);
|
||||
}
|
||||
// 20130201 - 601.2b
|
||||
// If the spell has alternative or additional costs that will be paid as it's being cast such
|
||||
// as buyback, kicker, or convoke costs (see rules 117.8 and 117.9), the player announces his
|
||||
|
|
@ -311,8 +297,29 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
handlePhyrexianManaCosts(game, sourceId, controller);
|
||||
|
||||
/* 20130201 - 601.2b
|
||||
* If the spell is modal the player announces the mode choice (see rule 700.2).
|
||||
*/
|
||||
// rules:
|
||||
// You kick a spell as you cast it. You declare whether you're going to pay a kicker cost at the same
|
||||
// time you'd choose a spell's mode, and then you actually pay it at the same time you pay the spell's mana cost.
|
||||
// Kicking a spell is always optional.
|
||||
if (!getModes().choose(game, this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// unit tests only: it allows to add targets/choices by two ways:
|
||||
// 1. From cast/activate command params (process it here)
|
||||
// 2. From single addTarget/setChoice, it's a preffered method for tests (process it in normal choose dialogs like human player)
|
||||
if (controller.isTestMode()) {
|
||||
if (!controller.addTargets(this, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
||||
this.getModes().setActiveMode(modeId);
|
||||
|
||||
//20121001 - 601.2c
|
||||
// 601.2c The player announces their choice of an appropriate player, object, or zone for
|
||||
// each target the spell requires. A spell may require some targets only if an alternative or
|
||||
|
|
@ -333,8 +340,10 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (sourceObject != null && this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility
|
||||
sourceObject.adjustTargets(this, game);
|
||||
}
|
||||
|
||||
if (!getTargets().isEmpty()) {
|
||||
Outcome outcome = getEffects().getOutcome(this);
|
||||
|
||||
// only activated abilities can be canceled by human user (not triggered)
|
||||
boolean canCancel = this instanceof ActivatedAbility && controller.isHuman();
|
||||
if (!getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game, canCancel)) {
|
||||
|
|
@ -434,7 +443,11 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
boolean alternativeCostUsed = false;
|
||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||
// it's important to apply alternative cost first
|
||||
// example: Omniscience gives free mana as alternative, but Entwine ability adds {2} as additional
|
||||
Abilities<Ability> abilities = CardUtil.getAbilities(sourceObject, game);
|
||||
|
||||
// 1. ALTERNATIVE COSTS
|
||||
for (Ability ability : abilities) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (canUseAlternativeCost && !noMana && ability instanceof AlternativeSourceCosts) {
|
||||
|
|
@ -447,11 +460,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (canUseAdditionalCost && ability instanceof OptionalAdditionalSourceCosts) {
|
||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||
}
|
||||
}
|
||||
|
||||
// controller specific alternate spell costs
|
||||
if (canUseAlternativeCost && !noMana && !alternativeCostUsed) {
|
||||
if (this.getAbilityType() == AbilityType.SPELL
|
||||
|
|
@ -469,6 +478,13 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. ADDITIONAL COST
|
||||
for (Ability ability : abilities) {
|
||||
if (canUseAdditionalCost && ability instanceof OptionalAdditionalSourceCosts) {
|
||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alternativeCostUsed;
|
||||
|
|
@ -806,7 +822,18 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
@Override
|
||||
public void addCost(Cost cost) {
|
||||
if (cost != null) {
|
||||
if (cost == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cost instanceof Costs) {
|
||||
// as list of costs
|
||||
Costs<Cost> list = (Costs<Cost>) cost;
|
||||
for (Cost single : list) {
|
||||
addCost(single);
|
||||
}
|
||||
} else {
|
||||
// as single cost
|
||||
if (cost instanceof ManaCost) {
|
||||
this.addManaCost((ManaCost) cost);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.abilities;
|
||||
|
||||
import mage.abilities.condition.common.KickedCondition;
|
||||
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -33,11 +32,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
private TargetController modeChooser;
|
||||
private boolean eachModeMoreThanOnce; // each mode can be selected multiple times during one choice
|
||||
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
|
||||
private OptionalAdditionalModeSourceCosts optionalAdditionalModeSourceCosts = null; // only set if costs have to be paid
|
||||
private Filter maxModesFilter = null; // calculates the max number of available modes
|
||||
private boolean isRandom = false;
|
||||
private String chooseText = null;
|
||||
private boolean allWhenKicked = false;
|
||||
private boolean resetEachTurn = false;
|
||||
private int turnNum = 0;
|
||||
|
||||
|
|
@ -68,12 +65,10 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
this.modeChooser = modes.modeChooser;
|
||||
this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
|
||||
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
|
||||
this.optionalAdditionalModeSourceCosts = modes.optionalAdditionalModeSourceCosts;
|
||||
this.maxModesFilter = modes.maxModesFilter; // can't change so no copy needed
|
||||
|
||||
this.isRandom = modes.isRandom;
|
||||
this.chooseText = modes.chooseText;
|
||||
this.allWhenKicked = modes.allWhenKicked;
|
||||
this.resetEachTurn = modes.resetEachTurn;
|
||||
this.turnNum = modes.turnNum;
|
||||
if (modes.getSelectedModes().isEmpty()) {
|
||||
|
|
@ -228,15 +223,6 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
this.turnNum = game.getTurnNum();
|
||||
}
|
||||
}
|
||||
if (this.allWhenKicked) {
|
||||
if (KickedCondition.instance.apply(game, source)) {
|
||||
this.setMinModes(0);
|
||||
this.setMaxModes(3);
|
||||
} else {
|
||||
this.setMinModes(1);
|
||||
this.setMaxModes(1);
|
||||
}
|
||||
}
|
||||
if (this.size() > 1) {
|
||||
this.clearSelectedModes();
|
||||
if (this.isRandom) {
|
||||
|
|
@ -244,15 +230,18 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
this.addSelectedMode(modes.get(RandomUtil.nextInt(modes.size())).getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if mode modifying abilities exist
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
for (Ability modeModifyingAbility : card.getAbilities()) {
|
||||
for (Ability modeModifyingAbility : card.getAbilities(game)) {
|
||||
if (modeModifyingAbility instanceof OptionalAdditionalModeSourceCosts) {
|
||||
// cost must check activation conditional in changeModes
|
||||
((OptionalAdditionalModeSourceCosts) modeModifyingAbility).changeModes(source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if all modes can be activated automatically
|
||||
if (this.size() == this.getMinModes() && !isEachModeMoreThanOnce()) {
|
||||
Set<UUID> onceSelectedModes = null;
|
||||
|
|
@ -434,8 +423,6 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
if (this.chooseText != null) {
|
||||
sb.append(chooseText);
|
||||
} else if (this.allWhenKicked) {
|
||||
sb.append("choose one. If this spell was kicked, choose any number instead.");
|
||||
} else if (this.getMaxModesFilter() != null) {
|
||||
sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage());
|
||||
} else if (this.getMinModes() == 0 && this.getMaxModes() == 1) {
|
||||
|
|
@ -499,22 +486,10 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
this.eachModeMoreThanOnce = eachModeMoreThanOnce;
|
||||
}
|
||||
|
||||
public OptionalAdditionalModeSourceCosts getAdditionalCost() {
|
||||
return optionalAdditionalModeSourceCosts;
|
||||
}
|
||||
|
||||
public void setAdditionalCost(OptionalAdditionalModeSourceCosts optionalAdditionalModeSourceCosts) {
|
||||
this.optionalAdditionalModeSourceCosts = optionalAdditionalModeSourceCosts;
|
||||
}
|
||||
|
||||
public void setRandom(boolean isRandom) {
|
||||
this.isRandom = isRandom;
|
||||
}
|
||||
|
||||
public void setAllWhenKicked(boolean allWhenKicked) {
|
||||
this.allWhenKicked = allWhenKicked;
|
||||
}
|
||||
|
||||
public boolean isResetEachTurn() {
|
||||
return resetEachTurn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.costs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -161,5 +160,4 @@ public class CostsImpl<T extends Cost> extends ArrayList<T> implements Costs<T>
|
|||
public Costs<T> copy() {
|
||||
return new CostsImpl(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
|
||||
package mage.abilities.costs;
|
||||
|
||||
import mage.util.Copyable;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*/
|
||||
public interface OptionalAdditionalCost extends Cost {
|
||||
public interface OptionalAdditionalCost extends Cost, Copyable<OptionalAdditionalCost> {
|
||||
|
||||
String getName();
|
||||
|
||||
|
|
@ -29,20 +30,18 @@ public interface OptionalAdditionalCost extends Cost {
|
|||
* message.
|
||||
*
|
||||
* @param position - if there are multiple costs, it's the postion the cost
|
||||
* is set (starting with 0)
|
||||
* is set (starting with 0)
|
||||
* @return
|
||||
*/
|
||||
String getCastSuffixMessage(int position);
|
||||
|
||||
/**
|
||||
* If the player intends to pay the cost, the cost will be activated
|
||||
*
|
||||
*/
|
||||
void activate();
|
||||
|
||||
/**
|
||||
* Reset the activate and count information
|
||||
*
|
||||
*/
|
||||
void reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
|
||||
package mage.abilities.costs;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Cost that can change ability's modes (example: Kicker or Entwine can make all modes selectabled).
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public interface OptionalAdditionalModeSourceCosts {
|
||||
|
||||
void addOptionalAdditionalModeCosts(Ability ability, Game game);
|
||||
public interface OptionalAdditionalModeSourceCosts extends OptionalAdditionalSourceCosts {
|
||||
|
||||
void changeModes(Ability ability, Game game);
|
||||
|
||||
String getCastMessageSuffix();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,19 @@ package mage.abilities.keyword;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.OptionalAdditionalCost;
|
||||
import mage.abilities.costs.OptionalAdditionalCostImpl;
|
||||
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 702.40. Entwine
|
||||
|
|
@ -24,20 +29,23 @@ import java.util.Iterator;
|
|||
* 702.40b If the entwine cost was paid, follow the text of each of the modes in
|
||||
* the order written on the card when the spell resolves.
|
||||
*
|
||||
* @author LevelX2
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class EntwineAbility extends StaticAbility implements OptionalAdditionalModeSourceCosts {
|
||||
|
||||
private static final String keywordText = "Entwine";
|
||||
protected static final String reminderText = "You may {cost} in addition to any other costs to use all modes.";
|
||||
|
||||
protected OptionalAdditionalCost additionalCost;
|
||||
protected Set<String> activations = new HashSet<>(); // same logic as KickerAbility: activations per zoneChangeCounter
|
||||
|
||||
public EntwineAbility(String manaString) {
|
||||
super(Zone.STACK, null);
|
||||
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "Choose both if you pay the entwine cost.", new ManaCostsImpl(manaString));
|
||||
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString));
|
||||
}
|
||||
|
||||
public EntwineAbility(Cost cost) {
|
||||
this(cost, "Choose both if you pay the entwine cost.");
|
||||
this(cost, reminderText);
|
||||
}
|
||||
|
||||
public EntwineAbility(Cost cost, String reminderText) {
|
||||
|
|
@ -48,7 +56,10 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
|
|||
|
||||
public EntwineAbility(final EntwineAbility ability) {
|
||||
super(ability);
|
||||
additionalCost = ability.additionalCost;
|
||||
if (ability.additionalCost != null) {
|
||||
this.additionalCost = ability.additionalCost.copy();
|
||||
}
|
||||
this.activations.addAll(ability.activations);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -57,61 +68,25 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addCost(Cost cost) {
|
||||
if (additionalCost != null) {
|
||||
((Costs) additionalCost).add(cost);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActivated() {
|
||||
if (additionalCost != null) {
|
||||
return additionalCost.isActivated();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void resetCosts() {
|
||||
if (additionalCost != null) {
|
||||
additionalCost.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeModes(Ability ability, Game game) {
|
||||
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||
if (!(ability instanceof SpellAbility)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = game.getPlayer(ability.getControllerId());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
this.resetCosts();
|
||||
|
||||
this.resetCosts(game, ability);
|
||||
if (additionalCost == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (additionalCost.canPay(ability, ability.getSourceId(), ability.getControllerId(), game)
|
||||
&& player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) {
|
||||
|
||||
additionalCost.activate();
|
||||
int modeCount = ability.getModes().size();
|
||||
ability.getModes().setAdditionalCost(this);
|
||||
ability.getModes().setMinModes(modeCount);
|
||||
ability.getModes().setMaxModes(modeCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOptionalAdditionalModeCosts(Ability ability, Game game) {
|
||||
if (additionalCost.isActivated()) {
|
||||
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
}
|
||||
}
|
||||
addCostsToAbility(additionalCost, ability);
|
||||
activateCost(game, ability);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,11 +109,52 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
|
|||
}
|
||||
}
|
||||
|
||||
public String getReminderText() {
|
||||
if (additionalCost != null) {
|
||||
return additionalCost.getReminderText();
|
||||
} else {
|
||||
return "";
|
||||
public void changeModes(Ability ability, Game game) {
|
||||
if (!costWasActivated(ability, game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// activate max modes all the time
|
||||
int maxModes = ability.getModes().size();
|
||||
ability.getModes().setMinModes(maxModes);
|
||||
ability.getModes().setMaxModes(maxModes);
|
||||
}
|
||||
|
||||
private void addCostsToAbility(Cost cost, Ability ability) {
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
|
||||
private void resetCosts(Game game, Ability source) {
|
||||
if (additionalCost != null) {
|
||||
additionalCost.reset();
|
||||
}
|
||||
|
||||
String key = getActivationKey(source, game);
|
||||
this.activations.remove(key);
|
||||
}
|
||||
|
||||
private void activateCost(Game game, Ability source) {
|
||||
String key = getActivationKey(source, game);
|
||||
this.activations.add(key);
|
||||
}
|
||||
|
||||
public boolean costWasActivated(Ability ability, Game game) {
|
||||
String key = getActivationKey(ability, game);
|
||||
return this.activations.contains(key);
|
||||
}
|
||||
|
||||
private String getActivationKey(Ability source, Game game) {
|
||||
// same logic as KickerAbility, uses for source ability only
|
||||
int zcc = 0;
|
||||
if (source.getAbilityType() == AbilityType.TRIGGERED) {
|
||||
zcc = source.getSourceObjectZoneChangeCounter();
|
||||
}
|
||||
if (zcc == 0) {
|
||||
zcc = game.getState().getZoneChangeCounter(source.getSourceId());
|
||||
}
|
||||
if (zcc > 0 && (source.getAbilityType() == AbilityType.TRIGGERED)) {
|
||||
--zcc;
|
||||
}
|
||||
return String.valueOf(zcc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
public KickerAbility(final KickerAbility ability) {
|
||||
super(ability);
|
||||
for (OptionalAdditionalCost cost : ability.kickerCosts) {
|
||||
this.kickerCosts.add((OptionalAdditionalCost) cost.copy());
|
||||
this.kickerCosts.add(cost.copy());
|
||||
}
|
||||
this.keywordText = ability.keywordText;
|
||||
this.reminderText = ability.reminderText;
|
||||
|
|
@ -113,7 +113,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
cost.reset();
|
||||
}
|
||||
String key = getActivationKey(source, "", game);
|
||||
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext();) {
|
||||
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext(); ) {
|
||||
String activationKey = iterator.next();
|
||||
if (activationKey.startsWith(key)
|
||||
&& activations.get(activationKey) > 0) {
|
||||
|
|
@ -192,15 +192,15 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
// canPay checks only single mana available, not total mana usage
|
||||
if (kickerCost.canPay(ability, sourceId, ability.getControllerId(), game)
|
||||
&& player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt,
|
||||
"Pay " + times + kickerCost.getText(false) + " ?", ability, game)) {
|
||||
"Pay " + times + kickerCost.getText(false) + " ?", ability, game)) {
|
||||
this.activateKicker(kickerCost, ability, game);
|
||||
if (kickerCost instanceof Costs) {
|
||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext();) {
|
||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext(); ) {
|
||||
Object kickerCostObject = itKickerCost.next();
|
||||
if ((kickerCostObject instanceof Costs)
|
||||
|| (kickerCostObject instanceof CostsImpl)) {
|
||||
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails
|
||||
= ((Costs) kickerCostObject).iterator(); itDetails.hasNext();) {
|
||||
= ((Costs) kickerCostObject).iterator(); itDetails.hasNext(); ) {
|
||||
addKickerCostsToAbility(itDetails.next(), ability, game);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Same as KickerAbility, but can enable any number modes in spell ability
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class KickerWithAnyNumberModesAbility extends KickerAbility implements OptionalAdditionalModeSourceCosts {
|
||||
|
||||
public KickerWithAnyNumberModesAbility(Cost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
public KickerWithAnyNumberModesAbility(final KickerWithAnyNumberModesAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeModes(Ability ability, Game game) {
|
||||
if (!isKicked(game, ability, "")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// activate any number modes
|
||||
int maxModes = ability.getModes().size();
|
||||
ability.getModes().setMinModes(0);
|
||||
ability.getModes().setMaxModes(maxModes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KickerWithAnyNumberModesAbility copy() {
|
||||
return new KickerWithAnyNumberModesAbility(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.condition.common.KickedCondition;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.OptionalAdditionalCost;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue