Merge branch 'master' into 'master'

Select cards from any Zone that can be shown and do arrangeForScry by popping up library and moving cards (in desktop GUI); Pass min/max card selections through to GUI

See merge request core-developers/forge!1260
This commit is contained in:
Michael Kamensky
2019-01-11 17:08:50 +00:00
19 changed files with 613 additions and 104 deletions

View File

@@ -162,7 +162,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public <T extends GameEntity> List<T> chooseEntitiesForEffect( public <T extends GameEntity> List<T> chooseEntitiesForEffect(
FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title,
Player targetedPlayer) { Player targetedPlayer) {
// this isn't used // this isn't used
return null; return null;
@@ -1090,7 +1090,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public List<Card> chooseCardsForZoneChange( public List<Card> chooseCardsForZoneChange(
ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, int min, int max,
DelayedReveal delayedReveal, String selectPrompt, Player decider) { DelayedReveal delayedReveal, String selectPrompt, Player decider) {
// this isn't used // this isn't used
return null; return null;

View File

@@ -86,7 +86,7 @@ public class Localizer {
resourceBundle = ResourceBundle.getBundle(languageRegionID, new Locale(splitLocale[0], splitLocale[1]), loader); resourceBundle = ResourceBundle.getBundle(languageRegionID, new Locale(splitLocale[0], splitLocale[1]), loader);
} catch (NullPointerException | MissingResourceException e) { } catch (NullPointerException | MissingResourceException e) {
//If the language can't be loaded, default to US English //If the language can't be loaded, default to US English
resourceBundle = ResourceBundle.getBundle("en-GB", new Locale("en", "GB"), loader); resourceBundle = ResourceBundle.getBundle("en-US", new Locale("en", "US"), loader);
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -852,7 +852,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
// ensure that selection is within maximum allowed changeNum // ensure that selection is within maximum allowed changeNum
do { do {
selectedCards = decider.getController().chooseCardsForZoneChange(destination, origin, sa, fetchList, delayedReveal, selectPrompt, decider); selectedCards = decider.getController().chooseCardsForZoneChange(destination, origin, sa, fetchList, 0, changeNum, delayedReveal, selectPrompt, decider);
} while (selectedCards != null && selectedCards.size() > changeNum); } while (selectedCards != null && selectedCards.size() > changeNum);
if (selectedCards != null) { if (selectedCards != null) {
for (Card card : selectedCards) { for (Card card : selectedCards) {

View File

@@ -111,7 +111,7 @@ public abstract class PlayerController {
public abstract SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title, public abstract SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title,
Map<String, Object> params); Map<String, Object> params);
public abstract <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer); public abstract <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer);
public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message); public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message);
public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner); public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner);
@@ -239,7 +239,7 @@ public abstract class PlayerController {
// better to have this odd method than those if playerType comparison in ChangeZone // better to have this odd method than those if playerType comparison in ChangeZone
public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider); public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider);
public abstract List<Card> chooseCardsForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, Player decider); public abstract List<Card> chooseCardsForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider);
public abstract void autoPassCancel(); public abstract void autoPassCancel();

View File

@@ -29,7 +29,7 @@ import forge.item.PaperCard;
import forge.model.FModel; import forge.model.FModel;
import forge.screens.match.CMatchUI; import forge.screens.match.CMatchUI;
import forge.toolbox.FOptionPane; import forge.toolbox.FOptionPane;
import forge.view.arcane.ListCardArea;
public class GuiChoose { public class GuiChoose {
@@ -285,5 +285,31 @@ public class GuiChoose {
return null; return null;
} }
public static List<Card> manipulateCardList(final CMatchUI gui, final String title, final List<Card> cards, final List<Card> manipulable,
final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
final Callable<List<Card>> callable = new Callable<List<Card>>() {
@Override
public List<Card> call() throws Exception {
ListCardArea tempArea = new ListCardArea(gui,title,cards,manipulable,toTop,toBottom,toAnywhere);
// tempArea.pack();
// window? tempArea.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
tempArea.show();
// tempArea.dispose();
//try { Thread.sleep(1000); } catch(InterruptedException ex) { }
final List<Card> cardList = tempArea.getCardList();
return cardList;
}
};
final FutureTask<List<Card>> ft = new FutureTask<List<Card>>(callable);
FThreads.invokeInEdtAndWait(ft);
try {
List<Card> result = ft.get();
return result;
} catch (final Exception e) { // we have waited enough
e.printStackTrace();
}
return null;
}
} }

View File

