From e64de69a396d9fa4dd4f87bf593f9e12b236a4c2 Mon Sep 17 00:00:00 2001 From: drdev Date: Sun, 7 Sep 2014 21:54:12 +0000 Subject: [PATCH] Make it so X mana costs are paid using a pre-mana payment announcement --- .gitattributes | 1 - .../forge/game/mana/ManaCostBeingPaid.java | 16 ++ forge-gui/CHANGES.txt | 9 +- .../java/forge/match/input/InputPayManaX.java | 184 ------------------ .../src/main/java/forge/player/HumanPlay.java | 25 +-- .../forge/player/HumanPlaySpellAbility.java | 22 ++- 6 files changed, 40 insertions(+), 217 deletions(-) delete mode 100644 forge-gui/src/main/java/forge/match/input/InputPayManaX.java diff --git a/.gitattributes b/.gitattributes index 20290fd7627..0b71d34959f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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/InputPayManaOfCostPayment.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/InputProliferate.java -text forge-gui/src/main/java/forge/match/input/InputProxy.java -text diff --git a/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java b/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java index ff804c46b19..8abc988c308 100644 --- a/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java +++ b/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java @@ -31,6 +31,8 @@ import forge.util.maps.MapToAmount; import java.util.*; import java.util.Map.Entry; +import org.apache.commons.lang3.StringUtils; + /** *

* ManaCostBeingPaid class. @@ -215,6 +217,20 @@ public class ManaCostBeingPaid { 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) { increaseShard(ManaCostShard.COLORLESS, manaToAdd); } diff --git a/forge-gui/CHANGES.txt b/forge-gui/CHANGES.txt index ad916f0b2f3..6a1894b86e7 100644 --- a/forge-gui/CHANGES.txt +++ b/forge-gui/CHANGES.txt @@ -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 dialog for the commander replacement effect will now display the commander's name. + - Momir Basic variant type - 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 -- Auto-pay support 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 -If you press Auto, you'll be prompted to pick a value for X, with it defaulting to the maximum value you can afford. -If you press OK on that prompt, Forge will use AI logic to automatically pay whatever value for X you chose. - +- Choose value for X mana costs - +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. +This also applies to spells with Replicate and Multikicker to allow picking the Replicate or Multikicker amount prior to paying the final mana cost. - 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. diff --git a/forge-gui/src/main/java/forge/match/input/InputPayManaX.java b/forge-gui/src/main/java/forge/match/input/InputPayManaX.java deleted file mode 100644 index a10956f222c..00000000000 --- a/forge-gui/src/main/java/forge/match/input/InputPayManaX.java +++ /dev/null @@ -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 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 list = new ArrayList(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 proc = new Evaluator() { - @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()); - } -} diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index d76c274fe8c..09c0d61d9da 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -4,9 +4,7 @@ import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import forge.FThreads; -import forge.card.MagicColor; import forge.card.mana.ManaCost; -import forge.card.mana.ManaCostShard; import forge.game.Game; import forge.game.GameActionUtil; import forge.game.GameLogEntryType; @@ -27,7 +25,6 @@ import forge.game.zone.ZoneType; import forge.match.input.InputPayMana; import forge.match.input.InputPayManaOfCostPayment; import forge.match.input.InputPayManaSimple; -import forge.match.input.InputPayManaX; import forge.match.input.InputSelectCardsFromList; import forge.util.Lang; import forge.util.gui.SGuiChoose; @@ -42,7 +39,6 @@ import java.util.Map; public class HumanPlay { public HumanPlay() { - // TODO Auto-generated constructor stub } /** @@ -694,14 +690,12 @@ public class HumanPlay { final Card source = ability.getHostCard(); ManaCostBeingPaid toPay = new ManaCostBeingPaid(realCost, mc.getRestiction()); - boolean xWasBilled = false; String xInCard = source.getSVar("X"); 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 - int xCost = AbilityUtils.calculateAmount(source, "X", ability) * mc.getAmountOfX(); - byte xColor = MagicColor.fromName(ability.hasParam("XColor") ? ability.getParam("XColor") : "1"); - toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost); - xWasBilled = true; + int xPaid = AbilityUtils.calculateAmount(source, "X", ability); + toPay.setXManaCostPaid(xPaid, ability.getParam("XColor")); + source.setXManaCostPaid(xPaid); } int timesMultikicked = source.getKickerMagnitude(); @@ -740,19 +734,6 @@ public class HumanPlay { source.setColorsPaid(toPay.getColorsPaid()); 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 if (ability.isOffering() && ability.getSacrificedAsOffering() != null) { diff --git a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java index c8eea877fb2..f51dd8de69a 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java +++ b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java @@ -195,20 +195,22 @@ public class HumanPlaySpellAbility { private boolean announceValuesLikeX() { 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 // SA Params as comma delimited list String announce = ability.getParam("Announce"); 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(",")) { String varName = aVar.trim(); boolean isX = "X".equalsIgnoreCase(varName); + if (isX) { needX = false; } Integer value = controller.announceRequirements(ability, varName, allowZero && (!isX || manaCost == null || manaCost.canXbe0())); 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; }