* GUI: added popup menu to view player's outside/sideboard at any time (allows to view only own or computer's sideboards);

This commit is contained in:
Oleg Agafonov 2021-07-21 13:44:35 +04:00
parent eda50cc7b1
commit 28473c7bd0
12 changed files with 265 additions and 165 deletions

View file

@ -34,7 +34,7 @@ public class CardInfoWindowDialog extends MageDialog {
private static final Logger LOGGER = Logger.getLogger(CardInfoWindowDialog.class);
public enum ShowType {
REVEAL, REVEAL_TOP_LIBRARY, LOOKED_AT, EXILE, GRAVEYARD, COMPANION, OTHER
REVEAL, REVEAL_TOP_LIBRARY, LOOKED_AT, EXILE, GRAVEYARD, COMPANION, SIDEBOARD, OTHER
}
private final ShowType showType;
@ -89,6 +89,17 @@ public class CardInfoWindowDialog extends MageDialog {
}
});
break;
case SIDEBOARD:
this.setFrameIcon(new ImageIcon(ImageHelper.getImageFromResources("/info/library.png")));
this.setClosable(true);
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
this.addInternalFrameListener(new InternalFrameAdapter() {
@Override
public void internalFrameClosing(InternalFrameEvent e) {
CardInfoWindowDialog.this.hideDialog();
}
});
break;
case EXILE:
this.setFrameIcon(new ImageIcon(ImageManagerImpl.instance.getExileImage()));
break;
@ -96,6 +107,7 @@ public class CardInfoWindowDialog extends MageDialog {
this.setFrameIcon(new ImageIcon(ImageManagerImpl.instance.getTokenIconImage()));
this.setClosable(false);
break;
case OTHER:
default:
// no icon yet
}
@ -149,12 +161,22 @@ public class CardInfoWindowDialog extends MageDialog {
public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId, boolean revertOrder) {
cards.loadCards(showCards, bigCard, gameId, revertOrder);
// additional info for grave windows
if (showType == ShowType.GRAVEYARD) {
int qty = qtyCardTypes(showCards);
String titel = name + "'s Graveyard (" + showCards.size() + ") - " + qty + ((qty == 1) ? " Card Type" : " Card Types");
setTitle(titel);
this.setTitelBarToolTip(titel);
String newTitle = name + "'s graveyard (" + showCards.size() + ") - " + qty + ((qty == 1) ? " card type" : " card types");
setTitle(newTitle);
this.setTitelBarToolTip(newTitle);
}
// additional info for sideboard window
if (showType == ShowType.SIDEBOARD) {
String newTitle = name + "'s sideboard";
setTitle(newTitle);
this.setTitelBarToolTip(newTitle);
}
showAndPositionWindow();
}

View file

