Make it so X mana costs are paid using a pre-mana payment announcement

This commit is contained in:
drdev
2014-09-07 21:54:12 +00:00
parent 407bc67af9
commit e64de69a39
6 changed files with 40 additions and 217 deletions

1
.gitattributes vendored
View File

@@ -16734,7 +16734,6 @@ forge-gui/src/main/java/forge/match/input/InputPassPriority.java -text
forge-gui/src/main/java/forge/match/input/InputPayMana.java -text forge-gui/src/main/java/forge/match/input/InputPayMana.java -text
forge-gui/src/main/java/forge/match/input/InputPayManaOfCostPayment.java -text forge-gui/src/main/java/forge/match/input/InputPayManaOfCostPayment.java -text
forge-gui/src/main/java/forge/match/input/InputPayManaSimple.java -text forge-gui/src/main/java/forge/match/input/InputPayManaSimple.java -text
forge-gui/src/main/java/forge/match/input/InputPayManaX.java -text
forge-gui/src/main/java/forge/match/input/InputPlaybackControl.java -text forge-gui/src/main/java/forge/match/input/InputPlaybackControl.java -text
forge-gui/src/main/java/forge/match/input/InputProliferate.java -text forge-gui/src/main/java/forge/match/input/InputProliferate.java -text
forge-gui/src/main/java/forge/match/input/InputProxy.java -text forge-gui/src/main/java/forge/match/input/InputProxy.java -text

View File

