* Monohybrid mana cost improves:

* fixed wrong manually pay by mana pool (it pays generic cost instead colored part of monohybrid);
 * fixed not working cost reduction effects (now monohybrid cost will be reduced correctly with some limitation, see #6130);
This commit is contained in:
Oleg Agafonov 2020-02-11 22:29:07 +04:00
parent 13ad86cb21
commit b5acf64772
9 changed files with 589 additions and 78 deletions

View file

@ -7,13 +7,16 @@ import mage.abilities.SpellAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.*;
import mage.cards.Card;
import mage.constants.ColoredManaSymbol;
import mage.constants.EmptyNames;
import mage.constants.ManaType;
import mage.filter.Filter;
import mage.game.CardState;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.Token;
import mage.util.functions.CopyTokenFunction;
import org.junit.Assert;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@ -90,34 +93,118 @@ public final class CardUtil {
}
private static ManaCosts<ManaCost> adjustCost(ManaCosts<ManaCost> manaCosts, int reduceCount) {
int restToReduce = reduceCount;
ManaCosts<ManaCost> adjustedCost = new ManaCostsImpl<>();
boolean updated = false;
for (ManaCost manaCost : manaCosts) {
if (manaCost instanceof SnowManaCost) {
adjustedCost.add(manaCost);
continue;
// nothing to change
if (reduceCount == 0) {
for (ManaCost manaCost : manaCosts) {
adjustedCost.add(manaCost.copy());
}
Mana mana = manaCost.getOptions().get(0);
int colorless = mana != null ? mana.getGeneric() : 0;
if (restToReduce != 0 && colorless > 0) {
if ((colorless - restToReduce) > 0) {
int newColorless = colorless - restToReduce;
adjustedCost.add(new GenericManaCost(newColorless));
restToReduce = 0;
} else {
restToReduce -= colorless;
return adjustedCost;
}
// remove or save cost
if (reduceCount > 0) {
int restToReduce = reduceCount;
// first run - priority single option costs (generic)
for (ManaCost manaCost : manaCosts) {
if (manaCost instanceof SnowManaCost) {
adjustedCost.add(manaCost);
continue;
}
updated = true;
} else {
adjustedCost.add(manaCost);
if (manaCost.getOptions().size() == 0) {
adjustedCost.add(manaCost);
continue;
}
// ignore monohybrid and other multi-option mana (for potential support)
if (manaCost.getOptions().size() > 1) {
continue;
}
// generic mana reduce
Mana mana = manaCost.getOptions().get(0);
int colorless = mana != null ? mana.getGeneric() : 0;
if (restToReduce != 0 && colorless > 0) {
if ((colorless - restToReduce) > 0) {
// partly reduce
int newColorless = colorless - restToReduce;
adjustedCost.add(new GenericManaCost(newColorless));
restToReduce = 0;
} else {
// full reduce - ignore cost
restToReduce -= colorless;
}
} else {
// nothing to reduce
adjustedCost.add(manaCost.copy());
}
}
// second run - priority for multi option costs (monohybrid)
//
// from Reaper King:
// If an effect reduces the cost to cast a spell by an amount of generic mana, it applies to a monocolored hybrid
// spell only if youve chosen a method of paying for it that includes generic mana.
// (2008-05-01)
// TODO: xmage don't use announce for hybrid mana (instead it uses auto-pay), so that's workaround uses first hybrid to reduce (see https://github.com/magefree/mage/issues/6130 )
for (ManaCost manaCost : manaCosts) {
if (manaCost.getOptions().size() <= 1) {
continue;
}
if (manaCost instanceof MonoHybridManaCost) {
// current implemention supports only 1 hybrid cost per object
MonoHybridManaCost mono = (MonoHybridManaCost) manaCost;
int colorless = mono.getOptions().get(1).getGeneric();
if (restToReduce != 0 && colorless > 0) {
if ((colorless - restToReduce) > 0) {
// partly reduce
int newColorless = colorless - restToReduce;
adjustedCost.add(new MonoHybridManaCost(mono.getManaColor(), newColorless));
restToReduce = 0;
} else {
// full reduce
adjustedCost.add(new MonoHybridManaCost(mono.getManaColor(), 0));
restToReduce -= colorless;
}
} else {
// nothing to reduce
adjustedCost.add(mono.copy());
}
continue;
}
// unsupported multi-option mana types for reduce (like HybridManaCost)
adjustedCost.add(manaCost.copy());
}
}
// for increasing spell cost effects
if (!updated && reduceCount < 0) {
adjustedCost.add(new GenericManaCost(-reduceCount));
// increase cost (add to first generic or add new)
if (reduceCount < 0) {
Assert.assertEquals("must be empty", 0, adjustedCost.size());
boolean added = false;
for (ManaCost manaCost : manaCosts) {
if (reduceCount != 0 && manaCost instanceof GenericManaCost) {
// add increase cost to existing generic
GenericManaCost gen = (GenericManaCost) manaCost;
adjustedCost.add(new GenericManaCost(gen.getOptions().get(0).getGeneric() + -reduceCount));
reduceCount = 0;
added = true;
} else {
// non-generic mana
adjustedCost.add(manaCost.copy());
}
}
if (!added) {
// add increase cost as new
adjustedCost.add(new GenericManaCost(-reduceCount));
}
}
// cost modifying effects requiring snow mana unnecessarily (fixes #6000)
Filter filter = manaCosts.stream()
.filter(manaCost -> !(manaCost instanceof SnowManaCost))
.map(ManaCost::getSourceFilter)
@ -642,4 +729,23 @@ public final class CardUtil {
res.addAll(mana2);
return res;
}
public static ColoredManaSymbol manaTypeToColoredManaSymbol(ManaType manaType) {
switch (manaType) {
case BLACK:
return ColoredManaSymbol.B;
case BLUE:
return ColoredManaSymbol.U;
case GREEN:
return ColoredManaSymbol.G;
case RED:
return ColoredManaSymbol.R;
case WHITE:
return ColoredManaSymbol.W;
case GENERIC:
case COLORLESS:
default:
throw new IllegalArgumentException("Wrong mana type " + manaType);
}
}
}