Fixed that the information what mana was payed to pay the mana cost of a spell or ability were not correct if "spend mana as though" abilities were involved in the payment (fixes #3604).

This commit is contained in:
LevelX2 2017-07-10 16:53:02 +02:00
parent dc5007003b
commit 5a3243890d
8 changed files with 109 additions and 23 deletions

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.abilities.enters;
import mage.constants.PhaseStep;
@ -90,9 +89,14 @@ public class GreenbeltRampagerTest extends CardTestPlayerBase {
@Test
public void testCastNotOwned() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 10);
addCard(Zone.HAND, playerA, "Gonti, Lord of Luxury");
// Deathtouch
// When Gonti, Lord of Luxury enters the battlefield, look at the top four cards of target opponent's library, exile one of them face down,
// then put the rest on the bottom of that library in a random order. For as long as that card remains exiled,
// you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it.
addCard(Zone.HAND, playerA, "Gonti, Lord of Luxury"); // Creature {2}{B}{B}
addCard(Zone.LIBRARY, playerB, "Greenbelt Rampager");
// When Greenbelt Rampager enters the battlefield, pay {E}{E}. If you can't, return Greenbelt Rampager to its owner's hand and you get {E}.
addCard(Zone.LIBRARY, playerB, "Greenbelt Rampager"); // Creature {G} 3/4
skipInitShuffling();

View file

@ -8,10 +8,38 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
public class MycosynthLatticeTest extends CardTestPlayerBase {
@Test
public void testMycoSynthLatticeNormal() {
// Converge - Crystalline Crawler enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.
// Remove a +1/+1 counter from Crystalline Crawler: Add one mana of any color to your mana pool.
// {T}: Put a +1/+1 counter on Crystalline Crawler.
String crawler = "Crystalline Crawler";
addCard(Zone.BATTLEFIELD, playerA, "Plains");
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.BATTLEFIELD, playerA, "Swamp");
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.HAND, playerA, crawler);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, crawler);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertCounterCount(playerA, crawler, CounterType.P1P1, 4);
}
@Test
public void testMycoSynthLatticeWithCrystallineCrawler(){
public void testMycoSynthLatticeWithCrystallineCrawler() {
// Converge - Crystalline Crawler enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.
// Remove a +1/+1 counter from Crystalline Crawler: Add one mana of any color to your mana pool.
// {T}: Put a +1/+1 counter on Crystalline Crawler.
String crawler = "Crystalline Crawler";
// All permanents are artifacts in addition to their other types.
// All cards that aren't on the battlefield, spells, and permanents are colorless.
// Players may spend mana as though it were mana of any color.
String lattice = "Mycosynth Lattice";
addCard(Zone.BATTLEFIELD, playerA, lattice);

View file

@ -237,6 +237,38 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
any += mana.getAny();
}
/**
* Increases the given mana by one.
*
* @param manaType
*/
public void increase(ManaType manaType) {
switch (manaType) {
case BLACK:
black++;
break;
case BLUE:
blue++;
break;
case COLORLESS:
colorless++;
break;
case GENERIC:
generic++;
break;
case GREEN:
green++;
break;
case RED:
red++;
break;
case WHITE:
white++;
break;
}
}
/**
* Increases the Red mana by one.
*/
@ -815,11 +847,12 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
}
/**
* Returns if this objects mana contains any coloured mana the same as the passed in
* {@link Mana}'s mana.
* Returns if this objects mana contains any coloured mana the same as the
* passed in {@link Mana}'s mana.
*
* @param mana the mana to check for
* @return true if this contains any of the same type of coloured mana that this has
* @return true if this contains any of the same type of coloured mana that
* this has
*/
public boolean containsAny(final Mana mana) {
if (mana.black > 0 && this.black > 0) {
@ -832,7 +865,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
return true;
} else if (mana.green > 0 && this.green > 0) {
return true;
}
}
return false;
}

View file

@ -47,6 +47,8 @@ public interface ManaCost extends Cost {
Mana getPayment();
Mana getUsedManaToPay();
void assignPayment(Game game, Ability ability, ManaPool pool, Cost costsToPay);
void setPayment(Mana mana);

View file

@ -46,18 +46,21 @@ import mage.util.ManaUtil;
public abstract class ManaCostImpl extends CostImpl implements ManaCost {
protected Mana payment;
protected Mana usedManaToPay;
protected Mana cost;
protected ManaOptions options;
protected Filter sourceFilter;
public ManaCostImpl() {
payment = new Mana();
usedManaToPay = new Mana();
options = new ManaOptions();
}
public ManaCostImpl(final ManaCostImpl manaCost) {
super(manaCost);
this.payment = manaCost.payment.copy();
this.usedManaToPay = manaCost.usedManaToPay.copy();
this.cost = manaCost.cost.copy();
this.options = manaCost.options.copy();
if (manaCost.sourceFilter != null) {
@ -70,6 +73,11 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
return payment;
}
@Override
public Mana getUsedManaToPay() {
return usedManaToPay;
}
@Override
public Mana getMana() {
return cost;
@ -118,31 +126,31 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
// first check special mana
switch (mana) {
case B:
if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseBlack();
return true;
}
break;
case U:
if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseBlue();
return true;
}
break;
case W:
if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseWhite();
return true;
}
break;
case G:
if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseGreen();
return true;
}
break;
case R:
if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseRed();
return true;
}
@ -154,7 +162,7 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
protected void assignColorless(Ability ability, Game game, ManaPool pool, int mana, Cost costToPay) {
int conditionalCount = pool.getConditionalCount(ability, game, null, costToPay);
while (mana > payment.count() && (pool.count() > 0 || conditionalCount > 0)) {
if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseColorless();
}
break;
@ -164,27 +172,27 @@ 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);
while (mana > payment.count() && (pool.count() > 0 || conditionalCount > 0)) {
if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseColorless();
continue;
}
if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.BLACK, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseBlack();
continue;
}
if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.BLUE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseBlue();
continue;
}
if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.WHITE, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseWhite();
continue;
}
if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.GREEN, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseGreen();
continue;
}
if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay)) {
if (pool.pay(ManaType.RED, ability, sourceFilter, game, costToPay, usedManaToPay)) {
this.payment.increaseRed();
continue;
}

View file

@ -120,6 +120,15 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
return manaTotal;
}
@Override
public Mana getUsedManaToPay() {
Mana manaTotal = new Mana();
for (ManaCost cost : this) {
manaTotal.add(cost.getUsedManaToPay());
}
return manaTotal;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
return pay(ability, game, sourceId, controllerId, noMana, this);

View file

@ -43,7 +43,7 @@ public class ColorsOfManaSpentToCastCount implements DynamicValue {
}
if (spell != null) {
// NOT the cmc of the spell on the stack
Mana mana = spell.getSpellAbility().getManaCostsToPay().getPayment();
Mana mana = spell.getSpellAbility().getManaCostsToPay().getUsedManaToPay();
if (mana.getBlack() > 0) {
count++;
}

View file

@ -110,9 +110,10 @@ public class ManaPool implements Serializable {
* @param filter
* @param game
* @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) {
public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game, Cost costToPay, Mana usedManaToPay) {
if (!autoPayment && manaType != unlockedManaType) {
// if manual payment and the needed mana type was not unlocked, nothing will be paid
return false;
@ -149,6 +150,7 @@ public class ManaPool implements Serializable {
GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAID, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag());
event.setData(mana.getOriginalId().toString());
game.fireEvent(event);
usedManaToPay.increase(mana.getFirstAvailable());
mana.remove(usableManaType);
if (mana.count() == 0) { // so no items with count 0 stay in list
manaItems.remove(mana);
@ -479,7 +481,7 @@ public class ManaPool implements Serializable {
return false;
}
public boolean isEmpty(){
public boolean isEmpty() {
return count() == 0;
}
}