mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
targeting is also synchronous now
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
package forge;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import forge.control.input.Input;
|
||||
import forge.error.BugReporter;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
@@ -81,8 +85,8 @@ public class FThreads {
|
||||
}
|
||||
|
||||
|
||||
public static void invokeInNewThread(Runnable proc) {
|
||||
invokeInNewThread(proc, false);
|
||||
public static void invokeInNewThread(Runnable toRun) {
|
||||
getCachedPool().execute(toRun);
|
||||
}
|
||||
|
||||
public static void invokeInNewThread(final Runnable proc, boolean lockUI) {
|
||||
@@ -94,13 +98,20 @@ public class FThreads {
|
||||
@Override
|
||||
public void run() {
|
||||
proc.run();
|
||||
// may try special unlock method here
|
||||
Singletons.getModel().getMatch().getInput().unlock();
|
||||
}
|
||||
};
|
||||
}
|
||||
invokeInNewThread(toRun);
|
||||
}
|
||||
|
||||
getCachedPool().execute(toRun);
|
||||
public static final void setInputAndWait(Input inp, CountDownLatch cdl) {
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
try {
|
||||
cdl.await();
|
||||
} catch (InterruptedException e) {
|
||||
BugReporter.reportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.common.base.Predicate;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -339,7 +340,7 @@ public class CostDiscard extends CostPartWithList {
|
||||
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
final Input inp = new InputPayCostDiscard(cdl, ability, handList, this, payment, c, discardType);
|
||||
setInputAndWait(inp, cdl);
|
||||
FThreads.setInputAndWait(inp, cdl);
|
||||
}
|
||||
}
|
||||
if ( !payment.isCanceled())
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -602,7 +603,7 @@ public class CostExile extends CostPartWithList {
|
||||
} else {
|
||||
target = new InputExileFrom(cdl,ability, this.getType(), c, payment, this);
|
||||
}
|
||||
setInputAndWait(target, cdl);
|
||||
FThreads.setInputAndWait(target, cdl);
|
||||
if(!payment.isCanceled())
|
||||
addListToHash(ability, "Exiled");
|
||||
}
|
||||
|
||||
@@ -17,13 +17,9 @@
|
||||
*/
|
||||
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;
|
||||
@@ -146,15 +142,6 @@ 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.
|
||||
*
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
@@ -112,8 +113,8 @@ public class CostPartMana extends CostPart {
|
||||
/**
|
||||
* @return the xCantBe0
|
||||
*/
|
||||
public boolean isxCantBe0() {
|
||||
return xCantBe0;
|
||||
public boolean canXbe0() {
|
||||
return !xCantBe0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +228,7 @@ public class CostPartMana extends CostPart {
|
||||
}
|
||||
else inp = null;
|
||||
if ( null != inp) {
|
||||
setInputAndWait(inp, cdl);
|
||||
FThreads.setInputAndWait(inp, cdl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -205,12 +205,7 @@ public class CostPayment {
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean payCost() {
|
||||
// Nothing actually ever checks this return value, is it needed?
|
||||
if (this.bCancel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void payCost() {
|
||||
for (final CostPart part : this.cost.getCostParts()) {
|
||||
// This portion of the cost is already paid for, keep moving
|
||||
if (this.paidCostParts.contains(part)) {
|
||||
@@ -218,13 +213,11 @@ public class CostPayment {
|
||||
}
|
||||
|
||||
part.payHuman(this.ability, this.card, this, game);
|
||||
if ( isCanceled() ) break;
|
||||
if ( isCanceled() ) return;
|
||||
|
||||
setPaidPart(part);
|
||||
}
|
||||
|
||||
this.resetUndoList(); // ??
|
||||
return true;
|
||||
this.resetUndoList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CounterType;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.GameState;
|
||||
@@ -255,7 +256,7 @@ public class CostPutCounter extends CostPartWithList {
|
||||
this.addToList(source);
|
||||
} else {
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
setInputAndWait(new InputPayCostPutCounter(cdl, this.getType(), this, c, payment, ability), cdl);
|
||||
FThreads.setInputAndWait(new InputPayCostPutCounter(cdl, this.getType(), this, c, payment, ability), cdl);
|
||||
}
|
||||
if ( !payment.isCanceled())
|
||||
addListToHash(ability, "CounterPut");
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CounterType;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
@@ -386,7 +387,7 @@ public class CostRemoveCounter extends CostPartWithList {
|
||||
} else {
|
||||
inp = new InputPayCostRemoveCounterFrom(cdl, this, this.getType(), ability, c, payment);
|
||||
}
|
||||
setInputAndWait(inp, cdl);
|
||||
FThreads.setInputAndWait(inp, cdl);
|
||||
|
||||
if ( !payment.isCanceled() )
|
||||
addListToHash(ability, "CounterRemove");
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -254,7 +255,7 @@ public class CostReturn extends CostPartWithList {
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
final Input target = new InputPayReturnType(cdl, ability, this, c, this.getType(), payment);
|
||||
final Input inp = target;
|
||||
setInputAndWait(inp, cdl);
|
||||
FThreads.setInputAndWait(inp, cdl);
|
||||
}
|
||||
|
||||
if (!payment.isCanceled())
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -279,7 +280,7 @@ public class CostReveal extends CostPartWithList {
|
||||
if (num > 0) {
|
||||
final CountDownLatch cdl = new CountDownLatch(1);
|
||||
final Input inp = new InputPayReveal(cdl, this, this.getType(), handList, ability, payment, num);;
|
||||
setInputAndWait(inp, cdl);
|
||||
FThreads.setInputAndWait(inp, cdl);
|
||||
}
|
||||
}
|
||||
if ( !payment.isCanceled())
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -252,7 +253,7 @@ public class CostSacrifice extends CostPartWithList {
|
||||
return;
|
||||
}
|
||||
final CountDownLatch cdl = new CountDownLatch(1);
|
||||
setInputAndWait(new InputPayCostSacrificeFromList(cdl, this, ability, c, payment, list), cdl);
|
||||
FThreads.setInputAndWait(new InputPayCostSacrificeFromList(cdl, this, ability, c, payment, list), cdl);
|
||||
}
|
||||
if( !payment.isCanceled())
|
||||
addListToHash(ability, "Sacrificed");
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -248,7 +249,7 @@ public class CostTapType extends CostPartWithList {
|
||||
}
|
||||
}
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
setInputAndWait(new InputPayCostTapType(cdl, this, c, typeList, payment), cdl);
|
||||
FThreads.setInputAndWait(new InputPayCostTapType(cdl, this, c, typeList, payment), cdl);
|
||||
if( !payment.isCanceled())
|
||||
addListToHash(ability, "Tapped");
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -249,7 +250,7 @@ public class CostUntapType extends CostPartWithList {
|
||||
}
|
||||
}
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
setInputAndWait(new InputPayCostUntapY(cdl, c, typeList, this, payment), cdl);
|
||||
FThreads.setInputAndWait(new InputPayCostUntapY(cdl, c, typeList, this, payment), cdl);
|
||||
|
||||
if ( !payment.isCanceled() )
|
||||
addListToHash(ability, "Untapped");
|
||||
|
||||
@@ -23,8 +23,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import forge.Card;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
@@ -1682,25 +1680,4 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
public void setCopied(boolean isCopied0) {
|
||||
this.isCopied = isCopied0;
|
||||
}
|
||||
|
||||
public boolean announceRequirements() {
|
||||
// Announcing Requirements like Choosing X or Multikicker
|
||||
// SA Params as comma delimited list
|
||||
String announce = this.getParam("Announce");
|
||||
if (announce != null) {
|
||||
String[] announceVars = announce.split(",");
|
||||
for(String aVar : announceVars) {
|
||||
String value = this.getActivatingPlayer().getController().announceRequirements(this, aVar);
|
||||
if (value == null || !StringUtils.isNumeric(value)) {
|
||||
return false;
|
||||
} else if (this.getPayCosts().getCostMana() != null && this.getPayCosts().getCostMana().isxCantBe0()
|
||||
&& Integer.parseInt(value) == 0) {
|
||||
return false;
|
||||
}
|
||||
this.setSVar(aVar, "Number$" + value);
|
||||
this.getSourceCard().setSVar(aVar, "Number$" + value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package forge.card.spellability;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardCharacteristicName;
|
||||
import forge.Singletons;
|
||||
@@ -44,67 +46,26 @@ public class SpellAbilityRequirements {
|
||||
private Zone fromZone = null;
|
||||
private Integer zonePosition = null;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>skipStack</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param bSkip
|
||||
* a boolean.
|
||||
*/
|
||||
|
||||
public final void setSkipStack(final boolean bSkip) {
|
||||
this.skipStack = bSkip;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setFree.
|
||||
* </p>
|
||||
*
|
||||
* @param bFree
|
||||
* a boolean.
|
||||
*/
|
||||
public final void setFree(final boolean bFree) {
|
||||
this.isFree = bFree;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for SpellAbility_Requirements.
|
||||
* </p>
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param ts
|
||||
* a {@link forge.card.spellability.TargetSelection} object.
|
||||
* @param cp
|
||||
* a {@link forge.card.cost.CostPayment} object.
|
||||
*/
|
||||
public SpellAbilityRequirements(final SpellAbility sa, final TargetSelection ts, final CostPayment cp) {
|
||||
this.ability = sa;
|
||||
this.select = ts;
|
||||
this.payment = cp;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* fillRequirements.
|
||||
* </p>
|
||||
*/
|
||||
public final void fillRequirements() {
|
||||
this.fillRequirements(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* fillRequirements.
|
||||
* </p>
|
||||
*
|
||||
* @param skipTargeting
|
||||
* a boolean.
|
||||
*/
|
||||
public final void fillRequirements(final boolean skipTargeting) {
|
||||
if ((this.ability instanceof Spell) && !this.bCasting) {
|
||||
// remove from hand
|
||||
@@ -118,14 +79,13 @@ public class SpellAbilityRequirements {
|
||||
}
|
||||
}
|
||||
|
||||
// freeze Stack. No abilities should go onto the stack while I'm filling
|
||||
// requirements.
|
||||
// freeze Stack. No abilities should go onto the stack while I'm filling requirements.
|
||||
Singletons.getModel().getGame().getStack().freezeStack();
|
||||
|
||||
// Announce things like how many times you want to Multikick or the value of X
|
||||
if (!this.ability.announceRequirements()) {
|
||||
if (!this.announceRequirements()) {
|
||||
this.select.setCancel(true);
|
||||
this.finishedTargeting();
|
||||
rollbackAbility();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,47 +94,15 @@ public class SpellAbilityRequirements {
|
||||
// (or trigger case where its already targeted)
|
||||
if (!skipTargeting && (this.select.doesTarget() || (this.ability.getSubAbility() != null))) {
|
||||
this.select.setRequirements(this);
|
||||
this.select.resetTargets();
|
||||
this.select.clearTargets();
|
||||
this.select.chooseTargets();
|
||||
} else {
|
||||
this.needPayment();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* finishedTargeting.
|
||||
* </p>
|
||||
*/
|
||||
public final void finishedTargeting() {
|
||||
if (this.select.isCanceled()) {
|
||||
// cancel ability during target choosing
|
||||
final Card c = this.ability.getSourceCard();
|
||||
|
||||
// split cards transform back to full form if targeting is canceled
|
||||
if (c.isSplitCard()) {
|
||||
c.setState(CardCharacteristicName.Original);
|
||||
if (this.select.isCanceled()) {
|
||||
rollbackAbility();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.bCasting && !c.isCopiedSpell()) { // and not a copy
|
||||
// add back to where it came from
|
||||
Singletons.getModel().getGame().getAction().moveTo(this.fromZone, c, this.zonePosition);
|
||||
}
|
||||
|
||||
this.select.resetTargets();
|
||||
Singletons.getModel().getGame().getStack().removeFromFrozenStack(this.ability);
|
||||
return;
|
||||
} else {
|
||||
this.needPayment();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* needPayment.
|
||||
* </p>
|
||||
*/
|
||||
public final void needPayment() {
|
||||
// Payment
|
||||
if (!this.isFree) {
|
||||
this.payment.setRequirements(this);
|
||||
this.payment.changeCost();
|
||||
@@ -182,62 +110,88 @@ public class SpellAbilityRequirements {
|
||||
}
|
||||
|
||||
if (this.payment.isCanceled()) {
|
||||
final Card c = this.ability.getSourceCard();
|
||||
|
||||
// split cards transform back to full form if mana cost is not paid
|
||||
if (c.isSplitCard()) {
|
||||
c.setState(CardCharacteristicName.Original);
|
||||
}
|
||||
|
||||
if (this.bCasting && !c.isCopiedSpell()) { // and not a copy
|
||||
// add back to Previous Zone
|
||||
Singletons.getModel().getGame().getAction().moveTo(this.fromZone, c, this.zonePosition);
|
||||
}
|
||||
|
||||
if (this.select != null) {
|
||||
this.select.resetTargets();
|
||||
}
|
||||
|
||||
this.ability.resetOnceResolved();
|
||||
this.payment.cancelPayment();
|
||||
Singletons.getModel().getGame().getStack().clearFrozen();
|
||||
rollbackAbility();
|
||||
return;
|
||||
}
|
||||
|
||||
else if (this.isFree || this.payment.isAllPaid()) {
|
||||
if (this.skipStack) {
|
||||
AbilityUtils.resolve(this.ability, false);
|
||||
} else {
|
||||
this.addAbilityToStack();
|
||||
|
||||
this.enusureAbilityHasDescription(this.ability);
|
||||
this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false);
|
||||
Singletons.getModel().getGame().getStack().addAndUnfreeze(this.ability);
|
||||
}
|
||||
|
||||
this.select.resetTargets();
|
||||
// Warning about this - resolution may come in another thread, and it would still need its targets
|
||||
this.select.clearTargets();
|
||||
Singletons.getModel().getGame().getAction().checkStateEffects();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addAbilityToStack.
|
||||
* </p>
|
||||
*/
|
||||
public final void addAbilityToStack() {
|
||||
// For older abilities that don't setStackDescription set it here
|
||||
if (this.ability.getStackDescription().equals("")) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.ability.getSourceCard().getName());
|
||||
if (this.ability.getTarget() != null) {
|
||||
final ArrayList<Object> targets = this.ability.getTarget().getTargets();
|
||||
if (targets.size() > 0) {
|
||||
sb.append(" - Targeting ");
|
||||
for (final Object o : targets) {
|
||||
sb.append(o.toString()).append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
private void rollbackAbility() {
|
||||
// cancel ability during target choosing
|
||||
final Card c = this.ability.getSourceCard();
|
||||
|
||||
this.ability.setStackDescription(sb.toString());
|
||||
// split cards transform back to full form if targeting is canceled
|
||||
if (c.isSplitCard()) {
|
||||
c.setState(CardCharacteristicName.Original);
|
||||
}
|
||||
|
||||
this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false);
|
||||
Singletons.getModel().getGame().getStack().addAndUnfreeze(this.ability);
|
||||
if (this.bCasting && !c.isCopiedSpell()) { // and not a copy
|
||||
// add back to where it came from
|
||||
Singletons.getModel().getGame().getAction().moveTo(this.fromZone, c, this.zonePosition);
|
||||
}
|
||||
|
||||
if (this.select != null) {
|
||||
this.select.clearTargets();
|
||||
}
|
||||
|
||||
this.ability.resetOnceResolved();
|
||||
this.payment.cancelPayment();
|
||||
Singletons.getModel().getGame().getStack().clearFrozen();
|
||||
// Singletons.getModel().getGame().getStack().removeFromFrozenStack(this.ability);
|
||||
}
|
||||
|
||||
|
||||
public boolean announceRequirements() {
|
||||
// Announcing Requirements like Choosing X or Multikicker
|
||||
// SA Params as comma delimited list
|
||||
String announce = ability.getParam("Announce");
|
||||
if (announce != null) {
|
||||
for(String aVar : announce.split(",")) {
|
||||
String value = ability.getActivatingPlayer().getController().announceRequirements(ability, aVar);
|
||||
if (value == null || !StringUtils.isNumeric(value)) {
|
||||
return false;
|
||||
} else if (ability.getPayCosts().getCostMana() != null && !ability.getPayCosts().getCostMana().canXbe0()
|
||||
&& Integer.parseInt(value) == 0) {
|
||||
return false;
|
||||
}
|
||||
ability.setSVar(aVar, "Number$" + value);
|
||||
ability.getSourceCard().setSVar(aVar, "Number$" + value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void enusureAbilityHasDescription(SpellAbility ability) {
|
||||
if (!StringUtils.isBlank(ability.getStackDescription()))
|
||||
return;
|
||||
|
||||
// For older abilities that don't setStackDescription set it here
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(ability.getSourceCard().getName());
|
||||
if (ability.getTarget() != null) {
|
||||
final ArrayList<Object> targets = ability.getTarget().getTargets();
|
||||
if (targets.size() > 0) {
|
||||
sb.append(" - Targeting ");
|
||||
for (final Object o : targets) {
|
||||
sb.append(o.toString()).append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ability.setStackDescription(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,13 @@ package forge.card.spellability;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.ApiType;
|
||||
@@ -44,6 +46,177 @@ import forge.view.ButtonUtil;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TargetSelection {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public final class InputSelectTargets extends Input {
|
||||
private final TargetSelection select;
|
||||
private final List<Card> choices;
|
||||
private final ArrayList<Object> alreadyTargeted;
|
||||
private final boolean targeted;
|
||||
private final Target tgt;
|
||||
private final SpellAbility sa;
|
||||
private final boolean mandatory;
|
||||
private final CountDownLatch cdlDone;
|
||||
private static final long serialVersionUID = -1091595663541356356L;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param select
|
||||
* @param choices
|
||||
* @param req
|
||||
* @param alreadyTargeted
|
||||
* @param targeted
|
||||
* @param tgt
|
||||
* @param sa
|
||||
* @param mandatory
|
||||
*/
|
||||
public InputSelectTargets(CountDownLatch cdl, TargetSelection select, List<Card> choices, ArrayList<Object> alreadyTargeted, boolean targeted, Target tgt, SpellAbility sa, boolean mandatory) {
|
||||
cdlDone = cdl;
|
||||
this.select = select;
|
||||
this.choices = choices;
|
||||
this.alreadyTargeted = alreadyTargeted;
|
||||
this.targeted = targeted;
|
||||
this.tgt = tgt;
|
||||
this.sa = sa;
|
||||
this.mandatory = mandatory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Targeted: ");
|
||||
for (final Object o : alreadyTargeted) {
|
||||
sb.append(o).append(" ");
|
||||
}
|
||||
sb.append(tgt.getTargetedString());
|
||||
sb.append("\n");
|
||||
sb.append(tgt.getVTSelection());
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
|
||||
|
||||
// If reached Minimum targets, enable OK button
|
||||
if (!tgt.isMinTargetsChosen(sa.getSourceCard(), sa) || tgt.isDividedAsYouChoose()) {
|
||||
if (mandatory && tgt.hasCandidates(sa, true)) {
|
||||
// Player has to click on a target
|
||||
ButtonUtil.disableAll();
|
||||
} else {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
}
|
||||
} else {
|
||||
if (mandatory && tgt.hasCandidates(sa, true)) {
|
||||
// Player has to click on a target or ok
|
||||
ButtonUtil.enableOnlyOk();
|
||||
} else {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
select.setCancel(true);
|
||||
this.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
this.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
// leave this in temporarily, there some seriously wrong things
|
||||
// going on here
|
||||
if (targeted && !card.canBeTargetedBy(sa)) {
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Cannot target this card (Shroud? Protection? Restrictions?).");
|
||||
} else if (choices.contains(card)) {
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
} else if (sa.getApi() == ApiType.PutCounter) {
|
||||
apiBasedMessage = "Select how many counters to distribute to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(card.toString());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(card, allocatedPortion);
|
||||
}
|
||||
tgt.addTarget(card);
|
||||
this.done();
|
||||
}
|
||||
} // selectCard()
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final Player player) {
|
||||
if (alreadyTargeted.contains(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sa.canTarget(player)) {
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((alreadyTargeted.size() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(player.getName());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(player, allocatedPortion);
|
||||
}
|
||||
tgt.addTarget(player);
|
||||
this.done();
|
||||
}
|
||||
}
|
||||
|
||||
void done() {
|
||||
this.stop();
|
||||
cdlDone.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private Target target = null;
|
||||
private SpellAbility ability = null;
|
||||
private Card card = null;
|
||||
@@ -98,6 +271,7 @@ public class TargetSelection {
|
||||
}
|
||||
|
||||
private boolean bCancel = false;
|
||||
private boolean bTargetingDone = false;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -130,20 +304,6 @@ public class TargetSelection {
|
||||
return this.subSelection.isCanceled();
|
||||
}
|
||||
|
||||
private boolean bDoneTarget = false;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setDoneTarget.
|
||||
* </p>
|
||||
*
|
||||
* @param done
|
||||
* a boolean.
|
||||
*/
|
||||
public final void setDoneTarget(final boolean done) {
|
||||
this.bDoneTarget = done;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Target_Selection.
|
||||
@@ -179,7 +339,7 @@ public class TargetSelection {
|
||||
* resetTargets.
|
||||
* </p>
|
||||
*/
|
||||
public final void resetTargets() {
|
||||
public final void clearTargets() {
|
||||
if (this.target != null) {
|
||||
this.target.resetTargets();
|
||||
this.target.calculateStillToDivide(this.ability.getParam("DividedAsYouChoose"), this.getCard(), this.ability);
|
||||
@@ -195,24 +355,25 @@ public class TargetSelection {
|
||||
*/
|
||||
public final boolean chooseTargets() {
|
||||
// if not enough targets chosen, reset and cancel Ability
|
||||
if (this.bCancel || (this.bDoneTarget && !this.target.isMinTargetsChosen(this.card, this.ability))) {
|
||||
if (this.bCancel || (this.bTargetingDone && !this.target.isMinTargetsChosen(this.card, this.ability))) {
|
||||
this.bCancel = true;
|
||||
this.req.finishedTargeting();
|
||||
return false;
|
||||
} else if (!this.doesTarget() || (this.bDoneTarget && this.target.isMinTargetsChosen(this.card, this.ability))
|
||||
}
|
||||
|
||||
if (!this.doesTarget()
|
||||
|| this.bTargetingDone && this.target.isMinTargetsChosen(this.card, this.ability)
|
||||
|| this.target.isMaxTargetsChosen(this.card, this.ability)
|
||||
|| (this.target.isDividedAsYouChoose() && this.target.getStillToDivide() == 0)) {
|
||||
|| this.target.isDividedAsYouChoose() && this.target.getStillToDivide() == 0) {
|
||||
final AbilitySub abSub = this.ability.getSubAbility();
|
||||
|
||||
if (abSub == null) {
|
||||
// if no more SubAbilities finish targeting
|
||||
this.req.finishedTargeting();
|
||||
return true;
|
||||
} else {
|
||||
// Has Sub Ability
|
||||
this.subSelection = new TargetSelection(abSub.getTarget(), abSub);
|
||||
this.subSelection.setRequirements(this.req);
|
||||
this.subSelection.resetTargets();
|
||||
this.subSelection.clearTargets();
|
||||
return this.subSelection.chooseTargets();
|
||||
}
|
||||
}
|
||||
@@ -220,11 +381,12 @@ public class TargetSelection {
|
||||
if (!this.target.hasCandidates(this.ability, true) && !this.target.isMinTargetsChosen(this.card, this.ability)) {
|
||||
// Cancel ability if there aren't any valid Candidates
|
||||
this.bCancel = true;
|
||||
this.req.finishedTargeting();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.chooseValidInput();
|
||||
if ( !bCancel )
|
||||
return chooseTargets();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -362,178 +524,15 @@ public class TargetSelection {
|
||||
}
|
||||
|
||||
if (zone.contains(ZoneType.Battlefield) && zone.size() == 1) {
|
||||
Singletons.getModel().getMatch().getInput().setInput(this.inputTargetSpecific(choices, true, mandatory, objects));
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
Input inp = new InputSelectTargets(cdl, this, choices, objects, true, this.target, this.ability, mandatory);
|
||||
FThreads.setInputAndWait(inp, cdl);
|
||||
bTargetingDone = !bCancel;
|
||||
} else {
|
||||
this.chooseCardFromList(choices, true, mandatory);
|
||||
}
|
||||
} // input_targetValid
|
||||
|
||||
// List<Card> choices are the only cards the user can successful select
|
||||
/**
|
||||
* <p>
|
||||
* input_targetSpecific.
|
||||
* </p>
|
||||
*
|
||||
* @param choices
|
||||
* a {@link forge.CardList} object.
|
||||
* @param targeted
|
||||
* a boolean.
|
||||
* @param mandatory
|
||||
* a boolean.
|
||||
* @param alreadyTargeted
|
||||
* the already targeted
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
*/
|
||||
public final Input inputTargetSpecific(final List<Card> choices, final boolean targeted, final boolean mandatory,
|
||||
final ArrayList<Object> alreadyTargeted) {
|
||||
final SpellAbility sa = this.ability;
|
||||
final TargetSelection select = this;
|
||||
final Target tgt = this.target;
|
||||
final SpellAbilityRequirements req = this.req;
|
||||
|
||||
final Input target = new Input() {
|
||||
private static final long serialVersionUID = -1091595663541356356L;
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Targeted: ");
|
||||
for (final Object o : alreadyTargeted) {
|
||||
sb.append(o).append(" ");
|
||||
}
|
||||
sb.append(tgt.getTargetedString());
|
||||
sb.append("\n");
|
||||
sb.append(tgt.getVTSelection());
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
|
||||
|
||||
// If reached Minimum targets, enable OK button
|
||||
if (!tgt.isMinTargetsChosen(sa.getSourceCard(), sa) || tgt.isDividedAsYouChoose()) {
|
||||
if (mandatory && tgt.hasCandidates(sa, true)) {
|
||||
// Player has to click on a target
|
||||
ButtonUtil.disableAll();
|
||||
} else {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
}
|
||||
} else {
|
||||
if (mandatory && tgt.hasCandidates(sa, true)) {
|
||||
// Player has to click on a target or ok
|
||||
ButtonUtil.enableOnlyOk();
|
||||
} else {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
select.setCancel(true);
|
||||
this.stop();
|
||||
req.finishedTargeting();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
select.setDoneTarget(true);
|
||||
this.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
// leave this in temporarily, there some seriously wrong things
|
||||
// going on here
|
||||
if (targeted && !card.canBeTargetedBy(sa)) {
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Cannot target this card (Shroud? Protection? Restrictions?).");
|
||||
} else if (choices.contains(card)) {
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
} else if (sa.getApi() == ApiType.PutCounter) {
|
||||
apiBasedMessage = "Select how many counters to distribute to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(card.toString());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(card, allocatedPortion);
|
||||
}
|
||||
tgt.addTarget(card);
|
||||
this.done();
|
||||
}
|
||||
} // selectCard()
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final Player player) {
|
||||
if (alreadyTargeted.contains(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sa.canTarget(player)) {
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((alreadyTargeted.size() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(player.getName());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(player, allocatedPortion);
|
||||
}
|
||||
tgt.addTarget(player);
|
||||
this.done();
|
||||
}
|
||||
}
|
||||
|
||||
void done() {
|
||||
this.stop();
|
||||
|
||||
select.chooseTargets();
|
||||
}
|
||||
};
|
||||
|
||||
return target;
|
||||
} // input_targetSpecific()
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* chooseCardFromList.
|
||||
@@ -624,7 +623,7 @@ public class TargetSelection {
|
||||
if (!c.equals(divBattlefield) && !c.equals(divExile) && !c.equals(divGrave)
|
||||
&& !c.equals(divLibrary) && !c.equals(divStack)) {
|
||||
if (c.equals(dummy)) {
|
||||
this.setDoneTarget(true);
|
||||
bTargetingDone = true;
|
||||
} else {
|
||||
tgt.addTarget(c);
|
||||
}
|
||||
@@ -632,8 +631,6 @@ public class TargetSelection {
|
||||
} else {
|
||||
this.setCancel(true);
|
||||
}
|
||||
|
||||
this.chooseTargets();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -675,7 +672,7 @@ public class TargetSelection {
|
||||
|
||||
if (madeChoice != null) {
|
||||
if (madeChoice.equals(doneDummy)) {
|
||||
this.setDoneTarget(true);
|
||||
bTargetingDone = true;
|
||||
} else {
|
||||
tgt.addTarget(map.get(madeChoice));
|
||||
}
|
||||
@@ -683,8 +680,6 @@ public class TargetSelection {
|
||||
select.setCancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
select.chooseTargets();
|
||||
}
|
||||
|
||||
// TODO The following three functions are Utility functions for
|
||||
|
||||
@@ -328,4 +328,15 @@ public abstract class InputPayManaBase extends Input {
|
||||
return "PayManaBase (" + manaCost.toString() + ")";
|
||||
}
|
||||
|
||||
protected void handleConvokedCards(boolean isCancelled) {
|
||||
if (saPaidFor.getTappedForConvoke() != null) {
|
||||
for (final Card c : saPaidFor.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
if (!isCancelled)
|
||||
c.tap();
|
||||
}
|
||||
saPaidFor.clearTappedForConvoke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,17 +82,7 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
|
||||
// any mana tapabilities can't be used in payment as well as being tapped for convoke)
|
||||
|
||||
handleConvokedCards(false);
|
||||
}
|
||||
|
||||
protected void handleConvokedCards(boolean isCancelled) {
|
||||
if (saPaidFor.getTappedForConvoke() != null) {
|
||||
for (final Card c : saPaidFor.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
if (!isCancelled)
|
||||
c.tap();
|
||||
}
|
||||
saPaidFor.clearTappedForConvoke();
|
||||
}
|
||||
cdlFinished.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,6 +92,7 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
|
||||
this.stop();
|
||||
this.resetManaCost();
|
||||
payment.cancelCost();
|
||||
cdlFinished.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -103,21 +103,7 @@ public class InputPayManaSimple extends InputPayManaBase {
|
||||
this.saPaidFor.setSourceCard(game.getAction().moveToStack(this.originalCard));
|
||||
}
|
||||
|
||||
// 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.saPaidFor.getTappedForConvoke() != null) {
|
||||
for (final Card c : this.saPaidFor.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
c.tap();
|
||||
}
|
||||
this.saPaidFor.clearTappedForConvoke();
|
||||
}
|
||||
handleConvokedCards(false);
|
||||
}
|
||||
|
||||
Singletons.getModel().getMatch().getInput().resetInput();
|
||||
@@ -127,14 +113,7 @@ public class InputPayManaSimple extends InputPayManaBase {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void selectButtonCancel() {
|
||||
// If this is a spell with convoke, untap all creatures used for it.
|
||||
if (this.saPaidFor.getTappedForConvoke() != null) {
|
||||
for (final Card c : this.saPaidFor.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
}
|
||||
this.saPaidFor.clearTappedForConvoke();
|
||||
}
|
||||
|
||||
handleConvokedCards(true);
|
||||
this.resetManaCost();
|
||||
|
||||
whoPays.getManaPool().refundManaPaid(this.saPaidFor, true);
|
||||
|
||||
@@ -38,8 +38,7 @@ public class InputPayManaX extends InputPayManaBase {
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
if ((xPaid == 0 && costMana.isxCantBe0()) || (this.colorX.equals("")
|
||||
&& !this.manaCost.toString().equals(strX))) {
|
||||
if (xPaid == 0 && !costMana.canXbe0() || this.colorX.equals("") && !this.manaCost.toString().equals(strX)) {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
// only cancel if partially paid an X value
|
||||
// or X is 0, and x can't be 0
|
||||
@@ -50,7 +49,7 @@ public class InputPayManaX extends InputPayManaBase {
|
||||
StringBuilder msg = new StringBuilder("Pay X Mana Cost for ");
|
||||
msg.append(saPaidFor.getSourceCard().getName()).append("\n").append(this.xPaid);
|
||||
msg.append(" Paid so far.");
|
||||
if (costMana.isxCantBe0()) {
|
||||
if (!costMana.canXbe0()) {
|
||||
msg.append(" X Can't be 0.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user