(c0.getController().getCardsIn(ZoneType.Hand));
- for (Card c : hand) {
- game.getAction().exile(c);
- }
- c0.getController().drawCards(hand.size());
- }
- else
- {
- lastExiled.add(c0);
- c0.setUsedToPay(true);
- }
- } else {
- lastExiled.add(c0);
- c0.setUsedToPay(true);
- }
- }
-
- if(lastExiled.size() > 0)
- ButtonUtil.enableAllFocusOk();
- else
- ButtonUtil.enableOnlyOk();
- }
-}
diff --git a/src/main/java/forge/control/input/InputQueue.java b/src/main/java/forge/control/input/InputQueue.java
index 1a079c1a8e2..4abe9435004 100644
--- a/src/main/java/forge/control/input/InputQueue.java
+++ b/src/main/java/forge/control/input/InputQueue.java
@@ -19,12 +19,8 @@ package forge.control.input;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
-
-import forge.Singletons;
import forge.game.GameAge;
import forge.game.GameState;
-import forge.game.GameType;
-import forge.game.MatchController;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -46,10 +42,8 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
private final BlockingDeque inputStack = new LinkedBlockingDeque();
- private final MatchController match;
- public InputQueue(MatchController matchController) {
- match = matchController;
- }
+
+ public InputQueue() {}
/**
*
@@ -125,12 +119,7 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
*/
public final Input getActualInput(GameState game) {
GameAge age = game.getAge();
- if ( age == GameAge.Mulligan ) {
- Player human = Singletons.getControl().getPlayer();
- return game.getType() == GameType.Commander ? new InputMulliganPartialParis(match, human) : new InputMulligan(match, human);
- }
-
- if ( age != GameAge.Play )
+ if ( age != GameAge.Play && age != GameAge.Mulligan)
return inputLock;
Input topMost = inputStack.peek(); // incoming input to Control
diff --git a/src/main/java/forge/game/GameAction.java b/src/main/java/forge/game/GameAction.java
index 991ad38bfcd..09dbfa1a877 100644
--- a/src/main/java/forge/game/GameAction.java
+++ b/src/main/java/forge/game/GameAction.java
@@ -18,15 +18,17 @@
package forge.game;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
+import java.util.Map.Entry;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import forge.Card;
import forge.CardCharacteristicName;
@@ -61,13 +63,15 @@ import forge.game.event.CardSacrificedEvent;
import forge.game.player.GameLossReason;
import forge.game.player.HumanPlay;
import forge.game.player.Player;
-import forge.game.player.PlayerType;
import forge.game.zone.PlayerZone;
import forge.game.zone.PlayerZoneBattlefield;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.gui.GuiDialog;
+import forge.util.maps.CollectionSuppliers;
+import forge.util.maps.HashMapOfLists;
+import forge.util.maps.MapOfLists;
/**
* Methods for common actions performed during a game.
@@ -1466,13 +1470,56 @@ public class GameAction {
game.getAction().checkStateEffects();
}
- /**
- *
- * playCardWithoutManaCost.
- *
- *
- * @param c
- * a {@link forge.Card} object.
- */
+ public void performMulligans(final Player firstPlayer, final boolean isCommander) {
+ List whoCanMulligan = Lists.newArrayList(game.getPlayers());
+ int offset = whoCanMulligan.indexOf(firstPlayer);
+
+ // Have to cycle-shift the list to get the first player on index 0
+ for( int i = 0; i < offset; i++ ) {
+ whoCanMulligan.add(whoCanMulligan.remove(0));
+ }
+
+ MapOfLists exiledDuringMulligans = new HashMapOfLists(CollectionSuppliers.arrayLists());
+
+ do {
+ for (int i = 0; i < whoCanMulligan.size(); i++) {
+ Player p = whoCanMulligan.get(i);
+ List toMulligan = p.canMulligan() ? p.getController().getCardsToMulligan(isCommander) : null;
+ if ( toMulligan != null ) {
+ if( !isCommander ) {
+ toMulligan = new ArrayList(p.getCardsIn(ZoneType.Hand));
+ for (final Card c : toMulligan) {
+ moveToLibrary(c);
+ }
+ p.shuffle();
+ p.drawCards(toMulligan.size() - 1);
+
+ } else if ( !toMulligan.isEmpty() ){
+ List toExile = Lists.newArrayList(toMulligan);
+ for(Card c : toExile) {
+ exile(c);
+ }
+ exiledDuringMulligans.addAll(p, toExile);
+ p.drawCards(toExile.size() - 1);
+ } else
+ continue;
+
+ p.onMulliganned();
+ } else {
+ whoCanMulligan.remove(i--);
+ }
+ }
+ } while( !whoCanMulligan.isEmpty() );
+
+ if( isCommander )
+ for(Entry> kv : exiledDuringMulligans.entrySet() ) {
+ Player p = kv.getKey();
+ Collection cc = kv.getValue();
+ for(Card c : cc) {
+ moveToLibrary(c);
+ }
+ p.shuffle();
+ }
+ }
}
diff --git a/src/main/java/forge/game/MatchController.java b/src/main/java/forge/game/MatchController.java
index 9f0c71857db..25b6cc6d0c0 100644
--- a/src/main/java/forge/game/MatchController.java
+++ b/src/main/java/forge/game/MatchController.java
@@ -138,7 +138,7 @@ public class MatchController {
*/
public void startRound() {
- inputQueue = new InputQueue(this);
+ inputQueue = new InputQueue();
currentGame = new GameState(players, gameType, this);
try {
@@ -146,16 +146,38 @@ public class MatchController {
final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed;
GameNew.newGame(currentGame, canRandomFoil);
- determineFirstTurnPlayer(getLastGameOutcome(), currentGame);
currentGame.setAge(GameAge.Mulligan);
- getInput().clearInput();
-
- // Update observers
- currentGame.getGameLog().updateObservers();
} catch (Exception e) {
BugReporter.reportException(e);
}
+
+ final Player firstPlayer = determineFirstTurnPlayer(getLastGameOutcome(), currentGame);
+
+ getInput().clearInput();
+ if(currentGame.getType() == GameType.Planechase)
+ firstPlayer.initPlane();
+
+ //Set Field shown to current player.
+ VField nextField = CMatchUI.SINGLETON_INSTANCE.getFieldViewFor(firstPlayer);
+ SDisplayUtil.showTab(nextField);
+
+ // Update observers
+ currentGame.getGameLog().updateObservers();
+
+ // This code was run from EDT.
+ FThreads.invokeInNewThread( new Runnable() {
+ @Override
+ public void run() {
+ currentGame.getAction().performMulligans(firstPlayer, currentGame.getType() == GameType.Commander);
+ currentGame.getAction().handleLeylinesAndChancellors();
+ // Run Trigger beginning of the game
+ final HashMap runParams = new HashMap();
+ currentGame.getTriggerHandler().runTrigger(TriggerType.NewGame, runParams, false);
+ currentGame.setAge(GameAge.Play);
+ getInput().clearInput();
+ }
+ });
}
public static void attachUiToMatch(MatchController match, LobbyPlayerHuman humanLobbyPlayer) {
@@ -328,22 +350,12 @@ public class MatchController {
return 10;
}
- public void afterMulligans()
- {
- currentGame.getAction().handleLeylinesAndChancellors();
- // Run Trigger beginning of the game
- final HashMap runParams = new HashMap();
- currentGame.getTriggerHandler().runTrigger(TriggerType.NewGame, runParams, false);
- currentGame.setAge(GameAge.Play);
- getInput().clearInput();
- }
-
/**
* TODO: Write javadoc for this method.
* @param match
* @param game
*/
- private void determineFirstTurnPlayer(final GameOutcome lastGameOutcome, final GameState game) {
+ private Player determineFirstTurnPlayer(final GameOutcome lastGameOutcome, final GameState game) {
// Only cut/coin toss if it's the first game of the match
Player goesFirst;
Player humanPlayer = Singletons.getControl().getPlayer();
@@ -360,6 +372,7 @@ public class MatchController {
}
goesFirst = willPlay ? goesFirst : goesFirst.getOpponent();
game.getPhaseHandler().setPlayerTurn(goesFirst);
+ return goesFirst;
}
// decides who goes first when starting another game, used by newGame()
diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java
index c7029421dcb..1717dd8cccb 100644
--- a/src/main/java/forge/game/player/Player.java
+++ b/src/main/java/forge/game/player/Player.java
@@ -1205,6 +1205,10 @@ public class Player extends GameEntity implements Comparable {
return this.drawCards(1);
}
+
+ public boolean canMulligan() {
+ return !getZone(ZoneType.Hand).isEmpty();
+ }
/**
*
* TODO Write javadoc for this method.
@@ -3123,4 +3127,15 @@ public class Player extends GameEntity implements Comparable {
public final void setHighlited(boolean value) { highlited = value; }
public final boolean isHighlited() { return highlited; }
+ /**
+ * TODO: Write javadoc for this method.
+ */
+ public void onMulliganned() {
+ game.getEvents().post(new MulliganEvent(this)); // quest listener may interfere here
+ final int newHand = getCardsIn(ZoneType.Hand).size();
+ game.getGameLog().add("Mulligan", this + " has mulliganed down to " + newHand + " cards.", 0);
+ stats.notifyHasMulliganed();
+ stats.notifyOpeningHandSize(newHand);
+ }
+
}
diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java
index 4fff5103646..33dd867b709 100644
--- a/src/main/java/forge/game/player/PlayerController.java
+++ b/src/main/java/forge/game/player/PlayerController.java
@@ -139,4 +139,5 @@ public abstract class PlayerController {
public abstract String chooseSomeType(String kindOfType, String aiLogic, List validTypes, List invalidTypes);
public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question);
+ public abstract List getCardsToMulligan(boolean isCommander);
}
diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java
index e4b92c9faaf..8a39395b0c5 100644
--- a/src/main/java/forge/game/player/PlayerControllerAi.java
+++ b/src/main/java/forge/game/player/PlayerControllerAi.java
@@ -287,5 +287,14 @@ public class PlayerControllerAi extends PlayerController {
return ReplacementEffect.aiShouldRun(replacementEffect, effectSA, player);
}
+ @Override
+ public List getCardsToMulligan(boolean isCommander) {
+ if( !ComputerUtil.wantMulligan(player) )
+ return null;
+ if (!isCommander)
+ return player.getCardsIn(ZoneType.Hand);
+ else
+ return ComputerUtil.getPartialParisCandidates(player);
+ }
}
diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java
index 50efced2318..bfeb8fe531d 100644
--- a/src/main/java/forge/game/player/PlayerControllerHuman.java
+++ b/src/main/java/forge/game/player/PlayerControllerHuman.java
@@ -22,6 +22,7 @@ import forge.card.spellability.TargetSelection;
import forge.control.input.Input;
import forge.control.input.InputBlock;
import forge.control.input.InputCleanup;
+import forge.control.input.InputConfirmMulligan;
import forge.control.input.InputPassPriority;
import forge.control.input.InputSelectCards;
import forge.control.input.InputSelectCardsFromList;
@@ -467,4 +468,11 @@ public class PlayerControllerHuman extends PlayerController {
return GuiDialog.confirm(replacementEffect.getHostCard(), question);
}
+
+ @Override
+ public List getCardsToMulligan(boolean isCommander) {
+ final InputConfirmMulligan inp = new InputConfirmMulligan(player, isCommander);
+ FThreads.setInputAndWait(inp);
+ return inp.isKeepHand() ? null : inp.getSelectedCards();
+ }
}
diff --git a/src/main/java/forge/gui/match/CMatchUI.java b/src/main/java/forge/gui/match/CMatchUI.java
index a3e01c5c358..3597cc94975 100644
--- a/src/main/java/forge/gui/match/CMatchUI.java
+++ b/src/main/java/forge/gui/match/CMatchUI.java
@@ -18,7 +18,6 @@
package forge.gui.match;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;