mirror of
https://github.com/correl/mage.git
synced 2025-01-11 19:13:02 +00:00
* K'rrik, Son of Yawgmoth - Fixe phyrexian mana like payment of mana costs (closes #6928 related to #6698).
This commit is contained in:
parent
e9999de931
commit
244cf2a1e9
7 changed files with 160 additions and 70 deletions
|
@ -31,25 +31,35 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
|
||||
@Test
|
||||
public void testKrrikOnlyUsableByController() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
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");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
||||
addCard(Zone.HAND, playerB, "Banehound");
|
||||
// Lifelink, haste
|
||||
addCard(Zone.HAND, playerB, "Banehound"); // Creature {B} 1/1
|
||||
|
||||
setChoice(playerA, "Yes");
|
||||
checkPlayableAbility("pay 2 life for Banehound", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Banehound", true);
|
||||
|
||||
setChoice(playerA, "Yes");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Banehound");
|
||||
setChoice(playerB, "Yes");
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banehound");
|
||||
|
||||
checkPlayableAbility("no Mana for Banehound", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Banehound", false);
|
||||
|
||||
setStopAt(2, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
//PlayerA pays life but PlayerB cannot
|
||||
assertLife(playerA, 18);
|
||||
assertLife(playerB, 20);
|
||||
assertPermanentCount(playerA, "Banehound", 1);
|
||||
assertPermanentCount(playerB, "Banehound", 1);
|
||||
assertPermanentCount(playerB, "Banehound", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -121,4 +131,65 @@ public class PhyrexianManaTest extends CardTestPlayerBase {
|
|||
assertGraveyardCount(playerA, "Dismember", 1);
|
||||
assertGraveyardCount(playerB, "Banehound", 1);
|
||||
}
|
||||
|
||||
@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, "Yes"); // Pay 2 life for {B}
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
//PlayerA pays life
|
||||
assertLife(playerA, 18);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
|
||||
assertPermanentCount(playerA, "Banehound", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayerEffectNotUsableIfKrrikNotOnBattlefield() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
// ({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");
|
||||
|
||||
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);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4008,11 +4008,6 @@ public class TestPlayer implements Player {
|
|||
computerPlayer.addPhyrexianToColors(colors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePhyrexianFromColors(FilterMana colors) {
|
||||
computerPlayer.removePhyrexianFromColors(colors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterMana getPhyrexianColors() {
|
||||
return computerPlayer.getPhyrexianColors();
|
||||
|
|
|
@ -1408,11 +1408,6 @@ public class PlayerStub implements Player {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePhyrexianFromColors(FilterMana colors) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterMana getPhyrexianColors() {
|
||||
return (new FilterMana());
|
||||
|
|
|
@ -120,7 +120,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
}
|
||||
|
||||
Player player = game.getPlayer(controllerId);
|
||||
handleKrrikPhyrexianManaCosts(controllerId, ability, game);
|
||||
handleLikePhyrexianManaCosts(controllerId, ability, game); // e.g. K'rrik, Son of Yawgmoth
|
||||
if (!player.getManaPool().isForcedToPay()) {
|
||||
assignPayment(game, ability, player.getManaPool(), this);
|
||||
}
|
||||
|
@ -170,11 +170,6 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
|
||||
while (manaCostIterator.hasNext()) {
|
||||
ManaCost manaCost = manaCostIterator.next();
|
||||
PhyrexianManaCost tempPhyrexianCost = null;
|
||||
Mana mana = manaCost.getMana();
|
||||
|
||||
FilterMana phyrexianColors = player.getPhyrexianColors();
|
||||
|
||||
if (manaCost instanceof PhyrexianManaCost) {
|
||||
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) manaCost;
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
|
@ -189,7 +184,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
tempCosts.pay(source, game, source.getSourceId(), player.getId(), false, null);
|
||||
}
|
||||
|
||||
private void handleKrrikPhyrexianManaCosts(UUID payingPlayerId, Ability source, Game game) {
|
||||
private void handleLikePhyrexianManaCosts(UUID payingPlayerId, Ability source, Game game) {
|
||||
Player player = game.getPlayer(payingPlayerId);
|
||||
if (this == null || player == null) {
|
||||
return; // nothing to be done without any mana costs. prevents NRE from occurring here
|
||||
|
|
|
@ -932,10 +932,16 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
List<Designation> getDesignations();
|
||||
|
||||
/**
|
||||
* Set the mana colors the user can pay with 2 life instead
|
||||
* @param colors
|
||||
*/
|
||||
void addPhyrexianToColors(FilterMana colors);
|
||||
|
||||
void removePhyrexianFromColors(FilterMana colors);
|
||||
|
||||
/**
|
||||
* Mana colors the player can pay instead with 2 life
|
||||
* @return
|
||||
*/
|
||||
FilterMana getPhyrexianColors();
|
||||
|
||||
}
|
||||
|
|
|
@ -174,6 +174,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
protected List<Designation> designations = new ArrayList<>();
|
||||
|
||||
// mana colors the player can handle like Phyrexian mana
|
||||
protected FilterMana phyrexianColors;
|
||||
|
||||
// Used during available mana calculation to give back possible available net mana from triggered mana abilities (No need to copy)
|
||||
|
@ -196,7 +197,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
manaPool = new ManaPool(playerId);
|
||||
library = new Library(playerId);
|
||||
sideboard = new CardsImpl();
|
||||
phyrexianColors = new FilterMana();
|
||||
phyrexianColors = null;
|
||||
}
|
||||
|
||||
protected PlayerImpl(UUID id) {
|
||||
|
@ -279,8 +280,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.castSourceIdCosts.putAll(player.castSourceIdCosts);
|
||||
|
||||
this.payManaMode = player.payManaMode;
|
||||
this.phyrexianColors = player.phyrexianColors.copy();
|
||||
|
||||
this.phyrexianColors = player.getPhyrexianColors() != null ? player.phyrexianColors.copy() : null;
|
||||
this.designations.addAll(player.designations);
|
||||
}
|
||||
|
||||
|
@ -357,8 +357,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
for (Entry<UUID, Costs<Cost>> entry : player.getCastSourceIdCosts().entrySet()) {
|
||||
this.castSourceIdCosts.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
this.phyrexianColors = player.getPhyrexianColors().copy();
|
||||
|
||||
this.phyrexianColors = player.getPhyrexianColors() != null ? player.getPhyrexianColors().copy() : null;
|
||||
this.designations.clear();
|
||||
this.designations.addAll(player.getDesignations());
|
||||
|
||||
|
@ -434,7 +434,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.clearCastSourceIdManaCosts();
|
||||
|
||||
this.getManaPool().init(); // needed to remove mana that not empties on step change from previous game if left
|
||||
this.phyrexianColors = new FilterMana();
|
||||
this.phyrexianColors = null;
|
||||
|
||||
this.designations.clear();
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.alternativeSourceCosts.clear();
|
||||
this.clearCastSourceIdManaCosts();
|
||||
this.getManaPool().clearEmptyManaPoolRules();
|
||||
this.phyrexianColors = new FilterMana();
|
||||
this.phyrexianColors = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3115,6 +3115,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (availableMana == null) {
|
||||
return true;
|
||||
}
|
||||
// Check for pay option with like phyrexian mana
|
||||
if (getPhyrexianColors() != null) {
|
||||
addPhyrexianLikePayOptions(abilityOptions, availableMana, game);
|
||||
}
|
||||
|
||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(),
|
||||
AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game);
|
||||
for (Mana mana : abilityOptions) {
|
||||
|
@ -3137,6 +3142,49 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void addPhyrexianLikePayOptions(ManaOptions abilityOptions, ManaOptions availableMana, Game game) {
|
||||
int maxLifeMana = getLife() / 2;
|
||||
if (maxLifeMana > 0) {
|
||||
Set<Mana> phyrexianOptions = new HashSet<>();
|
||||
for (Mana mana : abilityOptions) {
|
||||
int availableLifeMana = maxLifeMana;
|
||||
if (getPhyrexianColors().isBlack()) {
|
||||
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.BLACK);
|
||||
}
|
||||
if (getPhyrexianColors().isBlue()) {
|
||||
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.BLUE);
|
||||
}
|
||||
if (getPhyrexianColors().isRed()) {
|
||||
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.RED);
|
||||
}
|
||||
if (getPhyrexianColors().isGreen()) {
|
||||
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.GREEN);
|
||||
}
|
||||
if (getPhyrexianColors().isWhite()) {
|
||||
createReducedManaPayOption(availableLifeMana, mana, phyrexianOptions, ManaType.WHITE);
|
||||
}
|
||||
}
|
||||
abilityOptions.addAll(phyrexianOptions);
|
||||
}
|
||||
}
|
||||
|
||||
private int createReducedManaPayOption(int availableLifeMana, Mana oldPayOption, Set<Mana> phyrexianOptions, ManaType manaType) {
|
||||
if (oldPayOption.get(manaType) > 0) {
|
||||
Mana manaCopy = oldPayOption.copy();
|
||||
int restVal;
|
||||
if (availableLifeMana > oldPayOption.get(manaType)) {
|
||||
restVal = 0;
|
||||
availableLifeMana -= oldPayOption.get(manaType);
|
||||
} else {
|
||||
restVal = oldPayOption.get(manaType) - availableLifeMana;
|
||||
availableLifeMana = 0;
|
||||
}
|
||||
manaCopy.set(manaType, restVal);
|
||||
phyrexianOptions.add(manaCopy);
|
||||
}
|
||||
return availableLifeMana;
|
||||
}
|
||||
|
||||
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions availableMana, Ability ability, Game game) {
|
||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||
Ability copyAbility; // for alternative cost and reduce tries
|
||||
|
@ -4544,39 +4592,24 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public void addPhyrexianToColors(FilterMana colors) {
|
||||
if (colors.isWhite()) {
|
||||
this.phyrexianColors.setWhite(true);
|
||||
}
|
||||
if (colors.isBlue()) {
|
||||
this.phyrexianColors.setBlue(true);
|
||||
}
|
||||
if (colors.isBlack()) {
|
||||
this.phyrexianColors.setBlack(true);
|
||||
}
|
||||
if (colors.isRed()) {
|
||||
this.phyrexianColors.setRed(true);
|
||||
}
|
||||
if (colors.isGreen()) {
|
||||
this.phyrexianColors.setGreen(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePhyrexianFromColors(FilterMana colors) {
|
||||
if (colors.isWhite()) {
|
||||
this.phyrexianColors.setWhite(false);
|
||||
}
|
||||
if (colors.isBlue()) {
|
||||
this.phyrexianColors.setBlue(false);
|
||||
}
|
||||
if (colors.isBlack()) {
|
||||
this.phyrexianColors.setBlack(false);
|
||||
}
|
||||
if (colors.isRed()) {
|
||||
this.phyrexianColors.setRed(false);
|
||||
}
|
||||
if (colors.isGreen()) {
|
||||
this.phyrexianColors.setGreen(false);
|
||||
if (phyrexianColors == null) {
|
||||
phyrexianColors = colors.copy();
|
||||
} else {
|
||||
if (colors.isWhite()) {
|
||||
this.phyrexianColors.setWhite(true);
|
||||
}
|
||||
if (colors.isBlue()) {
|
||||
this.phyrexianColors.setBlue(true);
|
||||
}
|
||||
if (colors.isBlack()) {
|
||||
this.phyrexianColors.setBlack(true);
|
||||
}
|
||||
if (colors.isRed()) {
|
||||
this.phyrexianColors.setRed(true);
|
||||
}
|
||||
if (colors.isGreen()) {
|
||||
this.phyrexianColors.setGreen(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -225,11 +225,6 @@ public class StubPlayer extends PlayerImpl implements Player {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePhyrexianFromColors(FilterMana colors) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterMana getPhyrexianColors() {
|
||||
return (new FilterMana());
|
||||
|
|
Loading…
Reference in a new issue