1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-13 01:01:11 -09:00

Fixed tests with multiple X values

This commit is contained in:
Oleg Agafonov 2019-06-06 21:07:51 +04:00
parent b64a75aa4b
commit 0e2cfb7def
11 changed files with 102 additions and 48 deletions
Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai
Mage.Tests/src/test/java/org/mage/test/cards
Mage/src/main/java/mage/abilities

View file

@ -129,11 +129,12 @@ public class SimulatedPlayer2 extends ComputerPlayer {
} }
} }
if (variableManaCost != null) { if (variableManaCost != null) {
int multiplier = variableManaCost.getMultiplier(); int xInstancesCount = variableManaCost.getXInstancesCount();
for (int mana = variableManaCost.getMinX(); mana <= numAvailable; mana++) { for (int mana = variableManaCost.getMinX(); mana <= numAvailable; mana++) {
if (mana % multiplier == 0) { // use only values dependant from multiplier if (mana % xInstancesCount == 0) { // use only values dependant from multiplier
int xAmount = mana / multiplier; // find possible X value to pay
int xAnnounceValue = mana / xInstancesCount;
Ability newAbility = ability.copy(); Ability newAbility = ability.copy();
VariableManaCost varCost = null; VariableManaCost varCost = null;
for (ManaCost cost : newAbility.getManaCostsToPay()) { for (ManaCost cost : newAbility.getManaCostsToPay()) {
@ -142,13 +143,13 @@ public class SimulatedPlayer2 extends ComputerPlayer {
break; // only one VariableManCost per spell (or is it possible to have more?) break; // only one VariableManCost per spell (or is it possible to have more?)
} }
} }
// add the specific value for x // find real X value after replace events
int xMultiplier = 1; int xMultiplier = 1;
if (newAbility instanceof AbilityImpl) { if (newAbility instanceof AbilityImpl) {
xMultiplier = ((AbilityImpl) newAbility).handleManaXMultiplier(game, xMultiplier); xMultiplier = ((AbilityImpl) newAbility).handleManaXMultiplier(game, xMultiplier);
} }
newAbility.getManaCostsToPay().add(new ManaCostsImpl(new StringBuilder("{").append(xAmount).append('}').toString())); newAbility.getManaCostsToPay().add(new ManaCostsImpl(new StringBuilder("{").append(xAnnounceValue).append('}').toString()));
newAbility.getManaCostsToPay().setX(xAmount, xMultiplier); newAbility.getManaCostsToPay().setX(xAnnounceValue * xMultiplier, xAnnounceValue * xInstancesCount);
if (varCost != null) { if (varCost != null) {
varCost.setPaid(); varCost.setPaid();
} }

View file

@ -1,8 +1,10 @@
package org.mage.test.cards.continuous; package org.mage.test.cards.continuous;
import mage.abilities.costs.mana.VariableManaCost;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
@ -167,4 +169,42 @@ public class UnboundFlourishingTest extends CardTestPlayerBase {
assertAllCommandsUsed(); assertAllCommandsUsed();
} }
@Test
public void test_VariableManaCost() {
// VariableManaCost contains:
// - number of {X} instances (1, 2, 3)
// - final X value after all replace events
// - total number of pays
// getAmount() must return final X value
// setAmount() must setup final X value
// test example: {X}{X}, X=3, double X effect from replace event
int xInstancesCount = 2;
int xAnnouncedValue = 3;
int xMultiplier = 2;
VariableManaCost cost = new VariableManaCost(xInstancesCount);
cost.setAmount(xAnnouncedValue * xMultiplier, xAnnouncedValue * xInstancesCount);
Assert.assertEquals("instances count", xInstancesCount, cost.getXInstancesCount());
Assert.assertEquals("boosted X value", xAnnouncedValue * xMultiplier, cost.getAmount());
}
@Test
public void test_MultipleXInstances() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Chalice of the Void enters the battlefield with X charge counters on it.
// Whenever a player casts a spell with converted mana cost equal to the number of charge counters on Chalice of the Void, counter that spell.
addCard(Zone.HAND, playerA, "Chalice of the Void", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chalice of the Void");
setChoice(playerA, "X=1");
checkPermanentCounters("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Chalice of the Void", CounterType.CHARGE, 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
}
} }

View file

@ -1,4 +1,3 @@
package org.mage.test.cards.single; package org.mage.test.cards.single;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
@ -7,7 +6,6 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public class ChaliceOfTheVoidTest extends CardTestPlayerBase { public class ChaliceOfTheVoidTest extends CardTestPlayerBase {
@ -19,6 +17,7 @@ public class ChaliceOfTheVoidTest extends CardTestPlayerBase {
* cmc should be 2 in this case, it shouldnt be countered. * cmc should be 2 in this case, it shouldnt be countered.
* http://boardgames.stackexchange.com/questions/7327/what-is-the-converted-mana-cost-of-a-spell-with-x-when-cast-with-the-miracle-m * http://boardgames.stackexchange.com/questions/7327/what-is-the-converted-mana-cost-of-a-spell-with-x-when-cast-with-the-miracle-m
*/ */
@Test @Test
public void testX1CountsFor2CMC() { public void testX1CountsFor2CMC() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
@ -31,8 +30,10 @@ public class ChaliceOfTheVoidTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chalice of the Void"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chalice of the Void");
setChoice(playerA, "X=1"); setChoice(playerA, "X=1");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute(); execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Chalice of the Void", 2); assertPermanentCount(playerA, "Chalice of the Void", 2);

View file

@ -256,7 +256,7 @@ public abstract class AbilityImpl implements Ability {
VariableManaCost xCosts = new VariableManaCost(); VariableManaCost xCosts = new VariableManaCost();
// no x events - rules from Unbound Flourishing: // 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. // - 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); xCosts.setAmount(xValue, xValue);
this.getManaCostsToPay().add(xCosts); this.getManaCostsToPay().add(xCosts);
} else { } else {
this.getManaCostsToPay().clear(); this.getManaCostsToPay().clear();
@ -505,7 +505,7 @@ public abstract class AbilityImpl implements Ability {
// set the xcosts to paid // set the xcosts to paid
// no x events - rules from Unbound Flourishing: // 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. // - 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); // variableCost.setAmount(xValue, xValue);
((Cost) variableCost).setPaid(); ((Cost) variableCost).setPaid();
String message = controller.getLogName() + " announces a value of " + xValue + " (" + variableCost.getActionText() + ')'; String message = controller.getLogName() + " announces a value of " + xValue + " (" + variableCost.getActionText() + ')';
announceString.append(message); announceString.append(message);
@ -574,7 +574,7 @@ public abstract class AbilityImpl implements Ability {
if (!noMana) { if (!noMana) {
xValue = controller.announceXMana(variableManaCost.getMinX(), variableManaCost.getMaxX(), xValueMultiplier, xValue = controller.announceXMana(variableManaCost.getMinX(), variableManaCost.getMaxX(), xValueMultiplier,
"Announce the value for " + variableManaCost.getText(), game, this); "Announce the value for " + variableManaCost.getText(), game, this);
int amountMana = xValue * variableManaCost.getMultiplier(); int amountMana = xValue * variableManaCost.getXInstancesCount();
StringBuilder manaString = threadLocalBuilder.get(); StringBuilder manaString = threadLocalBuilder.get();
if (variableManaCost.getFilter() == null || variableManaCost.getFilter().isGeneric()) { if (variableManaCost.getFilter() == null || variableManaCost.getFilter().isGeneric()) {
manaString.append('{').append(amountMana).append('}'); manaString.append('{').append(amountMana).append('}');
@ -603,7 +603,7 @@ public abstract class AbilityImpl implements Ability {
} }
} }
manaCostsToPay.add(new ManaCostsImpl(manaString.toString())); manaCostsToPay.add(new ManaCostsImpl(manaString.toString()));
manaCostsToPay.setX(xValue, xValueMultiplier); manaCostsToPay.setX(xValue * xValueMultiplier, amountMana);
} }
variableManaCost.setPaid(); variableManaCost.setPaid();
} }

View file

@ -162,13 +162,15 @@ public class SpellAbility extends ActivatedAbilityImpl {
return 0; return 0;
} }
// mana cost instances
for (ManaCost manaCost : card.getManaCost()) { for (ManaCost manaCost : card.getManaCost()) {
if (manaCost instanceof VariableManaCost) { if (manaCost instanceof VariableManaCost) {
xMultiplier = ((VariableManaCost) manaCost).getMultiplier(); xMultiplier = ((VariableManaCost) manaCost).getXInstancesCount();
break; break;
} }
} }
// mana cost final X value
boolean hasNonManaXCost = false; boolean hasNonManaXCost = false;
for (Cost cost : getCosts()) { for (Cost cost : getCosts()) {
if (cost instanceof VariableCost) { if (cost instanceof VariableCost) {

View file

@ -1,12 +1,9 @@
package mage.abilities.costs; package mage.abilities.costs;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.game.Game; import mage.game.Game;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public interface VariableCost { public interface VariableCost {
@ -16,12 +13,14 @@ public interface VariableCost {
* @return * @return
*/ */
int getAmount(); int getAmount();
/** /**
* Sets the variable amount * Sets the variable amount
* *
* @param amount * @param xValue - value of X
* @param xPay - total value of pays for X (X * xMultiplier * xInstancesCount)
*/ */
void setAmount(int amount); void setAmount(int xValue, int xPay);
/** /**
* returns the action text (e.g. "creature cards to exile from your hand", "life to pay") * returns the action text (e.g. "creature cards to exile from your hand", "life to pay")
@ -29,6 +28,7 @@ public interface VariableCost {
* @return * @return
*/ */
String getActionText(); String getActionText();
/** /**
* Return a min value to announce * Return a min value to announce
* *
@ -37,6 +37,7 @@ public interface VariableCost {
* @return * @return
*/ */
int getMinValue(Ability source, Game game); int getMinValue(Ability source, Game game);
/** /**
* Returns a max value to announce * Returns a max value to announce
* *
@ -45,13 +46,16 @@ public interface VariableCost {
* @return * @return
*/ */
int getMaxValue(Ability source, Game game); int getMaxValue(Ability source, Game game);
/** /**
* Asks the controller to announce the variable value * Asks the controller to announce the variable value
*
* @param source * @param source
* @param game * @param game
* @return * @return
*/ */
int announceXValue(Ability source, Game game); int announceXValue(Ability source, Game game);
/** /**
* Returns a fixed cost with the announced variable value * Returns a fixed cost with the announced variable value
* *

View file

@ -1,7 +1,5 @@
package mage.abilities.costs; package mage.abilities.costs;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.mana.ManaAbility; import mage.abilities.mana.ManaAbility;
import mage.game.Game; import mage.game.Game;
@ -10,8 +8,9 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.Targets; import mage.target.Targets;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public abstract class VariableCostImpl implements Cost, VariableCost { public abstract class VariableCostImpl implements Cost, VariableCost {
@ -29,7 +28,6 @@ public abstract class VariableCostImpl implements Cost, VariableCost {
} }
/** /**
*
* @param xText string for the defined value * @param xText string for the defined value
* @param actionText what happens with the value (e.g. "to tap", "to exile * @param actionText what happens with the value (e.g. "to tap", "to exile
* from your graveyard") * from your graveyard")
@ -125,8 +123,8 @@ public abstract class VariableCostImpl implements Cost, VariableCost {
} }
@Override @Override
public void setAmount(int amount) { public void setAmount(int xValue, int xPay) {
amountPaid = amount; amountPaid = xPay;
} }
@Override @Override

View file

@ -69,7 +69,7 @@ public class ExileFromHandCost extends CostImpl {
VariableManaCost vmc = new VariableManaCost(); VariableManaCost vmc = new VariableManaCost();
// no x events - rules from Unbound Flourishing: // 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. // - 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); vmc.setAmount(cmc, cmc);
vmc.setPaid(); vmc.setPaid();
ability.getManaCostsToPay().add(vmc); ability.getManaCostsToPay().add(vmc);
} }

View file

@ -24,10 +24,10 @@ public interface ManaCosts<T extends ManaCost> extends List<T>, ManaCost {
int getX(); int getX();
/** /**
* @param xValue announced X value * @param xValue final X value -- announced X * xMultiplier, where xMultiplier can be changed by replace events like Unbound Flourishing)
* @param xMultiplier special X multiplier to change announced X value without pay increase, see Unbound Flourishing * @param xPay real number of pay amount (x * xMultiplier * xInstances, where xInstances is number of {X} in pay like 1, 2, 3)
*/ */
void setX(int xValue, int xMultiplier); void setX(int xValue, int xPay);
void load(String mana); void load(String mana);

View file

@ -229,10 +229,10 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
} }
@Override @Override
public void setX(int xValue, int xMultiplier) { public void setX(int xValue, int xPay) {
List<VariableCost> variableCosts = getVariableCosts(); List<VariableCost> variableCosts = getVariableCosts();
if (!variableCosts.isEmpty()) { if (!variableCosts.isEmpty()) {
variableCosts.get(0).setAmount(xValue * xMultiplier); variableCosts.get(0).setAmount(xValue, xPay);
} }
} }
@ -344,7 +344,12 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
if (player != null) { if (player != null) {
game.undo(playerId); game.undo(playerId);
this.clearPaid(); this.clearPaid();
this.setX(referenceCosts.getX(), 1); // TODO: checks Word of Command with Unbound Flourishing's X multiplier
// TODO: checks Word of Command with Unbound Flourishing's X multiplier
// TODO: checks Word of Command with {X}{X} cards
int xValue = referenceCosts.getX();
this.setX(xValue, xValue);
player.getManaPool().restoreMana(pool.getPoolBookmark()); player.getManaPool().restoreMana(pool.getPoolBookmark());
game.bookmarkState(); game.bookmarkState();
} }

View file

@ -1,4 +1,3 @@
package mage.abilities.costs.mana; package mage.abilities.costs.mana;
import mage.Mana; import mage.Mana;
@ -11,12 +10,12 @@ import mage.game.Game;
import mage.players.ManaPool; import mage.players.ManaPool;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class VariableManaCost extends ManaCostImpl implements VariableCost { public class VariableManaCost extends ManaCostImpl implements VariableCost {
protected int multiplier; protected int xInstancesCount; // number of {X}
protected int xValue = 0; // final X value after announce and replace events
protected FilterMana filter; protected FilterMana filter;
protected int minX = 0; protected int minX = 0;
protected int maxX = Integer.MAX_VALUE; protected int maxX = Integer.MAX_VALUE;
@ -25,15 +24,16 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
this(1); this(1);
} }
public VariableManaCost(int multiplier) { public VariableManaCost(int xInstancesCount) {
this.multiplier = multiplier; this.xInstancesCount = xInstancesCount;
this.cost = new Mana(); this.cost = new Mana();
options.add(new Mana()); options.add(new Mana());
} }
public VariableManaCost(final VariableManaCost manaCost) { public VariableManaCost(final VariableManaCost manaCost) {
super(manaCost); super(manaCost);
this.multiplier = manaCost.multiplier; this.xInstancesCount = manaCost.xInstancesCount;
this.xValue = manaCost.xValue;
if (manaCost.filter != null) { if (manaCost.filter != null) {
this.filter = manaCost.filter.copy(); this.filter = manaCost.filter.copy();
} }
@ -55,9 +55,9 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
@Override @Override
public String getText() { public String getText() {
if (multiplier > 1) { if (xInstancesCount > 1) {
StringBuilder symbol = new StringBuilder(multiplier); StringBuilder symbol = new StringBuilder(xInstancesCount);
for (int i = 0; i < multiplier; i++) { for (int i = 0; i < xInstancesCount; i++) {
symbol.append("{X}"); symbol.append("{X}");
} }
return symbol.toString(); return symbol.toString();
@ -73,12 +73,15 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
@Override @Override
public int getAmount() { public int getAmount() {
return payment.count() / multiplier; // must return X value
//return payment.count() / multiplier;
return this.xValue;
} }
@Override @Override
public void setAmount(int amount) { public void setAmount(int xValue, int xPay) {
payment.setGeneric(amount); this.xValue = xValue;
payment.setGeneric(xPay);
} }
@Override @Override
@ -91,8 +94,8 @@ public class VariableManaCost extends ManaCostImpl implements VariableCost {
return new VariableManaCost(this); return new VariableManaCost(this);
} }
public int getMultiplier() { public int getXInstancesCount() {
return multiplier; return this.xInstancesCount;
} }
public int getMinX() { public int getMinX() {