@@ -51,6 +51,7 @@ import forge.deck.Deck;
import forge.deckchooser.FDeckViewer; import forge.deckchooser.FDeckViewer;
import forge.game.GameEntityView; import forge.game.GameEntityView;
import forge.game.GameView; import forge.game.GameView;
import forge.game.card.Card;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.combat.CombatView; import forge.game.combat.CombatView;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -101,6 +102,7 @@ import forge.util.gui.SOptionPane;
import forge.view.FView; import forge.view.FView;
import forge.view.arcane.CardPanel; import forge.view.arcane.CardPanel;
import forge.view.arcane.FloatingCardArea; import forge.view.arcane.FloatingCardArea;
import forge.match.input.*;
/** /**
* Constructs instance of match UI controller, used as a single point of * Constructs instance of match UI controller, used as a single point of
@@ -395,7 +397,8 @@ public final class CMatchUI
break; break;
case Hand: case Hand:
updateHand = true; updateHand = true;
//$FALL-THROUGH$ updateZones = true;
break;
default: default:
updateZones = true; updateZones = true;
FloatingCardArea.refresh(owner, zone); FloatingCardArea.refresh(owner, zone);
@@ -424,6 +427,57 @@ public final class CMatchUI
} }
} }
@Override
public Iterable<PlayerZoneUpdate> tempShowZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
for (final PlayerZoneUpdate update : zonesToUpdate) {
final PlayerView player = update.getPlayer();
for (final ZoneType zone : update.getZones()) {
switch (zone) {
case Battlefield: // always shown
break;
case Hand: // controller hand always shown
if (controller != player) {
FloatingCardArea.show(this,player,zone);
}
break;
case Library:
case Graveyard:
case Exile:
case Flashback:
case Command:
FloatingCardArea.show(this,player,zone);
break;
default:
break;
}
}
}
return zonesToUpdate; //pfps should return only the newly shown zones
}
@Override
public void hideZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
for (final PlayerZoneUpdate update : zonesToUpdate) {
final PlayerView player = update.getPlayer();
for (final ZoneType zone : update.getZones()) {
switch (zone) {
case Battlefield: // always shown
break;
case Hand: // the controller's hand should never be temporarily shown, but ...
case Library:
case Graveyard:
case Exile:
case Flashback:
case Command:
FloatingCardArea.hide(this,player,zone);
break;
default:
break;
}
}
}
}
// Player's mana pool changes // Player's mana pool changes
@Override @Override
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) { public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
@@ -465,6 +519,7 @@ public final class CMatchUI
} }
break; break;
default: default:
FloatingCardArea.refresh(c.getController(),zone); // in case the card is visible in the zone
break; break;
} }
} }
@@ -942,11 +997,16 @@ public final class CMatchUI
} }
@Override @Override
public List<GameEntityView> chooseEntitiesForEffect(final String title, final List<? extends GameEntityView> optionList, final DelayedReveal delayedReveal) { public List<GameEntityView> chooseEntitiesForEffect(final String title, final List<? extends GameEntityView> optionList, final int min, final int max, final DelayedReveal delayedReveal) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getMessagePrefix(), delayedReveal.getCards()); //TODO: Merge this into search dialog reveal(delayedReveal.getMessagePrefix(), delayedReveal.getCards()); //TODO: Merge this into search dialog
} }
return (List<GameEntityView>) order(title,"Selected", 0, optionList.size(), optionList, null, null, false); return (List<GameEntityView>) order(title,"Selected", min, max, optionList, null, null, false);
}
@Override
public List<Card> manipulateCardList(final String title, final List<Card> cards, final List<Card> manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
return GuiChoose.manipulateCardList(this, title, cards, manipulable, toTop, toBottom, toAnywhere);
} }
@Override @Override

View File

@@ -246,7 +246,7 @@ public class CardArea extends CardPanelContainer implements CardPanelMouseListen
dragPanel.setDisplayEnabled(false); dragPanel.setDisplayEnabled(false);
CardPanel.setDragAnimationPanel(new CardPanel(dragPanel.getMatchUI(), dragPanel.getCard())); CardPanel.setDragAnimationPanel(new CardPanel(dragPanel.getMatchUI(), dragPanel.getCard()));
final JFrame frame = (JFrame) SwingUtilities.windowForComponent(this); final RootPaneContainer frame = (RootPaneContainer) SwingUtilities.windowForComponent(this);
final JLayeredPane layeredPane = frame.getLayeredPane(); final JLayeredPane layeredPane = frame.getLayeredPane();
layeredPane.add(CardPanel.getDragAnimationPanel()); layeredPane.add(CardPanel.getDragAnimationPanel());
layeredPane.moveToFront(CardPanel.getDragAnimationPanel()); layeredPane.moveToFront(CardPanel.getDragAnimationPanel());

View File

@@ -182,6 +182,10 @@ public abstract class CardPanelContainer extends SkinnedPanel {
}); });
} }
protected boolean cardPanelDraggable(final CardPanel panel) {
return true;
}
private MouseMotionListener setupMotionMouseListener() { private MouseMotionListener setupMotionMouseListener() {
final MouseMotionListener mml = new MouseMotionListener() { final MouseMotionListener mml = new MouseMotionListener() {
@Override @Override
@@ -207,6 +211,8 @@ public abstract class CardPanelContainer extends SkinnedPanel {
if (panel != mouseDownPanel) { if (panel != mouseDownPanel) {
return; return;
} }
if (cardPanelDraggable(panel)) { // allow for non-draggable cards
if (intialMouseDragX == -1) { if (intialMouseDragX == -1) {
intialMouseDragX = x; intialMouseDragX = x;
intialMouseDragY = y; intialMouseDragY = y;
@@ -222,6 +228,7 @@ public abstract class CardPanelContainer extends SkinnedPanel {
mouseDragOffsetY = panel.getY() - intialMouseDragY; mouseDragOffsetY = panel.getY() - intialMouseDragY;
mouseDragStart(getMouseDragPanel(), evt); mouseDragStart(getMouseDragPanel(), evt);
} }
}
@Override @Override
public void mouseMoved(final MouseEvent evt) { public void mouseMoved(final MouseEvent evt) {

View File

@@ -69,6 +69,10 @@ public class FloatingCardArea extends CardArea {
final FloatingCardArea cardArea = _init(matchUI, player, zone); final FloatingCardArea cardArea = _init(matchUI, player, zone);
cardArea.showWindow(); cardArea.showWindow();
} }
public static void hide(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) {
final FloatingCardArea cardArea = _init(matchUI, player, zone);
cardArea.hideWindow();
}
private static FloatingCardArea _init(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) { private static FloatingCardArea _init(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) {
final int key = getKey(player, zone); final int key = getKey(player, zone);
FloatingCardArea cardArea = floatingAreas.get(key); FloatingCardArea cardArea = floatingAreas.get(key);
@@ -205,6 +209,11 @@ public class FloatingCardArea extends CardArea {
window.setFocusableWindowState(false); // should probably do this earlier window.setFocusableWindowState(false); // should probably do this earlier
window.setVisible(true); window.setVisible(true);
} }
private void hideWindow() {
onShow();
window.setFocusableWindowState(false); // should probably do this earlier
window.setVisible(false);
}
private void showOrHideWindow() { private void showOrHideWindow() {
onShow(); onShow();
window.setFocusableWindowState(false); // should probably do this earlier window.setFocusableWindowState(false); // should probably do this earlier

View File

@@ -0,0 +1,314 @@
/*
* Forge: Play Magic: the Gathering.
*
* 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.view.arcane;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ScrollPaneConstants;
import javax.swing.Timer;
import forge.Singletons;
import forge.game.card.Card;
import forge.game.card.CardView;
import forge.gui.framework.SDisplayUtil;
import forge.model.FModel;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.screens.match.CMatchUI;
import forge.view.arcane.util.CardPanelMouseAdapter;
import forge.toolbox.FScrollPane;
import forge.toolbox.MouseTriggerEvent;
import forge.view.FFrame;
import forge.view.FDialog;
import forge.toolbox.FButton;
public class ListCardArea extends CardArea {
private static final String COORD_DELIM = ",";
private static final ForgePreferences prefs = FModel.getPreferences();
public void show() {
this.showWindow();
}
public void hide() {
this.hideWindow();
}
private ArrayList<Card> cardList;
private ArrayList<Card> moveableCards;
private boolean toTop, toBottom, toAnywhere;
private String title;
private FPref locPref;
private boolean hasBeenShown = false, locLoaded;
private static ListCardArea storedArea;
private final FButton doneButton;
public ListCardArea(final CMatchUI matchUI, final String title0, final List<Card> cardList0, final List<Card> moveableCards0, final boolean toTop0, final boolean toBottom0, final boolean toAnywhere0) {
super(matchUI, new FScrollPane(false, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER));
window.add(getScrollPane(),"grow, push");
try { Thread.sleep(1000); } catch(InterruptedException ex) { }
getScrollPane().setViewportView(this);
setOpaque(false);
doneButton = new FButton("Done");
doneButton.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { window.setVisible(false); }
});
window.add(doneButton,BorderLayout.SOUTH);
cardList = new ArrayList<Card>(cardList0); // this is modified - pfps - is there a better way?
moveableCards = new ArrayList<Card>(moveableCards0);
title = title0;
toTop = toTop0;
toBottom = toBottom0;
toAnywhere = toAnywhere0;
this.setDragEnabled(true);
this.setVertical(true);
storedArea = this;
}
public List<Card> getCardList() {
return cardList;
}
@SuppressWarnings("serial")
// private SkinnedFrame window = new SkinnedFrame() {
private final FDialog window = new FDialog(true, true, "0") {
@Override
public void setLocationRelativeTo(Component c) {
super.setLocationRelativeTo(c);
}
@Override
public void setVisible(boolean b0) {
if (isVisible() == b0) { return; }
if (b0) {
refresh();
}
super.setVisible(b0);
}
};
private void showWindow() {
onShow();
window.setFocusableWindowState(true);
window.setVisible(true);
}
private void hideWindow() {
onShow();
window.setFocusableWindowState(false); // should probably do this earlier
window.setVisible(false);
}
private void onShow() {
if (!hasBeenShown) {
loadLocation();
this.addCardPanelMouseListener(new CardPanelMouseAdapter() {
@Override
public void mouseDragEnd(final CardPanel dragPanel, final MouseEvent evt) {
dragEnd(dragPanel);
}
});
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ENTER:
doneButton.doClick();
break;
default:
break;
}
}
});
}
}
// is this a valid place to move the card?
private boolean validIndex(final Card card, final int index) {
if (toAnywhere) { return true; }
int oldIndex = cardList.indexOf(card);
boolean topMove = true;
for(int i=0; i<index+(oldIndex<index?1:0); i++) {
if (!moveableCards.contains(cardList.get(i))) { topMove=false; break; }
}
if (toTop && topMove) { return true; }
boolean bottomMove = true;
for(int i=index+1-(oldIndex>index?1:0); i<cardList.size(); i++) {
if (!moveableCards.contains(cardList.get(i))) { bottomMove=false; break; }
}
if (toBottom && bottomMove) { return true; }
return false;
}
protected Card panelToCard(final CardPanel panel) { //pfps there must be a better way
final CardView panelView = panel.getCard();
Card panelCard = null;
for ( Card card : cardList ) { if ( panelView == card.getView() ) { panelCard = card; } }
return panelCard;
}
@Override
protected boolean cardPanelDraggable(final CardPanel panel) {
return moveableCards.contains(panelToCard(panel));
}
private void dragEnd(final CardPanel dragPanel) {
// if drag is not allowed, don't move anything
final Card dragCard = panelToCard(dragPanel);
if (moveableCards.contains(dragCard)) {
//update index of dragged card in hand zone to match new index within hand area
final int index = getCardPanels().indexOf(dragPanel);
if (validIndex(dragCard,index)) {
synchronized (cardList) {
cardList.remove(dragCard);
cardList.add(index, dragCard);
}
}
}
refresh();
}
private void loadLocation() {
if (locPref != null) {
String value = prefs.getPref(locPref);
if (value.length() > 0) {
String[] coords = value.split(COORD_DELIM);
if (coords.length == 4) {
try {
int x = Integer.parseInt(coords[0]);
int y = Integer.parseInt(coords[1]);
int w = Integer.parseInt(coords[2]);
int h = Integer.parseInt(coords[3]);
//ensure the window is accessible
int centerX = x + w / 2;
int centerY = y + h / 2;
Rectangle screenBounds = SDisplayUtil.getScreenBoundsForPoint(new Point(centerX, centerY));
if (centerX < screenBounds.x) {
x = screenBounds.x;
}
else if (centerX > screenBounds.x + screenBounds.width) {
x = screenBounds.x + screenBounds.width - w;
if (x < screenBounds.x) {
x = screenBounds.x;
}
}
if (centerY < screenBounds.y) {
y = screenBounds.y;
}
else if (centerY > screenBounds.y + screenBounds.height) {
y = screenBounds.y + screenBounds.height - h;
if (y < screenBounds.y) {
y = screenBounds.y;
}
}
window.setBounds(x, y, w, h);
locLoaded = true;
return;
}
catch (Exception ex) {
ex.printStackTrace();
}
}
prefs.setPref(locPref, ""); //clear value if invalid
prefs.save();
}
}
//fallback default size
FFrame mainFrame = Singletons.getView().getFrame();
window.setSize(mainFrame.getWidth() / 5, mainFrame.getHeight() / 2);
}
public void refresh() {
List<CardPanel> cardPanels = new ArrayList<CardPanel>();
// FCollectionView<Card> cards = new FCollection<Card>(cardList);
if (cardList != null) {
for (final Card card : cardList) {
CardPanel cardPanel = getCardPanel(card.getId());
if (cardPanel == null) {
cardPanel = new CardPanel(getMatchUI(), card.getView());
cardPanel.setDisplayEnabled(true);
}
else {
cardPanel.setCard(card.getView()); //ensure card view updated
}
cardPanels.add(cardPanel);
}
}
boolean hadCardPanels = getCardPanels().size() > 0;
setCardPanels(cardPanels);
window.setTitle(String.format(title, cardPanels.size()));
//if window had cards and now doesn't, hide window
//(e.g. cast final card from Flashback zone)
if (hadCardPanels && cardPanels.size() == 0) {
window.setVisible(false);
}
}
@Override
public void doLayout() {
// if (window.isResizing()) {
// //delay layout slightly to reduce flicker during window resize
// layoutTimer.restart();
// }
//else {
finishDoLayout();
//}
}
private final Timer layoutTimer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
layoutTimer.stop();
finishDoLayout();
}
});
private void finishDoLayout() {
super.doLayout();
}
@Override
public final void mouseOver(final CardPanel panel, final MouseEvent evt) {
getMatchUI().setCard(panel.getCard(), evt.isShiftDown());
super.mouseOver(panel, evt);
}
@Override
public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) {
getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
super.mouseLeftClicked(panel, evt);
}
@Override
public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) {
getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
super.mouseRightClicked(panel, evt);
}
}

View File

@@ -174,7 +174,7 @@ public class PlayerControllerForTests extends PlayerController {
} }
@Override @Override
public <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer) { public <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer) {
// this isn't used // this isn't used
return null; return null;
} }
@@ -624,7 +624,7 @@ public class PlayerControllerForTests extends PlayerController {
} }
@Override @Override
public List<Card> chooseCardsForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, Player decider) { public List<Card> chooseCardsForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider) {
// this isn't used // this isn't used
return null; return null;
} }

View File

@@ -29,6 +29,7 @@ import forge.deck.CardPool;
import forge.deck.FSideboardDialog; import forge.deck.FSideboardDialog;
import forge.game.GameEntityView; import forge.game.GameEntityView;
import forge.game.GameView; import forge.game.GameView;
import forge.game.card.Card;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.DelayedReveal; import forge.game.player.DelayedReveal;
@@ -343,6 +344,16 @@ public class MatchController extends AbstractGuiGame {
view.updateZones(zonesToUpdate); view.updateZones(zonesToUpdate);
} }
@Override
public Iterable<PlayerZoneUpdate> tempShowZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
return view.tempShowZones(controller, zonesToUpdate);
}
@Override
public void hideZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
view.hideZones(controller, zonesToUpdate);
}
@Override @Override
public void updateCards(final Iterable<CardView> cards) { public void updateCards(final Iterable<CardView> cards) {
for (final CardView card : cards) { for (final CardView card : cards) {
@@ -506,8 +517,14 @@ public class MatchController extends AbstractGuiGame {
} }
@Override @Override
public List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal) { public List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, int min, int max, DelayedReveal delayedReveal) {
return SGuiChoose.order(title, "Selected", 0, -1, (List<GameEntityView>) optionList, null); return SGuiChoose.order(title, "Selected", min, max, (List<GameEntityView>) optionList, null);
}
@Override
public List<Card> manipulateCardList(final String title, final List<Card> cards, final List<Card> manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
System.err.println("Not implemented yet - should never be called");
return null;
} }
@Override @Override

View File

@@ -468,6 +468,15 @@ public class MatchScreen extends FScreen {
} }
} }
public Iterable<PlayerZoneUpdate> tempShowZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
// pfps needs to actually do something
return zonesToUpdate; // pfps should return only those zones newly shown
}
public void hideZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
// pfps needs to actually do something
}
public void updateSingleCard(final CardView card) { public void updateSingleCard(final CardView card) {
final CardAreaPanel pnl = CardAreaPanel.get(card); final CardAreaPanel pnl = CardAreaPanel.get(card);
if (pnl == null) { return; } if (pnl == null) { return; }

View File

@@ -11,6 +11,7 @@ import forge.assets.FSkinProp;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.game.GameEntityView; import forge.game.GameEntityView;
import forge.game.GameView; import forge.game.GameView;
import forge.game.card.Card;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.DelayedReveal; import forge.game.player.DelayedReveal;
@@ -47,6 +48,8 @@ public interface IGuiGame {
void showManaPool(PlayerView player); void showManaPool(PlayerView player);
void hideManaPool(PlayerView player); void hideManaPool(PlayerView player);
void updateStack(); void updateStack();
Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate); void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate);
void updateSingleCard(CardView card); void updateSingleCard(CardView card);
void updateCards(Iterable<CardView> cards); void updateCards(Iterable<CardView> cards);
@@ -144,7 +147,11 @@ public interface IGuiGame {
List<PaperCard> sideboard(CardPool sideboard, CardPool main); List<PaperCard> sideboard(CardPool sideboard, CardPool main);
GameEntityView chooseSingleEntityForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal, boolean isOptional); GameEntityView chooseSingleEntityForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal, boolean isOptional);
List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal); List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, int min, int max, DelayedReveal delayedReveal);
// show a list of cards and allow some of them to be moved around and return new list
List<Card> manipulateCardList(String title, final List<Card> cards, final List<Card> manipulable, boolean toTop, boolean toBottom, boolean toAnywhere);
void setCard(CardView card); void setCard(CardView card);
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi); void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players); boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);

View File

@@ -11,12 +11,17 @@ import forge.player.PlayerControllerHuman;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import forge.util.ITriggerEvent; import forge.util.ITriggerEvent;
import forge.player.PlayerZoneUpdate;
import forge.player.PlayerZoneUpdates;
import forge.game.zone.Zone;
import forge.FThreads;
public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSelectManyBase<T> { public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSelectManyBase<T> {
private static final long serialVersionUID = -6609493252672573139L; private static final long serialVersionUID = -6609493252672573139L;
private final FCollectionView<T> validChoices; private final FCollectionView<T> validChoices;
protected final FCollection<T> selected = new FCollection<T>(); protected final FCollection<T> selected = new FCollection<T>();
protected Iterable<PlayerZoneUpdate> zonesShown; // want to hide these zones when input done
public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0) { public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0) {
this(controller, min, max, validChoices0, null); this(controller, min, max, validChoices0, null);
@@ -28,6 +33,17 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
if (min > validChoices.size()) { if (min > validChoices.size()) {
System.out.println(String.format("Trying to choose at least %d things from a list with only %d things!", min, validChoices.size())); System.out.println(String.format("Trying to choose at least %d things from a list with only %d things!", min, validChoices.size()));
} }
PlayerZoneUpdates zonesToUpdate = new PlayerZoneUpdates();
for (final GameEntity c : validChoices) {
final Zone cz = (c instanceof Card) ? ((Card) c).getZone() : null ;
zonesToUpdate.add(new PlayerZoneUpdate(cz.getPlayer().getView(),cz.getZoneType()));
}
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public void run() {
controller.getGui().updateZones(zonesToUpdate);
zonesShown = controller.getGui().tempShowZones(controller.getPlayer().getView(),zonesToUpdate);
}
});
} }
@Override @Override
@@ -93,4 +109,10 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
? String.format(message, selected.size()) ? String.format(message, selected.size())
: String.format(message, max - selected.size()); : String.format(message, max - selected.size());
} }
@Override
protected void onStop() {
getController().getGui().hideZones(getController().getPlayer().getView(),zonesShown);
super.onStop();
}
} }

View File

@@ -49,6 +49,8 @@ public enum ProtocolMethod {
hideManaPool (Mode.SERVER, Void.TYPE, PlayerView.class), hideManaPool (Mode.SERVER, Void.TYPE, PlayerView.class),
updateStack (Mode.SERVER), updateStack (Mode.SERVER),
updateZones (Mode.SERVER, Void.TYPE, Iterable/*PlayerZoneUpdate*/.class), updateZones (Mode.SERVER, Void.TYPE, Iterable/*PlayerZoneUpdate*/.class),
tempShowZones (Mode.SERVER, Iterable/*PlayerZoneUpdate*/.class, PlayerView.class, Iterable/*PlayerZoneUpdate*/.class),
hideZones (Mode.SERVER, Void.TYPE, PlayerView.class, Iterable/*PlayerZoneUpdate*/.class),
updateCards (Mode.SERVER, Void.TYPE, Iterable/*CardView*/.class), updateCards (Mode.SERVER, Void.TYPE, Iterable/*CardView*/.class),
updateManaPool (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class), updateManaPool (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class),
updateLives (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class), updateLives (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class),
@@ -65,7 +67,8 @@ public enum ProtocolMethod {
order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE), order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE),
sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class), sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class),
chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class, Boolean.TYPE), chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class, Boolean.TYPE),
chooseEntitiesForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class), chooseEntitiesForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, Integer.TYPE, Integer.TYPE, DelayedReveal.class),
manipulateCardList (Mode.SERVER, List.class, String.class, List.class, List.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE),
setCard (Mode.SERVER, Void.TYPE, CardView.class), setCard (Mode.SERVER, Void.TYPE, CardView.class),
// TODO case "setPlayerAvatar": // TODO case "setPlayerAvatar":
openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class), openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class),

