forked from External/mage
Improves: * refactor: split CostAdjuster logic in multiple parts - prepare X, prepare cost, increase cost, reduce cost; * refactor: improved VariableManaCost to support min/max values, playable and AI calculations, test framework; * refactor: improved EarlyTargetCost to support mana costs too (related to #13023); * refactor: migrated some cards with CostAdjuster and X to EarlyTargetCost (Knollspine Invocation, etc - related to #13023); * refactor: added shared code for "As an additional cost to cast this spell, discard X creature cards"; * refactor: added shared code for "X is the converted mana cost of the exiled card"; * tests: added dozens tests with cost adjusters; Bug fixes: * game: fixed that some cards with CostAdjuster ignore min/max limits for X (allow to choose any X, example: Scorched Earth, Open The Way); * game: fixed that some cards ask to announce already defined X values (example: Bargaining Table); * game: fixed that some cards with CostAdjuster do not support combo with other cost modification effects; * game, gui: fixed missing game logs about predefined X values; * game, gui: fixed wrong X icon for predefined X values; Test framework: * test framework: added X min/max check for wrong values; * test framework: added X min/max info in miss X value announce; * test framework: added check to find duplicated effect bugs (see assertNoDuplicatedEffects); Cards: * Open The Way - fixed that it allow to choose any X without limits (close #12810); * Unbound Flourishing - improved combo support for activated abilities with predefined X mana costs like Bargaining Table;
210 lines
5.6 KiB
Java
210 lines
5.6 KiB
Java
package mage.abilities.costs.mana;
|
|
|
|
import mage.Mana;
|
|
import mage.abilities.Ability;
|
|
import mage.abilities.costs.Cost;
|
|
import mage.abilities.costs.MinMaxVariableCost;
|
|
import mage.abilities.costs.VariableCostType;
|
|
import mage.abilities.mana.ManaOptions;
|
|
import mage.constants.ColoredManaSymbol;
|
|
import mage.filter.FilterMana;
|
|
import mage.game.Game;
|
|
import mage.players.ManaPool;
|
|
import mage.util.CardUtil;
|
|
|
|
/**
|
|
* @author BetaSteward_at_googlemail.com, JayDi85
|
|
*/
|
|
public class VariableManaCost extends ManaCostImpl implements MinMaxVariableCost {
|
|
|
|
// variable mana cost usage on 2019-06-20:
|
|
// 1. as X value in spell/ability cast (announce X, set VariableManaCost as paid and add generic mana to pay instead)
|
|
// 2. as X value in direct pay (X already announced, cost is unpaid, need direct pay)
|
|
|
|
protected VariableCostType costType;
|
|
protected int xInstancesCount; // number of {X} instances in cost like {X} or {X}{X}
|
|
protected int xValue = 0; // final X value after announce and replace events
|
|
protected int xPay = 0; // final/total need pay after announce and replace events (example: {X}{X}, X=3, xPay = 6)
|
|
protected boolean wasAnnounced = false; // X was announced by player or auto-defined by CostAdjuster
|
|
|
|
protected FilterMana filter; // mana filter that can be used for that cost
|
|
protected int minX = 0;
|
|
protected int maxX = Integer.MAX_VALUE;
|
|
|
|
public VariableManaCost(VariableCostType costType) {
|
|
this(costType, 1);
|
|
}
|
|
|
|
public VariableManaCost(VariableCostType costType, int xInstancesCount) {
|
|
this.costType = costType;
|
|
this.xInstancesCount = xInstancesCount;
|
|
this.cost = new Mana();
|
|
options.add(new Mana());
|
|
}
|
|
|
|
protected VariableManaCost(final VariableManaCost manaCost) {
|
|
super(manaCost);
|
|
this.costType = manaCost.costType;
|
|
this.xInstancesCount = manaCost.xInstancesCount;
|
|
this.xValue = manaCost.xValue;
|
|
this.xPay = manaCost.xPay;
|
|
this.wasAnnounced = manaCost.wasAnnounced;
|
|
if (manaCost.filter != null) {
|
|
this.filter = manaCost.filter.copy();
|
|
}
|
|
this.minX = manaCost.minX;
|
|
this.maxX = manaCost.maxX;
|
|
}
|
|
|
|
@Override
|
|
public int manaValue() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public ManaOptions getOptions(boolean canPayLifeCost) {
|
|
ManaOptions res = new ManaOptions();
|
|
|
|
// limit mana options for better performance
|
|
CardUtil.distributeValues(10, getMinX(), getMaxX()).forEach(value -> {
|
|
res.add(Mana.GenericMana(value));
|
|
});
|
|
|
|
return res;
|
|
}
|
|
|
|
@Override
|
|
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) {
|
|
// X mana cost always pays as generic mana
|
|
this.assignGeneric(ability, game, pool, xPay, filter, costToPay);
|
|
}
|
|
|
|
@Override
|
|
public String getText() {
|
|
if (xInstancesCount > 1) {
|
|
StringBuilder symbol = new StringBuilder(xInstancesCount);
|
|
for (int i = 0; i < xInstancesCount; i++) {
|
|
symbol.append("{X}");
|
|
}
|
|
return symbol.toString();
|
|
} else {
|
|
return "{X}";
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isPaid() {
|
|
if (!wasAnnounced) return false;
|
|
if (paid) return true;
|
|
|
|
return this.isColorlessPaid(xPay);
|
|
}
|
|
|
|
public boolean wasAnnounced() {
|
|
return this.wasAnnounced;
|
|
}
|
|
|
|
@Override
|
|
public VariableManaCost getUnpaid() {
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public int getAmount() {
|
|
// must return X value
|
|
return this.xValue;
|
|
}
|
|
|
|
@Override
|
|
public void setAmount(int xValue, int xPay, boolean isPayed) {
|
|
// xPay is total pay value (X * instances)
|
|
this.xValue = xValue;
|
|
this.xPay = xPay;
|
|
if (isPayed) {
|
|
payment.setGeneric(xPay);
|
|
}
|
|
this.wasAnnounced = true;
|
|
}
|
|
|
|
@Override
|
|
public boolean testPay(Mana testMana) {
|
|
return true; // TODO: need rework to generic mana style?
|
|
}
|
|
|
|
@Override
|
|
public VariableManaCost copy() {
|
|
return new VariableManaCost(this);
|
|
}
|
|
|
|
public int getXInstancesCount() {
|
|
return this.xInstancesCount;
|
|
}
|
|
|
|
@Override
|
|
public int getMinX() {
|
|
return minX;
|
|
}
|
|
|
|
@Override
|
|
public void setMinX(int minX) {
|
|
this.minX = minX;
|
|
}
|
|
|
|
@Override
|
|
public int getMaxX() {
|
|
return maxX;
|
|
}
|
|
|
|
@Override
|
|
public void setMaxX(int maxX) {
|
|
this.maxX = maxX;
|
|
}
|
|
|
|
@Override
|
|
public boolean containsColor(ColoredManaSymbol coloredManaSymbol) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int announceXValue(Ability source, Game game) {
|
|
throw new UnsupportedOperationException("Not supported.");
|
|
}
|
|
|
|
@Override
|
|
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
|
|
throw new UnsupportedOperationException("Not supported.");
|
|
}
|
|
|
|
@Override
|
|
public String getActionText() {
|
|
throw new UnsupportedOperationException("Not supported.");
|
|
}
|
|
|
|
@Override
|
|
public int getMinValue(Ability source, Game game) {
|
|
throw new UnsupportedOperationException("Not supported.");
|
|
}
|
|
|
|
@Override
|
|
public int getMaxValue(Ability source, Game game) {
|
|
throw new UnsupportedOperationException("Not supported.");
|
|
}
|
|
|
|
public FilterMana getFilter() {
|
|
return filter;
|
|
}
|
|
|
|
public void setFilter(FilterMana filter) {
|
|
this.filter = filter;
|
|
}
|
|
|
|
@Override
|
|
public VariableCostType getCostType() {
|
|
return this.costType;
|
|
}
|
|
|
|
@Override
|
|
public void setCostType(VariableCostType costType) {
|
|
this.costType = costType;
|
|
}
|
|
}
|