diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java
index b382f4bb0ef..0334ed72fc7 100644
--- a/forge-ai/src/main/java/forge/ai/AiController.java
+++ b/forge-ai/src/main/java/forge/ai/AiController.java
@@ -97,7 +97,6 @@ import forge.util.MyRandom;
* @version $Id$
*/
public class AiController {
-
private final Player player;
private final Game game;
private final AiCardMemory memory;
@@ -111,13 +110,11 @@ public class AiController {
this.bCheatShuffle = canCheatShuffle;
}
- public Game getGame()
- {
+ public Game getGame() {
return game;
}
- public Player getPlayer()
- {
+ public Player getPlayer() {
return player;
}
@@ -125,24 +122,12 @@ public class AiController {
return memory;
}
- /**
- *
- * Constructor for ComputerAI_General.
- *
- */
public AiController(final Player computerPlayer, final Game game0) {
player = computerPlayer;
game = game0;
memory = new AiCardMemory();
}
- /**
- *
- * getAvailableSpellAbilities.
- *
- *
- * @return a {@link forge.CardList} object.
- */
private CardCollection getAvailableCards() {
CardCollection all = new CardCollection(player.getCardsIn(ZoneType.Hand));
@@ -158,13 +143,6 @@ public class AiController {
return all;
}
- /**
- *
- * getPossibleETBCounters.
- *
- *
- * @return a {@link java.util.ArrayList} object.
- */
private ArrayList getPossibleETBCounters() {
final Player opp = player.getOpponent();
CardCollection all = new CardCollection(player.getCardsIn(ZoneType.Hand));
@@ -348,13 +326,10 @@ public class AiController {
return false;
}
}
-
return true;
}
-
-
- private ArrayList getOriginalAndAltCostAbilities(final ArrayList originList)
- {
+
+ private ArrayList getOriginalAndAltCostAbilities(final ArrayList originList) {
final ArrayList newAbilities = new ArrayList();
for (SpellAbility sa : originList) {
sa.setActivatingPlayer(player);
@@ -371,13 +346,6 @@ public class AiController {
return result;
}
- /**
- * Returns the spellAbilities from the card list.
- *
- * @param l
- * a {@link forge.CardList} object.
- * @return an array of {@link forge.game.spellability.SpellAbility} objects.
- */
private ArrayList getSpellAbilities(final CardCollectionView l) {
final ArrayList spellAbilities = new ArrayList();
for (final Card c : l) {
@@ -388,15 +356,6 @@ public class AiController {
return spellAbilities;
}
- /**
- *
- * getPlayableCounters.
- *
- *
- * @param l
- * a {@link forge.CardList} object.
- * @return a {@link java.util.ArrayList} object.
- */
private ArrayList getPlayableCounters(final CardCollection l) {
final ArrayList spellAbility = new ArrayList();
for (final Card c : l) {
@@ -407,20 +366,11 @@ public class AiController {
}
}
}
-
return spellAbility;
}
// plays a land if one is available
- /**
- *
- * chooseLandsToPlay.
- *
- *
- * @return a boolean.
- */
public CardCollection getLandsToPlay() {
-
final CardCollection hand = new CardCollection(player.getCardsIn(ZoneType.Hand));
hand.addAll(player.getCardsIn(ZoneType.Exile));
CardCollection landList = CardLists.filter(hand, Presets.LANDS);
@@ -506,15 +456,13 @@ public class AiController {
return true;
}
});
-
return landList;
}
- public Card chooseBestLandToPlay(CardCollection landList)
- {
- if (landList.isEmpty())
+ public Card chooseBestLandToPlay(CardCollection landList) {
+ if (landList.isEmpty()) {
return null;
-
+ }
//Skip reflected lands.
CardCollection unreflectedLands = new CardCollection(landList);
for (Card l : landList) {
@@ -594,23 +542,13 @@ public class AiController {
}
// if return true, go to next phase
- /**
- *
- * playCounterSpell.
- *
- *
- * @param possibleCounters
- * a {@link java.util.ArrayList} object.
- * @return a boolean.
- */
private SpellAbility chooseCounterSpell(final ArrayList possibleCounters) {
- if (possibleCounters == null || possibleCounters.isEmpty())
- return null;;
-
+ if (possibleCounters == null || possibleCounters.isEmpty()) {
+ return null;
+ }
SpellAbility bestSA = null;
int bestRestriction = Integer.MIN_VALUE;
-
for (final SpellAbility sa : getOriginalAndAltCostAbilities(possibleCounters)) {
SpellAbility currentSA = sa;
sa.setActivatingPlayer(player);
@@ -639,7 +577,7 @@ public class AiController {
// TODO - "Look" at Targeted SA and "calculate" the threshold
// if (bestRestriction < targetedThreshold) return false;
return bestSA;
- } // playCounterSpell()
+ }
public SpellAbility predictSpellToCastInMain2(ApiType exceptSA) {
return predictSpellToCastInMain2(exceptSA, true);
@@ -651,10 +589,10 @@ public class AiController {
}
final CardCollectionView cards = handOnly ? player.getCardsIn(ZoneType.Hand) : getAvailableCards();
-
+
ArrayList all = getSpellAbilities(cards);
Collections.sort(all, saComparator); // put best spells first
-
+
for (final SpellAbility sa : getOriginalAndAltCostAbilities(all)) {
if (sa.getApi() == ApiType.Counter || sa.getApi() == exceptSA) {
continue;
@@ -669,7 +607,6 @@ public class AiController {
}
}
}
-
return null;
}
@@ -680,7 +617,7 @@ public class AiController {
((PlayerControllerAi)player.getController()).getAi().getCardMemory().rememberCard(c, AiCardMemory.MemorySet.HELD_MANA_SOURCES);
}
}
-
+
// This is for playing spells regularly (no Cascade/Ripple etc.)
private AiPlayDecision canPlayAndPayFor(final SpellAbility sa) {
if (!sa.canPlay()) {
@@ -693,7 +630,7 @@ public class AiController {
}
return ComputerUtilCost.canPayCost(sa, player) ? AiPlayDecision.WillPlay : AiPlayDecision.CantAfford;
}
-
+
public AiPlayDecision canPlaySa(SpellAbility sa) {
final Card card = sa.getHostCard();
if (sa instanceof WrappedAbility) {
@@ -701,9 +638,11 @@ public class AiController {
}
if (sa.getApi() != null) {
boolean canPlay = SpellApiToAi.Converter.get(sa.getApi()).canPlayAIWithSubs(player, sa);
- if (!canPlay)
+ if (!canPlay) {
return AiPlayDecision.CantPlayAi;
- } else if (sa.getPayCosts() != null){
+ }
+ }
+ else if (sa.getPayCosts() != null){
Cost payCosts = sa.getPayCosts();
ManaCost mana = payCosts.getTotalMana();
if (mana!= null && mana.countX() > 0) {
@@ -796,9 +735,9 @@ public class AiController {
}
}
}
-
return canPlayFromEffectAI((SpellPermanent)sa, false, true);
- } else if (sa instanceof Spell) {
+ }
+ if (sa instanceof Spell) {
return canPlaySpellBasic(card);
}
return AiPlayDecision.WillPlay;
@@ -901,22 +840,8 @@ public class AiController {
return p;
}
- }; // Comparator
-
- /**
- *
- * AI_discardNumType.
- *
- *
- * @param numDiscard
- * a int.
- * @param uTypes
- * an array of {@link java.lang.String} objects. May be null for
- * no restrictions.
- * @param sa
- * a {@link forge.game.spellability.SpellAbility} object.
- * @return a CardCollection of discarded cards.
- */
+ };
+
public CardCollection getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa) {
CardCollection hand = new CardCollection(player.getCardsIn(ZoneType.Hand));
if ((uTypes != null) && (sa != null)) {
@@ -981,7 +906,8 @@ public class AiController {
if (canDiscardLands) {
discardList.add(landsInHand.get(0));
validCards.remove(landsInHand.get(0));
- } else { // Discard other stuff
+ }
+ else { // Discard other stuff
CardLists.sortByCmcDesc(validCards);
int numLandsAvailable = numLandsInPlay;
if (numLandsInHand > 0) {
@@ -991,7 +917,8 @@ public class AiController {
if (validCards.get(0).getCMC() > numLandsAvailable) {
discardList.add(validCards.get(0));
validCards.remove(validCards.get(0));
- } else { //Discard worst card
+ }
+ else { //Discard worst card
Card worst = ComputerUtilCard.getWorstAI(validCards);
discardList.add(worst);
validCards.remove(worst);
@@ -1006,41 +933,37 @@ public class AiController {
ApiType api = sa.getApi();
// Abilities without api may also use this routine, However they should provide a unique mode value
- if (null == api) {
+ if (api == null) {
if (mode != null) switch (mode) {
// case BraidOfFire: return true;
// case Ripple: return true;
}
-
String exMsg = String.format("AI confirmAction does not know what to decide about %s mode (api is null).", mode);
throw new IllegalArgumentException(exMsg);
-
- } else
- return SpellApiToAi.Converter.get(api).confirmAction(player, sa, mode, message);
+ }
+ return SpellApiToAi.Converter.get(api).confirmAction(player, sa, mode, message);
}
- public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String message,
- int bid, Player winner) {
+ public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, int bid, Player winner) {
if (mode != null) switch (mode) {
case BidLife:
if (sa.hasParam("AIBidMax")) {
return !player.equals(winner) && bid < Integer.parseInt(sa.getParam("AIBidMax")) && player.getLife() > bid + 5;
- } else {
- return false;
}
+ return false;
default:
return false;
}
return false;
}
-
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
if (logic.equalsIgnoreCase("ProtectFriendly")) {
final Player controller = hostCard.getController();
if (affected instanceof Player) {
return !((Player) affected).isOpponentOf(controller);
- } else if (affected instanceof Card) {
+ }
+ if (affected instanceof Card) {
return !((Card) affected).getController().isOpponentOf(controller);
}
}
@@ -1084,28 +1007,30 @@ public class AiController {
if (AiPlayDecision.WillPlay != canPlayFromEffectAI((Spell) sa, mandatory, withoutPayingManaCost)) {
continue;
}
- } else {
+ }
+ else {
if (AiPlayDecision.WillPlay == canPlaySa(sa)) {
continue;
}
}
-
- if (withoutPayingManaCost)
+
+ if (withoutPayingManaCost) {
ComputerUtil.playSpellAbilityWithoutPayingManaCost(player, sa, game);
- else if (!ComputerUtilCost.canPayCost(sa, player))
+ }
+ else if (!ComputerUtilCost.canPayCost(sa, player)) {
continue;
- else
+ }
+ else {
ComputerUtil.playStack(sa, player, game);
+ }
return sa;
}
return null;
}
-
+
public AiPlayDecision canPlayFromEffectAI(Spell spell, boolean mandatory, boolean withoutPayingManaCost) {
-
final Card card = spell.getHostCard();
- if (spell instanceof SpellApiBased)
- {
+ if (spell instanceof SpellApiBased) {
boolean chance = false;
if (withoutPayingManaCost) {
chance = SpellApiToAi.Converter.get(spell.getApi()).doTriggerNoCostWithSubs(player, spell, mandatory);
@@ -1184,7 +1109,7 @@ public class AiController {
return canPlaySpellBasic(card);
}
- public SpellAbility chooseSpellAbilityToPlay() {
+ public List chooseSpellAbilityToPlay() {
final PhaseType phase = game.getPhaseHandler().getPhase();
if (game.getStack().isEmpty() && phase.isMain()) {
@@ -1194,14 +1119,21 @@ public class AiController {
Card land = chooseBestLandToPlay(landsWannaPlay);
if (ComputerUtil.damageFromETB(player, land) < player.getLife() || !player.canLoseLife()) {
Ability.PLAY_LAND_SURROGATE.setHostCard(land);
- return Ability.PLAY_LAND_SURROGATE;
+ final List abilities = new ArrayList();
+ abilities.add(Ability.PLAY_LAND_SURROGATE);
+ return abilities;
}
}
}
SpellAbility sa = getSpellAbilityToPlay();
+ if (sa == null) { return null; }
+
// System.out.println("Chosen to play: " + sa);
- return sa;
+
+ final List abilities = new ArrayList();
+ abilities.add(sa);
+ return abilities;
}
// declares blockers for given defender in a given combat
diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
index 2b930e0882e..0b3c19ce75b 100644
--- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
+++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
@@ -381,7 +381,7 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
- public SpellAbility chooseSpellAbilityToPlay() {
+ public List chooseSpellAbilityToPlay() {
return brains.chooseSpellAbilityToPlay();
}
diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
index cefb207e1ba..7e231ce08ab 100644
--- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
+++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
@@ -19,6 +19,7 @@ package forge.game.phase;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
+
import forge.card.mana.ManaCost;
import forge.game.*;
import forge.game.ability.AbilityFactory;
@@ -881,7 +882,7 @@ public class PhaseHandler implements java.io.Serializable {
}
game.fireEvent(new GameEventPlayerPriority(playerTurn, phase, getPriorityPlayer()));
- SpellAbility chosenSa = null;
+ List chosenSa = null;
int loopCount = 0;
do {
@@ -913,7 +914,9 @@ public class PhaseHandler implements java.io.Serializable {
System.out.print("... " + pPlayerPriority + " plays " + chosenSa);
}
pFirstPriority = pPlayerPriority; // all opponents have to pass before stack is allowed to resolve
- pPlayerPriority.getController().playChosenSpellAbility(chosenSa);
+ for (SpellAbility sa : chosenSa) {
+ pPlayerPriority.getController().playChosenSpellAbility(sa);
+ }
loopCount++;
} while (chosenSa != null && (loopCount < 999 || !pPlayerPriority.getController().isAI()));
diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java
index dde973164ea..10c14fc2709 100644
--- a/forge-game/src/main/java/forge/game/player/PlayerController.java
+++ b/forge-game/src/main/java/forge/game/player/PlayerController.java
@@ -233,7 +233,7 @@ public abstract class PlayerController {
public abstract void declareAttackers(Player attacker, Combat combat);
public abstract void declareBlockers(Player defender, Combat combat);
- public abstract SpellAbility chooseSpellAbilityToPlay();
+ public abstract List chooseSpellAbilityToPlay();
public abstract void playChosenSpellAbility(SpellAbility sa);
public abstract CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard);
diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java
index 3f452423ed5..3f141f0af19 100644
--- a/forge-game/src/main/java/forge/game/zone/MagicStack.java
+++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java
@@ -130,7 +130,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable chooseSpellAbilityToPlay() {
//TODO: This method has to return the spellability chosen by player
// It should not play the sa right from here. The code has been left as it is to quickly adapt to changed playercontroller interface
if (playerActions != null) {
diff --git a/forge-gui/src/main/java/forge/match/input/InputPassPriority.java b/forge-gui/src/main/java/forge/match/input/InputPassPriority.java
index 45ae4fccc72..51a43ab6f9a 100644
--- a/forge-gui/src/main/java/forge/match/input/InputPassPriority.java
+++ b/forge-gui/src/main/java/forge/match/input/InputPassPriority.java
@@ -44,9 +44,9 @@ public class InputPassPriority extends InputSyncronizedBase {
/** Constant serialVersionUID=-581477682214137181L. */
private static final long serialVersionUID = -581477682214137181L;
private final Player player;
-
- private SpellAbility chosenSa;
-
+
+ private List chosenSa;
+
public InputPassPriority(final PlayerControllerHuman controller, final Player human) {
super(controller);
player = human;
@@ -122,7 +122,7 @@ public class InputPassPriority extends InputSyncronizedBase {
runnable.run(); //just pass priority immediately if no mana floating that would be lost
}
- public SpellAbility getChosenSa() { return chosenSa; }
+ public List getChosenSa() { return chosenSa; }
@Override
protected boolean onCardSelected(final Card card, final List otherCardsToSelect, final ITriggerEvent triggerEvent) {
@@ -133,30 +133,22 @@ public class InputPassPriority extends InputSyncronizedBase {
}
final SpellAbility ability = player.getController().getAbilityToPlay(abilities, triggerEvent);
- if (selectAbility(ability)) {
+ if (ability != null) {
+ chosenSa = new ArrayList();
+ chosenSa.add(ability);
if (otherCardsToSelect != null && ability.isManaAbility()) {
//if mana ability activated, activate same ability on other cards to select if possible
String abStr = ability.toUnsuppressedString();
- final List otherAbilitiesToPlay = new ArrayList();
for (Card c : otherCardsToSelect) {
for (SpellAbility ab : c.getAllPossibleAbilities(player, true)) {
if (ab.toUnsuppressedString().equals(abStr)) {
- otherAbilitiesToPlay.add(ab);
+ chosenSa.add(ab);
break;
}
}
}
- if (otherAbilitiesToPlay.size() > 0) {
- ThreadUtil.invokeInGameThread(new Runnable() { //must execute other abilities on game thread
- @Override
- public void run() {
- for (SpellAbility ab : otherAbilitiesToPlay) {
- player.getController().playChosenSpellAbility(ab);
- }
- }
- });
- }
}
+ stop();
return true;
}
return false;
@@ -165,7 +157,8 @@ public class InputPassPriority extends InputSyncronizedBase {
@Override
public boolean selectAbility(final SpellAbility ab) {
if (ab != null) {
- chosenSa = ab;
+ chosenSa = new ArrayList();
+ chosenSa.add(ab);
stop();
return true;
}
diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
index 9d3827b1466..5233badd2d9 100644
--- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
+++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
@@ -834,7 +834,7 @@ public class PlayerControllerHuman extends PlayerController {
}
@Override
- public SpellAbility chooseSpellAbilityToPlay() {
+ public List chooseSpellAbilityToPlay() {
MagicStack stack = game.getStack();
if (mayAutoPass()) {