Improved and fixed X mana cost and pays, mana pool:

* Pay X abilities - fixed that it spends all available mana pool instead only needed;
 * Pay X abilities - added support of interactions with other X effects like Rosheen Meanderer's mana usage for "pay X to prevent";
 * Rosheen Meanderer - fixed that it can't use mana for "you may pay X" like Flameblast Dragon's effect (#5206);
 * Devs: added support to use VariableManaCost to pay X in code (without generic's workaround, use ManaUtil.createManaCost to generate cost to pay);
This commit is contained in:
Oleg Agafonov 2019-06-20 21:18:01 +04:00
parent 500fc935e4
commit 437861ec20
20 changed files with 675 additions and 192 deletions

View file

@ -256,7 +256,7 @@ public abstract class AbilityImpl implements Ability {
VariableManaCost xCosts = new VariableManaCost();
// no x events - rules from Unbound Flourishing:
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
xCosts.setAmount(xValue, xValue);
xCosts.setAmount(xValue, xValue, false);
this.getManaCostsToPay().add(xCosts);
} else {
this.getManaCostsToPay().clear();
@ -525,7 +525,7 @@ public abstract class AbilityImpl implements Ability {
// set the xcosts to paid
// no x events - rules from Unbound Flourishing:
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
variableCost.setAmount(xValue, xValue);
variableCost.setAmount(xValue, xValue, false);
((Cost) variableCost).setPaid();
String message = controller.getLogName() + " announces a value of " + xValue + " (" + variableCost.getActionText() + ')';
announceString.append(message);

View file

@ -17,10 +17,11 @@ public interface VariableCost {
/**
* Sets the variable amount
*
* @param xValue - value of X
* @param xPay - total value of pays for X (X * xMultiplier * xInstancesCount)
* @param xValue - value of X
* @param xPay - total value of pays for X (X * xMultiplier * xInstancesCount)
* @param isPayed - is that was real payed or just value setup
*/
void setAmount(int xValue, int xPay);
void setAmount(int xValue, int xPay, boolean isPayed);
/**
* returns the action text (e.g. "creature cards to exile from your hand", "life to pay")

View file

@ -123,7 +123,7 @@ public abstract class VariableCostImpl implements Cost, VariableCost {
}
@Override
public void setAmount(int xValue, int xPay) {
public void setAmount(int xValue, int xPay, boolean isPayed) {
amountPaid = xPay;
}

View file

@ -69,7 +69,7 @@ public class ExileFromHandCost extends CostImpl {
VariableManaCost vmc = new VariableManaCost();
// no x events - rules from Unbound Flourishing:
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
vmc.setAmount(cmc, cmc);
vmc.setAmount(cmc, cmc, false);
vmc.setPaid();
ability.getManaCostsToPay().add(vmc);
}

View file

@ -1,4 +1,3 @@
package mage.abilities.costs.mana;
import mage.Mana;
@ -42,7 +41,7 @@ public class GenericManaCost extends ManaCostImpl {
@Override
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costsToPay) {
this.assignGeneric(ability, game, pool, mana, costsToPay);
this.assignGeneric(ability, game, pool, mana, null, costsToPay);
}
@Override

View file

@ -1,9 +1,5 @@
package mage.abilities.costs.mana;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
@ -12,11 +8,16 @@ import mage.abilities.mana.ManaOptions;
import mage.constants.ColoredManaSymbol;
import mage.constants.ManaType;
import mage.filter.Filter;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.players.ManaPool;
import mage.players.Player;
import mage.util.ManaUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public abstract class ManaCostImpl extends CostImpl implements ManaCost {
protected Mana payment;
@ -143,33 +144,49 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
}
}
protected boolean assignGeneric(Ability ability, Game game, ManaPool pool, int mana, Cost costToPay) {
int conditionalCount = pool.getConditionalCount(ability, game, null, costToPay);
protected boolean assignGeneric(Ability ability, Game game, ManaPool pool, int mana, FilterMana filterMana, Cost costToPay) {
int conditionalCount = pool.getConditionalCount(ability, game, filterMana, costToPay);
while (mana > payment.count() && (pool.count() > 0 || conditionalCount > 0)) {
if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay, usedManaToPay)) {
// try to use different mana to pay (conditional mana will used in pool.pay)
// filterMana can be null, uses for spells like "spend only black mana on X"
// {C}
if ((filterMana == null || filterMana.isColorless()) && pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseColorless();
continue;
}
if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay, usedManaToPay)) {
// {B}
if ((filterMana == null || filterMana.isBlack()) && pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseBlack();
continue;
}
if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
// {U}
if ((filterMana == null || filterMana.isBlue()) && pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseBlue();
continue;
}
if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
// {W}
if ((filterMana == null || filterMana.isWhite()) && pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseWhite();
continue;
}
if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay, usedManaToPay)) {
// {G}
if ((filterMana == null || filterMana.isGreen()) && pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseGreen();
continue;
}
if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay, usedManaToPay)) {
// {R}
if ((filterMana == null || filterMana.isRed()) && pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseRed();
continue;
}
// nothing to pay
break;
}
return mana > payment.count();
@ -208,14 +225,14 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
}
Player player = game.getPlayer(controllerId);
if (!player.getManaPool().isForcedToPay()) {
assignPayment(game, ability, player.getManaPool(), costToPay);
assignPayment(game, ability, player.getManaPool(), costToPay != null ? costToPay : this);
}
game.getState().getSpecialActions().removeManaActions();
while (!isPaid()) {
ManaCost unpaid = this.getUnpaid();
String promptText = ManaUtil.addSpecialManaPayAbilities(ability, game, unpaid);
if (player.playMana(ability, unpaid, promptText, game)) {
assignPayment(game, ability, player.getManaPool(), costToPay);
assignPayment(game, ability, player.getManaPool(), costToPay != null ? costToPay : this);
} else {
return false;
}

View file

@ -232,7 +232,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
public void setX(int xValue, int xPay) {
List<VariableCost> variableCosts = getVariableCosts();
if (!variableCosts.isEmpty()) {
variableCosts.get(0).setAmount(xValue, xPay);
variableCosts.get(0).setAmount(xValue, xPay, false);
}
}

View file

@ -1,8 +1,5 @@
package mage.abilities.costs.mana;
import java.util.ArrayList;
import java.util.List;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
@ -10,6 +7,9 @@ import mage.constants.ColoredManaSymbol;
import mage.game.Game;
import mage.players.ManaPool;
import java.util.ArrayList;
import java.util.List;
public class MonoHybridManaCost extends ManaCostImpl {
private final ColoredManaSymbol mana;
@ -45,7 +45,7 @@ public class MonoHybridManaCost extends ManaCostImpl {
@Override
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) {
if (!assignColored(ability, game, pool, mana, costToPay)) {
assignGeneric(ability, game, pool, mana2, costToPay);
assignGeneric(ability, game, pool, mana2, null, costToPay);
}
}

View file

@ -1,4 +1,3 @@
package mage.abilities.costs.mana;
import mage.Mana;
@ -36,7 +35,7 @@ public class SnowManaCost extends ManaCostImpl {
@Override
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) {
this.assignGeneric(ability, game, pool, 1, costToPay);
this.assignGeneric(ability, game, pool, 1, null, costToPay);
}
@Override

View file

@ -10,13 +10,20 @@ import mage.game.Game;
import mage.players.ManaPool;
/**
* @author BetaSteward_at_googlemail.com
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class VariableManaCost extends ManaCostImpl implements VariableCost {
public final class VariableManaCost extends ManaCostImpl implements VariableCost {
protected int xInstancesCount; // number of {X}
// 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 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 FilterMana filter;
protected int xPay = 0; // final/total need pay after announce and replace events (example: {X}{X}, X=3, xPay = 6)
protected boolean wasAnnounced = false;
protected FilterMana filter; // mana filter that can be used for that cost
protected int minX = 0;
protected int maxX = Integer.MAX_VALUE;
@ -34,6 +41,8 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
super(manaCost);
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();
}
@ -48,9 +57,8 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
@Override
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) {
payment.add(pool.getMana(filter));
payment.add(pool.getAllConditionalMana(ability, game, filter));
pool.payX(ability, game, filter);
// X mana cost always pays as generic mana
this.assignGeneric(ability, game, pool, xPay, filter, costToPay);
}
@Override
@ -66,6 +74,14 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
}
}
@Override
public boolean isPaid() {
if (!wasAnnounced) return false;
if (paid) return true;
return this.isColorlessPaid(xPay);
}
@Override
public VariableManaCost getUnpaid() {
return this;
@ -74,19 +90,23 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
@Override
public int getAmount() {
// must return X value
//return payment.count() / multiplier;
return this.xValue;
}
@Override
public void setAmount(int xValue, int xPay) {
public void setAmount(int xValue, int xPay, boolean isPayed) {
// xPay is total pay value (X * instances)
this.xValue = xValue;
payment.setGeneric(xPay);
this.xPay = xPay;
if (isPayed) {
payment.setGeneric(xPay);
}
this.wasAnnounced = true;
}
@Override
public boolean testPay(Mana testMana) {
return true;
return true; // TODO: need rework to generic mana style?
}
@Override
@ -121,27 +141,27 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
@Override
public int announceXValue(Ability source, Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
throw new UnsupportedOperationException("Not supported.");
}
@Override
public Cost getFixedCostsFromAnnouncedValue(int xValue) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
throw new UnsupportedOperationException("Not supported.");
}
@Override
public String getActionText() {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
throw new UnsupportedOperationException("Not supported.");
}
@Override
public int getMinValue(Ability source, Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
throw new UnsupportedOperationException("Not supported.");
}
@Override
public int getMaxValue(Ability source, Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
throw new UnsupportedOperationException("Not supported.");
}
public FilterMana getFilter() {

View file

@ -1,10 +1,8 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.OneShotEffect;
@ -12,9 +10,9 @@ import mage.constants.Outcome;
import mage.game.Game;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.util.ManaUtil;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class CounterUnlessPaysEffect extends OneShotEffect {
@ -54,23 +52,27 @@ public class CounterUnlessPaysEffect extends OneShotEffect {
Player player = game.getPlayer(spell.getControllerId());
if (player != null) {
Cost costToPay;
String costValueMessage;
if (cost != null) {
costToPay = cost.copy();
costValueMessage = costToPay.getText();
} else {
costToPay = new GenericManaCost(genericMana.calculate(game, source, this));
costValueMessage = "{" + genericMana.calculate(game, source, this) + "}";
costToPay = ManaUtil.createManaCost(genericMana, game, source, this);
}
String message;
if (costToPay instanceof ManaCost) {
message = "Would you like to pay " + costToPay.getText() + " to prevent counter effect?";
message = "Would you like to pay " + costValueMessage + " to prevent counter effect?";
} else {
message = costToPay.getText() + " to prevent counter effect?";
message = costValueMessage + " to prevent counter effect?";
}
costToPay.clearPaid();
if (!(player.chooseUse(Outcome.Benefit, message, source, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false, null))) {
game.informPlayers(player.getLogName() + " chooses not to pay " + costToPay.getText() + " to prevent the counter effect");
game.informPlayers(player.getLogName() + " chooses not to pay " + costValueMessage + " to prevent the counter effect");
return game.getStack().counter(spell.getId(), source.getSourceId(), game);
}
game.informPlayers(player.getLogName() + " chooses to pay " + costToPay.getText() + " to prevent the counter effect");
game.informPlayers(player.getLogName() + " chooses to pay " + costValueMessage + " to prevent the counter effect");
return true;
}
}

View file

@ -1,11 +1,5 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.mana.builder.common;
import java.util.UUID;
import mage.ConditionalMana;
import mage.MageObject;
import mage.Mana;
@ -17,8 +11,9 @@ import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.abilities.mana.conditional.ManaCondition;
import mage.game.Game;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class InstantOrSorcerySpellManaBuilder extends ConditionalManaBuilder {
@ -49,9 +44,7 @@ class InstantOrSorceryCastManaCondition extends ManaCondition implements Conditi
public boolean apply(Game game, Ability source) {
if (source instanceof SpellAbility) {
MageObject object = game.getObject(source.getSourceId());
if (object != null && (object.isInstant() || object.isSorcery())) {
return true;
}
return object != null && (object.isInstant() || object.isSorcery());
}
return false;
}

View file

@ -0,0 +1,53 @@
package mage.abilities.mana.builder.common;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.Cost;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.abilities.mana.conditional.ManaCondition;
import mage.game.Game;
import java.util.UUID;
/**
* testing class
*
* @author JayDi85
*/
public class SimpleActivatedAbilityManaBuilder extends ConditionalManaBuilder {
@Override
public ConditionalMana build(Object... options) {
return new SimpleActivatedAbilityConditionalMana(this.mana);
}
@Override
public String getRule() {
return "Spend this mana only to activate simple abilities";
}
}
class SimpleActivatedAbilityConditionalMana extends ConditionalMana {
public SimpleActivatedAbilityConditionalMana(Mana mana) {
super(mana);
staticText = "Spend this mana only to activate simple abilities";
addCondition(new SimpleActivatedAbilityManaCondition());
}
}
class SimpleActivatedAbilityManaCondition extends ManaCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return source instanceof SimpleActivatedAbility;
}
@Override
public boolean apply(Game game, Ability source, UUID originalId, Cost costsToPay) {
return apply(game, source);
}
}

View file

@ -1,12 +1,5 @@
package mage.players;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
@ -22,8 +15,10 @@ import mage.game.events.GameEvent.EventType;
import mage.game.events.ManaEvent;
import mage.game.stack.Spell;
import java.io.Serializable;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class ManaPool implements Serializable {
@ -84,25 +79,24 @@ public class ManaPool implements Serializable {
}
/**
*
* @param manaType the mana type that should be paid
* @param manaType the mana type that should be paid
* @param ability
* @param filter
* @param game
* @param costToPay complete costs to pay (needed to check conditional mana)
* @param costToPay complete costs to pay (needed to check conditional mana)
* @param usedManaToPay the information about what mana was paid
* @return
*/
public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game, Cost costToPay, Mana usedManaToPay) {
if (!isAutoPayment()
if (!isAutoPayment()
&& manaType != unlockedManaType) {
// if manual payment and the needed mana type was not unlocked, nothing will be paid
return false;
}
ManaType possibleAsThoughPoolManaType = null;
if (isAutoPayment()
&& isAutoPaymentRestricted()
&& !wasManaAddedBeyondStock()
if (isAutoPayment()
&& isAutoPaymentRestricted()
&& !wasManaAddedBeyondStock()
&& manaType != unlockedManaType) {
// if automatic restricted payment and there is already mana in the pool
// and the needed mana type was not unlocked, nothing will be paid
@ -112,7 +106,7 @@ public class ManaPool implements Serializable {
possibleAsThoughPoolManaType = game.getContinuousEffects().asThoughMana(manaType, checkItem, ability.getSourceId(), ability, ability.getControllerId(), game);
}
// Check if it's possible to use mana as thought for the unlocked manatype in the mana pool for this ability
if (possibleAsThoughPoolManaType == null
if (possibleAsThoughPoolManaType == null
|| possibleAsThoughPoolManaType != unlockedManaType) {
return false; // if it's not possible return
}
@ -123,21 +117,21 @@ public class ManaPool implements Serializable {
lockManaType(); // pay only one mana if mana payment is set to manually
return true;
}
for (ManaPoolItem mana : manaItems) {
if (filter != null) {
if (!filter.match(mana.getSourceObject(), game)) {
// Prevent that cost reduction by convoke is filtered out
if (!(mana.getSourceObject() instanceof Spell)
if (!(mana.getSourceObject() instanceof Spell)
|| ability.getSourceId().equals(mana.getSourceId())) {
continue;
}
}
}
if (possibleAsThoughPoolManaType == null
&& manaType != unlockedManaType
&& isAutoPayment()
&& isAutoPaymentRestricted()
if (possibleAsThoughPoolManaType == null
&& manaType != unlockedManaType
&& isAutoPayment()
&& isAutoPaymentRestricted()
&& mana.count() == mana.getStock()) {
// no mana added beyond the stock so don't auto pay this
continue;
@ -174,7 +168,7 @@ public class ManaPool implements Serializable {
if (mana.isConditional()
&& mana.getConditionalMana().get(manaType) > 0
&& mana.getConditionalMana().apply(ability, game, mana.getSourceId(), costToPay)) {
if (filter == null
if (filter == null
|| filter.match(mana.getSourceObject(), game)) {
return mana.getConditionalMana().get(manaType);
}
@ -184,7 +178,7 @@ public class ManaPool implements Serializable {
}
public int getConditionalCount(Ability ability, Game game, FilterMana filter, Cost costToPay) {
if (ability == null
if (ability == null
|| getConditionalMana().isEmpty()) {
return 0;
}
@ -222,7 +216,7 @@ public class ManaPool implements Serializable {
for (ManaType manaType : ManaType.values()) {
if (!doNotEmptyManaTypes.contains(manaType)) {
if (item.get(manaType) > 0) {
if (item.getDuration() != Duration.EndOfTurn
if (item.getDuration() != Duration.EndOfTurn
|| game.getPhase().getType() == TurnPhase.END) {
if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) {
int amount = item.get(manaType);
@ -236,7 +230,7 @@ public class ManaPool implements Serializable {
}
if (conditionalItem != null) {
if (conditionalItem.get(manaType) > 0) {
if (item.getDuration() != Duration.EndOfTurn
if (item.getDuration() != Duration.EndOfTurn
|| game.getPhase().getType() == TurnPhase.END) {
if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) {
int amount = conditionalItem.get(manaType);
@ -258,86 +252,6 @@ public class ManaPool implements Serializable {
return total;
}
private int payX(Ability ability, Game game) {
int total = 0;
Iterator<ManaPoolItem> it = manaItems.iterator();
while (it.hasNext()) {
ManaPoolItem item = it.next();
if (item.isConditional()) {
ConditionalMana cm = item.getConditionalMana();
if (cm.apply(ability, game, cm.getManaProducerId(), null)) {
total += item.count();
it.remove();
}
} else {
total += item.count();
it.remove();
}
}
return total;
}
/**
* remove all mana from pool that applies and that matches filter
*
* @param ability
* @param game
* @param filter
* @return
*/
public int payX(Ability ability, Game game, FilterMana filter) {
if (filter == null) {
return payX(ability, game);
}
int total = 0;
Iterator<ManaPoolItem> it = manaItems.iterator();
while (it.hasNext()) {
ManaPoolItem item = it.next();
if (item.isConditional()) {
ConditionalMana c = item.getConditionalMana();
if (c.apply(ability, game, c.getManaProducerId(), null)) {
int count = c.count(filter);
if (count > 0) {
total += count;
c.removeAll(filter);
if (c.count() == 0) {
it.remove();
}
}
}
} else {
if (filter.isBlack()) {
total += item.getBlack();
item.removeBlack();
}
if (filter.isBlue()) {
total += item.getBlue();
item.removeBlue();
}
if (filter.isWhite()) {
total += item.getWhite();
item.removeWhite();
}
if (filter.isRed()) {
total += item.getRed();
item.removeRed();
}
if (filter.isGreen()) {
total += item.getGreen();
item.removeGreen();
}
if (filter.isGeneric()) {
total += item.getColorless();
item.removeColorless();
}
if (item.count() == 0) {
it.remove();
}
}
}
return total;
}
public Mana getMana() {
Mana m = new Mana();
for (ManaPoolItem item : manaItems) {
@ -376,12 +290,6 @@ public class ManaPool implements Serializable {
return m;
}
public Mana getAllConditionalMana(Ability ability, Game game, FilterMana filter) {
Mana m = new Mana();
m.setGeneric(getConditionalCount(ability, game, filter, null));
return m;
}
public void addMana(Mana manaToAdd, Game game, Ability source) {
addMana(manaToAdd, game, source, false);
}
@ -392,7 +300,7 @@ public class ManaPool implements Serializable {
if (!game.replaceEvent(new ManaEvent(EventType.ADD_MANA, source.getId(), source.getSourceId(), playerId, mana))) {
if (mana instanceof ConditionalMana) {
ManaPoolItem item = new ManaPoolItem((ConditionalMana) mana, source.getSourceObject(game),
((ConditionalMana) mana).getManaProducerOriginalId() != null
((ConditionalMana) mana).getManaProducerOriginalId() != null
? ((ConditionalMana) mana).getManaProducerOriginalId() : source.getOriginalId());
if (emptyOnTurnsEnd) {
item.setDuration(Duration.EndOfTurn);
@ -524,12 +432,12 @@ public class ManaPool implements Serializable {
public UUID getPlayerId() {
return playerId;
}
public void storeMana() {
poolBookmark.clear();
poolBookmark.addAll(getManaItems());
}
public List<ManaPoolItem> getPoolBookmark() {
List<ManaPoolItem> itemsCopy = new ArrayList<>();
for (ManaPoolItem manaItem : poolBookmark) {
@ -537,7 +445,7 @@ public class ManaPool implements Serializable {
}
return itemsCopy;
}
public void restoreMana(List<ManaPoolItem> manaList) {
manaItems.clear();
if (!manaList.isEmpty()) {

View file

@ -4,9 +4,10 @@ import mage.MageObject;
import mage.Mana;
import mage.ManaSymbol;
import mage.abilities.Ability;
import mage.abilities.costs.mana.AlternateManaPaymentAbility;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaSymbols;
import mage.abilities.costs.mana.*;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.Effect;
import mage.abilities.mana.*;
import mage.cards.Card;
import mage.choices.Choice;
@ -494,4 +495,21 @@ public final class ManaUtil {
destColors.setGreen(true);
}
}
public static ManaCost createManaCost(int manaValue) {
return new GenericManaCost(manaValue);
}
public static ManaCost createManaCost(DynamicValue manaValue, Game game, Ability sourceAbility, Effect effect) {
int costValue = manaValue.calculate(game, sourceAbility, effect);
if (manaValue instanceof ManacostVariableValue) {
// variable (X must be final value after all events and effects)
VariableManaCost xCost = new VariableManaCost();
xCost.setAmount(costValue, costValue, false);
return xCost;
} else {
// static/generic
return new GenericManaCost(costValue);
}
}
}