diff --git a/.gitattributes b/.gitattributes index 6ed5e4648b8..979588981cd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13812,6 +13812,7 @@ src/main/java/forge/control/input/InputPayManaSimple.java svneol=native#text/pla src/main/java/forge/control/input/InputPayManaX.java -text src/main/java/forge/control/input/InputPayReturnCost.java -text src/main/java/forge/control/input/InputPaySacCost.java -text +src/main/java/forge/control/input/InputPayment.java -text src/main/java/forge/control/input/InputSelectMany.java -text src/main/java/forge/control/input/InputSelectManyCards.java -text src/main/java/forge/control/input/InputSelectManyPlayers.java -text diff --git a/src/main/java/forge/card/cardfactory/CardFactorySorceries.java b/src/main/java/forge/card/cardfactory/CardFactorySorceries.java index d79de33be2d..4c9cc11debe 100644 --- a/src/main/java/forge/card/cardfactory/CardFactorySorceries.java +++ b/src/main/java/forge/card/cardfactory/CardFactorySorceries.java @@ -23,6 +23,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; +import java.util.concurrent.CountDownLatch; + import javax.swing.JOptionPane; import com.google.common.collect.Iterables; @@ -30,8 +32,8 @@ import com.google.common.collect.Iterables; import forge.Card; import forge.CardLists; import forge.CardPredicates; +import forge.FThreads; import forge.CardPredicates.Presets; -import forge.Command; import forge.Constant; import forge.Singletons; import forge.card.CardType; @@ -461,21 +463,13 @@ public class CardFactorySorceries { game.getAction().moveToPlay(newArtifact[0]); } else { final String diffCost = String.valueOf(newCMC - baseCMC); - Singletons.getModel().getMatch().getInput().setInput(new InputPayManaExecuteCommands(game, "Pay difference in artifacts CMC", diffCost, new Command() { - private static final long serialVersionUID = -8729850321341068049L; - - @Override - public void execute() { - Singletons.getModel().getGame().getAction().moveToPlay(newArtifact[0]); - } - }, new Command() { - private static final long serialVersionUID = -246036834856971935L; - - @Override - public void execute() { - Singletons.getModel().getGame().getAction().moveToGraveyard(newArtifact[0]); - } - })); + final CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, "Pay difference in artifacts CMC", diffCost, cdl); + FThreads.setInputAndWait(inp, cdl); + if ( inp.isPaid() ) + Singletons.getModel().getGame().getAction().moveToPlay(newArtifact[0]); + else + Singletons.getModel().getGame().getAction().moveToGraveyard(newArtifact[0]); } // finally, shuffle library diff --git a/src/main/java/forge/card/mana/ManaCost.java b/src/main/java/forge/card/mana/ManaCost.java index 2fab180f2ab..a4b64035b24 100644 --- a/src/main/java/forge/card/mana/ManaCost.java +++ b/src/main/java/forge/card/mana/ManaCost.java @@ -44,7 +44,22 @@ public final class ManaCost implements Comparable { public static final ManaCost NO_COST = new ManaCost(-1); public static final ManaCost ZERO = new ManaCost(0); public static final ManaCost ONE = new ManaCost(1); + public static final ManaCost TWO = new ManaCost(2); + public static final ManaCost THREE = new ManaCost(3); + public static final ManaCost FOUR = new ManaCost(4); + public static ManaCost get(int cntColorless) { + if(cntColorless >= 5 || cntColorless < 0) throw new IllegalArgumentException("Supports only 0-4"); + switch (cntColorless) { + case 0: return ZERO; + case 1: return ONE; + case 2: return TWO; + case 3: return THREE; + case 4: return FOUR; + default: return NO_COST; + } + } + // pass mana cost parser here private ManaCost(int cmc) { this.hasNoCost = cmc < 0; diff --git a/src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java b/src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java index 09137103c7e..9e7ee1b9bdd 100644 --- a/src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java +++ b/src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java @@ -18,10 +18,10 @@ package forge.control.input; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; -import forge.Command; import forge.Singletons; import forge.card.cardfactory.CardFactoryUtil; import forge.card.cost.CostDiscard; @@ -42,7 +42,7 @@ import forge.view.ButtonUtil; * @author Forge * @version $Id: InputPayManaCostAbility.java 15673 2012-05-23 14:01:35Z ArsenalNut $ */ -public class InputPayDiscardCostWithCommands extends Input { +public class InputPayDiscardCostWithCommands extends Input implements InputPayment { /** * Constant serialVersionUID=2685832214529141991L. */ @@ -53,8 +53,10 @@ public class InputPayDiscardCostWithCommands extends Input { private List choiceList; private CostDiscard discardCost; private SpellAbility ability; - private Command paid; - private Command unpaid; + private boolean bPaid; + + private final CountDownLatch cdlDone; + public final boolean isPaid() { return bPaid; } /** *

@@ -70,19 +72,16 @@ public class InputPayDiscardCostWithCommands extends Input { * @param unpaidCommand * a {@link forge.Command} object. */ - public InputPayDiscardCostWithCommands(final CostDiscard cost, final SpellAbility sa, final Command paidCommand, - final Command unpaidCommand) { + public InputPayDiscardCostWithCommands(final CostDiscard cost, final SpellAbility sa, final CountDownLatch cdl) { final Card source = sa.getSourceCard(); final Player human = Singletons.getControl().getPlayer(); - + this.cdlDone = cdl; this.ability = sa; this.discardCost = cost; this.choiceList = CardLists.getValidCards(human.getCardsIn(ZoneType.Hand), cost.getType().split(";"), human, source); String amountString = cost.getAmount(); this.numRequired = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString)); - this.paid = paidCommand; - this.unpaid = unpaidCommand; } /** {@inheritDoc} */ @@ -168,7 +167,10 @@ public class InputPayDiscardCostWithCommands extends Input { Singletons.getControl().getPlayer().discard(selected, this.ability); } this.discardCost.addListToHash(ability, "Discarded"); - this.paid.execute(); + bPaid = true; + cdlDone.countDown(); + + } /** @@ -182,7 +184,8 @@ public class InputPayDiscardCostWithCommands extends Input { for (Card selected : this.discardCost.getList()) { selected.setUsedToPay(false); } - this.unpaid.execute(); + bPaid = false; + cdlDone.countDown(); } @Override public void isClassUpdated() { diff --git a/src/main/java/forge/control/input/InputPayManaExecuteCommands.java b/src/main/java/forge/control/input/InputPayManaExecuteCommands.java index 57e1bc7bda5..312fea8697a 100644 --- a/src/main/java/forge/control/input/InputPayManaExecuteCommands.java +++ b/src/main/java/forge/control/input/InputPayManaExecuteCommands.java @@ -17,7 +17,8 @@ */ package forge.control.input; -import forge.Command; +import java.util.concurrent.CountDownLatch; + import forge.Singletons; import forge.card.mana.ManaCostBeingPaid; import forge.card.spellability.SpellAbility; @@ -36,18 +37,19 @@ import forge.view.ButtonUtil; * @author Forge * @version $Id$ */ -public class InputPayManaExecuteCommands extends InputPayManaBase { +public class InputPayManaExecuteCommands extends InputPayManaBase implements InputPayment { /** * Constant serialVersionUID=3836655722696348713L. */ private static final long serialVersionUID = 3836655722696348713L; + final private CountDownLatch cdlDone; + private String originalManaCost; private String message = ""; - - private Command paidCommand; - private Command unpaidCommand; + private boolean bPaid = false; + public boolean isPaid() { return bPaid; } // only used for X costs: private boolean showOnlyOKButton = false; @@ -67,8 +69,8 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { * @param unpaidCommand2 * a {@link forge.Command} object. */ - public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final Command paidCommand2, final Command unpaidCommand2) { - this(game, prompt, manaCost2, paidCommand2, unpaidCommand2, false); + public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final CountDownLatch cdl) { + this(game, prompt, manaCost2, cdl, false); } /** @@ -87,7 +89,7 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { * @param showOKButton * a boolean. */ - public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final Command paid, final Command unpaid, final boolean showOKButton) { + public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final CountDownLatch cdl, final boolean showOKButton) { super(game, new SpellAbility(null) { @Override public void resolve() {} @@ -98,10 +100,9 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { this.originalManaCost = manaCost2; this.phyLifeToLose = 0; this.message = prompt; + this.cdlDone = cdl; this.manaCost = new ManaCostBeingPaid(this.originalManaCost); - this.paidCommand = paid; - this.unpaidCommand = unpaid; this.showOnlyOKButton = showOKButton; } @@ -134,19 +135,22 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { if (this.phyLifeToLose > 0) { Singletons.getControl().getPlayer().payLife(this.phyLifeToLose, null); } - this.paidCommand.execute(); this.resetManaCost(); Singletons.getControl().getPlayer().getManaPool().clearManaPaid(this.saPaidFor, false); + bPaid = true; this.stop(); + cdlDone.countDown(); } /** {@inheritDoc} */ @Override public final void selectButtonCancel() { - this.unpaidCommand.execute(); + this.resetManaCost(); Singletons.getControl().getPlayer().getManaPool().refundManaPaid(this.saPaidFor, true); + bPaid = false; this.stop(); + cdlDone.countDown(); } /** {@inheritDoc} */ @@ -154,7 +158,9 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { public final void selectButtonOK() { if (this.showOnlyOKButton) { this.stop(); - this.unpaidCommand.execute(); + bPaid = false; + cdlDone.countDown(); + } } diff --git a/src/main/java/forge/control/input/InputPayReturnCost.java b/src/main/java/forge/control/input/InputPayReturnCost.java index 7793f08336e..35ccf2077f1 100644 --- a/src/main/java/forge/control/input/InputPayReturnCost.java +++ b/src/main/java/forge/control/input/InputPayReturnCost.java @@ -18,10 +18,10 @@ package forge.control.input; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; -import forge.Command; import forge.Singletons; import forge.card.cardfactory.CardFactoryUtil; import forge.card.cost.CostReturn; @@ -41,7 +41,7 @@ import forge.view.ButtonUtil; * @author Forge * @version $Id: InputPayManaCostAbility.java 15673 2012-05-23 14:01:35Z ArsenalNut $ */ -public class InputPayReturnCost extends Input { +public class InputPayReturnCost extends Input implements InputPayment { /** * Constant serialVersionUID=2685832214529141991L. */ @@ -52,8 +52,11 @@ public class InputPayReturnCost extends Input { private List choiceList; private CostReturn returnCost; private SpellAbility ability; - private Command paid; - private Command unpaid; + + private boolean bPaid; + public boolean isPaid() { return bPaid; } + + private final CountDownLatch cdlDone; /** *

@@ -69,18 +72,16 @@ public class InputPayReturnCost extends Input { * @param unpaidCommand * a {@link forge.Command} object. */ - public InputPayReturnCost(final CostReturn cost, final SpellAbility sa, final Command paidCommand, - final Command unpaidCommand) { + public InputPayReturnCost(final CostReturn cost, final SpellAbility sa, final CountDownLatch cdl) { final Card source = sa.getSourceCard(); + this.cdlDone = cdl; this.ability = sa; this.returnCost = cost; this.choiceList = CardLists.getValidCards(Singletons.getControl().getPlayer().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), Singletons.getControl().getPlayer(), source); String amountString = cost.getAmount(); this.numRequired = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString)); - this.paid = paidCommand; - this.unpaid = unpaidCommand; } /** {@inheritDoc} */ @@ -168,7 +169,8 @@ public class InputPayReturnCost extends Input { Singletons.getModel().getGame().getAction().moveTo(ZoneType.Hand, selected); } this.returnCost.addListToHash(ability, "Returned"); - this.paid.execute(); + bPaid = true; + cdlDone.countDown(); } /** @@ -182,7 +184,8 @@ public class InputPayReturnCost extends Input { for (Card selected : this.returnCost.getList()) { selected.setUsedToPay(false); } - this.unpaid.execute(); + bPaid = false; + cdlDone.countDown(); } @Override public void isClassUpdated() { diff --git a/src/main/java/forge/control/input/InputPayment.java b/src/main/java/forge/control/input/InputPayment.java new file mode 100644 index 00000000000..58f5dea23df --- /dev/null +++ b/src/main/java/forge/control/input/InputPayment.java @@ -0,0 +1,5 @@ +package forge.control.input; + +public interface InputPayment { + boolean isPaid(); +} \ No newline at end of file diff --git a/src/main/java/forge/game/GameActionUtil.java b/src/main/java/forge/game/GameActionUtil.java index 3696462f2b9..3a6fa2cb8f5 100644 --- a/src/main/java/forge/game/GameActionUtil.java +++ b/src/main/java/forge/game/GameActionUtil.java @@ -20,6 +20,7 @@ package forge.game; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.concurrent.CountDownLatch; import org.apache.commons.lang3.StringUtils; @@ -34,6 +35,7 @@ import forge.CardUtil; import forge.Command; import forge.Constant; import forge.CounterType; +import forge.FThreads; import forge.Singletons; import forge.card.ability.AbilityFactory; import forge.card.ability.AbilityUtils; @@ -61,6 +63,7 @@ import forge.control.input.Input; import forge.control.input.InputPayDiscardCostWithCommands; import forge.control.input.InputPayManaExecuteCommands; import forge.control.input.InputPayReturnCost; +import forge.control.input.InputPayment; import forge.game.event.CardDamagedEvent; import forge.game.event.LifeLossEvent; import forge.game.player.AIPlayer; @@ -367,31 +370,6 @@ public final class GameActionUtil { ripple.execute(); } - /** - *

- * payManaDuringAbilityResolve. - *

- * - * @param message - * a {@link java.lang.String} object. - * @param spellManaCost - * a {@link java.lang.String} object. - * @param paid - * a {@link forge.Command} object. - * @param unpaid - * a {@link forge.Command} object. - */ - public static void payManaDuringAbilityResolve(final String message, final ManaCost spellManaCost, final Command paid, - final Command unpaid) { - // temporarily disable the Resolve flag, so the user can payMana for the - // resolving Ability - GameState game = Singletons.getModel().getGame(); - final boolean bResolving = game.getStack().isResolving(); - game.getStack().setResolving(false); - Singletons.getModel().getMatch().getInput().setInput(new InputPayManaExecuteCommands(game, message, spellManaCost.toString(), paid, unpaid)); - game.getStack().setResolving(bResolving); - } - /** *

* payCostDuringAbilityResolve. @@ -597,25 +575,28 @@ public final class GameActionUtil { // interface for sacrifice costs (instead of the menu-based one above). //the following costs need inputs and can't be combined at the moment + + Input toSet = null; + CountDownLatch cdl = new CountDownLatch(1); if (costPart instanceof CostReturn) { - toSet = new InputPayReturnCost((CostReturn) costPart, ability, paid, unpaid); + toSet = new InputPayReturnCost((CostReturn) costPart, ability, cdl); } else if (costPart instanceof CostDiscard) { - toSet = new InputPayDiscardCostWithCommands((CostDiscard) costPart, ability, paid, unpaid); + toSet = new InputPayDiscardCostWithCommands((CostDiscard) costPart, ability, cdl); } else if (costPart instanceof CostPartMana) { - toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost().toString(), paid, unpaid); + toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost().toString(), cdl); } - if (toSet != null) { - // temporarily disable the Resolve flag, so the user can payMana for the - // resolving Ability - final boolean bResolving = Singletons.getModel().getGame().getStack().isResolving(); - Singletons.getModel().getGame().getStack().setResolving(false); - Singletons.getModel().getMatch().getInput().setInput(toSet); - Singletons.getModel().getGame().getStack().setResolving(bResolving); + + FThreads.setInputAndWait(toSet, cdl); + if (((InputPayment)toSet).isPaid() ) { + paid.execute(); + } else { + unpaid.execute(); + } } } diff --git a/src/main/java/forge/game/phase/Upkeep.java b/src/main/java/forge/game/phase/Upkeep.java index ed5623d075d..3a6ca57d4d5 100644 --- a/src/main/java/forge/game/phase/Upkeep.java +++ b/src/main/java/forge/game/phase/Upkeep.java @@ -21,12 +21,14 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CountDownLatch; import com.google.common.base.Predicate; import forge.Card; import forge.CardLists; import forge.CardPredicates; +import forge.FThreads; import forge.CardPredicates.Presets; import forge.Command; import forge.CounterType; @@ -40,6 +42,7 @@ import forge.card.spellability.AbilityManaPart; import forge.card.spellability.AbilityStatic; import forge.card.spellability.SpellAbility; import forge.control.input.Input; +import forge.control.input.InputPayManaExecuteCommands; import forge.control.input.InputSelectManyCards; import forge.game.GameActionUtil; import forge.game.GameState; @@ -279,44 +282,35 @@ public class Upkeep extends Phase { final String[] k = ability.split(" pay "); final ManaCost upkeepCost = new ManaCost(new ManaCostParser(k[1])); - final Command unpaidCommand = new Command() { - private static final long serialVersionUID = 8942537892273123542L; - - @Override - public void execute() { - if (c.getName().equals("Cosmic Horror")) { - controller.addDamage(7, c); - } - game.getAction().destroy(c); - } - }; - - final Command paidCommand = Command.BLANK; - - final Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString()); - - final StringBuilder sb = new StringBuilder(); - sb.append("Upkeep for ").append(c).append("\n"); + final String sb = "Upkeep for " + c; final Ability upkeepAbility = new Ability(c, ManaCost.ZERO) { @Override public void resolve() { + final boolean isUpkeepPaid; if (controller.isHuman()) { - GameActionUtil.payManaDuringAbilityResolve(sb.toString(), upkeepCost, paidCommand, unpaidCommand); + CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, sb, upkeepCost.toString(), cdl); + FThreads.setInputAndWait(inp, cdl); + isUpkeepPaid = inp.isPaid(); } else { // computer - if (ComputerUtilCost.canPayCost(aiPaid, controller) && !c.hasKeyword("Indestructible")) { + Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString()); + isUpkeepPaid = ComputerUtilCost.canPayCost(aiPaid, controller) && !c.hasKeyword("Indestructible"); + if (isUpkeepPaid) { ComputerUtil.playNoStack((AIPlayer)controller, aiPaid, game); - } else { - if (c.getName().equals("Cosmic Horror")) { - controller.addDamage(7, c); - } - game.getAction().destroy(c); } } + if( !isUpkeepPaid ) { + if (c.getName().equals("Cosmic Horror")) { + controller.addDamage(7, c); + } + game.getAction().destroy(c); + } + } }; upkeepAbility.setActivatingPlayer(controller); - upkeepAbility.setStackDescription(sb.toString()); - upkeepAbility.setDescription(sb.toString()); + upkeepAbility.setStackDescription(sb); + upkeepAbility.setDescription(sb); game.getStack().addSimultaneousStackEntry(upkeepAbility); } // destroy @@ -386,34 +380,26 @@ public class Upkeep extends Phase { final String[] l = k[1].split(" pay "); final ManaCost upkeepCost = new ManaCost(new ManaCostParser(l[1])); - final Command unpaidCommand = new Command() { - private static final long serialVersionUID = 1238166187561501928L; - - @Override - public void execute() { - controller.addDamage(upkeepDamage, c); - } - }; - - final Command paidCommand = Command.BLANK; - - final Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString()); - - final StringBuilder sb = new StringBuilder(); - sb.append("Damage upkeep for ").append(c).append("\n"); + final String sb = "Damage upkeep for " + c; final Ability upkeepAbility = new Ability(c, ManaCost.ZERO) { @Override public void resolve() { + boolean isUpkeepPaid = false; if (controller.isHuman()) { - GameActionUtil.payManaDuringAbilityResolve(sb.toString(), upkeepCost, paidCommand, unpaidCommand); + CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, sb, upkeepCost.toString(), cdl); + FThreads.setInputAndWait(inp, cdl); + isUpkeepPaid = inp.isPaid(); } else { // computers - if (ComputerUtilCost.canPayCost(aiPaid, controller) - && (ComputerUtilCombat.predictDamageTo(controller, upkeepDamage, c, false) > 0)) { + final Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString()); + if (ComputerUtilCost.canPayCost(aiPaid, controller) && ComputerUtilCombat.predictDamageTo(controller, upkeepDamage, c, false) > 0) { ComputerUtil.playNoStack((AIPlayer)controller, aiPaid, game); - } else { - controller.addDamage(upkeepDamage, c); + isUpkeepPaid = true; } } + if (!isUpkeepPaid) { + controller.addDamage(upkeepDamage, c); + } } }; upkeepAbility.setActivatingPlayer(controller); @@ -617,9 +603,7 @@ public class Upkeep extends Phase { final Player player = game.getPhaseHandler().getPlayerTurn(); final List cards = player.getCardsIn(ZoneType.Battlefield, "Demonic Hordes"); - for (int i = 0; i < cards.size(); i++) { - - final Card c = cards.get(i); + for (final Card c : cards) { final Ability cost = new Ability(c, new ManaCost(new ManaCostParser("B B B"))) { @Override @@ -627,7 +611,7 @@ public class Upkeep extends Phase { } }; // end cost ability - final Ability noPay = new Ability(c, ManaCost.ZERO) { + final Ability unpaidHordesAb = new Ability(c, ManaCost.ZERO) { @Override public void resolve() { final List playerLand = player.getLandsInPlay(); @@ -648,36 +632,25 @@ public class Upkeep extends Phase { final Player cp = c.getController(); if (cp.isHuman()) { - final String question = "Pay Demonic Hordes upkeep cost?"; - if (GuiDialog.confirm(c, question)) { - final Ability pay = new Ability(c, ManaCost.ZERO) { - @Override - public void resolve() { - if (game.getZoneOf(c).is(ZoneType.Battlefield)) { - final StringBuilder coststring = new StringBuilder(); - coststring.append("Pay cost for ").append(c).append("\r\n"); - GameActionUtil.payManaDuringAbilityResolve(coststring.toString(), cost.getManaCost(), - Command.BLANK, Command.BLANK); - } - } // end resolve() - }; // end pay ability - pay.setStackDescription("Demonic Hordes - Upkeep Cost"); - pay.setDescription("Demonic Hordes - Upkeep Cost"); + final Ability pay = new Ability(c, ManaCost.ZERO) { + @Override + public void resolve() { + if (game.getZoneOf(c).is(ZoneType.Battlefield)) { + CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, "Pay Demonic Hordes upkeep cost", cost.getManaCost().toString(), cdl/*, true */); + FThreads.setInputAndWait(inp, cdl); + if ( !inp.isPaid() ) + unpaidHordesAb.resolve(); + } + } // end resolve() + }; // end pay ability + pay.setStackDescription("Demonic Hordes - Upkeep Cost"); + pay.setDescription("Demonic Hordes - Upkeep Cost"); - game.getStack().addSimultaneousStackEntry(pay); - - } // end choice - else { - final StringBuilder sb = new StringBuilder(); - sb.append(c.getName()).append(" - is tapped and you must sacrifice a land of opponent's choice"); - noPay.setStackDescription(sb.toString()); - - game.getStack().addSimultaneousStackEntry(noPay); - - } + game.getStack().addSimultaneousStackEntry(pay); } // end human else { // computer - noPay.setActivatingPlayer(cp); + unpaidHordesAb.setActivatingPlayer(cp); if (ComputerUtilCost.canPayCost(cost, (AIPlayer) cp)) { final Ability computerPay = new Ability(c, ManaCost.ZERO) { @Override @@ -689,8 +662,8 @@ public class Upkeep extends Phase { game.getStack().addSimultaneousStackEntry(computerPay); } else { - noPay.setStackDescription("Demonic Hordes - Upkeep Cost"); - game.getStack().addSimultaneousStackEntry(noPay); + unpaidHordesAb.setStackDescription("Demonic Hordes - Upkeep Cost"); + game.getStack().addSimultaneousStackEntry(unpaidHordesAb); } } // end computer diff --git a/src/main/java/forge/game/zone/MagicStack.java b/src/main/java/forge/game/zone/MagicStack.java index a0a83608cfe..db45c1010b8 100644 --- a/src/main/java/forge/game/zone/MagicStack.java +++ b/src/main/java/forge/game/zone/MagicStack.java @@ -22,12 +22,14 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Stack; +import java.util.concurrent.CountDownLatch; import com.esotericsoftware.minlog.Log; import forge.Card; import forge.CardLists; import forge.CardPredicates; +import forge.FThreads; import forge.CardPredicates.Presets; import forge.Command; import forge.Singletons; @@ -36,7 +38,6 @@ import forge.card.cardfactory.CardFactory; import forge.card.cardfactory.CardFactoryUtil; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostBeingPaid; -import forge.card.mana.ManaCostParser; import forge.card.spellability.Ability; import forge.card.spellability.AbilityStatic; import forge.card.spellability.AbilityTriggered; @@ -478,49 +479,38 @@ public class MagicStack extends MyObservable { } else if (sp.isXCost()) { // TODO: convert any X costs to use abCost so it happens earlier final SpellAbility sa = sp; - final ManaCost mc = new ManaCost( new ManaCostParser(Integer.toString(sa.getXManaCost()))); - final Ability ability = new Ability(sp.getSourceCard(), mc) { - @Override - public void resolve() { - final Card crd = this.getSourceCard(); - crd.addXManaCostPaid(1); - } - }; - - final Command unpaidCommand = new Command() { - private static final long serialVersionUID = -3342222770086269767L; - - @Override - public void execute() { - MagicStack.this.push(sa); - } - }; - - final Command paidCommand = new Command() { - private static final long serialVersionUID = -2224875229611007788L; - - @Override - public void execute() { - ability.resolve(); - final Card crd = sa.getSourceCard(); - Singletons.getModel().getMatch().getInput().setInput( - new InputPayManaExecuteCommands(game, "Pay X cost for " + crd.getName() + " (X=" - + crd.getXManaCostPaid() + ")\r\n", ability.getManaCost().toString(), this, unpaidCommand, - true)); - } - }; - - final Card crd = sa.getSourceCard(); + final int xCost = sa.getXManaCost(); Player player = sp.getSourceCard().getController(); if (player.isHuman()) { - Singletons.getModel().getMatch().getInput().setInput( - new InputPayManaExecuteCommands(game, "Pay X cost for " + sp.getSourceCard().getName() + " (X=" - + crd.getXManaCostPaid() + ")\r\n", ability.getManaCost().toString(), paidCommand, - unpaidCommand, true)); + final Runnable payNextX = new Runnable() { + @Override + public void run() { + + final Card crd = sa.getSourceCard(); + + String message = "Pay X cost for " + crd.getName() + " (X=" + crd.getXManaCostPaid() + ")\r\n"; + CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, message, String.valueOf(xCost), cdl, true); + FThreads.setInputAndWait(inp, cdl); + if ( inp.isPaid() ) { + crd.addXManaCostPaid(1); + this.run(); + } else + MagicStack.this.push(sa); + } + }; + payNextX.run(); } else { // computer final int neededDamage = CardFactoryUtil.getNeededXDamage(sa); - + final Ability ability = new Ability(sp.getSourceCard(), ManaCost.get(xCost)) { + @Override + public void resolve() { + final Card crd = this.getSourceCard(); + crd.addXManaCostPaid(1); + } + }; + while (ComputerUtilCost.canPayCost(ability, player) && (neededDamage != sa.getSourceCard().getXManaCostPaid())) { ComputerUtil.playNoStack((AIPlayer)player, ability, game); } @@ -548,37 +538,44 @@ public class MagicStack extends MyObservable { } }; - final Command paidCommand = new Command() { - private static final long serialVersionUID = -6037161763374971106L; - @Override - public void execute() { - ability.resolve(); - - final ManaCostBeingPaid manaCost = MagicStack.this.getMultiKickerSpellCostChange(ability); - - if (manaCost.isPaid()) { - this.execute(); - } else { - String prompt; - int mkCostPaid = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaid(); - String mkCostPaidColored = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaidColored(); - int mkMagnitude = sa.getSourceCard().getMultiKickerMagnitude(); - if ((mkCostPaid == 0) && mkCostPaidColored.equals("")) { - prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", sa.getSourceCard(), mkMagnitude ); - } else { - prompt = String.format("Multikicker for %s\r\nMana in Reserve: %s %s\r\nTimes Kicked: %d", sa.getSourceCard(), - (mkCostPaid != 0) ? Integer.toString(mkCostPaid) : "", mkCostPaidColored, mkMagnitude); - } - Input toSet = new InputPayManaExecuteCommands(game, prompt, manaCost.toString(), this, unpaidCommand); - Singletons.getModel().getMatch().getInput().setInput(toSet); - } - } - }; Player activating = sp.getActivatingPlayer(); if (activating.isHuman()) { sa.getSourceCard().addMultiKickerMagnitude(-1); + final Command paidCommand = new Command() { + private static final long serialVersionUID = -6037161763374971106L; + + @Override + public void execute() { + ability.resolve(); + + final ManaCostBeingPaid manaCost = MagicStack.this.getMultiKickerSpellCostChange(ability); + + if (manaCost.isPaid()) { + this.execute(); + } else { + String prompt; + int mkCostPaid = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaid(); + String mkCostPaidColored = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaidColored(); + int mkMagnitude = sa.getSourceCard().getMultiKickerMagnitude(); + if ((mkCostPaid == 0) && mkCostPaidColored.equals("")) { + prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", sa.getSourceCard(), mkMagnitude ); + } else { + prompt = String.format("Multikicker for %s\r\nMana in Reserve: %s %s\r\nTimes Kicked: %d", sa.getSourceCard(), + (mkCostPaid != 0) ? Integer.toString(mkCostPaid) : "", mkCostPaidColored, mkMagnitude); + } + CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands toSet = new InputPayManaExecuteCommands(game, prompt, manaCost.toString(), cdl); + FThreads.setInputAndWait(toSet, cdl); + if ( toSet.isPaid() ) { + this.execute(); + } else + unpaidCommand.execute(); + Singletons.getModel().getMatch().getInput().setInput(toSet); + } + } + }; paidCommand.execute(); } else { // computer @@ -603,38 +600,33 @@ public class MagicStack extends MyObservable { } }; - final Command unpaidCommand = new Command() { - private static final long serialVersionUID = -3180458633098297855L; - - @Override - public void execute() { - for (int i = 0; i < sp.getSourceCard().getReplicateMagnitude(); i++) { - CardFactory.copySpellontoStack(sp.getSourceCard(), sp.getSourceCard(), sp, false); - } - } - }; - - final Command paidCommand = new Command() { - private static final long serialVersionUID = 132624005072267304L; - - @Override - public void execute() { - ability.resolve(); - final ManaCostBeingPaid manaCost = MagicStack.this.getReplicateSpellCostChange(ability); - if (manaCost.isPaid()) { - this.execute(); - } else { - String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", sa.getSourceCard(), sa.getSourceCard().getReplicateMagnitude()); - Input toSet = new InputPayManaExecuteCommands(game, prompt, manaCost.toString(), this, unpaidCommand); - Singletons.getModel().getMatch().getInput().setInput(toSet); - } - } - }; - + Player controller = sp.getSourceCard().getController(); if (controller.isHuman()) { sa.getSourceCard().addReplicateMagnitude(-1); - paidCommand.execute(); + final Runnable addMagnitude = new Runnable() { + @Override + public void run() { + ability.resolve(); + final ManaCostBeingPaid manaCost = MagicStack.this.getReplicateSpellCostChange(ability); + if (manaCost.isPaid()) { + this.run(); + } else { + String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", sa.getSourceCard(), sa.getSourceCard().getReplicateMagnitude()); + CountDownLatch cdl = new CountDownLatch(1); + InputPayManaExecuteCommands toSet = new InputPayManaExecuteCommands(game, prompt, manaCost.toString(), cdl); + FThreads.setInputAndWait(toSet, cdl); + if ( toSet.isPaid() ) { + this.run(); + } else { + for (int i = 0; i < sp.getSourceCard().getReplicateMagnitude(); i++) { + CardFactory.copySpellontoStack(sp.getSourceCard(), sp.getSourceCard(), sp, false); + } + } + } + } + }; + addMagnitude.run(); } else { // computer while (ComputerUtilCost.canPayCost(ability, controller)) {