mirror of
https://github.com/correl/mage.git
synced 2025-03-07 20:53:18 -10:00
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:
parent
500fc935e4
commit
437861ec20
20 changed files with 675 additions and 192 deletions
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
|
@ -13,20 +11,22 @@ import mage.abilities.keyword.FlyingAbility;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetAnyTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Loki
|
||||
*/
|
||||
public final class FlameblastDragon extends CardImpl {
|
||||
|
||||
public FlameblastDragon(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}");
|
||||
this.subtype.add(SubType.DRAGON);
|
||||
|
||||
this.power = new MageInt(5);
|
||||
|
@ -34,6 +34,7 @@ public final class FlameblastDragon extends CardImpl {
|
|||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Whenever Flameblast Dragon attacks, you may pay {X}{R}. If you do, Flameblast Dragon deals X damage to any target.
|
||||
Ability ability = new AttacksTriggeredAbility(new FlameblastDragonEffect(), false);
|
||||
ability.addTarget(new TargetAnyTarget());
|
||||
|
|
|
@ -4,9 +4,12 @@ import mage.ConditionalMana;
|
|||
import mage.MageInt;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.VariableManaCost;
|
||||
import mage.abilities.effects.mana.BasicManaEffect;
|
||||
import mage.abilities.mana.BasicManaAbility;
|
||||
import mage.abilities.mana.conditional.ManaCondition;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -70,7 +73,7 @@ class RosheenMeandererConditionalMana extends ConditionalMana {
|
|||
}
|
||||
}
|
||||
|
||||
class RosheenMeandererManaCondition implements Condition {
|
||||
class RosheenMeandererManaCondition extends ManaCondition {
|
||||
|
||||
/*
|
||||
A “cost that contains {X}” may be a spell’s total cost, an activated ability’s cost, a suspend cost, or a cost you’re
|
||||
|
@ -81,7 +84,11 @@ class RosheenMeandererManaCondition implements Condition {
|
|||
*/
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return source.getManaCostsToPay().containsX();
|
||||
public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) {
|
||||
if (costToPay instanceof ManaCosts) {
|
||||
return !((ManaCosts) costToPay).getVariableCosts().isEmpty();
|
||||
} else {
|
||||
return costToPay instanceof VariableManaCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ public class UnboundFlourishingTest extends CardTestPlayerBase {
|
|||
int xAnnouncedValue = 3;
|
||||
int xMultiplier = 2;
|
||||
VariableManaCost cost = new VariableManaCost(xInstancesCount);
|
||||
cost.setAmount(xAnnouncedValue * xMultiplier, xAnnouncedValue * xInstancesCount);
|
||||
cost.setAmount(xAnnouncedValue * xMultiplier, xAnnouncedValue * xInstancesCount, false);
|
||||
|
||||
Assert.assertEquals("instances count", xInstancesCount, cost.getXInstancesCount());
|
||||
Assert.assertEquals("boosted X value", xAnnouncedValue * xMultiplier, cost.getAmount());
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
package org.mage.test.cards.mana;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||
import mage.abilities.effects.common.CounterUnlessPaysEffect;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.mana.AddConditionalManaEffect;
|
||||
import mage.abilities.mana.SimpleManaAbility;
|
||||
import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder;
|
||||
import mage.abilities.mana.builder.common.SimpleActivatedAbilityManaBuilder;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.target.TargetSpell;
|
||||
import mage.target.common.TargetAnyTarget;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class ManaPoolTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_OneMana_OneSpell() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt"); // {R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleMana_OneSpell() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
addCard(Zone.HAND, playerA, "Precision Bolt"); // {2}{R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 3);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Precision Bolt", playerB);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ConditionalMana_OneSpell() {
|
||||
// +1: Add {R}{R}{R}. Spend this mana only to cast instant or sorcery spells.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Jaya Ballard");
|
||||
addCard(Zone.HAND, playerA, "Precision Bolt"); // {2}{R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Add {R}{R}{R}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 3);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Precision Bolt", playerB);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ConditionalMana_MultipleSpells() {
|
||||
// +1: Add {R}{R}{R}. Spend this mana only to cast instant or sorcery spells.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Jaya Ballard");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt", 2); // {R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Add {R}{R}{R}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 3);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3 * 2);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleMana_OneXSpell() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.HAND, playerA, "Volcanic Geyser"); // {X}{R}{R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 4);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB);
|
||||
setChoice(playerA, "X=2");
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 2);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleMana_MultipleXSpell() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4 * 2);
|
||||
addCard(Zone.HAND, playerA, "Volcanic Geyser", 2); // {X}{R}{R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
//
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 4 * 2);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB);
|
||||
setChoice(playerA, "X=2");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB);
|
||||
setChoice(playerA, "X=2");
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 2 * 2);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ConditionalMana_OneXSpell() {
|
||||
addCustomCardWithAbility("add 10", playerA, new SimpleActivatedAbility(Zone.ALL,
|
||||
new AddConditionalManaEffect(Mana.RedMana(10), new InstantOrSorcerySpellManaBuilder()),
|
||||
new ManaCostsImpl("")));
|
||||
addCard(Zone.HAND, playerA, "Volcanic Geyser"); // {X}{R}{R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Add {R}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10);
|
||||
|
||||
// use for spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB);
|
||||
setChoice(playerA, "X=1");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10 - 3);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 1);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ConditionalMana_MultipleXSpell() {
|
||||
addCustomCardWithAbility("add 10", playerA, new SimpleActivatedAbility(Zone.ALL,
|
||||
new AddConditionalManaEffect(Mana.RedMana(10), new InstantOrSorcerySpellManaBuilder()),
|
||||
new ManaCostsImpl("")));
|
||||
addCard(Zone.HAND, playerA, "Volcanic Geyser", 2); // {X}{R}{R}
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Add {R}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10);
|
||||
|
||||
// use for spell 1
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB);
|
||||
setChoice(playerA, "X=1");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10 - 3);
|
||||
|
||||
// use for spell 2
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB);
|
||||
setChoice(playerA, "X=1");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10 - 3 * 2);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 1 * 2);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleMana_OneXAbility() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
//
|
||||
Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}"));
|
||||
ability.addTarget(new TargetAnyTarget());
|
||||
addCustomCardWithAbility("damage X", playerA, ability);
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 4);
|
||||
|
||||
// use for ability
|
||||
showAvaileableAbilities("before ability", 1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{X}:", playerB);
|
||||
setChoice(playerA, "X=3");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 4 - 3);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ConditionalMana_OneXAbility() {
|
||||
addCustomCardWithAbility("add 10", playerA, new SimpleActivatedAbility(Zone.ALL,
|
||||
new AddConditionalManaEffect(Mana.RedMana(10), new SimpleActivatedAbilityManaBuilder()),
|
||||
new ManaCostsImpl("")));
|
||||
//
|
||||
Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}"));
|
||||
ability.addTarget(new TargetAnyTarget());
|
||||
addCustomCardWithAbility("damage X", playerA, ability);
|
||||
|
||||
// make mana
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Add {R}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10);
|
||||
|
||||
// use for ability
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{X}:", playerB);
|
||||
setChoice(playerA, "X=3");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10 - 3);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleMana_OneXPart() {
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt"); // {R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1 + 3 + 1);
|
||||
//
|
||||
Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl(""));
|
||||
ability.addTarget(new TargetAnyTarget());
|
||||
addCustomCardWithAbility("damage X", playerA, ability);
|
||||
//
|
||||
// {X}: Counter target spell
|
||||
ability = new SimpleActivatedAbility(Zone.ALL, new CounterUnlessPaysEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}"));
|
||||
ability.addTarget(new TargetSpell());
|
||||
addCustomCardWithAbility("counter until pay X", playerB, ability);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 3);
|
||||
|
||||
// make mana for spell
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1);
|
||||
// cast spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
// make mana for pay X to prevent
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); // one must be saved in pool
|
||||
checkManaPool("mana prevent", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 4);
|
||||
|
||||
// counter by X=3
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{X}: Counter");
|
||||
setChoice(playerB, "X=3");
|
||||
addTarget(playerB, "Lightning Bolt");
|
||||
// pay to prevent
|
||||
setChoice(playerA, "Yes"); // pay 3 to prevent counter
|
||||
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 4 - 3);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ConditionalMana_OneXPart() {
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt"); // {R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
//
|
||||
addCustomCardWithAbility("add 10", playerA, new SimpleManaAbility(Zone.ALL,
|
||||
new AddConditionalManaEffect(Mana.RedMana(10), new SimpleActivatedAbilityManaBuilder()),
|
||||
new ManaCostsImpl("")));
|
||||
//
|
||||
Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl(""));
|
||||
ability.addTarget(new TargetAnyTarget());
|
||||
addCustomCardWithAbility("damage X", playerA, ability);
|
||||
//
|
||||
// {X}: Counter target spell
|
||||
ability = new SimpleActivatedAbility(Zone.ALL, new CounterUnlessPaysEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}"));
|
||||
ability.addTarget(new TargetSpell());
|
||||
addCustomCardWithAbility("counter until pay X", playerB, ability);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 3);
|
||||
|
||||
// make mana for spell
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
|
||||
checkManaPool("mana spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1);
|
||||
// cast spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
// make mana for pay X to prevent
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Add {R}");
|
||||
checkManaPool("mana prevent", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10);
|
||||
|
||||
// counter by X=3
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{X}: Counter");
|
||||
setChoice(playerB, "X=3");
|
||||
addTarget(playerB, "Lightning Bolt");
|
||||
// pay to prevent
|
||||
setChoice(playerA, "Yes"); // pay 3 to prevent counter
|
||||
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkManaPool("mana after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 10 + 1 - 1 - 3);
|
||||
|
||||
checkLife("after", 1, PhaseStep.END_TURN, playerB, 20 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
|
@ -93,4 +93,92 @@ public class RosheenMeandererManaXTest extends CardTestPlayerBase {
|
|||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
// https://github.com/magefree/mage/issues/5206
|
||||
|
||||
// Flameblast Dragon {4}{R}{R}
|
||||
// 5/5
|
||||
// Flying
|
||||
// Whenever Flameblast Dragon attacks, you may pay {X}{R}. If you do, Flameblast Dragon deals X damage to any target.
|
||||
|
||||
@Test
|
||||
public void test_SimpleDragon() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Flameblast Dragon");
|
||||
|
||||
// attack (-5)
|
||||
attack(1, playerA, "Flameblast Dragon", playerB);
|
||||
|
||||
// with extra damage (-3)
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "X=3");
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
checkLife("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, 20 - 5 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_PayXForDragonAbility() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Flameblast Dragon");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Rosheen Meanderer");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
|
||||
// make 4 mana for X pay
|
||||
activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{T}: Add {C}");
|
||||
checkManaPool("mana", 1, PhaseStep.DECLARE_ATTACKERS, playerA, "C", 4);
|
||||
|
||||
// attack (-5)
|
||||
attack(1, playerA, "Flameblast Dragon", playerB);
|
||||
|
||||
// with extra damage (-3)
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "X=3"); // need to pay {3}{R}
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
checkLife("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, 20 - 5 - 3);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
// Condescend {X}{U}
|
||||
// Counter target spell unless its controller pays {X}. Scry 2.
|
||||
|
||||
@Test
|
||||
public void test_PayXForCondescendPrevent() {
|
||||
addCard(Zone.HAND, playerB, "Condescend");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 3);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Rosheen Meanderer");
|
||||
//
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
|
||||
// cast bolt
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
// counter with condescend
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Condescend");
|
||||
setChoice(playerB, "X=2");
|
||||
addTarget(playerB, "Lightning Bolt");
|
||||
// make 4 mana for X pay
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {C}");
|
||||
checkManaPool("mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "C", 4);
|
||||
// pay to prevent
|
||||
setChoice(playerA, "Yes"); // pay 2 to prevent counter
|
||||
|
||||
checkLife("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, 20 - 3);
|
||||
checkHandCardCount("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", 0);
|
||||
checkHandCardCount("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Condescend", 0);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue