diff --git a/Mage/src/mage/Mana.java b/Mage/src/mage/Mana.java index 0d7e66948f..e79e2cf945 100644 --- a/Mage/src/mage/Mana.java +++ b/Mage/src/mage/Mana.java @@ -170,6 +170,10 @@ public class Mana implements Comparable, Serializable, Copyable { public int count() { return red + green + blue + white + black + colorless + any; } + + public int countColored() { + return red + green + blue + white + black + any; + } public int count(FilterMana filter) { if (filter == null) { @@ -506,4 +510,74 @@ public class Mana implements Comparable, Serializable, Copyable { return flag; } + public void setToMana(Mana mana) { + this.any = mana.any; + this.red = mana.red; + this.green = mana.green; + this.white = mana.white; + this.blue = mana.blue; + this.black = mana.black; + this.colorless = mana.colorless; + } + + public boolean equalManaValue(Mana mana) { + return this.any == mana.any && + this.red == mana.red && + this.green == mana.green && + this.white == mana.white && + this.blue == mana.blue && + this.black == mana.black && + this.colorless == mana.colorless; + } + + /** + * Don't takes any mana into account to be usable in calculating available mana + * @param mana + * @return + */ + public boolean includesMana(Mana mana) { + return this.green >= mana.green && + this.blue >= mana.blue && + this.white >= mana.white && + this.black >= mana.black && + this.red >= mana.red && + ( + this.colorless >= mana.colorless || + this.countColored() >= mana.countColored() + mana.colorless + ); + + } + + /** + * Returns the mana that is more colored but does not contain + * one less mana in any color but colorless + * if you call with {1}{W}{R} and {G}{W}{R} you get back {G}{W}{R} + * if you call with {G}{W}{R} and {G}{W}{R} you get back {G}{W}{R} + * if you call with {G}{W}{B} and {G}{W}{R} you get back null + * + * @param mana1 + * @param mana2 + * @return + */ + public static Mana getMoreValuableMana(Mana mana1, Mana mana2) { + Mana moreMana; + Mana lessMana; + if (mana2.count() > mana1.count() || mana2.getAny() > mana1.getAny() || mana2.getColorless() < mana1.getColorless()) { + moreMana = mana2; + lessMana = mana1; + } else { + moreMana = mana1; + lessMana = mana2; + } + if (lessMana.getWhite() > moreMana.getWhite() || + lessMana.getRed() > moreMana.getRed() || + lessMana.getGreen() > moreMana.getGreen() || + lessMana.getBlue() > moreMana.getBlue() || + lessMana.getBlack() > moreMana.getBlack() || + lessMana.getAny() > moreMana.getAny() + ) { + return null; + } + return moreMana; + } } diff --git a/Mage/src/mage/abilities/mana/ManaOptions.java b/Mage/src/mage/abilities/mana/ManaOptions.java index d91dc28453..912bfa908c 100644 --- a/Mage/src/mage/abilities/mana/ManaOptions.java +++ b/Mage/src/mage/abilities/mana/ManaOptions.java @@ -82,10 +82,22 @@ public class ManaOptions extends ArrayList { this.clear(); for (ManaAbility ability: abilities) { for (Mana netMana: ability.getNetMana(game)) { + SkipAddMana: for (Mana mana: copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); + for(Mana existingMana: this) { + if (existingMana.equalManaValue(newMana)) { + continue SkipAddMana; + } + Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana); + if (moreValuable != null) { + // only keep the more valuable mana + existingMana.setToMana(newMana); + continue SkipAddMana; + } + } this.add(newMana); } } @@ -103,6 +115,7 @@ public class ManaOptions extends ArrayList { //if there is only one mana option available add it to all the existing options ManaAbility ability = abilities.get(0); List netManas = abilities.get(0).getNetMana(game); + // no mana costs if (ability.getManaCosts().isEmpty()) { if (netManas.size() == 1) { addMana(netManas.get(0)); @@ -121,7 +134,7 @@ public class ManaOptions extends ArrayList { } else { if (netManas.size() == 1) { - addMana(ability.getManaCosts().getMana(), netManas.get(0)); + subtractCostAddMana(ability.getManaCosts().getMana(), netManas.get(0), ability.getCosts().isEmpty()); } else { List copy = copy(); this.clear(); @@ -130,7 +143,7 @@ public class ManaOptions extends ArrayList { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); - addMana(ability.getManaCosts().getMana(), netMana); + subtractCostAddMana(ability.getManaCosts().getMana(), netMana, ability.getCosts().isEmpty()); } } } @@ -208,14 +221,21 @@ public class ManaOptions extends ArrayList { return new ManaOptions(this); } - public void addMana(Mana cost, Mana addMana) { + public void subtractCostAddMana(Mana cost, Mana addMana, boolean onlyManaCosts) { if (isEmpty()) { this.add(new Mana()); } + boolean addAny = false; + if (addMana.getAny() == 1 && addMana.count() == 1) { + addAny = true; // only replace to any will be repeated + } for (Mana mana: this) { - if (mana.contains(cost)) { + while (mana.includesMana(cost)) { mana.subtract(cost); mana.add(addMana); + if (!addAny) { + break; + } } } } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 2da315c33f..857bf9a8be 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -2099,14 +2099,35 @@ public abstract class PlayerImpl implements Player, Serializable { protected ManaOptions getManaAvailable(Game game) { ManaOptions available = new ManaOptions(); - List manaPerms = this.getAvailableManaProducers(game); - for (Permanent perm: manaPerms) { - available.addMana(perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game), game); + List> sourceWithoutCosts = new ArrayList<>(); + List> sourceWithCosts = new ArrayList<>(); + for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { + boolean canAdd = false; + boolean withCost = false; + Abilities manaAbilities = permanent.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game); + for (ManaAbility ability: manaAbilities) { + if (ability.canActivate(playerId, game)) { + canAdd = true; + if (!ability.getManaCosts().isEmpty()) { + withCost = true; + break; + } + } + } + if (canAdd) { + if (withCost) { + sourceWithCosts.add(manaAbilities); + } else { + sourceWithoutCosts.add(manaAbilities); + } + } } - List manaPermsWithCost = this.getAvailableManaProducersWithCost(game); - for (Permanent perm: manaPermsWithCost) { - available.addManaWithCost(perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game), game); + for (Abilities manaAbilities: sourceWithoutCosts) { + available.addMana(manaAbilities, game); + } + for (Abilities manaAbilities: sourceWithCosts) { + available.addManaWithCost(manaAbilities, game); } return available; } @@ -2117,13 +2138,13 @@ public abstract class PlayerImpl implements Player, Serializable { for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { boolean canAdd = false; for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - if (ability.canActivate(playerId, game)) { - canAdd = true; - } if (!ability.getManaCosts().isEmpty()) { canAdd = false; break; } + if (ability.canActivate(playerId, game)) { + canAdd = true; + } } if (canAdd) { result.add(permanent); @@ -2203,7 +2224,7 @@ public abstract class PlayerImpl implements Player, Serializable { } protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions available, Ability ability, Game game) { - if (!(sourceObject instanceof Permanent)) { + if (sourceObject != null && !(sourceObject instanceof Permanent)) { for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) { // if cast for noMana no Alternative costs are allowed if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) {