All cost-paying inputs are syncronous

This commit is contained in:
Maxmtg
2013-03-23 10:48:28 +00:00
parent d192d4977f
commit 0ce3aba250
43 changed files with 1229 additions and 1489 deletions

View File

@@ -7675,6 +7675,14 @@ public class Card extends GameEntity implements Comparable<Card> {
this.receivedDamageFromThisTurn.clear();
}
public final int getTotalDamageRecievedThisTurn() {
int total = 0;
for (int damage : this.receivedDamageFromThisTurn.values()) {
total += damage;
}
return total;
}
/**
* <p>
* addDealtDamageToThisTurn.

View File

@@ -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();
}
};
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
/*

View File

@@ -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<Num/Type{/TypeDescription}>
// Inputs
/**
* TODO: Write javadoc for this type.
*
*/
public static final class InputPayCostDiscard extends InputPayCostBase {
private final List<Card> 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<Card> 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<Card> 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<Card> handList = new ArrayList<Card>(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
/**
* <p>
* input_discardCost.
* </p>
*
* @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<Card> 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<Card> 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()
}

View File

@@ -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<Num/Type{/TypeDescription}> (of library)
// ExileSameGrave<Num/Type{/TypeDescription}>
/**
* 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<Card> 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<Card> list;
private final CostExile part;
private final CostPayment payment;
private final SpellAbility sa;
private final int nNeeded;
private final List<Player> payableZone;
private static final long serialVersionUID = 734256837615635021L;
@@ -148,12 +127,10 @@ public class CostExile extends CostPartWithList {
* @param nNeeded
* @param payableZone
*/
private InputExileFromSame(List<Card> list, CostExile part, CostPayment payment, SpellAbility sa, int nNeeded,
List<Player> payableZone) {
private InputExileFromSame(CountDownLatch cdl, List<Card> list, CostExile part, CostPayment payment, int nNeeded, List<Player> 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();
}

View File

@@ -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;
}
/*

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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;
}
/*

View File

@@ -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;
}
/*

View File

@@ -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;
}

View File

@@ -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<Card> 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;
}
/**
* <p>
* returnType.
* </p>
*
* @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<Card> 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;
}
}

View File

@@ -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<Card> 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<Card> 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<Card>(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;
}
/**
* <p>
* returnType.
* </p>
*
* @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<Card> 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;
}
/**
* <p>
* returnType.
* </p>
*
* @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<Card> typeList;
private int nRemove = 0;
@Override
public void showMessage() {
if (nNeeded == 0) {
this.done();
}
this.typeList = new ArrayList<Card>(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;
}
}

View File

@@ -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<Num/Type{/TypeDescription}>
/**
* 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<Card> 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<Card>(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
/**
* <p>
* returnType.
* </p>
*
* @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<Card> 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<Card>(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()
/**
* <p>
* returnThis.
* </p>
*
* @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()
}

View File

@@ -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<Num/Type/TypeDescription>
/**
* TODO: Write javadoc for this type.
*
*/
public static final class InputPayReveal extends Input {
private final CostReveal part;
private final String discType;
private final List<Card> 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<Card> 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<Card> 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<Card>(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
/**
* <p>
* input_discardCost.
* </p>
*
* @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<Card> 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<Card> 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()
}

View File

@@ -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<Card> 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<Card> 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
/**
* <p>
* sacrificeAllType.
* </p>
*
* @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<Card> typeList) {
// TODO Ask First
for (final Card card : typeList) {
payment.getAbility().addCostToHashList(card, "Sacrificed");
Singletons.getModel().getGame().getAction().sacrifice(card, sa);
}
payment.setPaidManaPart(part);
}
/**
* <p>
* sacrificeFromList.
* </p>
*
* @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<Card> 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()
/**
* <p>
* sacrificeThis.
* </p>
*
* @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()
}

View File

@@ -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;
}
/*

View File

@@ -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<Card> 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<Card> 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<Card> 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<Card> typeList = new ArrayList<Card>(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
/**
* <p>
* input_tapXCost.
* </p>
*
* @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<Card> 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<Card> 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()
}

View File

@@ -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) {

View File

@@ -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;
}
/*

View File

@@ -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<Card> 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<Card> 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<Card> 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<Card> 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
/**
* <p>
* input_untapYCost.
* </p>
*
* @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<Card> 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<Card> 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()
}

View File

@@ -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();
}
}

View File

@@ -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();
}
/**
* <p>
* startPaying.
* </p>
*/
public final void startPaying() {
this.payment.setRequirements(this);
this.payment.changeCost();
this.payment.payCost();
}
/**
* <p>
* finishPaying.
* </p>
*/
public final void finishPaying() {
if (this.payment.isCanceled()) {
final Card c = this.ability.getSourceCard();

View File

@@ -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(); } });
}

View File

@@ -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

View File

@@ -14,5 +14,10 @@ public class InputLockUI extends Input {
ButtonUtil.disableAll();
CMatchUI.SINGLETON_INSTANCE.showMessage("Waiting for actions...");
}
@Override
public String toString() {
return "lockUI";
}
}

View File

@@ -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 <code>serialVersionUID=2685832214529141991L</code>.
*/
@@ -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();

View File

@@ -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;
}
/**
* <p>
* selectManaPool.
* </p>
* @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);
}
/**
* <p>
@@ -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() + ")";
}
}

View File

@@ -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() {
}

View File

@@ -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() {
}
}

View File

@@ -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 <code>serialVersionUID=3467312982164195091L</code>. */
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;
/**
* <p>
* Constructor for Input_PayManaCost.
* </p>
*
* @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;
}
/**
* <p>
* Constructor for Input_PayManaCost.
* </p>
*
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
*/
public InputPayManaSimple(final GameState game, final SpellAbility sa) {
this(game, sa, new ManaCostBeingPaid(sa.getManaCost()));
}
/**
* <p>
* Constructor for Input_PayManaCost.
* </p>
*
* @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.
* </p>
*/
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() {
}
}

View File

@@ -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();
}
}

View File

@@ -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<Deck>(new DeckSerializer(new File(NewConstants.DECK_CONSTRUCTED_DIR), true));
this.draft = new StorageImmediatelySerialized<DeckGroup>(new DeckGroupSerializer(new File(NewConstants.DECK_DRAFT_DIR)));
this.sealed = new StorageImmediatelySerialized<DeckGroup>(new DeckGroupSerializer(new File(NewConstants.DECK_SEALED_DIR)));
@@ -51,8 +57,10 @@ public class CardCollections {
this.scheme = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_SCHEME_DIR)));
this.plane = new StorageImmediatelySerialized<Deck>(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();

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -179,7 +179,7 @@ public class MatchController {
getInput().clearInput();
getInput().resetInput();
getInput().setNewInput(currentGame);
//getInput().setNewInput(currentGame);
// Thread thGame = new GameInputUpdatesThread(this, currentGame);

View File

@@ -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();

View File

@@ -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<SpellAbility> 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<SpellAbility> 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);
}
}
}
}

View File

@@ -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();

View File

@@ -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 {