@@ -31,6 +31,8 @@ import forge.util.maps.MapToAmount;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
/** /**
* <p> * <p>
* ManaCostBeingPaid class. * ManaCostBeingPaid class.
@@ -215,6 +217,20 @@ public class ManaCostBeingPaid {
return unpaidShards.isEmpty(); return unpaidShards.isEmpty();
} }
public final void setXManaCostPaid(final int xPaid, final String xColor) {
int xCost = xPaid * cntX;
cntX = 0;
ManaCostShard increaseShard;
if (StringUtils.isEmpty(xColor)) {
increaseShard = ManaCostShard.COLORLESS;
}
else {
increaseShard = ManaCostShard.valueOf(MagicColor.fromName(xColor));
}
unpaidShards.add(increaseShard, xCost);
}
public final void increaseColorlessMana(final int manaToAdd) { public final void increaseColorlessMana(final int manaToAdd) {
increaseShard(ManaCostShard.COLORLESS, manaToAdd); increaseShard(ManaCostShard.COLORLESS, manaToAdd);
} }

View File

@@ -13,16 +13,15 @@ There will no longer be a black rectangle for "Commander effect" in the command
The details previously available by hovering over that rectangle will now appear when hovering over the commander itself. The details previously available by hovering over that rectangle will now appear when hovering over the commander itself.
The dialog for the commander replacement effect will now display the commander's name. The dialog for the commander replacement effect will now display the commander's name.
- Momir Basic variant type - - Momir Basic variant type -
Momir Basic is now available as its own variant option on the Constructed screen Momir Basic is now available as its own variant option on the Constructed screen
For this format. each player will automatically be given a deck with 12 of each basic land and the Momir Vig avatar For this format. each player will automatically be given a deck with 12 of each basic land and the Momir Vig avatar
- Auto-pay support for X mana costs - - Choose value for X mana costs -
When prompted to choose a value for X when paying a mana cost, the left button will now as display "Auto" until you manually click a mana source Now, when playing spells/abilities with X in its mana cost, you will now be prompted for a value for X prior to mana payment, ensuring the final mana cost is calculated properly from cost adjustment effects and allowing using the "Auto" button to pay the entire cost.
If you press Auto, you'll be prompted to pick a value for X, with it defaulting to the maximum value you can afford. This also applies to spells with Replicate and Multikicker to allow picking the Replicate or Multikicker amount prior to paying the final mana cost.
If you press OK on that prompt, Forge will use AI logic to automatically pay whatever value for X you chose.
- Auto-targeting support - - Auto-targeting support -
When playing spells and abilities with the text "target opponent", if you only have one opponent, you will no longer be asked to choose the opponent to target. When playing spells and abilities with the text "target opponent", if you only have one opponent, you will no longer be asked to choose the opponent to target.

View File

@@ -1,184 +0,0 @@
package forge.match.input;
import forge.ai.ComputerUtilMana;
import forge.card.ColorSet;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser;
import forge.game.card.Card;
import forge.game.mana.Mana;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.spellability.SpellAbility;
import forge.util.Evaluator;
import forge.util.ITriggerEvent;
import forge.util.ThreadUtil;
import forge.util.gui.SGuiChoose;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class InputPayManaX extends InputPayMana {
private static final long serialVersionUID = -6900234444347364050L;
private int xPaid = 0;
private ArrayList<Mana> xPaidByColor = new ArrayList<>();
private byte colorsPaid;
private final String xCostStr;
private final ManaCost manaCostPerX;
private final boolean xCanBe0;
private boolean canceled = false;
private Integer max;
public InputPayManaX(final SpellAbility sa0, final int amountX, final boolean xCanBe0) {
super(sa0, sa0.getActivatingPlayer());
xPaid = 0;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < amountX; i++) {
builder.append("{X}");
}
xCostStr = builder.toString();
if (saPaidFor.hasParam("XColor")) {
String xColor = saPaidFor.getParam("XColor");
if (amountX == 1) {
manaCostPerX = new ManaCost(new ManaCostParser(xColor));
}
else {
List<String> list = new ArrayList<String>(amountX);
for (int i = 0; i < amountX; i++) {
list.add(xColor);
}
manaCostPerX = new ManaCost(new ManaCostParser(StringUtils.join(list, ' ')));
}
}
else {
manaCostPerX = ManaCost.get(amountX);
}
manaCost = new ManaCostBeingPaid(manaCostPerX);
this.xCanBe0 = xCanBe0;
colorsPaid = saPaidFor.getHostCard().getColorsPaid(); // for effects like sunburst
canPayManaCost = true; //flag as true always since it doesn't need to be calculated using AI logic
}
/* (non-Javadoc)
* @see forge.control.input.InputPayManaBase#isPaid()
*/
@Override
public boolean isPaid() {
//return !( xPaid == 0 && !costMana.canXbe0() || this.colorX.equals("") && !this.manaCost.toString().equals(strX) );
// return !( xPaid == 0 && !costMana.canXbe0()) && !(this.colorX.equals("") && !this.manaCost.toString().equals(strX));
return !canceled && (xPaid > 0 || xCanBe0);
}
@Override
protected boolean supportAutoPay() {
return xPaid == 0;
}
@Override
public void showMessage() {
if (isFinished()) { return; }
updateMessage();
}
@Override
protected String getMessage() {
StringBuilder msg = new StringBuilder("Pay " + xCostStr + ". X=" + xPaid + ".");
if (xPaid > 0) {
// Enable just cancel is full X value hasn't been paid for multiple X values
// or X is 0, and x can't be 0
ButtonUtil.update(isPaid(), true, true);
}
if (!xCanBe0) {
msg.append("\nX Can't be 0.");
}
return msg.toString();
}
@Override
protected boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
// don't allow here the cards that produce only wrong colors
return activateManaAbility(card, this.manaCost);
}
@Override
protected void onManaAbilityPaid() {
if (this.manaCost.isPaid()) {
this.colorsPaid |= manaCost.getColorsPaid();
this.manaCost = new ManaCostBeingPaid(manaCostPerX);
this.xPaid++;
this.xPaidByColor.add(saPaidFor.getPayingMana().get(0));
}
}
@Override
protected final void onCancel() {
// If you hit cancel, isPaid needs to return false
this.canceled = true;
this.stop();
}
@Override
protected final void onOk() {
if (supportAutoPay()) {
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
int min = xCanBe0 ? 0 : 1;
if (max == null) {
//use AI utility to determine maximum possible value for X if that hasn't been determined yet
Evaluator<Integer> proc = new Evaluator<Integer>() {
@Override
public Integer evaluate() {
ManaCostBeingPaid cost = new ManaCostBeingPaid(manaCostPerX);
for (int i = 1; i < 100; i++) {
if (!ComputerUtilMana.canPayManaCost(cost, saPaidFor, player)) {
return i - 1;
}
cost.addManaCost(manaCostPerX);
}
return 99;
}
};
runAsAi(proc);
max = proc.getResult();
}
Integer value = SGuiChoose.getInteger("Choose a value for X", min, max, true);
if (value != null) {
xPaid = value;
saPaidFor.getHostCard().setXManaCostPaid(xPaid);
if (xPaid > 0) {
final ManaCostBeingPaid cost = new ManaCostBeingPaid(manaCostPerX);
for (int i = 1; i < xPaid; i++) {
cost.addManaCost(manaCostPerX);
}
runAsAi(new Runnable() {
@Override
public void run() {
ComputerUtilMana.payManaCost(cost, saPaidFor, player);
}
});
}
stop();
}
}
});
}
else {
done();
stop();
}
}
@Override
protected void done() {
final Card card = saPaidFor.getHostCard();
card.setXManaCostPaid(this.xPaid);
card.setXManaCostPaidByColor(this.xPaidByColor);
card.setColorsPaid(this.colorsPaid);
card.setSunburstValue(ColorSet.fromMask(this.colorsPaid).countColors());
}
}

View File

