mirror of
https://github.com/magefree/mage.git
synced 2026-01-09 12:22:10 -08:00
Verrak, Warped Sengir - improved combo support with phyrexian style effects like K'rrik, Son of Yawgmoth (closes #10119)
This commit is contained in:
parent
8a8773971d
commit
c0e027f4f4
8 changed files with 271 additions and 87 deletions
|
|
@ -26,6 +26,7 @@ public final class PestilentSouleater extends CardImpl {
|
|||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// {B/P}: Pestilent Souleater gains infect until end of turn. ({B/P} can be paid with either {B} or 2 life. A creature with infect deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.)
|
||||
this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect(
|
||||
InfectAbility.getInstance(), Duration.EndOfTurn
|
||||
), new ManaCostsImpl<>("{B/P}")));
|
||||
|
|
|
|||
|
|
@ -28,27 +28,27 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
// can be played only through life pay
|
||||
Assert.assertTrue(life == 20 && hand == 1 || life == 18 && hand == 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testKrrikOnlyUsableByController() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
|
||||
// ({B/P} can be paid with either {B} or 2 life.)
|
||||
// Lifelink
|
||||
// For each {B} in a cost, you may pay 2 life rather than pay that mana.
|
||||
// Whenever you cast a black spell, put a +1/+1 counter on K'rrik, Son of Yawgmoth.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth");
|
||||
addCard(Zone.HAND, playerA, "Banehound");
|
||||
|
||||
|
||||
// Lifelink, haste
|
||||
addCard(Zone.HAND, playerB, "Banehound"); // Creature {B} 1/1
|
||||
|
||||
checkPlayableAbility("pay 2 life for Banehound", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Banehound", true);
|
||||
|
||||
checkPlayableAbility("pay 2 life for Banehound", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Banehound", true);
|
||||
|
||||
setChoice(playerA, true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Banehound");
|
||||
|
||||
checkPlayableAbility("no Mana for Banehound", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Banehound", false);
|
||||
checkPlayableAbility("no Mana for Banehound", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Banehound", false);
|
||||
|
||||
setStopAt(2, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
|
@ -66,7 +66,7 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth");
|
||||
addCard(Zone.HAND, playerA, "Banehound");
|
||||
addCard(Zone.HAND, playerA, "Crypt Ghast");
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
||||
|
||||
setChoice(playerA, true); //yes to pay 2 life to cast Crypt Ghast
|
||||
|
|
@ -83,13 +83,13 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, "Banehound", 1);
|
||||
assertPermanentCount(playerA, "Crypt Ghast", 1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testKrrikActivatedAbility() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Frozen Shade");
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
||||
|
||||
setChoice(playerA, true); //yes to pay 2 life to activate Frozen Shade's +1/+1 ability
|
||||
|
|
@ -104,22 +104,36 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
|
||||
@Test
|
||||
public void testKrrikTrinispherePostPay() {
|
||||
// Source: https://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/812965-krrik-and-extort#c17
|
||||
// Summary rules:
|
||||
// - announce Phyrexian cost from Dismember
|
||||
// - apply cost modification from Trinisphere
|
||||
// - apply payment method from K'rrik
|
||||
// Detailed rules:
|
||||
// K'rrik's ability applies at the time you attempt to pay the cost after Trinisphere cares about it;
|
||||
// Phyrexian mana applies much earlier to the point where Trinisphere *does* care what the cost actually is.
|
||||
// 118.13a only applies at the time the choice is made on how to pay for that symbol. You choose to pay for
|
||||
// it with black mana thus getting around Trinisphere. Then, in step 601.2h is where K'rrik applies because he
|
||||
// changes how you pay for those 2 black mana symbols you chose to pay mana for. It is similar to Delve and
|
||||
// Convoke getting around Trinisphere for the same reason; you choose to pay mana up front but later in the
|
||||
// process, when you actually pay for the symbols, you choose a different method of payment.
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Trinisphere");
|
||||
addCard(Zone.HAND, playerA, "Dismember");
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Banehound");
|
||||
|
||||
setChoice(playerA, false); //don't pay 2 life for Dismember's Phyrexian cost
|
||||
setChoice(playerA, false); //don't pay 2 life for Dismember's Phyrexian cost
|
||||
setChoice(playerA, true); //yes to pay 2 life for Dismember's {B} cost via K'rrik
|
||||
setChoice(playerA, true); //yes to pay 2 life for Dismember's {B} cost via K'rrik
|
||||
|
||||
|
||||
//Dismember costs {1} now + life paid. Normally this would be {3} + life paid with true Phyrexian mana and Trinisphere active.
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dismember", "Banehound");
|
||||
|
||||
setChoice(playerA, false); //don't pay 2 life for Dismember's Phyrexian cost
|
||||
setChoice(playerA, false); //don't pay 2 life for Dismember's Phyrexian cost
|
||||
setChoice(playerA, true); //yes to pay 2 life for Dismember's {B} cost via K'rrik
|
||||
setChoice(playerA, true); //yes to pay 2 life for Dismember's {B} cost via K'rrik
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
|
|
@ -130,35 +144,35 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
assertGraveyardCount(playerB, "Banehound", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testPlayerCanCastBanehoundWithoutAvailableBlackMana() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
|
||||
// ({B/P} can be paid with either {B} or 2 life.)
|
||||
// Lifelink
|
||||
// For each {B} in a cost, you may pay 2 life rather than pay that mana.
|
||||
// Whenever you cast a black spell, put a +1/+1 counter on K'rrik, Son of Yawgmoth.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth"); // Creature {4}{B/P}{B/P}{B/P} 2/2
|
||||
addCard(Zone.HAND, playerA, "Banehound");
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Banehound");
|
||||
setChoice(playerA, true); // Pay 2 life for {B}
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
//PlayerA pays life
|
||||
//PlayerA pays life
|
||||
assertLife(playerA, 18);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
|
||||
|
||||
|
||||
assertPermanentCount(playerA, "Banehound", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayerEffectNotUsableIfKrrikNotOnBattlefield() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
|
||||
// addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
// ({B/P} can be paid with either {B} or 2 life.)
|
||||
// Lifelink
|
||||
|
|
@ -166,24 +180,24 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
// Whenever you cast a black spell, put a +1/+1 counter on K'rrik, Son of Yawgmoth.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth"); // Creature {4}{B/P}{B/P}{B/P} 2/2
|
||||
addCard(Zone.HAND, playerA, "Banehound");
|
||||
|
||||
|
||||
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.UPKEEP, playerB, "Lightning Bolt", "K'rrik, Son of Yawgmoth");
|
||||
|
||||
checkPlayableAbility("no Mana for Banehound", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Banehound", false);
|
||||
|
||||
checkPlayableAbility("no Mana for Banehound", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Banehound", false);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerB, "Lightning Bolt", 1);
|
||||
assertGraveyardCount(playerB, "Lightning Bolt", 1);
|
||||
assertGraveyardCount(playerA, "K'rrik, Son of Yawgmoth", 1);
|
||||
|
||||
|
||||
assertHandCount(playerA, "Banehound", 1);
|
||||
//PlayerA pays life
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class AlternativeCostRuleTest extends CardTestPlayerBase {
|
|||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
|
||||
Card firewildBorderpost = playerA.getGraveyard().getCards(currentGame).iterator().next();
|
||||
boolean found = false;
|
||||
for (String rule : firewildBorderpost.getRules(currentGame)) {
|
||||
|
|
@ -31,6 +31,28 @@ public class AlternativeCostRuleTest extends CardTestPlayerBase {
|
|||
Assert.assertTrue("Couldn't find rule text for alternative cost on a card: " + firewildBorderpost.getName(), found);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_PayLife() {
|
||||
// You may pay 1 life and exile a black card from your hand rather than pay this spell’s mana cost.
|
||||
// Distribute two -2/-1 counters among one or two target creatures.
|
||||
addCard(Zone.HAND, playerA, "Contagion"); // {3}{B}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
|
||||
addCard(Zone.HAND, playerA, "Arrogant Vampire", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Ancient Bronze Dragon"); // 7/7
|
||||
|
||||
// cast alternative
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Contagion");
|
||||
setChoice(playerA, "Cast with alternative cost: Pay 1 life");
|
||||
addTargetAmount(playerA, "Ancient Bronze Dragon", 2);
|
||||
setChoice(playerA, "Arrogant Vampire"); // to pay discard cost
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertPowerToughness(playerA, "Ancient Bronze Dragon", 7 - 2 * 2, 7 - 1 * 2); // from x1 boost
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AlternativeCostSourceAbility_OneCardMustNotAffectAnother() {
|
||||
// You may pay {W}{U}{B}{R}{G} rather than pay Bringer of the Black Dawn's mana cost.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
package org.mage.test.cards.single.dmc;
|
||||
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.PayVariableLifeCost;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.keyword.InfectAbility;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class VerrakWarpedSengirTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_CopyOnPayLife_DirectCost() {
|
||||
// Whenever you activate an ability that isn’t a mana ability, if life was paid to activate it,
|
||||
// you may pay that much life again. If you do, copy that ability. You may choose new targets for the copy.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Verrak, Warped Sengir");
|
||||
//
|
||||
// {1}{B}, Pay 2 life: Draw a card.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Arguel's Blood Fast");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
|
||||
checkHandCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0);
|
||||
|
||||
// activate and copy it
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{B}, Pay 2 life");
|
||||
setChoice(playerA, true); // pay for copy
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertHandCount(playerA, 1 + 1); // from x2 draws
|
||||
assertLife(playerA, 20 - 2 - 2); // from x2 life pays
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyOnPayLife_VariableCost() {
|
||||
// there are no real cards with X life in activated ability, so generate it here
|
||||
addCustomCardWithAbility("test", playerA, new SimpleActivatedAbility(
|
||||
new GainLifeEffect(10), new PayVariableLifeCost()
|
||||
));
|
||||
|
||||
// Whenever you activate an ability that isn’t a mana ability, if life was paid to activate it,
|
||||
// you may pay that much life again. If you do, copy that ability. You may choose new targets for the copy.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Verrak, Warped Sengir");
|
||||
|
||||
// activate and copy it
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pay X life: You gain 10 life");
|
||||
setChoice(playerA, "X=3");
|
||||
setChoice(playerA, true); // pay for copy
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 2 * 3 + 2 * 10); // x2: -3 for cost, +10 for resolve
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyOnPayLife_PhyrexianCost() {
|
||||
// Whenever you activate an ability that isn’t a mana ability, if life was paid to activate it,
|
||||
// you may pay that much life again. If you do, copy that ability. You may choose new targets for the copy.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Verrak, Warped Sengir");
|
||||
//
|
||||
// {B/P}: Pestilent Souleater gains infect until end of turn.
|
||||
// ({B/P} can be paid with either {B} or 2 life. A creature with infect deals damage to creatures in the
|
||||
// form of -1/-1 counters and to players in the form of poison counters.)
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Pestilent Souleater");
|
||||
|
||||
checkAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pestilent Souleater", InfectAbility.class, false);
|
||||
|
||||
// activate and copy it
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{B/P}:");
|
||||
setChoice(playerA, true); // pay 2 life instead B
|
||||
setChoice(playerA, true); // pay for copy
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pestilent Souleater", InfectAbility.class, true);
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 2 * 2); // x2 pays
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyOnPayLife_PaymentModification() {
|
||||
// bug: https://github.com/magefree/mage/issues/10119
|
||||
|
||||
// Whenever you activate an ability that isn’t a mana ability, if life was paid to activate it,
|
||||
// you may pay that much life again. If you do, copy that ability. You may choose new targets for the copy.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Verrak, Warped Sengir");
|
||||
//
|
||||
// For each {B} in a cost, you may pay 2 life rather than pay that mana.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "K'rrik, Son of Yawgmoth");
|
||||
//
|
||||
// {4}{B}: Each opponent loses 2 life and you gain 2 life. xxx
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Kami of Jealous Thirst");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
|
||||
// activate and copy it
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{B}: Each opponent");
|
||||
setChoice(playerA, true); // pay 2 life instead B
|
||||
setChoice(playerA, true); // pay for copy
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 2 * 2 + 2 * 2); // x2 pays, x2 gains
|
||||
assertLife(playerB, 20 - 2 * 2); // x2 lose
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@ package mage.abilities;
|
|||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
|
|
@ -24,6 +24,7 @@ import mage.choices.Choice;
|
|||
import mage.choices.ChoiceHintType;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.game.Game;
|
||||
import mage.game.command.Dungeon;
|
||||
import mage.game.command.Emblem;
|
||||
|
|
@ -329,7 +330,10 @@ public abstract class AbilityImpl implements Ability {
|
|||
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
|
||||
String announceString = handleOtherXCosts(game, controller);
|
||||
|
||||
handlePhyrexianManaCosts(game, controller);
|
||||
// 601.2b If a cost that will be paid as the spell is being cast includes
|
||||
// Phyrexian mana symbols, the player announces whether they intend to pay 2
|
||||
// life or the corresponding colored mana cost for each of those symbols.
|
||||
AbilityImpl.handlePhyrexianCosts(game, this, this, this.getManaCostsToPay());
|
||||
|
||||
// 20241022 - 601.2b
|
||||
// Not yet included in 601.2b but this is where it will be
|
||||
|
|
@ -632,24 +636,75 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
/**
|
||||
* 601.2b If a cost that will be paid as the spell is being cast includes
|
||||
* Phyrexian mana symbols, the player announces whether they intend to pay 2
|
||||
* life or the corresponding colored mana cost for each of those symbols.
|
||||
* Prepare Phyrexian costs (choose life to pay instead mana)
|
||||
* Must be called on cast announce before any cost modifications
|
||||
*
|
||||
* @param abilityToPay paying ability (will receive life cost)
|
||||
* @param manaCostsToPay paying cost (will remove P and replace it by mana or nothing)
|
||||
*/
|
||||
private void handlePhyrexianManaCosts(Game game, Player controller) {
|
||||
Iterator<ManaCost> costIterator = getManaCostsToPay().iterator();
|
||||
public static void handlePhyrexianCosts(Game game, Ability source, Ability abilityToPay, ManaCosts manaCostsToPay) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Iterator<ManaCost> costIterator = manaCostsToPay.iterator();
|
||||
while (costIterator.hasNext()) {
|
||||
ManaCost cost = costIterator.next();
|
||||
|
||||
if (!cost.isPhyrexian()) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(this, this, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "") + '?', this, game)) {
|
||||
if (payLifeCost.canPay(abilityToPay, source, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "")
|
||||
+ " (phyrexian cost)?", source, game)) {
|
||||
costIterator.remove();
|
||||
addCost(payLifeCost);
|
||||
getManaCostsToPay().incrPhyrexianPaid();
|
||||
abilityToPay.addCost(payLifeCost);
|
||||
manaCostsToPay.incrPhyrexianPaid(); // mark it as real phyrexian pay, e.g. for planeswalkers with Compleated ability
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare and pay Phyrexian style effects like replace mana by life
|
||||
* Must be called after original Phyrexian mana processing and after cost modifications, e.g. on payment
|
||||
*
|
||||
* @param abilityToPay paying ability (will receive life cost)
|
||||
* @param manaCostsToPay paying cost (will replace mana by nothing)
|
||||
*/
|
||||
public static void handlePhyrexianLikeEffects(Game game, Ability source, Ability abilityToPay, ManaCosts manaCostsToPay) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a cost contains a mana symbol that may be paid in multiple ways, such as {B/R}, {B/P}, or {2/B},
|
||||
// you choose how you'll pay it before you do so. If you choose to pay {B} this way, K'rrik's ability allows
|
||||
// you to pay life rather than pay that mana.
|
||||
// (2019-08-23)
|
||||
FilterMana phyrexianColors = controller.getPhyrexianColors();
|
||||
if (controller.getPhyrexianColors() == null) {
|
||||
return;
|
||||
}
|
||||
Iterator<ManaCost> costIterator = manaCostsToPay.iterator();
|
||||
while (costIterator.hasNext()) {
|
||||
ManaCost cost = costIterator.next();
|
||||
Mana mana = cost.getMana();
|
||||
if ((!phyrexianColors.isWhite() || mana.getWhite() <= 0)
|
||||
&& (!phyrexianColors.isBlue() || mana.getBlue() <= 0)
|
||||
&& (!phyrexianColors.isBlack() || mana.getBlack() <= 0)
|
||||
&& (!phyrexianColors.isRed() || mana.getRed() <= 0)
|
||||
&& (!phyrexianColors.isGreen() || mana.getGreen() <= 0)) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(abilityToPay, source, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "")
|
||||
+ " (pay life cost)?", source, game)) {
|
||||
if (payLifeCost.pay(abilityToPay, game, source, controller.getId(), false, null)) {
|
||||
costIterator.remove();
|
||||
abilityToPay.addCost(payLifeCost);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package mage.abilities.costs.mana;
|
|||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.AbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
|
|
@ -254,6 +255,13 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
|
|||
return true;
|
||||
}
|
||||
Player player = game.getPlayer(controllerId);
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: is it require Phyrexian stile effects here for single payment?
|
||||
//AbilityImpl.preparePhyrexianCost(game, source, player, ability, this);
|
||||
|
||||
if (!player.getManaPool().isForcedToPay()) {
|
||||
assignPayment(game, ability, player.getManaPool(), costToPay != null ? costToPay : this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package mage.abilities.costs.mana;
|
|||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.AbilityImpl;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
|
|
@ -127,17 +128,17 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
return false;
|
||||
}
|
||||
|
||||
handleLikePhyrexianManaCosts(player, ability, game); // e.g. K'rrik, Son of Yawgmoth
|
||||
AbilityImpl.handlePhyrexianLikeEffects(game, source, ability, this);
|
||||
|
||||
if (!player.getManaPool().isForcedToPay()) {
|
||||
assignPayment(game, ability, player.getManaPool(), this);
|
||||
assignPayment(game, ability, player.getManaPool(), costToPay != null ? costToPay : this);
|
||||
}
|
||||
game.getState().getSpecialActions().removeManaActions();
|
||||
while (player.canRespond() && !isPaid()) {
|
||||
ManaCost unpaid = this.getUnpaid();
|
||||
String promptText = ManaUtil.addSpecialManaPayAbilities(ability, game, unpaid);
|
||||
if (player.playMana(ability, unpaid, promptText, game)) {
|
||||
assignPayment(game, ability, player.getManaPool(), this);
|
||||
assignPayment(game, ability, player.getManaPool(), costToPay != null ? costToPay : this);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -195,40 +196,6 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
tempCosts.pay(source, game, source, payingPlayer.getId(), false, null);
|
||||
}
|
||||
|
||||
|
||||
private void handleLikePhyrexianManaCosts(Player player, Ability source, Game game) {
|
||||
if (this.isEmpty()) {
|
||||
return; // nothing to be done without any mana costs. prevents NRE from occurring here
|
||||
}
|
||||
FilterMana phyrexianColors = player.getPhyrexianColors();
|
||||
if (player.getPhyrexianColors() == null) {
|
||||
return;
|
||||
}
|
||||
Costs<PayLifeCost> tempCosts = new CostsImpl<>();
|
||||
|
||||
Iterator<T> manaCostIterator = this.iterator();
|
||||
while (manaCostIterator.hasNext()) {
|
||||
ManaCost manaCost = manaCostIterator.next();
|
||||
Mana mana = manaCost.getMana();
|
||||
|
||||
/* find which color mana is in the cost and set it in the temp Phyrexian cost */
|
||||
if ((!phyrexianColors.isWhite() || mana.getWhite() <= 0)
|
||||
&& (!phyrexianColors.isBlue() || mana.getBlue() <= 0)
|
||||
&& (!phyrexianColors.isBlack() || mana.getBlack() <= 0)
|
||||
&& (!phyrexianColors.isRed() || mana.getRed() <= 0)
|
||||
&& (!phyrexianColors.isGreen() || mana.getGreen() <= 0)) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(source, source, player.getId(), game)
|
||||
&& player.chooseUse(Outcome.LoseLife, "Pay 2 life (using an active ability) instead of " + manaCost.getMana() + '?', source, game)) {
|
||||
manaCostIterator.remove();
|
||||
tempCosts.add(payLifeCost);
|
||||
}
|
||||
}
|
||||
tempCosts.pay(source, game, source, player.getId(), false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaCosts<T> getUnpaid() {
|
||||
ManaCosts<T> unpaid = new ManaCostsImpl<>();
|
||||
|
|
|
|||
|
|
@ -1229,8 +1229,6 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
/**
|
||||
* Mana colors the player can pay instead with 2 life
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
FilterMana getPhyrexianColors();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue