From 0ce3aba250163b534f14f1a591084cbb1abcf601 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 23 Mar 2013 10:48:28 +0000 Subject: [PATCH] All cost-paying inputs are syncronous --- .gitattributes | 3 +- src/main/java/forge/Card.java | 8 + src/main/java/forge/FThreads.java | 7 +- .../forge/card/ability/ai/ChangeZoneAi.java | 1 - .../card/cardfactory/CardFactoryUtil.java | 4 + src/main/java/forge/card/cost/CostDamage.java | 6 +- .../java/forge/card/cost/CostDiscard.java | 231 ++++++------ src/main/java/forge/card/cost/CostExile.java | 142 ++------ .../java/forge/card/cost/CostGainLife.java | 10 +- src/main/java/forge/card/cost/CostMill.java | 7 +- src/main/java/forge/card/cost/CostPart.java | 16 +- .../java/forge/card/cost/CostPartMana.java | 27 +- .../java/forge/card/cost/CostPayLife.java | 8 +- .../java/forge/card/cost/CostPayment.java | 29 +- .../java/forge/card/cost/CostPutCounter.java | 160 ++++----- .../forge/card/cost/CostRemoveCounter.java | 335 ++++++++---------- src/main/java/forge/card/cost/CostReturn.java | 244 ++++++------- src/main/java/forge/card/cost/CostReveal.java | 216 +++++------ .../java/forge/card/cost/CostSacrifice.java | 258 +++++--------- src/main/java/forge/card/cost/CostTap.java | 4 +- .../java/forge/card/cost/CostTapType.java | 170 ++++----- .../java/forge/card/cost/CostUnattach.java | 7 +- src/main/java/forge/card/cost/CostUntap.java | 4 +- .../java/forge/card/cost/CostUntapType.java | 160 ++++----- .../forge/card/cost/InputPayCostBase.java | 41 +++ .../SpellAbilityRequirements.java | 26 +- src/main/java/forge/control/FControl.java | 5 +- .../forge/control/input/InputControl.java | 20 +- .../java/forge/control/input/InputLockUI.java | 5 + ...a => InputPayDiscardCostWithCommands.java} | 4 +- .../forge/control/input/InputPayManaBase.java | 92 +++-- .../input/InputPayManaExecuteCommands.java | 53 +-- .../input/InputPayManaOfCostPayment.java | 83 ++--- .../control/input/InputPayManaSimple.java | 123 ++----- .../forge/control/input/InputPayManaX.java | 62 ++-- src/main/java/forge/deck/CardCollections.java | 12 +- src/main/java/forge/game/GameActionPlay.java | 56 ++- src/main/java/forge/game/GameActionUtil.java | 4 +- src/main/java/forge/game/MatchController.java | 2 +- .../java/forge/game/phase/PhaseHandler.java | 2 +- src/main/java/forge/game/zone/MagicStack.java | 22 +- src/main/java/forge/gui/toolbox/FSkin.java | 40 ++- src/main/java/forge/model/FModel.java | 9 +- 43 files changed, 1229 insertions(+), 1489 deletions(-) create mode 100644 src/main/java/forge/card/cost/InputPayCostBase.java rename src/main/java/forge/control/input/{InputPayDiscardCost.java => InputPayDiscardCostWithCommands.java} (93%) diff --git a/.gitattributes b/.gitattributes index cede30e7b1e..6ed5e4648b8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13695,6 +13695,7 @@ src/main/java/forge/card/cost/CostUnattach.java -text src/main/java/forge/card/cost/CostUntap.java -text src/main/java/forge/card/cost/CostUntapType.java -text src/main/java/forge/card/cost/CostUtil.java -text +src/main/java/forge/card/cost/InputPayCostBase.java -text src/main/java/forge/card/cost/package-info.java svneol=native#text/plain src/main/java/forge/card/mana/IParserManaCost.java -text src/main/java/forge/card/mana/Mana.java svneol=native#text/plain @@ -13803,7 +13804,7 @@ src/main/java/forge/control/input/InputControl.java svneol=native#text/plain src/main/java/forge/control/input/InputLockUI.java -text src/main/java/forge/control/input/InputMulligan.java svneol=native#text/plain src/main/java/forge/control/input/InputPassPriority.java svneol=native#text/plain -src/main/java/forge/control/input/InputPayDiscardCost.java -text +src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java -text src/main/java/forge/control/input/InputPayManaBase.java -text src/main/java/forge/control/input/InputPayManaExecuteCommands.java svneol=native#text/plain src/main/java/forge/control/input/InputPayManaOfCostPayment.java -text diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index d4f8fd3e7c8..3c7b330cc7b 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -7675,6 +7675,14 @@ public class Card extends GameEntity implements Comparable { this.receivedDamageFromThisTurn.clear(); } + public final int getTotalDamageRecievedThisTurn() { + int total = 0; + for (int damage : this.receivedDamageFromThisTurn.values()) { + total += damage; + } + return total; + } + /** *

* addDealtDamageToThisTurn. diff --git a/src/main/java/forge/FThreads.java b/src/main/java/forge/FThreads.java index f35a94923bd..7130594025b 100644 --- a/src/main/java/forge/FThreads.java +++ b/src/main/java/forge/FThreads.java @@ -6,8 +6,6 @@ import java.util.concurrent.Executors; import javax.swing.SwingUtilities; -import forge.control.input.InputLockUI; - /** * TODO: Write javadoc for this type. * @@ -87,18 +85,17 @@ public class FThreads { invokeInNewThread(proc, false); } - private final static InputLockUI inpuptLock = new InputLockUI(); public static void invokeInNewThread(final Runnable proc, boolean lockUI) { Runnable toRun = proc; if( lockUI ) { // checkEDT("FThreads.invokeInNewthread", true) - Singletons.getModel().getMatch().getInput().setInput(inpuptLock); + Singletons.getModel().getMatch().getInput().lock(); toRun = new Runnable() { @Override public void run() { proc.run(); // may try special unlock method here - Singletons.getModel().getMatch().getInput().resetInput(); + Singletons.getModel().getMatch().getInput().unlock(); } }; } diff --git a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java index 8f5e49654cd..14f8dfc0b00 100644 --- a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java +++ b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java @@ -26,7 +26,6 @@ import forge.card.cost.CostDiscard; import forge.card.cost.CostPart; import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; -import forge.card.spellability.SpellPermanent; import forge.card.spellability.Target; import forge.card.trigger.TriggerType; import forge.game.GlobalRuleChange; diff --git a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java index af7877e5ca3..981093bb98d 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java @@ -1537,6 +1537,10 @@ public class CardFactoryUtil { return CardFactoryUtil.doXMath(c.getTotalDamageDoneBy(), m, c); } + if (sq[0].equals("TotalDamageReceivedThisTurn")) { + return CardFactoryUtil.doXMath(c.getTotalDamageRecievedThisTurn(), m, c); + } + // Count$YourPoisonCounters if (sq[0].contains("YourPoisonCounters")) { return CardFactoryUtil.doXMath(cardController.getPoisonCounters(), m, c); diff --git a/src/main/java/forge/card/cost/CostDamage.java b/src/main/java/forge/card/cost/CostDamage.java index e94787936e9..18155737fad 100644 --- a/src/main/java/forge/card/cost/CostDamage.java +++ b/src/main/java/forge/card/cost/CostDamage.java @@ -103,7 +103,7 @@ public class CostDamage extends CostPart { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); final Player activator = ability.getActivatingPlayer(); final int life = activator.getLife(); @@ -125,13 +125,9 @@ public class CostDamage extends CostPart { if (GuiDialog.confirm(source, sb.toString()) && activator.canPayLife(c)) { activator.addDamage(c, source); this.setLastPaidAmount(c); - payment.setPaidManaPart(this); } else { payment.setCancel(true); - payment.getRequirements().finishPaying(); - return false; } - return true; } /* diff --git a/src/main/java/forge/card/cost/CostDiscard.java b/src/main/java/forge/card/cost/CostDiscard.java index 727f61c5abc..9d99e7af8e8 100644 --- a/src/main/java/forge/card/cost/CostDiscard.java +++ b/src/main/java/forge/card/cost/CostDiscard.java @@ -19,6 +19,7 @@ package forge.card.cost; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; import com.google.common.base.Predicate; @@ -43,6 +44,99 @@ import forge.view.ButtonUtil; public class CostDiscard extends CostPartWithList { // Discard + // Inputs + + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostDiscard extends InputPayCostBase { + private final List handList; + private final CostDiscard part; + private final int nNeeded; + private final String discType; + private static final long serialVersionUID = -329993322080934435L; + private int nDiscard = 0; + private boolean sameName; + + private final SpellAbility sa; + + /** + * TODO: Write javadoc for Constructor. + * @param sa + * @param handList + * @param part + * @param payment + * @param nNeeded + * @param sp + * @param discType + */ + public InputPayCostDiscard(CountDownLatch cdl, SpellAbility sa, List handList, CostDiscard part, CostPayment payment, int nNeeded, String discType) { + super(cdl, payment); + this.sa = sa; + this.handList = handList; + this.part = part; + this.nNeeded = nNeeded; + this.discType = discType; + sameName = discType.contains("WithSameName"); + } + + @Override + public void showMessage() { + if (nNeeded == 0) { + this.done(); + } + + if (sa.getActivatingPlayer().getZone(ZoneType.Hand).isEmpty()) { + this.stop(); + } + final StringBuilder type = new StringBuilder(""); + if (!discType.equals("Card")) { + type.append(" ").append(discType); + } + final StringBuilder sb = new StringBuilder(); + sb.append("Select a "); + sb.append(part.getDescriptiveType()); + sb.append(" to discard."); + if (nNeeded > 1) { + sb.append(" You have "); + sb.append(nNeeded - this.nDiscard); + sb.append(" remaining."); + } + CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString()); + if (nNeeded > 0) { + ButtonUtil.enableOnlyCancel(); + } + } + + @Override + public void selectCard(final Card card) { + Zone zone = Singletons.getModel().getGame().getZoneOf(card); + if (zone.is(ZoneType.Hand) && handList.contains(card)) { + if (!sameName || part.getList().isEmpty() + || part.getList().get(0).getName().equals(card.getName())) { + // send in List for Typing + card.getController().discard(card, sa); + part.addToList(card); + handList.remove(card); + this.nDiscard++; + + // in case no more cards in hand + if (this.nDiscard == nNeeded) { + this.done(); + } else if (sa.getActivatingPlayer().getZone(ZoneType.Hand).size() == 0) { + // really + // shouldn't + // happen + this.cancel(); + } else { + this.showMessage(); + } + } + } + } + } + /** * Instantiates a new cost discard. * @@ -167,36 +261,36 @@ public class CostDiscard extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final Player activator = ability.getActivatingPlayer(); List handList = new ArrayList(activator.getCardsIn(ZoneType.Hand)); - String discType = this.getType(); + String discardType = this.getType(); final String amount = this.getAmount(); this.resetList(); if (this.payCostFromSource()) { if (!handList.contains(source)) { - return false; + payment.setCancel(true); } activator.discard(source, ability); - payment.setPaidManaPart(this); + payment.setPaidPart(this); //this.addToList(source); - } else if (discType.equals("Hand")) { + } else if (discardType.equals("Hand")) { this.setList(handList); activator.discardHand(ability); - payment.setPaidManaPart(this); - } else if (discType.equals("LastDrawn")) { + payment.setPaidPart(this); + } else if (discardType.equals("LastDrawn")) { final Card lastDrawn = activator.getLastDrawnCard(); this.addToList(lastDrawn); if (!handList.contains(lastDrawn)) { - return false; + payment.setCancel(true); } activator.discard(lastDrawn, ability); - payment.setPaidManaPart(this); + payment.setPaidPart(this); } else { Integer c = this.convertAmount(); - if (discType.equals("Random")) { + if (discardType.equals("Random")) { if (c == null) { final String sVar = ability.getSVar(amount); // Generalize this @@ -208,9 +302,9 @@ public class CostDiscard extends CostPartWithList { } this.setList(activator.discardRandom(c, ability)); - payment.setPaidManaPart(this); + payment.setPaidPart(this); } else { - String type = new String(discType); + String type = new String(discardType); boolean sameName = false; if (type.contains("+WithSameName")) { sameName = true; @@ -243,13 +337,13 @@ public class CostDiscard extends CostPartWithList { } } - final Input inp = CostDiscard.inputDiscardCost(discType, handList, ability, payment, this, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - return false; + CountDownLatch cdl = new CountDownLatch(1); + final Input inp = new InputPayCostDiscard(cdl, ability, handList, this, payment, c, discardType); + setInputAndWait(inp, cdl); } } - this.addListToHash(ability, "Discarded"); - return true; + if ( !payment.isCanceled()) + this.addListToHash(ability, "Discarded"); } /* @@ -308,107 +402,4 @@ public class CostDiscard extends CostPartWithList { // Inputs - /** - *

- * input_discardCost. - *

- * - * @param discType - * a {@link java.lang.String} object. - * @param handList - * a {@link forge.CardList} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @param nNeeded - * a int. - * - * @return a {@link forge.control.input.Input} object. - */ - public static Input inputDiscardCost(final String discType, final List handList, final SpellAbility sa, - final CostPayment payment, final CostDiscard part, final int nNeeded) { - final SpellAbility sp = sa; - final Input target = new Input() { - private static final long serialVersionUID = -329993322080934435L; - - private int nDiscard = 0; - private boolean sameName = discType.contains("WithSameName"); - - @Override - public void showMessage() { - if (nNeeded == 0) { - this.done(); - } - - if (sa.getActivatingPlayer().getZone(ZoneType.Hand).isEmpty()) { - this.stop(); - } - final StringBuilder type = new StringBuilder(""); - if (!discType.equals("Card")) { - type.append(" ").append(discType); - } - final StringBuilder sb = new StringBuilder(); - sb.append("Select a "); - sb.append(part.getDescriptiveType()); - sb.append(" to discard."); - if (nNeeded > 1) { - sb.append(" You have "); - sb.append(nNeeded - this.nDiscard); - sb.append(" remaining."); - } - CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString()); - if (nNeeded > 0) { - ButtonUtil.enableOnlyCancel(); - } - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - Zone zone = Singletons.getModel().getGame().getZoneOf(card); - if (zone.is(ZoneType.Hand) && handList.contains(card)) { - if (!sameName || part.getList().isEmpty() - || part.getList().get(0).getName().equals(card.getName())) { - // send in List for Typing - card.getController().discard(card, sp); - part.addToList(card); - handList.remove(card); - this.nDiscard++; - - // in case no more cards in hand - if (this.nDiscard == nNeeded) { - this.done(); - } else if (sa.getActivatingPlayer().getZone(ZoneType.Hand).size() == 0) { - // really - // shouldn't - // happen - this.cancel(); - } else { - this.showMessage(); - } - } - } - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } - - public void done() { - this.stop(); - part.addListToHash(sp, "Discarded"); - payment.paidCost(part); - } - }; - - return target; - } // input_discard() } diff --git a/src/main/java/forge/card/cost/CostExile.java b/src/main/java/forge/card/cost/CostExile.java index b339110f65b..232ab9177dc 100644 --- a/src/main/java/forge/card/cost/CostExile.java +++ b/src/main/java/forge/card/cost/CostExile.java @@ -20,6 +20,7 @@ package forge.card.cost; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; @@ -49,18 +50,14 @@ public class CostExile extends CostPartWithList { // ExileFromTop (of library) // ExileSameGrave - /** - * TODO: Write javadoc for this type. - * - */ - private static final class InputExileFrom extends Input { + private static final class InputExileFrom extends InputPayCostBase { private final SpellAbility sa; private final String type; private final int nNeeded; - private final CostPayment payment; private final CostExile part; private static final long serialVersionUID = 734256837615635021L; private List typeList; + /** * TODO: Write javadoc for Constructor. @@ -70,11 +67,11 @@ public class CostExile extends CostPartWithList { * @param payment * @param part */ - private InputExileFrom(SpellAbility sa, String type, int nNeeded, CostPayment payment, CostExile part) { + private InputExileFrom(CountDownLatch cdl, SpellAbility sa, String type, int nNeeded, CostPayment payment, CostExile part) { + super(cdl, payment); this.sa = sa; this.type = type; this.nNeeded = nNeeded; - this.payment = payment; this.part = part; } @@ -107,33 +104,15 @@ public class CostExile extends CostPartWithList { } } } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - public void done() { - this.stop(); - part.addListToHash(sa, "Exiled"); - payment.paidCost(part); - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } } /** * TODO: Write javadoc for this type. * */ - private static final class InputExileFromSame extends Input { + private static final class InputExileFromSame extends InputPayCostBase { private final List list; private final CostExile part; - private final CostPayment payment; - private final SpellAbility sa; private final int nNeeded; private final List payableZone; private static final long serialVersionUID = 734256837615635021L; @@ -148,12 +127,10 @@ public class CostExile extends CostPartWithList { * @param nNeeded * @param payableZone */ - private InputExileFromSame(List list, CostExile part, CostPayment payment, SpellAbility sa, int nNeeded, - List payableZone) { + private InputExileFromSame(CountDownLatch cdl, List list, CostExile part, CostPayment payment, int nNeeded, List payableZone) { + super(cdl, payment); this.list = list; this.part = part; - this.payment = payment; - this.sa = sa; this.nNeeded = nNeeded; this.payableZone = payableZone; } @@ -196,30 +173,14 @@ public class CostExile extends CostPartWithList { } } } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - public void done() { - this.stop(); - part.addListToHash(sa, "Exiled"); - payment.paidCost(part); - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } } /** * TODO: Write javadoc for this type. * */ - private static final class InputExileFromStack extends Input { - private final CostPayment payment; + private static final class InputExileFromStack extends InputPayCostBase { + private final SpellAbility sa; private final String type; private final int nNeeded; @@ -236,8 +197,8 @@ public class CostExile extends CostPartWithList { * @param nNeeded * @param part */ - private InputExileFromStack(CostPayment payment, SpellAbility sa, String type, int nNeeded, CostExile part) { - this.payment = payment; + private InputExileFromStack(CountDownLatch cdl, CostPayment payment, SpellAbility sa, String type, int nNeeded, CostExile part) { + super(cdl, payment); this.sa = sa; this.type = type; this.nNeeded = nNeeded; @@ -293,31 +254,14 @@ public class CostExile extends CostPartWithList { } } } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - public void done() { - this.stop(); - part.addListToHash(sa, "Exiled"); - payment.paidCost(part); - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } } /** * TODO: Write javadoc for this type. * */ - private static final class InputExileType extends Input { + private static final class InputExileType extends InputPayCostBase { private final CostExile part; - private final CostPayment payment; private final String type; private final int nNeeded; private final SpellAbility sa; @@ -333,9 +277,9 @@ public class CostExile extends CostPartWithList { * @param nNeeded * @param sa */ - private InputExileType(CostExile part, CostPayment payment, String type, int nNeeded, SpellAbility sa) { + private InputExileType(CountDownLatch cdl, CostExile part, CostPayment payment, String type, int nNeeded, SpellAbility sa) { + super(cdl, payment); this.part = part; - this.payment = payment; this.type = type; this.nNeeded = nNeeded; this.sa = sa; @@ -366,11 +310,6 @@ public class CostExile extends CostPartWithList { ButtonUtil.enableOnlyCancel(); } - @Override - public void selectButtonCancel() { - this.cancel(); - } - @Override public void selectCard(final Card card) { if (this.typeList.contains(card)) { @@ -389,25 +328,13 @@ public class CostExile extends CostPartWithList { } } } - - public void done() { - this.stop(); - part.addListToHash(sa, "Exiled"); - payment.paidCost(part); - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } } /** * TODO: Write javadoc for this type. * */ - private static final class InputExileThis extends Input { - private final CostPayment payment; + private static final class InputExileThis extends InputPayCostBase { private final CostExile part; private final SpellAbility sa; private static final long serialVersionUID = 678668673002725001L; @@ -418,30 +345,27 @@ public class CostExile extends CostPartWithList { * @param part * @param sa */ - private InputExileThis(CostPayment payment, CostExile part, SpellAbility sa) { - this.payment = payment; + private InputExileThis(CountDownLatch cdl, CostPayment payment, CostExile part, SpellAbility sa) { + super(cdl, payment); this.part = part; this.sa = sa; } - @Override public void showMessage() { final Card card = sa.getSourceCard(); if ( sa.getActivatingPlayer().getZone(part.getFrom()).contains(card)) { - boolean choice = GuiDialog.confirm(card, card.getName() + " - Exile?"); if (choice) { - payment.getAbility().addCostToHashList(card, "Exiled"); Singletons.getModel().getGame().getAction().exile(card); part.addToList(card); this.stop(); part.addListToHash(sa, "Exiled"); - payment.paidCost(part); + done(); } else { - this.stop(); - payment.cancelCost(); + cancel(); } } + else cancel(); } } @@ -619,7 +543,7 @@ public class CostExile extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); Integer c = this.convertAmount(); final Player activator = ability.getActivatingPlayer(); @@ -636,7 +560,7 @@ public class CostExile extends CostPartWithList { for (final Card card : list) { Singletons.getModel().getGame().getAction().exile(card); } - payment.paidCost(this); + payment.setPaidPart(this); } list = CardLists.getValidCards(list, this.getType().split(";"), activator, source); if (c == null) { @@ -651,13 +575,15 @@ public class CostExile extends CostPartWithList { } } + final CountDownLatch cdl = new CountDownLatch(1); + Input target = null; if (this.payCostFromSource()) { - target = new InputExileThis(payment, this, ability); + target = new InputExileThis(cdl, payment, this, ability); } else if (this.from.equals(ZoneType.Battlefield) || this.from.equals(ZoneType.Hand)) { - target = new InputExileType(this, payment, this.getType(), c, ability); + target = new InputExileType(cdl, this, payment, this.getType(), c, ability); } else if (this.from.equals(ZoneType.Stack)) { - target = new InputExileFromStack(payment, ability, this.getType(), c, this); + target = new InputExileFromStack(cdl,payment, ability, this.getType(), c, this); } else if (this.from.equals(ZoneType.Library)) { // this does not create input CostExile.exileFromTop(ability, this, payment, c); @@ -672,13 +598,13 @@ public class CostExile extends CostPartWithList { payableZone.add(p); } } - target = new InputExileFromSame(list, this, payment, ability, c, payableZone); + target = new InputExileFromSame(cdl, list, this, payment, c, payableZone); } else { - target = new InputExileFrom(ability, this.getType(), c, payment, this); + target = new InputExileFrom(cdl,ability, this.getType(), c, payment, this); } - if ( null != target ) - Singletons.getModel().getMatch().getInput().setInputInterrupt(target); - return false; + setInputAndWait(target, cdl); + if(!payment.isCanceled()) + addListToHash(ability, "Exiled"); } /* @@ -762,7 +688,7 @@ public class CostExile extends CostPartWithList { Singletons.getModel().getGame().getAction().exile(c); } part.addListToHash(sa, "Exiled"); - payment.paidCost(part); + payment.setPaidPart(part); } else { payment.cancelCost(); } diff --git a/src/main/java/forge/card/cost/CostGainLife.java b/src/main/java/forge/card/cost/CostGainLife.java index 1419a568205..ceea608893f 100644 --- a/src/main/java/forge/card/cost/CostGainLife.java +++ b/src/main/java/forge/card/cost/CostGainLife.java @@ -137,7 +137,7 @@ public class CostGainLife extends CostPart { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); final Player activator = ability.getActivatingPlayer(); final int life = activator.getLife(); @@ -163,8 +163,6 @@ public class CostGainLife extends CostPart { if(cntPlayers == Integer.MAX_VALUE) { // applied to all players who can gain for(Player opp: oppsThatCanGainLife) opp.gainLife(c, null); - payment.setPaidManaPart(this); - return true; } final StringBuilder sb = new StringBuilder(); @@ -175,16 +173,12 @@ public class CostGainLife extends CostPart { final Player chosenToGain = GuiChoose.oneOrNone(sb.toString(), oppsThatCanGainLife); if (null == chosenToGain) { payment.setCancel(true); - payment.getRequirements().finishPaying(); - return false; + return; } else { final Player chosen = chosenToGain; chosen.gainLife(c, null); } } - - payment.setPaidManaPart(this); - return true; } /* diff --git a/src/main/java/forge/card/cost/CostMill.java b/src/main/java/forge/card/cost/CostMill.java index 65919ae541c..bf537d0d6e8 100644 --- a/src/main/java/forge/card/cost/CostMill.java +++ b/src/main/java/forge/card/cost/CostMill.java @@ -126,7 +126,7 @@ public class CostMill extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); Integer c = this.convertAmount(); final Player activator = ability.getActivatingPlayer(); @@ -145,7 +145,7 @@ public class CostMill extends CostPartWithList { if ((list == null) || (list.size() > c)) { // I don't believe this is possible payment.cancelCost(); - return false; + return; } final StringBuilder sb = new StringBuilder(); @@ -161,11 +161,8 @@ public class CostMill extends CostPartWithList { Singletons.getModel().getGame().getAction().moveToGraveyard(card); } this.addListToHash(ability, "Milled"); - payment.paidCost(this); - return false; } else { payment.cancelCost(); - return false; } } diff --git a/src/main/java/forge/card/cost/CostPart.java b/src/main/java/forge/card/cost/CostPart.java index 675d151f993..8a4f60659fc 100644 --- a/src/main/java/forge/card/cost/CostPart.java +++ b/src/main/java/forge/card/cost/CostPart.java @@ -17,8 +17,13 @@ */ package forge.card.cost; +import java.util.concurrent.CountDownLatch; + import forge.Card; +import forge.Singletons; import forge.card.spellability.SpellAbility; +import forge.control.input.Input; +import forge.error.BugReporter; import forge.game.GameState; import forge.game.player.AIPlayer; import forge.game.player.Player; @@ -141,6 +146,15 @@ public abstract class CostPart { return i; } + public final void setInputAndWait(Input inp, CountDownLatch cdl) { + Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + try { + cdl.await(); + } catch (InterruptedException e) { + BugReporter.reportException(e); + } + } + /** * Can pay. * @@ -199,7 +213,7 @@ public abstract class CostPart { * @param game * @return true, if successful */ - public abstract boolean payHuman(SpellAbility ability, Card source, CostPayment payment, GameState game); + public abstract void payHuman(SpellAbility ability, Card source, CostPayment payment, GameState game); /* * (non-Javadoc) diff --git a/src/main/java/forge/card/cost/CostPartMana.java b/src/main/java/forge/card/cost/CostPartMana.java index 6d91123d5d3..121abdf068e 100644 --- a/src/main/java/forge/card/cost/CostPartMana.java +++ b/src/main/java/forge/card/cost/CostPartMana.java @@ -17,10 +17,11 @@ */ package forge.card.cost; +import java.util.concurrent.CountDownLatch; + import com.google.common.base.Strings; import forge.Card; -import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.spellability.SpellAbility; import forge.control.input.Input; @@ -206,7 +207,7 @@ public class CostPartMana extends CostPart { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { int manaToAdd = 0; if (!this.hasNoXManaCost()) { // if X cost is a defined value, other than xPaid @@ -215,19 +216,19 @@ public class CostPartMana extends CostPart { manaToAdd = AbilityUtils.calculateAmount(source, "X", ability) * this.getXMana(); } } - if (!this.getManaToPay().equals("0") || (manaToAdd > 0)) { - final Input inp = new InputPayManaOfCostPayment(game, this, ability, payment, manaToAdd); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + + CountDownLatch cdl = new CountDownLatch(1); + final Input inp; + if (!"0".equals(this.getManaToPay()) || manaToAdd > 0) { + inp = new InputPayManaOfCostPayment(game, this, ability, payment, manaToAdd, cdl); + } else if (this.getXMana() > 0) { - final Input inp = new InputPayManaX(game, ability, payment, this); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - } else { - payment.paidCost(this); + inp = new InputPayManaX(game, ability, payment, this, cdl); + } + else inp = null; + if ( null != inp) { + setInputAndWait(inp, cdl); } - - // We return false here because the Inputs set above should recall - // payment.payCosts() - return false; } /* diff --git a/src/main/java/forge/card/cost/CostPayLife.java b/src/main/java/forge/card/cost/CostPayLife.java index 0b6c08eee92..4fc6b6548ad 100644 --- a/src/main/java/forge/card/cost/CostPayLife.java +++ b/src/main/java/forge/card/cost/CostPayLife.java @@ -123,7 +123,7 @@ public class CostPayLife extends CostPart { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); final Player activator = ability.getActivatingPlayer(); final int life = activator.getLife(); @@ -147,16 +147,12 @@ public class CostPayLife extends CostPart { final StringBuilder sb = new StringBuilder(); sb.append(source.getName()).append(" - Pay ").append(c).append(" Life?"); - if (GuiDialog.confirm(source, sb.toString()) && activator.canPayLife(c)) { + if (activator.canPayLife(c) && GuiDialog.confirm(source, sb.toString())) { activator.payLife(c, null); this.setLastPaidAmount(c); - payment.setPaidManaPart(this); } else { payment.setCancel(true); - payment.getRequirements().finishPaying(); - return false; } - return true; } /* diff --git a/src/main/java/forge/card/cost/CostPayment.java b/src/main/java/forge/card/cost/CostPayment.java index 3de175c6130..71090206939 100644 --- a/src/main/java/forge/card/cost/CostPayment.java +++ b/src/main/java/forge/card/cost/CostPayment.java @@ -179,26 +179,15 @@ public class CostPayment { * @param bPaid * the b paid */ - public final void setPaidManaPart(final CostPart part) { + public final void setPaidPart(final CostPart part) { this.paidCostParts.add(part); } - /** - * Paid cost. - * - * @param part - * the part - */ - public final void paidCost(final CostPart part) { - this.setPaidManaPart(part); - this.payCost(); - } - /** * Cancel cost (including CostPart for refunding). */ public final void cancelCost(final CostPart part) { - this.setPaidManaPart(part); + this.setPaidPart(part); this.cancelCost(); } @@ -207,7 +196,6 @@ public class CostPayment { */ public final void cancelCost() { this.setCancel(true); - this.req.finishPaying(); } /** @@ -220,7 +208,6 @@ public class CostPayment { public final boolean payCost() { // Nothing actually ever checks this return value, is it needed? if (this.bCancel) { - this.req.finishPaying(); return false; } @@ -230,13 +217,13 @@ public class CostPayment { continue; } - if (!part.payHuman(this.ability, this.card, this, game)) { - return false; - } + part.payHuman(this.ability, this.card, this, game); + if ( isCanceled() ) break; + + setPaidPart(part); } - - this.resetUndoList(); - this.req.finishPaying(); + + this.resetUndoList(); // ?? return true; } diff --git a/src/main/java/forge/card/cost/CostPutCounter.java b/src/main/java/forge/card/cost/CostPutCounter.java index b3c380d7664..7e782640a69 100644 --- a/src/main/java/forge/card/cost/CostPutCounter.java +++ b/src/main/java/forge/card/cost/CostPutCounter.java @@ -18,14 +18,13 @@ package forge.card.cost; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; import forge.CounterType; -import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.spellability.SpellAbility; -import forge.control.input.Input; import forge.game.GameState; import forge.game.ai.ComputerUtilCard; import forge.game.player.AIPlayer; @@ -38,6 +37,72 @@ import forge.view.ButtonUtil; * The Class CostPutCounter. */ public class CostPutCounter extends CostPartWithList { + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostPutCounter extends InputPayCostBase { + private final String type; + private final CostPutCounter costPutCounter; + private final int nNeeded; + private final SpellAbility sa; + private static final long serialVersionUID = 2685832214519141903L; + private List typeList; + private int nPut = 0; + + /** + * TODO: Write javadoc for Constructor. + * @param type + * @param costPutCounter + * @param nNeeded + * @param payment + * @param sa + */ + public InputPayCostPutCounter(CountDownLatch cdl, String type, CostPutCounter costPutCounter, int nNeeded, CostPayment payment, SpellAbility sa) { + super(cdl, payment); + this.type = type; + this.costPutCounter = costPutCounter; + this.nNeeded = nNeeded; + this.sa = sa; + } + + @Override + public void showMessage() { + if ((nNeeded == 0) || (nNeeded == this.nPut)) { + this.done(); + } + + final StringBuilder msg = new StringBuilder("Put "); + final int nLeft = nNeeded - this.nPut; + msg.append(nLeft).append(" "); + msg.append(costPutCounter.getCounter()).append(" on "); + + msg.append(costPutCounter.getDescriptiveType()); + if (nLeft > 1) { + msg.append("s"); + } + + this.typeList = CardLists.getValidCards(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); + CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); + ButtonUtil.enableOnlyCancel(); + } + + @Override + public void selectCard(final Card card) { + if (this.typeList.contains(card)) { + this.nPut++; + costPutCounter.addToList(card); + card.addCounter(costPutCounter.getCounter(), 1, false); + + if (nNeeded == this.nPut) { + this.done(); + } else { + this.showMessage(); + } + } + } + } + // Put Counter doesn't really have a "Valid" portion of the cost private final CounterType counter; private int lastPaidAmount = 0; @@ -179,7 +244,7 @@ public class CostPutCounter extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { Integer c = this.convertAmount(); if (c == null) { c = AbilityUtils.calculateAmount(source, this.getAmount(), ability); @@ -187,14 +252,13 @@ public class CostPutCounter extends CostPartWithList { if (this.payCostFromSource()) { source.addCounter(this.getCounter(), c, false); - payment.setPaidManaPart(this); this.addToList(source); - return true; } else { - final Input inp = CostPutCounter.putCounterType(ability, this.getType(), payment, this, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - return false; + CountDownLatch cdl = new CountDownLatch(1); + setInputAndWait(new InputPayCostPutCounter(cdl, this.getType(), this, c, payment, ability), cdl); } + if ( !payment.isCanceled()) + addListToHash(ability, "CounterPut"); } /* @@ -229,84 +293,4 @@ public class CostPutCounter extends CostPartWithList { } return true; } - - /** - *

- * returnType. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param type - * a {@link java.lang.String} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param costPutCounter - * TODO - * @param nNeeded - * the n needed - * @return a {@link forge.control.input.Input} object. - */ - public static Input putCounterType(final SpellAbility sa, final String type, final CostPayment payment, - final CostPutCounter costPutCounter, final int nNeeded) { - final Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - private List typeList; - private int nPut = 0; - - @Override - public void showMessage() { - if ((nNeeded == 0) || (nNeeded == this.nPut)) { - this.done(); - } - - final StringBuilder msg = new StringBuilder("Put "); - final int nLeft = nNeeded - this.nPut; - msg.append(nLeft).append(" "); - msg.append(costPutCounter.getCounter()).append(" on "); - - msg.append(costPutCounter.getDescriptiveType()); - if (nLeft > 1) { - msg.append("s"); - } - - this.typeList = CardLists.getValidCards(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); - CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - if (this.typeList.contains(card)) { - this.nPut++; - costPutCounter.addToList(card); - card.addCounter(costPutCounter.getCounter(), 1, false); - - if (nNeeded == this.nPut) { - this.done(); - } else { - this.showMessage(); - } - } - } - - public void done() { - this.stop(); - payment.paidCost(costPutCounter); - } - - public void cancel() { - this.stop(); - costPutCounter.addListToHash(sa, "CounterPut"); - payment.cancelCost(); - } - }; - - return target; - } } diff --git a/src/main/java/forge/card/cost/CostRemoveCounter.java b/src/main/java/forge/card/cost/CostRemoveCounter.java index dee934b4e69..e016050a109 100644 --- a/src/main/java/forge/card/cost/CostRemoveCounter.java +++ b/src/main/java/forge/card/cost/CostRemoveCounter.java @@ -19,11 +19,11 @@ package forge.card.cost; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; import forge.CounterType; -import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.spellability.SpellAbility; import forge.control.input.Input; @@ -46,6 +46,148 @@ public class CostRemoveCounter extends CostPartWithList { // Counter is tough), // Quillspike, Rift Elemental, Sage of Fables, Spike Rogue + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostRemoveCounterType extends InputPayCostBase { + private final int nNeeded; + private final SpellAbility sa; + private final String type; + private final CostRemoveCounter costRemoveCounter; + private static final long serialVersionUID = 2685832214519141903L; + private List typeList; + private int nRemove = 0; + + /** + * TODO: Write javadoc for Constructor. + * @param payment + * @param nNeeded + * @param sa + * @param type + * @param costRemoveCounter + */ + public InputPayCostRemoveCounterType(CountDownLatch cdl, CostPayment payment, int nNeeded, SpellAbility sa, String type, + CostRemoveCounter costRemoveCounter) { + super(cdl, payment); + this.nNeeded = nNeeded; + this.sa = sa; + this.type = type; + this.costRemoveCounter = costRemoveCounter; + } + + @Override + public void showMessage() { + if ((nNeeded == 0) || (nNeeded == this.nRemove)) { + this.done(); + } + + final StringBuilder msg = new StringBuilder("Remove "); + final int nLeft = nNeeded - this.nRemove; + msg.append(nLeft).append(" "); + msg.append(costRemoveCounter.getCounter().getName()).append(" counters from "); + msg.append(costRemoveCounter.getDescriptiveType()); + + this.typeList = CardLists.getValidCards(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone()), type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); + + // TODO Tabulate typelist vs nNeeded to see if there are enough counters to remove + + CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); + ButtonUtil.enableOnlyCancel(); + } + + @Override + public void selectCard(final Card card) { + if (this.typeList.contains(card)) { + if (card.getCounters(costRemoveCounter.getCounter()) > 0) { + this.nRemove++; + costRemoveCounter.addToList(card); + card.subtractCounter(costRemoveCounter.getCounter(), 1); + + if (nNeeded == this.nRemove) { + this.done(); + } else { + this.showMessage(); + } + } + } + } + } + + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostRemoveCounterFrom extends InputPayCostBase { + private final CostRemoveCounter costRemoveCounter; + private final String type; + private final SpellAbility sa; + private final int nNeeded; + private static final long serialVersionUID = 734256837615635021L; + private List typeList; + private int nRemove = 0; + + /** + * TODO: Write javadoc for Constructor. + * @param costRemoveCounter + * @param type + * @param sa + * @param nNeeded + * @param payment + */ + public InputPayCostRemoveCounterFrom(CountDownLatch cdl, CostRemoveCounter costRemoveCounter, String type, SpellAbility sa, + int nNeeded, CostPayment payment) { + super(cdl, payment); + this.costRemoveCounter = costRemoveCounter; + this.type = type; + this.sa = sa; + this.nNeeded = nNeeded; + + } + + @Override + public void showMessage() { + if (nNeeded == 0) { + this.done(); + } + + this.typeList = new ArrayList(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone())); + this.typeList = CardLists.getValidCards(this.typeList, type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); + + for (int i = 0; i < nNeeded; i++) { + if (this.typeList.size() == 0) { + this.cancel(); + } + + final Card o = GuiChoose + .oneOrNone("Remove counter(s) from a card in " + costRemoveCounter.getZone(), this.typeList); + + if (o != null) { + final Card card = o; + + if (card.getCounters(costRemoveCounter.getCounter()) > 0) { + this.nRemove++; + costRemoveCounter.addToList(card); + card.subtractCounter(costRemoveCounter.getCounter(), 1); + + if (card.getCounters(costRemoveCounter.getCounter()) == 0) { + this.typeList.remove(card); + } + + if (nNeeded == this.nRemove) { + this.done(); + } else { + this.showMessage(); + } + } + } else { + this.cancel(); + break; + } + } + } + } + private final CounterType counter; private int lastPaidAmount = 0; private ZoneType zone; @@ -221,7 +363,7 @@ public class CostRemoveCounter extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); Integer c = this.convertAmount(); int maxCounters = 0; @@ -237,15 +379,18 @@ public class CostRemoveCounter extends CostPartWithList { } } + final Input inp; + CountDownLatch cdl = new CountDownLatch(1); if (this.getZone().equals(ZoneType.Battlefield)) { - final Input inp = CostRemoveCounter.removeCounterType(ability, this.getType(), payment, this, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + inp = new InputPayCostRemoveCounterType(cdl, payment, c, ability, this.getType(), this); + } else { + inp = new InputPayCostRemoveCounterFrom(cdl, this, this.getType(), ability, c, payment); } - else { - final Input inp = CostRemoveCounter.removeCounterTypeFrom(ability, this.getType(), payment, this, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - } - return false; + setInputAndWait(inp, cdl); + + if ( !payment.isCanceled() ) + addListToHash(ability, "CounterRemove"); + return; } maxCounters = source.getCounters(this.counter); @@ -268,13 +413,9 @@ public class CostRemoveCounter extends CostPartWithList { source.setSVar("CostCountersRemoved", "Number$" + Integer.toString(c)); source.subtractCounter(this.counter, c); this.setLastPaidAmount(c); - payment.setPaidManaPart(this); } else { payment.setCancel(true); - payment.getRequirements().finishPaying(); - return false; } - return true; } /* @@ -320,172 +461,4 @@ public class CostRemoveCounter extends CostPartWithList { } return true; } - - /** - *

- * returnType. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param type - * a {@link java.lang.String} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param costRemoveCounter - * TODO - * @param nNeeded - * the n needed - * @return a {@link forge.control.input.Input} object. - */ - public static Input removeCounterType(final SpellAbility sa, final String type, final CostPayment payment, - final CostRemoveCounter costRemoveCounter, final int nNeeded) { - final Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - private List typeList; - private int nRemove = 0; - - @Override - public void showMessage() { - if ((nNeeded == 0) || (nNeeded == this.nRemove)) { - this.done(); - } - - final StringBuilder msg = new StringBuilder("Remove "); - final int nLeft = nNeeded - this.nRemove; - msg.append(nLeft).append(" "); - msg.append(costRemoveCounter.getCounter().getName()).append(" counters from "); - msg.append(costRemoveCounter.getDescriptiveType()); - - this.typeList = CardLists.getValidCards(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone()), type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); - - // TODO Tabulate typelist vs nNeeded to see if there are enough counters to remove - - CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - if (this.typeList.contains(card)) { - if (card.getCounters(costRemoveCounter.getCounter()) > 0) { - this.nRemove++; - costRemoveCounter.addToList(card); - card.subtractCounter(costRemoveCounter.getCounter(), 1); - - if (nNeeded == this.nRemove) { - this.done(); - } else { - this.showMessage(); - } - } - } - } - - public void done() { - this.stop(); - costRemoveCounter.addListToHash(sa, "CounterRemove"); - payment.paidCost(costRemoveCounter); - } - - public void cancel() { - this.stop(); - costRemoveCounter.addListToHash(sa, "CounterRemove"); - payment.cancelCost(costRemoveCounter); - } - }; - - return target; - } - - /** - *

- * returnType. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param type - * a {@link java.lang.String} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param costRemoveCounter - * TODO - * @param nNeeded - * the n needed - * @return a {@link forge.control.input.Input} object. - */ - public static Input removeCounterTypeFrom(final SpellAbility sa, final String type, final CostPayment payment, - final CostRemoveCounter costRemoveCounter, final int nNeeded) { - final Input target = new Input() { - private static final long serialVersionUID = 734256837615635021L; - private List typeList; - private int nRemove = 0; - - @Override - public void showMessage() { - if (nNeeded == 0) { - this.done(); - } - - this.typeList = new ArrayList(sa.getActivatingPlayer().getCardsIn(costRemoveCounter.getZone())); - this.typeList = CardLists.getValidCards(this.typeList, type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); - - for (int i = 0; i < nNeeded; i++) { - if (this.typeList.size() == 0) { - this.cancel(); - } - - final Card o = GuiChoose - .oneOrNone("Remove counter(s) from a card in " + costRemoveCounter.getZone(), this.typeList); - - if (o != null) { - final Card card = o; - - if (card.getCounters(costRemoveCounter.getCounter()) > 0) { - this.nRemove++; - costRemoveCounter.addToList(card); - card.subtractCounter(costRemoveCounter.getCounter(), 1); - - if (card.getCounters(costRemoveCounter.getCounter()) == 0) { - this.typeList.remove(card); - } - - if (nNeeded == this.nRemove) { - this.done(); - } else { - this.showMessage(); - } - } - } else { - this.cancel(); - break; - } - } - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - public void done() { - this.stop(); - costRemoveCounter.addListToHash(sa, "CounterRemove"); - payment.paidCost(costRemoveCounter); - } - - public void cancel() { - this.stop(); - costRemoveCounter.addListToHash(sa, "CounterRemove"); - payment.cancelCost(); - } - }; - return target; - } } diff --git a/src/main/java/forge/card/cost/CostReturn.java b/src/main/java/forge/card/cost/CostReturn.java index 5849a50a64c..c8c0f554379 100644 --- a/src/main/java/forge/card/cost/CostReturn.java +++ b/src/main/java/forge/card/cost/CostReturn.java @@ -19,8 +19,7 @@ package forge.card.cost; import java.util.ArrayList; import java.util.List; - -import javax.swing.JOptionPane; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; @@ -33,6 +32,7 @@ import forge.game.ai.ComputerUtil; import forge.game.player.AIPlayer; import forge.game.player.Player; import forge.game.zone.ZoneType; +import forge.gui.GuiDialog; import forge.gui.match.CMatchUI; import forge.view.ButtonUtil; @@ -42,6 +42,96 @@ import forge.view.ButtonUtil; public class CostReturn extends CostPartWithList { // Return + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayReturnType extends Input { + private final SpellAbility sa; + private final CostReturn part; + private final int nNeeded; + private final String type; + private final CostPayment payment; + private static final long serialVersionUID = 2685832214519141903L; + private List typeList; + private int nReturns = 0; + private final CountDownLatch cdlDone; + + /** + * TODO: Write javadoc for Constructor. + * @param sa + * @param part + * @param nNeeded + * @param cdl + * @param type + * @param payment + */ + public InputPayReturnType(CountDownLatch cdl, SpellAbility sa, CostReturn part, int nNeeded, String type, + CostPayment payment) { + this.sa = sa; + this.part = part; + this.nNeeded = nNeeded; + this.type = type; + this.payment = payment; + cdlDone = cdl; + } + + @Override + public void showMessage() { + if (nNeeded == 0) { + this.done(); + } + + final StringBuilder msg = new StringBuilder("Return "); + final int nLeft = nNeeded - this.nReturns; + msg.append(nLeft).append(" "); + msg.append(type); + if (nLeft > 1) { + msg.append("s"); + } + + this.typeList = new ArrayList(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield)); + this.typeList = CardLists.getValidCards(this.typeList, type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); + CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); + ButtonUtil.enableOnlyCancel(); + } + + @Override + public void selectButtonCancel() { + this.cancel(); + } + + @Override + public void selectCard(final Card card) { + if (this.typeList.contains(card)) { + this.nReturns++; + part.addToList(card); + Singletons.getModel().getGame().getAction().moveToHand(card); + this.typeList.remove(card); + // in case nothing else to return + if (this.nReturns == nNeeded) { + this.done(); + } else if (this.typeList.size() == 0) { + // happen + this.cancel(); + } else { + this.showMessage(); + } + } + } + + public void done() { + this.stop(); + cdlDone.countDown(); + } + + public void cancel() { + this.stop(); + payment.cancelCost(); + cdlDone.countDown(); + } + } + /** * Instantiates a new cost return. * @@ -135,7 +225,7 @@ public class CostReturn extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); Integer c = this.convertAmount(); final Player activator = ability.getActivatingPlayer(); @@ -150,13 +240,25 @@ public class CostReturn extends CostPartWithList { } } if (this.payCostFromSource()) { - final Input inp = CostReturn.returnThis(ability, payment, this); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + final Card card = ability.getSourceCard(); + if (card.getController() == ability.getActivatingPlayer() && card.isInPlay()) { + boolean confirm = GuiDialog.confirm(card, card.getName() + " - Return to Hand?"); + if (confirm) { + addToList(card); + Singletons.getModel().getGame().getAction().moveToHand(card); + } else { + payment.cancelCost(); + } + } } else { - final Input inp = CostReturn.returnType(ability, this.getType(), payment, this, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + CountDownLatch cdl = new CountDownLatch(1); + final Input target = new InputPayReturnType(cdl, ability, this, c, this.getType(), payment); + final Input inp = target; + setInputAndWait(inp, cdl); } - return false; + + if (!payment.isCanceled()) + addListToHash(ability, "Returned"); } /* @@ -187,131 +289,5 @@ public class CostReturn extends CostPartWithList { // Inputs - /** - *

- * returnType. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param type - * a {@link java.lang.String} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @param nNeeded - * the n needed - * @return a {@link forge.control.input.Input} object. - */ - public static Input returnType(final SpellAbility sa, final String type, final CostPayment payment, - final CostReturn part, final int nNeeded) { - final Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - private List typeList; - private int nReturns = 0; - @Override - public void showMessage() { - if (nNeeded == 0) { - this.done(); - } - - final StringBuilder msg = new StringBuilder("Return "); - final int nLeft = nNeeded - this.nReturns; - msg.append(nLeft).append(" "); - msg.append(type); - if (nLeft > 1) { - msg.append("s"); - } - - this.typeList = new ArrayList(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield)); - this.typeList = CardLists.getValidCards(this.typeList, type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()); - CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - if (this.typeList.contains(card)) { - this.nReturns++; - part.addToList(card); - Singletons.getModel().getGame().getAction().moveToHand(card); - this.typeList.remove(card); - // in case nothing else to return - if (this.nReturns == nNeeded) { - this.done(); - } else if (this.typeList.size() == 0) { - // happen - this.cancel(); - } else { - this.showMessage(); - } - } - } - - public void done() { - this.stop(); - part.addListToHash(sa, "Returned"); - payment.paidCost(part); - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } - }; - - return target; - } // returnType() - - /** - *

- * returnThis. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @return a {@link forge.control.input.Input} object. - */ - public static Input returnThis(final SpellAbility sa, final CostPayment payment, final CostReturn part) { - final Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - - @Override - public void showMessage() { - final Card card = sa.getSourceCard(); - if (card.getController().isHuman() && card.isInPlay()) { - final StringBuilder sb = new StringBuilder(); - sb.append(card.getName()); - sb.append(" - Return to Hand?"); - final Object[] possibleValues = { "Yes", "No" }; - final Object choice = JOptionPane.showOptionDialog(null, sb.toString(), card.getName() + " - Cost", - JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, possibleValues, - possibleValues[0]); - if (choice.equals(0)) { - part.addToList(card); - Singletons.getModel().getGame().getAction().moveToHand(card); - this.stop(); - part.addListToHash(sa, "Returned"); - payment.paidCost(part); - } else { - this.stop(); - payment.cancelCost(); - } - } - } - }; - - return target; - } // input_sacrifice() } diff --git a/src/main/java/forge/card/cost/CostReveal.java b/src/main/java/forge/card/cost/CostReveal.java index 42060d82b55..d4021fef02c 100644 --- a/src/main/java/forge/card/cost/CostReveal.java +++ b/src/main/java/forge/card/cost/CostReveal.java @@ -19,6 +19,7 @@ package forge.card.cost; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; @@ -41,6 +42,108 @@ import forge.view.ButtonUtil; public class CostReveal extends CostPartWithList { // Reveal + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayReveal extends Input { + private final CostReveal part; + private final String discType; + private final List handList; + private final SpellAbility sa; + private final CostPayment payment; + private final int nNeeded; + private static final long serialVersionUID = -329993322080934435L; + private int nReveal = 0; + private final CountDownLatch cdlDone; + + /** + * TODO: Write javadoc for Constructor. + * @param part + * @param discType + * @param handList + * @param sa + * @param payment + * @param nNeeded + */ + public InputPayReveal(CountDownLatch cdl, CostReveal part, String discType, List handList, SpellAbility sa, + CostPayment payment, int nNeeded) { + this.cdlDone = cdl; + this.part = part; + this.discType = discType; + this.handList = handList; + this.sa = sa; + this.payment = payment; + this.nNeeded = nNeeded; + } + + @Override + public void showMessage() { + if (nNeeded == 0) { + this.done(); + } + + /*if (handList.size() + this.nReveal < nNeeded) { + this.stop(); + }*/ + final StringBuilder type = new StringBuilder(""); + if (!discType.equals("Card")) { + type.append(" ").append(discType); + } + final StringBuilder sb = new StringBuilder(); + sb.append("Select a "); + sb.append(part.getDescriptiveType()); + sb.append(" to reveal."); + if (nNeeded > 1) { + sb.append(" You have "); + sb.append(nNeeded - this.nReveal); + sb.append(" remaining."); + } + CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString()); + ButtonUtil.enableOnlyCancel(); + } + + @Override + public void selectButtonCancel() { + this.cancel(); + } + + @Override + public void selectCard(final Card card) { + Zone zone = Singletons.getModel().getGame().getZoneOf(card); + if (zone.is(ZoneType.Hand) && handList.contains(card)) { + // send in List for Typing + handList.remove(card); + part.addToList(card); + this.nReveal++; + + // in case no more cards in hand + if (this.nReveal == nNeeded) { + this.done(); + } else if (sa.getActivatingPlayer().getZone(ZoneType.Hand).size() == 0) { + // really + // shouldn't + // happen + this.cancel(); + } else { + this.showMessage(); + } + } + } + + public void cancel() { + this.stop(); + payment.cancelCost(); + cdlDone.countDown(); + } + + public void done() { + this.stop(); + // "Inform" AI of the revealed cards + cdlDone.countDown(); + } + } + /** * Instantiates a new cost reveal. * @@ -150,17 +253,15 @@ public class CostReveal extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final Player activator = ability.getActivatingPlayer(); final String amount = this.getAmount(); this.resetList(); if (this.payCostFromSource()) { this.addToList(source); - payment.setPaidManaPart(this); } else if (this.getType().equals("Hand")) { this.setList(new ArrayList(activator.getCardsIn(ZoneType.Hand))); - payment.setPaidManaPart(this); } else { Integer num = this.convertAmount(); @@ -176,15 +277,13 @@ public class CostReveal extends CostPartWithList { } } if (num > 0) { - final Input inp = CostReveal.inputRevealCost(this.getType(), handList, payment, this, ability, num); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - return false; - } else { - payment.setPaidManaPart(this); - } + final CountDownLatch cdl = new CountDownLatch(1); + final Input inp = new InputPayReveal(cdl, this, this.getType(), handList, ability, payment, num);; + setInputAndWait(inp, cdl); + } } - this.addListToHash(ability, "Revealed"); - return true; + if ( !payment.isCanceled()) + this.addListToHash(ability, "Revealed"); } /* @@ -222,100 +321,5 @@ public class CostReveal extends CostPartWithList { // Inputs - /** - *

- * input_discardCost. - *

- * - * @param discType - * a {@link java.lang.String} object. - * @param handList - * a {@link forge.CardList} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @param sa - * TODO - * @param nNeeded - * a int. - * @return a {@link forge.control.input.Input} object. - */ - public static Input inputRevealCost(final String discType, final List handList, final CostPayment payment, - final CostReveal part, final SpellAbility sa, final int nNeeded) { - final Input target = new Input() { - private static final long serialVersionUID = -329993322080934435L; - - private int nReveal = 0; - - @Override - public void showMessage() { - if (nNeeded == 0) { - this.done(); - } - - /*if (handList.size() + this.nReveal < nNeeded) { - this.stop(); - }*/ - final StringBuilder type = new StringBuilder(""); - if (!discType.equals("Card")) { - type.append(" ").append(discType); - } - final StringBuilder sb = new StringBuilder(); - sb.append("Select a "); - sb.append(part.getDescriptiveType()); - sb.append(" to reveal."); - if (nNeeded > 1) { - sb.append(" You have "); - sb.append(nNeeded - this.nReveal); - sb.append(" remaining."); - } - CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString()); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - Zone zone = Singletons.getModel().getGame().getZoneOf(card); - if (zone.is(ZoneType.Hand) && handList.contains(card)) { - // send in List for Typing - handList.remove(card); - part.addToList(card); - this.nReveal++; - - // in case no more cards in hand - if (this.nReveal == nNeeded) { - this.done(); - } else if (sa.getActivatingPlayer().getZone(ZoneType.Hand).size() == 0) { - // really - // shouldn't - // happen - this.cancel(); - } else { - this.showMessage(); - } - } - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } - - public void done() { - this.stop(); - // "Inform" AI of the revealed cards - part.addListToHash(sa, "Revealed"); - payment.paidCost(part); - } - }; - - return target; - } // input_discard() } diff --git a/src/main/java/forge/card/cost/CostSacrifice.java b/src/main/java/forge/card/cost/CostSacrifice.java index 75d1994e5f1..462e9dc267e 100644 --- a/src/main/java/forge/card/cost/CostSacrifice.java +++ b/src/main/java/forge/card/cost/CostSacrifice.java @@ -19,20 +19,19 @@ package forge.card.cost; import java.util.ArrayList; import java.util.List; - -import javax.swing.JOptionPane; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.spellability.SpellAbility; -import forge.control.input.Input; import forge.game.GameState; import forge.game.ai.ComputerUtil; import forge.game.player.AIPlayer; import forge.game.player.Player; import forge.game.zone.ZoneType; +import forge.gui.GuiDialog; import forge.gui.match.CMatchUI; import forge.view.ButtonUtil; @@ -41,6 +40,73 @@ import forge.view.ButtonUtil; */ public class CostSacrifice extends CostPartWithList { + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostSacrificeFromList extends InputPayCostBase { + private final CostSacrifice part; + private final SpellAbility sa; + private final int nNeeded; + private final List typeList; + private static final long serialVersionUID = 2685832214519141903L; + private int nSacrifices = 0; + + /** + * TODO: Write javadoc for Constructor. + * @param part + * @param sa + * @param nNeeded + * @param payment + * @param typeList + */ + public InputPayCostSacrificeFromList(CountDownLatch cdl, CostSacrifice part, SpellAbility sa, int nNeeded, CostPayment payment, + List typeList) { + super(cdl, payment); + this.part = part; + this.sa = sa; + this.nNeeded = nNeeded; + this.typeList = typeList; + } + + @Override + public void showMessage() { + if (nNeeded == 0) { + this.done(); + } + + final StringBuilder msg = new StringBuilder("Sacrifice "); + final int nLeft = nNeeded - this.nSacrifices; + msg.append(nLeft).append(" "); + msg.append(part.getDescriptiveType()); + if (nLeft > 1) { + msg.append("s"); + } + + CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); + ButtonUtil.enableOnlyCancel(); + } + + @Override + public void selectCard(final Card card) { + if (typeList.contains(card)) { + this.nSacrifices++; + part.addToList(card); + Singletons.getModel().getGame().getAction().sacrifice(card, sa); + typeList.remove(card); + // in case nothing else to sacrifice + if (this.nSacrifices == nNeeded) { + this.done(); + } else if (typeList.size() == 0) { + // happen + this.cancel(); + } else { + this.showMessage(); + } + } + } + } + /** * Instantiates a new cost sacrifice. * @@ -144,7 +210,7 @@ public class CostSacrifice extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final String amount = this.getAmount(); final String type = this.getType(); final Player activator = ability.getActivatingPlayer(); @@ -155,33 +221,41 @@ public class CostSacrifice extends CostPartWithList { } if (this.payCostFromSource()) { - final Input inp = CostSacrifice.sacrificeThis(ability, payment, this); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + final Card card = ability.getSourceCard(); + if (card.getController() == ability.getActivatingPlayer() && card.isInPlay()) { + if (GuiDialog.confirm(card, card.getName() + " - Sacrifice?")) { + this.addToList(card); + Singletons.getModel().getGame().getAction().sacrifice(card, ability); + } else { + payment.cancelCost(); + } + } } else if (amount.equals("All")) { this.setList(list); - CostSacrifice.sacrificeAll(ability, payment, this, list); - //this.addListToHash(ability, "Sacrificed"); - return true; + // TODO Ask First + for (final Card card : list) { + payment.getAbility().addCostToHashList(card, "Sacrificed"); + Singletons.getModel().getGame().getAction().sacrifice(card, ability); + } + payment.setPaidPart(this); } else { Integer c = this.convertAmount(); if (c == null) { - final String sVar = ability.getSVar(amount); // Generalize this - if (sVar.equals("XChoice")) { + if (ability.getSVar(amount).equals("XChoice")) { c = CostUtil.chooseXValue(source, ability, list.size()); } else { c = AbilityUtils.calculateAmount(source, amount, ability); } } if (0 == c.intValue()) { - payment.setPaidManaPart(this); - return true; + return; } - final Input inp = CostSacrifice.sacrificeFromList(ability, payment, this, list, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); + final CountDownLatch cdl = new CountDownLatch(1); + setInputAndWait(new InputPayCostSacrificeFromList(cdl, this, ability, c, payment, list), cdl); } - - return false; + if( !payment.isCanceled()) + addListToHash(ability, "Sacrificed"); } /* @@ -224,154 +298,4 @@ public class CostSacrifice extends CostPartWithList { // Inputs - /** - *

- * sacrificeAllType. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @param typeList - * TODO - */ - public static void sacrificeAll(final SpellAbility sa, final CostPayment payment, final CostPart part, - final List typeList) { - // TODO Ask First - for (final Card card : typeList) { - payment.getAbility().addCostToHashList(card, "Sacrificed"); - Singletons.getModel().getGame().getAction().sacrifice(card, sa); - } - - payment.setPaidManaPart(part); - } - - /** - *

- * sacrificeFromList. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @param typeList - * TODO - * @param nNeeded - * the n needed - * @return a {@link forge.control.input.Input} object. - */ - public static Input sacrificeFromList(final SpellAbility sa, final CostPayment payment, final CostSacrifice part, - final List typeList, final int nNeeded) { - final Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - private int nSacrifices = 0; - - @Override - public void showMessage() { - if (nNeeded == 0) { - this.done(); - } - - final StringBuilder msg = new StringBuilder("Sacrifice "); - final int nLeft = nNeeded - this.nSacrifices; - msg.append(nLeft).append(" "); - msg.append(part.getDescriptiveType()); - if (nLeft > 1) { - msg.append("s"); - } - - CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - if (typeList.contains(card)) { - this.nSacrifices++; - part.addToList(card); - Singletons.getModel().getGame().getAction().sacrifice(card, sa); - typeList.remove(card); - // in case nothing else to sacrifice - if (this.nSacrifices == nNeeded) { - this.done(); - } else if (typeList.size() == 0) { - // happen - this.cancel(); - } else { - this.showMessage(); - } - } - } - - public void done() { - this.stop(); - part.addListToHash(sa, "Sacrificed"); - payment.paidCost(part); - } - - public void cancel() { - this.stop(); - - payment.cancelCost(); - } - }; - - return target; - } // sacrificeType() - - /** - *

- * sacrificeThis. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param part - * TODO - * @return a {@link forge.control.input.Input} object. - */ - public static Input sacrificeThis(final SpellAbility sa, final CostPayment payment, final CostSacrifice part) { - final Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - - @Override - public void showMessage() { - final Card card = sa.getSourceCard(); - if (card.getController().isHuman() && card.isInPlay()) { - final StringBuilder sb = new StringBuilder(); - sb.append(card.getName()); - sb.append(" - Sacrifice?"); - final Object[] possibleValues = { "Yes", "No" }; - final Object choice = JOptionPane.showOptionDialog(null, sb.toString(), card.getName() + " - Cost", - JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, possibleValues, - possibleValues[0]); - if (choice.equals(0)) { - part.addToList(card); - part.addListToHash(sa, "Sacrificed"); - Singletons.getModel().getGame().getAction().sacrifice(card, sa); - this.stop(); - payment.paidCost(part); - } else { - this.stop(); - payment.cancelCost(); - } - } - } - }; - - return target; - } // input_sacrifice() } diff --git a/src/main/java/forge/card/cost/CostTap.java b/src/main/java/forge/card/cost/CostTap.java index 43ba105933f..f14da7667e1 100644 --- a/src/main/java/forge/card/cost/CostTap.java +++ b/src/main/java/forge/card/cost/CostTap.java @@ -93,14 +93,12 @@ public class CostTap extends CostPart { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { // if (!canPay(ability, source, ability.getActivatingPlayer(), // payment.getCost())) // return false; source.tap(); - payment.setPaidManaPart(this); - return true; } /* diff --git a/src/main/java/forge/card/cost/CostTapType.java b/src/main/java/forge/card/cost/CostTapType.java index c08f2660054..b39df05fd9f 100644 --- a/src/main/java/forge/card/cost/CostTapType.java +++ b/src/main/java/forge/card/cost/CostTapType.java @@ -19,6 +19,7 @@ package forge.card.cost; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; @@ -41,6 +42,88 @@ import forge.view.ButtonUtil; */ public class CostTapType extends CostPartWithList { + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostTapType extends Input { + private final CostTapType tapType; + private final int nCards; + private final List cardList; + private final CostPayment payment; + private static final long serialVersionUID = 6438988130447851042L; + private int nTapped = 0; + private final CountDownLatch cdlDone; + + /** + * TODO: Write javadoc for Constructor. + * @param sa + * @param tapType + * @param nCards + * @param cardList + * @param payment + */ + public InputPayCostTapType(CountDownLatch cdl, CostTapType tapType, int nCards, List cardList, + CostPayment payment) { + cdlDone = cdl; + this.tapType = tapType; + this.nCards = nCards; + this.cardList = cardList; + this.payment = payment; + } + + @Override + public void showMessage() { + + final int left = nCards - this.nTapped; + CMatchUI.SINGLETON_INSTANCE + .showMessage("Select a " + tapType.getDescription() + " to tap (" + left + " left)"); + ButtonUtil.enableOnlyCancel(); + if (nCards == 0) { + this.done(); + } + } + + @Override + public void selectButtonCancel() { + this.cancel(); + } + + @Override + public void selectCard(final Card card) { + Zone zone = Singletons.getModel().getGame().getZoneOf(card); + if (zone.is(ZoneType.Battlefield) && cardList.contains(card) && card.isUntapped()) { + // send in List for Typing + card.tap(); + tapType.addToList(card); + cardList.remove(card); + + this.nTapped++; + + if (this.nTapped == nCards) { + this.done(); + } else if (cardList.size() == 0) { + // happen + this.cancel(); + } else { + this.showMessage(); + } + } + } + + public void cancel() { + this.stop(); + payment.cancelCost(); + cdlDone.countDown(); + } + + public void done() { + this.stop(); + cdlDone.countDown(); + + } + } + /** * Instantiates a new cost tap type. * @@ -149,7 +232,7 @@ public class CostTapType extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { List typeList = new ArrayList(ability.getActivatingPlayer().getCardsIn(ZoneType.Battlefield)); typeList = CardLists.getValidCards(typeList, this.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard()); typeList = CardLists.filter(typeList, Presets.UNTAPPED); @@ -164,10 +247,10 @@ public class CostTapType extends CostPartWithList { c = AbilityUtils.calculateAmount(source, amount, ability); } } - - final Input inp = CostTapType.inputTapXCost(this, typeList, ability, payment, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - return false; + CountDownLatch cdl = new CountDownLatch(1); + setInputAndWait(new InputPayCostTapType(cdl, this, c, typeList, payment), cdl); + if( !payment.isCanceled()) + addListToHash(ability, "Tapped"); } /* @@ -207,81 +290,4 @@ public class CostTapType extends CostPartWithList { // Inputs - /** - *

- * input_tapXCost. - *

- * - * @param tapType - * the tap type - * @param cardList - * a {@link forge.CardList} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param nCards - * a int. - * @return a {@link forge.control.input.Input} object. - */ - public static Input inputTapXCost(final CostTapType tapType, final List cardList, final SpellAbility sa, - final CostPayment payment, final int nCards) { - final Input target = new Input() { - - private static final long serialVersionUID = 6438988130447851042L; - private int nTapped = 0; - - @Override - public void showMessage() { - - final int left = nCards - this.nTapped; - CMatchUI.SINGLETON_INSTANCE - .showMessage("Select a " + tapType.getDescription() + " to tap (" + left + " left)"); - ButtonUtil.enableOnlyCancel(); - if (nCards == 0) { - this.done(); - } - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - Zone zone = Singletons.getModel().getGame().getZoneOf(card); - if (zone.is(ZoneType.Battlefield) && cardList.contains(card) && card.isUntapped()) { - // send in List for Typing - card.tap(); - tapType.addToList(card); - cardList.remove(card); - - this.nTapped++; - - if (this.nTapped == nCards) { - this.done(); - } else if (cardList.size() == 0) { - // happen - this.cancel(); - } else { - this.showMessage(); - } - } - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } - - public void done() { - this.stop(); - tapType.addListToHash(sa, "Tapped"); - payment.paidCost(tapType); - } - }; - - return target; - } // input_tapXCost() } diff --git a/src/main/java/forge/card/cost/CostUnattach.java b/src/main/java/forge/card/cost/CostUnattach.java index cec1332bbab..ef620d61724 100644 --- a/src/main/java/forge/card/cost/CostUnattach.java +++ b/src/main/java/forge/card/cost/CostUnattach.java @@ -114,7 +114,7 @@ public class CostUnattach extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { this.resetList(); Player activator = ability.getActivatingPlayer(); Card cardToUnattach = findCardToUnattach(source, activator, ability); @@ -123,14 +123,9 @@ public class CostUnattach extends CostPartWithList { cardToUnattach.unEquipCard(equippingCard); this.addToList(cardToUnattach); this.addListToHash(ability, "Unattached"); - payment.setPaidManaPart(this); } else { payment.setCancel(true); - payment.getRequirements().finishPaying(); - return false; } - - return true; } private Card findCardToUnattach(final Card source, Player activator, SpellAbility ability) { diff --git a/src/main/java/forge/card/cost/CostUntap.java b/src/main/java/forge/card/cost/CostUntap.java index 04bbc79d314..6490a4d67ab 100644 --- a/src/main/java/forge/card/cost/CostUntap.java +++ b/src/main/java/forge/card/cost/CostUntap.java @@ -92,14 +92,12 @@ public class CostUntap extends CostPart { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { // if (!canPay(ability, source, ability.getActivatingPlayer(), // payment.getCost())) // return false; source.untap(); - payment.setPaidManaPart(this); - return true; } /* diff --git a/src/main/java/forge/card/cost/CostUntapType.java b/src/main/java/forge/card/cost/CostUntapType.java index 57bffb896f0..fb26df53138 100644 --- a/src/main/java/forge/card/cost/CostUntapType.java +++ b/src/main/java/forge/card/cost/CostUntapType.java @@ -18,6 +18,7 @@ package forge.card.cost; import java.util.List; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.CardLists; @@ -25,7 +26,6 @@ import forge.CardPredicates.Presets; import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.spellability.SpellAbility; -import forge.control.input.Input; import forge.game.GameState; import forge.game.ai.ComputerUtil; import forge.game.player.AIPlayer; @@ -40,6 +40,73 @@ import forge.view.ButtonUtil; */ public class CostUntapType extends CostPartWithList { + /** + * TODO: Write javadoc for this type. + * + */ + public static final class InputPayCostUntapY extends InputPayCostBase { + private final int nCards; + private final List cardList; + private final CostUntapType untapType; + private static final long serialVersionUID = -7151144318287088542L; + private int nUntapped = 0; + + + /** + * TODO: Write javadoc for Constructor. + * @param nCards + * @param cardList + * @param untapType + * @param sa + * @param payment + */ + public InputPayCostUntapY(CountDownLatch cdl, int nCards, List cardList, CostUntapType untapType, CostPayment payment) { + super(cdl, payment); + this.nCards = nCards; + this.cardList = cardList; + this.untapType = untapType; + } + + @Override + public void showMessage() { + if (nCards == 0) { + this.done(); + } + + if (cardList.size() == 0) { + this.stop(); + } + + final int left = nCards - this.nUntapped; + CMatchUI.SINGLETON_INSTANCE + .showMessage("Select a " + untapType.getDescription() + " to untap (" + left + " left)"); + ButtonUtil.enableOnlyCancel(); + } + + + + @Override + public void selectCard(final Card card) { + Zone zone = Singletons.getModel().getGame().getZoneOf(card); + if (zone.is(ZoneType.Battlefield) && cardList.contains(card) && card.isTapped()) { + // send in List for Typing + card.untap(); + untapType.addToList(card); + cardList.remove(card); + + this.nUntapped++; + + if (this.nUntapped == nCards) { + this.done(); + } else if (cardList.size() == 0) { + this.cancel(); + } else { + this.showMessage(); + } + } + } + } + /** * Instantiates a new cost untap type. * @@ -162,7 +229,7 @@ public class CostUntapType extends CostPartWithList { * forge.Card, forge.card.cost.Cost_Payment) */ @Override - public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + public final void payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { final boolean untap = payment.getCost().hasUntapCost(); List typeList = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield); typeList = CardLists.getValidCards(typeList, this.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard()); @@ -181,10 +248,11 @@ public class CostUntapType extends CostPartWithList { c = AbilityUtils.calculateAmount(source, amount, ability); } } - - final Input inp = CostUntapType.inputUntapYCost(this, typeList, ability, payment, c); - Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); - return false; + CountDownLatch cdl = new CountDownLatch(1); + setInputAndWait(new InputPayCostUntapY(cdl, c, typeList, this, payment), cdl); + + if ( !payment.isCanceled() ) + addListToHash(ability, "Untapped"); } /* @@ -227,84 +295,4 @@ public class CostUntapType extends CostPartWithList { // Inputs - /** - *

- * input_untapYCost. - *

- * - * @param untapType - * the untap type - * @param cardList - * a {@link forge.CardList} object. - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param payment - * a {@link forge.card.cost.CostPayment} object. - * @param nCards - * a int. - * @return a {@link forge.control.input.Input} object. - */ - public static Input inputUntapYCost(final CostUntapType untapType, final List cardList, final SpellAbility sa, - final CostPayment payment, final int nCards) { - final Input target = new Input() { - - private static final long serialVersionUID = -7151144318287088542L; - private int nUntapped = 0; - - @Override - public void showMessage() { - if (nCards == 0) { - this.done(); - } - - if (cardList.size() == 0) { - this.stop(); - } - - final int left = nCards - this.nUntapped; - CMatchUI.SINGLETON_INSTANCE - .showMessage("Select a " + untapType.getDescription() + " to untap (" + left + " left)"); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - this.cancel(); - } - - @Override - public void selectCard(final Card card) { - Zone zone = Singletons.getModel().getGame().getZoneOf(card); - if (zone.is(ZoneType.Battlefield) && cardList.contains(card) && card.isTapped()) { - // send in List for Typing - card.untap(); - untapType.addToList(card); - cardList.remove(card); - - this.nUntapped++; - - if (this.nUntapped == nCards) { - this.done(); - } else if (cardList.size() == 0) { - this.cancel(); - } else { - this.showMessage(); - } - } - } - - public void cancel() { - this.stop(); - payment.cancelCost(); - } - - public void done() { - this.stop(); - untapType.addListToHash(sa, "Untapped"); - payment.paidCost(untapType); - } - }; - - return target; - } // input_untapYCost() } diff --git a/src/main/java/forge/card/cost/InputPayCostBase.java b/src/main/java/forge/card/cost/InputPayCostBase.java new file mode 100644 index 00000000000..8d9f452189d --- /dev/null +++ b/src/main/java/forge/card/cost/InputPayCostBase.java @@ -0,0 +1,41 @@ +package forge.card.cost; + +import java.util.concurrent.CountDownLatch; + +import forge.control.input.Input; + +/** + * TODO: Write javadoc for this type. + * + */ +abstract class InputPayCostBase extends Input { + private static final long serialVersionUID = -2967434867139585579L; + + private final CountDownLatch cdlDone; + private final CostPayment payment; + /** + * TODO: Write javadoc for Constructor. + * @param cdl + * @param payment + */ + public InputPayCostBase(CountDownLatch cdl, CostPayment payment0) { + cdlDone = cdl; + payment = payment0; + } + + @Override + final public void selectButtonCancel() { + this.cancel(); + } + + final protected void done() { + this.stop(); + cdlDone.countDown(); + } + + final public void cancel() { + this.stop(); + payment.cancelCost(); + cdlDone.countDown(); + } +} \ No newline at end of file diff --git a/src/main/java/forge/card/spellability/SpellAbilityRequirements.java b/src/main/java/forge/card/spellability/SpellAbilityRequirements.java index 9978017329f..7d3ee7c6b4e 100644 --- a/src/main/java/forge/card/spellability/SpellAbilityRequirements.java +++ b/src/main/java/forge/card/spellability/SpellAbilityRequirements.java @@ -176,29 +176,11 @@ public class SpellAbilityRequirements { */ public final void needPayment() { if (!this.isFree) { - this.startPaying(); - } else { - this.finishPaying(); - } - } + this.payment.setRequirements(this); + this.payment.changeCost(); + this.payment.payCost(); + } - /** - *

- * startPaying. - *

- */ - public final void startPaying() { - this.payment.setRequirements(this); - this.payment.changeCost(); - this.payment.payCost(); - } - - /** - *

- * finishPaying. - *

- */ - public final void finishPaying() { if (this.payment.isCanceled()) { final Card c = this.ability.getSourceCard(); diff --git a/src/main/java/forge/control/FControl.java b/src/main/java/forge/control/FControl.java index c6922f5cc6e..15ccf0a43cd 100644 --- a/src/main/java/forge/control/FControl.java +++ b/src/main/java/forge/control/FControl.java @@ -155,7 +155,8 @@ public enum FControl { this.shortcuts = KeyboardShortcuts.attachKeyboardShortcuts(); this.display = FView.SINGLETON_INSTANCE.getLpnDocument(); - + + FSkin.setProgessBarMessage("About to load current quest."); // Preload quest data if present final File dirQuests = new File(NewConstants.QUEST_SAVE_DIR); final String questname = Singletons.getModel().getQuestPreferences().getPref(QPref.CURRENT_QUEST); @@ -164,6 +165,7 @@ public enum FControl { Singletons.getModel().getQuest().load(QuestDataIO.loadData(data)); } + FSkin.setProgessBarMessage("Will load AI profiles now."); // Preload AI profiles AiProfileUtil.loadAllProfiles(); @@ -178,6 +180,7 @@ public enum FControl { FView.SINGLETON_INSTANCE.getLpnDocument().addMouseListener(SOverflowUtil.getHideOverflowListener()); FView.SINGLETON_INSTANCE.getLpnDocument().addComponentListener(SResizingUtil.getWindowResizeListener()); + FSkin.setProgessBarMessage("Opening main window..."); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Singletons.getView().initialize(); } }); } diff --git a/src/main/java/forge/control/input/InputControl.java b/src/main/java/forge/control/input/InputControl.java index eda672e558f..00499c62e86 100644 --- a/src/main/java/forge/control/input/InputControl.java +++ b/src/main/java/forge/control/input/InputControl.java @@ -114,7 +114,8 @@ public class InputControl extends MyObservable implements java.io.Serializable { * a boolean. */ public final void resetInput() { - this.inputStack.pop(); + if ( !this.inputStack.isEmpty() ) + this.inputStack.pop(); this.updateObservers(); } @@ -208,8 +209,9 @@ public class InputControl extends MyObservable implements java.io.Serializable { PhaseHandler ph = game.getPhaseHandler(); final Input tmp = getActualInput(); - String message = String.format("%s's %s, priority of %s [%sP] input is %s", ph.getPlayerTurn(), ph.getPhase(), ph.getPriorityPlayer(), ph.isPlayerPriorityAllowed() ? "+" : "-", tmp == null ? "null" : tmp.getClass().getSimpleName()); + String message = String.format("%s's %s, priority of %s [%sP] input is %s \t stack:%s", ph.getPlayerTurn(), ph.getPhase(), ph.getPriorityPlayer(), ph.isPlayerPriorityAllowed() ? "+" : "-", tmp == null ? "null" : tmp.getClass().getSimpleName(), inputStack); System.out.println(message); + if (tmp != null) { //System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() ); CMessage.SINGLETON_INSTANCE.getInputControl().setInput(tmp); @@ -219,4 +221,18 @@ public class InputControl extends MyObservable implements java.io.Serializable { } } + /** + * TODO: Write javadoc for this method. + */ + private final static InputLockUI inpuptLock = new InputLockUI(); + public void lock() { + setInput(inpuptLock); + } + + public void unlock() { + if ( inputStack.isEmpty() || inputStack.peek() != inpuptLock ) + throw new RuntimeException("Trying to unlock input which is not locked! Do check when your threads terminate!"); + resetInput(); + } + } // InputControl diff --git a/src/main/java/forge/control/input/InputLockUI.java b/src/main/java/forge/control/input/InputLockUI.java index cd76856a653..e6f79ac7b90 100644 --- a/src/main/java/forge/control/input/InputLockUI.java +++ b/src/main/java/forge/control/input/InputLockUI.java @@ -14,5 +14,10 @@ public class InputLockUI extends Input { ButtonUtil.disableAll(); CMatchUI.SINGLETON_INSTANCE.showMessage("Waiting for actions..."); } + + @Override + public String toString() { + return "lockUI"; + } } diff --git a/src/main/java/forge/control/input/InputPayDiscardCost.java b/src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java similarity index 93% rename from src/main/java/forge/control/input/InputPayDiscardCost.java rename to src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java index c10d0e80f25..09137103c7e 100644 --- a/src/main/java/forge/control/input/InputPayDiscardCost.java +++ b/src/main/java/forge/control/input/InputPayDiscardCostWithCommands.java @@ -42,7 +42,7 @@ import forge.view.ButtonUtil; * @author Forge * @version $Id: InputPayManaCostAbility.java 15673 2012-05-23 14:01:35Z ArsenalNut $ */ -public class InputPayDiscardCost extends Input { +public class InputPayDiscardCostWithCommands extends Input { /** * Constant serialVersionUID=2685832214529141991L. */ @@ -70,7 +70,7 @@ public class InputPayDiscardCost extends Input { * @param unpaidCommand * a {@link forge.Command} object. */ - public InputPayDiscardCost(final CostDiscard cost, final SpellAbility sa, final Command paidCommand, + public InputPayDiscardCostWithCommands(final CostDiscard cost, final SpellAbility sa, final Command paidCommand, final Command unpaidCommand) { final Card source = sa.getSourceCard(); final Player human = Singletons.getControl().getPlayer(); diff --git a/src/main/java/forge/control/input/InputPayManaBase.java b/src/main/java/forge/control/input/InputPayManaBase.java index 0a350da4bc4..81188b89340 100644 --- a/src/main/java/forge/control/input/InputPayManaBase.java +++ b/src/main/java/forge/control/input/InputPayManaBase.java @@ -9,6 +9,7 @@ import java.util.Map; import forge.Card; import forge.CardUtil; import forge.Constant; +import forge.FThreads; import forge.Singletons; import forge.card.MagicColor; import forge.card.ability.ApiType; @@ -18,7 +19,10 @@ import forge.card.spellability.AbilityManaPart; import forge.card.spellability.SpellAbility; import forge.game.GameState; import forge.game.player.Player; +import forge.game.zone.ZoneType; import forge.gui.GuiChoose; +import forge.gui.framework.SDisplayUtil; +import forge.gui.match.views.VMessage; /** * TODO: Write javadoc for this type. @@ -33,19 +37,28 @@ public abstract class InputPayManaBase extends Input { protected final Player whoPays; protected final GameState game; protected ManaCostBeingPaid manaCost; + protected final SpellAbility saPaidFor; - protected InputPayManaBase(final GameState game) { + protected InputPayManaBase(final GameState game, SpellAbility saToPayFor) { this.game = game; this.whoPays = Singletons.getControl().getPlayer(); + this.saPaidFor = saToPayFor; } - /** - *

- * selectManaPool. - *

- * @param color a String that represents the Color the mana is coming from - */ - public abstract void selectManaPool(String color); + /** {@inheritDoc} */ + @Override + public void selectCard(final Card card) { + if (card.getManaAbility().isEmpty() || card.isInZone(ZoneType.Hand)) { + SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE); + return; + } + // only tap card if the mana is needed + activateManaAbility(card, this.manaCost); + } + + public void selectManaPool(String color) { + useManaFromPool(color, this.manaCost); + } /** *

@@ -103,7 +116,7 @@ public abstract class InputPayManaBase extends Input { * * @return ManaCost the amount of mana remaining to be paid after the mana is activated */ - protected static ManaCostBeingPaid activateManaAbility(String color, final SpellAbility saBeingPaidFor, ManaCostBeingPaid manaCost) { + protected void useManaFromPool(String color, ManaCostBeingPaid manaCost) { ManaPool mp = Singletons.getControl().getPlayer().getManaPool(); // Convert Color to short String @@ -111,8 +124,10 @@ public abstract class InputPayManaBase extends Input { if (!color.equalsIgnoreCase("Colorless")) { manaStr = CardUtil.getShortColor(color); } + + this.manaCost = mp.payManaFromPool(saPaidFor, manaCost, manaStr); - return mp.payManaFromPool(saBeingPaidFor, manaCost, manaStr); + onManaAbilityPlayed(saPaidFor.getActivatingPlayer(), null); } /** @@ -128,10 +143,10 @@ public abstract class InputPayManaBase extends Input { * a {@link forge.card.mana.ManaCostBeingPaid} object. * @return a {@link forge.card.mana.ManaCostBeingPaid} object. */ - protected ManaCostBeingPaid activateManaAbility(final SpellAbility sa, final Card card, ManaCostBeingPaid manaCost) { + protected void activateManaAbility(final Card card, ManaCostBeingPaid manaCost) { // make sure computer's lands aren't selected if (card.getController() != whoPays) { - return manaCost; + return; } @@ -170,7 +185,7 @@ public abstract class InputPayManaBase extends Input { continue; } else if (ma.isAbility() && ma.getRestrictions().isInstantSpeed()) { continue; - } else if (!m.meetsManaRestrictions(sa)) { + } else if (!m.meetsManaRestrictions(saPaidFor)) { continue; } @@ -185,16 +200,16 @@ public abstract class InputPayManaBase extends Input { } } if (abilities.isEmpty()) { - return manaCost; + return; } // Store some information about color costs to help with any mana choices String colorsNeeded = colorRequired.toString(); if ("1".equals(colorsNeeded)) { // only colorless left - if (sa.getSourceCard() != null - && !sa.getSourceCard().getSVar("ManaNeededToAvoidNegativeEffect").equals("")) { + if (saPaidFor.getSourceCard() != null + && !saPaidFor.getSourceCard().getSVar("ManaNeededToAvoidNegativeEffect").equals("")) { colorsNeeded = ""; - String[] negEffects = sa.getSourceCard().getSVar("ManaNeededToAvoidNegativeEffect").split(","); + String[] negEffects = saPaidFor.getSourceCard().getSVar("ManaNeededToAvoidNegativeEffect").split(","); for (String negColor : negEffects) { // convert long color strings to short color strings if (negColor.length() > 1) { @@ -216,8 +231,8 @@ public abstract class InputPayManaBase extends Input { // If the card has sunburst or any other ability that tracks mana spent, // skip express Mana choice - if (sa.getSourceCard() != null - && sa.getSourceCard().hasKeyword("Sunburst") && sa.isSpell()) { + if (saPaidFor.getSourceCard() != null + && saPaidFor.getSourceCard().hasKeyword("Sunburst") && saPaidFor.isSpell()) { colorsNeeded = "WUBRG"; skipExpress = true; } @@ -255,7 +270,7 @@ public abstract class InputPayManaBase extends Input { } } - if ((colorMatches.size() == 0)) { + if (colorMatches.isEmpty()) { // can only match colorless just grab the first and move on. choice = false; } else if (colorMatches.size() < abilities.size()) { @@ -282,14 +297,35 @@ public abstract class InputPayManaBase extends Input { // save off color needed for use by any mana and reflected mana subchosen.getManaPart().setExpressChoice(colorsNeeded); + System.out.println("Chosen sa=" + chosen + " of " + chosen.getSourceCard() + " to pay mana"); Player p = chosen.getActivatingPlayer(); - Singletons.getModel().getGame().getActionPlay().playSpellAbility(chosen, p); - - manaCost = p.getManaPool().payManaFromAbility(sa, manaCost, chosen); - - //AllZone.getHumanPlayer().getZone(ZoneType.Battlefield).updateObservers(); - // DO NOT REMOVE THIS, otherwise the cards don't always tap (copied) - return manaCost; - + p.getGame().getActionPlay().playManaAbilityAsPayment(chosen, p, this); } + + public void onManaAbilityPlayed(final Player p, final SpellAbility saPaymentSrc) { + if ( saPaymentSrc != null) // null comes when they've paid from pool + this.manaCost = p.getManaPool().payManaFromAbility(saPaidFor, manaCost, saPaymentSrc); + + onManaAbilityPaid(); + + FThreads.invokeInEDT(new Runnable( ) { + @Override + public void run() { + if (manaCost.isPaid()) { + done(); + } else if (Singletons.getModel().getMatch().getInput().getInput() == InputPayManaBase.this) { + showMessage(); + } + } + }); + } + + protected void onManaAbilityPaid() {} // some inputs overload it + protected abstract void done(); + + @Override + public String toString() { + return "PayManaBase (" + manaCost.toString() + ")"; + } + } diff --git a/src/main/java/forge/control/input/InputPayManaExecuteCommands.java b/src/main/java/forge/control/input/InputPayManaExecuteCommands.java index 3b07ae81cd0..57e1bc7bda5 100644 --- a/src/main/java/forge/control/input/InputPayManaExecuteCommands.java +++ b/src/main/java/forge/control/input/InputPayManaExecuteCommands.java @@ -17,17 +17,13 @@ */ package forge.control.input; -import forge.Card; import forge.Command; import forge.Singletons; import forge.card.mana.ManaCostBeingPaid; import forge.card.spellability.SpellAbility; import forge.game.GameState; import forge.game.player.Player; -import forge.game.zone.ZoneType; -import forge.gui.framework.SDisplayUtil; import forge.gui.match.CMatchUI; -import forge.gui.match.views.VMessage; import forge.view.ButtonUtil; //if cost is paid, Command.execute() is called @@ -48,7 +44,6 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { private String originalManaCost; private String message = ""; - private SpellAbility fakeAbility; private Command paidCommand; @@ -93,17 +88,13 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { * a boolean. */ public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final Command paid, final Command unpaid, final boolean showOKButton) { - super(game); - this.fakeAbility = new SpellAbility(null) { + super(game, new SpellAbility(null) { @Override - public void resolve() { - } + public void resolve() {} @Override - public boolean canPlay() { - return false; - } - }; + public boolean canPlay() { return false; } + }); this.originalManaCost = manaCost2; this.phyLifeToLose = 0; this.message = prompt; @@ -138,30 +129,14 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { } } - /** {@inheritDoc} */ @Override - public final void selectCard(final Card card) { - // only tap card if the mana is needed - this.manaCost = activateManaAbility(this.fakeAbility, card, this.manaCost); - - if (card.getManaAbility().isEmpty() || card.isInZone(ZoneType.Hand)) { - SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE); - } - - if (this.manaCost.isPaid()) { - this.done(); - } else { - this.showMessage(); - } - } - - private void done() { + protected void done() { if (this.phyLifeToLose > 0) { Singletons.getControl().getPlayer().payLife(this.phyLifeToLose, null); } this.paidCommand.execute(); this.resetManaCost(); - Singletons.getControl().getPlayer().getManaPool().clearManaPaid(this.fakeAbility, false); + Singletons.getControl().getPlayer().getManaPool().clearManaPaid(this.saPaidFor, false); this.stop(); } @@ -170,7 +145,7 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { public final void selectButtonCancel() { this.unpaidCommand.execute(); this.resetManaCost(); - Singletons.getControl().getPlayer().getManaPool().refundManaPaid(this.fakeAbility, true); + Singletons.getControl().getPlayer().getManaPool().refundManaPaid(this.saPaidFor, true); this.stop(); } @@ -204,20 +179,6 @@ public class InputPayManaExecuteCommands extends InputPayManaBase { CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString()); } - /* (non-Javadoc) - * @see forge.control.input.InputMana#selectManaPool() - */ - @Override - public void selectManaPool(String color) { - this.manaCost = activateManaAbility(color, this.fakeAbility, this.manaCost); - - if (this.manaCost.isPaid()) { - this.done(); - } else { - this.showMessage(); - } - } - @Override public void isClassUpdated() { } diff --git a/src/main/java/forge/control/input/InputPayManaOfCostPayment.java b/src/main/java/forge/control/input/InputPayManaOfCostPayment.java index 56b90128fdb..208eec9cfa9 100644 --- a/src/main/java/forge/control/input/InputPayManaOfCostPayment.java +++ b/src/main/java/forge/control/input/InputPayManaOfCostPayment.java @@ -1,5 +1,7 @@ package forge.control.input; +import java.util.concurrent.CountDownLatch; + import forge.Card; import forge.Singletons; import forge.card.cost.CostPartMana; @@ -8,7 +10,6 @@ import forge.card.mana.ManaCostBeingPaid; import forge.card.spellability.SpellAbility; import forge.game.GameState; import forge.game.player.Player; -import forge.game.zone.ZoneType; import forge.gui.match.CMatchUI; import forge.view.ButtonUtil; @@ -18,21 +19,20 @@ public class InputPayManaOfCostPayment extends InputPayManaBase { // I would kill the one who made 2 classes like above private final String originalManaCost; - private final SpellAbility sa; private final int manaToAdd; private final CostPayment payment; + private final CountDownLatch cdlFinished; - public InputPayManaOfCostPayment(final GameState game, CostPartMana costMana, SpellAbility spellAbility, final CostPayment payment, int toAdd) { - super(game); + public InputPayManaOfCostPayment(final GameState game, CostPartMana costMana, SpellAbility spellAbility, final CostPayment payment, int toAdd, CountDownLatch cdl) { + super(game, spellAbility); manaCost = new ManaCostBeingPaid(costMana.getManaToPay()); manaCost.increaseColorlessMana(toAdd); this.costMana = costMana; originalManaCost = costMana.getMana(); - sa = spellAbility; manaToAdd = toAdd; this.payment = payment; - + cdlFinished = cdl; } private static final long serialVersionUID = 3467312982164195091L; @@ -46,19 +46,6 @@ public class InputPayManaOfCostPayment extends InputPayManaBase { this.phyLifeToLose = 0; } - @Override - public void selectCard(final Card card) { - // prevent cards from tapping themselves if ability is a - // tapability, although it should already be tapped - this.manaCost = activateManaAbility(sa, card, this.manaCost); - - if (this.manaCost.isPaid()) { - this.done(); - } else if (Singletons.getModel().getMatch().getInput().getInput() == this) { - this.showMessage(); - } - } - @Override public void selectPlayer(final Player player) { if (player == whoPays) { @@ -70,8 +57,9 @@ public class InputPayManaOfCostPayment extends InputPayManaBase { } } - private void done() { - final Card source = sa.getSourceCard(); + @Override + protected void done() { + final Card source = saPaidFor.getSourceCard(); if (this.phyLifeToLose > 0) { Singletons.getControl().getPlayer().payLife(this.phyLifeToLose, source); } @@ -81,47 +69,39 @@ public class InputPayManaOfCostPayment extends InputPayManaBase { this.stop(); if (costMana.hasNoXManaCost() || (manaToAdd > 0)) { - payment.paidCost(costMana); + payment.setPaidPart(costMana); } else { source.setXManaCostPaid(0); - final Input inp = new InputPayManaX(game, sa, payment, costMana); + final Input inp = new InputPayManaX(game, saPaidFor, payment, costMana, cdlFinished); Singletons.getModel().getMatch().getInput().setInputInterrupt(inp); } - // If this is a spell with convoke, re-tap all creatures used - // for it. - // This is done to make sure Taps triggers go off at the right - // time - // (i.e. AFTER cost payment, they are tapped previously as well - // so that - // any mana tapabilities can't be used in payment as well as - // being tapped for convoke) + // If this is a spell with convoke, re-tap all creatures used for it. + // This is done to make sure Taps triggers go off at the right time + // (i.e. AFTER cost payment, they are tapped previously as well so that + // any mana tapabilities can't be used in payment as well as being tapped for convoke) - if (sa.getTappedForConvoke() != null) { - for (final Card c : sa.getTappedForConvoke()) { + handleConvokedCards(false); + } + + protected void handleConvokedCards(boolean isCancelled) { + if (saPaidFor.getTappedForConvoke() != null) { + for (final Card c : saPaidFor.getTappedForConvoke()) { c.setTapped(false); - c.tap(); + if (!isCancelled) + c.tap(); } - sa.clearTappedForConvoke(); - } - + saPaidFor.clearTappedForConvoke(); + } } @Override public void selectButtonCancel() { - // If we're paying for a spell with convoke, untap all creatures - // used for it. - if (sa.getTappedForConvoke() != null) { - for (final Card c : sa.getTappedForConvoke()) { - c.setTapped(false); - } - sa.clearTappedForConvoke(); - } + handleConvokedCards(true); this.stop(); this.resetManaCost(); payment.cancelCost(); - Singletons.getControl().getPlayer().getZone(ZoneType.Battlefield).updateObservers(); } @Override @@ -147,17 +127,6 @@ public class InputPayManaOfCostPayment extends InputPayManaBase { } } - @Override - public void selectManaPool(String color) { - manaCost = InputPayManaBase.activateManaAbility(color, sa, this.manaCost); - - if (this.manaCost.isPaid()) { - this.done(); - } else if (Singletons.getModel().getMatch().getInput().getInput() == this) { - this.showMessage(); - } - } - @Override public void isClassUpdated() { } } diff --git a/src/main/java/forge/control/input/InputPayManaSimple.java b/src/main/java/forge/control/input/InputPayManaSimple.java index c4cdbc52b98..8c571d78294 100644 --- a/src/main/java/forge/control/input/InputPayManaSimple.java +++ b/src/main/java/forge/control/input/InputPayManaSimple.java @@ -17,6 +17,7 @@ */ package forge.control.input; +import java.util.concurrent.CountDownLatch; import forge.Card; import forge.Singletons; import forge.card.mana.ManaCostBeingPaid; @@ -35,61 +36,23 @@ public class InputPayManaSimple extends InputPayManaBase { /** Constant serialVersionUID=3467312982164195091L. */ private static final long serialVersionUID = 3467312982164195091L; - private boolean skipStack; - private final SpellAbility spell; private final Card originalCard; private final String originalManaCost; + private final CountDownLatch cdlNotify; - /** - *

- * Constructor for Input_PayManaCost. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * @param noStack - * a boolean. - */ - public InputPayManaSimple(final GameState game, final SpellAbility sa, final boolean noStack) { - this(game, sa, game.getActionPlay().getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost()))); - this.skipStack = noStack; - } - - /** - *

- * Constructor for Input_PayManaCost. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - */ - public InputPayManaSimple(final GameState game, final SpellAbility sa) { - this(game, sa, new ManaCostBeingPaid(sa.getManaCost())); - } - - /** - *

- * Constructor for Input_PayManaCost. - *

- * - * @param sa - * a {@link forge.card.spellability.SpellAbility} object. - * - * @param manaCostToPay - * a {@link forge.card.mana.ManaCostBeingPaid} object. - */ - public InputPayManaSimple(final GameState game, final SpellAbility sa, final ManaCostBeingPaid manaCostToPay) { - super(game); + public InputPayManaSimple(final GameState game, final SpellAbility sa, final ManaCostBeingPaid manaCostToPay, final CountDownLatch callOnDone) { + super(game, sa); this.originalManaCost = manaCostToPay.toString(); // Change this.originalCard = sa.getSourceCard(); - this.spell = sa; if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) { this.manaCost = new ManaCostBeingPaid("0"); - game.getStack().add(this.spell); + game.getStack().add(this.saPaidFor); } else { this.manaCost = manaCostToPay; } + + cdlNotify = callOnDone; } /** @@ -102,24 +65,9 @@ public class InputPayManaSimple extends InputPayManaBase { this.phyLifeToLose = 0; } - /** {@inheritDoc} */ - @Override - public final void selectCard(final Card card) { - // this is a hack, to prevent lands being able to use mana to pay their - // own abilities from cards like - // Kher Keep, Pendelhaven, Blinkmoth Nexus, and Mikokoro, Center of the - // Sea, .... - - this.manaCost = activateManaAbility(this.spell, card, this.manaCost); - - // only show message if this is the active input - if (Singletons.getModel().getMatch().getInput().getInput() == this) { - this.showMessage(); - } - + protected void onManaAbilityPaid() { if (this.manaCost.isPaid()) { this.originalCard.setSunburstValue(this.manaCost.getSunburst()); - this.done(); } } @@ -142,27 +90,19 @@ public class InputPayManaSimple extends InputPayManaBase { * done. *

*/ - private void done() { + @Override + protected void done() { if (this.phyLifeToLose > 0) { whoPays.payLife(this.phyLifeToLose, this.originalCard); } - if (this.spell.getSourceCard().isCopiedSpell()) { - Singletons.getModel().getMatch().getInput().resetInput(); - } else { - whoPays.getManaPool().clearManaPaid(this.spell, false); + if (!this.saPaidFor.getSourceCard().isCopiedSpell()) { + whoPays.getManaPool().clearManaPaid(this.saPaidFor, false); this.resetManaCost(); - if (this.spell.isSpell()) { - this.spell.setSourceCard(game.getAction().moveToStack(this.originalCard)); + if (this.saPaidFor.isSpell()) { + this.saPaidFor.setSourceCard(game.getAction().moveToStack(this.originalCard)); } - if (this.skipStack) { - this.spell.resolve(); - } else { - game.getStack().add(this.spell); - } - Singletons.getModel().getMatch().getInput().resetInput(); - // If this is a spell with convoke, re-tap all creatures used for // it. // This is done to make sure Taps triggers go off at the right time @@ -171,30 +111,33 @@ public class InputPayManaSimple extends InputPayManaBase { // any mana tapabilities can't be used in payment as well as being // tapped for convoke) - if (this.spell.getTappedForConvoke() != null) { - for (final Card c : this.spell.getTappedForConvoke()) { + if (this.saPaidFor.getTappedForConvoke() != null) { + for (final Card c : this.saPaidFor.getTappedForConvoke()) { c.setTapped(false); c.tap(); } - this.spell.clearTappedForConvoke(); + this.saPaidFor.clearTappedForConvoke(); } } + + Singletons.getModel().getMatch().getInput().resetInput(); + cdlNotify.countDown(); } /** {@inheritDoc} */ @Override public final void selectButtonCancel() { // If this is a spell with convoke, untap all creatures used for it. - if (this.spell.getTappedForConvoke() != null) { - for (final Card c : this.spell.getTappedForConvoke()) { + if (this.saPaidFor.getTappedForConvoke() != null) { + for (final Card c : this.saPaidFor.getTappedForConvoke()) { c.setTapped(false); } - this.spell.clearTappedForConvoke(); + this.saPaidFor.clearTappedForConvoke(); } this.resetManaCost(); - whoPays.getManaPool().refundManaPaid(this.spell, true); + whoPays.getManaPool().refundManaPaid(this.saPaidFor, true); whoPays.getZone(ZoneType.Battlefield).updateObservers(); // DO this.stop(); @@ -224,24 +167,6 @@ public class InputPayManaSimple extends InputPayManaBase { } - /* (non-Javadoc) - * @see forge.control.input.InputMana#selectManaPool(String) - */ - @Override - public void selectManaPool(String color) { - this.manaCost = InputPayManaBase.activateManaAbility(color, this.spell, this.manaCost); - - // only show message if this is the active input - if (Singletons.getModel().getMatch().getInput().getInput() == this) { - this.showMessage(); - } - - if (this.manaCost.isPaid()) { - this.originalCard.setSunburstValue(this.manaCost.getSunburst()); - this.done(); - } - } - @Override public void isClassUpdated() { } } diff --git a/src/main/java/forge/control/input/InputPayManaX.java b/src/main/java/forge/control/input/InputPayManaX.java index 9edb2ec4090..5b21bb31cb8 100644 --- a/src/main/java/forge/control/input/InputPayManaX.java +++ b/src/main/java/forge/control/input/InputPayManaX.java @@ -1,13 +1,13 @@ package forge.control.input; +import java.util.concurrent.CountDownLatch; + import forge.Card; -import forge.Singletons; import forge.card.cost.CostPartMana; import forge.card.cost.CostPayment; import forge.card.mana.ManaCostBeingPaid; import forge.card.spellability.SpellAbility; import forge.game.GameState; -import forge.game.zone.ZoneType; import forge.gui.match.CMatchUI; import forge.view.ButtonUtil; @@ -19,20 +19,21 @@ public class InputPayManaX extends InputPayManaBase { private String colorsPaid; private final CostPartMana costMana; private final CostPayment payment; - private final SpellAbility sa; + private final CountDownLatch cdlFinished; - public InputPayManaX(final GameState game, final SpellAbility sa0, final CostPayment payment0, final CostPartMana costMana0) + public InputPayManaX(final GameState game, final SpellAbility sa0, final CostPayment payment0, final CostPartMana costMana0, final CountDownLatch cdl) { - super(game); - sa = sa0; + super(game, sa0); + payment = payment0; xPaid = 0; - colorX = sa.hasParam("XColor") ? sa.getParam("XColor") : ""; - colorsPaid = sa.getSourceCard().getColorsPaid(); + colorX = saPaidFor.hasParam("XColor") ? saPaidFor.getParam("XColor") : ""; + colorsPaid = saPaidFor.getSourceCard().getColorsPaid(); costMana = costMana0; strX = Integer.toString(costMana.getXMana()); manaCost = new ManaCostBeingPaid(strX); + cdlFinished = cdl; } @Override @@ -47,7 +48,7 @@ public class InputPayManaX extends InputPayManaBase { } StringBuilder msg = new StringBuilder("Pay X Mana Cost for "); - msg.append(sa.getSourceCard().getName()).append("\n").append(this.xPaid); + msg.append(saPaidFor.getSourceCard().getName()).append("\n").append(this.xPaid); msg.append(" Paid so far."); if (costMana.isxCantBe0()) { msg.append(" X Can't be 0."); @@ -59,8 +60,12 @@ public class InputPayManaX extends InputPayManaBase { // selectCard @Override public void selectCard(final Card card) { - this.manaCost = activateManaAbility(sa, card, - this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX)); + activateManaAbility(card, this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX)); + } + + + @Override + protected void onManaAbilityPaid() { if (this.manaCost.isPaid()) { if (!this.colorsPaid.contains(this.manaCost.getColorsPaid())) { this.colorsPaid += this.manaCost.getColorsPaid(); @@ -68,43 +73,24 @@ public class InputPayManaX extends InputPayManaBase { this.manaCost = new ManaCostBeingPaid(strX); this.xPaid++; } - - if (Singletons.getModel().getMatch().getInput().getInput() == this) { - this.showMessage(); - } } @Override public void selectButtonCancel() { this.stop(); payment.cancelCost(); - Singletons.getControl().getPlayer().getZone(ZoneType.Battlefield).updateObservers(); + cdlFinished.countDown(); } @Override public void selectButtonOK() { this.stop(); - payment.getCard().setXManaCostPaid(this.xPaid); - payment.paidCost(costMana); - payment.getCard().setColorsPaid(this.colorsPaid); - payment.getCard().setSunburstValue(this.colorsPaid.length()); + done(); } @Override public void selectManaPool(String color) { - this.manaCost = activateManaAbility(color, sa, - this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX)); - if (this.manaCost.isPaid()) { - if (!this.colorsPaid.contains(this.manaCost.getColorsPaid())) { - this.colorsPaid += this.manaCost.getColorsPaid(); - } - this.manaCost = new ManaCostBeingPaid(strX); - this.xPaid++; - } - - if (Singletons.getModel().getMatch().getInput().getInput() == this) { - this.showMessage(); - } + useManaFromPool(color, this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX)); } /* (non-Javadoc) @@ -113,4 +99,14 @@ public class InputPayManaX extends InputPayManaBase { @Override public void isClassUpdated() { } + + + @Override + protected void done() { + payment.getCard().setXManaCostPaid(this.xPaid); + payment.setPaidPart(costMana); + payment.getCard().setColorsPaid(this.colorsPaid); + payment.getCard().setSunburstValue(this.colorsPaid.length()); + cdlFinished.countDown(); + } } diff --git a/src/main/java/forge/deck/CardCollections.java b/src/main/java/forge/deck/CardCollections.java index d669de66eb2..ae30b624c1b 100644 --- a/src/main/java/forge/deck/CardCollections.java +++ b/src/main/java/forge/deck/CardCollections.java @@ -19,9 +19,12 @@ package forge.deck; import java.io.File; +import org.apache.commons.lang.time.StopWatch; + import forge.deck.io.DeckGroupSerializer; import forge.deck.io.DeckSerializer; import forge.deck.io.OldDeckParser; +import forge.gui.toolbox.FSkin; import forge.properties.NewConstants; import forge.util.storage.IStorage; import forge.util.storage.StorageImmediatelySerialized; @@ -44,6 +47,9 @@ public class CardCollections { * @param file the file */ public CardCollections() { + FSkin.setProgessBarMessage("Loading decks"); + StopWatch sw = new StopWatch(); + sw.start(); this.constructed = new StorageImmediatelySerialized(new DeckSerializer(new File(NewConstants.DECK_CONSTRUCTED_DIR), true)); this.draft = new StorageImmediatelySerialized(new DeckGroupSerializer(new File(NewConstants.DECK_DRAFT_DIR))); this.sealed = new StorageImmediatelySerialized(new DeckGroupSerializer(new File(NewConstants.DECK_SEALED_DIR))); @@ -51,8 +57,10 @@ public class CardCollections { this.scheme = new StorageImmediatelySerialized(new DeckSerializer(new File(NewConstants.DECK_SCHEME_DIR))); this.plane = new StorageImmediatelySerialized(new DeckSerializer(new File(NewConstants.DECK_PLANE_DIR))); - System.out.printf("Read decks: %d constructed, %d sealed, %d draft, %d cubes, %d scheme, %d planar.%n", constructed.size(), sealed.size(), draft.size(), cube.size(), scheme.size(), plane.size()); - + sw.stop(); + System.out.printf("Read decks (%d ms): %d constructed, %d sealed, %d draft, %d cubes, %d scheme, %d planar.%n", sw.getTime(), constructed.size(), sealed.size(), draft.size(), cube.size(), scheme.size(), plane.size()); +// int sum = constructed.size() + sealed.size() + draft.size() + cube.size() + scheme.size() + plane.size(); +// FSkin.setProgessBarMessage(String.format("Loaded %d decks in %f sec", sum, sw.getTime() / 1000f )); // remove this after most people have been switched to new layout final OldDeckParser oldParser = new OldDeckParser(this.constructed, this.draft, this.sealed, this.cube); oldParser.tryParse(); diff --git a/src/main/java/forge/game/GameActionPlay.java b/src/main/java/forge/game/GameActionPlay.java index 8ccfcd9275c..410612154c6 100644 --- a/src/main/java/forge/game/GameActionPlay.java +++ b/src/main/java/forge/game/GameActionPlay.java @@ -2,7 +2,7 @@ package forge.game; import java.util.ArrayList; import java.util.List; - +import java.util.concurrent.CountDownLatch; import com.google.common.collect.Lists; import forge.Card; @@ -25,7 +25,9 @@ import forge.card.spellability.Target; import forge.card.spellability.TargetSelection; import forge.card.staticability.StaticAbility; import forge.control.input.InputControl; +import forge.control.input.InputPayManaBase; import forge.control.input.InputPayManaSimple; +import forge.error.BugReporter; import forge.game.ai.ComputerUtilCard; import forge.game.player.Player; import forge.game.zone.ZoneType; @@ -387,6 +389,7 @@ public class GameActionPlay { ability = ability.getSubAbility(); } + System.out.println("Playing:" + sa.getDescription() + " of " + sa.getSourceCard() + " new = " + newAbility); if (newAbility) { final TargetSelection ts = new TargetSelection(sa.getTarget(), sa); CostPayment payment = null; @@ -405,15 +408,25 @@ public class GameActionPlay { } else { manaCost = this.getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost())); } + + if (!manaCost.isPaid()) { + CountDownLatch cdlWaitForPayment = new CountDownLatch(1); + matchInput.setInput(new InputPayManaSimple(game, sa, manaCost, cdlWaitForPayment)); + try { + cdlWaitForPayment.await(); + } catch (Exception e) { + BugReporter.reportException(e); + } + } + + if (manaCost.isPaid()) { if (sa.isSpell() && !source.isCopiedSpell()) { sa.setSourceCard(game.getAction().moveToStack(source)); } game.getStack().add(sa); - } else { - matchInput.setInput(new InputPayManaSimple(game, sa, manaCost)); - } + } } } @@ -448,12 +461,22 @@ public class GameActionPlay { } else { manaCost = this.getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost())); } + + final CountDownLatch cdlWaitForPayment = new CountDownLatch(1); + + if( !manaCost.isPaid() ) { + matchInput.setInput(new InputPayManaSimple(game, sa, getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost())), cdlWaitForPayment)); + try { + cdlWaitForPayment.await(); + } catch (Exception e) { + BugReporter.reportException(e); + } + } + if (manaCost.isPaid()) { AbilityUtils.resolve(sa, false); - return; - } else { - matchInput.setInput(new InputPayManaSimple(game, sa, true)); } + } } @@ -550,4 +573,23 @@ public class GameActionPlay { } } } + + /** + * TODO: Write javadoc for this method. + * @param chosen + * @param p + * @param inputPayManaBase + * @param manaCost + * @param saPaidFor + */ + public void playManaAbilityAsPayment(final SpellAbility chosen, final Player p, final InputPayManaBase inputPayManaBase) { + Runnable proc = new Runnable() { + @Override + public void run() { + p.getGame().getActionPlay().playSpellAbility(chosen, p); + inputPayManaBase.onManaAbilityPlayed(p, chosen); + } + }; + FThreads.invokeInNewThread(proc, true); + } } diff --git a/src/main/java/forge/game/GameActionUtil.java b/src/main/java/forge/game/GameActionUtil.java index d0183522413..3696462f2b9 100644 --- a/src/main/java/forge/game/GameActionUtil.java +++ b/src/main/java/forge/game/GameActionUtil.java @@ -58,7 +58,7 @@ import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbilityRestriction; import forge.control.input.Input; -import forge.control.input.InputPayDiscardCost; +import forge.control.input.InputPayDiscardCostWithCommands; import forge.control.input.InputPayManaExecuteCommands; import forge.control.input.InputPayReturnCost; import forge.game.event.CardDamagedEvent; @@ -602,7 +602,7 @@ public final class GameActionUtil { toSet = new InputPayReturnCost((CostReturn) costPart, ability, paid, unpaid); } else if (costPart instanceof CostDiscard) { - toSet = new InputPayDiscardCost((CostDiscard) costPart, ability, paid, unpaid); + toSet = new InputPayDiscardCostWithCommands((CostDiscard) costPart, ability, paid, unpaid); } else if (costPart instanceof CostPartMana) { toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost().toString(), paid, unpaid); diff --git a/src/main/java/forge/game/MatchController.java b/src/main/java/forge/game/MatchController.java index 16256cec3e9..011bb10f14d 100644 --- a/src/main/java/forge/game/MatchController.java +++ b/src/main/java/forge/game/MatchController.java @@ -179,7 +179,7 @@ public class MatchController { getInput().clearInput(); getInput().resetInput(); - getInput().setNewInput(currentGame); + //getInput().setNewInput(currentGame); // Thread thGame = new GameInputUpdatesThread(this, currentGame); diff --git a/src/main/java/forge/game/phase/PhaseHandler.java b/src/main/java/forge/game/phase/PhaseHandler.java index a871a13feec..1fd5cd54b8a 100644 --- a/src/main/java/forge/game/phase/PhaseHandler.java +++ b/src/main/java/forge/game/phase/PhaseHandler.java @@ -739,7 +739,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { } else { // pass the priority to other player this.pPlayerPriority = nextPlayer; - Singletons.getModel().getMatch().getInput().resetInput(); + Singletons.getModel().getMatch().getInput().updateObservers(); } game.getStack().chooseOrderOfSimultaneousStackEntryAll(); diff --git a/src/main/java/forge/game/zone/MagicStack.java b/src/main/java/forge/game/zone/MagicStack.java index dac8c592511..a0a83608cfe 100644 --- a/src/main/java/forge/game/zone/MagicStack.java +++ b/src/main/java/forge/game/zone/MagicStack.java @@ -1290,26 +1290,18 @@ public class MagicStack extends MyObservable { ComputerUtil.playStack(sa, (AIPlayer) activePlayer, game); } } else { - // If only one, just add as necessary - if (activePlayerSAs.size() == 1) { - SpellAbility next = activePlayerSAs.get(0); + List orderedSAs = activePlayerSAs; + if (activePlayerSAs.size() > 1) { // give a dual list form to create instead of needing to do it one at a time + orderedSAs = GuiChoose.order("Select order for Simultaneous Spell Abilities", "Resolve first", 0, activePlayerSAs, null, null); + } + int size = orderedSAs.size(); + for (int i = size - 1; i >= 0; i--) { + SpellAbility next = orderedSAs.get(i); if (next.isTrigger()) { game.getActionPlay().playSpellAbility(next, activePlayer); } else { this.add(next); } - } else { - // Otherwise, gave a dual list form to create instead of needing to do it one at a time - List orderedSAs = GuiChoose.order("Select order for Simultaneous Spell Abilities", "Resolve first", 0, activePlayerSAs, null, null); - int size = orderedSAs.size(); - for (int i = size - 1; i >= 0; i--) { - SpellAbility next = orderedSAs.get(i); - if (next.isTrigger()) { - game.getActionPlay().playSpellAbility(next, activePlayer); - } else { - this.add(next); - } - } } } diff --git a/src/main/java/forge/gui/toolbox/FSkin.java b/src/main/java/forge/gui/toolbox/FSkin.java index 88f723e3f15..50c3273e930 100644 --- a/src/main/java/forge/gui/toolbox/FSkin.java +++ b/src/main/java/forge/gui/toolbox/FSkin.java @@ -458,6 +458,26 @@ public enum FSkin { } } } + + public static void setProgessBarMessage(final String message) { + setProgessBarMessage(message, 0); + } + public static void setProgessBarMessage(final String message, final int cnt) { + final FProgressBar barProgress = FView.SINGLETON_INSTANCE.getSplash().getProgressBar(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if ( cnt > 0 ) { + barProgress.reset(); + barProgress.setMaximum(4); + } + barProgress.setShowETA(false); + barProgress.setShowCount(cnt > 0); + barProgress.setDescription(message); + + } + }); + } /** * Loads two sprites: the default (which should be a complete @@ -487,19 +507,12 @@ public enum FSkin { if (FSkin.preferredName.isEmpty()) { FSkin.loadLight("default"); } // Everything OK? + final FProgressBar barProgress = FView.SINGLETON_INSTANCE.getSplash().getProgressBar(); + setProgessBarMessage("Processing image sprites: ", 4); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - barProgress.reset(); - barProgress.setShowETA(false); - barProgress.setDescription("Processing image sprites: "); - } - }); // Grab and test various sprite files. - barProgress.setMaximum(4); final File f1 = new File(DEFAULT_DIR + FILE_ICON_SPRITE); final File f2 = new File(preferredDir + FILE_ICON_SPRITE); final File f3 = new File(DEFAULT_DIR + FILE_FOIL_SPRITE); @@ -567,14 +580,7 @@ public enum FSkin { UIManager.put("Table.alternateRowColor", new Color(240, 240, 240)); // Images loaded; can start UI init. - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - barProgress.setShowETA(false); - barProgress.setShowCount(false); - barProgress.setDescription("Creating display components."); - } - }); + setProgessBarMessage("Creating display components."); // Clear references to buffered images FSkin.bimDefaultSprite.flush(); diff --git a/src/main/java/forge/model/FModel.java b/src/main/java/forge/model/FModel.java index 5a40205d8e5..a90fc986e3c 100644 --- a/src/main/java/forge/model/FModel.java +++ b/src/main/java/forge/model/FModel.java @@ -117,11 +117,12 @@ public enum FModel { } // initialize log file - final File logFile = new File(NewConstants.LOG_FILE); - final boolean deleteSucceeded = logFile.delete(); + File logFile = new File(NewConstants.LOG_FILE); - if (logFile.exists() && !deleteSucceeded && (logFile.length() != 0)) { - throw new IllegalStateException("Could not delete existing logFile:" + logFile.getAbsolutePath()); + int i = 0; + while (logFile.exists() && !logFile.delete()) { + String pathname = logFile.getPath().replaceAll("[0-9]{0,2}.log$", String.valueOf(i++) + ".log"); + logFile = new File(pathname); } try {