Add reveal button to mobile-gui

- currently it gets all cards that was revealed by via reveal(...)
- update menutab to show scroll indicator as default
This commit is contained in:
Anthony Calosa
2022-12-10 09:20:41 +08:00
parent d15a505081
commit ccc985654c
19 changed files with 841 additions and 367 deletions

View File

@@ -18,6 +18,7 @@ import forge.game.player.PlayerView;
import forge.game.player.RegisteredPlayer;
import forge.game.spellability.StackItemView;
import forge.game.zone.MagicStack;
import forge.trackable.TrackableCollection;
import forge.trackable.TrackableObject;
import forge.trackable.TrackableProperty;
import forge.util.collect.FCollectionView;
@@ -64,15 +65,19 @@ public class GameView extends TrackableObject {
public String getTitle() {
return get(TrackableProperty.Title);
}
public boolean isCommander() {
return get(TrackableProperty.IsCommander);
}
public GameType getGameType() {
return get(TrackableProperty.GameType);
}
public int getPoisonCountersToLose() {
return get(TrackableProperty.PoisonCountersToLose);
}
public int getNumGamesInMatch() {
return get(TrackableProperty.NumGamesInMatch);
}
@@ -80,31 +85,39 @@ public class GameView extends TrackableObject {
public int getTurn() {
return get(TrackableProperty.Turn);
}
void updateTurn(PhaseHandler phaseHandler) {
set(TrackableProperty.Turn, phaseHandler.getTurn());
}
public PhaseType getPhase() {
return get(TrackableProperty.Phase);
}
void updatePhase(PhaseHandler phaseHandler) {
set(TrackableProperty.Phase, phaseHandler.getPhase());
}
public PlayerView getPlayerTurn() {
return get(TrackableProperty.PlayerTurn);
}
void updatePlayerTurn(PhaseHandler phaseHandler) {
set(TrackableProperty.PlayerTurn, PlayerView.get(phaseHandler.getPlayerTurn()));
}
public void updateNeedsPhaseRedrawn(PlayerView p, PhaseType ph) {
set(TrackableProperty.PlayerTurn, p);
set(TrackableProperty.Phase, ph);
set(TrackableProperty.NeedsPhaseRedrawn, true);
}
public boolean getNeedsPhaseRedrawn() {
if (get(TrackableProperty.NeedsPhaseRedrawn) == null)
return false;
return get(TrackableProperty.NeedsPhaseRedrawn);
}
public void clearNeedsPhaseRedrawn() {
set(TrackableProperty.NeedsPhaseRedrawn, false);
}
@@ -112,18 +125,23 @@ public class GameView extends TrackableObject {
public void updatePlanarPlayer(PlayerView p) {
set(TrackableProperty.PlanarPlayer, p);
}
public PlayerView getPlanarPlayer() {
return get(TrackableProperty.PlanarPlayer);
}
public FCollectionView<StackItemView> getStack() {
return get(TrackableProperty.Stack);
}
public StackItemView peekStack() {
return Iterables.getFirst(getStack(), null);
}
public int getStormCount() {
return get(TrackableProperty.StormCount);
}
void updateStack(final MagicStack stack) {
set(TrackableProperty.Stack, StackItemView.getCollection(stack));
set(TrackableProperty.StormCount, stack.getSpellsCastThisTurn().size());
@@ -132,6 +150,7 @@ public class GameView extends TrackableObject {
public boolean isFirstGameInMatch() {
return getNumPlayedGamesInMatch() == 0;
}
public int getNumPlayedGamesInMatch() {
return get(TrackableProperty.NumPlayedGamesInMatch);
}
@@ -139,23 +158,29 @@ public class GameView extends TrackableObject {
public boolean isGameOver() {
return get(TrackableProperty.GameOver);
}
public boolean isMatchOver() {
return get(TrackableProperty.MatchOver);
}
public boolean isMulligan() {
if (get(TrackableProperty.Mulligan) == null)
return false;
return get(TrackableProperty.Mulligan);
}
public void updateIsMulligan(boolean value) {
set(TrackableProperty.Mulligan, value);
}
public String getWinningPlayerName() {
return get(TrackableProperty.WinningPlayerName);
}
public int getWinningTeam() {
return get(TrackableProperty.WinningTeam);
}
void updateGameOver(final Game game) {
set(TrackableProperty.GameOver, game.isGameOver());
set(TrackableProperty.MatchOver, game.getMatch().isMatchOver());
@@ -168,16 +193,27 @@ public class GameView extends TrackableObject {
public GameLog getGameLog() {
return get(TrackableProperty.GameLog);
}
void updateGameLog(GameLog gameLog) {
flagAsChanged(TrackableProperty.GameLog); //don't need to set the property since it won't change
}
public TrackableCollection<CardView> getRevealedCollection() {
return get(TrackableProperty.RevealedCardsCollection);
}
public void updateRevealedCards(TrackableCollection<CardView> collection) {
set(TrackableProperty.RevealedCardsCollection, collection);
}
public CombatView getCombat() {
return get(TrackableProperty.CombatView);
}
public void updateCombatView(CombatView combatView) {
set(TrackableProperty.CombatView, combatView);
}
void updateCombat(Combat combat) {
if (combat == null) {
set(TrackableProperty.CombatView, null);

View File

@@ -43,6 +43,7 @@ public enum TrackableProperty {
SplitCard(TrackableTypes.BooleanType),
MergedCards(TrackableTypes.StringType),
MergedCardsCollection(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
RevealedCardsCollection(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
PaperCardBackup(TrackableTypes.IPaperCardType),
Attacking(TrackableTypes.BooleanType),
@@ -278,6 +279,7 @@ public enum TrackableProperty {
TrackableProperty(TrackableType<?> type0) {
this(type0, FreezeMode.RespectsFreeze);
}
TrackableProperty(TrackableType<?> type0, FreezeMode freezeMode0) {
type = type0;
freezeMode = freezeMode0;
@@ -293,7 +295,7 @@ public enum TrackableProperty {
@SuppressWarnings("unchecked")
public <T> void updateObjLookup(Tracker tracker, T newObj) {
((TrackableType<T>)type).updateObjLookup(tracker, newObj);
((TrackableType<T>) type).updateObjLookup(tracker, newObj);
}
public void copyChangedProps(TrackableObject from, TrackableObject to) {
@@ -302,15 +304,17 @@ public enum TrackableProperty {
@SuppressWarnings("unchecked")
public <T> T getDefaultValue() {
return ((TrackableType<T>)type).getDefaultValue();
return ((TrackableType<T>) type).getDefaultValue();
}
@SuppressWarnings("unchecked")
public <T> T deserialize(TrackableDeserializer td, T oldValue) {
return ((TrackableType<T>)type).deserialize(td, oldValue);
return ((TrackableType<T>) type).deserialize(td, oldValue);
}
@SuppressWarnings("unchecked")
public <T> void serialize(TrackableSerializer ts, T value) {
((TrackableType<T>)type).serialize(ts, value);
((TrackableType<T>) type).serialize(ts, value);
}
//cache array of all properties to allow quick lookup by ordinal,
@@ -318,9 +322,11 @@ public enum TrackableProperty {
//we don't need to worry about the values changing since we will ensure
//both players are on the same version of Forge before allowing them to connect
private static TrackableProperty[] props = values();
public static int serialize(TrackableProperty prop) {
return prop.ordinal();
}
public static TrackableProperty deserialize(int ordinal) {
return props[ordinal];
}

View File

@@ -1132,7 +1132,8 @@ public class Forge implements ApplicationListener {
return false;
}
}
public static float mouseMovedX = 0;
public static float mouseMovedY = 0;
private static class MainInputProcessor extends FGestureAdapter {
private static final List<FDisplayObject> potentialListeners = new ArrayList<>();
private static char lastKeyTyped;
@@ -1216,7 +1217,7 @@ public class Forge implements ApplicationListener {
return false;
}
private void updatePotentialListeners(int x, int y) {
private void updatePotentialListeners(float x, float y) {
potentialListeners.clear();
//base potential listeners on object containing touch down point
@@ -1391,8 +1392,6 @@ public class Forge implements ApplicationListener {
}
//mouseMoved and scrolled events for desktop version
private int mouseMovedX, mouseMovedY;
@Override
public boolean mouseMoved(int screenX, int screenY) {
magnify = true;

View File

@@ -338,6 +338,9 @@ public enum FSkinImage implements FImage {
FAVICON (FSkinProp.ICO_FAVICON, SourceFile.ICONS),
LOCK (FSkinProp.ICO_LOCK, SourceFile.ICONS),
//reveal icons
SEE (FSkinProp.ICO_SEE, SourceFile.ICONS),
UNSEE (FSkinProp.ICO_UNSEE, SourceFile.ICONS),
//Layout images
HANDLE (FSkinProp.IMG_HANDLE, SourceFile.ICONS),

View File

@@ -774,9 +774,7 @@ public class CardRenderer {
}
//Darken unselectable cards
if (unselectable) {
g.setAlphaComposite(0.6f);
g.fillRect(Color.BLACK, cx, cy, cw, ch);
g.setAlphaComposite(oldAlpha);
g.fillRect(FSkinColor.getStandardColor(Color.BLACK).alphaColor(0.6f), cx, cy, cw, ch);
}
//Magenta outline when card is chosen
if (MatchController.instance.isUsedToPay(card)) {

View File

@@ -7,8 +7,13 @@ import forge.Graphics;
import forge.assets.FSkinColor;
import forge.assets.FSkinColor.Colors;
import forge.assets.FSkinTexture;
import forge.gui.GuiBase;
import forge.screens.FScreen;
import forge.screens.match.views.VDevMenu;
import forge.screens.match.views.VGameMenu;
import forge.screens.match.views.VLog;
import forge.screens.match.views.VPlayers;
import forge.screens.match.views.VReveal;
import forge.screens.match.views.VStack;
import forge.toolbox.FContainer;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FOverlay;
@@ -34,6 +39,7 @@ public abstract class FDropDown extends FScrollPane {
public FMenuTab getMenuTab() {
return menuTab;
}
public void setMenuTab(FMenuTab menuTab0) {
menuTab = menuTab0;
}
@@ -41,6 +47,7 @@ public abstract class FDropDown extends FScrollPane {
public FContainer getDropDownContainer() {
return dropDownContainer;
}
public void setDropDownContainer(FContainer dropDownContainer0) {
dropDownContainer = dropDownContainer0;
}
@@ -69,9 +76,11 @@ public abstract class FDropDown extends FScrollPane {
public void hide() {
setVisible(false);
}
public void setNextSelected() {
scrollToHoveredChild(true);
}
public void setPreviousSelected() {
scrollToHoveredChild(false);
}
@@ -101,7 +110,9 @@ public abstract class FDropDown extends FScrollPane {
@Override
public void setVisible(boolean visible0) {
if (isVisible() == visible0) { return; }
if (isVisible() == visible0) {
return;
}
//add/remove drop down from its container, current screen, or top overlay when its visibility changes
FContainer container = getContainer();
@@ -114,8 +125,7 @@ public abstract class FDropDown extends FScrollPane {
container.add(backdrop);
}
container.add(this);
}
else {
} else {
container.remove(this);
if (backdrop != null) {
backdrop.setVisible(false);
@@ -131,10 +141,13 @@ public abstract class FDropDown extends FScrollPane {
}
protected abstract boolean autoHide();
protected abstract ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight);
protected void updateSizeAndPosition() {
if (menuTab == null) { return; }
if (menuTab == null) {
return;
}
Rectangle boundary = Forge.getCurrentScreen().getDropDownBoundary();
@@ -145,8 +158,7 @@ public abstract class FDropDown extends FScrollPane {
if (y < boundary.y + boundary.height / 2) {
showAbove = false;
maxVisibleHeight = boundary.y + boundary.height - y; //prevent covering prompt
}
else { //handle drop downs at near bottom of screen
} else { //handle drop downs at near bottom of screen
showAbove = true;
y = menuTab.screenPos.y;
maxVisibleHeight = y - boundary.y;
@@ -191,6 +203,31 @@ public abstract class FDropDown extends FScrollPane {
float w = getWidth();
float h = getHeight();
g.drawRect(2, getBorderColor(), 0, 0, w, h); //ensure border shows up on all sides
if (getDropDownOwner() instanceof FMenuTab) {
try {
if (getScrollLeft() > 0) {
float x = getIndicatorMargin();
float y = getHeight() / 2;
g.fillTriangle(getIndicatorColor(), x, y, x + getIndicatorSize(), y - getIndicatorSize(), x + getIndicatorSize(), y + getIndicatorSize());
}
if (getScrollLeft() < getMaxScrollLeft()) {
float x = getWidth() - getIndicatorMargin();
float y = getHeight() / 2;
g.fillTriangle(getIndicatorColor(), x, y, x - getIndicatorSize(), y - getIndicatorSize(), x - getIndicatorSize(), y + getIndicatorSize());
}
if (getScrollTop() > 0) {
float x = getWidth() / 2;
float y = getIndicatorMargin();
g.fillTriangle(getIndicatorColor(), x, y, x - getIndicatorSize(), y + getIndicatorSize(), x + getIndicatorSize(), y + getIndicatorSize());
}
if (getScrollTop() < getMaxScrollTop()) {
float x = getWidth() / 2;
float y = getHeight() - getIndicatorSize();
g.fillTriangle(getIndicatorColor(), x, y, x - getIndicatorSize(), y - getIndicatorSize(), x + getIndicatorSize(), y - getIndicatorSize());
}
} catch (Exception e) {
}
}
}
protected FDisplayObject getDropDownOwner() {
@@ -201,6 +238,7 @@ public abstract class FDropDown extends FScrollPane {
FDisplayObject owner = getDropDownOwner();
return owner == null || !owner.screenPos.contains(x, y); //auto-hide when backdrop pressed unless over owner
}
public void tapChild() {
if (selectedChild != null) {
selectedChild.tap(0, 0, 1);
@@ -210,18 +248,20 @@ public abstract class FDropDown extends FScrollPane {
hide();
}
}
public void cancel() {
if (getMenuTab() != null)
getMenuTab().clearSelected();
hide();
}
public void scrollToHoveredChild(boolean down) {
selectedChild = null;
for (FDisplayObject fDisplayObject : getChildren()) {
if (fDisplayObject.isHovered()) {
//System.out.println(fDisplayObject.screenPos.x+"|"+fDisplayObject.screenPos.y);
float mod = down ? 0 : -fDisplayObject.screenPos.height;
float y = fDisplayObject.screenPos.y+mod;
float y = fDisplayObject.screenPos.y + mod;
scrollIntoView(fDisplayObject.screenPos.x, y, fDisplayObject.screenPos.width, fDisplayObject.screenPos.height, 0);
selectedChild = fDisplayObject;
break;
@@ -235,7 +275,7 @@ public abstract class FDropDown extends FScrollPane {
if (owner instanceof FSubMenu) {
return owner.contains(owner.getLeft() + owner.screenToLocalX(x), owner.getTop() + owner.screenToLocalY(y));
}
return true;
return true;
}
private class Backdrop extends FDisplayObject {
@@ -252,7 +292,9 @@ public abstract class FDropDown extends FScrollPane {
@Override
public boolean tap(float x, float y, int count) {
if (!isVisible()) { return false; }
if (!isVisible()) {
return false;
}
hide(); //always hide if tapped
return preventOwnerHandlingBackupTap(x, y, count);
@@ -260,21 +302,21 @@ public abstract class FDropDown extends FScrollPane {
@Override
public boolean pan(float x, float y, float deltaX, float deltaY, boolean moreVertical) {
if (!GuiBase.isAndroid())
if (!isMatchHeader())
hide(); //always hide if backdrop panned
return false; //allow pan to pass through to object behind backdrop
}
@Override
public boolean fling(float velocityX, float velocityY) {
if (!GuiBase.isAndroid())
if (!isMatchHeader())
hide(); //always hide if backdrop flung
return false; //allow fling to pass through to object behind backdrop
}
@Override
public boolean zoom(float x, float y, float amount) {
if (!GuiBase.isAndroid())
if (!isMatchHeader())
hide(); //always hide if backdrop zoomed
return false; //allow zoom to pass through to object behind backdrop
}
@@ -284,4 +326,20 @@ public abstract class FDropDown extends FScrollPane {
//draw nothing for backdrop
}
}
private boolean isMatchHeader() {
if (this instanceof VGameMenu)
return true;
if (this instanceof VPlayers)
return true;
if (this instanceof VReveal)
return true;
if (this instanceof VLog)
return true;
if (this instanceof VDevMenu)
return true;
if (this instanceof VStack)
return true;
return false;
}
}

View File

@@ -4,15 +4,21 @@ import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.Input;
import forge.Forge;
import forge.Graphics;
import forge.screens.FScreen.Header;
import forge.screens.match.MatchController;
public class FMenuBar extends Header {
private final List<FMenuTab> tabs = new ArrayList<>();
private int selected = -1;
public void addTab(String text0, FDropDown dropDown0) {
FMenuTab tab = new FMenuTab(text0, this, dropDown0, tabs.size());
addTab(text0, dropDown0, false);
}
public void addTab(String text0, FDropDown dropDown0, boolean iconOnly) {
FMenuTab tab = new FMenuTab(text0, this, dropDown0, tabs.size(), iconOnly);
dropDown0.setMenuTab(tab);
tabs.add(add(tab));
}
@@ -29,10 +35,22 @@ public class FMenuBar extends Header {
protected void doLayout(float width, float height) {
int visibleTabCount = 0;
float minWidth = 0;
int iconOnlyTabCount = 0;
float iconMinWidth = 0;
for (FMenuTab tab : tabs) {
if (tab.isVisible()) {
minWidth += tab.getMinWidth();
visibleTabCount++;
if (Forge.isLandscapeMode()) {
if (!tab.iconOnly) {
minWidth += tab.getMinWidth();
visibleTabCount++;
} else {
iconMinWidth += tab.getMinWidth();
iconOnlyTabCount++;
}
} else {
minWidth += tab.getMinWidth();
visibleTabCount++;
}
}
}
int tabWidth;
@@ -40,12 +58,15 @@ public class FMenuBar extends Header {
float dx = (width - minWidth) / visibleTabCount;
for (FMenuTab tab : tabs) {
if (tab.isVisible()) {
if (tab.iconOnly) {
tab.setActiveIcon(MatchController.instance.getGameView().getRevealedCollection() != null);
}
tabWidth = Math.round(tab.getMinWidth() + dx);
if (x + tabWidth > width) {
tabWidth = Math.round(width - x); //prevent final tab extending off screen
}
tab.setBounds(x, 0, tabWidth, height);
x += tabWidth;
tab.setBounds(tab.iconOnly ? 0 : x, 0, tab.iconOnly ? tab.getMinWidth() + FMenuTab.PADDING * 2 : tabWidth, height);
x += tab.iconOnly ? tab.getMinWidth() + FMenuTab.PADDING * 2 : tabWidth;
}
}
}
@@ -61,6 +82,7 @@ public class FMenuBar extends Header {
public float doLandscapeLayout(float screenWidth, float screenHeight) {
return 0;
}
public void setNextSelected() {
selected++;
closeAll();
@@ -68,13 +90,15 @@ public class FMenuBar extends Header {
selected = 0;
try {
tabs.get(selected).showDropDown();
} catch (Exception e) {}
} catch (Exception e) {
}
if (selected > tabs.size()) {
closeAll();
selected = tabs.size();
return;
}
}
public void setPreviousSelected() {
selected--;
closeAll();
@@ -82,21 +106,25 @@ public class FMenuBar extends Header {
selected = tabs.size();
try {
tabs.get(selected).showDropDown();
} catch (Exception e) {}
} catch (Exception e) {
}
if (selected < 0) {
closeAll();
selected = -1;
return;
}
}
public void closeAll() {
for (FMenuTab fMenuTab : tabs) {
fMenuTab.hideDropDown();
}
}
public boolean isShowingMenu(boolean anyDropdown) {
return tabs.stream().anyMatch(tab -> tab.isShowingDropdownMenu(anyDropdown));
}
public void clearSelected() {
selected--;
if (selected < -1)

View File

@@ -5,14 +5,18 @@ import com.badlogic.gdx.utils.Align;
import forge.Forge;
import forge.Graphics;
import forge.assets.FImage;
import forge.assets.FSkinColor;
import forge.assets.FSkinColor.Colors;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
import forge.toolbox.FDisplayObject;
import forge.util.Utils;
public class FMenuTab extends FDisplayObject {
public static final FSkinFont FONT = FSkinFont.get(12);
boolean iconOnly = false;
boolean active = false;
private static FSkinColor getSelBackColor() {
if (Forge.isMobileAdventureMode)
return FSkinColor.get(Colors.ADV_CLR_ACTIVE);
@@ -42,10 +46,11 @@ public class FMenuTab extends FDisplayObject {
private float minWidth;
private int index;
public FMenuTab(String text0, FMenuBar menuBar0, FDropDown dropDown0, int index0) {
public FMenuTab(String text0, FMenuBar menuBar0, FDropDown dropDown0, int index0, boolean iconOnly0) {
menuBar = menuBar0;
dropDown = dropDown0;
index = index0;
iconOnly = iconOnly0;
setText(text0);
}
@@ -89,6 +94,10 @@ public class FMenuTab extends FDisplayObject {
menuBar.revalidate();
}
public void setActiveIcon(boolean value) {
active = value;
}
@Override
public void setVisible(boolean visible0) {
if (isVisible() == visible0) { return; }
@@ -102,6 +111,10 @@ public class FMenuTab extends FDisplayObject {
}
public float getMinWidth() {
if (iconOnly) {
float multiplier = Forge.isLandscapeMode() ? 2.5f : 1.8f;
return FONT.getLineHeight() * multiplier;
}
return minWidth;
}
@@ -140,7 +153,14 @@ public class FMenuTab extends FDisplayObject {
h = getHeight() - 2 * PADDING;
if (isHovered())
g.fillRect(getSelBackColor().brighter(), x, y, w, h);
g.drawText(text, FONT, foreColor, x, y, w, h, false, Align.center, true);
if (iconOnly) {
float mod = w * 0.75f;
FImage icon = active ? FSkinImage.SEE : FSkinImage.UNSEE;
float scaleW = icon.getWidth() * 0.8f;
float scaleH = icon.getHeight() * 0.8f;
g.drawImage(icon, x + w/2 - scaleW/2, y + h/2 - scaleH/2, scaleW, scaleH);
} else
g.drawText(text, FONT, foreColor, x, y, w, h, false, Align.center, true);
}
public boolean isShowingDropdownMenu(boolean any) {
if (dropDown == null)

View File

@@ -123,9 +123,7 @@ public class LoadingOverlay extends FOverlay {
float y = (getHeight() - panelHeight) / 2;
float oldAlpha = g.getfloatAlphaComposite();
//dark translucent back..
g.setAlphaComposite(0.6f);
g.fillRect(Color.BLACK, 0, 0, getWidth(), getHeight());
g.setAlphaComposite(oldAlpha);
g.fillRect(FSkinColor.getStandardColor(Color.BLACK).alphaColor(0.6f), 0, 0, getWidth(), getHeight());
//overlay
g.fillRect(getOverlayColor(), x, y, panelWidth, panelHeight);
g.drawRect(Utils.scale(2), getForeColor(), x, y, panelWidth, panelHeight);

View File

@@ -13,6 +13,7 @@ import forge.card.CardZoom;
import forge.game.spellability.StackItemView;
import forge.gui.interfaces.IGuiGame;
import forge.screens.match.views.VField;
import forge.screens.match.views.VReveal;
import forge.toolbox.FDisplayObject;
import forge.util.Utils;
import forge.util.collect.FCollectionView;
@@ -77,6 +78,7 @@ public class MatchScreen extends FScreen {
private List<VPlayerPanel> playerPanelsList;
private final VGameMenu gameMenu;
private final VPlayers players;
private final VReveal revealed;
private final VLog log;
private final VStack stack;
private final VDevMenu devMenu;
@@ -101,7 +103,7 @@ public class MatchScreen extends FScreen {
for (VPlayerPanel playerPanel : playerPanels0) {
playerPanels.put(playerPanel.getPlayer(), scroller.add(playerPanel));
playerPanel.setFlipped(true);
if(!playerPanel.getPlayer().isAI())
if (!playerPanel.getPlayer().isAI())
humanCount++;
}
bottomPlayerPanel = playerPanels0.get(0);
@@ -111,7 +113,7 @@ public class MatchScreen extends FScreen {
//reorder list so bottom player is at the end of the list ensuring top to bottom turn order
playerPanelsList.remove(bottomPlayerPanel);
playerPanelsList.add(bottomPlayerPanel);
selectedPlayer = playerPanelsList.size()-1;
selectedPlayer = playerPanelsList.size() - 1;
bottomPlayerPrompt = add(new VPrompt("", "",
e -> getGameController().selectButtonOk(),
@@ -133,6 +135,8 @@ public class MatchScreen extends FScreen {
gameMenu.setDropDownContainer(this);
players = new VPlayers();
players.setDropDownContainer(this);
revealed = new VReveal();
revealed.setDropDownContainer(this);
log = new VLog();
log.setDropDownContainer(this);
devMenu = new VDevMenu();
@@ -140,15 +144,15 @@ public class MatchScreen extends FScreen {
stack = new VStack();
stack.setDropDownContainer(this);
FMenuBar menuBar = (FMenuBar)getHeader();
FMenuBar menuBar = (FMenuBar) getHeader();
if (topPlayerPrompt == null) {
menuBar.addTab("", revealed, true);
menuBar.addTab(Forge.getLocalizer().getMessage("lblGame"), gameMenu);
menuBar.addTab(Forge.getLocalizer().getMessage("lblPlayers") + " (" + playerPanels.size() + ")", players);
menuBar.addTab(Forge.getLocalizer().getMessage("lblLog"), log);
menuBar.addTab(Forge.getLocalizer().getMessage("lblDev"), devMenu);
menuBar.addTab( Forge.getLocalizer().getMessage("lblStack") + " (0)", stack);
}
else {
menuBar.addTab(Forge.getLocalizer().getMessage("lblStack") + " (0)", stack);
} else {
menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(true));
stack.setRotate90(true);
menuBar.addTab(Forge.getLocalizer().getMessage("lblStack") + " (0)", stack);
@@ -162,11 +166,11 @@ public class MatchScreen extends FScreen {
}
}
private boolean is4Player(){
private boolean is4Player() {
return playerPanels.keySet().size() == 4;
}
private boolean is3Player(){
private boolean is3Player() {
return playerPanels.keySet().size() == 3;
}
@@ -176,9 +180,10 @@ public class MatchScreen extends FScreen {
private class HiddenMenuTab extends FMenuTab {
private HiddenMenuTab(FDropDown dropDown0) {
super(null, null, dropDown0, -1);
super(null, null, dropDown0, -1, false);
setVisible(false);
}
@Override
public void setText(String text0) {
//avoid trying to set text for this tab
@@ -214,8 +219,7 @@ public class MatchScreen extends FScreen {
Rectangle menuScreenPos = PlayerSpecificMenu.this.screenPos;
if (dropDown.getRotate180()) {
dropDown.getMenuTab().screenPos.setPosition(menuScreenPos.x + menuScreenPos.width, menuScreenPos.y);
}
else {
} else {
dropDown.getMenuTab().screenPos.setPosition(menuScreenPos.x + menuScreenPos.width, menuScreenPos.y + menuScreenPos.height);
}
dropDown.show();
@@ -233,8 +237,7 @@ public class MatchScreen extends FScreen {
if (ForgePreferences.DEV_MODE) {
addItem(new MenuItem(Forge.getLocalizer().getMessage("lblDev"), devMenu));
}
}
else { //TODO: Support using menu when player doesn't have priority
} else { //TODO: Support using menu when player doesn't have priority
FMenuItem item = new FMenuItem(Forge.getLocalizer().getMessage("lblMustWaitPriority"), null);
item.setEnabled(false);
addItem(item);
@@ -280,7 +283,7 @@ public class MatchScreen extends FScreen {
return topPlayerPanel;
}
public void setViewWinLose( ViewWinLose viewWinLose ){
public void setViewWinLose(ViewWinLose viewWinLose) {
this.viewWinLose = viewWinLose;
}
@@ -338,29 +341,31 @@ public class MatchScreen extends FScreen {
@Override
protected void drawOverlay(Graphics g) {
final GameView game = MatchController.instance.getGameView();
if (game == null) { return; }
if (gameMenu!=null) {
if (gameMenu.getChildCount()>1){
if (viewWinLose == null) {
gameMenu.getChildAt(0).setEnabled(!game.isMulligan());
gameMenu.getChildAt(1).setEnabled(!game.isMulligan());
if (!Forge.isMobileAdventureMode) {
gameMenu.getChildAt(2).setEnabled(!game.isMulligan());
gameMenu.getChildAt(3).setEnabled(false);
}
} else {
gameMenu.getChildAt(0).setEnabled(false);
gameMenu.getChildAt(1).setEnabled(false);
if (!Forge.isMobileAdventureMode) {
gameMenu.getChildAt(2).setEnabled(false);
gameMenu.getChildAt(3).setEnabled(true);
}
}
}
if (game == null) {
return;
}
if (devMenu!=null) {
if (devMenu.isVisible()){
if (gameMenu != null) {
if (gameMenu.getChildCount() > 1) {
if (viewWinLose == null) {
gameMenu.getChildAt(0).setEnabled(!game.isMulligan());
gameMenu.getChildAt(1).setEnabled(!game.isMulligan());
if (!Forge.isMobileAdventureMode) {
gameMenu.getChildAt(2).setEnabled(!game.isMulligan());
gameMenu.getChildAt(3).setEnabled(false);
}
} else {
gameMenu.getChildAt(0).setEnabled(false);
gameMenu.getChildAt(1).setEnabled(false);
if (!Forge.isMobileAdventureMode) {
gameMenu.getChildAt(2).setEnabled(false);
gameMenu.getChildAt(3).setEnabled(true);
}
}
}
}
if (devMenu != null) {
if (devMenu.isVisible()) {
try {
//rollbackphase enable -- todo limit by gametype?
devMenu.getChildAt(2).setEnabled(game.getPlayers().size() == 2 && game.getStack().size() == 0 && !GuiBase.isNetworkplay() && game.getPhase().isMain() && !game.getPlayerTurn().isAI());
@@ -384,7 +389,7 @@ public class MatchScreen extends FScreen {
}
drawArcs(g);
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ENABLE_MAGNIFIER) && Forge.magnify && Forge.magnifyToggle) {
if (Forge.isLandscapeMode() && (!GuiBase.isAndroid()||Forge.hasGamepad()) && !CardZoom.isOpen() && potentialListener != null) {
if (Forge.isLandscapeMode() && (!GuiBase.isAndroid() || Forge.hasGamepad()) && !CardZoom.isOpen() && potentialListener != null) {
for (FDisplayObject object : potentialListener) {
if (object != null) {
if (object instanceof FCardPanel) {
@@ -398,24 +403,23 @@ public class MatchScreen extends FScreen {
float cardW = getHeight() * 0.45f;
float cardH = FCardPanel.ASPECT_RATIO * cardW;
float cardX = !ZoneType.Battlefield.equals(cardPanel.getCard().getZone())
? cardPanel.screenPos.x-cardW : cardPanel.screenPos.x+(cardPanel.isTapped()
? cardPanel.getWidth() : cardPanel.getWidth()/1.4f);
? cardPanel.screenPos.x - cardW : cardPanel.screenPos.x + (cardPanel.isTapped()
? cardPanel.getWidth() : cardPanel.getWidth() / 1.4f);
if (vPlayerPanel.getSelectedTab() != null && vPlayerPanel.getSelectedTab().isVisible()
&& cardX > vPlayerPanel.getSelectedTab().getDisplayArea().getLeft()) {
cardX = cardPanel.screenPos.x-cardW;
cardX = cardPanel.screenPos.x - cardW;
}
if ((cardX+cardW) > scroller.getWidth()+scroller.getLeft())
cardX = cardPanel.screenPos.x-cardW;
if ((cardX + cardW) > scroller.getWidth() + scroller.getLeft())
cardX = cardPanel.screenPos.x - cardW;
if (vPlayerPanel.getCommandZone() != null
&& vPlayerPanel.getCommandZone().isVisible() && cardX > vPlayerPanel.getCommandZone().screenPos.x)
cardX = cardPanel.screenPos.x-cardW;
float cardY = (cardPanel.screenPos.y-cardH)+cardPanel.getHeight();
cardX = cardPanel.screenPos.x - cardW;
float cardY = (cardPanel.screenPos.y - cardH) + cardPanel.getHeight();
if (vPlayerPanel.getPlayer() == bottomPlayerPanel.getPlayer()) {
cardY = bottomPlayerPrompt.screenPos.y - cardH;
}
else if (cardY < vPlayerPanel.getField().screenPos.y && vPlayerPanel.getPlayer() != bottomPlayerPanel.getPlayer()) {
} else if (cardY < vPlayerPanel.getField().screenPos.y && vPlayerPanel.getPlayer() != bottomPlayerPanel.getPlayer()) {
cardY = vPlayerPanel.getField().screenPos.y;
if ((cardY+cardH) > bottomPlayerPrompt.screenPos.y)
if ((cardY + cardH) > bottomPlayerPrompt.screenPos.y)
cardY = bottomPlayerPrompt.screenPos.y - cardH;
}
if (Forge.magnifyShowDetails)
@@ -433,11 +437,11 @@ public class MatchScreen extends FScreen {
if (object.isHovered() && cardView != null && getStack().isVisible()) {
float cardW = getHeight() * 0.45f;
float cardH = FCardPanel.ASPECT_RATIO * cardW;
float cardX = object.screenPos.x-cardW-Utils.scale(4);
float cardY = object.screenPos.y-Utils.scale(2);
float cardX = object.screenPos.x - cardW - Utils.scale(4);
float cardY = object.screenPos.y - Utils.scale(2);
if (cardY < topPlayerPanel.getField().screenPos.y)
cardY = topPlayerPanel.getField().screenPos.y;
if ((cardY+cardH) > bottomPlayerPrompt.screenPos.y)
if ((cardY + cardH) > bottomPlayerPrompt.screenPos.y)
cardY = bottomPlayerPrompt.screenPos.y - cardH;
if (Forge.magnifyShowDetails)
CardImageRenderer.drawDetails(g, cardView, MatchController.instance.getGameView(), false, cardX, cardY, cardW, cardH);
@@ -453,6 +457,7 @@ public class MatchScreen extends FScreen {
}
}
}
void drawArcs(Graphics g) {
//get all card targeting arrow origins on the battlefield
final Map<Integer, Vector2> endpoints = new HashMap<>();
@@ -483,11 +488,11 @@ public class MatchScreen extends FScreen {
@Override
public boolean keyDown(int keyCode) {
// TODO: make the keyboard shortcuts configurable on Mobile
if (Forge.hasGamepad() && ((FMenuBar)getHeader()).isShowingMenu(false) && (keyCode == Keys.ESCAPE || keyCode == Keys.ENTER))
if (Forge.hasGamepad() && ((FMenuBar) getHeader()).isShowingMenu(false) && (keyCode == Keys.ESCAPE || keyCode == Keys.ENTER))
return false;
switch (keyCode) {
case Keys.DPAD_DOWN:
if (!((FMenuBar)getHeader()).isShowingMenu(true)) {
if (!((FMenuBar) getHeader()).isShowingMenu(true)) {
try {
InfoTab selected = selectedPlayerPanel().getSelectedTab();
if (selected != null && selected.getDisplayArea().isVisible()) {
@@ -506,11 +511,12 @@ public class MatchScreen extends FScreen {
}
}
revalidate(true);
} catch (Exception e) {}
} catch (Exception e) {
}
}
break;
case Keys.DPAD_RIGHT:
if (!((FMenuBar)getHeader()).isShowingMenu(true)) {
if (!((FMenuBar) getHeader()).isShowingMenu(true)) {
try {
InfoTab selected = selectedPlayerPanel().getSelectedTab();
if (selected != null && selected.getDisplayArea().isVisible()) {
@@ -519,11 +525,12 @@ public class MatchScreen extends FScreen {
selectedPlayerPanel().getSelectedRow().setNextSelected(1);
}
revalidate(true);
} catch (Exception e) {}
} catch (Exception e) {
}
}
break;
case Keys.DPAD_UP:
if (!((FMenuBar)getHeader()).isShowingMenu(true)) {
if (!((FMenuBar) getHeader()).isShowingMenu(true)) {
try {
InfoTab selected = selectedPlayerPanel().getSelectedTab();
if (selected != null && selected.getDisplayArea().isVisible()) {
@@ -542,11 +549,12 @@ public class MatchScreen extends FScreen {
}
}
revalidate(true);
} catch (Exception e) {}
} catch (Exception e) {
}
}
break;
case Keys.DPAD_LEFT:
if (!((FMenuBar)getHeader()).isShowingMenu(true)) {
if (!((FMenuBar) getHeader()).isShowingMenu(true)) {
try {
InfoTab selected = selectedPlayerPanel().getSelectedTab();
if (selected != null && selected.getDisplayArea().isVisible()) {
@@ -555,11 +563,12 @@ public class MatchScreen extends FScreen {
selectedPlayerPanel().getSelectedRow().setPreviousSelected(1);
}
revalidate(true);
} catch (Exception e) {}
} catch (Exception e) {
}
}
break;
case Keys.BUTTON_Y:
if (!((FMenuBar)getHeader()).isShowingMenu(true)) {
if (!((FMenuBar) getHeader()).isShowingMenu(true)) {
try {
InfoTab selected = selectedPlayerPanel().getSelectedTab();
if (selected != null && selected.getDisplayArea().isVisible()) {
@@ -567,11 +576,12 @@ public class MatchScreen extends FScreen {
} else {
selectedPlayerPanel().getSelectedRow().showZoom();
}
} catch (Exception e) {}
} catch (Exception e) {
}
}
break;
case Keys.BUTTON_A:
if (!((FMenuBar)getHeader()).isShowingMenu(true)) {
if (!((FMenuBar) getHeader()).isShowingMenu(true)) {
try {
InfoTab selected = selectedPlayerPanel().getSelectedTab();
if (selected != null && selected.getDisplayArea().isVisible()) {
@@ -581,7 +591,8 @@ public class MatchScreen extends FScreen {
//nullPotentialListener();
selectedPlayerPanel().getSelectedRow().tapChild();
}
} catch (Exception e) {}
} catch (Exception e) {
}
}
break;
case Keys.BUTTON_L1: //switch selected panels
@@ -590,7 +601,7 @@ public class MatchScreen extends FScreen {
selectedPlayerPanel().hideSelectedTab();
selectedPlayer--;
if (selectedPlayer < 0)
selectedPlayer=playerPanelsList.size()-1;
selectedPlayer = playerPanelsList.size() - 1;
selectedPlayerPanel().closeSelectedTab();
selectedPlayerPanel().getSelectedRow().unselectCurrent();
//selectedPlayerPanel().setNextSelectedTab(true);
@@ -652,8 +663,7 @@ public class MatchScreen extends FScreen {
if (gui.shouldAlwaysAcceptTrigger(triggerID)) {
gui.setShouldAlwaysAskTrigger(triggerID);
}
else {
} else {
gui.setShouldAlwaysAcceptTrigger(triggerID);
if (stackInstance.equals(gameView.peekStack())) {
//auto-yes if ability is on top of stack
@@ -686,8 +696,7 @@ public class MatchScreen extends FScreen {
if (gui.shouldAlwaysDeclineTrigger(triggerID)) {
gui.setShouldAlwaysAskTrigger(triggerID);
}
else {
} else {
gui.setShouldAlwaysDeclineTrigger(triggerID);
if (stackInstance.equals(gameView.peekStack())) {
//auto-no if ability is on top of stack
@@ -749,7 +758,7 @@ public class MatchScreen extends FScreen {
public void resetFields() {
CardAreaPanel.resetForNewGame();
for (VPlayerPanel playerPanel : getPlayerPanels().values()) {
for (CardAreaPanel p : playerPanel.getField().getCardPanels()){
for (CardAreaPanel p : playerPanel.getField().getCardPanels()) {
p.reset();
}
playerPanel.getZoneTab(ZoneType.Hand).getDisplayArea().clear();
@@ -778,22 +787,23 @@ 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
// 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
// pfps needs to actually do something
}
public void updateSingleCard(final CardView card) {
final CardAreaPanel pnl = CardAreaPanel.get(card);
if (pnl == null) { return; }
if (pnl == null) {
return;
}
final ZoneType zone = card.getZone();
if (zone != null && zone == ZoneType.Battlefield) {
pnl.updateCard(card);
}
else { //ensure card not on battlefield is reset such that it no longer thinks it's on the battlefield
} else { //ensure card not on battlefield is reset such that it no longer thinks it's on the battlefield
pnl.setTapped(false);
pnl.getAttachedPanels().clear();
pnl.setAttachedToPanel(null);
@@ -801,12 +811,14 @@ public class MatchScreen extends FScreen {
pnl.setNextPanelInStack(null);
}
}
private String daytime = null;
private Float time = null;
FSkinTexture currentBG = getBG();
FSkinTexture getBG() {
if (Forge.isMobileAdventureMode) {
switch(GameScene.instance().getAdventurePlayerLocation(false)) {
switch (GameScene.instance().getAdventurePlayerLocation(false)) {
case "green":
return FSkinTexture.ADV_BG_FOREST;
case "black":
@@ -831,6 +843,7 @@ public class MatchScreen extends FScreen {
}
return FSkinTexture.BG_MATCH;
}
private class BGAnimation extends ForgeAnimation {
private static final float DURATION = 1.4f;
private float progress = 0;
@@ -845,7 +858,7 @@ public class MatchScreen extends FScreen {
percentage = 1;
}
if (MatchController.instance.getGameView().isMatchOver())
percentage=1;
percentage = 1;
if (Forge.isMobileAdventureMode) {
if (percentage < 1)
g.drawNightDay(image, x, y, w, h, time, false, 0);
@@ -870,14 +883,14 @@ public class MatchScreen extends FScreen {
if (hasActivePlane()) {
String dt = MatchController.instance.getDayTime() == null ? "" : MatchController.instance.getDayTime();
if (percentage < 1)
g.drawRipple(image, x, y, w, h, 1-percentage);
g.drawRipple(image, x, y, w, h, 1 - percentage);
if ("Day".equalsIgnoreCase(dt)) {
g.setAlphaComposite(percentage);
g.drawNightDay(image, x, y, w, h, 100f, true, 1-percentage);
g.drawNightDay(image, x, y, w, h, 100f, true, 1 - percentage);
g.setAlphaComposite(oldAlpha);
} else if ("Night".equalsIgnoreCase(dt)) {
g.setAlphaComposite(percentage);
g.drawNightDay(image, x, y, w, h, -100f, true, 1-percentage);
g.drawNightDay(image, x, y, w, h, -100f, true, 1 - percentage);
g.setAlphaComposite(oldAlpha);
}
} else {
@@ -925,6 +938,7 @@ public class MatchScreen extends FScreen {
}
}
private class FieldScroller extends FScrollPane {
private float extraHeight = 0;
private String plane = "";
@@ -935,12 +949,12 @@ public class MatchScreen extends FScreen {
super.drawBackground(g);
if (!FModel.getPreferences().getPrefBoolean(FPref.UI_MATCH_IMAGE_VISIBLE)) {
if (!Forge.isMobileAdventureMode)
if(!hasActivePlane())
if (!hasActivePlane())
return;
}
boolean isGameFast = MatchController.instance.isGameFast();
float midField = topPlayerPanel.getBottom();
float promptHeight = !Forge.isLandscapeMode() || bottomPlayerPrompt == null ? 0f : bottomPlayerPrompt.getHeight()/1.3f;
float promptHeight = !Forge.isLandscapeMode() || bottomPlayerPrompt == null ? 0f : bottomPlayerPrompt.getHeight() / 1.3f;
float x = topPlayerPanel.getField().getLeft();
float y = midField - topPlayerPanel.getField().getHeight() - promptHeight;
float w = getWidth() - x;
@@ -998,8 +1012,10 @@ public class MatchScreen extends FScreen {
}
}
}
//auto adjust zoom for local multiplayer landscape mode
List<VPlayerPanel> losers = new ArrayList<>();
@Override
public void drawOverlay(Graphics g) {
if (Forge.isLandscapeMode()) {
@@ -1017,20 +1033,20 @@ public class MatchScreen extends FScreen {
height = p.getAvatar().getHeight();
p.setVisible(false);
playerPanelsList.remove(p);
System.out.println("Removed panel: "+p.getPlayer().toString());
System.out.println("Removed panel: " + p.getPlayer().toString());
}
}
losers.clear();
if (playerPanelsList.size() == 2) {
//reset avatar size
for (VPlayerPanel playerPanel : playerPanelsList) {
float size = playerPanel.getAvatar().getWidth()*2;
float size = playerPanel.getAvatar().getWidth() * 2;
playerPanel.getAvatar().setSize(size, size);
playerPanel.revalidate(true);
System.out.println("Panel Resized: "+playerPanel.getPlayer().toString());
System.out.println("Panel Resized: " + playerPanel.getPlayer().toString());
}
}
zoom(0,0, height);
zoom(0, 0, height);
}
}
@@ -1041,7 +1057,7 @@ public class MatchScreen extends FScreen {
//field separator lines
if (!Forge.isLandscapeMode()) {
for (VPlayerPanel playerPanel: playerPanelsList){
for (VPlayerPanel playerPanel : playerPanelsList) {
midField = playerPanel.getTop();
y = midField - playerPanel.getField().getHeight();
if (playerPanel.getSelectedTab() == null) {
@@ -1051,7 +1067,7 @@ public class MatchScreen extends FScreen {
}
}
for (VPlayerPanel playerPanel: playerPanelsList){
for (VPlayerPanel playerPanel : playerPanelsList) {
midField = playerPanel.getTop();
y = midField - 0.5f;
g.drawLine(1, getBorderColor(), x, y, w, y);
@@ -1066,7 +1082,7 @@ public class MatchScreen extends FScreen {
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
float totalHeight = visibleHeight + extraHeight;
float avatarHeight = VAvatar.HEIGHT;
if (is4Player() || is3Player()){
if (is4Player() || is3Player()) {
avatarHeight *= 0.5f;
}
float playerCount = getPlayerPanels().keySet().size();
@@ -1154,14 +1170,19 @@ public class MatchScreen extends FScreen {
}
backupHorzScrollPane(playerPanel.getCommandZone(), x, horzScrollPanes);
}
private void backupHorzScrollPane(FScrollPane scrollPane, float x, Map<FScrollPane, Pair<Float, Float>> horzScrollPanes) {
horzScrollPanes.put(scrollPane, Pair.of(scrollPane.getScrollLeft(), scrollPane.getScrollWidth()));
}
}
private String getPlaneName(){ return MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName(); }
private boolean hasActivePlane(){
if(MatchController.instance.getGameView() != null)
if(MatchController.instance.getGameView().getPlanarPlayer() != null) {
private String getPlaneName() {
return MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName();
}
private boolean hasActivePlane() {
if (MatchController.instance.getGameView() != null)
if (MatchController.instance.getGameView().getPlanarPlayer() != null) {
return !MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName().equals("");
}
return false;
@@ -1172,22 +1193,25 @@ public class MatchScreen extends FScreen {
setPotentialListener(listeners);
super.buildTouchListeners(screenX, screenY, listeners);
}
public VPlayerPanel selectedPlayerPanel() {
if (selectedPlayer >= playerPanelsList.size())
selectedPlayer = playerPanelsList.size()-1;
selectedPlayer = playerPanelsList.size() - 1;
if (playerPanelsList.isEmpty())
return null;
return playerPanelsList.get(selectedPlayer);
}
public static void setPotentialListener(List<FDisplayObject> listener) {
if (potentialListener != null)
for (FDisplayObject f: potentialListener)
for (FDisplayObject f : potentialListener)
f.setHovered(false);
potentialListener = listener;
}
public static void nullPotentialListener() {
if (potentialListener != null)
for (FDisplayObject f: potentialListener)
for (FDisplayObject f : potentialListener)
f.setHovered(false);
potentialListener = null;
}

View File

@@ -11,6 +11,7 @@ import forge.Graphics;
import forge.animation.ForgeAnimation;
import forge.assets.FImage;
import forge.assets.FSkin;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.game.card.CounterEnumType;
import forge.game.player.PlayerView;
@@ -153,15 +154,11 @@ public class VAvatar extends FDisplayObject {
float alpha = displayPriority ? 1f : 0.8f;
if (alphaModifier < 1)
alpha = alphaModifier;
g.setAlphaComposite(alpha);
g.drawRect(w / 16f, Color.CYAN, 0, 0, w, h);
g.setAlphaComposite(oldAlpha);
g.drawRect(w / 16f, FSkinColor.getStandardColor(Color.CYAN).alphaColor(alpha), 0, 0, w, h);
}
//priority indicator
if (displayPriority && player.getHasPriority() && alphaModifier == 1) {
g.setAlphaComposite(0.6f);
g.drawRect(w / 16f, Color.LIME, 0, 0, w, h);
g.setAlphaComposite(oldAlpha);
g.drawRect(w / 16f, FSkinColor.getStandardColor(Color.LIME).alphaColor(0.6f), 0, 0, w, h);
}
//highlighted
if (MatchController.instance.isHighlighted(player)) {

View File

@@ -0,0 +1,159 @@
package forge.screens.match.views;
import com.badlogic.gdx.utils.Align;
import forge.Forge;
import forge.Graphics;
import forge.assets.FImage;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.TextRenderer;
import forge.card.CardRenderer;
import forge.card.CardZoom;
import forge.game.card.CardView;
import forge.gui.card.CardDetailUtil;
import forge.menu.FDropDown;
import forge.screens.match.MatchController;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FLabel;
import forge.trackable.TrackableCollection;
import forge.util.CardTranslation;
import forge.util.Utils;
import java.util.ArrayList;
import java.util.List;
public class VReveal extends FDropDown {
public static final float MARGINS = Utils.scale(4);
private static final FSkinFont FONT = FSkinFont.get(11);
public static final float PADDING = Utils.scale(3);
private TrackableCollection<CardView> revealed;
private static FSkinColor getAltRowColor() {
if (Forge.isMobileAdventureMode)
return FSkinColor.get(FSkinColor.Colors.ADV_CLR_ZEBRA);
return FSkinColor.get(FSkinColor.Colors.CLR_ZEBRA);
}
private static FSkinColor getRowColor() {
return getAltRowColor().darker();
}
private static FSkinColor getForeColor() {
if (Forge.isMobileAdventureMode)
return FSkinColor.get(FSkinColor.Colors.ADV_CLR_TEXT);
return FSkinColor.get(FSkinColor.Colors.CLR_TEXT);
}
private final TextRenderer renderer = new TextRenderer(false);
@Override
protected boolean autoHide() {
return true;
}
@Override
protected void drawBackground(Graphics g) {
float w = getWidth();
float h = getHeight();
g.fillRect(getRowColor(), 0, 0, w, h); //can fill background with main row color since drop down will never be taller than number of rows
}
@Override
protected ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight) {
float x = MARGINS;
float y = MARGINS;
float totalWidth = Forge.getScreenWidth();
float width = totalWidth - 2 * MARGINS;
float entryHeight;
float entryWidth = totalWidth;
float minWidth = 4 * Utils.AVG_FINGER_WIDTH;
if (entryWidth < minWidth) {
entryWidth = minWidth;
}
revealed = MatchController.instance.getGameView().getRevealedCollection();
if (revealed == null || revealed.isEmpty()) {
FLabel label = add(new FLabel.Builder().text("[" + Forge.getLocalizer().getMessage("lblEmpty") + "]").font(FSkinFont.get(11)).align(Align.center).build());
float height = Math.round(label.getAutoSizeBounds().height) + 2 * PADDING;
label.setBounds(x, y, width, height);
return new ScrollBounds(totalWidth, y + height + MARGINS);
} else {
clear();
boolean isAltRow = false;
RevealEntryDisplay revealEntryDisplay;
x = getMenuTab().screenPos.x;
y = 1;
for (CardView c : revealed) {
revealEntryDisplay = add(new RevealEntryDisplay(c, isAltRow));
isAltRow = !isAltRow;
entryHeight = revealEntryDisplay.getMinHeight(entryWidth) + MARGINS;
revealEntryDisplay.setBounds(0, y, entryWidth, entryHeight);
y += entryHeight;
}
}
return new ScrollBounds(totalWidth, y + MARGINS);
}
private class RevealEntryDisplay extends FDisplayObject {
CardView card;
boolean altRow;
String text;
FImage cardArt;
private RevealEntryDisplay(CardView cardView, boolean isAltRow) {
card = cardView;
altRow = isAltRow;
text = CardTranslation.getTranslatedName(card.getCurrentState().getName()) + "\n" + formatType();
cardArt = CardRenderer.getCardArt(cardView);
}
private float getMinHeight(float width) {
width -= 2 * PADDING; //account for left and right insets
float height = renderer.getWrappedBounds("\n", FONT, width).height;
height += 2 * PADDING;
return Math.round(height);
}
@Override
public boolean tap(float x, float y, int count) {
try {
List<CardView> cardViewList = new ArrayList<>(revealed);
int index = cardViewList.indexOf(card);
CardZoom.show(cardViewList, index, null);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
@Override
public void draw(Graphics g) {
float w = getWidth();
float h = getHeight();
float cardArtWidth = h * 1.302f;
if (altRow) {
g.fillRect(getAltRowColor(), 0, 0, w, h);
}
if (isHovered()) {
g.fillRect(getForeColor().brighter().alphaColor(0.3f), 0, 0, w, h);
}
g.drawImage(cardArt, 0, 0, cardArtWidth, h);
//use full height without padding so text not scaled down
renderer.drawText(g, text, FONT, getForeColor(), cardArtWidth + PADDING, PADDING, w - (2 * PADDING + cardArtWidth), h, 0, h, false, Align.left, false);
}
private String formatType() {
String type = CardDetailUtil.formatCardType(card.getCurrentState(), true);
if (card.getCurrentState().isCreature()) { //include P/T or Loyalty at end of type
type += " (" + card.getCurrentState().getPower() + " / " + card.getCurrentState().getToughness() + ")";
} else if (card.getCurrentState().isPlaneswalker()) {
type += " (" + card.getCurrentState().getLoyalty() + ")";
} else if (card.getCurrentState().getType().hasSubtype("Vehicle")) {
type += String.format(" [%s / %s]", card.getCurrentState().getPower(), card.getCurrentState().getToughness());
}
return type;
}
}
}

View File

@@ -427,9 +427,7 @@ public class FLabel extends FDisplayObject implements IButton {
else if (!text.isEmpty()) {
float oldAlpha = g.getfloatAlphaComposite();
if (isHovered() && selectable) {
g.setAlphaComposite(0.4f);
g.fillRect(Color.GRAY, x, y, w, h);
g.setAlphaComposite(oldAlpha);
g.fillRect(FSkinColor.getStandardColor(Color.GRAY).alphaColor(0.4f), x, y, w, h);
}
drawText(g, x, y, w, h, alignment);
}

View File

@@ -15,7 +15,7 @@ import forge.util.Utils;
public abstract class FScrollPane extends FContainer {
private static final float FLING_DECEL = 750f;
private static FSkinColor getIndicatorColor() {
public static FSkinColor getIndicatorColor() {
if (Forge.isMobileAdventureMode)
return FSkinColor.get(FSkinColor.Colors.ADV_CLR_TEXT).alphaColor(0.7f);
return FSkinColor.get(FSkinColor.Colors.CLR_TEXT).alphaColor(0.7f);
@@ -30,6 +30,14 @@ public abstract class FScrollPane extends FContainer {
scrollBounds = new ScrollBounds();
}
public float getIndicatorMargin() {
return INDICATOR_MARGIN;
}
public float getIndicatorSize() {
return INDICATOR_SIZE;
}
public float getScrollLeft() {
return scrollLeft;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -9,6 +9,7 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import forge.trackable.TrackableCollection;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList;
@@ -50,12 +51,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public final boolean hasLocalPlayers() {
return !gameControllers.isEmpty();
}
public final Set<PlayerView> getLocalPlayers() {
return gameControllers.keySet();
}
public final int getLocalPlayerCount() {
return gameControllers.size();
}
public final boolean isLocalPlayer(final PlayerView player) {
return gameControllers.containsKey(player);
}
@@ -94,12 +98,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
currentPlayer = player;
updateCurrentPlayer(player);
}
protected abstract void updateCurrentPlayer(PlayerView player);
private GameView gameView = null;
public final GameView getGameView() {
return gameView;
}
@Override
public void setGameView(final GameView gameView0) {
if (gameView == null || gameView0 == null) {
@@ -118,6 +125,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public final IGameController getGameController() {
return getGameController(getCurrentPlayer());
}
public final IGameController getGameController(final PlayerView player) {
if (player == null) {
return spectator;
@@ -180,6 +188,16 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
updateCards(Collections.singleton(card));
}
@Override
public void updateRevealedCards(TrackableCollection<CardView> collection) {
if (gameView != null) {
TrackableCollection<CardView> existing = gameView.getRevealedCollection();
if (existing != null)
collection.addAll(existing);
gameView.updateRevealedCards(collection);
}
}
@Override
public void refreshCardDetails(final Iterable<CardView> cards) {
//not needed for base game implementation
@@ -199,7 +217,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
if (gameView != null && gameView.isGameOver()) {
return true;
}
if (spectator!=null) { //workaround fix!! this is needed on above code or it will
if (spectator != null) { //workaround fix!! this is needed on above code or it will
for (Map.Entry<PlayerView, IGameController> e : gameControllers.entrySet()) {
if (e.getValue().equals(spectator)) {
gameControllers.remove(e.getKey());
@@ -212,7 +230,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
if (getGameController().mayLookAtAllCards()) { // when it bugged here, the game thinks the spectator (null)
return true; // is the humancontroller here (maybe because there is an existing game thread???)
}
} catch (NullPointerException e){
} catch (NullPointerException e) {
return true; // return true so it will work as normal
}
} else {
@@ -225,10 +243,14 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
@Override
public boolean mayFlip(final CardView cv) {
if (cv == null) { return false; }
if (cv == null) {
return false;
}
final CardStateView altState = cv.getAlternateState();
if (altState == null) { return false; }
if (altState == null) {
return false;
}
switch (altState.getState()) {
case Original:
@@ -252,6 +274,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
}
private final Set<PlayerView> highlightedPlayers = Sets.newHashSet();
@Override
public void setHighlighted(final PlayerView pv, final boolean b) {
final boolean hasChanged = b ? highlightedPlayers.add(pv) : highlightedPlayers.remove(pv);
@@ -265,6 +288,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
}
private final Set<CardView> highlightedCards = Sets.newHashSet();
// used to highlight cards in UI
@Override
public void setUsedToPay(final CardView card, final boolean value) {
@@ -279,34 +303,56 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
}
private final Set<CardView> selectableCards = Sets.newHashSet();
public void setSelectables(final Iterable<CardView> cards) {
for (CardView cv : cards) { selectableCards.add(cv); }
for (CardView cv : cards) {
selectableCards.add(cv);
}
}
public void clearSelectables() {
selectableCards.clear();
}
public boolean isSelectable(final CardView card) {
return selectableCards.contains(card);
}
public boolean isSelecting() {
return !selectableCards.isEmpty();
}
public boolean isGamePaused() { return gamePause; }
public boolean isGameFast() { return gameSpeed; }
public void setgamePause(boolean pause) { gamePause = pause; }
public void setGameSpeed(boolean isFast) { gameSpeed = isFast; }
public boolean isGamePaused() {
return gamePause;
}
public boolean isGameFast() {
return gameSpeed;
}
public void setgamePause(boolean pause) {
gamePause = pause;
}
public void setGameSpeed(boolean isFast) {
gameSpeed = isFast;
}
public void pauseMatch() {
IGameController controller = spectator;
if (controller != null && !isGamePaused())
controller.selectButtonOk();
}
public void resumeMatch() {
IGameController controller = spectator;
if (controller != null && isGamePaused())
controller.selectButtonOk();
}
/** Concede game, bring up WinLose UI. */
/**
* Concede game, bring up WinLose UI.
*/
public boolean concede() {
if (gameView.isGameOver()) {
return true;
@@ -346,11 +392,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
}
ignoreConcedeChain = false;
return false;
}
else if (spectator == null) {
} else if (spectator == null) {
return true; //if no local players or spectator, just quit
}
else {
} else {
if (showConfirmDialog(Localizer.getInstance().getMessage("lblCloseGameSpectator"), Localizer.getInstance().getMessage("lblCloseGame"), Localizer.getInstance().getMessage("lblClose"), Localizer.getInstance().getMessage("lblCancel"))) {
IGameController controller = spectator;
spectator = null; //ensure we don't prompt again, including when calling nextGameDecision below
@@ -421,14 +465,11 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
awaitNextInputTask = new TimerTask() {
@Override
public void run() {
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
synchronized (awaitNextInputTimer) {
if (awaitNextInputTask != null) {
updatePromptForAwait(getCurrentPlayer());
awaitNextInputTask = null;
}
FThreads.invokeInEdtLater(() -> {
synchronized (awaitNextInputTimer) {
if (awaitNextInputTask != null) {
updatePromptForAwait(getCurrentPlayer());
awaitNextInputTask = null;
}
}
});
@@ -451,7 +492,8 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
if (awaitNextInputTask != null) {
try {
awaitNextInputTask.cancel(); //cancel timer once next input shown if needed
} catch (final Exception ex) {} //suppress any exception thrown by cancel()
} catch (final Exception ex) {
} //suppress any exception thrown by cancel()
awaitNextInputTask = null;
}
}
@@ -470,9 +512,11 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
// Abilities to auto-yield to
private final Set<String> autoYields = Sets.newHashSet();
public final Iterable<String> getAutoYields() {
return autoYields;
}
@Override
public final boolean shouldAutoYield(final String key) {
String abilityKey = key.indexOf("): ") != -1 ? key.substring(key.indexOf("): ") + 3) : key;
@@ -480,6 +524,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
return !getDisableAutoYields() && autoYields.contains(yieldPerAbility ? abilityKey : key);
}
@Override
public final void setShouldAutoYield(final String key, final boolean autoYield) {
String abilityKey = key.indexOf("): ") != -1 ? key.substring(key.indexOf("): ") + 3) : key;
@@ -487,16 +532,17 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
if (autoYield) {
autoYields.add(yieldPerAbility ? abilityKey : key);
}
else {
} else {
autoYields.remove(yieldPerAbility ? abilityKey : key);
}
}
private boolean disableAutoYields;
public final boolean getDisableAutoYields() {
return disableAutoYields;
}
public final void setDisableAutoYields(final boolean b0) {
disableAutoYields = b0;
}
@@ -511,16 +557,29 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
private final Map<Integer, Boolean> triggersAlwaysAccept = Maps.newTreeMap();
@Override
public final boolean shouldAlwaysAcceptTrigger(final int trigger) { return Boolean.TRUE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger))); }
@Override
public final boolean shouldAlwaysDeclineTrigger(final int trigger) { return Boolean.FALSE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger))); }
public final boolean shouldAlwaysAcceptTrigger(final int trigger) {
return Boolean.TRUE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger)));
}
@Override
public final void setShouldAlwaysAcceptTrigger(final int trigger) { triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.TRUE); }
public final boolean shouldAlwaysDeclineTrigger(final int trigger) {
return Boolean.FALSE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger)));
}
@Override
public final void setShouldAlwaysDeclineTrigger(final int trigger) { triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.FALSE); }
public final void setShouldAlwaysAcceptTrigger(final int trigger) {
triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.TRUE);
}
@Override
public final void setShouldAlwaysAskTrigger(final int trigger) { triggersAlwaysAccept.remove(Integer.valueOf(trigger)); }
public final void setShouldAlwaysDeclineTrigger(final int trigger) {
triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.FALSE);
}
@Override
public final void setShouldAlwaysAskTrigger(final int trigger) {
triggersAlwaysAccept.remove(Integer.valueOf(trigger));
}
// End of Triggers preliminary choice
@@ -529,15 +588,12 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
/**
* Convenience for getChoices(message, 0, 1, choices).
*
* @param <T>
* is automatically inferred.
* @param message
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @param <T> is automatically inferred.
* @param message a {@link java.lang.String} object.
* @param choices a T object.
* @return null if choices is missing, empty, or if the users' choices are
* empty; otherwise, returns the first item in the List returned by
* getChoices.
* empty; otherwise, returns the first item in the List returned by
* getChoices.
* @see #getChoices(String, int, int, List)
*/
@Override
@@ -550,17 +606,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
}
// returned Object will never be null
/**
* <p>
* getChoice.
* </p>
*
* @param <T>
* a T object.
* @param message
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @param <T> a T object.
* @param message a {@link java.lang.String} object.
* @param choices a T object.
* @return a T object.
*/
@Override
@@ -588,13 +642,17 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public Integer getInteger(final String message, final int min) {
return getInteger(message, min, Integer.MAX_VALUE, false);
}
@Override
public Integer getInteger(final String message, final int min, final int max) {
return getInteger(message, min, max, false);
}
@Override
public Integer getInteger(final String message, final int min, final int max, final boolean sortDesc) {
if (max <= min) { return min; } //just return min if max <= min
if (max <= min) {
return min;
} //just return min if max <= min
//force cutting off after 100 numbers at most
if (max == Integer.MAX_VALUE) {
@@ -654,7 +712,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
while (true) {
final String str = showInputDialog(prompt, message);
if (str == null) { return null; } // that is 'cancel'
if (str == null) {
return null;
} // that is 'cancel'
if (StringUtils.isNumeric(str)) {
final Integer val = Integer.valueOf(str);
@@ -696,8 +756,8 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
* current implementation requires the user to cancel in order to get the
* new item to be the first item in the resulting list.
*
* @param title the dialog title.
* @param newItem the object to insert.
* @param title the dialog title.
* @param newItem the object to insert.
* @param oldItems the list of objects.
* @return A shallow copy of the list of objects, with newItem inserted.
*/
@@ -753,24 +813,24 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
@Override
public boolean showConfirmDialog(final String message, final String title,
final boolean defaultYes) {
final boolean defaultYes) {
return showConfirmDialog(message, title, Localizer.getInstance().getMessage("lblYes"), Localizer.getInstance().getMessage("lblNo"));
}
@Override
public boolean showConfirmDialog(final String message, final String title,
final String yesButtonText, final String noButtonText) {
final String yesButtonText, final String noButtonText) {
return showConfirmDialog(message, title, yesButtonText, noButtonText, true);
}
@Override
public void notifyStackAddition(GameEventSpellAbilityCast event) {
public void notifyStackAddition(GameEventSpellAbilityCast event) {
}
@Override
public void notifyStackRemoval(GameEventSpellRemovedFromStack event) {
}
@Override
public void handleLandPlayed(Card land) {
}

View File

@@ -31,90 +31,142 @@ import forge.util.ITriggerEvent;
public interface IGuiGame {
void setGameView(GameView gameView);
GameView getGameView();
void setOriginalGameController(PlayerView view, IGameController gameController);
void setGameController(PlayerView player, IGameController gameController);
void setSpectator(IGameController spectator);
void openView(TrackableCollection<PlayerView> myPlayers);
void afterGameEnd();
void showCombat();
void showPromptMessage(PlayerView playerView, String message);
void showCardPromptMessage(PlayerView playerView, String message, CardView card);
void updateButtons(PlayerView owner, boolean okEnabled, boolean cancelEnabled, boolean focusOk);
void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1);
void flashIncorrectAction();
void alertUser();
void updatePhase(boolean saveState);
void updateTurn(PlayerView player);
void updatePlayerControl();
void enableOverlay();
void disableOverlay();
void finishGame();
void showManaPool(PlayerView player);
void hideManaPool(PlayerView player);
void updateStack();
void notifyStackAddition(final GameEventSpellAbilityCast event);
void notifyStackRemoval(final GameEventSpellRemovedFromStack event);
void handleLandPlayed(Card land);
Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate);
void updateSingleCard(CardView card);
void updateCards(Iterable<CardView> cards);
void updateRevealedCards(TrackableCollection<CardView> collection);
void refreshCardDetails(Iterable<CardView> cards);
void refreshField();
GameState getGamestate();
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
void updateLives(Iterable<PlayerView> livesUpdate);
void setPanelSelection(CardView hostCard);
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent);
Map<CardView, Integer> assignCombatDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder, boolean maySkip);
// The Object passed should be GameEntityView for most case. Can be Byte for "generate mana of any combination" effect
Map<Object, Integer> assignGenericAmount(CardView effectSource, Map<Object, Integer> target, int amount, final boolean atLeastOne, final String amountLabel);
void message(String message);
void message(String message, String title);
void showErrorDialog(String message);
void showErrorDialog(String message, String title);
boolean showConfirmDialog(String message, String title);
boolean showConfirmDialog(String message, String title, boolean defaultYes);
boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText);
boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText, boolean defaultYes);
int showOptionDialog(String message, String title, FSkinProp icon, List<String> options, int defaultOption);
String showInputDialog(String message, String title);
String showInputDialog(String message, String title, FSkinProp icon);
String showInputDialog(String message, String title, FSkinProp icon, String initialInput);
String showInputDialog(String message, String title, FSkinProp icon, String initialInput, List<String> inputOptions);
boolean confirm(CardView c, String question);
boolean confirm(CardView c, String question, List<String> options);
boolean confirm(CardView c, String question, boolean defaultIsYes, List<String> options);
<T> List<T> getChoices(String message, int min, int max, List<T> choices);
<T> List<T> getChoices(String message, int min, int max, List<T> choices, T selected, Function<T, String> display);
// Get Integer in range
Integer getInteger(String message, int min);
Integer getInteger(String message, int min, int max);
Integer getInteger(String message, int min, int max, boolean sortDesc);
Integer getInteger(String message, int min, int max, int cutoff);
/**
* Convenience for getChoices(message, 0, 1, choices).
*
* @param <T>
* is automatically inferred.
* @param message
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @param <T> is automatically inferred.
* @param message a {@link java.lang.String} object.
* @param choices a T object.
* @return null if choices is missing, empty, or if the users' choices are
* empty; otherwise, returns the first item in the List returned by
* getChoices.
* empty; otherwise, returns the first item in the List returned by
* getChoices.
*/
<T> T oneOrNone(String message, List<T> choices);
@@ -123,12 +175,9 @@ public interface IGuiGame {
* getChoice.
* </p>
*
* @param <T>
* a T object.
* @param message
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @param <T> a T object.
* @param message a {@link java.lang.String} object.
* @param choices a T object.
* @return One of {@code choices}. Can only be {@code null} if {@code choices} is empty.
*/
<T> T one(String message, List<T> choices);
@@ -136,9 +185,11 @@ public interface IGuiGame {
<T> void reveal(String message, List<T> items);
<T> List<T> many(String title, String topCaption, int cnt, List<T> sourceChoices, CardView c);
<T> List<T> many(String title, String topCaption, int min, int max, List<T> sourceChoices, CardView c);
<T> List<T> order(String title, String top, List<T> sourceChoices, CardView c);
<T> List<T> order(String title, String top, int remainingObjectsMin, int remainingObjectsMax, List<T> sourceChoices, List<T> destChoices, CardView referenceCard, boolean sideboardingMode);
/**
@@ -146,53 +197,78 @@ public interface IGuiGame {
* current implementation requires the user to cancel in order to get the
* new item to be the first item in the resulting list.
*
* @param title
* the dialog title.
* @param newItem
* the object to insert.
* @param oldItems
* the list of objects.
* @param title the dialog title.
* @param newItem the object to insert.
* @param oldItems the list of objects.
* @return A shallow copy of the list of objects, with newItem inserted.
*/
<T> List<T> insertInList(String title, T newItem, List<T> oldItems);
List<PaperCard> sideboard(CardPool sideboard, CardPool main, String message);
GameEntityView chooseSingleEntityForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal, boolean isOptional);
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<CardView> manipulateCardList(String title, final Iterable<CardView> cards, final Iterable<CardView> manipulable, boolean toTop, boolean toBottom, boolean toAnywhere);
void setCard(CardView card);
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
PlayerZoneUpdates openZones(PlayerView controller, Collection<ZoneType> zones, Map<PlayerView, Object> players, boolean backupLastZones);
void restoreOldZones(PlayerView playerView, PlayerZoneUpdates playerZoneUpdates);
void setHighlighted(PlayerView pv, boolean b);
void setUsedToPay(CardView card, boolean value);
void setSelectables(final Iterable<CardView> cards);
void clearSelectables();
boolean isSelecting();
boolean isGamePaused();
void setgamePause(boolean pause);
void setGameSpeed(boolean gameSpeed);
String getDayTime();
void updateDayTime(String daytime);
void awaitNextInput();
void cancelAwaitNextInput();
boolean isUiSetToSkipPhase(PlayerView playerTurn, PhaseType phase);
void autoPassUntilEndOfTurn(PlayerView player);
boolean mayAutoPass(PlayerView player);
void autoPassCancel(PlayerView player);
void updateAutoPassPrompt();
boolean shouldAutoYield(String key);
void setShouldAutoYield(String key, boolean autoYield);
boolean shouldAlwaysAcceptTrigger(int trigger);
boolean shouldAlwaysDeclineTrigger(int trigger);
void setShouldAlwaysAcceptTrigger(int trigger);
void setShouldAlwaysDeclineTrigger(int trigger);
void setShouldAlwaysAskTrigger(int trigger);
void clearAutoYields();
void setCurrentPlayer(PlayerView player);

View File

@@ -328,6 +328,9 @@ public enum FSkinProp {
ICO_FAVICON (new int[] {0, 640, 80, 80}, PropType.ICON),
ICO_LOCK (new int[] {620, 800, 48, 48}, PropType.ICON),
//reveal icons
ICO_SEE (new int[] {568, 1520, 60, 40}, PropType.ICON),
ICO_UNSEE (new int[] {568, 1560, 60, 40}, PropType.ICON),
//layout images
IMG_HANDLE (new int[] {320, 450, 80, 20}, PropType.IMAGE),

View File

@@ -19,6 +19,7 @@ import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.TreeSet;
import forge.trackable.TrackableCollection;
import forge.util.ImageUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.Range;
@@ -148,7 +149,7 @@ import io.sentry.Sentry;
/**
* A prototype for player controller class
*
* <p>
* Handles phase skips for now.
*/
public class PlayerControllerHuman extends PlayerController implements IGameController {
@@ -258,8 +259,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
* Set this to {@code true} to enable this player to see all cards any other
* player can see.
*
* @param mayLookAtAllCards
* the mayLookAtAllCards to set
* @param mayLookAtAllCards the mayLookAtAllCards to set
*/
public void setMayLookAtAllCards(final boolean mayLookAtAllCards) {
this.mayLookAtAllCards = mayLookAtAllCards;
@@ -271,7 +271,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities,
final ITriggerEvent triggerEvent) {
final ITriggerEvent triggerEvent) {
// make sure another human player can't choose opponents cards just because he might see them
if (triggerEvent != null && !hostCard.isInPlay() && !hostCard.getOwner().equals(player) &&
!hostCard.getController().equals(player) &&
@@ -355,15 +355,15 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Map<Card, Integer> assignCombatDamage(final Card attacker, final CardCollectionView blockers, final CardCollectionView remaining,
final int damageDealt, final GameEntity defender, final boolean overrideOrder) {
final int damageDealt, final GameEntity defender, final boolean overrideOrder) {
// Attacker is a poor name here, since the creature assigning damage
// could just as easily be the blocker.
final Map<Card, Integer> map = Maps.newHashMap();
if ((attacker.hasKeyword(Keyword.TRAMPLE) && defender != null) || (blockers.size() > 1)
|| ((attacker.hasKeyword("You may assign CARDNAME's combat damage divided as you choose among " +
"defending player and/or any number of creatures they control.")) && overrideOrder &&
blockers.size() > 0) || (attacker.hasKeyword("Trample:Planeswalker") && defender instanceof Card)) {
"defending player and/or any number of creatures they control.")) && overrideOrder &&
blockers.size() > 0) || (attacker.hasKeyword("Trample:Planeswalker") && defender instanceof Card)) {
GameEntityViewMap<Card, CardView> gameCacheBlockers = GameEntityView.getMap(blockers);
final CardView vAttacker = CardView.get(attacker);
final GameEntityView vDefender = GameEntityView.get(defender);
@@ -398,7 +398,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
vAffected.put(GameEntityView.get(e.getKey()), e.getValue());
}
final Map<Object, Integer> vResult = getGui().assignGenericAmount(vSource, vAffected, shieldAmount, false,
localizer.getMessage("lblShield"));
localizer.getMessage("lblShield"));
Map<GameEntity, Integer> result = new HashMap<>();
if (vResult != null) { //fix for netplay
for (Map.Entry<GameEntity, Integer> e : affected.entrySet()) {
@@ -420,7 +420,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
vAffected.put(it.next(), maxAmount);
}
final Map<Object, Integer> vResult = getGui().assignGenericAmount(vSource, vAffected, manaAmount, false,
localizer.getMessage("lblMana").toLowerCase());
localizer.getMessage("lblMana").toLowerCase());
Map<Byte, Integer> result = new HashMap<>();
if (vResult != null) { //fix for netplay
it = colorSet.iterator();
@@ -471,7 +471,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
ability.getParamOrDefault("AnnounceTitle", announce);
if (cost.isMandatory()) {
return chooseNumber(ability, localizer.getMessage("lblChooseAnnounceForCard", announceTitle,
CardTranslation.getTranslatedName(ability.getHostCard().getName())) , min, max);
CardTranslation.getTranslatedName(ability.getHostCard().getName())), min, max);
}
if ("NumTimes".equals(announce)) {
return getGui().getInteger(localizer.getMessage("lblHowManyTimesToPay", ability.getPayCosts().getTotalMana(),
@@ -483,18 +483,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public CardCollectionView choosePermanentsToSacrifice(final SpellAbility sa, final int min, final int max,
final CardCollectionView valid, final String message) {
final CardCollectionView valid, final String message) {
return choosePermanentsTo(min, max, valid, message, localizer.getMessage("lblSacrifice").toLowerCase(), sa);
}
@Override
public CardCollectionView choosePermanentsToDestroy(final SpellAbility sa, final int min, final int max,
final CardCollectionView valid, final String message) {
final CardCollectionView valid, final String message) {
return choosePermanentsTo(min, max, valid, message, localizer.getMessage("lblDestroy"), sa);
}
private CardCollectionView choosePermanentsTo(final int min, int max, final CardCollectionView valid,
final String message, final String action, final SpellAbility sa) {
final String message, final String action, final SpellAbility sa) {
max = Math.min(max, valid.size());
if (max <= 0) {
return CardCollection.EMPTY;
@@ -516,7 +516,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
private boolean useSelectCardsInput(final FCollectionView<? extends GameEntity> sourceList) {
// can't use InputSelect from GUI thread (e.g., DevMode Tutor)
if (FThreads.isGuiThread()) { return false; }
if (FThreads.isGuiThread()) {
return false;
}
// 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
@@ -535,11 +537,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
}
final boolean useUiPointAtCard =
(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.Sideboard)) :
(cz.is(ZoneType.Hand, player) || cz.is(ZoneType.Battlefield));
(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.Sideboard)) :
(cz.is(ZoneType.Hand, player) || cz.is(ZoneType.Battlefield));
if (!useUiPointAtCard) {
return false;
}
@@ -549,7 +551,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public CardCollectionView chooseCardsForEffect(final CardCollectionView sourceList, final SpellAbility sa,
final String title, final int min, final int max, final boolean isOptional, Map<String, Object> params) {
final String title, final int min, final int max, final boolean isOptional, Map<String, Object> params) {
// If only one card to choose, use a dialog box.
// Otherwise, use the order dialog to be able to grab multiple cards in one shot
@@ -586,8 +588,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public <T extends GameEntity> T chooseSingleEntityForEffect(final FCollectionView<T> optionList,
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final boolean isOptional,
final Player targetedPlayer, Map<String, Object> params) {
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final boolean isOptional,
final Player targetedPlayer, Map<String, Object> params) {
// Human is supposed to read the message and understand from it what to choose
if (optionList.isEmpty()) {
if (delayedReveal != null) {
@@ -632,7 +634,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
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, Map<String, Object> params) {
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer, Map<String, Object> params) {
// useful details for debugging problems with the mass select logic
Sentry.setExtra("Card", sa.getCardView().toString());
Sentry.setExtra("SpellAbility", sa.toString());
@@ -688,13 +690,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public int chooseNumber(final SpellAbility sa, final String title, final List<Integer> choices,
final Player relatedPlayer) {
final Player relatedPlayer) {
return getGui().one(title, choices).intValue();
}
@Override
public SpellAbility chooseSingleSpellForEffect(final List<SpellAbility> spells, final SpellAbility sa,
final String title, Map<String, Object> params) {
final String title, Map<String, Object> params) {
if (spells.size() < 2) {
return Iterables.getFirst(spells, null);
}
@@ -719,7 +721,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
//override generic
List<SpellAbilityView> chosen = getGui().getChoices(title, num, num, Lists.newArrayList(spellViewCache.keySet()));
for(SpellAbilityView view : chosen) {
for (SpellAbilityView view : chosen) {
if (spellViewCache.containsKey(view)) {
result.add(spellViewCache.get(view));
}
@@ -744,13 +746,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
case "FirstRemembered":
o = sa.getHostCard().getFirstRemembered();
if (o instanceof Card) {
show = (Card)o;
show = (Card) o;
}
break;
case "LastRemembered":
o = sa.getHostCard().getFirstRemembered();
if (o instanceof Card) {
show = (Card)o;
show = (Card) o;
}
break;
}
@@ -766,13 +768,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean confirmBidAction(final SpellAbility sa, final PlayerActionConfirmMode bidlife, final String string,
final int bid, final Player winner) {
final int bid, final Player winner) {
return InputConfirm.confirm(this, sa, string + " " + localizer.getMessage("lblHighestBidder") + " " + winner);
}
@Override
public boolean confirmStaticApplication(final Card hostCard, final GameEntity affected, final String logic,
final String message) {
final String message) {
return InputConfirm.confirm(this, CardView.get(hostCard), message);
}
@@ -919,7 +921,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
final String fm = MessageUtil.formatMessage(message, getLocalPlayerView(), owner);
if (!cards.isEmpty()) {
tempShowCards(cards);
getGui().reveal(fm, CardView.getCollection(cards));
TrackableCollection<CardView> collection = CardView.getCollection(cards);
getGui().reveal(fm, collection);
getGui().updateRevealedCards(collection);
endTempShowCards();
} else {
getGui().message(MessageUtil.formatMessage(localizer.getMessage("lblThereNoCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase()),
@@ -935,14 +939,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
}
public ImmutablePair<CardCollection, CardCollection> arrangeForMove(final String title, final FCollectionView<Card> cards, final List<Card> manipulable, final boolean topOK, final boolean bottomOK) {
List<Card> result = manipulateCardList(title, cards, manipulable, topOK, bottomOK, false);
List<Card> result = manipulateCardList(title, cards, manipulable, topOK, bottomOK, false);
CardCollection toBottom = new CardCollection();
CardCollection toTop = new CardCollection();
for (int i = 0; i<cards.size() && manipulable.contains(result.get(i)) ; i++ ) {
for (int i = 0; i < cards.size() && manipulable.contains(result.get(i)); i++) {
toTop.add(result.get(i));
}
if (toTop.size() < cards.size()) { // the top isn't everything
for (int i = result.size()-1; i>=0 && manipulable.contains(result.get(i)); i-- ) {
for (int i = result.size() - 1; i >= 0 && manipulable.contains(result.get(i)); i--) {
toBottom.add(result.get(i));
}
}
@@ -956,10 +960,10 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
tempShowCards(topN);
if (FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) &&
(!GuiBase.getInterface().isLibgdxPort()) && (!GuiBase.isNetworkplay())) { //prevent crash for desktop vs mobile port it will crash the netplay since mobile doesnt have manipulatecardlist, send the alternate below
(!GuiBase.getInterface().isLibgdxPort()) && (!GuiBase.isNetworkplay())) { //prevent crash for desktop vs mobile port it will crash the netplay since mobile doesnt have manipulatecardlist, send the alternate below
CardCollectionView cardList = player.getCardsIn(ZoneType.Library);
ImmutablePair<CardCollection, CardCollection> result =
arrangeForMove(localizer.getMessage("lblMoveCardstoToporBbottomofLibrary"), cardList, topN, true, true);
arrangeForMove(localizer.getMessage("lblMoveCardstoToporBbottomofLibrary"), cardList, topN, true, true);
toTop = result.getLeft();
toBottom = result.getRight();
} else {
@@ -974,7 +978,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
toBottom = new CardCollection();
List<CardView> views = getGui().many(localizer.getMessage("lblSelectCardsToBeOutOnTheBottomOfYourLibrary"),
localizer.getMessage("lblCardsToPutOnTheBottom"), -1, cardCacheScry.getTrackableKeys(), null);
localizer.getMessage("lblCardsToPutOnTheBottom"), -1, cardCacheScry.getTrackableKeys(), null);
cardCacheScry.addToList(views, toBottom);
topN.removeAll(toBottom);
@@ -986,7 +990,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
GameEntityViewMap<Card, CardView> cardCacheOrder = GameEntityView.getMap(topN);
toTop = new CardCollection();
views = getGui().order(localizer.getMessage("lblArrangeCardsToBePutOnTopOfYourLibrary"),
localizer.getMessage("lblTopOfLibrary"), cardCacheOrder.getTrackableKeys(), null);
localizer.getMessage("lblTopOfLibrary"), cardCacheOrder.getTrackableKeys(), null);
cardCacheOrder.addToList(views, toTop);
}
}
@@ -1088,34 +1092,34 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
List<CardView> choices = gameCacheMove.getTrackableKeys();
switch (destinationZone) {
case Library:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoLibrary"), localizer.getMessage(bottomOfLibrary ? "lblClosestToBottom" : "lblClosestToTop"), choices, null);
break;
case Battlefield:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutOntoBattlefield"), localizer.getMessage("lblPutFirst"), choices, null);
break;
case Graveyard:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoGraveyard"), localizer.getMessage("lblClosestToBottom"), choices, null);
break;
case Exile:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoExile"), localizer.getMessage("lblPutFirst"), choices, null);
break;
case PlanarDeck:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoPlanarDeck"), localizer.getMessage("lblClosestToTop"), choices, null);
break;
case SchemeDeck:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoSchemeDeck"), localizer.getMessage("lblClosestToTop"), choices, null);
break;
case Stack:
choices = getGui().order(localizer.getMessage("lblChooseOrderCopiesCast"), localizer.getMessage("lblPutFirst"), choices, null);
break;
case None: //for when we want to order but don't really want to move the cards
choices = getGui().order(localizer.getMessage("lblChooseOrderCards"), localizer.getMessage("lblPutFirst"), choices, null);
break;
default:
System.out.println("ZoneType " + destinationZone + " - Not Ordered");
endTempShowCards();
return cards;
case Library:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoLibrary"), localizer.getMessage(bottomOfLibrary ? "lblClosestToBottom" : "lblClosestToTop"), choices, null);
break;
case Battlefield:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutOntoBattlefield"), localizer.getMessage("lblPutFirst"), choices, null);
break;
case Graveyard:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoGraveyard"), localizer.getMessage("lblClosestToBottom"), choices, null);
break;
case Exile:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoExile"), localizer.getMessage("lblPutFirst"), choices, null);
break;
case PlanarDeck:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoPlanarDeck"), localizer.getMessage("lblClosestToTop"), choices, null);
break;
case SchemeDeck:
choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoSchemeDeck"), localizer.getMessage("lblClosestToTop"), choices, null);
break;
case Stack:
choices = getGui().order(localizer.getMessage("lblChooseOrderCopiesCast"), localizer.getMessage("lblPutFirst"), choices, null);
break;
case None: //for when we want to order but don't really want to move the cards
choices = getGui().order(localizer.getMessage("lblChooseOrderCards"), localizer.getMessage("lblPutFirst"), choices, null);
break;
default:
System.out.println("ZoneType " + destinationZone + " - Not Ordered");
endTempShowCards();
return cards;
}
endTempShowCards();
CardCollection result = new CardCollection();
@@ -1125,7 +1129,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public CardCollectionView chooseCardsToDiscardFrom(final Player p, final SpellAbility sa,
final CardCollection valid, final int min, final int max) {
final CardCollection valid, final int min, final int max) {
boolean optional = min == 0;
if (p != player) {
@@ -1184,8 +1188,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public CardCollectionView chooseCardsToDiscardUnlessType(final int num, final CardCollectionView hand,
final String uType, final SpellAbility sa) {
String [] splitUTypes = uType.split(",");
final String uType, final SpellAbility sa) {
String[] splitUTypes = uType.split(",");
final InputSelectEntitiesFromList<Card> target = new InputSelectEntitiesFromList<Card>(this, num, num, hand,
sa) {
private static final long serialVersionUID = -5774108410928795591L;
@@ -1206,10 +1210,10 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return super.hasAllTargets();
}
};
int n=1;
int n = 1;
StringBuilder promptType = new StringBuilder();
for (String part : splitUTypes) {
if (n==1) {
if (n == 1) {
promptType.append(part.toLowerCase());
} else {
promptType.append(" or ").append(part.toLowerCase());
@@ -1247,7 +1251,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public String chooseSomeType(final String kindOfType, final SpellAbility sa, final Collection<String> validTypes,
final List<String> invalidTypes, final boolean isOptional) {
final List<String> invalidTypes, final boolean isOptional) {
final List<String> types = Lists.newArrayList(validTypes);
if (invalidTypes != null && !invalidTypes.isEmpty()) {
Iterables.removeAll(types, invalidTypes);
@@ -1378,7 +1382,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Object vote(final SpellAbility sa, final String prompt, final List<Object> options,
final ListMultimap<Object, Player> votes, Player forPlayer) {
final ListMultimap<Object, Player> votes, Player forPlayer) {
return getGui().one(prompt, options);
}
@@ -1392,7 +1396,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public boolean confirmReplacementEffect(final ReplacementEffect replacementEffect, final SpellAbility effectSA,
GameEntity affected, final String question) {
GameEntity affected, final String question) {
if (GuiBase.getInterface().isLibgdxPort()) {
return this.getGui().confirm(effectSA.getView().getHostCard(), question.replaceAll("\n", " "));
} else {
@@ -1430,7 +1434,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (mayAutoPass()) {
if (CombatUtil.validateAttackers(combat)) {
return; // don't prompt to declare attackers if user chose to
// end the turn and not attacking is legal
// end the turn and not attacking is legal
}
// otherwise: cancel auto pass because of this unexpected attack
autoPassCancel();
@@ -1482,7 +1486,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (getGui().isUiSetToSkipPhase(getGame().getPhaseHandler().getPlayerTurn().getView(),
getGame().getPhaseHandler().getPhase())) {
return null; // avoid prompt for input if stack is empty and
// player is set to skip the current phase
// player is set to skip the current phase
}
} else {
final SpellAbility ability = stack.peekAbility();
@@ -1522,13 +1526,12 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return choices;
}
@SuppressWarnings("serial")
final InputSelectCardsFromList inp = new InputSelectCardsFromList(this, nDiscard, nDiscard,
@SuppressWarnings("serial") final InputSelectCardsFromList inp = new InputSelectCardsFromList(this, nDiscard, nDiscard,
player.getZone(ZoneType.Hand).getCards()) {
@Override
protected final boolean allowAwaitNextInput() {
return true; // prevent Cleanup message getting stuck during
// opponent's next turn
// opponent's next turn
}
};
final String message = localizer.getMessage("lblCleanupPhase") + "\n"
@@ -1551,7 +1554,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean payManaOptional(final Card c, final Cost cost, final SpellAbility sa, final String prompt,
final ManaPaymentPurpose purpose) {
final ManaPaymentPurpose purpose) {
if (sa == null && cost.isOnlyManaCost() && cost.getTotalMana().isZero()
&& !FModel.getPreferences().getPrefBoolean(FPref.MATCHPREF_PROMPT_FREE_BLOCKS)) {
return true;
@@ -1590,36 +1593,36 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean chooseBinary(final SpellAbility sa, final String question, final BinaryChoiceType kindOfChoice,
final Boolean defaultVal) {
final Boolean defaultVal) {
final List<String> labels;
switch (kindOfChoice) {
case HeadsOrTails:
labels = ImmutableList.of(localizer.getMessage("lblHeads"), localizer.getMessage("lblTails"));
break;
case TapOrUntap:
labels = ImmutableList.of(StringUtils.capitalize(localizer.getMessage("lblTap")),
localizer.getMessage("lblUntap"));
break;
case OddsOrEvens:
labels = ImmutableList.of(localizer.getMessage("lblOdds"), localizer.getMessage("lblEvens"));
break;
case UntapOrLeaveTapped:
labels = ImmutableList.of(localizer.getMessage("lblUntap"), localizer.getMessage("lblLeaveTapped"));
break;
case UntapTimeVault:
labels = ImmutableList.of(localizer.getMessage("lblUntapAndSkipThisTurn"), localizer.getMessage("lblLeaveTapped"));
break;
case PlayOrDraw:
labels = ImmutableList.of(localizer.getMessage("lblPlay"), localizer.getMessage("lblDraw"));
break;
case LeftOrRight:
labels = ImmutableList.of(localizer.getMessage("lblLeft"), localizer.getMessage("lblRight"));
break;
case AddOrRemove:
labels = ImmutableList.of(localizer.getMessage("lblAddCounter"), localizer.getMessage("lblRemoveCounter"));
break;
default:
labels = ImmutableList.copyOf(kindOfChoice.toString().split("Or"));
case HeadsOrTails:
labels = ImmutableList.of(localizer.getMessage("lblHeads"), localizer.getMessage("lblTails"));
break;
case TapOrUntap:
labels = ImmutableList.of(StringUtils.capitalize(localizer.getMessage("lblTap")),
localizer.getMessage("lblUntap"));
break;
case OddsOrEvens:
labels = ImmutableList.of(localizer.getMessage("lblOdds"), localizer.getMessage("lblEvens"));
break;
case UntapOrLeaveTapped:
labels = ImmutableList.of(localizer.getMessage("lblUntap"), localizer.getMessage("lblLeaveTapped"));
break;
case UntapTimeVault:
labels = ImmutableList.of(localizer.getMessage("lblUntapAndSkipThisTurn"), localizer.getMessage("lblLeaveTapped"));
break;
case PlayOrDraw:
labels = ImmutableList.of(localizer.getMessage("lblPlay"), localizer.getMessage("lblDraw"));
break;
case LeftOrRight:
labels = ImmutableList.of(localizer.getMessage("lblLeft"), localizer.getMessage("lblRight"));
break;
case AddOrRemove:
labels = ImmutableList.of(localizer.getMessage("lblAddCounter"), localizer.getMessage("lblRemoveCounter"));
break;
default:
labels = ImmutableList.copyOf(kindOfChoice.toString().split("Or"));
}
return InputConfirm.confirm(this, sa, question, defaultVal == null || defaultVal.booleanValue(), labels);
@@ -1627,9 +1630,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean chooseFlipResult(final SpellAbility sa, final Player flipper, final boolean[] results,
final boolean call) {
final String[] labelsSrc = call ? new String[] { localizer.getMessage("lblHeads"), localizer.getMessage("lblTails") }
: new String[] { localizer.getMessage("lblWinTheFlip"), localizer.getMessage("lblLoseTheFlip") };
final boolean call) {
final String[] labelsSrc = call ? new String[]{localizer.getMessage("lblHeads"), localizer.getMessage("lblTails")}
: new String[]{localizer.getMessage("lblWinTheFlip"), localizer.getMessage("lblLoseTheFlip")};
final List<String> sortedResults = new ArrayList<String>();
for (boolean result : results) {
sortedResults.add(labelsSrc[result ? 0 : 1]);
@@ -1644,14 +1647,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Card chooseProtectionShield(final GameEntity entityBeingDamaged, final List<String> options,
final Map<String, Card> choiceMap) {
final Map<String, Card> choiceMap) {
final String title = entityBeingDamaged + " - " + localizer.getMessage("lblSelectPreventionShieldToUse");
return choiceMap.get(getGui().one(title, options));
}
@Override
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(final SpellAbility saSpellskite,
final List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
final List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
if (allTargets.size() < 2) {
return Iterables.getFirst(allTargets, null);
}
@@ -1692,7 +1695,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public List<AbilitySub> chooseModeForAbility(final SpellAbility sa, List<AbilitySub> possible, final int min, final int num,
boolean allowRepeat) {
boolean allowRepeat) {
boolean trackerFrozen = getGame().getTracker().isFrozen();
if (trackerFrozen) {
// The view tracker needs to be unfrozen to update the SpellAbilityViews at this point, or it may crash
@@ -1726,7 +1729,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public List<String> chooseColors(final String message, final SpellAbility sa, final int min, final int max,
List<String> options) {
List<String> options) {
options = options.stream().map(DeckRecognizer::getLocalisedMagicColorName).collect(Collectors.toList());
List<String> choices = getGui().getChoices(message, min, max, options);
return choices.stream().map(DeckRecognizer::getColorNameByLocalisedName).collect(Collectors.toList());
@@ -1736,12 +1739,12 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
public byte chooseColor(final String message, final SpellAbility sa, final ColorSet colors) {
final int cntColors = colors.countColors();
switch (cntColors) {
case 0:
return 0;
case 1:
return colors.getColor();
default:
return chooseColorCommon(message, sa == null ? null : sa.getHostCard(), colors, false);
case 0:
return 0;
case 1:
return colors.getColor();
default:
return chooseColorCommon(message, sa == null ? null : sa.getHostCard(), colors, false);
}
}
@@ -1749,15 +1752,15 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
public byte chooseColorAllowColorless(final String message, final Card c, final ColorSet colors) {
final int cntColors = 1 + colors.countColors();
switch (cntColors) {
case 1:
return 0;
default:
return chooseColorCommon(message, c, colors, true);
case 1:
return 0;
default:
return chooseColorCommon(message, c, colors, true);
}
}
private byte chooseColorCommon(final String message, final Card c, final ColorSet colors,
final boolean withColorless) {
final boolean withColorless) {
final ImmutableList.Builder<String> colorNamesBuilder = ImmutableList.builder();
if (withColorless) {
colorNamesBuilder.add(MagicColor.toLongString(MagicColor.COLORLESS));
@@ -1778,7 +1781,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public ICardFace chooseSingleCardFace(final SpellAbility sa, final String message, final Predicate<ICardFace> cpp,
final String name) {
final String name) {
final Iterable<ICardFace> cardsFromDb = FModel.getMagicDb().getCommonCards().getAllFaces();
final List<ICardFace> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
CardFaceView cardFaceView;
@@ -1794,7 +1797,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public CounterType chooseCounterType(final List<CounterType> options, final SpellAbility sa, final String prompt,
Map<String, Object> params) {
Map<String, Object> params) {
if (options.size() <= 1) {
return Iterables.getFirst(options, null);
}
@@ -1830,7 +1833,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public ReplacementEffect chooseSingleReplacementEffect(final String prompt,
final List<ReplacementEffect> possibleReplacers) {
final List<ReplacementEffect> possibleReplacers) {
final ReplacementEffect first = possibleReplacers.get(0);
if (possibleReplacers.size() == 1) {
return first;
@@ -1853,7 +1856,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean payCostToPreventEffect(final Cost cost, final SpellAbility sa, final boolean alreadyPaid,
final FCollectionView<Player> allPayers) {
final FCollectionView<Player> allPayers) {
// if it's paid by the AI already the human can pay, but it won't change anything
return HumanPlay.payCostDuringAbilityResolve(this, player, sa.getHostCard(), cost, sa, null);
}
@@ -1883,7 +1886,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
}
if (!needPrompt && !saStr.equals(firstStr) && !currentSa.hasParam("OrderDuplicates")) {
needPrompt = true; // prompt by default unless all abilities
// are the same
// are the same
}
saLookupKey.append(delim).append(saStr);
@@ -2065,7 +2068,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean chooseCardsPile(final SpellAbility sa, final CardCollectionView pile1,
final CardCollectionView pile2, final String faceUp) {
final CardCollectionView pile2, final String faceUp) {
final String p1Str = TextUtil.concatNoSpace("-- Pile 1 (", String.valueOf(pile1.size()), " cards) --");
final String p2Str = TextUtil.concatNoSpace("-- Pile 2 (", String.valueOf(pile2.size()), " cards) --");
@@ -2125,23 +2128,23 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
for (Player p : unplayable.keySet()) {
final Map<DeckSection, List<? extends PaperCard>> removedUnplayableCards = unplayable.get(p);
final List<PaperCard> labels = new ArrayList<>();
for (final DeckSection s: new TreeSet<>(removedUnplayableCards.keySet())) {
for (final DeckSection s : new TreeSet<>(removedUnplayableCards.keySet())) {
if (DeckSection.Sideboard.equals(s))
continue;
for (PaperCard c: removedUnplayableCards.get(s)) {
for (PaperCard c : removedUnplayableCards.get(s)) {
labels.add(c);
}
}
if (!labels.isEmpty())
getGui().reveal(localizer.getMessage("lblActionFromPlayerDeck", message, Lang.getInstance().getPossessedObject(MessageUtil.mayBeYou(player, p), "")),
ImmutableList.copyOf(labels));
ImmutableList.copyOf(labels));
}
return;
}
for (Player p : unplayable.keySet()) {
final Map<DeckSection, List<? extends PaperCard>> removedUnplayableCards = unplayable.get(p);
final List<Object> labels = new ArrayList<>();
for (final DeckSection s: new TreeSet<>(removedUnplayableCards.keySet())) {
for (final DeckSection s : new TreeSet<>(removedUnplayableCards.keySet())) {
labels.add("=== " + DeckAIUtils.getLocalizedDeckSection(localizer, s) + " ===");
labels.addAll(removedUnplayableCards.get(s));
}
@@ -2163,7 +2166,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(final SpellAbility sa, final ManaCost manaCost,
final CardCollectionView untappedCards, boolean improvise) {
final CardCollectionView untappedCards, boolean improvise) {
final InputSelectCardsForConvokeOrImprovise inp = new InputSelectCardsForConvokeOrImprovise(this, player,
manaCost, untappedCards, improvise, sa);
inp.showAndWait();
@@ -2172,7 +2175,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public String chooseCardName(final SpellAbility sa, final Predicate<ICardFace> cpp, final String valid,
final String message) {
final String message) {
while (true) {
final ICardFace cardFace = chooseSingleCardFace(sa, message, cpp, sa.getHostCard().getName());
final PaperCard cp = FModel.getMagicDb().getCommonCards().getCard(cardFace.getName());
@@ -2188,14 +2191,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Card chooseSingleCardForZoneChange(final ZoneType destination, final List<ZoneType> origin,
final SpellAbility sa, final CardCollection fetchList, final DelayedReveal delayedReveal,
final String selectPrompt, final boolean isOptional, final Player decider) {
final SpellAbility sa, final CardCollection fetchList, final DelayedReveal delayedReveal,
final String selectPrompt, final boolean isOptional, final Player decider) {
return chooseSingleEntityForEffect(fetchList, delayedReveal, sa, selectPrompt, isOptional, decider, null);
}
public List<Card> chooseCardsForZoneChange(final ZoneType destination, final List<ZoneType> origin,
final SpellAbility sa, final CardCollection fetchList, final int min, final int max, final DelayedReveal delayedReveal,
final String selectPrompt, final Player decider) {
final SpellAbility sa, final CardCollection fetchList, final int min, final int max, final DelayedReveal delayedReveal,
final String selectPrompt, final Player decider) {
return chooseEntitiesForEffect(fetchList, min, max, delayedReveal, sa, selectPrompt, decider, null);
}
@@ -2292,7 +2295,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect,
final ITriggerEvent triggerEvent) {
final ITriggerEvent triggerEvent) {
return inputProxy.selectCard(cardView, otherCardViewsToSelect, triggerEvent);
}
@@ -2539,7 +2542,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
final Card card = gameCacheCounters.get(cv);
final ImmutableList<CounterType> counters = subtract ? ImmutableList.copyOf(card.getCounters().keySet())
: ImmutableList.copyOf(Collections2.transform(CounterEnumType.values, input -> CounterType.get(input)));
: ImmutableList.copyOf(Collections2.transform(CounterEnumType.values, input -> CounterType.get(input)));
final CounterType counter = getGui().oneOrNone(localizer.getMessage("lblWhichTypeofCounter"), counters);
if (counter == null) {
@@ -2706,8 +2709,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
/*
* (non-Javadoc)
*
* @see forge.player.IDevModeCheats#addCardToExile()
*/
* @see forge.player.IDevModeCheats#addCardToExile()
*/
@Override
public void castASpell() {
addCardToZone(ZoneType.Battlefield, false, false);
@@ -2847,7 +2850,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
} else if (targetZone == ZoneType.Library) {
if (!repeatLast) {
lastTopOfTheLibrary = getGui().confirm(forgeCard.getView(), localizer.getMessage("lblCardShouldBeAddedToLibraryTopOrBottom", CardTranslation.getTranslatedName(forgeCard.getName())),
true, Arrays.asList(localizer.getMessage("lblTop"), localizer.getMessage("lblBottom")));
true, Arrays.asList(localizer.getMessage("lblTop"), localizer.getMessage("lblBottom")));
}
if (lastTopOfTheLibrary) {
getGame().getAction().moveToLibrary(forgeCard, null);
@@ -3148,8 +3151,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
}
// Fetch cards and players specified by the user input
final ZoneType[] zones = { ZoneType.Battlefield, ZoneType.Hand, ZoneType.Graveyard, ZoneType.Exile,
ZoneType.Command };
final ZoneType[] zones = {ZoneType.Battlefield, ZoneType.Hand, ZoneType.Graveyard, ZoneType.Exile,
ZoneType.Command};
final CardCollectionView cards = getGame().getCardsIn(Arrays.asList(zones));
for (final Pair<Integer, Boolean> entity : entityInfo) {
boolean found = false;
@@ -3306,14 +3309,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public List<OptionalCostValue> chooseOptionalCosts(SpellAbility choosen,
List<OptionalCostValue> optionalCost) {
List<OptionalCostValue> optionalCost) {
return getGui().many(localizer.getMessage("lblChooseOptionalCosts"), localizer.getMessage("lblOptionalCosts"), 0, optionalCost.size(),
optionalCost, choosen.getHostCard().getView());
}
@Override
public boolean confirmMulliganScry(Player p) {
return InputConfirm.confirm(this, (SpellAbility)null, localizer.getMessage("lblDoYouWanttoScry"));
return InputConfirm.confirm(this, (SpellAbility) null, localizer.getMessage("lblDoYouWanttoScry"));
}
@Override
@@ -3344,7 +3347,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
public CardCollection getCardList(Iterable<CardView> cardViews) {
CardCollection result = new CardCollection();
for(CardView cardView : cardViews){
for (CardView cardView : cardViews) {
final Card c = this.getCard(cardView);
if (c != null) {
result.add(c);