@@ -4,9 +4,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.FThreads; import forge.FThreads;
import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
@@ -27,7 +25,6 @@ import forge.game.zone.ZoneType;
import forge.match.input.InputPayMana; import forge.match.input.InputPayMana;
import forge.match.input.InputPayManaOfCostPayment; import forge.match.input.InputPayManaOfCostPayment;
import forge.match.input.InputPayManaSimple; import forge.match.input.InputPayManaSimple;
import forge.match.input.InputPayManaX;
import forge.match.input.InputSelectCardsFromList; import forge.match.input.InputSelectCardsFromList;
import forge.util.Lang; import forge.util.Lang;
import forge.util.gui.SGuiChoose; import forge.util.gui.SGuiChoose;
@@ -42,7 +39,6 @@ import java.util.Map;
public class HumanPlay { public class HumanPlay {
public HumanPlay() { public HumanPlay() {
// TODO Auto-generated constructor stub
} }
/** /**
@@ -694,14 +690,12 @@ public class HumanPlay {
final Card source = ability.getHostCard(); final Card source = ability.getHostCard();
ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction()); ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction());
boolean xWasBilled = false;
String xInCard = source.getSVar("X"); String xInCard = source.getSVar("X");
if (mc.getAmountOfX() > 0 && !"Count$xPaid".equals(xInCard)) { // announce X will overwrite whatever was in card script if (mc.getAmountOfX() > 0 && !"Count$xPaid".equals(xInCard)) { // announce X will overwrite whatever was in card script
// this currently only works for things about Targeted object // this currently only works for things about Targeted object
int xCost = AbilityUtils.calculateAmount(source, "X", ability) * mc.getAmountOfX(); int xPaid = AbilityUtils.calculateAmount(source, "X", ability);
byte xColor = MagicColor.fromName(ability.hasParam("XColor") ? ability.getParam("XColor") : "1"); toPay.setXManaCostPaid(xPaid, ability.getParam("XColor"));
toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost); source.setXManaCostPaid(xPaid);
xWasBilled = true;
} }
int timesMultikicked = source.getKickerMagnitude(); int timesMultikicked = source.getKickerMagnitude();
@@ -740,19 +734,6 @@ public class HumanPlay {
source.setColorsPaid(toPay.getColorsPaid()); source.setColorsPaid(toPay.getColorsPaid());
source.setSunburstValue(toPay.getSunburst()); source.setSunburstValue(toPay.getSunburst());
} }
if (mc.getAmountOfX() > 0) {
if (!ability.isAnnouncing("X") && !xWasBilled) {
source.setXManaCostPaid(0);
inpPayment = new InputPayManaX(ability, mc.getAmountOfX(), mc.canXbe0());
inpPayment.showAndWait();
if (!inpPayment.isPaid()) {
return false;
}
} else {
int x = AbilityUtils.calculateAmount(source, "X", ability);
source.setXManaCostPaid(x);
}
}
// Handle convoke and offerings // Handle convoke and offerings
if (ability.isOffering() && ability.getSacrificedAsOffering() != null) { if (ability.isOffering() && ability.getSacrificedAsOffering() != null) {

View File

@@ -195,20 +195,22 @@ public class HumanPlaySpellAbility {
private boolean announceValuesLikeX() { private boolean announceValuesLikeX() {
if (ability.isCopied()) { return true; } //don't re-announce for spell copies if (ability.isCopied()) { return true; } //don't re-announce for spell copies
boolean needX = true;
boolean allowZero = !ability.hasParam("XCantBe0");
CostPartMana manaCost = ability.getPayCosts().getCostMana();
PlayerController controller = ability.getActivatingPlayer().getController();
Card card = ability.getHostCard();
// Announcing Requirements like Choosing X or Multikicker // Announcing Requirements like Choosing X or Multikicker
// SA Params as comma delimited list // SA Params as comma delimited list
String announce = ability.getParam("Announce"); String announce = ability.getParam("Announce");
if (announce != null) { if (announce != null) {
PlayerController controller = ability.getActivatingPlayer().getController();
Card card = ability.getHostCard();
boolean allowZero = !ability.hasParam("XCantBe0");
CostPartMana manaCost = ability.getPayCosts().getCostMana();
for (String aVar : announce.split(",")) { for (String aVar : announce.split(",")) {
String varName = aVar.trim(); String varName = aVar.trim();
boolean isX = "X".equalsIgnoreCase(varName); boolean isX = "X".equalsIgnoreCase(varName);
if (isX) { needX = false; }
Integer value = controller.announceRequirements(ability, varName, allowZero && (!isX || manaCost == null || manaCost.canXbe0())); Integer value = controller.announceRequirements(ability, varName, allowZero && (!isX || manaCost == null || manaCost.canXbe0()));
if (value == null) { if (value == null) {
@@ -224,6 +226,16 @@ public class HumanPlaySpellAbility {
} }
} }
} }
if (needX && manaCost != null && manaCost.getAmountOfX() > 0) {
Integer value = controller.announceRequirements(ability, "X", allowZero && manaCost.canXbe0());
if (value == null) {
return false;
}
ability.setSVar("X", value.toString());
card.setSVar("X", value.toString());
}
return true; return true;
} }