@ -77,9 +77,11 @@ public final class GamePanel extends javax.swing.JPanel {
private final Map<UUID, CardInfoWindowDialog> exiles = new HashMap<>();
private final Map<String, CardInfoWindowDialog> revealed = new HashMap<>();
private final Map<String, CardInfoWindowDialog> lookedAt = new HashMap<>();
private final Map<String, CardsView> graveyards = new HashMap<>(); // need to sync selection
private final Map<String, CardInfoWindowDialog> graveyardWindows = new HashMap<>();
private final Map<String, CardInfoWindowDialog> companion = new HashMap<>();
private final Map<String, CardsView> graveyards = new HashMap<>();
private final Map<String, CardsView> sideboards = new HashMap<>(); // need to sync selection
private final Map<String, CardInfoWindowDialog> sideboardWindows = new HashMap<>();
private final ArrayList<ShowCardsDialog> pickTarget = new ArrayList<>();
private final ArrayList<PickPileDialog> pickPile = new ArrayList<>();
private UUID gameId;
@ -246,25 +248,29 @@ public final class GamePanel extends javax.swing.JPanel {
if (pickMultiNumber != null) {
pickMultiNumber.removeDialog();
}
for (CardInfoWindowDialog exileDialog : exiles.values()) {
exileDialog.cleanUp();
exileDialog.removeDialog();
for (CardInfoWindowDialog windowDialog : exiles.values()) {
windowDialog.cleanUp();
windowDialog.removeDialog();
}
for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) {
graveyardDialog.cleanUp();
graveyardDialog.removeDialog();
for (CardInfoWindowDialog windowDialog : graveyardWindows.values()) {
windowDialog.cleanUp();
windowDialog.removeDialog();
}
for (CardInfoWindowDialog revealDialog : revealed.values()) {
revealDialog.cleanUp();
revealDialog.removeDialog();
for (CardInfoWindowDialog windowDialog : sideboardWindows.values()) {
windowDialog.cleanUp();
windowDialog.removeDialog();
}
for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) {
lookedAtDialog.cleanUp();
lookedAtDialog.removeDialog();
for (CardInfoWindowDialog windowDialog : revealed.values()) {
windowDialog.cleanUp();
windowDialog.removeDialog();
}
for (CardInfoWindowDialog companionDialog : companion.values()) {
companionDialog.cleanUp();
companionDialog.removeDialog();
for (CardInfoWindowDialog windowDialog : lookedAt.values()) {
windowDialog.cleanUp();
windowDialog.removeDialog();
}
for (CardInfoWindowDialog windowDialog : companion.values()) {
windowDialog.cleanUp();
windowDialog.removeDialog();
}
clearPickTargetDialogs();
@ -308,26 +314,29 @@ public final class GamePanel extends javax.swing.JPanel {
playAreaPanel.changeGUISize();
}
for (CardInfoWindowDialog cardInfoWindowDialog : exiles.values()) {
cardInfoWindowDialog.changeGUISize();
for (CardInfoWindowDialog windowDialog : exiles.values()) {
windowDialog.changeGUISize();
}
for (CardInfoWindowDialog cardInfoWindowDialog : revealed.values()) {
cardInfoWindowDialog.changeGUISize();
for (CardInfoWindowDialog windowDialog : revealed.values()) {
windowDialog.changeGUISize();
}
for (CardInfoWindowDialog cardInfoWindowDialog : lookedAt.values()) {
cardInfoWindowDialog.changeGUISize();
for (CardInfoWindowDialog windowDialog : lookedAt.values()) {
windowDialog.changeGUISize();
}
for (CardInfoWindowDialog cardInfoWindowDialog : companion.values()) {
cardInfoWindowDialog.changeGUISize();
for (CardInfoWindowDialog windowDialog : companion.values()) {
windowDialog.changeGUISize();
}
for (CardInfoWindowDialog cardInfoWindowDialog : graveyardWindows.values()) {
cardInfoWindowDialog.changeGUISize();
for (CardInfoWindowDialog windowDialog : graveyardWindows.values()) {
windowDialog.changeGUISize();
}
for (ShowCardsDialog showCardsDialog : pickTarget) {
showCardsDialog.changeGUISize();
for (CardInfoWindowDialog windowDialog : sideboardWindows.values()) {
windowDialog.changeGUISize();
}
for (PickPileDialog pickPileDialog : pickPile) {
pickPileDialog.changeGUISize();
for (ShowCardsDialog windowDialog : pickTarget) {
windowDialog.changeGUISize();
}
for (PickPileDialog windowDialog : pickPile) {
windowDialog.changeGUISize();
}
this.revalidate();
@ -575,7 +584,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
PlayerView player = game.getPlayers().get(playerSeat);
PlayAreaPanel playAreaPanel = new PlayAreaPanel(player, bigCard, gameId, game.getPriorityTime(), this,
new PlayAreaPanelOptions(game.isPlayer(), game.isPlayer(), game.isRollbackTurnsAllowed(), row == 0));
new PlayAreaPanelOptions(game.isPlayer(), player.isHuman(), game.isPlayer(), game.isRollbackTurnsAllowed(), row == 0));
players.put(player.getPlayerId(), playAreaPanel);
playersWhoLeft.put(player.getPlayerId(), false);
GridBagConstraints c = new GridBagConstraints();
@ -619,7 +628,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
player = game.getPlayers().get(playerNum);
PlayAreaPanel playerPanel = new PlayAreaPanel(player, bigCard, gameId, game.getPriorityTime(), this,
new PlayAreaPanelOptions(game.isPlayer(), false, game.isRollbackTurnsAllowed(), row == 0));
new PlayAreaPanelOptions(game.isPlayer(), player.isHuman(), false, game.isRollbackTurnsAllowed(), row == 0));
players.put(player.getPlayerId(), playerPanel);
playersWhoLeft.put(player.getPlayerId(), false);
c = new GridBagConstraints();
@ -790,16 +799,29 @@ public final class GamePanel extends javax.swing.JPanel {
if (player.getPlayerId().equals(playerId)) {
skipButtons.updateFromPlayer(player);
}
// update open or remove closed graveyard windows
graveyards.put(player.getName(), player.getGraveyard());
if (graveyardWindows.containsKey(player.getName())) {
CardInfoWindowDialog cardInfoWindowDialog = graveyardWindows.get(player.getName());
if (cardInfoWindowDialog.isClosed()) {
CardInfoWindowDialog windowDialog = graveyardWindows.get(player.getName());
if (windowDialog.isClosed()) {
graveyardWindows.remove(player.getName());
} else {
cardInfoWindowDialog.loadCards(player.getGraveyard(), bigCard, gameId, false);
windowDialog.loadCards(player.getGraveyard(), bigCard, gameId, false);
}
}
// update open or remove closed sideboard windows
sideboards.put(player.getName(), player.getSideboard());
if (sideboardWindows.containsKey(player.getName())) {
CardInfoWindowDialog windowDialog = sideboardWindows.get(player.getName());
if (windowDialog.isClosed()) {
sideboardWindows.remove(player.getName());
} else {
windowDialog.loadCards(player.getSideboard(), bigCard, gameId, false);
}
}
// show top card window
if (player.getTopCard() != null) {
CardsView cardsView = new CardsView();
@ -852,8 +874,12 @@ public final class GamePanel extends javax.swing.JPanel {
exiles.get(exile.getId()).loadCards(exile, bigCard, gameId);
}
// reveal and look at dialogs can unattached, so windows opened by game doesn't have it
showRevealed(lastGameData.game);
showLookedAt(lastGameData.game);
// sideboard dialogs is unattached all the time -- user opens it by command
showCompanion(lastGameData.game);
if (!lastGameData.game.getCombat().isEmpty()) {
CombatManager.instance.showCombat(lastGameData.game.getCombat(), gameId);
@ -1147,40 +1173,46 @@ public final class GamePanel extends javax.swing.JPanel {
// Called if the game frame is deactivated because the tabled the deck editor or other frames go to foreground
public void deactivated() {
// hide the non modal windows (because otherwise they are shown on top of the new active pane)
for (CardInfoWindowDialog exileDialog : exiles.values()) {
exileDialog.hideDialog();
for (CardInfoWindowDialog windowDialog : exiles.values()) {
windowDialog.hideDialog();
}
for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) {
graveyardDialog.hideDialog();
for (CardInfoWindowDialog windowDialog : graveyardWindows.values()) {
windowDialog.hideDialog();
}
for (CardInfoWindowDialog revealDialog : revealed.values()) {
revealDialog.hideDialog();
for (CardInfoWindowDialog windowDialog : revealed.values()) {
windowDialog.hideDialog();
}
for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) {
lookedAtDialog.hideDialog();
for (CardInfoWindowDialog windowDialog : lookedAt.values()) {
windowDialog.hideDialog();
}
for (CardInfoWindowDialog companionDialog : companion.values()) {
companionDialog.hideDialog();
for (CardInfoWindowDialog windowDialog : companion.values()) {
windowDialog.hideDialog();
}
for (CardInfoWindowDialog windowDialog : sideboardWindows.values()) {
windowDialog.hideDialog();
}
}
// Called if the game frame comes to front again
public void activated() {
// hide the non modal windows (because otherwise they are shown on top of the new active pane)
for (CardInfoWindowDialog exileDialog : exiles.values()) {
exileDialog.show();
for (CardInfoWindowDialog windowDialog : exiles.values()) {
windowDialog.show();
}
for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) {
graveyardDialog.show();
for (CardInfoWindowDialog windowDialog : graveyardWindows.values()) {
windowDialog.show();
}
for (CardInfoWindowDialog revealDialog : revealed.values()) {
revealDialog.show();
for (CardInfoWindowDialog windowDialog : revealed.values()) {
windowDialog.show();
}
for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) {
lookedAtDialog.show();
for (CardInfoWindowDialog windowDialog : lookedAt.values()) {
windowDialog.show();
}
for (CardInfoWindowDialog companionDialog : companion.values()) {
companionDialog.show();
for (CardInfoWindowDialog windowDialog : companion.values()) {
windowDialog.show();
}
for (CardInfoWindowDialog windowDialog : sideboardWindows.values()) {
windowDialog.show();
}
}
@ -1197,9 +1229,40 @@ public final class GamePanel extends javax.swing.JPanel {
CardInfoWindowDialog newGraveyard = new CardInfoWindowDialog(ShowType.GRAVEYARD, playerName);
graveyardWindows.put(playerName, newGraveyard);
MageFrame.getDesktop().add(newGraveyard, JLayeredPane.PALETTE_LAYER);
// use graveyards to sync selection (don't use player data here)
newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId, false);
}
public void openSideboardWindow(UUID playerId) {
if (lastGameData == null) {
return;
}
PlayerView playerView = lastGameData.game.getPlayers().stream()
.filter(p -> p.getPlayerId().equals(playerId))
.findFirst()
.orElse(null);
if (playerView == null) {
return;
}
if (sideboardWindows.containsKey(playerView.getName())) {
CardInfoWindowDialog windowDialog = sideboardWindows.get(playerView.getName());
if (windowDialog.isVisible()) {
windowDialog.hideDialog();
} else {
windowDialog.show();
}
return;
}
CardInfoWindowDialog windowDialog = new CardInfoWindowDialog(ShowType.SIDEBOARD, playerView.getName());
sideboardWindows.put(playerView.getName(), windowDialog);
MageFrame.getDesktop().add(windowDialog, JLayeredPane.PALETTE_LAYER);
// use sideboards to sync selection (don't use player data here)
windowDialog.loadCards(sideboards.get(playerView.getName()), bigCard, gameId, false);
}
public void openTopLibraryWindow(String playerName) {
String title = playerName + "'s top library card";
if (revealed.containsKey(title)) {
@ -1387,6 +1450,25 @@ public final class GamePanel extends javax.swing.JPanel {
}
}
// sideboard
if (needZone == Zone.OUTSIDE || needZone == Zone.ALL) {
for (PlayerView player : lastGameData.game.getPlayers()) {
for (Map.Entry<UUID, CardView> card : player.getSideboard().entrySet()) {
if (needSelectable.contains(card.getKey())) {
card.getValue().setChoosable(true);
}
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.containsObject(card.getKey())) {
card.getValue().setPlayableStats(needPlayable.getStats(card.getKey()));
}
}
}
}
// sideboards (old windows all the time, e.g. unattached from game data)
prepareSelectableWindows(sideboardWindows.values(), needSelectable, needChoosen, needPlayable);
// exile
if (needZone == Zone.EXILED || needZone == Zone.ALL) {
// exile from player panel
@ -1403,6 +1485,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
}
}
// exile from windows
for (ExileView exile : lastGameData.game.getExile()) {
for (Map.Entry<UUID, CardView> card : exile.entrySet()) {

View file

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="357" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="1" pref="278" max="32767" attributes="0"/>
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
<BevelBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="manaPool" alignment="0" pref="116" max="32767" attributes="1"/>
<Component id="playerPanel" alignment="0" max="32767" attributes="1"/>
<Component id="btnCheat" alignment="0" pref="116" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="playerPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="manaPool" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="17" max="32767" attributes="0"/>
<Component id="btnCheat" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="mage.client.game.PlayerPanel" name="playerPanel">
</Component>
<Component class="mage.client.game.ManaPool" name="manaPool">
</Component>
<Component class="javax.swing.JButton" name="btnCheat">
<Properties>
<Property name="text" type="java.lang.String" value="Cheat"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCheatActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="mage.client.game.BattlefieldPanel" name="battlefieldPanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View file

@ -24,6 +24,8 @@ import java.util.UUID;
import static mage.client.dialog.PreferencesDialog.*;
/**
* GUI: play area panel (player with avatar/mana panel + battlefield panel)
*
* @author BetaSteward_at_googlemail.com
*/
public class PlayAreaPanel extends javax.swing.JPanel {
@ -441,14 +443,28 @@ public class PlayAreaPanel extends javax.swing.JPanel {
popupMenu.addSeparator();
menuItem = new JMenuItem("<html>View current deck");
menuItem.setMnemonic(KeyEvent.VK_V);
// view deck
menuItem = new JMenuItem("<html>View player's deck");
menuItem.setMnemonic(KeyEvent.VK_D);
popupMenu.add(menuItem);
// View limited deck
menuItem.addActionListener(e -> {
SessionHandler.sendPlayerAction(PlayerAction.VIEW_LIMITED_DECK, gameId, null);
});
// view sideboard (allows to view only own sideboard or computer)
// it's a client side checks... same checks must be on server side too (see PlayerView)
if (options.playerItself || !options.isHuman) {
String menuCaption = "<html>View my sideboard";
if (!options.isHuman) {
menuCaption = "<html>View computer's sideboard";
}
menuItem = new JMenuItem(menuCaption);
menuItem.setMnemonic(KeyEvent.VK_S);
popupMenu.add(menuItem);
menuItem.addActionListener(e -> {
SessionHandler.sendPlayerAction(PlayerAction.VIEW_SIDEBOARD, gameId, playerId);
});
}
}
private void addPopupMenuWatcher() {

View file

@ -8,8 +8,9 @@ package mage.client.game;
*/
public class PlayAreaPanelOptions {
public PlayAreaPanelOptions(boolean isPlayer, boolean playerItself, boolean rollbackTurnsAllowed, boolean topRow) {
public PlayAreaPanelOptions(boolean isPlayer, boolean isHuman, boolean playerItself, boolean rollbackTurnsAllowed, boolean topRow) {
this.isPlayer = isPlayer;
this.isHuman = isHuman;
this.playerItself = playerItself;
this.rollbackTurnsAllowed = rollbackTurnsAllowed;
this.topRow = topRow;
@ -18,22 +19,27 @@ public class PlayAreaPanelOptions {
/**
* true if the client is a player / false if the client is a watcher
*/
public boolean isPlayer = false;
public boolean isPlayer;
/**
* true if the player is the human, not computer
*/
public boolean isHuman;
/**
* true if the player is the client player itself, false if the player is
* another player playing with the clinet player
* another player playing with the client player
*/
public boolean playerItself = false;
public boolean playerItself;
/**
* true if the player can rollback turns if all players agree
*/
public boolean rollbackTurnsAllowed = false;
public boolean rollbackTurnsAllowed;
/**
* true if the battlefield is on the top row of player areas
*/
public boolean topRow = false;
public boolean topRow;
}

View file

@ -391,6 +391,12 @@ public class CallbackClientImpl implements CallbackClient {
break;
}
case VIEW_SIDEBOARD: {
TableClientMessage message = (TableClientMessage) callback.getData();
viewSideboard(message.getGameId(), message.getPlayerId());
break;
}
case CONSTRUCT: {
TableClientMessage message = (TableClientMessage) callback.getData();
DeckView deckView = message.getDeck();
@ -616,6 +622,15 @@ public class CallbackClientImpl implements CallbackClient {
frame.showDeckEditor(DeckEditorMode.VIEW_LIMITED_DECK, deck, tableId, time);
}
protected void viewSideboard(UUID gameId, UUID playerId) {
SwingUtilities.invokeLater(() -> {
GamePanel panel = MageFrame.getGame(gameId);
if (panel != null) {
panel.openSideboardWindow(playerId);
}
});
}
private void handleException(Exception ex) {
logger.fatal("Client error\n", ex);
String errorMessage = ex.getMessage();

View file

@ -14,6 +14,7 @@ public enum ClientCallbackMethod {
START_TOURNAMENT("startTournament"),
SIDEBOARD("sideboard"),
VIEW_LIMITED_DECK("viewLimitedDeck"),
VIEW_SIDEBOARD("viewSideboard"),
CONSTRUCT("construct"),
SHOW_USERMESSAGE("showUserMessage"),
WATCHGAME("watchGame"),

View file

@ -24,6 +24,7 @@ public class PlayerView implements Serializable {
private final UUID playerId;
private final String name;
private final boolean controlled; // gui: player is current user
private final boolean isHuman; // human or computer
private final int life;
private final Counters counters;
private final int wins;
@ -38,6 +39,7 @@ public class PlayerView implements Serializable {
private final ManaPoolView manaPool;
private final CardsView graveyard = new CardsView();
private final CardsView exile = new CardsView();
private final CardsView sideboard = new CardsView();
private final Map<UUID, PermanentView> battlefield = new LinkedHashMap<>();
private final CardView topCard;
private final UserData userData;
@ -58,6 +60,7 @@ public class PlayerView implements Serializable {
this.playerId = player.getId();
this.name = player.getName();
this.controlled = player.getId().equals(createdForPlayerId);
this.isHuman = player.isHuman();
this.life = player.getLife();
this.counters = player.getCounters();
this.wins = player.getMatchPlayer().getWins();
@ -85,6 +88,13 @@ public class PlayerView implements Serializable {
}
}
}
if (this.controlled || !player.isHuman()) {
// sideboard available for itself or for computer only
for (Card card : player.getSideboard().getCards(game)) {
sideboard.put(card.getId(), new CardView(card, game, false));
}
}
try {
for (Permanent permanent : state.getBattlefield().getAllPermanents()) {
if (showInBattlefield(permanent, state)) {
@ -167,6 +177,10 @@ public class PlayerView implements Serializable {
return this.controlled;
}
public boolean isHuman() {
return this.isHuman;
}
public int getLife() {
return this.life;
}
@ -207,6 +221,10 @@ public class PlayerView implements Serializable {
return exile;
}
public CardsView getSideboard() {
return this.sideboard;
}
public Map<UUID, PermanentView> getBattlefield() {
return this.battlefield;
}

View file

@ -259,6 +259,10 @@ public class User {
fireCallback(new ClientCallback(ClientCallbackMethod.VIEW_LIMITED_DECK, tableId, new TableClientMessage(deck, tableId, time, limited)));
}
public void ccViewSideboard(final UUID tableId, final UUID gameId, final UUID targetPlayerId) {
fireCallback(new ClientCallback(ClientCallbackMethod.VIEW_SIDEBOARD, tableId, new TableClientMessage(gameId, targetPlayerId)));
}
public void ccConstruct(final Deck deck, final UUID tableId, final int time) {
fireCallback(new ClientCallback(ClientCallbackMethod.CONSTRUCT, tableId, new TableClientMessage(deck, tableId, time)));
}

View file

@ -598,6 +598,12 @@ public class GameController implements GameCallback {
case VIEW_LIMITED_DECK:
viewLimitedDeck(getPlayerId(userId), userId);
break;
case VIEW_SIDEBOARD:
if (data instanceof UUID) {
UUID targetPlayerId = (UUID) data;
viewSideboard(getPlayerId(userId), userId, targetPlayerId);
}
break;
default:
game.sendPlayerAction(playerAction, getPlayerId(userId), data);
}
@ -656,13 +662,13 @@ public class GameController implements GameCallback {
}
}
private void viewLimitedDeck(UUID userIdRequester, UUID origId) {
Player viewLimitedDeckPlayer = game.getPlayer(userIdRequester);
private void viewLimitedDeck(UUID playerId, UUID userId) {
Player viewLimitedDeckPlayer = game.getPlayer(playerId);
if (viewLimitedDeckPlayer != null) {
if (viewLimitedDeckPlayer.isHuman()) {
for (MatchPlayer p : managerFactory.tableManager().getTable(tableId).getMatch().getPlayers()) {
if (p.getPlayer().getId().equals(userIdRequester)) {
Optional<User> u = managerFactory.userManager().getUser(origId);
if (p.getPlayer().getId().equals(playerId)) {
Optional<User> u = managerFactory.userManager().getUser(userId);
if (u.isPresent() && p.getDeck() != null) {
u.get().ccViewLimitedDeck(p.getDeck(), tableId, requestsOpen, true);
}
@ -672,6 +678,18 @@ public class GameController implements GameCallback {
}
}
private void viewSideboard(UUID playerId, UUID userId, UUID targetPlayerId) {
Player needPlayer = game.getPlayer(playerId);
if (needPlayer != null && needPlayer.isHuman()) {
for (MatchPlayer p : managerFactory.tableManager().getTable(tableId).getMatch().getPlayers()) {
if (p.getPlayer().getId().equals(playerId)) {
Optional<User> u = managerFactory.userManager().getUser(userId);
u.ifPresent(user -> user.ccViewSideboard(tableId, game.getId(), targetPlayerId));
}
}
}
}
public void cheat(UUID userId, UUID playerId, DeckCardLists deckList) {
try {
Deck deck = Deck.load(deckList, false, false);

View file

@ -592,9 +592,14 @@ public class ContinuousEffects implements Serializable {
Map<String, String> keyChoices = new HashMap<>();
for (ApprovingObject approvingObject : possibleApprovingObjects) {
MageObject mageObject = game.getObject(approvingObject.getApprovingAbility().getSourceId());
keyChoices.put(approvingObject.getApprovingAbility().getId().toString(),
(approvingObject.getApprovingAbility().getRule(mageObject == null ? "" : mageObject.getName()))
+ (mageObject == null ? "" : " (" + mageObject.getIdName() + ")"));
String choiceKey = approvingObject.getApprovingAbility().getId().toString();
String choiceValue;
if (mageObject == null) {
choiceValue = approvingObject.getApprovingAbility().getRule();
} else {
choiceValue = mageObject.getIdName() + ": " + approvingObject.getApprovingAbility().getRule(mageObject.getName());
}
keyChoices.put(choiceKey, choiceValue);
}
Choice choicePermitting = new ChoiceImpl(true);
choicePermitting.setMessage("Choose the permitting object");

View file

@ -59,5 +59,6 @@ public enum PlayerAction {
HOLD_PRIORITY,
UNHOLD_PRIORITY,
VIEW_LIMITED_DECK,
VIEW_SIDEBOARD,
TOGGLE_RECORD_MACRO
}