mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
reintegration of input-sync
This commit is contained in:
19
.gitattributes
vendored
19
.gitattributes
vendored
@@ -13708,6 +13708,7 @@ src/main/java/forge/card/cost/CostUnattach.java -text
|
||||
src/main/java/forge/card/cost/CostUntap.java -text
|
||||
src/main/java/forge/card/cost/CostUntapType.java -text
|
||||
src/main/java/forge/card/cost/CostUtil.java -text
|
||||
src/main/java/forge/card/cost/InputPayCostBase.java -text
|
||||
src/main/java/forge/card/cost/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/card/mana/IParserManaCost.java -text
|
||||
src/main/java/forge/card/mana/Mana.java svneol=native#text/plain
|
||||
@@ -13808,25 +13809,27 @@ src/main/java/forge/control/Lobby.java -text
|
||||
src/main/java/forge/control/RestartUtil.java -text
|
||||
src/main/java/forge/control/bazaar/ControlStall.java -text
|
||||
src/main/java/forge/control/bazaar/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/Input.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/Input.java -text
|
||||
src/main/java/forge/control/input/InputAttack.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputBase.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputBlock.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputCleanup.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputControl.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputLockUI.java -text
|
||||
src/main/java/forge/control/input/InputMulligan.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputPassPriority.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputPayDiscardCost.java -text
|
||||
src/main/java/forge/control/input/InputPayManaBase.java -text
|
||||
src/main/java/forge/control/input/InputPayManaExecuteCommands.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputPayManaOfCostPayment.java -text
|
||||
src/main/java/forge/control/input/InputPayManaSimple.java svneol=native#text/plain
|
||||
src/main/java/forge/control/input/InputPayManaX.java -text
|
||||
src/main/java/forge/control/input/InputPayReturnCost.java -text
|
||||
src/main/java/forge/control/input/InputPaySacCost.java -text
|
||||
src/main/java/forge/control/input/InputSelectMany.java -text
|
||||
src/main/java/forge/control/input/InputSelectManyCards.java -text
|
||||
src/main/java/forge/control/input/InputSelectManyPlayers.java -text
|
||||
src/main/java/forge/control/input/InputPayment.java -text
|
||||
src/main/java/forge/control/input/InputSelectCards.java -text
|
||||
src/main/java/forge/control/input/InputSelectCardsFromList.java -text
|
||||
src/main/java/forge/control/input/InputSelectList.java -text
|
||||
src/main/java/forge/control/input/InputSelectListBase.java -text
|
||||
src/main/java/forge/control/input/InputSynchronized.java -text
|
||||
src/main/java/forge/control/input/InputSyncronizedBase.java -text
|
||||
src/main/java/forge/control/input/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/control/package-info.java -text
|
||||
src/main/java/forge/deck/CardCollections.java -text
|
||||
@@ -13860,7 +13863,6 @@ src/main/java/forge/game/GameActionPlay.java -text
|
||||
src/main/java/forge/game/GameActionUtil.java svneol=native#text/plain
|
||||
src/main/java/forge/game/GameEndReason.java -text
|
||||
src/main/java/forge/game/GameFormat.java -text
|
||||
src/main/java/forge/game/GameInputUpdatesThread.java -text
|
||||
src/main/java/forge/game/GameLossReason.java -text
|
||||
src/main/java/forge/game/GameNew.java -text
|
||||
src/main/java/forge/game/GameOutcome.java -text
|
||||
@@ -14254,7 +14256,6 @@ src/main/java/forge/util/MyRandom.java svneol=native#text/plain
|
||||
src/main/java/forge/util/PredicateString.java -text
|
||||
src/main/java/forge/util/ReflectionUtil.java -text
|
||||
src/main/java/forge/util/TextUtil.java -text
|
||||
src/main/java/forge/util/ThreadUtil.java svneol=native#text/plain
|
||||
src/main/java/forge/util/XmlUtil.java -text
|
||||
src/main/java/forge/util/package-info.java -text
|
||||
src/main/java/forge/util/storage/IStorage.java -text
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -8,6 +8,14 @@
|
||||
/pom.xml.releaseBackup
|
||||
/pom.xml.tag
|
||||
/release.properties
|
||||
res/*.log
|
||||
res/PerSetTrackingResults
|
||||
res/cardsfolder/*.bat
|
||||
res/decks
|
||||
res/layouts
|
||||
res/pics*
|
||||
res/pics_product
|
||||
/target
|
||||
/test-output
|
||||
tools/PerSetTrackingResults
|
||||
tools/oracleScript.log
|
||||
|
||||
@@ -3,25 +3,28 @@ package forge;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import forge.control.input.InputLockUI;
|
||||
import forge.control.input.InputSynchronized;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class FThreads {
|
||||
|
||||
static {
|
||||
System.out.printf("(FThreads static ctor): Running on a machine with %d cpu core(s)%n", Runtime.getRuntime().availableProcessors() );
|
||||
}
|
||||
|
||||
private FThreads() { } // no instances supposed
|
||||
|
||||
private final static ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
public static ExecutorService getCachedPool() {
|
||||
return threadPool;
|
||||
}
|
||||
private static ExecutorService getCachedPool() { return threadPool; }
|
||||
private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1);
|
||||
private static ScheduledExecutorService getScheduledPool() { return scheduledPool; }
|
||||
|
||||
// This pool is designed to parallel CPU or IO intensive tasks like parse cards or download images, assuming a load factor of 0.5
|
||||
public final static ExecutorService getComputingPool(float loadFactor) {
|
||||
@@ -83,27 +86,42 @@ public class FThreads {
|
||||
}
|
||||
|
||||
|
||||
public static void invokeInNewThread(Runnable proc) {
|
||||
invokeInNewThread(proc, false);
|
||||
public static void invokeInNewThread(Runnable toRun) {
|
||||
getCachedPool().execute(toRun);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
invokeInNewThread(toRun);
|
||||
}
|
||||
|
||||
getCachedPool().execute(toRun);
|
||||
public static void setInputAndWait(InputSynchronized input) {
|
||||
Singletons.getModel().getMatch().getInput().setInput(input);
|
||||
input.awaitLatchRelease();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public static boolean isEDT() {
|
||||
return SwingUtilities.isEventDispatchThread();
|
||||
}
|
||||
|
||||
|
||||
public static void delay(int milliseconds, Runnable inputUpdater) {
|
||||
getScheduledPool().schedule(inputUpdater, milliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardUtil;
|
||||
import forge.Command;
|
||||
import forge.Constant;
|
||||
import forge.CounterType;
|
||||
import forge.Singletons;
|
||||
@@ -1036,6 +1035,19 @@ public class AbilityUtils {
|
||||
AbilityUtils.resolveApiAbility(abSub, usedStack, game);
|
||||
}
|
||||
|
||||
private static void resolveApiAbility(final SpellAbility sa, boolean usedStack, final GameState game) {
|
||||
// check conditions
|
||||
if (sa.getConditions().areMet(sa)) {
|
||||
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
|
||||
sa.resolve();
|
||||
} else {
|
||||
handleUnlessCost(sa, usedStack, game);
|
||||
return;
|
||||
}
|
||||
}
|
||||
resolveSubAbilities(sa, usedStack, game);
|
||||
}
|
||||
|
||||
private static void handleUnlessCost(final SpellAbility sa, final boolean usedStack, final GameState game) {
|
||||
final Card source = sa.getSourceCard();
|
||||
String unlessCost = sa.getParam("UnlessCost");
|
||||
@@ -1047,6 +1059,7 @@ public class AbilityUtils {
|
||||
final String resolveSubs = sa.getParam("UnlessResolveSubs"); // no value means 'Always'
|
||||
final boolean execSubsWhenPaid = "WhenPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs);
|
||||
final boolean execSubsWhenNotPaid = "WhenNotPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs);
|
||||
final boolean isSwitched = sa.hasParam("UnlessSwitched");
|
||||
|
||||
// The cost
|
||||
if (unlessCost.equals("CardManaCost")) {
|
||||
@@ -1070,43 +1083,6 @@ public class AbilityUtils {
|
||||
//instead of just X for cards like Draco.
|
||||
}
|
||||
|
||||
final boolean isSwitched = sa.hasParam("UnlessSwitched");
|
||||
|
||||
Command paidCommand = new Command() {
|
||||
private static final long serialVersionUID = 8094833091127334678L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
if (isSwitched && execSubsWhenNotPaid || execSubsWhenPaid) {
|
||||
resolveSubAbilities(sa, usedStack, game);
|
||||
} else if (usedStack) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
game.getStack().finishResolving(root, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = 8094833091127334678L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
sa.resolve();
|
||||
if (isSwitched && execSubsWhenPaid || execSubsWhenNotPaid) {
|
||||
resolveSubAbilities(sa, usedStack, game);
|
||||
} else if (usedStack) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
game.getStack().finishResolving(root, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isSwitched) {
|
||||
final Command dummy = paidCommand;
|
||||
paidCommand = unpaidCommand;
|
||||
unpaidCommand = dummy;
|
||||
}
|
||||
|
||||
final Cost cost = new Cost(source, unlessCost, true);
|
||||
final Ability ability = new AbilityStatic(source, cost, null) {
|
||||
@Override
|
||||
@@ -1117,34 +1093,35 @@ public class AbilityUtils {
|
||||
|
||||
boolean paid = false;
|
||||
for (Player payer : payers) {
|
||||
if (payer.isComputer()) {
|
||||
ability.setActivatingPlayer(payer);
|
||||
if (AbilityUtils.willAIPayForAbility(sa, payer, ability, paid, payers)) {
|
||||
ability.setTarget(sa.getTarget());
|
||||
if (payer.isComputer()) {
|
||||
if (AbilityUtils.willAIPayForAbility(sa, payer, ability, paid, payers)) {
|
||||
ComputerUtil.playNoStack((AIPlayer) payer, ability, game); // Unless cost was payed - no resolve
|
||||
paid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean waitForInput = false;
|
||||
for (Player payer : payers) {
|
||||
if (payer.isHuman()) {
|
||||
} else {
|
||||
// if it's paid by the AI already the human can pay, but it won't change anything
|
||||
if (paid) {
|
||||
unpaidCommand = paidCommand;
|
||||
paid |= GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, sa, game);
|
||||
}
|
||||
ability.setActivatingPlayer(payer);
|
||||
ability.setTarget(sa.getTarget());
|
||||
GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, paidCommand, unpaidCommand, sa, game);
|
||||
waitForInput = true; // wait for the human input
|
||||
break; // multiple human players are not supported
|
||||
}
|
||||
}
|
||||
if (!waitForInput) {
|
||||
Command toExecute = paid ? paidCommand : unpaidCommand;
|
||||
toExecute.execute();
|
||||
}
|
||||
|
||||
if ( paid ^ isSwitched ) {
|
||||
if (isSwitched && execSubsWhenNotPaid || execSubsWhenPaid) {
|
||||
resolveSubAbilities(sa, usedStack, game);
|
||||
} else if (usedStack) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
game.getStack().finishResolving(root, false);
|
||||
}
|
||||
} else {
|
||||
sa.resolve();
|
||||
if (isSwitched && execSubsWhenPaid || execSubsWhenNotPaid) {
|
||||
resolveSubAbilities(sa, usedStack, game);
|
||||
} else if (usedStack) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
game.getStack().finishResolving(root, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1221,19 +1198,6 @@ public class AbilityUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void resolveApiAbility(final SpellAbility sa, boolean usedStack, final GameState game) {
|
||||
// check conditions
|
||||
if (sa.getConditions().areMet(sa)) {
|
||||
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
|
||||
sa.resolve();
|
||||
} else {
|
||||
handleUnlessCost(sa, usedStack, game);
|
||||
return;
|
||||
}
|
||||
}
|
||||
resolveSubAbilities(sa, usedStack, game);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Parse non-mana X variables.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package forge.card.ability.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import forge.Card;
|
||||
@@ -72,8 +71,7 @@ public class DrawAi extends SpellAbilityAi {
|
||||
if (part instanceof CostDiscard) {
|
||||
CostDiscard cd = (CostDiscard) part;
|
||||
cd.decideAIPayment((AIPlayer) ai, sa, sa.getSourceCard(), null);
|
||||
List<Card> discards = cd.getList();
|
||||
for (Card discard : discards) {
|
||||
for (Card discard : cd.getList()) {
|
||||
if (!ComputerUtil.isWorseThanDraw(ai, discard)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import forge.Singletons;
|
||||
import forge.card.ability.SpellAbilityEffect;
|
||||
import forge.card.cardfactory.CardFactoryUtil;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
@@ -45,7 +45,7 @@ public class CountersProliferateEffect extends SpellAbilityEffect {
|
||||
private static void resolveHuman(final SpellAbility sa) {
|
||||
final List<Card> unchosen = Lists.newArrayList(Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield));
|
||||
final List<Player> players = new ArrayList<Player>(Singletons.getModel().getGame().getPlayers());
|
||||
Singletons.getModel().getMatch().getInput().setInput(new Input() {
|
||||
Singletons.getModel().getMatch().getInput().setInput(new InputBase() {
|
||||
private static final long serialVersionUID = -1779224307654698954L;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.google.common.collect.Iterables;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.Command;
|
||||
import forge.CounterType;
|
||||
@@ -44,8 +45,7 @@ import forge.card.spellability.SpellPermanent;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerHandler;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectManyCards;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.ai.ComputerUtilCombat;
|
||||
import forge.game.event.TokenCreatedEvent;
|
||||
@@ -477,43 +477,27 @@ public class CardFactoryCreatures {
|
||||
private static void getCard_PhyrexianDreadnought(final Card card, final String cardName) {
|
||||
final Player player = card.getController();
|
||||
|
||||
final Input target = new InputSelectManyCards(0, Integer.MAX_VALUE) {
|
||||
final Ability sacOrSac = new Ability(card, ManaCost.NO_COST) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
if (player.isHuman()) {
|
||||
final InputSelectCards target = new InputSelectCards(0, Integer.MAX_VALUE) {
|
||||
private static final long serialVersionUID = 2698036349873486664L;
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
String toDisplay = cardName + " - Select any number of creatures to sacrifice. ";
|
||||
toDisplay += "Currently, (" + selected.size() + ") selected with a total power of: "
|
||||
+ getTotalPower();
|
||||
toDisplay += "Currently, (" + selected.size() + ") selected with a total power of: " + getTotalPower();
|
||||
toDisplay += " Click OK when Done.";
|
||||
return toDisplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canCancelWithSomethingSelected() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Input onCancel() {
|
||||
Singletons.getModel().getGame().getAction().sacrifice(card, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidChoice(Card c) {
|
||||
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
|
||||
return c.isCreature() && zone.is(ZoneType.Battlefield, player);
|
||||
} // selectCard()
|
||||
|
||||
@Override
|
||||
protected Input onDone() {
|
||||
for (final Card sac : selected) {
|
||||
Singletons.getModel().getGame().getAction().sacrifice(sac, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasEnoughTargets() {
|
||||
return getTotalPower() >= 12;
|
||||
@@ -528,10 +512,16 @@ public class CardFactoryCreatures {
|
||||
}
|
||||
}; // Input
|
||||
|
||||
final Ability sacOrSac = new Ability(card, ManaCost.NO_COST) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
if (player.isHuman()) {
|
||||
target.setCancelWithSelectedAllowed(true);
|
||||
FThreads.setInputAndWait(target);
|
||||
if(!target.hasCancelled()) {
|
||||
for (final Card sac : target.getSelected()) {
|
||||
Singletons.getModel().getGame().getAction().sacrifice(sac, null);
|
||||
}
|
||||
} else {
|
||||
Singletons.getModel().getGame().getAction().sacrifice(card, null);
|
||||
}
|
||||
|
||||
Singletons.getModel().getMatch().getInput().setInput(target);
|
||||
}
|
||||
} // end resolve
|
||||
|
||||
@@ -24,9 +24,9 @@ import javax.swing.JOptionPane;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Command;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectManyCards;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -46,7 +46,7 @@ class CardFactoryLands {
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
private static final class InputRevealCardType extends InputSelectManyCards {
|
||||
private static final class InputRevealCardType extends InputSelectCards {
|
||||
private final String type;
|
||||
private final Card card;
|
||||
private static final long serialVersionUID = -2774066137824255680L;
|
||||
@@ -74,23 +74,6 @@ class CardFactoryLands {
|
||||
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
|
||||
return zone.is(ZoneType.Hand) && c.isType(type) && c.getController() == card.getController();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Input onDone() {
|
||||
if (selected.isEmpty()) {
|
||||
return onCancel();
|
||||
}
|
||||
|
||||
String cardName = selected.get(0).getName();
|
||||
JOptionPane.showMessageDialog(null, "Revealed card: " + cardName, cardName, JOptionPane.PLAIN_MESSAGE);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Input onCancel() {
|
||||
card.setTapped(true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,7 +212,16 @@ class CardFactoryLands {
|
||||
}
|
||||
|
||||
public void humanExecute() {
|
||||
Singletons.getModel().getMatch().getInput().setInput(new InputRevealCardType(0, 1, type, card));
|
||||
InputSelectCards inp = new InputRevealCardType(0, 1, type, card);
|
||||
FThreads.setInputAndWait(inp);
|
||||
|
||||
if ( inp.hasCancelled() || inp.getSelected().isEmpty() ) {
|
||||
card.setTapped(true);
|
||||
} else {
|
||||
String cardName = inp.getSelected().get(0).getName();
|
||||
JOptionPane.showMessageDialog(null, "Revealed card: " + cardName, cardName, JOptionPane.PLAIN_MESSAGE);
|
||||
}
|
||||
|
||||
} // execute()
|
||||
|
||||
private void revealCard(final Card c) {
|
||||
|
||||
@@ -30,12 +30,13 @@ import com.google.common.collect.Iterables;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.Command;
|
||||
import forge.Constant;
|
||||
import forge.Singletons;
|
||||
import forge.card.CardType;
|
||||
import forge.card.cost.Cost;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.spellability.Spell;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.InputPayManaExecuteCommands;
|
||||
@@ -460,22 +461,13 @@ public class CardFactorySorceries {
|
||||
if (newCMC <= baseCMC) {
|
||||
game.getAction().moveToPlay(newArtifact[0]);
|
||||
} else {
|
||||
final String diffCost = String.valueOf(newCMC - baseCMC);
|
||||
Singletons.getModel().getMatch().getInput().setInput(new InputPayManaExecuteCommands(game, "Pay difference in artifacts CMC", diffCost, new Command() {
|
||||
private static final long serialVersionUID = -8729850321341068049L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Singletons.getModel().getGame().getAction().moveToPlay(newArtifact[0]);
|
||||
}
|
||||
}, new Command() {
|
||||
private static final long serialVersionUID = -246036834856971935L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Singletons.getModel().getGame().getAction().moveToGraveyard(newArtifact[0]);
|
||||
}
|
||||
}));
|
||||
final int diffCost = newCMC - baseCMC;
|
||||
InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, "Pay difference in artifacts CMC", ManaCost.get(diffCost));
|
||||
FThreads.setInputAndWait(inp);
|
||||
if ( inp.isPaid() )
|
||||
game.getAction().moveToPlay(newArtifact[0]);
|
||||
else
|
||||
game.getAction().moveToGraveyard(newArtifact[0]);
|
||||
}
|
||||
|
||||
// finally, shuffle library
|
||||
|
||||
@@ -38,6 +38,7 @@ import forge.CardUtil;
|
||||
import forge.Command;
|
||||
import forge.Constant;
|
||||
import forge.CounterType;
|
||||
import forge.FThreads;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityFactory;
|
||||
@@ -63,7 +64,8 @@ import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerHandler;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectManyCards;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
@@ -98,10 +100,10 @@ public class CardFactoryUtil {
|
||||
* a {@link forge.CardList} object.
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public static Input inputDestroyNoRegeneration(final List<Card> choices, final String message) {
|
||||
final Input target = new Input() {
|
||||
public static InputBase inputDestroyNoRegeneration(final List<Card> choices, final String message) {
|
||||
final InputBase target = new InputBase() {
|
||||
private static final long serialVersionUID = -6637588517573573232L;
|
||||
|
||||
@Override
|
||||
@@ -549,11 +551,11 @@ public class CardFactoryUtil {
|
||||
* a {@link forge.CardList} object.
|
||||
* @param paid
|
||||
* a {@link forge.Command} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public static Input masterOfTheWildHuntInputTargetCreature(final SpellAbility spell, final List<Card> choices,
|
||||
public static InputBase masterOfTheWildHuntInputTargetCreature(final SpellAbility spell, final List<Card> choices,
|
||||
final Command paid) {
|
||||
final Input target = new Input() {
|
||||
final InputBase target = new InputBase() {
|
||||
private static final long serialVersionUID = -1779224307654698954L;
|
||||
|
||||
@Override
|
||||
@@ -593,10 +595,10 @@ public class CardFactoryUtil {
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param card
|
||||
* a {@link forge.Card} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public static Input modularInput(final SpellAbility ability, final Card card) {
|
||||
final Input modularInput = new Input() {
|
||||
public static InputBase modularInput(final SpellAbility ability, final Card card) {
|
||||
final InputBase modularInput = new InputBase() {
|
||||
|
||||
private static final long serialVersionUID = 2322926875771867901L;
|
||||
|
||||
@@ -2302,10 +2304,10 @@ public class CardFactoryUtil {
|
||||
* a int.
|
||||
* @param type
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public static Input inputUntapUpToNType(final int n, final String type) {
|
||||
final Input untap = new Input() {
|
||||
final Input untap = new InputBase() {
|
||||
private static final long serialVersionUID = -2167059918040912025L;
|
||||
|
||||
private final int stop = n;
|
||||
@@ -3151,27 +3153,6 @@ public class CardFactoryUtil {
|
||||
};
|
||||
haunterDiesWork.setDescription(hauntDescription);
|
||||
|
||||
final InputSelectManyCards target = new InputSelectManyCards(1, 1) {
|
||||
private static final long serialVersionUID = 1981791992623774490L;
|
||||
|
||||
@Override
|
||||
protected Input onDone() {
|
||||
haunterDiesWork.setTargetCard(selected.get(0));
|
||||
Singletons.getModel().getGame().getStack().add(haunterDiesWork);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidChoice(Card c) {
|
||||
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
|
||||
if (!zone.is(ZoneType.Battlefield) || !c.isCreature()) {
|
||||
return false;
|
||||
}
|
||||
return c.canBeTargetedBy(haunterDiesWork);
|
||||
}
|
||||
};
|
||||
target.setMessage("Choose target creature to haunt.");
|
||||
|
||||
final Ability haunterDiesSetup = new Ability(card, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
@@ -3189,7 +3170,25 @@ public class CardFactoryUtil {
|
||||
// need to do it this way because I don't know quite how to
|
||||
// make TriggerHandler respect BeforePayMana.
|
||||
if (card.getController().isHuman()) {
|
||||
Singletons.getModel().getMatch().getInput().setInput(target);
|
||||
|
||||
final InputSelectCards target = new InputSelectCards(1, 1) {
|
||||
private static final long serialVersionUID = 1981791992623774490L;
|
||||
@Override
|
||||
protected boolean isValidChoice(Card c) {
|
||||
Zone zone = Singletons.getModel().getGame().getZoneOf(c);
|
||||
if (!zone.is(ZoneType.Battlefield) || !c.isCreature()) {
|
||||
return false;
|
||||
}
|
||||
return c.canBeTargetedBy(haunterDiesWork);
|
||||
}
|
||||
};
|
||||
target.setMessage("Choose target creature to haunt.");
|
||||
|
||||
FThreads.setInputAndWait(target);
|
||||
if (!target.hasCancelled()) {
|
||||
haunterDiesWork.setTargetCard(target.getSelected().get(0));
|
||||
Singletons.getModel().getGame().getStack().add(haunterDiesWork);
|
||||
}
|
||||
} else {
|
||||
// AI choosing what to haunt
|
||||
final List<Card> oppCreats = CardLists.filterControlledBy(creats, card.getController().getOpponent());
|
||||
|
||||
@@ -103,10 +103,11 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final String amount = this.getAmount();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
final int life = activator.getLife();
|
||||
final Card source = ability.getSourceCard();
|
||||
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
@@ -124,11 +125,7 @@ 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;
|
||||
|
||||
@@ -19,23 +19,20 @@ package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.control.input.InputSelectCardsFromList;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
* The Class CostDiscard.
|
||||
@@ -43,6 +40,8 @@ import forge.view.ButtonUtil;
|
||||
public class CostDiscard extends CostPartWithList {
|
||||
// Discard<Num/Type{/TypeDescription}>
|
||||
|
||||
// Inputs
|
||||
|
||||
/**
|
||||
* Instantiates a new cost discard.
|
||||
*
|
||||
@@ -155,7 +154,7 @@ public class CostDiscard extends CostPartWithList {
|
||||
@Override
|
||||
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
|
||||
for (final Card c : this.getList()) {
|
||||
ai.discard(c, ability);
|
||||
executePayment(ability, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,10 +166,11 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
final Card source = ability.getSourceCard();
|
||||
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();
|
||||
|
||||
@@ -178,25 +178,24 @@ public class CostDiscard extends CostPartWithList {
|
||||
if (!handList.contains(source)) {
|
||||
return false;
|
||||
}
|
||||
activator.discard(source, ability);
|
||||
payment.setPaidManaPart(this);
|
||||
executePayment(ability, source);
|
||||
return true;
|
||||
//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")) {
|
||||
return true;
|
||||
} else if (discardType.equals("LastDrawn")) {
|
||||
final Card lastDrawn = activator.getLastDrawnCard();
|
||||
this.addToList(lastDrawn);
|
||||
if (!handList.contains(lastDrawn)) {
|
||||
return false;
|
||||
}
|
||||
activator.discard(lastDrawn, ability);
|
||||
payment.setPaidManaPart(this);
|
||||
executePayment(ability, lastDrawn);
|
||||
return true;
|
||||
} 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 +207,9 @@ public class CostDiscard extends CostPartWithList {
|
||||
}
|
||||
|
||||
this.setList(activator.discardRandom(c, ability));
|
||||
payment.setPaidManaPart(this);
|
||||
return true;
|
||||
} else {
|
||||
String type = new String(discType);
|
||||
String type = new String(discardType);
|
||||
boolean sameName = false;
|
||||
if (type.contains("+WithSameName")) {
|
||||
sameName = true;
|
||||
@@ -243,14 +242,18 @@ public class CostDiscard extends CostPartWithList {
|
||||
}
|
||||
}
|
||||
|
||||
final Input inp = CostDiscard.inputDiscardCost(discType, handList, ability, payment, this, c);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
InputSelectCards inp = new InputSelectCardsFromList(c, c, handList);
|
||||
inp.setMessage("Select %d more " + getDescriptiveType() + " to discard.");
|
||||
//InputPayment inp = new InputPayCostDiscard(ability, handList, this, c, discardType);
|
||||
FThreads.setInputAndWait(inp);
|
||||
if( inp.hasCancelled() || inp.getSelected().size() != c)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.addListToHash(ability, "Discarded");
|
||||
for(Card crd : inp.getSelected())
|
||||
executePayment(ability, crd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -306,109 +309,23 @@ public class CostDiscard extends CostPartWithList {
|
||||
return this.getList() != null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
this.addToList(targetCard);
|
||||
targetCard.getController().discard(targetCard, ability);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Discarded";
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
@@ -20,19 +20,20 @@ package forge.card.cost;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
import forge.card.spellability.SpellAbilityStackInstance;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.MagicStack;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.GuiDialog;
|
||||
@@ -49,19 +50,15 @@ 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.
|
||||
* @param sa
|
||||
@@ -70,11 +67,10 @@ public class CostExile extends CostPartWithList {
|
||||
* @param payment
|
||||
* @param part
|
||||
*/
|
||||
private InputExileFrom(SpellAbility sa, String type, int nNeeded, CostPayment payment, CostExile part) {
|
||||
private InputExileFrom(SpellAbility sa, String type, int nNeeded, CostExile part) {
|
||||
this.sa = sa;
|
||||
this.type = type;
|
||||
this.nNeeded = nNeeded;
|
||||
this.payment = payment;
|
||||
this.part = part;
|
||||
}
|
||||
|
||||
@@ -96,8 +92,7 @@ public class CostExile extends CostPartWithList {
|
||||
|
||||
if (c != null) {
|
||||
this.typeList.remove(c);
|
||||
part.addToList(c);
|
||||
Singletons.getModel().getGame().getAction().exile(c);
|
||||
part.executePayment(sa, c);
|
||||
if (i == (nNeeded - 1)) {
|
||||
this.done();
|
||||
}
|
||||
@@ -107,33 +102,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 +125,9 @@ 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(List<Card> list, CostExile part, int nNeeded, List<Player> payableZone) {
|
||||
this.list = list;
|
||||
this.part = part;
|
||||
this.payment = payment;
|
||||
this.sa = sa;
|
||||
this.nNeeded = nNeeded;
|
||||
this.payableZone = payableZone;
|
||||
}
|
||||
@@ -185,8 +159,7 @@ public class CostExile extends CostPartWithList {
|
||||
|
||||
if (c != null) {
|
||||
this.typeList.remove(c);
|
||||
part.addToList(c);
|
||||
Singletons.getModel().getGame().getAction().exile(c);
|
||||
part.executePayment(null, c);
|
||||
if (i == (nNeeded - 1)) {
|
||||
this.done();
|
||||
}
|
||||
@@ -196,30 +169,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 +193,7 @@ 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(SpellAbility sa, String type, int nNeeded, CostExile part) {
|
||||
this.sa = sa;
|
||||
this.type = type;
|
||||
this.nNeeded = nNeeded;
|
||||
@@ -252,10 +208,11 @@ public class CostExile extends CostPartWithList {
|
||||
|
||||
saList = new ArrayList<SpellAbility>();
|
||||
descList = new ArrayList<String>();
|
||||
final MagicStack stack = sa.getActivatingPlayer().getGame().getStack();
|
||||
|
||||
for (int i = 0; i < Singletons.getModel().getGame().getStack().size(); i++) {
|
||||
final Card stC = Singletons.getModel().getGame().getStack().peekAbility(i).getSourceCard();
|
||||
final SpellAbility stSA = Singletons.getModel().getGame().getStack().peekAbility(i).getRootAbility();
|
||||
for (int i = 0; i < stack.size(); i++) {
|
||||
final Card stC = stack.peekAbility(i).getSourceCard();
|
||||
final SpellAbility stSA = stack.peekAbility(i).getRootAbility();
|
||||
if (stC.isValid(type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard()) && stSA.isSpell()) {
|
||||
this.saList.add(stSA);
|
||||
if (stC.isCopiedSpell()) {
|
||||
@@ -277,47 +234,33 @@ public class CostExile extends CostPartWithList {
|
||||
if (o != null) {
|
||||
final SpellAbility toExile = this.saList.get(descList.indexOf(o));
|
||||
final Card c = toExile.getSourceCard();
|
||||
|
||||
|
||||
this.saList.remove(toExile);
|
||||
part.addToList(c);
|
||||
if (!c.isCopiedSpell()) {
|
||||
Singletons.getModel().getGame().getAction().exile(c);
|
||||
}
|
||||
part.executePayment(sa, c);
|
||||
} else
|
||||
part.addToList(c);
|
||||
|
||||
if (i == (nNeeded - 1)) {
|
||||
this.done();
|
||||
}
|
||||
final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(toExile);
|
||||
Singletons.getModel().getGame().getStack().remove(si);
|
||||
final SpellAbilityStackInstance si = stack.getInstanceFromSpellAbility(toExile);
|
||||
stack.remove(si);
|
||||
} else {
|
||||
this.cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 +276,8 @@ public class CostExile extends CostPartWithList {
|
||||
* @param nNeeded
|
||||
* @param sa
|
||||
*/
|
||||
private InputExileType(CostExile part, CostPayment payment, String type, int nNeeded, SpellAbility sa) {
|
||||
private InputExileType(CostExile part, String type, int nNeeded, SpellAbility sa) {
|
||||
this.part = part;
|
||||
this.payment = payment;
|
||||
this.type = type;
|
||||
this.nNeeded = nNeeded;
|
||||
this.sa = sa;
|
||||
@@ -366,17 +308,11 @@ 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)) {
|
||||
this.nExiles++;
|
||||
part.addToList(card);
|
||||
Singletons.getModel().getGame().getAction().exile(card);
|
||||
part.executePayment(sa, card);
|
||||
this.typeList.remove(card);
|
||||
// in case nothing else to exile
|
||||
if (this.nExiles == nNeeded) {
|
||||
@@ -389,25 +325,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 +342,22 @@ public class CostExile extends CostPartWithList {
|
||||
* @param part
|
||||
* @param sa
|
||||
*/
|
||||
private InputExileThis(CostPayment payment, CostExile part, SpellAbility sa) {
|
||||
this.payment = payment;
|
||||
private InputExileThis(CostExile part, SpellAbility sa) {
|
||||
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);
|
||||
} else {
|
||||
this.stop();
|
||||
payment.cancelCost();
|
||||
part.executePayment(sa, card);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,8 +535,9 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = this.convertAmount();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
List<Card> list;
|
||||
@@ -632,11 +549,10 @@ public class CostExile extends CostPartWithList {
|
||||
}
|
||||
|
||||
if (this.getType().equals("All")) {
|
||||
this.setList(list);
|
||||
for (final Card card : list) {
|
||||
Singletons.getModel().getGame().getAction().exile(card);
|
||||
executePayment(ability, card);
|
||||
}
|
||||
payment.paidCost(this);
|
||||
return true;
|
||||
}
|
||||
list = CardLists.getValidCards(list, this.getType().split(";"), activator, source);
|
||||
if (c == null) {
|
||||
@@ -651,16 +567,16 @@ public class CostExile extends CostPartWithList {
|
||||
}
|
||||
}
|
||||
|
||||
Input target = null;
|
||||
InputPayment target = null;
|
||||
if (this.payCostFromSource()) {
|
||||
target = new InputExileThis(payment, this, ability);
|
||||
target = new InputExileThis(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(this, this.getType(), c, ability);
|
||||
} else if (this.from.equals(ZoneType.Stack)) {
|
||||
target = new InputExileFromStack(payment, ability, this.getType(), c, this);
|
||||
target = new InputExileFromStack(ability, this.getType(), c, this);
|
||||
} else if (this.from.equals(ZoneType.Library)) {
|
||||
// this does not create input
|
||||
CostExile.exileFromTop(ability, this, payment, c);
|
||||
return exileFromTop(ability, c);
|
||||
} else if (this.sameZone) {
|
||||
List<Player> players = game.getPlayers();
|
||||
List<Player> payableZone = new ArrayList<Player>();
|
||||
@@ -672,13 +588,13 @@ public class CostExile extends CostPartWithList {
|
||||
payableZone.add(p);
|
||||
}
|
||||
}
|
||||
target = new InputExileFromSame(list, this, payment, ability, c, payableZone);
|
||||
target = new InputExileFromSame(list, this, c, payableZone);
|
||||
} else {
|
||||
target = new InputExileFrom(ability, this.getType(), c, payment, this);
|
||||
target = new InputExileFrom(ability, this.getType(), c, this);
|
||||
}
|
||||
if ( null != target )
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(target);
|
||||
return false;
|
||||
FThreads.setInputAndWait(target);
|
||||
return target.isPaid();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -741,30 +657,43 @@ public class CostExile extends CostPartWithList {
|
||||
* @param nNeeded
|
||||
* the n needed
|
||||
*/
|
||||
public static void exileFromTop(final SpellAbility sa, final CostExile part, final CostPayment payment,
|
||||
final int nNeeded) {
|
||||
public boolean exileFromTop(final SpellAbility sa, final int nNeeded) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Exile ").append(nNeeded).append(" cards from the top of your library?");
|
||||
final List<Card> list = sa.getActivatingPlayer().getCardsIn(ZoneType.Library, nNeeded);
|
||||
|
||||
if (list.size() > nNeeded) {
|
||||
// I don't believe this is possible
|
||||
payment.cancelCost();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean doExile = GuiDialog.confirm(sa.getSourceCard(), sb.toString());
|
||||
if (doExile) {
|
||||
final Iterator<Card> itr = list.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
part.addToList(c);
|
||||
Singletons.getModel().getGame().getAction().exile(c);
|
||||
executePayment(sa, itr.next());
|
||||
}
|
||||
part.addListToHash(sa, "Exiled");
|
||||
payment.paidCost(part);
|
||||
return true;
|
||||
} else {
|
||||
payment.cancelCost();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
addToList(targetCard);
|
||||
ability.getActivatingPlayer().getGame().getAction().exile(targetCard);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
// TODO Auto-generated method stub
|
||||
return "Exiled";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,8 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Card source = ability.getSourceCard();
|
||||
final String amount = this.getAmount();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
final int life = activator.getLife();
|
||||
@@ -163,8 +164,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();
|
||||
@@ -174,16 +173,12 @@ public class CostGainLife extends CostPart {
|
||||
for(int playersLeft = cntPlayers; playersLeft > 0; playersLeft--) {
|
||||
final Player chosenToGain = GuiChoose.oneOrNone(sb.toString(), oppsThatCanGainLife);
|
||||
if (null == chosenToGain) {
|
||||
payment.setCancel(true);
|
||||
payment.getRequirements().finishPaying();
|
||||
return false;
|
||||
} else {
|
||||
final Player chosen = chosenToGain;
|
||||
chosen.gainLife(c, null);
|
||||
}
|
||||
}
|
||||
|
||||
payment.setPaidManaPart(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,9 +126,10 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final String amount = this.getAmount();
|
||||
Integer c = this.convertAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
|
||||
if (c == null) {
|
||||
@@ -144,29 +145,22 @@ public class CostMill extends CostPartWithList {
|
||||
|
||||
if ((list == null) || (list.size() > c)) {
|
||||
// I don't believe this is possible
|
||||
payment.cancelCost();
|
||||
return false;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Mill ").append(c).append(" cards from your library?");
|
||||
|
||||
final boolean doMill = GuiDialog.confirm(source, sb.toString());
|
||||
if (doMill) {
|
||||
if ( false == GuiDialog.confirm(source, sb.toString()) )
|
||||
return false;
|
||||
|
||||
this.resetList();
|
||||
final Iterator<Card> itr = list.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card card = itr.next();
|
||||
this.addToList(card);
|
||||
Singletons.getModel().getGame().getAction().moveToGraveyard(card);
|
||||
}
|
||||
this.addListToHash(ability, "Milled");
|
||||
payment.paidCost(this);
|
||||
return false;
|
||||
} else {
|
||||
payment.cancelCost();
|
||||
return false;
|
||||
executePayment(ability, card);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -195,4 +189,21 @@ public class CostMill extends CostPartWithList {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
this.addToList(targetCard);
|
||||
ability.getActivatingPlayer().getGame().getAction().moveToGraveyard(targetCard);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Milled";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.card.cost;
|
||||
|
||||
|
||||
import forge.Card;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.GameState;
|
||||
@@ -199,7 +200,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 boolean payHuman(SpellAbility ability, GameState game);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
||||
@@ -20,12 +20,12 @@ package forge.card.cost;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayManaOfCostPayment;
|
||||
import forge.control.input.InputPayManaX;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtilMana;
|
||||
import forge.game.player.AIPlayer;
|
||||
@@ -111,8 +111,8 @@ public class CostPartMana extends CostPart {
|
||||
/**
|
||||
* @return the xCantBe0
|
||||
*/
|
||||
public boolean isxCantBe0() {
|
||||
return xCantBe0;
|
||||
public boolean canXbe0() {
|
||||
return !xCantBe0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +206,8 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Card source = ability.getSourceCard();
|
||||
int manaToAdd = 0;
|
||||
if (!this.hasNoXManaCost()) {
|
||||
// if X cost is a defined value, other than xPaid
|
||||
@@ -215,20 +216,24 @@ 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);
|
||||
} else if (this.getXMana() > 0) {
|
||||
final Input inp = new InputPayManaX(game, ability, payment, this);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
} else {
|
||||
payment.paidCost(this);
|
||||
}
|
||||
|
||||
// We return false here because the Inputs set above should recall
|
||||
// payment.payCosts()
|
||||
|
||||
if (!"0".equals(this.getManaToPay()) || manaToAdd > 0) {
|
||||
InputPayment inpPayment = new InputPayManaOfCostPayment(game, this, ability, manaToAdd);
|
||||
FThreads.setInputAndWait(inpPayment);
|
||||
if(!inpPayment.isPaid())
|
||||
return false;
|
||||
}
|
||||
if (this.getXMana() > 0) {
|
||||
source.setXManaCostPaid(0);
|
||||
InputPayment inpPayment = new InputPayManaX(game, ability, this);
|
||||
FThreads.setInputAndWait(inpPayment);
|
||||
if(!inpPayment.isPaid())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
*/
|
||||
package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardUtil;
|
||||
@@ -30,14 +31,16 @@ import forge.card.spellability.SpellAbility;
|
||||
public abstract class CostPartWithList extends CostPart {
|
||||
|
||||
/** The list. */
|
||||
private List<Card> list = null;
|
||||
private Set<Card> list = new HashSet<Card>();
|
||||
// set is here because executePayment() adds card to list, while ai's decide payment does the same thing.
|
||||
// set allows to avoid duplication
|
||||
|
||||
/**
|
||||
* Gets the list.
|
||||
*
|
||||
* @return the list
|
||||
*/
|
||||
public final List<Card> getList() {
|
||||
public final Set<Card> getList() {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
@@ -48,14 +51,15 @@ public abstract class CostPartWithList extends CostPart {
|
||||
* the new list
|
||||
*/
|
||||
public final void setList(final List<Card> setList) {
|
||||
this.list = setList;
|
||||
this.list.clear();
|
||||
list.addAll(setList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset list.
|
||||
*/
|
||||
public final void resetList() {
|
||||
this.setList(new ArrayList<Card>());
|
||||
this.list.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,10 +69,7 @@ public abstract class CostPartWithList extends CostPart {
|
||||
* the c
|
||||
*/
|
||||
public final void addToList(final Card c) {
|
||||
if (this.getList() == null) {
|
||||
this.resetList();
|
||||
}
|
||||
this.getList().add(c);
|
||||
this.list.add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,4 +107,12 @@ public abstract class CostPartWithList extends CostPart {
|
||||
super(amount, type, description);
|
||||
this.resetList();
|
||||
}
|
||||
|
||||
public abstract void executePayment(SpellAbility ability, Card targetCard);
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public abstract String getHashForList();
|
||||
}
|
||||
|
||||
@@ -123,7 +123,8 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Card source = ability.getSourceCard();
|
||||
final String amount = this.getAmount();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
final int life = activator.getLife();
|
||||
@@ -147,13 +148,9 @@ 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;
|
||||
|
||||
@@ -38,7 +38,6 @@ import forge.game.player.Player;
|
||||
public class CostPayment {
|
||||
private Cost cost = null;
|
||||
private SpellAbility ability = null;
|
||||
private Card card = null;
|
||||
private SpellAbilityRequirements req = null;
|
||||
private boolean bCancel = false;
|
||||
private final ArrayList<CostPart> paidCostParts = new ArrayList<CostPart>();
|
||||
@@ -74,7 +73,7 @@ public class CostPayment {
|
||||
* @return a {@link forge.Card} object.
|
||||
*/
|
||||
public final Card getCard() {
|
||||
return this.card;
|
||||
return this.ability.getSourceCard();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +134,6 @@ public class CostPayment {
|
||||
public CostPayment(final Cost cost, final SpellAbility abil, final GameState game) {
|
||||
this.cost = cost;
|
||||
this.ability = abil;
|
||||
this.card = abil.getSourceCard();
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
@@ -179,26 +177,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 +194,6 @@ public class CostPayment {
|
||||
*/
|
||||
public final void cancelCost() {
|
||||
this.setCancel(true);
|
||||
this.req.finishPaying();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,27 +203,22 @@ public class CostPayment {
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean payCost() {
|
||||
// Nothing actually ever checks this return value, is it needed?
|
||||
if (this.bCancel) {
|
||||
this.req.finishPaying();
|
||||
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)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!part.payHuman(this.ability, this.card, this, game)) {
|
||||
return false;
|
||||
if ( false == part.payHuman(getAbility(), game) ) {
|
||||
this.setCancel(true);
|
||||
return;
|
||||
}
|
||||
if( part instanceof CostPartWithList )
|
||||
((CostPartWithList) part).addListToHash(ability, ((CostPartWithList) part).getHashForList());
|
||||
setPaidPart(part);
|
||||
}
|
||||
|
||||
this.resetUndoList();
|
||||
this.req.finishPaying();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +259,7 @@ public class CostPayment {
|
||||
public final void cancelPayment() {
|
||||
for (final CostPart part : this.paidCostParts) {
|
||||
if (part.isUndoable()) {
|
||||
part.refund(this.card);
|
||||
part.refund(this.getCard());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,13 @@
|
||||
package forge.card.cost;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CounterType;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.player.AIPlayer;
|
||||
@@ -38,6 +37,69 @@ 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(String type, CostPutCounter costPutCounter, int nNeeded, SpellAbility sa) {
|
||||
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.executePayment(sa, card);
|
||||
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;
|
||||
@@ -156,17 +218,14 @@ public class CostPutCounter extends CostPartWithList {
|
||||
*/
|
||||
@Override
|
||||
public final void payAI(final AIPlayer ai, 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);
|
||||
}
|
||||
Integer c = getNumberOfCounters(ability);
|
||||
|
||||
if (this.payCostFromSource()) {
|
||||
source.addCounter(this.getCounter(), c, false);
|
||||
executePayment(ability, source, c);
|
||||
} else {
|
||||
// Put counter on chosen card
|
||||
for (final Card card : this.getList()) {
|
||||
card.addCounter(this.getCounter(), 1, false);
|
||||
executePayment(ability, card);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,24 +238,28 @@ 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) {
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
|
||||
}
|
||||
public final boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = getNumberOfCounters(ability);
|
||||
|
||||
if (this.payCostFromSource()) {
|
||||
source.addCounter(this.getCounter(), c, false);
|
||||
payment.setPaidManaPart(this);
|
||||
this.addToList(source);
|
||||
executePayment(ability, source, c);
|
||||
return true;
|
||||
} else {
|
||||
final Input inp = CostPutCounter.putCounterType(ability, this.getType(), payment, this, c);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
return false;
|
||||
InputPayment inp = new InputPayCostPutCounter(this.getType(), this, c, ability);
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.isPaid();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getNumberOfCounters(final SpellAbility ability) {
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
c = AbilityUtils.calculateAmount(ability.getSourceCard(), this.getAmount(), ability);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -211,13 +274,7 @@ public class CostPutCounter extends CostPartWithList {
|
||||
this.addToList(source);
|
||||
return true;
|
||||
} else {
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
c = AbilityUtils.calculateAmount(source, this.getAmount(), ability);
|
||||
}
|
||||
|
||||
final List<Card> typeList =
|
||||
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), this.getType().split(";"), ai, source);
|
||||
final List<Card> typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), this.getType().split(";"), ai, source);
|
||||
|
||||
Card card = null;
|
||||
if (this.getType().equals("Creature.YouCtrl")) {
|
||||
@@ -230,83 +287,22 @@ 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.
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
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 executePayment(SpellAbility ability, Card targetCard){
|
||||
executePayment(ability, targetCard, 1);
|
||||
}
|
||||
|
||||
public void executePayment(SpellAbility ability, Card targetCard, int c) {
|
||||
targetCard.addCounter(this.getCounter(), c, false);
|
||||
this.addToList(targetCard);
|
||||
}
|
||||
|
||||
|
||||
@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;
|
||||
public String getHashForList() {
|
||||
return "CounterPut";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,13 @@ package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CounterType;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
@@ -46,6 +45,142 @@ 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(int nNeeded, SpellAbility sa, String type, CostRemoveCounter costRemoveCounter) {
|
||||
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.executePayment(sa, card);
|
||||
|
||||
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(CostRemoveCounter costRemoveCounter, String type, SpellAbility sa, int nNeeded) {
|
||||
|
||||
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.isEmpty()) {
|
||||
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.executePayment(sa, card);
|
||||
|
||||
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,8 +356,9 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = this.convertAmount();
|
||||
int maxCounters = 0;
|
||||
|
||||
@@ -237,15 +373,14 @@ public class CostRemoveCounter extends CostPartWithList {
|
||||
}
|
||||
}
|
||||
|
||||
final InputPayment inp;
|
||||
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(c, ability, this.getType(), this);
|
||||
} else {
|
||||
inp = new InputPayCostRemoveCounterFrom(this, this.getType(), ability, c);
|
||||
}
|
||||
else {
|
||||
final Input inp = CostRemoveCounter.removeCounterTypeFrom(ability, this.getType(), payment, this, c);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
}
|
||||
return false;
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.isPaid();
|
||||
}
|
||||
|
||||
maxCounters = source.getCounters(this.counter);
|
||||
@@ -263,17 +398,12 @@ public class CostRemoveCounter extends CostPartWithList {
|
||||
}
|
||||
}
|
||||
|
||||
if (maxCounters >= c) {
|
||||
if (maxCounters < c) return false;
|
||||
|
||||
|
||||
this.addToList(source);
|
||||
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;
|
||||
}
|
||||
executePayment(ability, source, c);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -321,171 +451,23 @@ 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.
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
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();
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
executePayment(ability, targetCard, 1);
|
||||
}
|
||||
|
||||
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();
|
||||
public void executePayment(SpellAbility ability, Card targetCard, int n) {
|
||||
addToList(targetCard);
|
||||
targetCard.subtractCounter(getCounter(), n);
|
||||
}
|
||||
|
||||
@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.
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
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;
|
||||
public String getHashForList() {
|
||||
return "CounterRemove";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,22 +19,19 @@ package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.control.input.InputSelectCardsFromList;
|
||||
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.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
import forge.gui.GuiDialog;
|
||||
|
||||
/**
|
||||
* The Class CostReturn.
|
||||
@@ -123,7 +120,7 @@ public class CostReturn extends CostPartWithList {
|
||||
@Override
|
||||
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
|
||||
for (final Card c : this.getList()) {
|
||||
Singletons.getModel().getGame().getAction().moveToHand(c);
|
||||
executePayment(ability, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,8 +132,9 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = this.convertAmount();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
final List<Card> list = activator.getCardsIn(ZoneType.Battlefield);
|
||||
@@ -150,11 +148,26 @@ 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) {
|
||||
executePayment(ability, card);
|
||||
}
|
||||
return confirm;
|
||||
}
|
||||
} else {
|
||||
final Input inp = CostReturn.returnType(ability, this.getType(), payment, this, c);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
List<Card> validCards = CardLists.getValidCards(ability.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), this.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
|
||||
|
||||
InputSelectCards inp = new InputSelectCardsFromList(c, c, validCards);
|
||||
inp.setMessage("Return %d " + this.getType() + " " + this.getType() + " card(s) to hand");
|
||||
FThreads.setInputAndWait(inp);
|
||||
if (inp.hasCancelled())
|
||||
return false;
|
||||
|
||||
for(Card crd : inp.getSelected())
|
||||
executePayment(ability, crd);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -178,140 +191,31 @@ public class CostReturn extends CostPartWithList {
|
||||
}
|
||||
|
||||
this.setList(ComputerUtil.chooseReturnType(ai, this.getType(), source, ability.getTargetCard(), c));
|
||||
if (this.getList() == null) {
|
||||
if (this.getList().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
addToList(targetCard);
|
||||
ability.getActivatingPlayer().getGame().getAction().moveToHand(targetCard);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Returned";
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
@@ -19,20 +19,19 @@ package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
@@ -41,6 +40,87 @@ 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 InputPayCostBase {
|
||||
private final CostReveal part;
|
||||
private final String discType;
|
||||
private final List<Card> handList;
|
||||
private final SpellAbility sa;
|
||||
private final int nNeeded;
|
||||
private static final long serialVersionUID = -329993322080934435L;
|
||||
private int nReveal = 0;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param part
|
||||
* @param discType
|
||||
* @param handList
|
||||
* @param sa
|
||||
* @param payment
|
||||
* @param nNeeded
|
||||
*/
|
||||
public InputPayReveal(CostReveal part, String discType, List<Card> handList, SpellAbility sa, int nNeeded) {
|
||||
this.part = part;
|
||||
this.discType = discType;
|
||||
this.handList = handList;
|
||||
this.sa = sa;
|
||||
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.");
|
||||
}
|
||||
showMessage(sb.toString());
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
}
|
||||
|
||||
@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.executePayment(sa, 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new cost reveal.
|
||||
*
|
||||
@@ -140,6 +220,8 @@ public class CostReveal extends CostPartWithList {
|
||||
@Override
|
||||
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
|
||||
GuiChoose.oneOrNone("Revealed cards:", this.getList());
|
||||
for(Card c: getList()) // should not throw concurrent modification here - no items should be added.
|
||||
executePayment(ability, c);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,17 +232,19 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
final Card source = ability.getSourceCard();
|
||||
final String amount = this.getAmount();
|
||||
this.resetList();
|
||||
|
||||
if (this.payCostFromSource()) {
|
||||
this.addToList(source);
|
||||
payment.setPaidManaPart(this);
|
||||
executePayment(ability, source);
|
||||
return true;
|
||||
} else if (this.getType().equals("Hand")) {
|
||||
this.setList(new ArrayList<Card>(activator.getCardsIn(ZoneType.Hand)));
|
||||
payment.setPaidManaPart(this);
|
||||
for(Card c : activator.getCardsIn(ZoneType.Hand))
|
||||
executePayment(ability, c);
|
||||
return true;
|
||||
} else {
|
||||
Integer num = this.convertAmount();
|
||||
|
||||
@@ -175,17 +259,13 @@ public class CostReveal extends CostPartWithList {
|
||||
num = AbilityUtils.calculateAmount(source, amount, ability);
|
||||
}
|
||||
}
|
||||
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);
|
||||
if ( num == 0 ) return true;
|
||||
|
||||
InputPayment inp = new InputPayReveal(this, this.getType(), handList, ability, num);
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.isPaid();
|
||||
}
|
||||
}
|
||||
this.addListToHash(ability, "Revealed");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -220,102 +300,24 @@ public class CostReveal extends CostPartWithList {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
addToList(targetCard);
|
||||
// write code to actually reveal card
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Revealed";
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@ package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
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 +39,70 @@ 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(CostSacrifice part, SpellAbility sa, int nNeeded, List<Card> typeList) {
|
||||
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.executePayment(sa, card);
|
||||
typeList.remove(card);
|
||||
// in case nothing else to sacrifice
|
||||
if (this.nSacrifices == nNeeded) {
|
||||
this.done();
|
||||
} else if (typeList.isEmpty()) {
|
||||
// happen
|
||||
this.cancel();
|
||||
} else {
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new cost sacrifice.
|
||||
*
|
||||
@@ -132,7 +194,7 @@ public class CostSacrifice extends CostPartWithList {
|
||||
public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) {
|
||||
this.addListToHash(ability, "Sacrificed");
|
||||
for (final Card c : this.getList()) {
|
||||
Singletons.getModel().getGame().getAction().sacrifice(c, ability);
|
||||
executePayment(ability, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,8 +206,9 @@ 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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
final String type = this.getType();
|
||||
final Player activator = ability.getActivatingPlayer();
|
||||
List<Card> list = new ArrayList<Card>(activator.getCardsIn(ZoneType.Battlefield));
|
||||
@@ -155,32 +218,36 @@ public class CostSacrifice extends CostPartWithList {
|
||||
}
|
||||
|
||||
if (this.payCostFromSource()) {
|
||||
final Input inp = CostSacrifice.sacrificeThis(ability, payment, this);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
if (source.getController() == ability.getActivatingPlayer() && source.isInPlay()) {
|
||||
if (!GuiDialog.confirm(source, source.getName() + " - Sacrifice?"))
|
||||
return false;
|
||||
executePayment(ability, source);
|
||||
return true;
|
||||
}
|
||||
} else if (amount.equals("All")) {
|
||||
this.setList(list);
|
||||
CostSacrifice.sacrificeAll(ability, payment, this, list);
|
||||
//this.addListToHash(ability, "Sacrificed");
|
||||
// TODO Ask First
|
||||
for (final Card card : list) {
|
||||
executePayment(ability, card);
|
||||
}
|
||||
return true;
|
||||
} 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;
|
||||
}
|
||||
final Input inp = CostSacrifice.sacrificeFromList(ability, payment, this, list, c);
|
||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(inp);
|
||||
InputPayment inp = new InputPayCostSacrificeFromList(this, ability, c, list);
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.isPaid();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -222,156 +289,23 @@ public class CostSacrifice extends CostPartWithList {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
this.addToList(targetCard);
|
||||
ability.getActivatingPlayer().getGame().getAction().sacrifice(targetCard, ability);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Sacrificed";
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
@@ -93,13 +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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
// if (!canPay(ability, source, ability.getActivatingPlayer(),
|
||||
// payment.getCost()))
|
||||
// return false;
|
||||
|
||||
source.tap();
|
||||
payment.setPaidManaPart(this);
|
||||
ability.getSourceCard().tap();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,21 +19,20 @@ package forge.card.cost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
@@ -41,6 +40,66 @@ import forge.view.ButtonUtil;
|
||||
*/
|
||||
public class CostTapType extends CostPartWithList {
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public static final class InputPayCostTapType extends InputPayCostBase {
|
||||
private final CostTapType tapType;
|
||||
private final int nCards;
|
||||
private final List<Card> cardList;
|
||||
private static final long serialVersionUID = 6438988130447851042L;
|
||||
private int nTapped = 0;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param sa
|
||||
* @param tapType
|
||||
* @param nCards
|
||||
* @param cardList
|
||||
* @param payment
|
||||
*/
|
||||
public InputPayCostTapType(CostTapType tapType, int nCards, List<Card> cardList) {
|
||||
this.tapType = tapType;
|
||||
this.nCards = nCards;
|
||||
this.cardList = cardList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
|
||||
final int left = nCards - this.nTapped;
|
||||
showMessage("Select a " + tapType.getDescription() + " to tap (" + left + " left)");
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
if (nCards == 0) {
|
||||
this.done();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@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
|
||||
tapType.executePayment(null, card);
|
||||
cardList.remove(card);
|
||||
|
||||
this.nTapped++;
|
||||
|
||||
if (this.nTapped == nCards) {
|
||||
this.done();
|
||||
} else if (cardList.size() == 0) {
|
||||
// happen
|
||||
this.cancel();
|
||||
} else {
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new cost tap type.
|
||||
*
|
||||
@@ -149,11 +208,12 @@ 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 boolean payHuman(final SpellAbility ability, 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);
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
final String sVar = ability.getSVar(amount);
|
||||
@@ -164,10 +224,9 @@ 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;
|
||||
InputPayment inp = new InputPayCostTapType(this, c, typeList);
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.isPaid();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -205,83 +264,23 @@ public class CostTapType extends CostPartWithList {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
addToList(targetCard);
|
||||
targetCard.tap();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Tapped";
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
@@ -114,23 +114,16 @@ 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) {
|
||||
this.resetList();
|
||||
public final boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final Card source = ability.getSourceCard();
|
||||
Player activator = ability.getActivatingPlayer();
|
||||
Card cardToUnattach = findCardToUnattach(source, activator, ability);
|
||||
if (cardToUnattach != null && GuiDialog.confirm(source, String.format("Unattach %s?", cardToUnattach.toString()))) {
|
||||
Card equippingCard = cardToUnattach.getEquipping().get(0);
|
||||
cardToUnattach.unEquipCard(equippingCard);
|
||||
this.addToList(cardToUnattach);
|
||||
this.addListToHash(ability, "Unattached");
|
||||
payment.setPaidManaPart(this);
|
||||
executePayment(ability, cardToUnattach);
|
||||
return true;
|
||||
} else {
|
||||
payment.setCancel(true);
|
||||
payment.getRequirements().finishPaying();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Card findCardToUnattach(final Card source, Player activator, SpellAbility ability) {
|
||||
@@ -165,4 +158,18 @@ public class CostUnattach extends CostPartWithList {
|
||||
this.resetList();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
targetCard.unEquipCard(targetCard.getEquipping().get(0));
|
||||
this.addToList(targetCard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Unattached";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,13 +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 boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
// if (!canPay(ability, source, ability.getActivatingPlayer(),
|
||||
// payment.getCost()))
|
||||
// return false;
|
||||
|
||||
source.untap();
|
||||
payment.setPaidManaPart(this);
|
||||
ability.getSourceCard().untap();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,21 +18,20 @@
|
||||
package forge.card.cost;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
@@ -40,6 +39,71 @@ 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(int nCards, List<Card> cardList, CostUntapType untapType) {
|
||||
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;
|
||||
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,12 +226,13 @@ 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) {
|
||||
final boolean untap = payment.getCost().hasUntapCost();
|
||||
public final boolean payHuman(final SpellAbility ability, final GameState game) {
|
||||
final boolean canUntapSource = false; // payment.getCost().hasUntapCost(); - only Crackleburr uses this
|
||||
List<Card> typeList = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
|
||||
typeList = CardLists.getValidCards(typeList, this.getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
|
||||
typeList = CardLists.filter(typeList, Presets.TAPPED);
|
||||
if (untap) {
|
||||
final Card source = ability.getSourceCard();
|
||||
if (canUntapSource) {
|
||||
typeList.remove(source);
|
||||
}
|
||||
final String amount = this.getAmount();
|
||||
@@ -181,10 +246,9 @@ 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;
|
||||
InputPayment inp = new InputPayCostUntapY(c, typeList, this);
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.isPaid();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -225,86 +289,23 @@ public class CostUntapType extends CostPartWithList {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
|
||||
*/
|
||||
@Override
|
||||
public void executePayment(SpellAbility ability, Card targetCard) {
|
||||
addToList(targetCard);
|
||||
targetCard.untap();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.cost.CostPartWithList#getHashForList()
|
||||
*/
|
||||
@Override
|
||||
public String getHashForList() {
|
||||
return "Untapped";
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
29
src/main/java/forge/card/cost/InputPayCostBase.java
Normal file
29
src/main/java/forge/card/cost/InputPayCostBase.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package forge.card.cost;
|
||||
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.control.input.InputSyncronizedBase;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
abstract class InputPayCostBase extends InputSyncronizedBase implements InputPayment {
|
||||
private static final long serialVersionUID = -2967434867139585579L;
|
||||
boolean bPaid = false;
|
||||
|
||||
@Override
|
||||
final public void selectButtonCancel() {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
final protected void done() {
|
||||
bPaid = true;
|
||||
this.stop();
|
||||
}
|
||||
|
||||
final public void cancel() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
final public boolean isPaid() { return bPaid; }
|
||||
}
|
||||
@@ -44,6 +44,20 @@ public final class ManaCost implements Comparable<ManaCost> {
|
||||
public static final ManaCost NO_COST = new ManaCost(-1);
|
||||
public static final ManaCost ZERO = new ManaCost(0);
|
||||
public static final ManaCost ONE = new ManaCost(1);
|
||||
public static final ManaCost TWO = new ManaCost(2);
|
||||
public static final ManaCost THREE = new ManaCost(3);
|
||||
public static final ManaCost FOUR = new ManaCost(4);
|
||||
|
||||
public static ManaCost get(int cntColorless) {
|
||||
switch (cntColorless) {
|
||||
case 0: return ZERO;
|
||||
case 1: return ONE;
|
||||
case 2: return TWO;
|
||||
case 3: return THREE;
|
||||
case 4: return FOUR;
|
||||
}
|
||||
return cntColorless > 0 ? new ManaCost(cntColorless) : NO_COST;
|
||||
}
|
||||
|
||||
// pass mana cost parser here
|
||||
private ManaCost(int cmc) {
|
||||
|
||||
@@ -42,6 +42,8 @@ public class ManaCostBeingPaid {
|
||||
private final ArrayList<String> manaNeededToAvoidNegativeEffect = new ArrayList<String>();
|
||||
private final ArrayList<String> manaPaidToAvoidNegativeEffect = new ArrayList<String>();
|
||||
|
||||
private final ManaCost originalCost;
|
||||
|
||||
// manaCost can be like "0", "3", "G", "GW", "10", "3 GW", "10 GW"
|
||||
// or "split hybrid mana" like "2/G 2/G", "2/B 2/B 2/B"
|
||||
// "GW" can be paid with either G or W
|
||||
@@ -59,6 +61,7 @@ public class ManaCostBeingPaid {
|
||||
}
|
||||
|
||||
public ManaCostBeingPaid(ManaCost manaCost) {
|
||||
originalCost = manaCost;
|
||||
if ( null == manaCost )
|
||||
return;
|
||||
|
||||
@@ -645,4 +648,8 @@ public class ManaCostBeingPaid {
|
||||
public final ArrayList<String> getManaPaidToAvoidNegativeEffect() {
|
||||
return this.manaPaidToAvoidNegativeEffect;
|
||||
}
|
||||
|
||||
public ManaCost getStartingCost() {
|
||||
return originalCost;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,20 +94,43 @@ 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();
|
||||
if (this.select.isCanceled()) {
|
||||
rollbackAbility();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* finishedTargeting.
|
||||
* </p>
|
||||
*/
|
||||
public final void finishedTargeting() {
|
||||
if (this.select.isCanceled()) {
|
||||
// Payment
|
||||
if (!this.isFree) {
|
||||
this.payment.setRequirements(this);
|
||||
this.payment.changeCost();
|
||||
this.payment.payCost();
|
||||
}
|
||||
|
||||
if (this.payment.isCanceled()) {
|
||||
rollbackAbility();
|
||||
return;
|
||||
}
|
||||
|
||||
else if (this.isFree || this.payment.isAllPaid()) {
|
||||
if (this.skipStack) {
|
||||
AbilityUtils.resolve(this.ability, false);
|
||||
} else {
|
||||
|
||||
this.enusureAbilityHasDescription(this.ability);
|
||||
this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false);
|
||||
Singletons.getModel().getGame().getStack().addAndUnfreeze(this.ability);
|
||||
}
|
||||
|
||||
// Warning about this - resolution may come in another thread, and it would still need its targets
|
||||
this.select.clearTargets();
|
||||
Singletons.getModel().getGame().getAction().checkStateEffects();
|
||||
}
|
||||
}
|
||||
|
||||
private void rollbackAbility() {
|
||||
// cancel ability during target choosing
|
||||
final Card c = this.ability.getSourceCard();
|
||||
|
||||
@@ -161,89 +144,46 @@ public class SpellAbilityRequirements {
|
||||
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() {
|
||||
if (!this.isFree) {
|
||||
this.startPaying();
|
||||
} else {
|
||||
this.finishPaying();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <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();
|
||||
|
||||
// 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.select.clearTargets();
|
||||
}
|
||||
|
||||
this.ability.resetOnceResolved();
|
||||
this.payment.cancelPayment();
|
||||
Singletons.getModel().getGame().getStack().clearFrozen();
|
||||
}
|
||||
else if (this.isFree || this.payment.isAllPaid()) {
|
||||
if (this.skipStack) {
|
||||
AbilityUtils.resolve(this.ability, false);
|
||||
} else {
|
||||
this.addAbilityToStack();
|
||||
// Singletons.getModel().getGame().getStack().removeFromFrozenStack(this.ability);
|
||||
}
|
||||
|
||||
this.select.resetTargets();
|
||||
Singletons.getModel().getGame().getAction().checkStateEffects();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addAbilityToStack.
|
||||
* </p>
|
||||
*/
|
||||
public final void addAbilityToStack() {
|
||||
private void enusureAbilityHasDescription(SpellAbility ability) {
|
||||
if (!StringUtils.isBlank(ability.getStackDescription()))
|
||||
return;
|
||||
|
||||
// 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();
|
||||
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) {
|
||||
@@ -252,10 +192,6 @@ public class SpellAbilityRequirements {
|
||||
}
|
||||
}
|
||||
|
||||
this.ability.setStackDescription(sb.toString());
|
||||
}
|
||||
|
||||
this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false);
|
||||
Singletons.getModel().getGame().getStack().addAndUnfreeze(this.ability);
|
||||
ability.setStackDescription(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,16 @@ package forge.card.spellability;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSynchronized;
|
||||
import forge.control.input.InputSyncronizedBase;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
@@ -44,6 +45,174 @@ import forge.view.ButtonUtil;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TargetSelection {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
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 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(TargetSelection select, List<Card> choices, ArrayList<Object> alreadyTargeted, boolean targeted, Target tgt, SpellAbility sa, boolean mandatory) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private Target target = null;
|
||||
private SpellAbility ability = null;
|
||||
private Card card = null;
|
||||
@@ -98,6 +267,7 @@ public class TargetSelection {
|
||||
}
|
||||
|
||||
private boolean bCancel = false;
|
||||
private boolean bTargetingDone = false;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -130,20 +300,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 +335,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 +351,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 +377,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 +520,14 @@ public class TargetSelection {
|
||||
}
|
||||
|
||||
if (zone.contains(ZoneType.Battlefield) && zone.size() == 1) {
|
||||
Singletons.getModel().getMatch().getInput().setInput(this.inputTargetSpecific(choices, true, mandatory, objects));
|
||||
InputSynchronized inp = new InputSelectTargets(this, choices, objects, true, this.target, this.ability, mandatory);
|
||||
FThreads.setInputAndWait(inp);
|
||||
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 +618,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 +626,6 @@ public class TargetSelection {
|
||||
} else {
|
||||
this.setCancel(true);
|
||||
}
|
||||
|
||||
this.chooseTargets();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -675,7 +667,7 @@ public class TargetSelection {
|
||||
|
||||
if (madeChoice != null) {
|
||||
if (madeChoice.equals(doneDummy)) {
|
||||
this.setDoneTarget(true);
|
||||
bTargetingDone = true;
|
||||
} else {
|
||||
tgt.addTarget(map.get(madeChoice));
|
||||
}
|
||||
@@ -683,8 +675,6 @@ public class TargetSelection {
|
||||
select.setCancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
select.chooseTargets();
|
||||
}
|
||||
|
||||
// TODO The following three functions are Utility functions for
|
||||
|
||||
@@ -156,6 +156,7 @@ 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(); } });
|
||||
}
|
||||
|
||||
@@ -1,128 +1,23 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.match.CMatchUI;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Abstract Input class.
|
||||
* </p>
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class Input implements java.io.Serializable {
|
||||
/** Constant <code>serialVersionUID=-6539552513871194081L</code>. */
|
||||
private static final long serialVersionUID = -6539552513871194081L;
|
||||
public interface Input {
|
||||
|
||||
// showMessage() is always the first method called
|
||||
/**
|
||||
* <p>
|
||||
* showMessage.
|
||||
* </p>
|
||||
*/
|
||||
public void showMessage() {
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Blank Input");
|
||||
}
|
||||
void showMessage();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* selectCard.
|
||||
* </p>
|
||||
*
|
||||
* @param c
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public void selectCard(final Card c) {
|
||||
}
|
||||
void selectCard(Card c);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* selectPlayer.
|
||||
* </p>
|
||||
*
|
||||
* @param player
|
||||
* a {@link forge.game.player.Player} object.
|
||||
*/
|
||||
public void selectPlayer(final Player player) {
|
||||
}
|
||||
void selectPlayer(Player player);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* selectButtonOK.
|
||||
* </p>
|
||||
*/
|
||||
public void selectButtonOK() {
|
||||
}
|
||||
void selectButtonOK();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* selectButtonCancel.
|
||||
* </p>
|
||||
*/
|
||||
public void selectButtonCancel() {
|
||||
}
|
||||
|
||||
// helper methods, since they are used alot
|
||||
// to be used by anything in CardFactory like SetTargetInput
|
||||
// NOT TO BE USED by Input_Main or any of the "regular" Inputs objects that
|
||||
// are not set using AllZone.getInputControl().setInput(Input)
|
||||
/**
|
||||
* <p>
|
||||
* stop.
|
||||
* </p>
|
||||
*/
|
||||
public final void stop() {
|
||||
// clears a "temp" Input like Input_PayManaCost if there is one
|
||||
Singletons.getModel().getMatch().getInput().resetInput();
|
||||
|
||||
}
|
||||
|
||||
// exits the "current" Input and sets the next Input
|
||||
/**
|
||||
* <p>
|
||||
* stopSetNext.
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* a {@link forge.control.input.Input} object.
|
||||
*/
|
||||
public final void stopSetNext(final Input in) {
|
||||
this.stop();
|
||||
Singletons.getModel().getMatch().getInput().setInput(in);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public String toString() {
|
||||
return "blank";
|
||||
} // returns the Input name like "EmptyStack"
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to mark old descendants of Input
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
public /*abstract */void isClassUpdated() {
|
||||
} //;
|
||||
void selectButtonCancel();
|
||||
|
||||
}
|
||||
@@ -24,9 +24,9 @@ import com.google.common.collect.Iterables;
|
||||
import forge.Card;
|
||||
import forge.CardPredicates;
|
||||
import forge.Singletons;
|
||||
import forge.game.GameState;
|
||||
import forge.game.phase.CombatUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.framework.SDisplayUtil;
|
||||
@@ -42,10 +42,16 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InputAttack extends Input {
|
||||
public class InputAttack extends InputBase {
|
||||
/** Constant <code>serialVersionUID=7849903731842214245L</code>. */
|
||||
private static final long serialVersionUID = 7849903731842214245L;
|
||||
|
||||
private final GameState game;
|
||||
public InputAttack(GameState game0) {
|
||||
game = game0;
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void showMessage() {
|
||||
@@ -53,7 +59,7 @@ public class InputAttack extends Input {
|
||||
|
||||
ButtonUtil.enableOnlyOk();
|
||||
|
||||
final Object o = Singletons.getModel().getGame().getCombat().nextDefender();
|
||||
final Object o = game.getCombat().nextDefender();
|
||||
if (o == null) {
|
||||
return;
|
||||
}
|
||||
@@ -64,13 +70,13 @@ public class InputAttack extends Input {
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
|
||||
|
||||
if (Singletons.getModel().getGame().getCombat().getRemainingDefenders() == 0) {
|
||||
if (game.getCombat().getRemainingDefenders() == 0) {
|
||||
// Nothing left to attack, has to attack this defender
|
||||
List<Card> possibleAttackers = Singletons.getControl().getPlayer().getCardsIn(ZoneType.Battlefield);
|
||||
for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) {
|
||||
if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, Singletons.getModel().getGame().getCombat())
|
||||
if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, game.getCombat())
|
||||
&& !c.isAttacking()) {
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(c);
|
||||
game.getCombat().addAttacker(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,36 +85,36 @@ public class InputAttack extends Input {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void selectButtonOK() {
|
||||
if (!Singletons.getModel().getGame().getCombat().getAttackers().isEmpty()) {
|
||||
Singletons.getModel().getGame().getPhaseHandler().setCombat(true);
|
||||
if (!game.getCombat().getAttackers().isEmpty()) {
|
||||
game.getPhaseHandler().setCombat(true);
|
||||
}
|
||||
|
||||
if (Singletons.getModel().getGame().getCombat().getRemainingDefenders() != 0) {
|
||||
Singletons.getModel().getGame().getPhaseHandler().repeatPhase();
|
||||
if (game.getCombat().getRemainingDefenders() != 0) {
|
||||
game.getPhaseHandler().repeatPhase();
|
||||
}
|
||||
|
||||
Singletons.getModel().getGame().getPhaseHandler().setPlayersPriorityPermission(false);
|
||||
Singletons.getModel().getMatch().getInput().resetInput();
|
||||
game.getPhaseHandler().setPlayersPriorityPermission(false);
|
||||
Singletons.getModel().getMatch().getInput().updateObservers();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void selectCard(final Card card) {
|
||||
if (card.isAttacking() || card.getController().isComputer()) {
|
||||
if (card.isAttacking() || card.getController() != Singletons.getControl().getPlayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Player human = Singletons.getControl().getPlayer();
|
||||
Zone zone = Singletons.getModel().getGame().getZoneOf(card);
|
||||
Zone zone = game.getZoneOf(card);
|
||||
if (zone.is(ZoneType.Battlefield, human)
|
||||
&& CombatUtil.canAttack(card, Singletons.getModel().getGame().getCombat())) {
|
||||
&& CombatUtil.canAttack(card, game.getCombat())) {
|
||||
|
||||
// TODO add the propaganda code here and remove it in
|
||||
// Phase.nextPhase()
|
||||
// if (!CombatUtil.checkPropagandaEffects(card))
|
||||
// return;
|
||||
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(card);
|
||||
game.getCombat().addAttacker(card);
|
||||
|
||||
// just to make sure the attack symbol is marked
|
||||
human.getZone(ZoneType.Battlefield).updateObservers();
|
||||
@@ -118,25 +124,4 @@ public class InputAttack extends Input {
|
||||
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
|
||||
}
|
||||
} // selectCard()
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* unselectCard.
|
||||
* </p>
|
||||
*
|
||||
* @param card
|
||||
* a {@link forge.Card} object.
|
||||
* @param zone
|
||||
* a {@link forge.game.zone.PlayerZone} object.
|
||||
*/
|
||||
public void unselectCard(final Card card, final PlayerZone zone) {
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.Input#isClassUpdated()
|
||||
*/
|
||||
@Override
|
||||
public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
|
||||
67
src/main/java/forge/control/input/InputBase.java
Normal file
67
src/main/java/forge/control/input/InputBase.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.match.CMatchUI;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Abstract Input class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class InputBase implements java.io.Serializable, Input {
|
||||
/** Constant <code>serialVersionUID=-6539552513871194081L</code>. */
|
||||
private static final long serialVersionUID = -6539552513871194081L;
|
||||
|
||||
// showMessage() is always the first method called
|
||||
@Override
|
||||
public abstract void showMessage();
|
||||
|
||||
@Override
|
||||
public void selectCard(final Card c) { }
|
||||
@Override
|
||||
public void selectPlayer(final Player player) { }
|
||||
@Override
|
||||
public void selectButtonOK() { }
|
||||
@Override
|
||||
public void selectButtonCancel() { }
|
||||
|
||||
// to remove need for CMatchUI dependence
|
||||
protected void showMessage(String message) {
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(message);
|
||||
}
|
||||
|
||||
// Removes this input from the stack and releases any latches (in synchronous imports)
|
||||
protected final void stop() {
|
||||
// clears a "temp" Input like Input_PayManaCost if there is one
|
||||
Singletons.getModel().getMatch().getInput().removeInput(this);
|
||||
afterStop(); // sync inputs will release their latch there
|
||||
}
|
||||
|
||||
protected final boolean isActive() {
|
||||
return Singletons.getModel().getMatch().getInput().getInput() == this;
|
||||
}
|
||||
|
||||
protected void afterStop() { }
|
||||
}
|
||||
@@ -42,7 +42,7 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InputBlock extends Input {
|
||||
public class InputBlock extends InputBase {
|
||||
/** Constant <code>serialVersionUID=6120743598368928128L</code>. */
|
||||
private static final long serialVersionUID = 6120743598368928128L;
|
||||
|
||||
@@ -144,11 +144,4 @@ public class InputBlock extends Input {
|
||||
|
||||
this.showMessage();
|
||||
} // selectCard()
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.Input#isClassUpdated()
|
||||
*/
|
||||
@Override
|
||||
public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InputCleanup extends Input {
|
||||
public class InputCleanup extends InputBase {
|
||||
/** Constant <code>serialVersionUID=-4164275418971547948L</code>. */
|
||||
private static final long serialVersionUID = -4164275418971547948L;
|
||||
private final GameState game;
|
||||
@@ -82,18 +82,4 @@ public class InputCleanup extends Input {
|
||||
}
|
||||
}
|
||||
} // selectCard()
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* AI_CleanupDiscard.
|
||||
* </p>
|
||||
*/
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.Input#isClassUpdated()
|
||||
*/
|
||||
@Override
|
||||
public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.zone.MagicStack;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
import forge.util.MyObservable;
|
||||
|
||||
/**
|
||||
@@ -40,21 +39,7 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
/** Constant <code>serialVersionUID=3955194449319994301L</code>. */
|
||||
private static final long serialVersionUID = 3955194449319994301L;
|
||||
|
||||
private Input input;
|
||||
|
||||
private final Stack<Input> inputStack = new Stack<Input>();
|
||||
private final Stack<Input> urgentInputStack = new Stack<Input>();
|
||||
|
||||
private final transient GameState game;
|
||||
/**
|
||||
* TODO Write javadoc for Constructor.
|
||||
*
|
||||
* @param fModel
|
||||
* the f model
|
||||
*/
|
||||
public InputControl(final GameState game0) {
|
||||
this.game = game0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -62,46 +47,12 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* a {@link forge.control.input.Input} object.
|
||||
* a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public final void setInput(final Input in) {
|
||||
boolean isInputEmpty = this.input == null || this.input instanceof InputPassPriority;
|
||||
//System.out.println(in.getClass().getName());
|
||||
if (!this.game.getStack().isResolving() && isInputEmpty) {
|
||||
this.input = in;
|
||||
} else {
|
||||
this.inputStack.add(in);
|
||||
}
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>input</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* a {@link forge.control.input.Input} object.
|
||||
* @param bAddToResolving
|
||||
* a boolean.
|
||||
*/
|
||||
public final void setInputInterrupt(final Input in) {
|
||||
// Make this
|
||||
final Input old = this.input;
|
||||
this.urgentInputStack.add(old);
|
||||
this.changeInput(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* changeInput.
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* a {@link forge.control.input.Input} object.
|
||||
*/
|
||||
private void changeInput(final Input in) {
|
||||
this.input = in;
|
||||
this.inputStack.push(in);
|
||||
// System.out.print("Current: " + input + "; Stack = " + inputStack);
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
@@ -110,10 +61,10 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
* Getter for the field <code>input</code>.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public final Input getInput() {
|
||||
return this.input;
|
||||
return inputStack.isEmpty() ? null : this.inputStack.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,8 +73,8 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
* </p>
|
||||
*/
|
||||
public final void clearInput() {
|
||||
this.input = null;
|
||||
this.inputStack.clear();
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
|
||||
@@ -135,19 +86,34 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
* @param update
|
||||
* a boolean.
|
||||
*/
|
||||
public final void resetInput() {
|
||||
this.input = null;
|
||||
public final void removeInput(Input inp) {
|
||||
Input topMostInput = inputStack.isEmpty() ? null : inputStack.pop();
|
||||
|
||||
// StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
// System.out.printf("%s > Remove input %s -- called from %s%n", FThreads.isEDT() ? "EDT" : "TRD", topMostInput, trace[2].toString());
|
||||
// if( trace[2].toString().contains("InputBase.stop"))
|
||||
// for(StackTraceElement se : trace) {
|
||||
// System.out.println(se.toString());
|
||||
// }
|
||||
|
||||
if( topMostInput != inp )
|
||||
throw new RuntimeException("Inputs adding/removal into stack is imbalanced! Check your code again!");
|
||||
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
public final boolean isEmpty() {
|
||||
return inputStack.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* updateInput.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public final Input getActualInput() {
|
||||
public final Input getActualInput(GameState game) {
|
||||
if ( !game.hasMulliganned() )
|
||||
return new InputMulligan();
|
||||
|
||||
@@ -157,36 +123,11 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
final Player priority = handler.getPriorityPlayer();
|
||||
final MagicStack stack = game.getStack();
|
||||
|
||||
|
||||
// TODO this resolving portion needs more work, but fixes Death Cloud
|
||||
// issues
|
||||
if (this.urgentInputStack.size() > 0) {
|
||||
if (this.input != null) {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
// if an SA is resolving, only change input for something that is
|
||||
// part of the resolving SA
|
||||
this.changeInput(this.urgentInputStack.pop());
|
||||
return this.input;
|
||||
}
|
||||
|
||||
if (stack.isResolving()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.input != null) {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
if (!this.inputStack.isEmpty()) { // incoming input to Control
|
||||
this.changeInput(this.inputStack.pop());
|
||||
return this.input;
|
||||
}
|
||||
|
||||
if (handler.hasPhaseEffects()) {
|
||||
// Handle begin phase stuff, then start back from the top
|
||||
handler.handleBeginPhase();
|
||||
return this.getActualInput();
|
||||
return this.inputStack.peek();
|
||||
}
|
||||
|
||||
// If the Phase we're in doesn't allow for Priority, return null to move
|
||||
@@ -205,7 +146,7 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
stack.freezeStack();
|
||||
if (playerTurn.isHuman() && !playerTurn.getController().mayAutoPass(phase)) {
|
||||
game.getCombat().initiatePossibleDefenders(playerTurn.getOpponents());
|
||||
return new InputAttack();
|
||||
return new InputAttack(game);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -236,7 +177,7 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
// priority
|
||||
|
||||
boolean prioritySkip = pc.mayAutoPass(phase) || pc.isUiSetToSkipPhase(playerTurn, phase);
|
||||
if (this.game.getStack().isEmpty() && prioritySkip) {
|
||||
if (game.getStack().isEmpty() && prioritySkip) {
|
||||
pc.passPriority();
|
||||
return null;
|
||||
} else
|
||||
@@ -245,19 +186,23 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
return pc.getDefaultInput();
|
||||
} // getInput()
|
||||
|
||||
public final void setNewInput(GameState game) {
|
||||
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());
|
||||
//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);
|
||||
} else if (!ph.isPlayerPriorityAllowed()) {
|
||||
// System.out.println("cannot have priority, forced to pass");
|
||||
ph.getPriorityPlayer().getController().passPriority();
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
private final static InputLockUI inputLock = new InputLockUI();
|
||||
public void lock() {
|
||||
setInput(inputLock);
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
if ( inputStack.isEmpty() || inputStack.peek() != inputLock )
|
||||
throw new RuntimeException("Trying to unlock input which is not locked! Do check when your threads terminate!");
|
||||
removeInput(inputLock);
|
||||
}
|
||||
|
||||
// only for debug purposes
|
||||
public String printInputStack() {
|
||||
return inputStack.toString();
|
||||
}
|
||||
|
||||
} // InputControl
|
||||
|
||||
@@ -1,18 +1,51 @@
|
||||
package forge.control.input;
|
||||
|
||||
import forge.gui.match.CMatchUI;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class InputLockUI extends Input {
|
||||
public class InputLockUI extends InputBase {
|
||||
private static final long serialVersionUID = 5777143577098597374L;
|
||||
|
||||
private final AtomicInteger iCall = new AtomicInteger();
|
||||
|
||||
public void showMessage() {
|
||||
ButtonUtil.disableAll();
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Waiting for actions...");
|
||||
int ixCall = 1 + iCall.getAndIncrement();
|
||||
FThreads.delay(500, new InputUpdater(ixCall));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lockUI";
|
||||
}
|
||||
|
||||
private class InputUpdater implements Runnable {
|
||||
final int ixCall;
|
||||
|
||||
public InputUpdater(final int idxCall) {
|
||||
ixCall = idxCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if ( ixCall != iCall.get() || !isActive()) // cancel the message if it's not from latest call or input is gone already
|
||||
return;
|
||||
FThreads.invokeInEDT(showMessageFromEdt);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable showMessageFromEdt = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ButtonUtil.disableAll();
|
||||
showMessage("Waiting for actions...");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InputMulligan extends Input {
|
||||
public class InputMulligan extends InputBase {
|
||||
/** Constant <code>serialVersionUID=-8112954303001155622L</code>. */
|
||||
private static final long serialVersionUID = -8112954303001155622L;
|
||||
|
||||
@@ -174,7 +174,6 @@ public class InputMulligan extends Input {
|
||||
|
||||
game.setMulliganned(true);
|
||||
Singletons.getModel().getMatch().getInput().clearInput();
|
||||
Singletons.getModel().getMatch().getInput().resetInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -192,8 +191,4 @@ public class InputMulligan extends Input {
|
||||
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.FControl;
|
||||
import forge.game.GameState;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.GuiDisplayUtil;
|
||||
@@ -38,7 +38,7 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InputPassPriority extends Input {
|
||||
public class InputPassPriority extends InputBase {
|
||||
/** Constant <code>serialVersionUID=-581477682214137181L</code>. */
|
||||
private static final long serialVersionUID = -581477682214137181L;
|
||||
|
||||
@@ -80,17 +80,20 @@ public class InputPassPriority extends Input {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void selectCard(final Card card) {
|
||||
Player player = Singletons.getControl().getPlayer();
|
||||
GameState game = Singletons.getModel().getGame();
|
||||
SpellAbility ab = player.getController().getAbilityToPlay(game.getAbilitesOfCard(card, player));
|
||||
final Player player = Singletons.getControl().getPlayer();
|
||||
final SpellAbility ab = player.getController().getAbilityToPlay(player.getGame().getAbilitesOfCard(card, player));
|
||||
if ( null != ab) {
|
||||
Runnable execAbility = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.playSpellAbility(card, ab);
|
||||
}
|
||||
};
|
||||
|
||||
FThreads.invokeInNewThread(execAbility, true);
|
||||
}
|
||||
else {
|
||||
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
|
||||
}
|
||||
} // selectCard()
|
||||
|
||||
@Override public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Command;
|
||||
import forge.Singletons;
|
||||
import forge.card.cardfactory.CardFactoryUtil;
|
||||
import forge.card.cost.CostDiscard;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
//if cost is paid, Command.execute() is called
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Input_PayManaCost_Ability class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: InputPayManaCostAbility.java 15673 2012-05-23 14:01:35Z ArsenalNut $
|
||||
*/
|
||||
public class InputPayDiscardCost extends Input {
|
||||
/**
|
||||
* Constant <code>serialVersionUID=2685832214529141991L</code>.
|
||||
*/
|
||||
private static final long serialVersionUID = 5634078561074764401L;
|
||||
|
||||
private int numChosen = 0;
|
||||
private int numRequired = 0;
|
||||
private List<Card> choiceList;
|
||||
private CostDiscard discardCost;
|
||||
private SpellAbility ability;
|
||||
private Command paid;
|
||||
private Command unpaid;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Input_PayManaCost_Ability.
|
||||
* </p>
|
||||
*
|
||||
* @param cost
|
||||
* a {@link forge.card.cost.CostSacrifice} object.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param paidCommand
|
||||
* a {@link forge.Command} object.
|
||||
* @param unpaidCommand
|
||||
* a {@link forge.Command} object.
|
||||
*/
|
||||
public InputPayDiscardCost(final CostDiscard cost, final SpellAbility sa, final Command paidCommand,
|
||||
final Command unpaidCommand) {
|
||||
final Card source = sa.getSourceCard();
|
||||
final Player human = Singletons.getControl().getPlayer();
|
||||
|
||||
this.ability = sa;
|
||||
this.discardCost = cost;
|
||||
this.choiceList = CardLists.getValidCards(human.getCardsIn(ZoneType.Hand), cost.getType().split(";"), human, source);
|
||||
String amountString = cost.getAmount();
|
||||
this.numRequired = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString)
|
||||
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
this.paid = paidCommand;
|
||||
this.unpaid = unpaidCommand;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void showMessage() {
|
||||
final StringBuilder msg = new StringBuilder("Discard ");
|
||||
final int nLeft = this.numRequired - this.numChosen;
|
||||
msg.append(nLeft).append(" ");
|
||||
msg.append(this.discardCost.getDescriptiveType());
|
||||
if (nLeft > 1) {
|
||||
msg.append("s");
|
||||
}
|
||||
if (!this.discardCost.getList().isEmpty()) {
|
||||
msg.append("\r\nSelected:\r\n");
|
||||
for (Card selected : this.discardCost.getList()) {
|
||||
msg.append(selected + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
if (nLeft > 0) {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
}
|
||||
else {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
this.done();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
if (this.choiceList.contains(card) && this.numChosen < numRequired) {
|
||||
this.numChosen++;
|
||||
this.discardCost.addToList(card);
|
||||
card.setUsedToPay(true);
|
||||
this.choiceList.remove(card);
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* unselectCard.
|
||||
* </p>
|
||||
*
|
||||
* @param card
|
||||
* a {@link forge.Card} object.
|
||||
* @param zone
|
||||
* a {@link forge.game.zone.PlayerZone} object.
|
||||
*/
|
||||
public void unselectCard(final Card card, final PlayerZone zone) {
|
||||
if (this.discardCost.getList().contains(card)) {
|
||||
this.numChosen--;
|
||||
card.setUsedToPay(false);
|
||||
this.discardCost.getList().remove(card);
|
||||
this.choiceList.add(card);
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executes paid commmand.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void done() {
|
||||
this.stop();
|
||||
for (Card selected : this.discardCost.getList()) {
|
||||
selected.setUsedToPay(false);
|
||||
Singletons.getControl().getPlayer().discard(selected, this.ability);
|
||||
}
|
||||
this.discardCost.addListToHash(ability, "Discarded");
|
||||
this.paid.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executes unpaid commmand.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void cancel() {
|
||||
this.stop();
|
||||
for (Card selected : this.discardCost.getList()) {
|
||||
selected.setUsedToPay(false);
|
||||
}
|
||||
this.unpaid.execute();
|
||||
}
|
||||
|
||||
@Override public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
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,13 +16,16 @@ 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.
|
||||
*
|
||||
*/
|
||||
public abstract class InputPayManaBase extends Input {
|
||||
public abstract class InputPayManaBase extends InputSyncronizedBase implements InputPayment {
|
||||
|
||||
private static final long serialVersionUID = -9133423708688480255L;
|
||||
|
||||
@@ -33,19 +34,30 @@ 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) {
|
||||
boolean bPaid = false;
|
||||
|
||||
protected InputPayManaBase(final GameState game, SpellAbility saToPayFor) {
|
||||
this.game = game;
|
||||
this.whoPays = Singletons.getControl().getPlayer();
|
||||
this.whoPays = saToPayFor.getActivatingPlayer();
|
||||
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 +115,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
|
||||
@@ -112,7 +124,10 @@ public abstract class InputPayManaBase extends Input {
|
||||
manaStr = CardUtil.getShortColor(color);
|
||||
}
|
||||
|
||||
return mp.payManaFromPool(saBeingPaidFor, manaCost, manaStr);
|
||||
this.manaCost = mp.payManaFromPool(saPaidFor, manaCost, manaStr);
|
||||
|
||||
onManaAbilityPlayed(null);
|
||||
showMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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()) {
|
||||
@@ -264,15 +279,7 @@ public abstract class InputPayManaBase extends Input {
|
||||
}
|
||||
}
|
||||
|
||||
SpellAbility chosen = abilities.get(0);
|
||||
if ((1 < abilities.size()) && choice) {
|
||||
final Map<String, SpellAbility> ability = new HashMap<String, SpellAbility>();
|
||||
for (final SpellAbility am : abilities) {
|
||||
ability.put(am.toString(), am);
|
||||
}
|
||||
chosen = GuiChoose.one("Choose mana ability", abilities);
|
||||
}
|
||||
|
||||
final SpellAbility chosen = abilities.size() > 1 && choice ? GuiChoose.one("Choose mana ability", abilities) : abilities.get(0);
|
||||
SpellAbility subchosen = chosen;
|
||||
while(subchosen.getManaPart() == null)
|
||||
{
|
||||
@@ -282,14 +289,53 @@ public abstract class InputPayManaBase extends Input {
|
||||
// save off color needed for use by any mana and reflected mana
|
||||
subchosen.getManaPart().setExpressChoice(colorsNeeded);
|
||||
|
||||
Player p = chosen.getActivatingPlayer();
|
||||
Singletons.getModel().getGame().getActionPlay().playSpellAbility(chosen, p);
|
||||
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getSourceCard() + " to pay mana");
|
||||
Runnable proc = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Player p = chosen.getActivatingPlayer();
|
||||
p.getGame().getActionPlay().playSpellAbility(chosen, p);
|
||||
onManaAbilityPlayed(chosen);
|
||||
}
|
||||
};
|
||||
FThreads.invokeInNewThread(proc, true);
|
||||
// EDT that removes lockUI from input stack will call our showMessage() method
|
||||
}
|
||||
|
||||
manaCost = p.getManaPool().payManaFromAbility(sa, manaCost, chosen);
|
||||
public void onManaAbilityPlayed(final SpellAbility saPaymentSrc) {
|
||||
if ( saPaymentSrc != null) // null comes when they've paid from pool
|
||||
this.manaCost = whoPays.getManaPool().payManaFromAbility(saPaidFor, manaCost, saPaymentSrc);
|
||||
|
||||
//AllZone.getHumanPlayer().getZone(ZoneType.Battlefield).updateObservers();
|
||||
// DO NOT REMOVE THIS, otherwise the cards don't always tap (copied)
|
||||
return manaCost;
|
||||
onManaAbilityPaid();
|
||||
if ( saPaymentSrc != null )
|
||||
whoPays.getZone(ZoneType.Battlefield).updateObservers();
|
||||
}
|
||||
|
||||
protected final void checkIfAlredyPaid() {
|
||||
if (manaCost.isPaid()) {
|
||||
bPaid = true;
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onManaAbilityPaid() {} // some inputs overload it
|
||||
protected abstract void done();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PayManaBase %s (out of %s)", manaCost.toString(), manaCost.getStartingCost() );
|
||||
}
|
||||
|
||||
protected void handleConvokedCards(boolean isCancelled) {
|
||||
if (saPaidFor.getTappedForConvoke() != null) {
|
||||
for (final Card c : saPaidFor.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
if (!isCancelled)
|
||||
c.tap(); // that will tap cards with all the triggers, it's no good to call this from EDT
|
||||
}
|
||||
saPaidFor.clearTappedForConvoke();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPaid() { return bPaid; }
|
||||
}
|
||||
|
||||
@@ -17,17 +17,12 @@
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Command;
|
||||
import forge.Singletons;
|
||||
import forge.card.mana.ManaCost;
|
||||
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
|
||||
@@ -40,19 +35,17 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InputPayManaExecuteCommands extends InputPayManaBase {
|
||||
public class InputPayManaExecuteCommands extends InputPayManaBase implements InputPayment {
|
||||
/**
|
||||
* Constant <code>serialVersionUID=3836655722696348713L</code>.
|
||||
*/
|
||||
private static final long serialVersionUID = 3836655722696348713L;
|
||||
|
||||
private String originalManaCost;
|
||||
private ManaCost originalManaCost;
|
||||
private String message = "";
|
||||
private SpellAbility fakeAbility;
|
||||
|
||||
|
||||
private Command paidCommand;
|
||||
private Command unpaidCommand;
|
||||
private boolean bPaid = false;
|
||||
public boolean isPaid() { return bPaid; }
|
||||
|
||||
// only used for X costs:
|
||||
private boolean showOnlyOKButton = false;
|
||||
@@ -72,8 +65,8 @@ public class InputPayManaExecuteCommands extends InputPayManaBase {
|
||||
* @param unpaidCommand2
|
||||
* a {@link forge.Command} object.
|
||||
*/
|
||||
public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final Command paidCommand2, final Command unpaidCommand2) {
|
||||
this(game, prompt, manaCost2, paidCommand2, unpaidCommand2, false);
|
||||
public InputPayManaExecuteCommands(final GameState game, final String prompt, final ManaCost manaCost2) {
|
||||
this(game, prompt, manaCost2, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,25 +85,19 @@ public class InputPayManaExecuteCommands extends InputPayManaBase {
|
||||
* @param showOKButton
|
||||
* a boolean.
|
||||
*/
|
||||
public InputPayManaExecuteCommands(final GameState game, final String prompt, final String manaCost2, final Command paid, final Command unpaid, final boolean showOKButton) {
|
||||
super(game);
|
||||
this.fakeAbility = new SpellAbility(null) {
|
||||
public InputPayManaExecuteCommands(final GameState game, final String prompt, final ManaCost manaCost2, final boolean showOKButton) {
|
||||
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;
|
||||
|
||||
this.manaCost = new ManaCostBeingPaid(this.originalManaCost);
|
||||
this.paidCommand = paid;
|
||||
this.unpaidCommand = unpaid;
|
||||
this.showOnlyOKButton = showOKButton;
|
||||
}
|
||||
|
||||
@@ -138,39 +125,24 @@ 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);
|
||||
bPaid = true;
|
||||
this.stop();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
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);
|
||||
bPaid = false;
|
||||
this.stop();
|
||||
}
|
||||
|
||||
@@ -178,8 +150,8 @@ public class InputPayManaExecuteCommands extends InputPayManaBase {
|
||||
@Override
|
||||
public final void selectButtonOK() {
|
||||
if (this.showOnlyOKButton) {
|
||||
bPaid = false;
|
||||
this.stop();
|
||||
this.unpaidCommand.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,24 +173,7 @@ public class InputPayManaExecuteCommands extends InputPayManaBase {
|
||||
msg.append("\n(Click on your life total to pay life for phyrexian mana.)");
|
||||
}
|
||||
|
||||
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();
|
||||
showMessage(msg.toString());
|
||||
checkIfAlredyPaid();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void isClassUpdated() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,62 +3,23 @@ package forge.control.input;
|
||||
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.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
public class InputPayManaOfCostPayment extends InputPayManaBase {
|
||||
|
||||
private final CostPartMana costMana;
|
||||
|
||||
// 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;
|
||||
|
||||
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, int toAdd) {
|
||||
super(game, spellAbility);
|
||||
manaCost = new ManaCostBeingPaid(costMana.getManaToPay());
|
||||
manaCost.increaseColorlessMana(toAdd);
|
||||
|
||||
this.costMana = costMana;
|
||||
originalManaCost = costMana.getMana();
|
||||
sa = spellAbility;
|
||||
manaToAdd = toAdd;
|
||||
this.payment = payment;
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 3467312982164195091L;
|
||||
|
||||
|
||||
|
||||
private int phyLifeToLose = 0;
|
||||
|
||||
private void resetManaCost() {
|
||||
this.manaCost = new ManaCostBeingPaid(this.originalManaCost);
|
||||
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,65 +31,34 @@ 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);
|
||||
}
|
||||
source.setColorsPaid(this.manaCost.getColorsPaid());
|
||||
source.setSunburstValue(this.manaCost.getSunburst());
|
||||
this.resetManaCost();
|
||||
this.stop();
|
||||
|
||||
if (costMana.hasNoXManaCost() || (manaToAdd > 0)) {
|
||||
payment.paidCost(costMana);
|
||||
} else {
|
||||
source.setXManaCostPaid(0);
|
||||
final Input inp = new InputPayManaX(game, sa, payment, costMana);
|
||||
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 (sa.getTappedForConvoke() != null) {
|
||||
for (final Card c : sa.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
c.tap();
|
||||
}
|
||||
sa.clearTappedForConvoke();
|
||||
}
|
||||
// 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)
|
||||
|
||||
handleConvokedCards(false);
|
||||
stop();
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
this.stop();
|
||||
this.resetManaCost();
|
||||
payment.cancelCost();
|
||||
Singletons.getControl().getPlayer().getZone(ZoneType.Battlefield).updateObservers();
|
||||
handleConvokedCards(true);
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
final String displayMana = manaCost.toString().replace("X", "").trim();
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Pay Mana Cost: " + displayMana);
|
||||
|
||||
final StringBuilder msg = new StringBuilder("Pay Mana Cost: " + displayMana);
|
||||
if (this.phyLifeToLose > 0) {
|
||||
@@ -141,23 +71,7 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
|
||||
msg.append("\n(Click on your life total to pay life for phyrexian mana.)");
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
if (manaCost.isPaid()) {
|
||||
this.done();
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
showMessage(msg.toString());
|
||||
checkIfAlredyPaid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,11 @@
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
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.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
//pays the cost of a card played from the player's hand
|
||||
@@ -35,61 +33,21 @@ 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;
|
||||
|
||||
/**
|
||||
* <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);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,24 +60,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,59 +85,32 @@ 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);
|
||||
handleConvokedCards(false);
|
||||
}
|
||||
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
|
||||
// (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.spell.getTappedForConvoke() != null) {
|
||||
for (final Card c : this.spell.getTappedForConvoke()) {
|
||||
c.setTapped(false);
|
||||
c.tap();
|
||||
}
|
||||
this.spell.clearTappedForConvoke();
|
||||
}
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
/** {@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()) {
|
||||
c.setTapped(false);
|
||||
}
|
||||
this.spell.clearTappedForConvoke();
|
||||
}
|
||||
|
||||
handleConvokedCards(true);
|
||||
this.resetManaCost();
|
||||
|
||||
whoPays.getManaPool().refundManaPaid(this.spell, true);
|
||||
whoPays.getManaPool().refundManaPaid(this.saPaidFor, true);
|
||||
whoPays.getZone(ZoneType.Battlefield).updateObservers(); // DO
|
||||
|
||||
this.stop();
|
||||
@@ -216,32 +132,12 @@ public class InputPayManaSimple extends InputPayManaBase {
|
||||
msg.append("\n(Click on your life total to pay life for phyrexian mana.)");
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
// has its own variant of checkIfPaid
|
||||
showMessage(msg.toString());
|
||||
if (this.manaCost.isPaid() && !new ManaCostBeingPaid(this.originalManaCost).isPaid()) {
|
||||
this.originalCard.setSunburstValue(this.manaCost.getSunburst());
|
||||
this.done();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (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() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package forge.control.input;
|
||||
|
||||
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;
|
||||
|
||||
public class InputPayManaX extends InputPayManaBase {
|
||||
@@ -18,49 +14,60 @@ public class InputPayManaX extends InputPayManaBase {
|
||||
private final String strX;
|
||||
private String colorsPaid;
|
||||
private final CostPartMana costMana;
|
||||
private final CostPayment payment;
|
||||
private final SpellAbility sa;
|
||||
|
||||
|
||||
public InputPayManaX(final GameState game, final SpellAbility sa0, final CostPayment payment0, final CostPartMana costMana0)
|
||||
public InputPayManaX(final GameState game, final SpellAbility sa0, final CostPartMana costMana0)
|
||||
{
|
||||
super(game);
|
||||
sa = sa0;
|
||||
payment = payment0;
|
||||
super(game, sa0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.InputPayManaBase#isPaid()
|
||||
*/
|
||||
@Override
|
||||
public boolean isPaid() {
|
||||
//return !( xPaid == 0 && !costMana.canXbe0() || this.colorX.equals("") && !this.manaCost.toString().equals(strX) );
|
||||
// return !( xPaid == 0 && !costMana.canXbe0()) && !(this.colorX.equals("") && !this.manaCost.toString().equals(strX));
|
||||
return ( xPaid > 0 || costMana.canXbe0()) && (!this.colorX.equals("") || this.manaCost.toString().equals(strX));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage() {
|
||||
if ((xPaid == 0 && costMana.isxCantBe0()) || (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
|
||||
if (!isPaid()) {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
} else {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
|
||||
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()) {
|
||||
if (!costMana.canXbe0()) {
|
||||
msg.append(" X Can't be 0.");
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
showMessage(msg.toString());
|
||||
}
|
||||
|
||||
// selectCard
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
this.manaCost = activateManaAbility(sa, card,
|
||||
this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX));
|
||||
// don't allow here the cards that produce only wrong colors
|
||||
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,49 +75,30 @@ 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();
|
||||
}
|
||||
|
||||
@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++;
|
||||
useManaFromPool(color, this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX));
|
||||
}
|
||||
|
||||
if (Singletons.getModel().getMatch().getInput().getInput() == this) {
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.Input#isClassUpdated()
|
||||
*/
|
||||
@Override
|
||||
public void isClassUpdated() {
|
||||
protected void done() {
|
||||
final Card card = saPaidFor.getSourceCard();
|
||||
card.setXManaCostPaid(this.xPaid);
|
||||
card.setColorsPaid(this.colorsPaid);
|
||||
card.setSunburstValue(this.colorsPaid.length());
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Command;
|
||||
import forge.Singletons;
|
||||
import forge.card.cardfactory.CardFactoryUtil;
|
||||
import forge.card.cost.CostReturn;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
//if cost is paid, Command.execute() is called
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Input_PayManaCost_Ability class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: InputPayManaCostAbility.java 15673 2012-05-23 14:01:35Z ArsenalNut $
|
||||
*/
|
||||
public class InputPayReturnCost extends Input {
|
||||
/**
|
||||
* Constant <code>serialVersionUID=2685832214529141991L</code>.
|
||||
*/
|
||||
private static final long serialVersionUID = 8701146064257627671L;
|
||||
|
||||
private int numChosen = 0;
|
||||
private int numRequired = 0;
|
||||
private List<Card> choiceList;
|
||||
private CostReturn returnCost;
|
||||
private SpellAbility ability;
|
||||
private Command paid;
|
||||
private Command unpaid;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for InputPayReturnCost.
|
||||
* </p>
|
||||
*
|
||||
* @param cost
|
||||
* a {@link forge.card.cost.CostSacrifice} object.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param paidCommand
|
||||
* a {@link forge.Command} object.
|
||||
* @param unpaidCommand
|
||||
* a {@link forge.Command} object.
|
||||
*/
|
||||
public InputPayReturnCost(final CostReturn cost, final SpellAbility sa, final Command paidCommand,
|
||||
final Command unpaidCommand) {
|
||||
final Card source = sa.getSourceCard();
|
||||
|
||||
this.ability = sa;
|
||||
this.returnCost = cost;
|
||||
this.choiceList = CardLists.getValidCards(Singletons.getControl().getPlayer().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), Singletons.getControl().getPlayer(), source);
|
||||
String amountString = cost.getAmount();
|
||||
this.numRequired = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString)
|
||||
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
this.paid = paidCommand;
|
||||
this.unpaid = unpaidCommand;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void showMessage() {
|
||||
final StringBuilder msg = new StringBuilder("Return ");
|
||||
final int nLeft = this.numRequired - this.numChosen;
|
||||
msg.append(nLeft).append(" ");
|
||||
msg.append(this.returnCost.getDescriptiveType());
|
||||
if (nLeft > 1) {
|
||||
msg.append("s");
|
||||
}
|
||||
msg.append(" to your hand");
|
||||
if (!this.returnCost.getList().isEmpty()) {
|
||||
msg.append("\r\nSelected:\r\n");
|
||||
for (Card selected : this.returnCost.getList()) {
|
||||
msg.append(selected + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
if (nLeft > 0) {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
}
|
||||
else {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
this.done();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
if (this.choiceList.contains(card) && this.numChosen < numRequired) {
|
||||
this.numChosen++;
|
||||
this.returnCost.addToList(card);
|
||||
card.setUsedToPay(true);
|
||||
this.choiceList.remove(card);
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* unselectCard.
|
||||
* </p>
|
||||
*
|
||||
* @param card
|
||||
* a {@link forge.Card} object.
|
||||
* @param zone
|
||||
* a {@link forge.game.zone.PlayerZone} object.
|
||||
*/
|
||||
public void unselectCard(final Card card, final PlayerZone zone) {
|
||||
if (this.returnCost.getList().contains(card)) {
|
||||
this.numChosen--;
|
||||
card.setUsedToPay(false);
|
||||
this.returnCost.getList().remove(card);
|
||||
this.choiceList.add(card);
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executes paid commmand.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void done() {
|
||||
this.stop();
|
||||
// actually sacrifice the cards
|
||||
for (Card selected : this.returnCost.getList()) {
|
||||
selected.setUsedToPay(false);
|
||||
Singletons.getModel().getGame().getAction().moveTo(ZoneType.Hand, selected);
|
||||
}
|
||||
this.returnCost.addListToHash(ability, "Returned");
|
||||
this.paid.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executes unpaid commmand.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void cancel() {
|
||||
this.stop();
|
||||
for (Card selected : this.returnCost.getList()) {
|
||||
selected.setUsedToPay(false);
|
||||
}
|
||||
this.unpaid.execute();
|
||||
}
|
||||
|
||||
@Override public void isClassUpdated() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Command;
|
||||
import forge.Singletons;
|
||||
import forge.card.cardfactory.CardFactoryUtil;
|
||||
import forge.card.cost.CostSacrifice;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
//if cost is paid, Command.execute() is called
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Input_PayManaCost_Ability class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: InputPayManaCostAbility.java 15673 2012-05-23 14:01:35Z ArsenalNut $
|
||||
*/
|
||||
public class InputPaySacCost extends Input {
|
||||
/**
|
||||
* Constant <code>serialVersionUID=2685832214529141991L</code>.
|
||||
*/
|
||||
private static final long serialVersionUID = 2685832214529141991L;
|
||||
|
||||
private int numChosen = 0;
|
||||
private int numRequired = 0;
|
||||
private List<Card> choiceList;
|
||||
private CostSacrifice sacCost;
|
||||
private SpellAbility ability;
|
||||
private Command paid;
|
||||
private Command unpaid;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Input_PayManaCost_Ability.
|
||||
* </p>
|
||||
*
|
||||
* @param cost
|
||||
* a {@link forge.card.cost.CostSacrifice} object.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param paidCommand
|
||||
* a {@link forge.Command} object.
|
||||
* @param unpaidCommand
|
||||
* a {@link forge.Command} object.
|
||||
*/
|
||||
public InputPaySacCost(final CostSacrifice cost, final SpellAbility sa, final Command paidCommand,
|
||||
final Command unpaidCommand) {
|
||||
final Card source = sa.getSourceCard();
|
||||
|
||||
this.ability = sa;
|
||||
this.sacCost = cost;
|
||||
Player human = Singletons.getControl().getPlayer();
|
||||
this.choiceList = CardLists.getValidCards(human.getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), human, source);
|
||||
String amountString = cost.getAmount();
|
||||
this.numRequired = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString)
|
||||
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
this.paid = paidCommand;
|
||||
this.unpaid = unpaidCommand;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void showMessage() {
|
||||
final StringBuilder msg = new StringBuilder("Sacrifice ");
|
||||
final int nLeft = this.numRequired - this.numChosen;
|
||||
msg.append(nLeft).append(" ");
|
||||
msg.append(this.sacCost.getDescriptiveType());
|
||||
if (nLeft > 1) {
|
||||
msg.append("s");
|
||||
}
|
||||
if (!this.sacCost.getList().isEmpty()) {
|
||||
msg.append("\r\nSelected:\r\n");
|
||||
for (Card selected : this.sacCost.getList()) {
|
||||
msg.append(selected + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msg.toString());
|
||||
if (nLeft > 0) {
|
||||
ButtonUtil.enableOnlyCancel();
|
||||
}
|
||||
else {
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
this.done();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
if (this.choiceList.contains(card) && this.numChosen < numRequired) {
|
||||
this.numChosen++;
|
||||
this.sacCost.addToList(card);
|
||||
card.setUsedToPay(true);
|
||||
this.choiceList.remove(card);
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* unselectCard.
|
||||
* </p>
|
||||
*
|
||||
* @param card
|
||||
* a {@link forge.Card} object.
|
||||
* @param zone
|
||||
* a {@link forge.game.zone.PlayerZone} object.
|
||||
*/
|
||||
public void unselectCard(final Card card, final PlayerZone zone) {
|
||||
if (this.sacCost.getList().contains(card)) {
|
||||
this.numChosen--;
|
||||
card.setUsedToPay(false);
|
||||
this.sacCost.getList().remove(card);
|
||||
this.choiceList.add(card);
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executes paid commmand.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void done() {
|
||||
this.stop();
|
||||
// actually sacrifice the cards
|
||||
for (Card selected : this.sacCost.getList()) {
|
||||
selected.setUsedToPay(false);
|
||||
Singletons.getModel().getGame().getAction().sacrifice(selected, this.ability);
|
||||
}
|
||||
this.sacCost.addListToHash(ability, "Sacrificed");
|
||||
this.paid.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executes unpaid commmand.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void cancel() {
|
||||
this.stop();
|
||||
for (Card selected : this.sacCost.getList()) {
|
||||
selected.setUsedToPay(false);
|
||||
}
|
||||
this.unpaid.execute();
|
||||
}
|
||||
|
||||
@Override public void isClassUpdated() {
|
||||
}
|
||||
}
|
||||
5
src/main/java/forge/control/input/InputPayment.java
Normal file
5
src/main/java/forge/control/input/InputPayment.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package forge.control.input;
|
||||
|
||||
public interface InputPayment extends InputSynchronized {
|
||||
boolean isPaid();
|
||||
}
|
||||
37
src/main/java/forge/control/input/InputSelectCards.java
Normal file
37
src/main/java/forge/control/input/InputSelectCards.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
|
||||
public abstract class InputSelectCards extends InputSelectListBase<Card> {
|
||||
private static final long serialVersionUID = -6609493252672573139L;
|
||||
|
||||
protected InputSelectCards(int min, int max) {
|
||||
|
||||
super(min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void selectCard(final Card c) {
|
||||
selectEntity(c);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.InputSelectListBase#onSelectStateChanged(forge.GameEntity, boolean)
|
||||
*/
|
||||
@Override
|
||||
protected void onSelectStateChanged(Card c, boolean newState) {
|
||||
c.setUsedToPay(newState); // UI supports card highlighting though this abstraction-breaking mechanism
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.InputSyncronizedBase#afterStop()
|
||||
*/
|
||||
@Override
|
||||
protected void afterStop() {
|
||||
for(Card c : selected)
|
||||
c.setUsedToPay(false);
|
||||
super.afterStop(); // It's ultimatelly important to keep call to super class!
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
|
||||
public class InputSelectCardsFromList extends InputSelectCards {
|
||||
private static final long serialVersionUID = 6230360322294805986L;
|
||||
|
||||
private final List<Card> validChoices;
|
||||
|
||||
public InputSelectCardsFromList(int min, int max, List<Card> validCards) {
|
||||
super(min, max);
|
||||
this.validChoices = validCards;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final boolean isValidChoice(Card choice) {
|
||||
return validChoices.contains(choice);
|
||||
}
|
||||
|
||||
}
|
||||
12
src/main/java/forge/control/input/InputSelectList.java
Normal file
12
src/main/java/forge/control/input/InputSelectList.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public interface InputSelectList<T> extends InputSynchronized {
|
||||
boolean hasCancelled();
|
||||
List<T> getSelected();
|
||||
}
|
||||
@@ -7,22 +7,23 @@ import forge.GameEntity;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public abstract class InputSelectMany<T extends GameEntity> extends Input {
|
||||
public abstract class InputSelectListBase<T extends GameEntity> extends InputSyncronizedBase implements InputSelectList<T> {
|
||||
|
||||
private static final long serialVersionUID = -2305549394512889450L;
|
||||
|
||||
protected final List<T> selected = new ArrayList<T>();
|
||||
protected final List<T> selected;
|
||||
protected boolean bCancelled = false;
|
||||
protected final int min;
|
||||
protected final int max;
|
||||
public boolean allowUnselect = false;
|
||||
private boolean allowCancelWithNotEmptyList = false;
|
||||
|
||||
private String message = "Source-Card-Name - Select %d more card(s)";
|
||||
|
||||
protected InputSelectMany(int min, int max) {
|
||||
|
||||
|
||||
protected InputSelectListBase(int min, int max) {
|
||||
selected = new ArrayList<T>();
|
||||
if (min > max) {
|
||||
throw new IllegalArgumentException("Min must not be greater than Max");
|
||||
}
|
||||
@@ -35,7 +36,7 @@ public abstract class InputSelectMany<T extends GameEntity> extends Input {
|
||||
String msgToShow = getMessage();
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(msgToShow);
|
||||
|
||||
boolean canCancel = (min == 0 && selected.isEmpty()) || canCancelWithSomethingSelected();
|
||||
boolean canCancel = (min == 0 && selected.isEmpty()) || isCancelWithSelectedAllowed();
|
||||
boolean canOk = hasEnoughTargets();
|
||||
|
||||
if (canOk && canCancel) {
|
||||
@@ -65,20 +66,18 @@ public abstract class InputSelectMany<T extends GameEntity> extends Input {
|
||||
|
||||
@Override
|
||||
public final void selectButtonCancel() {
|
||||
// this.stop();
|
||||
Input next = onCancel(); // might add ability to stack from here
|
||||
// if ( next != null ) {
|
||||
// Singletons.getModel().getMatch().getInput().setInput(next);
|
||||
// }
|
||||
|
||||
if (null == next) {
|
||||
bCancelled = true;
|
||||
this.stop();
|
||||
} else {
|
||||
this.stopSetNext(next);
|
||||
}
|
||||
|
||||
// for a next use
|
||||
selected.clear();
|
||||
@Override
|
||||
public final boolean hasCancelled() {
|
||||
return bCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<T> getSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,24 +86,7 @@ public abstract class InputSelectMany<T extends GameEntity> extends Input {
|
||||
// if an ability is put on stack before this input is stopped;
|
||||
// if it does, uncomment the 5 lines below, use them as method body
|
||||
|
||||
// this.stop();
|
||||
Input next = onDone(); // might add ability to stack from here
|
||||
// if ( next != null ) {
|
||||
// Singletons.getModel().getMatch().getInput().setInput(next);
|
||||
// }
|
||||
|
||||
if (null == next) {
|
||||
this.stop();
|
||||
} else {
|
||||
this.stopSetNext(next);
|
||||
}
|
||||
|
||||
// for a next use
|
||||
selected.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isClassUpdated() {
|
||||
}
|
||||
|
||||
public void setMessage(String message0) {
|
||||
@@ -112,27 +94,41 @@ public abstract class InputSelectMany<T extends GameEntity> extends Input {
|
||||
}
|
||||
|
||||
// must define these
|
||||
protected abstract Input onDone();
|
||||
protected abstract boolean isValidChoice(T choice);
|
||||
|
||||
// might re-define later
|
||||
protected Input onCancel() { return null; }
|
||||
protected boolean canCancelWithSomethingSelected() { return false; }
|
||||
protected boolean hasEnoughTargets() { return selected.size() >= min; }
|
||||
protected boolean hasAllTargets() { return selected.size() >= max; }
|
||||
protected void onSelectStateChanged(T c, boolean newState) {} // Select card inputs may highlight selected cards with this method
|
||||
|
||||
protected void selectEntity(T c) {
|
||||
|
||||
if (selected.contains(c) || !isValidChoice(c)) {
|
||||
if (!isValidChoice(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( selected.contains(c) ) {
|
||||
if ( allowUnselect ) {
|
||||
this.selected.remove(c);
|
||||
onSelectStateChanged(c, false);
|
||||
}
|
||||
} else {
|
||||
this.selected.add(c);
|
||||
this.showMessage();
|
||||
onSelectStateChanged(c, true);
|
||||
}
|
||||
|
||||
if (hasAllTargets()) {
|
||||
selectButtonOK();
|
||||
} else {
|
||||
this.showMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public final boolean isUnselectAllowed() { return allowUnselect; }
|
||||
public final void setUnselectAllowed(boolean allow) { this.allowUnselect = allow; }
|
||||
|
||||
public final boolean isCancelWithSelectedAllowed() { return allowCancelWithNotEmptyList; }
|
||||
public final void setCancelWithSelectedAllowed(boolean allow) { this.allowCancelWithNotEmptyList = allow ; }
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package forge.control.input;
|
||||
|
||||
import forge.Card;
|
||||
|
||||
public abstract class InputSelectManyCards extends InputSelectMany<Card> {
|
||||
private static final long serialVersionUID = -6609493252672573139L;
|
||||
|
||||
protected InputSelectManyCards(int min, int max) {
|
||||
|
||||
super(min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void selectCard(final Card c) {
|
||||
selectEntity(c);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public class InputSelectManyPlayers extends InputSelectMany<Player> {
|
||||
private static final long serialVersionUID = -8209690791522735L;
|
||||
|
||||
protected final Function<List<Player>, Input> onComplete;
|
||||
private final Predicate<Player> allowedFilter;
|
||||
|
||||
public InputSelectManyPlayers(final Predicate<Player> allowedRule, int min, int max, final Function<List<Player>, Input> onDone) {
|
||||
|
||||
super(min, max);
|
||||
allowedFilter = allowedRule;
|
||||
onComplete = onDone;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final Player p) {
|
||||
selectEntity(p);
|
||||
}
|
||||
|
||||
protected boolean isValidChoice(Player choice) {
|
||||
if (allowedFilter != null && !allowedFilter.apply(choice)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Input onDone() {
|
||||
return onComplete.apply(selected);
|
||||
}
|
||||
}
|
||||
6
src/main/java/forge/control/input/InputSynchronized.java
Normal file
6
src/main/java/forge/control/input/InputSynchronized.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package forge.control.input;
|
||||
|
||||
public interface InputSynchronized extends Input {
|
||||
|
||||
public void awaitLatchRelease();
|
||||
}
|
||||
31
src/main/java/forge/control/input/InputSyncronizedBase.java
Normal file
31
src/main/java/forge/control/input/InputSyncronizedBase.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.error.BugReporter;
|
||||
|
||||
public abstract class InputSyncronizedBase extends InputBase implements InputSynchronized {
|
||||
private static final long serialVersionUID = 8756177361251703052L;
|
||||
|
||||
private final CountDownLatch cdlDone;
|
||||
|
||||
public InputSyncronizedBase() {
|
||||
cdlDone = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
public void awaitLatchRelease() {
|
||||
FThreads.checkEDT("InputSyncronizedBase.awaitLatchRelease", false);
|
||||
try{
|
||||
cdlDone.await();
|
||||
} catch (InterruptedException e) {
|
||||
BugReporter.reportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void afterStop() {
|
||||
cdlDone.countDown();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -486,24 +486,6 @@ public class GameAction {
|
||||
final String recoverCost = recoverable.getKeyword().get(recoverable.getKeywordPosition("Recover")).split(":")[1];
|
||||
final Cost cost = new Cost(recoverable, recoverCost, true);
|
||||
|
||||
final Command paidCommand = new Command() {
|
||||
private static final long serialVersionUID = -6357156873861051845L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
moveToHand(recoverable);
|
||||
}
|
||||
};
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = -7354791599039157375L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
exile(recoverable);
|
||||
}
|
||||
};
|
||||
|
||||
final SpellAbility abRecover = new AbilityActivated(recoverable, cost, null) {
|
||||
private static final long serialVersionUID = 8858061639236920054L;
|
||||
|
||||
@@ -535,8 +517,10 @@ public class GameAction {
|
||||
Player p = recoverable.getController();
|
||||
|
||||
if (p.isHuman()) {
|
||||
GameActionUtil.payCostDuringAbilityResolve(p, abRecover, abRecover.getPayCosts(),
|
||||
paidCommand, unpaidCommand, null, game);
|
||||
if ( GameActionUtil.payCostDuringAbilityResolve(p, abRecover, abRecover.getPayCosts(), null, game) )
|
||||
moveToHand(recoverable);
|
||||
else
|
||||
exile(recoverable);
|
||||
} else { // computer
|
||||
if (ComputerUtilCost.canPayCost(abRecover, p)) {
|
||||
ComputerUtil.playNoStack((AIPlayer)p, abRecover, game);
|
||||
|
||||
@@ -2,7 +2,6 @@ package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Card;
|
||||
@@ -10,6 +9,7 @@ import forge.CardCharacteristicName;
|
||||
import forge.CardColor;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.ApiType;
|
||||
@@ -23,7 +23,6 @@ import forge.card.spellability.SpellAbilityRequirements;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.control.input.InputControl;
|
||||
import forge.control.input.InputPayManaSimple;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.player.Player;
|
||||
@@ -37,17 +36,12 @@ import forge.gui.GuiChoose;
|
||||
public class GameActionPlay {
|
||||
|
||||
private final GameState game;
|
||||
private InputControl matchInput;
|
||||
|
||||
|
||||
public GameActionPlay(final GameState game0) {
|
||||
game = game0;
|
||||
}
|
||||
|
||||
void setMatchInput(InputControl input) {
|
||||
this.matchInput = input; // TODO: Add 0 to parameter's name.
|
||||
}
|
||||
|
||||
public final void playCardWithoutManaCost(final Card c, Player player) {
|
||||
final List<SpellAbility> choices = c.getBasicSpells();
|
||||
// TODO add Buyback, Kicker, ... , spells here
|
||||
@@ -71,6 +65,7 @@ public class GameActionPlay {
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public final void playSpellAbilityWithoutPayingManaCost(final SpellAbility sa) {
|
||||
FThreads.checkEDT("GameActionPlay.playSpellAbilityWithoutPayingManaCost", false);
|
||||
final Card source = sa.getSourceCard();
|
||||
setSplitCardState(source, sa); // Split card support
|
||||
|
||||
@@ -358,6 +353,7 @@ public class GameActionPlay {
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public final void playSpellAbility(SpellAbility sa, Player activator) {
|
||||
FThreads.checkEDT("Player.playSpellAbility", false);
|
||||
sa.setActivatingPlayer(activator);
|
||||
|
||||
final Card source = sa.getSourceCard();
|
||||
@@ -385,6 +381,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;
|
||||
@@ -403,14 +400,18 @@ public class GameActionPlay {
|
||||
} else {
|
||||
manaCost = this.getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost()));
|
||||
}
|
||||
|
||||
if (!manaCost.isPaid()) {
|
||||
FThreads.setInputAndWait(new InputPayManaSimple(game, sa, manaCost));
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,60 +447,19 @@ public class GameActionPlay {
|
||||
} else {
|
||||
manaCost = this.getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost()));
|
||||
}
|
||||
|
||||
if( !manaCost.isPaid() ) {
|
||||
FThreads.setInputAndWait(new InputPayManaSimple(game, sa, getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost()))));
|
||||
}
|
||||
|
||||
if (manaCost.isPaid()) {
|
||||
AbilityUtils.resolve(sa, false);
|
||||
return;
|
||||
} else {
|
||||
matchInput.setInput(new InputPayManaSimple(game, sa, true));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** The Cost cutting_ get multi kicker mana cost paid. */
|
||||
private int costCuttingGetMultiKickerManaCostPaid = 0;
|
||||
/** The Cost cutting_ get multi kicker mana cost paid_ colored. */
|
||||
private String costCuttingGetMultiKickerManaCostPaidColored = "";
|
||||
|
||||
/**
|
||||
* Gets the cost cutting get multi kicker mana cost paid.
|
||||
*
|
||||
* @return the costCuttingGetMultiKickerManaCostPaid
|
||||
*/
|
||||
public int getCostCuttingGetMultiKickerManaCostPaid() {
|
||||
return this.costCuttingGetMultiKickerManaCostPaid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost cutting get multi kicker mana cost paid.
|
||||
*
|
||||
* @param costCuttingGetMultiKickerManaCostPaid0
|
||||
* the costCuttingGetMultiKickerManaCostPaid to set
|
||||
*/
|
||||
public void setCostCuttingGetMultiKickerManaCostPaid(final int costCuttingGetMultiKickerManaCostPaid0) {
|
||||
this.costCuttingGetMultiKickerManaCostPaid = costCuttingGetMultiKickerManaCostPaid0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost cutting get multi kicker mana cost paid colored.
|
||||
*
|
||||
* @return the costCuttingGetMultiKickerManaCostPaidColored
|
||||
*/
|
||||
public String getCostCuttingGetMultiKickerManaCostPaidColored() {
|
||||
return this.costCuttingGetMultiKickerManaCostPaidColored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost cutting get multi kicker mana cost paid colored.
|
||||
*
|
||||
* @param costCuttingGetMultiKickerManaCostPaidColored0
|
||||
* the costCuttingGetMultiKickerManaCostPaidColored to set
|
||||
*/
|
||||
public void setCostCuttingGetMultiKickerManaCostPaidColored(
|
||||
final String costCuttingGetMultiKickerManaCostPaidColored0) {
|
||||
this.costCuttingGetMultiKickerManaCostPaidColored = costCuttingGetMultiKickerManaCostPaidColored0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the convokable colors.
|
||||
*
|
||||
|
||||
@@ -20,7 +20,6 @@ package forge.game;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -34,6 +33,7 @@ import forge.CardUtil;
|
||||
import forge.Command;
|
||||
import forge.Constant;
|
||||
import forge.CounterType;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityFactory;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
@@ -57,10 +57,10 @@ import forge.card.spellability.AbilityManaPart;
|
||||
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.InputPayManaExecuteCommands;
|
||||
import forge.control.input.InputPayReturnCost;
|
||||
import forge.control.input.InputPayment;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.control.input.InputSelectCardsFromList;
|
||||
import forge.game.event.CardDamagedEvent;
|
||||
import forge.game.event.LifeLossEvent;
|
||||
import forge.game.player.AIPlayer;
|
||||
@@ -367,29 +367,21 @@ public final class GameActionUtil {
|
||||
ripple.execute();
|
||||
}
|
||||
|
||||
private static int getAmountFromPart(CostPart part, Card source, SpellAbility sourceAbility) {
|
||||
String amountString = part.getAmount();
|
||||
return StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : AbilityUtils.calculateAmount(source, amountString, sourceAbility);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* payManaDuringAbilityResolve.
|
||||
* </p>
|
||||
*
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @param spellManaCost
|
||||
* a {@link java.lang.String} object.
|
||||
* @param paid
|
||||
* a {@link forge.Command} object.
|
||||
* @param unpaid
|
||||
* a {@link forge.Command} object.
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param part
|
||||
* @param source
|
||||
* @param sourceAbility
|
||||
* @return
|
||||
*/
|
||||
public static void payManaDuringAbilityResolve(final String message, final ManaCost spellManaCost, final Command paid,
|
||||
final Command unpaid) {
|
||||
// temporarily disable the Resolve flag, so the user can payMana for the
|
||||
// resolving Ability
|
||||
GameState game = Singletons.getModel().getGame();
|
||||
final boolean bResolving = game.getStack().isResolving();
|
||||
game.getStack().setResolving(false);
|
||||
Singletons.getModel().getMatch().getInput().setInput(new InputPayManaExecuteCommands(game, message, spellManaCost.toString(), paid, unpaid));
|
||||
game.getStack().setResolving(bResolving);
|
||||
private static int getAmountFromPartX(CostPart part, Card source, SpellAbility sourceAbility) {
|
||||
String amountString = part.getAmount();
|
||||
return StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,8 +399,7 @@ public final class GameActionUtil {
|
||||
* a {@link forge.Command} object.
|
||||
* @param sourceAbility TODO
|
||||
*/
|
||||
public static void payCostDuringAbilityResolve(final Player p, final SpellAbility ability, final Cost cost, final Command paid,
|
||||
final Command unpaid, SpellAbility sourceAbility, final GameState game) {
|
||||
public static boolean payCostDuringAbilityResolve(final Player p, final SpellAbility ability, final Cost cost, SpellAbility sourceAbility, final GameState game) {
|
||||
final Card source = ability.getSourceCard();
|
||||
final List<CostPart> parts = cost.getCostParts();
|
||||
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
|
||||
@@ -416,53 +407,40 @@ public final class GameActionUtil {
|
||||
if (!parts.isEmpty()) {
|
||||
costPart = parts.get(0);
|
||||
}
|
||||
String orString = "";
|
||||
if (sourceAbility != null) {
|
||||
orString = " (or: " + sourceAbility.getStackDescription() + ")";
|
||||
}
|
||||
final String orString = sourceAbility == null ? "" : " (or: " + sourceAbility.getStackDescription() + ")";
|
||||
|
||||
if (parts.isEmpty() || costPart.getAmount().equals("0")) {
|
||||
if (GuiDialog.confirm(source, "Do you want to pay 0?" + orString)) {
|
||||
paid.execute();
|
||||
} else {
|
||||
unpaid.execute();
|
||||
}
|
||||
return;
|
||||
return GuiDialog.confirm(source, "Do you want to pay 0?" + orString);
|
||||
}
|
||||
|
||||
boolean hasPaid = true;
|
||||
//the following costs do not need inputs
|
||||
for (CostPart part : parts) {
|
||||
if (part instanceof CostPayLife) {
|
||||
String amountString = part.getAmount();
|
||||
boolean dontRemove = false;
|
||||
|
||||
final int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString)
|
||||
: AbilityUtils.calculateAmount(source, amountString, sourceAbility);
|
||||
if (part instanceof CostPayLife) {
|
||||
final int amount = getAmountFromPart(part, source, sourceAbility);
|
||||
if (p.canPayLife(amount) && GuiDialog.confirm(source, "Do you want to pay " + amount + " life?" + orString)) {
|
||||
p.payLife(amount, null);
|
||||
} else {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
remainingParts.remove(part);
|
||||
}
|
||||
|
||||
else if (part instanceof CostDamage) {
|
||||
String amountString = part.getAmount();
|
||||
final int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString)
|
||||
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||
if (p.canPayLife(amount) && GuiDialog.confirm(source, "Do you want " + source + " to deal " + amount + " damage to you?")) {
|
||||
p.addDamage(amount, source);
|
||||
} else {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
remainingParts.remove(part);
|
||||
}
|
||||
|
||||
else if (part instanceof CostPutCounter) {
|
||||
String amountString = part.getAmount();
|
||||
CounterType counterType = ((CostPutCounter) part).getCounter();
|
||||
int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString)
|
||||
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||
String plural = amount > 1 ? "s" : "";
|
||||
if (GuiDialog.confirm(source, "Do you want to put " + amount + " " + counterType.getName()
|
||||
+ " counter" + plural + " on " + source + "?")) {
|
||||
@@ -470,7 +448,7 @@ public final class GameActionUtil {
|
||||
source.addCounter(counterType, amount, false);
|
||||
} else {
|
||||
hasPaid = false;
|
||||
Singletons.getModel().getGame().getGameLog().add("ResolveStack", "Trying to pay upkeep for " + source + " but it can't have "
|
||||
p.getGame().getGameLog().add("ResolveStack", "Trying to pay upkeep for " + source + " but it can't have "
|
||||
+ counterType.getName() + " counters put on it.", 2);
|
||||
break;
|
||||
}
|
||||
@@ -478,14 +456,11 @@ public final class GameActionUtil {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
remainingParts.remove(part);
|
||||
}
|
||||
|
||||
else if (part instanceof CostRemoveCounter) {
|
||||
String amountString = part.getAmount();
|
||||
CounterType counterType = ((CostRemoveCounter) part).getCounter();
|
||||
int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString)
|
||||
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
|
||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||
String plural = amount > 1 ? "s" : "";
|
||||
if (part.canPay(sourceAbility, source, p, cost, game)
|
||||
&& GuiDialog.confirm(source, "Do you want to remove " + amount + " " + counterType.getName()
|
||||
@@ -495,7 +470,6 @@ public final class GameActionUtil {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
remainingParts.remove(part);
|
||||
}
|
||||
|
||||
else if (part instanceof CostExile) {
|
||||
@@ -503,35 +477,32 @@ public final class GameActionUtil {
|
||||
if (GuiDialog.confirm(source, "Do you want to exile all cards in your graveyard?")) {
|
||||
List<Card> cards = new ArrayList<Card>(p.getCardsIn(ZoneType.Graveyard));
|
||||
for (final Card card : cards) {
|
||||
Singletons.getModel().getGame().getAction().exile(card);
|
||||
p.getGame().getAction().exile(card);
|
||||
}
|
||||
} else {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
remainingParts.remove(part);
|
||||
} else {
|
||||
CostExile costExile = (CostExile) part;
|
||||
ZoneType from = costExile.getFrom();
|
||||
List<Card> list = CardLists.getValidCards(p.getCardsIn(from), part.getType().split(";"), p, source);
|
||||
final int nNeeded = AbilityUtils.calculateAmount(source, part.getAmount(), ability);
|
||||
if (list.size() >= nNeeded) {
|
||||
if (list.size() < nNeeded) {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
|
||||
final Card c = GuiChoose.oneOrNone("Exile from " + from, list);
|
||||
|
||||
if (c != null) {
|
||||
list.remove(c);
|
||||
Singletons.getModel().getGame().getAction().exile(c);
|
||||
p.getGame().getAction().exile(c);
|
||||
} else {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,73 +521,84 @@ public final class GameActionUtil {
|
||||
GuiUtils.clearPanelSelections();
|
||||
GuiUtils.setPanelSelection(source);
|
||||
|
||||
if (!GuiDialog.confirm(source, "Do you want to pay the sacrifice cost?")) {
|
||||
List<Card> toSac = p.getController().choosePermanentsToSacrifice(list, amount, ability, false, true);
|
||||
if ( toSac.size() != amount ) {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
for(Card c : toSac) {
|
||||
p.getGame().getAction().sacrifice(c, ability);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (list.isEmpty()) {
|
||||
else if (part instanceof CostReturn) {
|
||||
List<Card> choiceList = CardLists.getValidCards(p.getCardsIn(ZoneType.Battlefield), part.getType().split(";"), p, source);
|
||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||
|
||||
InputSelectCards inp = new InputSelectCardsFromList(amount, amount, choiceList);
|
||||
inp.setMessage("Select %d card(s) to return to hand");
|
||||
inp.setCancelWithSelectedAllowed(true);
|
||||
|
||||
FThreads.setInputAndWait(inp);
|
||||
if( inp.hasCancelled() || inp.getSelected().size() != amount) {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
Object o = GuiChoose.one("Select a card to sacrifice", list);
|
||||
if (o != null) {
|
||||
final Card c = (Card) o;
|
||||
|
||||
Singletons.getModel().getGame().getAction().sacrifice(c, ability);
|
||||
|
||||
list.remove(c);
|
||||
((CostReturn)part).addListToHash(ability, "Returned");
|
||||
for(Card c : inp.getSelected()) {
|
||||
p.getGame().getAction().moveTo(ZoneType.Hand, c);
|
||||
}
|
||||
}
|
||||
|
||||
else if (part instanceof CostDiscard) {
|
||||
List<Card> choiceList = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), part.getType().split(";"), p, source);
|
||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||
|
||||
InputSelectCards inp = new InputSelectCardsFromList(amount, amount, choiceList);
|
||||
inp.setMessage("Select %d card(s) to discard");
|
||||
inp.setCancelWithSelectedAllowed(true);
|
||||
|
||||
FThreads.setInputAndWait(inp);
|
||||
if( inp.hasCancelled() || inp.getSelected().size() != amount) {
|
||||
hasPaid = false;
|
||||
break;
|
||||
}
|
||||
((CostDiscard)part).addListToHash(ability, "Discarded");
|
||||
for(Card c : inp.getSelected()) {
|
||||
p.discard(c, ability);
|
||||
}
|
||||
}
|
||||
|
||||
else if (part instanceof CostPartMana ) {
|
||||
if (!((CostPartMana) part).getManaToPay().equals("0")) // non-zero costs require input
|
||||
dontRemove = true;
|
||||
} else
|
||||
throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - An unhandled type of cost has ocurred: " + part.getClass());
|
||||
|
||||
|
||||
if ( !hasPaid )
|
||||
return false;
|
||||
|
||||
if( !dontRemove )
|
||||
remainingParts.remove(part);
|
||||
}
|
||||
|
||||
else if (part instanceof CostPartMana && ((CostPartMana) part).getManaToPay().equals("0")) {
|
||||
remainingParts.remove(part);
|
||||
}
|
||||
}
|
||||
|
||||
GuiUtils.clearPanelSelections();
|
||||
|
||||
if (!hasPaid) {
|
||||
unpaid.execute();
|
||||
return;
|
||||
}
|
||||
if (remainingParts.isEmpty()) {
|
||||
paid.execute();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (remainingParts.size() > 1) {
|
||||
throw new RuntimeException("GameActionUtil::payCostDuringAbilityResolve - Too many payment types - " + source);
|
||||
throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - Too many payment types - " + source);
|
||||
}
|
||||
costPart = remainingParts.get(0);
|
||||
// check this is a mana cost
|
||||
if (!(costPart instanceof CostPartMana ))
|
||||
throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - The remaining payment type is not Mana.");
|
||||
|
||||
//TODO: if a full-featured algorithm to chain together input-based costs is implemented
|
||||
// at some point in time, it's possible to restore the InputPaySacCost-based input
|
||||
// interface for sacrifice costs (instead of the menu-based one above).
|
||||
|
||||
//the following costs need inputs and can't be combined at the moment
|
||||
Input toSet = null;
|
||||
if (costPart instanceof CostReturn) {
|
||||
toSet = new InputPayReturnCost((CostReturn) costPart, ability, paid, unpaid);
|
||||
}
|
||||
else if (costPart instanceof CostDiscard) {
|
||||
toSet = new InputPayDiscardCost((CostDiscard) costPart, ability, paid, unpaid);
|
||||
}
|
||||
else if (costPart instanceof CostPartMana) {
|
||||
toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost().toString(), paid, unpaid);
|
||||
}
|
||||
|
||||
|
||||
if (toSet != null) {
|
||||
// temporarily disable the Resolve flag, so the user can payMana for the
|
||||
// resolving Ability
|
||||
final boolean bResolving = Singletons.getModel().getGame().getStack().isResolving();
|
||||
Singletons.getModel().getGame().getStack().setResolving(false);
|
||||
Singletons.getModel().getMatch().getInput().setInput(toSet);
|
||||
Singletons.getModel().getGame().getStack().setResolving(bResolving);
|
||||
}
|
||||
InputPayment toSet = new InputPayManaExecuteCommands(game, source + "\r\n", ability.getManaCost());
|
||||
FThreads.setInputAndWait(toSet);
|
||||
return toSet.isPaid();
|
||||
}
|
||||
|
||||
// not restricted to combat damage, not restricted to dealing damage to
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package forge.game;
|
||||
|
||||
import forge.error.BugReporter;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public final class GameInputUpdatesThread extends Thread {
|
||||
private final MatchController match;
|
||||
private final GameState game;
|
||||
private boolean wasChangedRecently;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param match
|
||||
* @param game
|
||||
*/
|
||||
public GameInputUpdatesThread(MatchController match, GameState game) {
|
||||
this.match = match;
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
public void run(){
|
||||
while(!game.isGameOver()) {
|
||||
boolean needsNewInput = CMessage.SINGLETON_INSTANCE.getInputControl().isValid() == false;
|
||||
if ( needsNewInput ) {
|
||||
match.getInput().setNewInput(game);
|
||||
wasChangedRecently = true;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(wasChangedRecently ? 2 : 40);
|
||||
wasChangedRecently = false;
|
||||
} catch (InterruptedException e) {
|
||||
BugReporter.reportException(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,7 @@ public class GameState {
|
||||
* Constructor.
|
||||
* @param players2
|
||||
* @param match0
|
||||
* @param input
|
||||
*/
|
||||
public GameState(Iterable<LobbyPlayer> players2, GameType t, MatchController match0) { /* no more zones to map here */
|
||||
type = t;
|
||||
|
||||
@@ -129,10 +129,8 @@ public class MatchController {
|
||||
public void startRound() {
|
||||
|
||||
// Deal with circular dependencies here
|
||||
input = new InputControl();
|
||||
currentGame = Singletons.getModel().newGame(players.keySet(),gameType, this);
|
||||
input = new InputControl(currentGame);
|
||||
currentGame.getActionPlay().setMatchInput(input);
|
||||
|
||||
|
||||
Map<Player, PlayerStartConditions> startConditions = new HashMap<Player, PlayerStartConditions>();
|
||||
for (Player p : currentGame.getPlayers()) {
|
||||
@@ -167,9 +165,11 @@ public class MatchController {
|
||||
SDisplayUtil.showTab(EDocID.REPORT_LOG.getDoc());
|
||||
|
||||
InputProxy inputControl = CMessage.SINGLETON_INSTANCE.getInputControl();
|
||||
inputControl.setMatch(this);
|
||||
input.addObserver(inputControl);
|
||||
currentGame.getStack().addObserver(inputControl);
|
||||
currentGame.getPhaseHandler().addObserver(inputControl);
|
||||
|
||||
currentGame.getGameLog().addObserver(CLog.SINGLETON_INSTANCE);
|
||||
currentGame.getStack().addObserver(CStack.SINGLETON_INSTANCE);
|
||||
// some observers are set in CMatchUI.initMatch
|
||||
@@ -178,8 +178,7 @@ public class MatchController {
|
||||
GameNew.newGame(this, startConditions, currentGame, canRandomFoil);
|
||||
|
||||
getInput().clearInput();
|
||||
getInput().resetInput();
|
||||
getInput().setNewInput(currentGame);
|
||||
//getInput().setNewInput(currentGame);
|
||||
|
||||
|
||||
// Thread thGame = new GameInputUpdatesThread(this, currentGame);
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -44,6 +45,7 @@ import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.SpellPermanent;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.GameState;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -762,5 +764,97 @@ public class AiController {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onPriorityRecieved() {
|
||||
final PhaseType phase = game.getPhaseHandler().getPhase();
|
||||
|
||||
if (game.getStack().size() > 0) {
|
||||
playSpellAbilities(game);
|
||||
} else {
|
||||
switch(phase) {
|
||||
case CLEANUP:
|
||||
if ( game.getPhaseHandler().getPlayerTurn() == player ) {
|
||||
final int size = player.getCardsIn(ZoneType.Hand).size();
|
||||
|
||||
if (!player.isUnlimitedHandSize()) {
|
||||
int max = Math.min(player.getZone(ZoneType.Hand).size(), size - player.getMaxHandSize());
|
||||
final List<Card> toDiscard = player.getAi().getCardsToDiscard(max, (String[])null, null);
|
||||
for (int i = 0; i < toDiscard.size(); i++) {
|
||||
player.discard(toDiscard.get(i), null);
|
||||
}
|
||||
game.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case COMBAT_DECLARE_ATTACKERS:
|
||||
declareAttackers();
|
||||
break;
|
||||
|
||||
case MAIN1:
|
||||
case MAIN2:
|
||||
Log.debug("Computer " + phase.toString());
|
||||
playLands();
|
||||
// fall through is intended
|
||||
default:
|
||||
playSpellAbilities(game);
|
||||
break;
|
||||
}
|
||||
}
|
||||
player.getController().passPriority();
|
||||
}
|
||||
|
||||
|
||||
private void declareAttackers() {
|
||||
// 12/2/10(sol) the decision making here has moved to getAttackers()
|
||||
game.setCombat(new AiAttackController(player, player.getOpponent()).getAttackers());
|
||||
|
||||
final List<Card> att = game.getCombat().getAttackers();
|
||||
if (!att.isEmpty()) {
|
||||
game.getPhaseHandler().setCombat(true);
|
||||
}
|
||||
|
||||
for (final Card element : att) {
|
||||
// tapping of attackers happens after Propaganda is paid for
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Computer just assigned ").append(element.getName()).append(" as an attacker.");
|
||||
Log.debug(sb.toString());
|
||||
}
|
||||
|
||||
player.getZone(ZoneType.Battlefield).updateObservers();
|
||||
|
||||
game.getPhaseHandler().setPlayersPriorityPermission(false);
|
||||
|
||||
// ai is about to attack, cancel all phase skipping
|
||||
for (Player p : game.getPlayers()) {
|
||||
p.getController().autoPassCancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void playLands() {
|
||||
final Player player = getPlayer();
|
||||
List<Card> landsWannaPlay = getLandsToPlay();
|
||||
|
||||
while(landsWannaPlay != null && !landsWannaPlay.isEmpty() && player.canPlayLand(null)) {
|
||||
Card land = chooseBestLandToPlay(landsWannaPlay);
|
||||
landsWannaPlay.remove(land);
|
||||
player.playLand(land);
|
||||
game.getPhaseHandler().setPriority(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void playSpellAbilities(final GameState game)
|
||||
{
|
||||
SpellAbility sa;
|
||||
do {
|
||||
sa = getSpellAbilityToPlay();
|
||||
if ( sa == null ) break;
|
||||
//System.out.println("Playing sa: " + sa);
|
||||
if (!ComputerUtil.handlePlayingSpellAbility(player, sa, game)) {
|
||||
break;
|
||||
}
|
||||
} while ( sa != null );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ package forge.game.ai;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.control.input.Input;
|
||||
import forge.Singletons;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.game.GameState;
|
||||
import forge.game.phase.CombatUtil;
|
||||
import forge.game.player.Player;
|
||||
@@ -12,7 +13,7 @@ import forge.game.player.Player;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class AiInputBlock extends Input {
|
||||
public class AiInputBlock extends InputBase {
|
||||
|
||||
private final GameState game;
|
||||
/**
|
||||
@@ -38,6 +39,7 @@ public class AiInputBlock extends Input {
|
||||
CombatUtil.orderMultipleCombatants(game.getCombat());
|
||||
game.getPhaseHandler().setPlayersPriorityPermission(false);
|
||||
|
||||
stop();
|
||||
// was not added to stack, so will be replaced by plain update
|
||||
Singletons.getModel().getMatch().getInput().updateObservers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,8 @@
|
||||
*/
|
||||
package forge.game.ai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
|
||||
import forge.Card;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.game.GameState;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.FThreads;
|
||||
import forge.control.input.InputBase;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -38,13 +28,11 @@ import forge.game.zone.ZoneType;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AiInputCommon extends Input {
|
||||
public class AiInputCommon extends InputBase {
|
||||
/** Constant <code>serialVersionUID=-3091338639571662216L</code>. */
|
||||
private static final long serialVersionUID = -3091338639571662216L;
|
||||
|
||||
private final AiController computer;
|
||||
private final AIPlayer player;
|
||||
private final GameState game;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -56,15 +44,13 @@ public class AiInputCommon extends Input {
|
||||
*/
|
||||
public AiInputCommon(final AiController iComputer) {
|
||||
this.computer = iComputer;
|
||||
player = computer.getPlayer();
|
||||
this.game = computer.getGame();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void showMessage() {
|
||||
// should not think when the game is over
|
||||
if (game.isGameOver()) {
|
||||
if (computer.getGame().isGameOver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,104 +62,15 @@ public class AiInputCommon extends Input {
|
||||
* \"Detailed Error Trace\" to the Forge forum.");
|
||||
*/
|
||||
|
||||
final PhaseType phase = game.getPhaseHandler().getPhase();
|
||||
FThreads.invokeInNewThread(aiActions, true);
|
||||
|
||||
if (game.getStack().size() > 0) {
|
||||
playSpellAbilities(game);
|
||||
} else {
|
||||
switch(phase) {
|
||||
case CLEANUP:
|
||||
if ( game.getPhaseHandler().getPlayerTurn() == player ) {
|
||||
final int size = player.getCardsIn(ZoneType.Hand).size();
|
||||
|
||||
if (!player.isUnlimitedHandSize()) {
|
||||
int max = Math.min(player.getZone(ZoneType.Hand).size(), size - player.getMaxHandSize());
|
||||
final List<Card> toDiscard = player.getAi().getCardsToDiscard(max, (String[])null, null);
|
||||
for (int i = 0; i < toDiscard.size(); i++) {
|
||||
player.discard(toDiscard.get(i), null);
|
||||
}
|
||||
game.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case COMBAT_DECLARE_ATTACKERS:
|
||||
declareAttackers();
|
||||
break;
|
||||
|
||||
case MAIN1:
|
||||
case MAIN2:
|
||||
Log.debug("Computer " + phase.toString());
|
||||
playLands();
|
||||
// fall through is intended
|
||||
default:
|
||||
playSpellAbilities(game);
|
||||
break;
|
||||
}
|
||||
}
|
||||
player.getController().passPriority();
|
||||
} // getMessage();
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
private void declareAttackers() {
|
||||
// 12/2/10(sol) the decision making here has moved to getAttackers()
|
||||
game.setCombat(new AiAttackController(player, player.getOpponent()).getAttackers());
|
||||
final Runnable aiActions = new Runnable() {
|
||||
|
||||
final List<Card> att = game.getCombat().getAttackers();
|
||||
if (!att.isEmpty()) {
|
||||
game.getPhaseHandler().setCombat(true);
|
||||
@Override
|
||||
public void run() {
|
||||
computer.onPriorityRecieved();
|
||||
}
|
||||
|
||||
for (final Card element : att) {
|
||||
// tapping of attackers happens after Propaganda is paid for
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Computer just assigned ").append(element.getName()).append(" as an attacker.");
|
||||
Log.debug(sb.toString());
|
||||
}
|
||||
|
||||
player.getZone(ZoneType.Battlefield).updateObservers();
|
||||
|
||||
game.getPhaseHandler().setPlayersPriorityPermission(false);
|
||||
|
||||
// ai is about to attack, cancel all phase skipping
|
||||
for (Player p : game.getPlayers()) {
|
||||
p.getController().autoPassCancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
private void playLands() {
|
||||
final Player player = computer.getPlayer();
|
||||
List<Card> landsWannaPlay = computer.getLandsToPlay();
|
||||
|
||||
while(landsWannaPlay != null && !landsWannaPlay.isEmpty() && player.canPlayLand(null)) {
|
||||
Card land = computer.chooseBestLandToPlay(landsWannaPlay);
|
||||
landsWannaPlay.remove(land);
|
||||
player.playLand(land);
|
||||
game.getPhaseHandler().setPriority(player);
|
||||
}
|
||||
}
|
||||
|
||||
protected void playSpellAbilities(final GameState game)
|
||||
{
|
||||
SpellAbility sa;
|
||||
do {
|
||||
sa = computer.getSpellAbilityToPlay();
|
||||
if ( sa == null ) break;
|
||||
//System.out.println("Playing sa: " + sa);
|
||||
if (!ComputerUtil.handlePlayingSpellAbility(player, sa, game)) {
|
||||
break;
|
||||
}
|
||||
} while ( sa != null );
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.input.Input#isClassUpdated()
|
||||
*/
|
||||
@Override public void isClassUpdated() { }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1150,39 +1150,13 @@ public class CombatUtil {
|
||||
}
|
||||
};
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
|
||||
private static final long serialVersionUID = -6483405139208343935L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
game.getCombat().removeFromCombat(crd);
|
||||
|
||||
if (bLast) {
|
||||
PhaseUtil.handleAttackingTriggers();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = new Command() {
|
||||
private static final long serialVersionUID = -8303368287601871955L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
// if Propaganda is paid, tap this card
|
||||
if (!crd.hasKeyword("Vigilance")) {
|
||||
crd.tap();
|
||||
}
|
||||
|
||||
if (bLast) {
|
||||
PhaseUtil.handleAttackingTriggers();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ability.setActivatingPlayer(c.getController());
|
||||
if (c.getController().isHuman()) {
|
||||
GameActionUtil.payCostDuringAbilityResolve(c.getController(), ability, attackCost, paidCommand, unpaidCommand, null, game);
|
||||
if ( GameActionUtil.payCostDuringAbilityResolve(c.getController(), ability, attackCost, null, game) ) {
|
||||
if (!crd.hasKeyword("Vigilance")) { crd.tap(); }
|
||||
} else {
|
||||
game.getCombat().removeFromCombat(crd);
|
||||
}
|
||||
} else { // computer
|
||||
if (ComputerUtilCost.canPayCost(ability, c.getController())) {
|
||||
ComputerUtil.playNoStack((AIPlayer)c.getController(), ability, game);
|
||||
@@ -1194,12 +1168,11 @@ public class CombatUtil {
|
||||
// during Declare_Attackers
|
||||
game.getCombat().removeFromCombat(crd);
|
||||
}
|
||||
if (bLast) {
|
||||
}
|
||||
if (bLast)
|
||||
PhaseUtil.handleAttackingTriggers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Stack;
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.GameState;
|
||||
@@ -734,15 +735,25 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
nextPhase();
|
||||
return;
|
||||
} else if (!game.getStack().hasSimultaneousStackEntries()) {
|
||||
Runnable proc = new Runnable(){
|
||||
@Override public void run() {
|
||||
game.getStack().resolveStack();
|
||||
game.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
}
|
||||
};
|
||||
|
||||
if ( FThreads.isEDT() )
|
||||
FThreads.invokeInNewThread(proc, true);
|
||||
else
|
||||
proc.run();
|
||||
}
|
||||
} else {
|
||||
// pass the priority to other player
|
||||
this.pPlayerPriority = nextPlayer;
|
||||
Singletons.getModel().getMatch().getInput().resetInput();
|
||||
Singletons.getModel().getMatch().getInput().updateObservers();
|
||||
|
||||
}
|
||||
game.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -817,4 +828,9 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
this.planarDiceRolledthisTurn++;
|
||||
}
|
||||
|
||||
public String debugPrintState() {
|
||||
return String.format("%s's %s, priority of %s [%sP]", getPlayerTurn(), getPhase(), getPriorityPlayer(), isPlayerPriorityAllowed() ? "+" : "-");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import forge.CardPredicates.Presets;
|
||||
import forge.CounterType;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.player.Player;
|
||||
@@ -210,7 +210,7 @@ public class Untap extends Phase {
|
||||
landList.get(0).untap();
|
||||
}
|
||||
} else {
|
||||
final Input target = new Input() {
|
||||
final InputBase target = new InputBase() {
|
||||
private static final long serialVersionUID = 6653677835629939465L;
|
||||
|
||||
@Override
|
||||
@@ -250,7 +250,7 @@ public class Untap extends Phase {
|
||||
ComputerUtilCard.getBestArtifactAI(artList).untap();
|
||||
}
|
||||
} else {
|
||||
final Input target = new Input() {
|
||||
final InputBase target = new InputBase() {
|
||||
private static final long serialVersionUID = 5555427219659889707L;
|
||||
|
||||
@Override
|
||||
@@ -290,7 +290,7 @@ public class Untap extends Phase {
|
||||
creatures.get(0).untap();
|
||||
}
|
||||
} else {
|
||||
final Input target = new Input() {
|
||||
final InputBase target = new InputBase() {
|
||||
private static final long serialVersionUID = 5555427219659889707L;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,14 +21,13 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.Command;
|
||||
import forge.CounterType;
|
||||
import forge.Singletons;
|
||||
import forge.card.cardfactory.CardFactoryUtil;
|
||||
@@ -39,8 +38,9 @@ import forge.card.spellability.Ability;
|
||||
import forge.card.spellability.AbilityManaPart;
|
||||
import forge.card.spellability.AbilityStatic;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectManyCards;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.control.input.InputPayManaExecuteCommands;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
@@ -174,18 +174,6 @@ public class Upkeep extends Phase {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
final Card c = list.get(i);
|
||||
if (c.hasStartOfKeyword("(Echo unpaid)")) {
|
||||
|
||||
final Command paidCommand = Command.BLANK;
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = -7354791599039157375L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
game.getAction().sacrifice(c, null);
|
||||
}
|
||||
};
|
||||
|
||||
final Ability blankAbility = Upkeep.BlankAbility(c, c.getEchoCost());
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
@@ -198,7 +186,9 @@ public class Upkeep extends Phase {
|
||||
Player controller = c.getController();
|
||||
if (controller.isHuman()) {
|
||||
Cost cost = new Cost(c, c.getEchoCost().trim(), true);
|
||||
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, cost, paidCommand, unpaidCommand, null, game);
|
||||
if ( !GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, cost, null, game) )
|
||||
game.getAction().sacrifice(c, null);;
|
||||
|
||||
} else { // computer
|
||||
if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
||||
ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game);
|
||||
@@ -279,44 +269,34 @@ public class Upkeep extends Phase {
|
||||
final String[] k = ability.split(" pay ");
|
||||
final ManaCost upkeepCost = new ManaCost(new ManaCostParser(k[1]));
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = 8942537892273123542L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
if (c.getName().equals("Cosmic Horror")) {
|
||||
controller.addDamage(7, c);
|
||||
}
|
||||
game.getAction().destroy(c);
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = Command.BLANK;
|
||||
|
||||
final Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString());
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Upkeep for ").append(c).append("\n");
|
||||
final String sb = "Upkeep for " + c;
|
||||
final Ability upkeepAbility = new Ability(c, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
final boolean isUpkeepPaid;
|
||||
if (controller.isHuman()) {
|
||||
GameActionUtil.payManaDuringAbilityResolve(sb.toString(), upkeepCost, paidCommand, unpaidCommand);
|
||||
InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, sb, upkeepCost);
|
||||
FThreads.setInputAndWait(inp);
|
||||
isUpkeepPaid = inp.isPaid();
|
||||
} else { // computer
|
||||
if (ComputerUtilCost.canPayCost(aiPaid, controller) && !c.hasKeyword("Indestructible")) {
|
||||
Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString());
|
||||
isUpkeepPaid = ComputerUtilCost.canPayCost(aiPaid, controller) && !c.hasKeyword("Indestructible");
|
||||
if (isUpkeepPaid) {
|
||||
ComputerUtil.playNoStack((AIPlayer)controller, aiPaid, game);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
if( !isUpkeepPaid ) {
|
||||
if (c.getName().equals("Cosmic Horror")) {
|
||||
controller.addDamage(7, c);
|
||||
}
|
||||
game.getAction().destroy(c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
upkeepAbility.setActivatingPlayer(controller);
|
||||
upkeepAbility.setStackDescription(sb.toString());
|
||||
upkeepAbility.setDescription(sb.toString());
|
||||
upkeepAbility.setStackDescription(sb);
|
||||
upkeepAbility.setDescription(sb);
|
||||
|
||||
game.getStack().addSimultaneousStackEntry(upkeepAbility);
|
||||
} // destroy
|
||||
@@ -341,18 +321,6 @@ public class Upkeep extends Phase {
|
||||
}
|
||||
|
||||
final String upkeepCost = cost;
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = 5612348769167529102L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
game.getAction().sacrifice(c, null);
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = Command.BLANK;
|
||||
|
||||
final Ability blankAbility = Upkeep.BlankAbility(c, upkeepCost);
|
||||
blankAbility.setActivatingPlayer(controller);
|
||||
|
||||
@@ -360,11 +328,11 @@ public class Upkeep extends Phase {
|
||||
@Override
|
||||
public void resolve() {
|
||||
if (controller.isHuman()) {
|
||||
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, blankAbility.getPayCosts(),
|
||||
paidCommand, unpaidCommand, this, game);
|
||||
if ( !GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, blankAbility.getPayCosts(), this, game))
|
||||
game.getAction().sacrifice(c, null);
|
||||
} else { // computer
|
||||
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
||||
ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game);
|
||||
ComputerUtil.playNoStack((AIPlayer)controller, blankAbility, game); // this makes AI pay
|
||||
} else {
|
||||
game.getAction().sacrifice(c, null);
|
||||
}
|
||||
@@ -386,34 +354,25 @@ public class Upkeep extends Phase {
|
||||
final String[] l = k[1].split(" pay ");
|
||||
final ManaCost upkeepCost = new ManaCost(new ManaCostParser(l[1]));
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = 1238166187561501928L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
controller.addDamage(upkeepDamage, c);
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = Command.BLANK;
|
||||
|
||||
final Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString());
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Damage upkeep for ").append(c).append("\n");
|
||||
final String sb = "Damage upkeep for " + c;
|
||||
final Ability upkeepAbility = new Ability(c, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
boolean isUpkeepPaid = false;
|
||||
if (controller.isHuman()) {
|
||||
GameActionUtil.payManaDuringAbilityResolve(sb.toString(), upkeepCost, paidCommand, unpaidCommand);
|
||||
InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, sb, upkeepCost);
|
||||
FThreads.setInputAndWait(inp);
|
||||
isUpkeepPaid = inp.isPaid();
|
||||
} else { // computers
|
||||
if (ComputerUtilCost.canPayCost(aiPaid, controller)
|
||||
&& (ComputerUtilCombat.predictDamageTo(controller, upkeepDamage, c, false) > 0)) {
|
||||
final Ability aiPaid = Upkeep.BlankAbility(c, upkeepCost.toString());
|
||||
if (ComputerUtilCost.canPayCost(aiPaid, controller) && ComputerUtilCombat.predictDamageTo(controller, upkeepDamage, c, false) > 0) {
|
||||
ComputerUtil.playNoStack((AIPlayer)controller, aiPaid, game);
|
||||
} else {
|
||||
controller.addDamage(upkeepDamage, c);
|
||||
isUpkeepPaid = true;
|
||||
}
|
||||
}
|
||||
if (!isUpkeepPaid) {
|
||||
controller.addDamage(upkeepDamage, c);
|
||||
}
|
||||
}
|
||||
};
|
||||
upkeepAbility.setActivatingPlayer(controller);
|
||||
@@ -478,27 +437,20 @@ public class Upkeep extends Phase {
|
||||
@Override
|
||||
public void resolve() {
|
||||
final List<Card> targets = CardLists.getTargetableCards(abyssGetTargets, this);
|
||||
final Input chooseArt = new InputSelectManyCards(1, 1) {
|
||||
if (player.isHuman() && targets.size() > 0) {
|
||||
final InputSelectCards chooseArt = new InputSelectCards(1, 1) {
|
||||
private static final long serialVersionUID = 4820011040853968644L;
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return abyss.getName() + " - Select one nonartifact creature to destroy";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidChoice(Card choice) {
|
||||
return choice.isCreature() && !choice.isArtifact() && canTarget(choice) && choice.getController() == player;
|
||||
};
|
||||
|
||||
@Override
|
||||
protected Input onDone() {
|
||||
game.getAction().destroyNoRegeneration(selected.get(0));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (player.isHuman() && targets.size() > 0) {
|
||||
Singletons.getModel().getMatch().getInput().setInput(chooseArt); // Input
|
||||
chooseArt.setMessage(abyss.getName() + " - Select one nonartifact creature to destroy");
|
||||
FThreads.setInputAndWait(chooseArt); // Input
|
||||
if (!chooseArt.hasCancelled()) {
|
||||
game.getAction().destroyNoRegeneration(chooseArt.getSelected().get(0));
|
||||
}
|
||||
|
||||
} else { // computer
|
||||
|
||||
final List<Card> indestruct = CardLists.getKeyword(targets, "Indestructible");
|
||||
@@ -617,9 +569,7 @@ public class Upkeep extends Phase {
|
||||
final Player player = game.getPhaseHandler().getPlayerTurn();
|
||||
final List<Card> cards = player.getCardsIn(ZoneType.Battlefield, "Demonic Hordes");
|
||||
|
||||
for (int i = 0; i < cards.size(); i++) {
|
||||
|
||||
final Card c = cards.get(i);
|
||||
for (final Card c : cards) {
|
||||
|
||||
final Ability cost = new Ability(c, new ManaCost(new ManaCostParser("B B B"))) {
|
||||
@Override
|
||||
@@ -627,7 +577,7 @@ public class Upkeep extends Phase {
|
||||
}
|
||||
}; // end cost ability
|
||||
|
||||
final Ability noPay = new Ability(c, ManaCost.ZERO) {
|
||||
final Ability unpaidHordesAb = new Ability(c, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
final List<Card> playerLand = player.getLandsInPlay();
|
||||
@@ -648,16 +598,14 @@ public class Upkeep extends Phase {
|
||||
|
||||
final Player cp = c.getController();
|
||||
if (cp.isHuman()) {
|
||||
final String question = "Pay Demonic Hordes upkeep cost?";
|
||||
if (GuiDialog.confirm(c, question)) {
|
||||
final Ability pay = new Ability(c, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
if (game.getZoneOf(c).is(ZoneType.Battlefield)) {
|
||||
final StringBuilder coststring = new StringBuilder();
|
||||
coststring.append("Pay cost for ").append(c).append("\r\n");
|
||||
GameActionUtil.payManaDuringAbilityResolve(coststring.toString(), cost.getManaCost(),
|
||||
Command.BLANK, Command.BLANK);
|
||||
InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, "Pay Demonic Hordes upkeep cost", cost.getManaCost() /*, true */);
|
||||
FThreads.setInputAndWait(inp);
|
||||
if ( !inp.isPaid() )
|
||||
unpaidHordesAb.resolve();
|
||||
}
|
||||
} // end resolve()
|
||||
}; // end pay ability
|
||||
@@ -665,19 +613,9 @@ public class Upkeep extends Phase {
|
||||
pay.setDescription("Demonic Hordes - Upkeep Cost");
|
||||
|
||||
game.getStack().addSimultaneousStackEntry(pay);
|
||||
|
||||
} // end choice
|
||||
else {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(c.getName()).append(" - is tapped and you must sacrifice a land of opponent's choice");
|
||||
noPay.setStackDescription(sb.toString());
|
||||
|
||||
game.getStack().addSimultaneousStackEntry(noPay);
|
||||
|
||||
}
|
||||
} // end human
|
||||
else { // computer
|
||||
noPay.setActivatingPlayer(cp);
|
||||
unpaidHordesAb.setActivatingPlayer(cp);
|
||||
if (ComputerUtilCost.canPayCost(cost, (AIPlayer) cp)) {
|
||||
final Ability computerPay = new Ability(c, ManaCost.ZERO) {
|
||||
@Override
|
||||
@@ -689,8 +627,8 @@ public class Upkeep extends Phase {
|
||||
|
||||
game.getStack().addSimultaneousStackEntry(computerPay);
|
||||
} else {
|
||||
noPay.setStackDescription("Demonic Hordes - Upkeep Cost");
|
||||
game.getStack().addSimultaneousStackEntry(noPay);
|
||||
unpaidHordesAb.setStackDescription("Demonic Hordes - Upkeep Cost");
|
||||
game.getStack().addSimultaneousStackEntry(unpaidHordesAb);
|
||||
|
||||
}
|
||||
} // end computer
|
||||
@@ -1061,7 +999,7 @@ public class Upkeep extends Phase {
|
||||
list.remove(toTap);
|
||||
}
|
||||
} else {
|
||||
Singletons.getModel().getMatch().getInput().setInput(new Input() {
|
||||
Singletons.getModel().getMatch().getInput().setInput(new InputBase() {
|
||||
private static final long serialVersionUID = 5313424586016061612L;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,6 +39,7 @@ import forge.CardPredicates.Presets;
|
||||
import forge.CardUtil;
|
||||
import forge.Constant.Preferences;
|
||||
import forge.CounterType;
|
||||
import forge.FThreads;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityFactory;
|
||||
@@ -1624,6 +1625,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
protected final void doDiscard(final Card c, final SpellAbility sa) {
|
||||
FThreads.checkEDT("Player.doDiscard", false);
|
||||
// TODO: This line should be moved inside CostPayment somehow
|
||||
/*if (sa != null) {
|
||||
sa.addCostToHashList(c, "Discarded");
|
||||
@@ -1846,6 +1848,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void playLand(final Card land) {
|
||||
FThreads.checkEDT("Player.playSpellAbility", false);
|
||||
if (this.canPlayLand(land)) {
|
||||
land.setController(this, 0);
|
||||
game.getAction().moveTo(this.getZone(ZoneType.Battlefield), land);
|
||||
|
||||
@@ -11,12 +11,15 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.GameEntity;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputBlock;
|
||||
import forge.control.input.InputCleanup;
|
||||
import forge.control.input.InputPassPriority;
|
||||
import forge.control.input.InputSelectCards;
|
||||
import forge.control.input.InputSelectCardsFromList;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
@@ -212,26 +215,18 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
*/
|
||||
@Override
|
||||
public List<Card> choosePermanentsToSacrifice(List<Card> validTargets, int amount, SpellAbility sa, boolean destroy, boolean isOptional) {
|
||||
List<Card> result = new ArrayList<Card>();
|
||||
int max = Math.min(amount, validTargets.size());
|
||||
if (max == 0)
|
||||
return new ArrayList<Card>();
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (validTargets.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
Card c;
|
||||
if (isOptional) {
|
||||
c = GuiChoose.oneOrNone("Select a card to sacrifice", validTargets);
|
||||
} else {
|
||||
c = GuiChoose.one("Select a card to sacrifice", validTargets);
|
||||
}
|
||||
if (c != null) {
|
||||
result.add(c);
|
||||
validTargets.remove(c);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
InputSelectCards inp = new InputSelectCardsFromList(isOptional ? 0 : amount, max, validTargets);
|
||||
// TODO: Either compose a message here, or pass it as parameter from caller.
|
||||
inp.setMessage("Select %d card(s) to sacrifice");
|
||||
|
||||
FThreads.setInputAndWait(inp);
|
||||
if( inp.hasCancelled() )
|
||||
return new ArrayList<Card>();
|
||||
else return inp.getSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -321,10 +316,19 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
|
||||
@Override
|
||||
public List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> valid, int minDiscard) {
|
||||
if ( p != getPlayer() ) {
|
||||
int cntToKeepInHand = minDiscard == 0 ? -1 : valid.size() - minDiscard;
|
||||
return GuiChoose.order("Choose cards to Discard", "Discarded", cntToKeepInHand, valid, null, null);
|
||||
}
|
||||
|
||||
int max = minDiscard == 0 ? Integer.MAX_VALUE : minDiscard;
|
||||
InputSelectCards inp = new InputSelectCardsFromList(minDiscard, max, valid);
|
||||
inp.setCancelWithSelectedAllowed(false);
|
||||
inp.setMessage("Discard %d cards");
|
||||
FThreads.setInputAndWait(inp);
|
||||
return inp.getSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Card chooseCardToDredge(List<Card> dredgers) {
|
||||
if (GuiDialog.confirm(null, "Do you want to dredge?", false)) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import forge.CardLists;
|
||||
import forge.Singletons;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.CMatchUI;
|
||||
@@ -54,12 +55,12 @@ public final class PlayerUtil {
|
||||
* a {@link java.lang.String} object.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Input inputDiscardNumUnless(final int nCards, final String uType, final SpellAbility sa) {
|
||||
final SpellAbility sp = sa;
|
||||
final Input target = new Input() {
|
||||
final Input target = new InputBase() {
|
||||
private static final long serialVersionUID = 8822292413831640944L;
|
||||
|
||||
private int n = 0;
|
||||
@@ -111,12 +112,12 @@ public final class PlayerUtil {
|
||||
* a int.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Input inputDiscard(final int nCards, final SpellAbility sa) {
|
||||
final SpellAbility sp = sa;
|
||||
final Input target = new Input() {
|
||||
final Input target = new InputBase() {
|
||||
private static final long serialVersionUID = -329993322080934435L;
|
||||
|
||||
private int n = 0;
|
||||
@@ -162,7 +163,7 @@ public final class PlayerUtil {
|
||||
* a int.
|
||||
* @param type
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Input inputSacrificePermanents(final int nCards, final String type) {
|
||||
@@ -182,11 +183,11 @@ public final class PlayerUtil {
|
||||
* a {@link forge.CardList} object.
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link forge.control.input.Input} object.
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
* @since 1.0.15
|
||||
*/
|
||||
public static Input inputSacrificePermanentsFromList(final int nCards, final List<Card> list, final String message) {
|
||||
final Input target = new Input() {
|
||||
final Input target = new InputBase() {
|
||||
private static final long serialVersionUID = 1981791992623774490L;
|
||||
private int n = 0;
|
||||
|
||||
|
||||
@@ -22,21 +22,18 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.Command;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.cardfactory.CardFactory;
|
||||
import forge.card.cardfactory.CardFactoryUtil;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostBeingPaid;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
import forge.card.spellability.Ability;
|
||||
import forge.card.spellability.AbilityStatic;
|
||||
import forge.card.spellability.AbilityTriggered;
|
||||
@@ -48,7 +45,7 @@ import forge.card.spellability.TargetChoices;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputBase;
|
||||
import forge.control.input.InputPayManaExecuteCommands;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.GameState;
|
||||
@@ -295,95 +292,6 @@ public class MagicStack extends MyObservable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getMultiKickerSpellCostChange.
|
||||
* </p>
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @return a {@link forge.card.mana.ManaCostBeingPaid} object.
|
||||
*/
|
||||
public final ManaCostBeingPaid getMultiKickerSpellCostChange(final SpellAbility sa) {
|
||||
final int max = 25;
|
||||
final String[] numbers = new String[max];
|
||||
for (int no = 0; no < max; no++) {
|
||||
numbers[no] = String.valueOf(no);
|
||||
}
|
||||
|
||||
ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost());
|
||||
String mana = manaCost.toString();
|
||||
|
||||
int multiKickerPaid = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaid();
|
||||
|
||||
String numberManaCost = " ";
|
||||
|
||||
if (mana.toString().length() == 1) {
|
||||
numberManaCost = mana.toString().substring(0, 1);
|
||||
} else if (mana.toString().length() == 0) {
|
||||
numberManaCost = "0"; // Should Never Occur
|
||||
} else {
|
||||
numberManaCost = mana.toString().substring(0, 2);
|
||||
}
|
||||
|
||||
numberManaCost = numberManaCost.trim();
|
||||
|
||||
for (int check = 0; check < max; check++) {
|
||||
if (numberManaCost.equals(numbers[check])) {
|
||||
|
||||
if ((check - multiKickerPaid) < 0) {
|
||||
multiKickerPaid = multiKickerPaid - check;
|
||||
game.getActionPlay().setCostCuttingGetMultiKickerManaCostPaid(multiKickerPaid);
|
||||
mana = mana.replaceFirst(String.valueOf(check), "0");
|
||||
} else {
|
||||
mana = mana.replaceFirst(String.valueOf(check), String.valueOf(check - multiKickerPaid));
|
||||
multiKickerPaid = 0;
|
||||
game.getActionPlay().setCostCuttingGetMultiKickerManaCostPaid(multiKickerPaid);
|
||||
}
|
||||
}
|
||||
mana = mana.trim();
|
||||
if (mana.equals("")) {
|
||||
mana = "0";
|
||||
}
|
||||
manaCost = new ManaCostBeingPaid(mana);
|
||||
}
|
||||
final String colorCut = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaidColored();
|
||||
|
||||
for (int colorCutIx = 0; colorCutIx < colorCut.length(); colorCutIx++) {
|
||||
if ("WUGRB".contains(colorCut.substring(colorCutIx, colorCutIx + 1))
|
||||
&& !mana.equals(mana.replaceFirst((colorCut.substring(colorCutIx, colorCutIx + 1)), ""))) {
|
||||
mana = mana.replaceFirst(colorCut.substring(colorCutIx, colorCutIx + 1), "");
|
||||
|
||||
game.getActionPlay().setCostCuttingGetMultiKickerManaCostPaidColored(
|
||||
game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaidColored()
|
||||
.replaceFirst(colorCut.substring(colorCutIx, colorCutIx + 1), ""));
|
||||
|
||||
mana = mana.trim();
|
||||
if (mana.equals("")) {
|
||||
mana = "0";
|
||||
}
|
||||
manaCost = new ManaCostBeingPaid(mana);
|
||||
}
|
||||
}
|
||||
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
// TODO: this may be able to use a straight copy of MultiKicker cost change
|
||||
/**
|
||||
* <p>
|
||||
* getReplicateSpellCostChange.
|
||||
* </p>
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @return a {@link forge.card.mana.ManaCostBeingPaid} object.
|
||||
*/
|
||||
public final ManaCostBeingPaid getReplicateSpellCostChange(final SpellAbility sa) {
|
||||
final ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost());
|
||||
// String Mana = manaCost.toString();
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -394,6 +302,7 @@ public class MagicStack extends MyObservable {
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public final void add(final SpellAbility sp) {
|
||||
FThreads.checkEDT("MagicStack.add", false);
|
||||
final ArrayList<TargetChoices> chosenTargets = sp.getAllTargetChoices();
|
||||
|
||||
if (sp.isManaAbility()) { // Mana Abilities go straight through
|
||||
@@ -478,8 +387,30 @@ public class MagicStack extends MyObservable {
|
||||
} else if (sp.isXCost()) {
|
||||
// TODO: convert any X costs to use abCost so it happens earlier
|
||||
final SpellAbility sa = sp;
|
||||
final ManaCost mc = new ManaCost( new ManaCostParser(Integer.toString(sa.getXManaCost())));
|
||||
final Ability ability = new Ability(sp.getSourceCard(), mc) {
|
||||
final int xCost = sa.getXManaCost();
|
||||
Player player = sp.getSourceCard().getController();
|
||||
if (player.isHuman()) {
|
||||
final Runnable payNextX = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
final Card crd = sa.getSourceCard();
|
||||
|
||||
String message = "Pay X cost for " + crd.getName() + " (X=" + crd.getXManaCostPaid() + ")\r\n";
|
||||
InputPayManaExecuteCommands inp = new InputPayManaExecuteCommands(game, message, ManaCost.get(xCost), true);
|
||||
FThreads.setInputAndWait(inp);
|
||||
if ( inp.isPaid() ) {
|
||||
crd.addXManaCostPaid(1);
|
||||
this.run();
|
||||
} else
|
||||
MagicStack.this.push(sa);
|
||||
}
|
||||
};
|
||||
payNextX.run();
|
||||
} else {
|
||||
// computer
|
||||
final int neededDamage = CardFactoryUtil.getNeededXDamage(sa);
|
||||
final Ability ability = new Ability(sp.getSourceCard(), ManaCost.get(xCost)) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
final Card crd = this.getSourceCard();
|
||||
@@ -487,40 +418,6 @@ public class MagicStack extends MyObservable {
|
||||
}
|
||||
};
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = -3342222770086269767L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
MagicStack.this.push(sa);
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = new Command() {
|
||||
private static final long serialVersionUID = -2224875229611007788L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ability.resolve();
|
||||
final Card crd = sa.getSourceCard();
|
||||
Singletons.getModel().getMatch().getInput().setInput(
|
||||
new InputPayManaExecuteCommands(game, "Pay X cost for " + crd.getName() + " (X="
|
||||
+ crd.getXManaCostPaid() + ")\r\n", ability.getManaCost().toString(), this, unpaidCommand,
|
||||
true));
|
||||
}
|
||||
};
|
||||
|
||||
final Card crd = sa.getSourceCard();
|
||||
Player player = sp.getSourceCard().getController();
|
||||
if (player.isHuman()) {
|
||||
Singletons.getModel().getMatch().getInput().setInput(
|
||||
new InputPayManaExecuteCommands(game, "Pay X cost for " + sp.getSourceCard().getName() + " (X="
|
||||
+ crd.getXManaCostPaid() + ")\r\n", ability.getManaCost().toString(), paidCommand,
|
||||
unpaidCommand, true));
|
||||
} else {
|
||||
// computer
|
||||
final int neededDamage = CardFactoryUtil.getNeededXDamage(sa);
|
||||
|
||||
while (ComputerUtilCost.canPayCost(ability, player) && (neededDamage != sa.getSourceCard().getXManaCostPaid())) {
|
||||
ComputerUtil.playNoStack((AIPlayer)player, ability, game);
|
||||
}
|
||||
@@ -532,59 +429,38 @@ public class MagicStack extends MyObservable {
|
||||
// both X and multi is not supported yet
|
||||
|
||||
final SpellAbility sa = sp;
|
||||
final Ability ability = new Ability(sp.getSourceCard(), sp.getMultiKickerManaCost()) {
|
||||
final Ability abilityIncreaseMultikicker = new Ability(sp.getSourceCard(), sp.getMultiKickerManaCost()) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
this.getSourceCard().addMultiKickerMagnitude(1);
|
||||
}
|
||||
};
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = -3342222770086269767L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
MagicStack.this.push(sa);
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = new Command() {
|
||||
private static final long serialVersionUID = -6037161763374971106L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ability.resolve();
|
||||
|
||||
final ManaCostBeingPaid manaCost = MagicStack.this.getMultiKickerSpellCostChange(ability);
|
||||
|
||||
if (manaCost.isPaid()) {
|
||||
this.execute();
|
||||
} else {
|
||||
String prompt;
|
||||
int mkCostPaid = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaid();
|
||||
String mkCostPaidColored = game.getActionPlay().getCostCuttingGetMultiKickerManaCostPaidColored();
|
||||
int mkMagnitude = sa.getSourceCard().getMultiKickerMagnitude();
|
||||
if ((mkCostPaid == 0) && mkCostPaidColored.equals("")) {
|
||||
prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", sa.getSourceCard(), mkMagnitude );
|
||||
} else {
|
||||
prompt = String.format("Multikicker for %s\r\nMana in Reserve: %s %s\r\nTimes Kicked: %d", sa.getSourceCard(),
|
||||
(mkCostPaid != 0) ? Integer.toString(mkCostPaid) : "", mkCostPaidColored, mkMagnitude);
|
||||
}
|
||||
Input toSet = new InputPayManaExecuteCommands(game, prompt, manaCost.toString(), this, unpaidCommand);
|
||||
Singletons.getModel().getMatch().getInput().setInput(toSet);
|
||||
}
|
||||
}
|
||||
};
|
||||
Player activating = sp.getActivatingPlayer();
|
||||
|
||||
if (activating.isHuman()) {
|
||||
sa.getSourceCard().addMultiKickerMagnitude(-1);
|
||||
paidCommand.execute();
|
||||
final Runnable paidCommand = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
abilityIncreaseMultikicker.resolve();
|
||||
int mkMagnitude = sa.getSourceCard().getMultiKickerMagnitude();
|
||||
String prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", sa.getSourceCard(), mkMagnitude );
|
||||
InputPayManaExecuteCommands toSet = new InputPayManaExecuteCommands(game, prompt, sp.getMultiKickerManaCost());
|
||||
FThreads.setInputAndWait(toSet);
|
||||
if ( toSet.isPaid() ) {
|
||||
this.run();
|
||||
} else
|
||||
MagicStack.this.push(sa);
|
||||
|
||||
}
|
||||
};
|
||||
paidCommand.run();
|
||||
} else {
|
||||
// computer
|
||||
|
||||
while (ComputerUtilCost.canPayCost(ability, activating)) {
|
||||
ComputerUtil.playNoStack((AIPlayer)activating, ability, game);
|
||||
while (ComputerUtilCost.canPayCost(abilityIncreaseMultikicker, activating)) {
|
||||
ComputerUtil.playNoStack((AIPlayer)activating, abilityIncreaseMultikicker, game);
|
||||
}
|
||||
|
||||
this.push(sa);
|
||||
@@ -603,38 +479,27 @@ public class MagicStack extends MyObservable {
|
||||
}
|
||||
};
|
||||
|
||||
final Command unpaidCommand = new Command() {
|
||||
private static final long serialVersionUID = -3180458633098297855L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
for (int i = 0; i < sp.getSourceCard().getReplicateMagnitude(); i++) {
|
||||
CardFactory.copySpellontoStack(sp.getSourceCard(), sp.getSourceCard(), sp, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Command paidCommand = new Command() {
|
||||
private static final long serialVersionUID = 132624005072267304L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ability.resolve();
|
||||
final ManaCostBeingPaid manaCost = MagicStack.this.getReplicateSpellCostChange(ability);
|
||||
if (manaCost.isPaid()) {
|
||||
this.execute();
|
||||
} else {
|
||||
String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", sa.getSourceCard(), sa.getSourceCard().getReplicateMagnitude());
|
||||
Input toSet = new InputPayManaExecuteCommands(game, prompt, manaCost.toString(), this, unpaidCommand);
|
||||
Singletons.getModel().getMatch().getInput().setInput(toSet);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Player controller = sp.getSourceCard().getController();
|
||||
if (controller.isHuman()) {
|
||||
sa.getSourceCard().addReplicateMagnitude(-1);
|
||||
paidCommand.execute();
|
||||
final Runnable addMagnitude = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ability.resolve();
|
||||
String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", sa.getSourceCard(), sa.getSourceCard().getReplicateMagnitude());
|
||||
InputPayManaExecuteCommands toSet = new InputPayManaExecuteCommands(game, prompt, sp.getReplicateManaCost());
|
||||
FThreads.setInputAndWait(toSet);
|
||||
if ( toSet.isPaid() ) {
|
||||
this.run();
|
||||
} else {
|
||||
for (int i = 0; i < sp.getSourceCard().getReplicateMagnitude(); i++) {
|
||||
CardFactory.copySpellontoStack(sp.getSourceCard(), sp.getSourceCard(), sp, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
addMagnitude.run();
|
||||
} else {
|
||||
// computer
|
||||
while (ComputerUtilCost.canPayCost(ability, controller)) {
|
||||
@@ -829,17 +694,18 @@ public class MagicStack extends MyObservable {
|
||||
final Card source = sa.getSourceCard();
|
||||
curResolvingCard = source;
|
||||
|
||||
if (this.hasFizzled(sa, source, false)) { // Fizzle
|
||||
|
||||
boolean thisHasFizzled = this.hasFizzled(sa, source, false);
|
||||
String messageForLog = thisHasFizzled ? source.getName() + " ability fizzles." : sa.getStackDescription();
|
||||
game.getGameLog().add("ResolveStack", messageForLog, 2);
|
||||
if (thisHasFizzled) { // Fizzle
|
||||
// TODO: Spell fizzles, what's the best way to alert player?
|
||||
Log.debug(source.getName() + " ability fizzles.");
|
||||
game.getGameLog().add("ResolveStack", source.getName() + " ability fizzles.", 2);
|
||||
this.finishResolving(sa, true);
|
||||
} else if (sa.getApi() != null) {
|
||||
game.getGameLog().add("ResolveStack", sa.getStackDescription(), 2);
|
||||
AbilityUtils.handleRemembering(sa);
|
||||
AbilityUtils.resolve(sa, true);
|
||||
} else {
|
||||
game.getGameLog().add("ResolveStack", sa.getStackDescription(), 2);
|
||||
sa.resolve();
|
||||
this.finishResolving(sa, false);
|
||||
// do creatures ETB from here?
|
||||
@@ -867,7 +733,7 @@ public class MagicStack extends MyObservable {
|
||||
if (creats.size() != 0) {
|
||||
haunterDiesWork.setDescription("");
|
||||
|
||||
final Input target = new Input() {
|
||||
final InputBase target = new InputBase() {
|
||||
private static final long serialVersionUID = 1981791992623774490L;
|
||||
|
||||
@Override
|
||||
@@ -1290,17 +1156,10 @@ 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);
|
||||
if (next.isTrigger()) {
|
||||
game.getActionPlay().playSpellAbility(next, activePlayer);
|
||||
} else {
|
||||
this.add(next);
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
@@ -1311,7 +1170,6 @@ public class MagicStack extends MyObservable {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ public class GuiChoose {
|
||||
}
|
||||
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
|
||||
if (null == choices || 0 == choices.size()) {
|
||||
if (null == choices || choices.isEmpty()) {
|
||||
if (0 == min) {
|
||||
return new ArrayList<T>();
|
||||
} else {
|
||||
|
||||
@@ -44,6 +44,7 @@ import forge.CardPredicates;
|
||||
import forge.CardUtil;
|
||||
import forge.Constant;
|
||||
import forge.CounterType;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.card.CardType;
|
||||
import forge.card.spellability.AbilityManaPart;
|
||||
@@ -611,7 +612,7 @@ public final class GuiDisplayUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
Card forgeCard = c.toForgeCard(p);
|
||||
final Card forgeCard = c.toForgeCard(p);
|
||||
|
||||
final GameState game = Singletons.getModel().getGame();
|
||||
if (forgeCard.getType().contains("Land")) {
|
||||
@@ -628,10 +629,15 @@ public final class GuiDisplayUtil {
|
||||
return; // happens if cancelled
|
||||
}
|
||||
|
||||
FThreads.invokeInNewThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sa.setActivatingPlayer(p);
|
||||
game.getAction().moveToHand(forgeCard); // this is really needed
|
||||
game.getActionPlay().playSpellAbilityWithoutPayingManaCost(sa);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,10 +21,12 @@ import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.FThreads;
|
||||
import forge.control.input.Input;
|
||||
import forge.game.GameState;
|
||||
import forge.game.MatchController;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.player.Player;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -38,36 +40,48 @@ public class InputProxy implements Observer {
|
||||
|
||||
/** The input. */
|
||||
private Input input;
|
||||
private boolean valid = false;
|
||||
private MatchController match = null;
|
||||
|
||||
public void setMatch(MatchController matchController) {
|
||||
match = matchController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized void update(final Observable observable, final Object obj) {
|
||||
ButtonUtil.disableAll();
|
||||
valid = false;
|
||||
this.input = null;
|
||||
final GameState game = match.getCurrentGame();
|
||||
final PhaseHandler ph = game.getPhaseHandler();
|
||||
|
||||
Singletons.getModel().getMatch().getInput().setNewInput(Singletons.getModel().getGame());
|
||||
//System.out.print((FThreads.isEDT() ? "EDT > " : "TRD > ") + ph.debugPrintState());
|
||||
if ( match.getInput().isEmpty() && ph.hasPhaseEffects()) {
|
||||
//System.out.println(" handle begin phase");
|
||||
FThreads.invokeInNewThread(new Runnable() {
|
||||
@Override public void run() {
|
||||
ph.handleBeginPhase();
|
||||
update(observable, obj);
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>input</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* a {@link forge.control.input.Input} object.
|
||||
*/
|
||||
public final synchronized void setInput(final Input in) {
|
||||
valid = true;
|
||||
this.input = in;
|
||||
this.input.showMessage(); // this call may invalidate the input by the time it returns
|
||||
}, true);
|
||||
return;
|
||||
}
|
||||
|
||||
final Input nextInput = match.getInput().getActualInput(game);
|
||||
//System.out.printf(" input is %s \t stack = %s%n", nextInput == null ? "null" : nextInput.getClass().getSimpleName(), match.getInput().printInputStack());
|
||||
|
||||
if (nextInput != null) {
|
||||
this.input = nextInput;
|
||||
FThreads.invokeInEDT(new Runnable() { @Override public void run() { nextInput.showMessage(); } });
|
||||
} else if (!ph.isPlayerPriorityAllowed()) {
|
||||
ph.getPriorityPlayer().getController().passPriority();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* selectButtonOK.
|
||||
* </p>
|
||||
*/
|
||||
public final void selectButtonOK() {
|
||||
this.getInput().selectButtonOK();
|
||||
if ( null == input ) return;
|
||||
input.selectButtonOK();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +90,8 @@ public class InputProxy implements Observer {
|
||||
* </p>
|
||||
*/
|
||||
public final void selectButtonCancel() {
|
||||
this.getInput().selectButtonCancel();
|
||||
if ( null == input ) return;
|
||||
input.selectButtonCancel();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +103,8 @@ public class InputProxy implements Observer {
|
||||
* a {@link forge.game.player.Player} object.
|
||||
*/
|
||||
public final void selectPlayer(final Player player) {
|
||||
this.getInput().selectPlayer(player);
|
||||
if ( null == input ) return;
|
||||
input.selectPlayer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,22 +118,19 @@ public class InputProxy implements Observer {
|
||||
* a {@link forge.game.zone.PlayerZone} object.
|
||||
*/
|
||||
public final void selectCard(final Card card) {
|
||||
this.getInput().selectCard(card);
|
||||
if ( null == input ) return;
|
||||
input.selectCard(card);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final String toString() {
|
||||
return this.getInput().toString();
|
||||
if ( null == input ) return "(null)";
|
||||
return this.input.toString();
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.InputProxy.Input} */
|
||||
/** @return {@link forge.gui.InputProxy.InputBase} */
|
||||
public Input getInput() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
|
||||
public synchronized boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.GameEntity;
|
||||
import forge.ImageCache;
|
||||
import forge.Singletons;
|
||||
@@ -181,7 +181,8 @@ public enum CMatchUI {
|
||||
* @param blockers   {@link forge.CardList}
|
||||
* @param damage   int
|
||||
*/
|
||||
public Map<Card, Integer> getDamageToAssign(final Card attacker, final List<Card> blockers, final int damage, GameEntity defender) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<Card, Integer> getDamageToAssign(final Card attacker, final List<Card> blockers, final int damage, final GameEntity defender) {
|
||||
if (damage <= 0) {
|
||||
return new HashMap<Card, Integer>();
|
||||
}
|
||||
@@ -194,8 +195,15 @@ public enum CMatchUI {
|
||||
return res;
|
||||
}
|
||||
|
||||
final Object[] result = { null }; // how else can I extract a value from EDT thread?
|
||||
FThreads.invokeInEDTAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO Auto-generated method stub
|
||||
VAssignDamage v = new VAssignDamage(attacker, blockers, damage, defender);
|
||||
return v.getDamageMap();
|
||||
result[0] = v.getDamageMap();
|
||||
}});
|
||||
return (Map<Card, Integer>)result[0];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,7 @@ import forge.Card;
|
||||
import forge.CardCharacteristicName;
|
||||
import forge.Command;
|
||||
import forge.Constant;
|
||||
import forge.FThreads;
|
||||
import forge.Constant.Preferences;
|
||||
import forge.Singletons;
|
||||
import forge.card.cardfactory.CardFactory;
|
||||
@@ -41,10 +42,6 @@ import forge.control.input.Input;
|
||||
import forge.control.input.InputAttack;
|
||||
import forge.control.input.InputBlock;
|
||||
import forge.control.input.InputPayManaBase;
|
||||
import forge.control.input.InputPayManaExecuteCommands;
|
||||
import forge.control.input.InputPayManaSimple;
|
||||
import forge.control.input.InputPaySacCost;
|
||||
import forge.game.GameState;
|
||||
import forge.game.phase.CombatUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
@@ -56,6 +53,7 @@ import forge.gui.framework.ICDoc;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.view.arcane.CardPanel;
|
||||
|
||||
/**
|
||||
* Controls Swing components of a player's field instance.
|
||||
@@ -144,6 +142,7 @@ public class CField implements ICDoc {
|
||||
private final Observer observerPlay = new Observer() {
|
||||
@Override
|
||||
public void update(final Observable a, final Object b) {
|
||||
//FThreads.checkEDT("observerPlay.update", true);
|
||||
CField.this.view.getTabletop().setupPlayZone();
|
||||
}
|
||||
};
|
||||
@@ -344,10 +343,11 @@ public class CField implements ICDoc {
|
||||
if ( CField.this.player != CField.this.playerViewer )
|
||||
return;
|
||||
|
||||
final GameState game = Singletons.getModel().getGame();
|
||||
SpellAbility ab = player.getController().getAbilityToPlay(game.getAbilitesOfCard(c, player));
|
||||
final SpellAbility ab = player.getController().getAbilityToPlay(player.getGame().getAbilitesOfCard(c, player));
|
||||
if ( null != ab) {
|
||||
FThreads.invokeInNewThread(new Runnable(){ @Override public void run(){
|
||||
player.playSpellAbility(c, ab);
|
||||
}});
|
||||
}
|
||||
}
|
||||
}.actionPerformed(null);
|
||||
@@ -390,10 +390,14 @@ public class CField implements ICDoc {
|
||||
|
||||
final Input input = CMessage.SINGLETON_INSTANCE.getInputControl().getInput();
|
||||
|
||||
if (c != null && c.isInZone(ZoneType.Battlefield)) {
|
||||
if (c.isTapped() && (input instanceof InputPayManaSimple || input instanceof InputPayManaExecuteCommands)) {
|
||||
final forge.view.arcane.CardPanel cardPanel = CField.this.view.getTabletop().getCardPanel(c.getUniqueNumber());
|
||||
for (final forge.view.arcane.CardPanel cp : cardPanel.getAttachedPanels()) {
|
||||
if (c == null || !c.isInZone(ZoneType.Battlefield)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Why does CField filter cards here? That's Input's responsibility to detect incorrect choices!
|
||||
if (c.isTapped() && input instanceof InputPayManaBase) {
|
||||
final CardPanel cardPanel = CField.this.view.getTabletop().getCardPanel(c.getUniqueNumber());
|
||||
for (final CardPanel cp : cardPanel.getAttachedPanels()) {
|
||||
if (cp.getCard().isUntapped()) {
|
||||
break;
|
||||
}
|
||||
@@ -402,9 +406,8 @@ public class CField implements ICDoc {
|
||||
|
||||
final List<Card> att = Singletons.getModel().getGame().getCombat().getAttackerList();
|
||||
if ((c.isTapped() || c.hasSickness() || (c.hasKeyword("Vigilance") && att.contains(c))) && (input instanceof InputAttack)) {
|
||||
final forge.view.arcane.CardPanel cardPanel = CField.this.view.getTabletop().getCardPanel(
|
||||
c.getUniqueNumber());
|
||||
for (final forge.view.arcane.CardPanel cp : cardPanel.getAttachedPanels()) {
|
||||
final CardPanel cardPanel = CField.this.view.getTabletop().getCardPanel(c.getUniqueNumber());
|
||||
for (final CardPanel cp : cardPanel.getAttachedPanels()) {
|
||||
if (cp.getCard().isUntapped() && !cp.getCard().hasSickness()) {
|
||||
break;
|
||||
}
|
||||
@@ -412,8 +415,7 @@ public class CField implements ICDoc {
|
||||
}
|
||||
|
||||
if (e.isMetaDown()) {
|
||||
if (att.contains(c) && (input instanceof InputAttack)
|
||||
&& !c.hasKeyword("CARDNAME attacks each turn if able.")) {
|
||||
if (att.contains(c) && input instanceof InputAttack && !c.hasKeyword("CARDNAME attacks each turn if able.")) {
|
||||
c.untap();
|
||||
Singletons.getModel().getGame().getCombat().removeFromCombat(c);
|
||||
CombatUtil.showCombat();
|
||||
@@ -424,10 +426,7 @@ public class CField implements ICDoc {
|
||||
((InputBlock) input).removeFromAllBlocking(c);
|
||||
CombatUtil.showCombat();
|
||||
}
|
||||
else if (input instanceof InputPaySacCost) {
|
||||
((InputPaySacCost) input).unselectCard(c, Singletons.getControl().getPlayer().getZone(ZoneType.Battlefield));
|
||||
}
|
||||
} else {
|
||||
} else if ( input != null ){
|
||||
//Yosei, the Morning Star required cards to be chosen on computer side
|
||||
//earlier it was enforced that cards must be in player zone
|
||||
//this can potentially break some other functionality
|
||||
@@ -437,7 +436,7 @@ public class CField implements ICDoc {
|
||||
//in weird case card has no controller revert to default behaviour
|
||||
input.selectCard(c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
@@ -459,6 +459,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
|
||||
* collection of all symbols) and the preferred (which may be
|
||||
@@ -487,19 +507,12 @@ public enum FSkin {
|
||||
if (FSkin.preferredName.isEmpty()) { FSkin.loadLight("default"); }
|
||||
|
||||
// Everything OK?
|
||||
final FProgressBar barProgress = FView.SINGLETON_INSTANCE.getSplash().getProgressBar();
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
barProgress.reset();
|
||||
barProgress.setShowETA(false);
|
||||
barProgress.setDescription("Processing image sprites: ");
|
||||
}
|
||||
});
|
||||
final FProgressBar barProgress = FView.SINGLETON_INSTANCE.getSplash().getProgressBar();
|
||||
setProgessBarMessage("Processing image sprites: ", 4);
|
||||
|
||||
|
||||
// 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();
|
||||
|
||||
@@ -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 {
|
||||
@@ -400,6 +401,7 @@ public enum FModel {
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param players
|
||||
* @param input
|
||||
*/
|
||||
public GameState newGame(Iterable<LobbyPlayer> players, GameType type, final MatchController match0) {
|
||||
gameState = new GameState(players,type, match0);
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* The files in the directory "net/slightlymagic/braids" and in all subdirectories of it (the "Files") are
|
||||
* Copyright 2011 Braids Cabal-Conjurer. They are available under either Forge's
|
||||
* main license (the GNU Public License; see LICENSE.txt in Forge's top directory)
|
||||
* or under the Apache License, as explained below.
|
||||
*
|
||||
* The Files are additionally licensed under the Apache License, Version 2.0 (the
|
||||
* "Apache License"); you may not use the files in this directory except in
|
||||
* compliance with one of its two licenses. You may obtain a copy of the Apache
|
||||
* License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the Apache License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the Apache License for the specific language governing permissions and
|
||||
* limitations under the Apache License.
|
||||
*
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/**
|
||||
* Some general-purpose functions.
|
||||
*/
|
||||
public final class ThreadUtil {
|
||||
|
||||
/**
|
||||
* Invoke the given Runnable in an Event Dispatch Thread and wait for it to
|
||||
* finish; but <B>try to use SwingUtilities.invokeLater instead whenever
|
||||
* feasible.</B>
|
||||
*
|
||||
* Exceptions generated by SwingUtilities.invokeAndWait (if used), are
|
||||
* rethrown as RuntimeExceptions.
|
||||
*
|
||||
* @param proc
|
||||
* the Runnable to run
|
||||
* @see javax.swing.SwingUtilities#invokeLater(Runnable)
|
||||
*/
|
||||
public static void invokeInEventDispatchThreadAndWait(final Runnable proc) {
|
||||
// by
|
||||
// Braids
|
||||
// on
|
||||
// 8/18/11
|
||||
// 11:19
|
||||
// PM
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
// Just run in the current thread.
|
||||
proc.run();
|
||||
} else {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(proc);
|
||||
} catch (final InterruptedException exn) {
|
||||
throw new RuntimeException(exn);
|
||||
// 11:19 PM
|
||||
} catch (final InvocationTargetException exn) {
|
||||
throw new RuntimeException(exn);
|
||||
// 11:19 PM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -24,10 +24,12 @@ import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.view.arcane.util.Animation;
|
||||
import forge.view.arcane.util.CardPanelMouseListener;
|
||||
|
||||
@@ -497,7 +499,27 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
* @param newList
|
||||
* an array of {@link forge.Card} objects.
|
||||
*/
|
||||
private final AtomicBoolean wantRedraw = new AtomicBoolean(false);
|
||||
public void setupPlayZone() {
|
||||
boolean wasSet = wantRedraw.getAndSet(true);
|
||||
if(wasSet) return;
|
||||
FThreads.invokeInEDT(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try { // user won't notice, but the requests coming in that interval won't trigger re-draw
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
wantRedraw.set(false);
|
||||
final List<Card> modelshot = new ArrayList<Card>(model); // I am afraid of ConcurrentModificationExceptions
|
||||
setupPlayZone(modelshot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void setupPlayZone(final List<Card> model) {
|
||||
List<Card> oldCards, toDelete;
|
||||
oldCards = new ArrayList<Card>();
|
||||
for (final CardPanel cpa : getCardPanels()) {
|
||||
|
||||
Reference in New Issue
Block a user