View File

@@ -11,6 +11,7 @@ import forge.assets.FSkinProp;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.game.GameEntityView; import forge.game.GameEntityView;
import forge.game.GameView; import forge.game.GameView;
import forge.game.card.Card;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.DelayedReveal; import forge.game.player.DelayedReveal;
@@ -147,6 +148,18 @@ public class NetGuiGame extends AbstractGuiGame {
send(ProtocolMethod.updateZones, zonesToUpdate); send(ProtocolMethod.updateZones, zonesToUpdate);
} }
@Override
public Iterable<PlayerZoneUpdate> tempShowZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
updateGameView();
return sendAndWait(ProtocolMethod.tempShowZones, controller, zonesToUpdate);
}
@Override
public void hideZones(final PlayerView controller, final Iterable<PlayerZoneUpdate> zonesToUpdate) {
updateGameView();
send(ProtocolMethod.hideZones, controller, zonesToUpdate);
}
@Override @Override
public void updateCards(final Iterable<CardView> cards) { public void updateCards(final Iterable<CardView> cards) {
updateGameView(); updateGameView();
@@ -232,8 +245,13 @@ public class NetGuiGame extends AbstractGuiGame {
} }
@Override @Override
public List<GameEntityView> chooseEntitiesForEffect(final String title, final List<? extends GameEntityView> optionList, final DelayedReveal delayedReveal) { public List<GameEntityView> chooseEntitiesForEffect(final String title, final List<? extends GameEntityView> optionList, final int min, final int max, final DelayedReveal delayedReveal) {
return sendAndWait(ProtocolMethod.chooseEntitiesForEffect, title, optionList, delayedReveal); return sendAndWait(ProtocolMethod.chooseEntitiesForEffect, title, optionList, min, max, delayedReveal);
}
@Override
public List<Card> manipulateCardList(final String title, final List<Card> cards, final List<Card> manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) {
return sendAndWait(ProtocolMethod.manipulateCardList, title, cards, manipulable, toTop, toBottom, toAnywhere);
} }
@Override @Override

View File

@@ -348,6 +348,31 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return new CardCollection(inp.getSelected()); return new CardCollection(inp.getSelected());
} }
private boolean useSelectCardsInput(final FCollectionView<? extends GameEntity> sourceList) {
if ( FThreads.isGuiThread() ) { return false; } // can't use InputSelect from GUI thread (e.g., DevMode Tutor)
// if UI_SELECT_FROM_CARD_DISPLAYS not set use InputSelect only for battlefield and player hand
// if UI_SELECT_FROM_CARD_DISPLAYS set and using desktop GUI use InputSelect for any zone that can be shown
for (final GameEntity c : sourceList) {
if (c instanceof Player) {
continue;
}
if (!(c instanceof Card)) {
return false;
}
final Zone cz = ((Card) c).getZone();
final boolean useUiPointAtCard =
cz != null &&
(FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) && (!GuiBase.getInterface().isLibgdxPort()) ) ?
(cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) ||
cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) :
(cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield));
if (!useUiPointAtCard) {
return false;
}
}
return true;
}
@Override @Override
public CardCollectionView chooseCardsForEffect(final CardCollectionView sourceList, final SpellAbility sa, public CardCollectionView chooseCardsForEffect(final CardCollectionView sourceList, final SpellAbility sa,
final String title, final int min, final int max, final boolean isOptional) { final String title, final int min, final int max, final boolean isOptional) {
@@ -362,22 +387,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
getGui().setPanelSelection(CardView.get(sa.getHostCard())); getGui().setPanelSelection(CardView.get(sa.getHostCard()));
// try to use InputSelectCardsFromList when possible if (useSelectCardsInput(sourceList)) {
boolean cardsAreInMyHandOrBattlefield = true; tempShowCards(sourceList);
for (final Card c : sourceList) {
final Zone z = c.getZone();
if (z != null && (z.is(ZoneType.Battlefield) || z.is(ZoneType.Hand, player))) {
continue;
}
cardsAreInMyHandOrBattlefield = false;
break;
}
if (cardsAreInMyHandOrBattlefield) {
final InputSelectCardsFromList sc = new InputSelectCardsFromList(this, min, max, sourceList, sa); final InputSelectCardsFromList sc = new InputSelectCardsFromList(this, min, max, sourceList, sa);
sc.setMessage(title); sc.setMessage(title);
sc.setCancelAllowed(isOptional); sc.setCancelAllowed(isOptional);
sc.showAndWait(); sc.showAndWait();
endTempShowCards();
return new CardCollection(sc.getSelected()); return new CardCollection(sc.getSelected());
} }
@@ -411,31 +427,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return Iterables.getFirst(optionList, null); return Iterables.getFirst(optionList, null);
} }
boolean canUseSelectCardsInput = true; if (useSelectCardsInput(optionList)) {
for (final GameEntity c : optionList) {
if (c instanceof Player) {
continue;
}
final Zone cz = ((Card) c).getZone();
// can point at cards in own hand and anyone's battlefield
final boolean canUiPointAtCards = cz != null
&& (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield));
if (!canUiPointAtCards) {
canUseSelectCardsInput = false;
break;
}
}
if (canUseSelectCardsInput) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
delayedReveal.getMessagePrefix()); delayedReveal.getMessagePrefix());
} }
tempShow(optionList);
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, isOptional ? 0 : 1, 1, final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, isOptional ? 0 : 1, 1,
optionList, sa); optionList, sa);
input.setCancelAllowed(isOptional); input.setCancelAllowed(isOptional);
input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer)); input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer));
input.showAndWait(); input.showAndWait();
endTempShowCards();
return Iterables.getFirst(input.getSelected(), null); return Iterables.getFirst(input.getSelected(), null);
} }
@@ -458,7 +461,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, final int min, final int max,
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer) { final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer) {
// useful details for debugging problems with the mass select logic // useful details for debugging problems with the mass select logic
@@ -475,31 +478,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return null; return null;
} }
boolean canUseSelectCardsInput = true; if (useSelectCardsInput(optionList)) {
for (final GameEntity c : optionList) {
if (c instanceof Player) {
continue;
}
final Zone cz = ((Card) c).getZone();
// can point at cards in own hand and anyone's battlefield
final boolean canUiPointAtCards = cz != null
&& (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield));
if (!canUiPointAtCards) {
canUseSelectCardsInput = false;
break;
}
}
if (canUseSelectCardsInput) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
delayedReveal.getMessagePrefix()); delayedReveal.getMessagePrefix());
} }
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, 0, optionList.size(), tempShow(optionList);
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, min, max,
optionList, sa); optionList, sa);
input.setCancelAllowed(true); input.setCancelAllowed(true);
input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer)); input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer));
input.showAndWait(); input.showAndWait();
endTempShowCards();
return (List<T>) input.getSelected(); return (List<T>) input.getSelected();
} }
@@ -508,7 +498,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
tempShow(delayedReveal.getCards()); tempShow(delayedReveal.getCards());
} }
final List<GameEntityView> chosen = getGui().chooseEntitiesForEffect(title, final List<GameEntityView> chosen = getGui().chooseEntitiesForEffect(title,
GameEntityView.getEntityCollection(optionList), delayedReveal); GameEntityView.getEntityCollection(optionList), min, max, delayedReveal);
endTempShowCards(); endTempShowCards();
List<T> results = new ArrayList<>(); List<T> results = new ArrayList<>();
@@ -747,12 +737,38 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
} }
} }
public ImmutablePair<CardCollection, CardCollection> arrangeForMove(final String title, final List<Card> cards, final List<Card> manipulable, final boolean topOK, final boolean bottomOK) {
List<Card> result = getGui().manipulateCardList("Move cards to top or bottom of library", cards, manipulable, topOK, bottomOK, false);
CardCollection toBottom = new CardCollection();
CardCollection toTop = new CardCollection();
for (int i = 0; manipulable.contains(result.get(i)) && i<cards.size(); i++ ) {
toTop.add(result.get(i));
}
if (toTop.size() < cards.size()) { // the top isn't everything
for (int i = result.size()-1; manipulable.contains(result.get(i)); i-- ) {
toBottom.add(result.get(i));
}
}
return ImmutablePair.of(toTop,toBottom);
}
@Override @Override
public ImmutablePair<CardCollection, CardCollection> arrangeForScry(final CardCollection topN) { public ImmutablePair<CardCollection, CardCollection> arrangeForScry(final CardCollection topN) {
CardCollection toBottom = null; CardCollection toBottom = null;
CardCollection toTop = null; CardCollection toTop = null;
tempShowCards(topN); tempShowCards(topN);
if ( FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) &&
(!GuiBase.getInterface().isLibgdxPort()) ) {
ArrayList<Card> cardList = new ArrayList<Card>(); // pfps there must be a better way
for (final Card card : player.getCardsIn(ZoneType.Library)) {
cardList.add(card);
}
ImmutablePair<CardCollection, CardCollection> result =
arrangeForMove("Move cards to top or bottom of library", cardList, topN, true, true);
toTop = result.getLeft();
toBottom = result.getRight();
} else {
if (topN.size() == 1) { if (topN.size() == 1) {
if (willPutCardOnTop(topN.get(0))) { if (willPutCardOnTop(topN.get(0))) {
toTop = topN; toTop = topN;
@@ -772,6 +788,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
"Top of Library", CardView.getCollection(topN), null)); "Top of Library", CardView.getCollection(topN), null));
} }
} }
}
endTempShowCards(); endTempShowCards();
return ImmutablePair.of(toTop, toBottom); return ImmutablePair.of(toTop, toBottom);
} }
@@ -1791,9 +1808,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
} }
public List<Card> chooseCardsForZoneChange(final ZoneType destination, final List<ZoneType> origin, public List<Card> chooseCardsForZoneChange(final ZoneType destination, final List<ZoneType> origin,
final SpellAbility sa, final CardCollection fetchList, final DelayedReveal delayedReveal, final SpellAbility sa, final CardCollection fetchList, final int min, final int max, final DelayedReveal delayedReveal,
final String selectPrompt, final Player decider) { final String selectPrompt, final Player decider) {
return chooseEntitiesForEffect(fetchList, delayedReveal, sa, selectPrompt, decider); return chooseEntitiesForEffect(fetchList, min, max, delayedReveal, sa, selectPrompt, decider);
} }
@Override @Override

View File

@@ -125,7 +125,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_DISABLE_IMAGES_EFFECT_CARDS("false"), UI_DISABLE_IMAGES_EFFECT_CARDS("false"),
UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"),
UI_DEFAULT_FONT_SIZE("12"), UI_DEFAULT_FONT_SIZE("12"),
UI_SELECT_FROM_CARD_DISPLAYS("true"),
UI_FOR_TOUCHSCREN("false"), UI_FOR_TOUCHSCREN("false"),
UI_VIBRATE_ON_LIFE_LOSS("true"), UI_VIBRATE_ON_LIFE_LOSS("true"),