Phyrexian mana now correctly a payment choice.

Per rule 601.2b, it is not determined at the pay costs step,
but at the "choice" step, long before costs are determined.

This fixes trinisphere interactions and should be consistent with the
rules.
This commit is contained in:
Nathaniel Brandes 2017-03-08 20:03:28 -08:00
parent 209e2d13c1
commit ce1f4a3bf8
47 changed files with 234 additions and 222 deletions

View file

@ -31,11 +31,9 @@ import mage.MageObject;
import mage.MageObjectReference;
import mage.Mana;
import mage.abilities.costs.*;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.costs.mana.*;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
@ -62,6 +60,7 @@ import mage.watchers.Watcher;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
@ -298,6 +297,9 @@ public abstract class AbilityImpl implements Ability {
&& game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) {
return false;
}
handlePhyrexianManaCosts(game, sourceId, controller);
for (UUID modeId : this.getModes().getSelectedModes()) {
this.getModes().setActiveMode(modeId);
//20121001 - 601.2c
@ -503,6 +505,27 @@ public abstract class AbilityImpl implements Ability {
return announceString.toString();
}
/**
* 601.2b
* If a cost that will be paid as the spell is being cast includes Phyrexian mana symbols,
* the player announces whether he or she intends to pay 2 life or the corresponding colored mana cost for each of those symbols.
*/
private void handlePhyrexianManaCosts(Game game, UUID sourceId, Player controller) {
Iterator<ManaCost> costIterator = manaCostsToPay.iterator();
while(costIterator.hasNext()) {
ManaCost cost = costIterator.next();
if(cost instanceof PhyrexianManaCost) {
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost)cost;
PayLifeCost payLifeCost = new PayLifeCost(2);
if(payLifeCost.canPay(this, sourceId, controller.getId(), game) &&
controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + "?", this, game)) {
costIterator.remove();
costs.add(payLifeCost);
}
}
}
}
/**
* Handles X mana costs and sets manaCostsToPay.
*

View file

@ -50,34 +50,20 @@ public class PhyrexianManaCost extends ColoredManaCost {
super(manaCost);
}
@Override
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) {
assignColored(ability, game, pool, this.mana, costToPay);
}
@Override
public String getText() {
return '{' + mana.toString() + "P}";
return '{' + mana.toString() + "/P}";
}
public String getBaseText() {
return super.getText();
}
@Override
public PhyrexianManaCost getUnpaid() {
return this;
public ColoredManaCost getUnpaid() {
return new ColoredManaCost(this);
}
@Override
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
if (!game.getPlayer(controllerId).isLifeTotalCanChange()) {
return false;
}
return game.getPlayer(controllerId).getLife() >= 2;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
this.paid = game.getPlayer(controllerId).loseLife(2, game, false) == 2;
return paid;
}
@Override
public PhyrexianManaCost copy() {

View file

@ -29,8 +29,13 @@ package mage.abilities.effects;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.PhyrexianManaCost;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
@ -38,6 +43,9 @@ import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.players.Player;
import java.util.Iterator;
import java.util.List;
/**
*
* @author LevelX2
@ -141,6 +149,7 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
attackBlockManaTax.clearPaid();
if (attackBlockManaTax.canPay(source, source.getSourceId(), player.getId(), game)
&& player.chooseUse(Outcome.Neutral, chooseText, source, game)) {
handlePhyrexianManaCosts(manaCosts, player, source, game);
if (attackBlockManaTax instanceof ManaCostsImpl) {
if (attackBlockManaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
return false;
@ -152,6 +161,27 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
return false;
}
private void handlePhyrexianManaCosts(ManaCosts<ManaCost> manaCosts, Player player, Ability source, Game game) {
Iterator<ManaCost> manaCostIterator = manaCosts.iterator();
Costs<PayLifeCost> costs = new CostsImpl<>();
while(manaCostIterator.hasNext()) {
ManaCost manaCost = manaCostIterator.next();
if(manaCost instanceof PhyrexianManaCost) {
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost)manaCost;
PayLifeCost payLifeCost = new PayLifeCost(2);
if(payLifeCost.canPay(source, source.getSourceId(), player.getId(), game) &&
player.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + "?", source, game)) {
manaCostIterator.remove();
costs.add(payLifeCost);
}
}
}
costs.pay(source, game, source.getSourceId(), player.getId(), false, null);
}
private boolean handleOtherCosts(Cost attackBlockOtherTax, GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if (player != null) {

View file

@ -2438,7 +2438,9 @@ public abstract class PlayerImpl implements Player, Serializable {
if (!copy.canActivate(playerId, game)) {
return false;
}
game.getContinuousEffects().costModification(copy, game);
if(available != null) {
game.getContinuousEffects().costModification(copy, game);
}
Card card = game.getCard(ability.getSourceId());
if (card != null) {