mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
commit
81193148e9
59 changed files with 673 additions and 233 deletions
|
@ -20,7 +20,7 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Panel for stack and hand zones
|
||||
* Panel for stack and hand zones, component for lookAt and reveal windows (CardInfoWindowDialog)
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||
*/
|
||||
|
@ -386,4 +386,14 @@
|
|||
public void setZone(Zone zone) {
|
||||
this.zone = zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* For GUI: get mage card components for update (example: change playable status)
|
||||
* Warning, do not change the list
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<UUID, MageCard> getMageCardsForUpdate() {
|
||||
return this.cards;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,13 @@ import java.awt.*;
|
|||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.InternalFrameAdapter;
|
||||
import javax.swing.event.InternalFrameEvent;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
|
||||
import mage.cards.MageCard;
|
||||
import mage.client.cards.BigCard;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.ImageHelper;
|
||||
|
@ -36,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;
|
||||
|
@ -91,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;
|
||||
|
@ -98,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
|
||||
}
|
||||
|
@ -151,15 +161,35 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* For GUI: get mage card components for update (example: change playable status)
|
||||
* Warning, do not change the list
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<UUID, MageCard> getMageCardsForUpdate() {
|
||||
return this.cards.getMageCardsForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (showType == ShowType.EXILE) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import mage.client.util.gui.ArrowBuilder;
|
|||
import mage.client.util.gui.MageDialogState;
|
||||
import mage.constants.*;
|
||||
import mage.game.events.PlayerQueryEvent;
|
||||
import mage.players.PlayableObjectStats;
|
||||
import mage.players.PlayableObjectsList;
|
||||
import mage.view.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
@ -76,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;
|
||||
|
@ -245,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();
|
||||
|
@ -307,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();
|
||||
|
@ -574,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();
|
||||
|
@ -618,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();
|
||||
|
@ -789,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();
|
||||
|
@ -851,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);
|
||||
|
@ -1146,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1196,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)) {
|
||||
|
@ -1386,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
|
||||
|
@ -1402,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()) {
|
||||
|
@ -1435,21 +1519,6 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
}
|
||||
}
|
||||
|
||||
// revealed
|
||||
for (RevealedView rev : lastGameData.game.getRevealed()) {
|
||||
for (Map.Entry<UUID, CardView> card : rev.getCards().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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// companion
|
||||
for (RevealedView rev : lastGameData.game.getCompanion()) {
|
||||
for (Map.Entry<UUID, CardView> card : rev.getCards().entrySet()) {
|
||||
|
@ -1465,7 +1534,24 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
}
|
||||
}
|
||||
|
||||
// looked at
|
||||
// revealed (current cards)
|
||||
for (RevealedView rev : lastGameData.game.getRevealed()) {
|
||||
for (Map.Entry<UUID, CardView> card : rev.getCards().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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// revealed (old windows)
|
||||
prepareSelectableWindows(revealed.values(), needSelectable, needChoosen, needPlayable);
|
||||
|
||||
// looked at (current cards)
|
||||
for (LookedAtView look : lastGameData.game.getLookedAt()) {
|
||||
for (Map.Entry<UUID, SimpleCardView> card : look.getCards().entrySet()) {
|
||||
if (needPlayable.containsObject(card.getKey())) {
|
||||
|
@ -1473,6 +1559,32 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
}
|
||||
}
|
||||
}
|
||||
// looked at (old windows)
|
||||
prepareSelectableWindows(lookedAt.values(), needSelectable, needChoosen, needPlayable);
|
||||
}
|
||||
|
||||
private void prepareSelectableWindows(
|
||||
Collection<CardInfoWindowDialog> windows,
|
||||
Set<UUID> needSelectable,
|
||||
List<UUID> needChoosen,
|
||||
PlayableObjectsList needPlayable
|
||||
) {
|
||||
// lookAt or reveals windows clean up on next priority, so users can see dialogs, but xmage can't restore it
|
||||
// so it must be updated manually (it's ok to keep outdated cards in dialog, but not ok to show wrong selections)
|
||||
for (CardInfoWindowDialog window : windows) {
|
||||
for (MageCard mageCard : window.getMageCardsForUpdate().values()) {
|
||||
CardView cardView = mageCard.getOriginal();
|
||||
cardView.setChoosable(needSelectable.contains(cardView.getId()));
|
||||
cardView.setSelected(needChoosen.contains(cardView.getId()));
|
||||
if (needPlayable.containsObject(cardView.getId())) {
|
||||
cardView.setPlayableStats(needPlayable.getStats(cardView.getId()));
|
||||
} else {
|
||||
cardView.setPlayableStats(new PlayableObjectStats());
|
||||
}
|
||||
// TODO: little bug with toggled night card after update/clicks, but that's ok (can't click on second side)
|
||||
mageCard.update(cardView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.combat.BlocksIfAbleTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.ReachAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -34,6 +35,7 @@ public final class AcademicDispute extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private AcademicDispute(final AcademicDispute card) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.a;
|
|||
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -23,6 +24,7 @@ public final class ArcaneSubtraction extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private ArcaneSubtraction(final ArcaneSubtraction card) {
|
||||
|
|
|
@ -4,6 +4,7 @@ package mage.cards.b;
|
|||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -26,6 +27,7 @@ public final class BurningWish extends CardImpl {
|
|||
|
||||
// You may choose a sorcery card you own from outside the game, reveal that card, and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(filter));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// Exile Burning Wish.
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.c;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -26,6 +27,7 @@ public final class CoaxFromTheBlindEternities extends CardImpl {
|
|||
|
||||
// You may choose an Eldrazi card you own from outside the game or in exile, reveal that card, and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(filter, true, true));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private CoaxFromTheBlindEternities(final CoaxFromTheBlindEternities card) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.c;
|
|||
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -21,6 +22,7 @@ public final class CramSession extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private CramSession(final CramSession card) {
|
||||
|
|
|
@ -4,6 +4,7 @@ package mage.cards.c;
|
|||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -26,6 +27,7 @@ public final class CunningWish extends CardImpl {
|
|||
|
||||
// You may choose an instant card you own from outside the game, reveal that card, and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(filter));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// Exile Cunning Wish.
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.d;
|
|||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.LoseHalfLifeEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -20,6 +21,7 @@ public final class DeathWish extends CardImpl {
|
|||
|
||||
// You may choose a card you own from outside the game and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(StaticFilters.FILTER_CARD_A, false));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// You lose half your life, rounded up.
|
||||
this.getSpellAbility().addEffect(new LoseHalfLifeEffect());
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.d;
|
|||
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -37,6 +38,7 @@ public final class DivideByZero extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private DivideByZero(final DivideByZero card) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import mage.abilities.common.BecomesTargetTriggeredAbility;
|
|||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -36,7 +37,8 @@ public final class DreamStrix extends CardImpl {
|
|||
));
|
||||
|
||||
// When Dream Strix dies, learn.
|
||||
this.addAbility(new DiesSourceTriggeredAbility(new LearnEffect()));
|
||||
this.addAbility(new DiesSourceTriggeredAbility(new LearnEffect())
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private DreamStrix(final DreamStrix card) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.e;
|
|||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -31,6 +32,7 @@ public final class EnthusiasticStudy extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private EnthusiasticStudy(final EnthusiasticStudy card) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.e;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -28,7 +29,8 @@ public final class Eyetwitch extends CardImpl {
|
|||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// When Eyetwitch dies, learn.
|
||||
this.addAbility(new DiesSourceTriggeredAbility(new LearnEffect()));
|
||||
this.addAbility(new DiesSourceTriggeredAbility(new LearnEffect())
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private Eyetwitch(final Eyetwitch card) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.costs.common.DiscardTargetCost;
|
|||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.ReturnToHandSourceEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.AdventureCard;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -46,6 +47,7 @@ public final class FaeOfWishes extends AdventureCard {
|
|||
// Granted
|
||||
// You may choose a noncreature card you own from outside the game, reveal it, and put it into your hand.
|
||||
this.getSpellCard().getSpellAbility().addEffect(new WishEffect(StaticFilters.FILTER_CARD_A_NON_CREATURE));
|
||||
this.getSpellCard().getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private FaeOfWishes(final FaeOfWishes card) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.f;
|
|||
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -32,6 +33,7 @@ public final class FieldTrip extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private FieldTrip(final FieldTrip card) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
|||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -32,6 +33,7 @@ public final class FirstDayOfClass extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private FirstDayOfClass(final FirstDayOfClass card) {
|
||||
|
|
|
@ -4,6 +4,7 @@ package mage.cards.g;
|
|||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -27,6 +28,7 @@ public final class GlitteringWish extends CardImpl {
|
|||
|
||||
// You may choose a multicolored card you own from outside the game, reveal that card, and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(filter));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// Exile Glittering Wish.
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.g;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -28,7 +29,8 @@ public final class GnarledProfessor extends CardImpl {
|
|||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// When Gnarled Professor enters the battlefield, learn.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect()));
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect())
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private GnarledProfessor(final GnarledProfessor card) {
|
||||
|
|
|
@ -4,6 +4,7 @@ package mage.cards.g;
|
|||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -29,6 +30,7 @@ public final class GoldenWish extends CardImpl {
|
|||
|
||||
// You may choose an artifact or enchantment card you own from outside the game, reveal that card, and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(filter));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// Exile Golden Wish.
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.g;
|
|||
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -22,8 +23,9 @@ public final class GuidingVoice extends CardImpl {
|
|||
this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
|
||||
// Learn (You may reveal a Lesson card you own from outside the game and p
|
||||
// Learn (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private GuidingVoice(final GuidingVoice card) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.h;
|
|||
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -22,6 +23,7 @@ public final class HuntForSpecimens extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private HuntForSpecimens(final HuntForSpecimens card) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.i;
|
|||
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -23,6 +24,7 @@ public final class IgneousInspiration extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private IgneousInspiration(final IgneousInspiration card) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.common.SimpleStaticAbility;
|
|||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
|
@ -50,7 +51,7 @@ public final class KarnTheGreatCreator extends CardImpl {
|
|||
// -2: You may choose an artifact card you own from outside the game or in exile, reveal that card, and put it into your hand.
|
||||
this.addAbility(new LoyaltyAbility(new WishEffect(
|
||||
StaticFilters.FILTER_CARD_ARTIFACT_AN, true, true
|
||||
), -2));
|
||||
), -2).addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private KarnTheGreatCreator(final KarnTheGreatCreator card) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.UUID;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -37,7 +38,8 @@ public final class LegionAngel extends CardImpl {
|
|||
|
||||
// When Legion Angel enters the battlefield, you may reveal a card you own named Legion Angel from outside the game and put it into your hand.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new WishEffect(filter, true, false)
|
||||
.setText("you may reveal a card you own named Legion Angel from outside the game and put it into your hand")));
|
||||
.setText("you may reveal a card you own named Legion Angel from outside the game and put it into your hand"))
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private LegionAngel(final LegionAngel card) {
|
||||
|
|
|
@ -4,6 +4,7 @@ package mage.cards.l;
|
|||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -29,6 +30,7 @@ public final class LivingWish extends CardImpl {
|
|||
|
||||
// You may choose a creature or land card you own from outside the game, reveal that card, and put it into your hand.
|
||||
this.getSpellAbility().addEffect(new WishEffect(filter));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// Exile Living Wish.
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.m;
|
|||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -27,6 +28,7 @@ public final class MastermindsAcquisition extends CardImpl {
|
|||
Mode mode = new Mode(new WishEffect(StaticFilters.FILTER_CARD_A, false)
|
||||
.setText("Put a card you own from outside the game into your hand"));
|
||||
this.getSpellAbility().addMode(mode);
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private MastermindsAcquisition(final MastermindsAcquisition card) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import mage.abilities.costs.common.TapSourceCost;
|
|||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.DefenderAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -38,6 +39,7 @@ public final class OvergrownArch extends CardImpl {
|
|||
// {2}, Sacrifice Overgrown Arch: Learn.
|
||||
Ability ability = new SimpleActivatedAbility(new LearnEffect(), new GenericManaCost(2));
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
ability.addHint(OpenSideboardHint.instance);
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
|||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -29,7 +30,8 @@ public final class PoetsQuill extends CardImpl {
|
|||
this.subtype.add(SubType.EQUIPMENT);
|
||||
|
||||
// When Poet's Quill enters the battlefield, learn.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect()));
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect())
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
|
||||
// Equipped creature gets +1/+1 and has lifelink.
|
||||
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1));
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.p;
|
|||
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -21,6 +22,7 @@ public final class PopQuiz extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private PopQuiz(final PopQuiz card) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.cards.p;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -24,7 +25,8 @@ public final class ProfessorOfSymbology extends CardImpl {
|
|||
this.toughness = new MageInt(1);
|
||||
|
||||
// When Professor of Symbology enters the battlefield, learn.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect()));
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect())
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private ProfessorOfSymbology(final ProfessorOfSymbology card) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.UUID;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
|
@ -26,6 +27,7 @@ public final class ResearchDevelopment extends SplitCard {
|
|||
|
||||
// Choose up to four cards you own from outside the game and shuffle them into your library.
|
||||
getLeftHalfCard().getSpellAbility().addEffect(new ResearchEffect());
|
||||
getLeftHalfCard().getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
|
||||
// Create a 3/1 red Elemental creature token unless any opponent has you draw a card. Repeat this process two more times.
|
||||
getRightHalfCard().getSpellAbility().addEffect(new DevelopmentEffect());
|
||||
|
|
|
@ -9,6 +9,7 @@ import mage.abilities.condition.common.CastFromEverywhereSourceCondition;
|
|||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.Card;
|
||||
|
@ -43,7 +44,7 @@ public final class RetrieverPhoenix extends CardImpl {
|
|||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
|
||||
new EntersBattlefieldTriggeredAbility(new LearnEffect()), CastFromEverywhereSourceCondition.instance,
|
||||
"When {this} enters the battlefield, if you cast it, " + LearnEffect.getDefaultText()
|
||||
));
|
||||
).addHint(OpenSideboardHint.instance));
|
||||
|
||||
// As long as Retriever Phoenix is in your graveyard, if you would learn, you may instead return Retriever Phoenix to the battlefield.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new RetrieverPhoenixEffect()));
|
||||
|
|
|
@ -9,6 +9,7 @@ import mage.abilities.costs.common.TapSourceCost;
|
|||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -33,6 +34,7 @@ public final class RingOfMaruf extends CardImpl {
|
|||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RingOfMarufEffect(), new ManaCostsImpl("{5}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new ExileSourceCost());
|
||||
ability.addHint(OpenSideboardHint.instance);
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.r;
|
|||
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -29,6 +30,7 @@ public final class RiseOfExtus extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private RiseOfExtus(final RiseOfExtus card) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
|||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.UntapTargetEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -23,7 +24,8 @@ public final class SparringRegimen extends CardImpl {
|
|||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
|
||||
|
||||
// When Sparring Regimen enters the battlefield, learn.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect()));
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new LearnEffect())
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
|
||||
// Whenever you attack, put a +1/+1 counter on target attacking creature and untap it.
|
||||
Ability ability = new AttacksWithCreaturesTriggeredAbility(
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CastCardFromOutsideTheGameEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.AnnihilatorAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -43,7 +44,9 @@ public final class SpawnsireOfUlamog extends CardImpl {
|
|||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new EldraziSpawnToken(), 2), new GenericManaCost(4)));
|
||||
|
||||
// {20}: Cast any number of Eldrazi cards you own from outside the game without paying their mana costs.
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CastCardFromOutsideTheGameEffect(filter, ruleText), new GenericManaCost(20)));
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
||||
new CastCardFromOutsideTheGameEffect(filter, ruleText), new GenericManaCost(20)
|
||||
).addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private SpawnsireOfUlamog(final SpawnsireOfUlamog card) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package mage.cards.s;
|
|||
|
||||
import mage.abilities.effects.common.LearnEffect;
|
||||
import mage.abilities.effects.common.TapTargetEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -23,6 +24,7 @@ public final class StudyBreak extends CardImpl {
|
|||
|
||||
// Learn.
|
||||
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private StudyBreak(final StudyBreak card) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.UUID;
|
|||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.common.SagaAbility;
|
||||
import mage.abilities.effects.common.*;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SagaChapter;
|
||||
|
@ -51,6 +52,7 @@ public final class TheRavensWarning extends CardImpl {
|
|||
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III,
|
||||
new WishEffect(StaticFilters.FILTER_CARD_A, false, false, true)
|
||||
);
|
||||
sagaAbility.addHint(OpenSideboardHint.instance);
|
||||
this.addAbility(sagaAbility);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect
|
|||
import mage.abilities.effects.common.WishEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.effects.common.counter.DistributeCountersEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -58,7 +59,8 @@ public final class VivienArkbowRanger extends CardImpl {
|
|||
this.addAbility(ability);
|
||||
|
||||
// −5: You may choose a creature card you own from outside the game, reveal it, and put it into your hand.
|
||||
this.addAbility(new LoyaltyAbility(new WishEffect(StaticFilters.FILTER_CARD_CREATURE_A), -5));
|
||||
this.addAbility(new LoyaltyAbility(new WishEffect(StaticFilters.FILTER_CARD_CREATURE_A), -5)
|
||||
.addHint(OpenSideboardHint.instance));
|
||||
}
|
||||
|
||||
private VivienArkbowRanger(final VivienArkbowRanger card) {
|
||||
|
|
137
Mage.Sets/src/mage/cards/w/Wish.java
Normal file
137
Mage.Sets/src/mage/cards/w/Wish.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
package mage.cards.w;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.hint.common.OpenSideboardHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author weirddan455
|
||||
*/
|
||||
public final class Wish extends CardImpl {
|
||||
|
||||
public Wish(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
|
||||
|
||||
// You may play a card you own from outside the game this turn.
|
||||
this.getSpellAbility().addEffect(new WishEffect());
|
||||
this.getSpellAbility().setIdentifier(MageIdentifier.WishWatcher);
|
||||
this.getSpellAbility().addWatcher(new WishWatcher());
|
||||
this.getSpellAbility().addHint(OpenSideboardHint.instance);
|
||||
}
|
||||
|
||||
private Wish(final Wish card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wish copy() {
|
||||
return new Wish(this);
|
||||
}
|
||||
}
|
||||
|
||||
class WishEffect extends OneShotEffect {
|
||||
|
||||
public WishEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "You may play a card you own from outside the game this turn";
|
||||
}
|
||||
|
||||
private WishEffect(final WishEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WishEffect copy() {
|
||||
return new WishEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && !controller.getSideboard().isEmpty()) {
|
||||
controller.lookAtCards(source, "Sideboard", controller.getSideboard(), game);
|
||||
game.addEffect(new WishPlayFromSideboardEffect(), source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class WishPlayFromSideboardEffect extends AsThoughEffectImpl {
|
||||
|
||||
public WishPlayFromSideboardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit, true);
|
||||
}
|
||||
|
||||
private WishPlayFromSideboardEffect(final WishPlayFromSideboardEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WishPlayFromSideboardEffect copy() {
|
||||
return new WishPlayFromSideboardEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (source.getControllerId().equals(affectedControllerId)) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
UUID mainCardId = CardUtil.getMainCardId(game, objectId);
|
||||
if (controller != null && sourceObject != null && controller.getSideboard().contains(mainCardId)) {
|
||||
WishWatcher watcher = game.getState().getWatcher(WishWatcher.class);
|
||||
return watcher != null && !watcher.isAbilityUsed(new MageObjectReference(sourceObject, game));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class WishWatcher extends Watcher {
|
||||
|
||||
private final Set<MageObjectReference> usedFrom = new HashSet<>();
|
||||
|
||||
WishWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if ((GameEvent.EventType.SPELL_CAST.equals(event.getType()) || GameEvent.EventType.LAND_PLAYED.equals(event.getType()))
|
||||
&& event.hasApprovingIdentifier(MageIdentifier.WishWatcher)) {
|
||||
usedFrom.add(event.getAdditionalReference().getApprovingMageObjectReference());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
usedFrom.clear();
|
||||
}
|
||||
|
||||
boolean isAbilityUsed(MageObjectReference mor) {
|
||||
return usedFrom.contains(mor);
|
||||
}
|
||||
}
|
|
@ -263,6 +263,7 @@ public final class AdventuresInTheForgottenRealms extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("White Dragon", 41, Rarity.UNCOMMON, mage.cards.w.WhiteDragon.class));
|
||||
cards.add(new SetCardInfo("Wight", 127, Rarity.RARE, mage.cards.w.Wight.class));
|
||||
cards.add(new SetCardInfo("Wild Shape", 212, Rarity.UNCOMMON, mage.cards.w.WildShape.class));
|
||||
cards.add(new SetCardInfo("Wish", 166, Rarity.RARE, mage.cards.w.Wish.class));
|
||||
cards.add(new SetCardInfo("Wizard Class", 81, Rarity.UNCOMMON, mage.cards.w.WizardClass.class));
|
||||
cards.add(new SetCardInfo("Wizard's Spellbook", 82, Rarity.RARE, mage.cards.w.WizardsSpellbook.class));
|
||||
cards.add(new SetCardInfo("Xorn", 167, Rarity.RARE, mage.cards.x.Xorn.class));
|
||||
|
|
|
@ -94,47 +94,48 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
// @Ignore // It's not possible yet to select which ability to use to allow a asThoughtAs effect
|
||||
public void test_castFromGraveyardWithDifferentApprovers() {
|
||||
setStrictChooseMode(true);
|
||||
skipInitShuffling();
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||
|
||||
//
|
||||
// {1}{B}: Target attacking Zombie gains indestructible until end of turn.
|
||||
addCard(Zone.LIBRARY, playerA, "Accursed Horde", 1); // Creature Zombie {3}{B}
|
||||
skipInitShuffling();
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 5);
|
||||
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 5); // Creature {1}{W}
|
||||
//
|
||||
// Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard.
|
||||
// During each of your turns, you may cast one creature card from your graveyard.
|
||||
addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W}
|
||||
|
||||
//
|
||||
// When Gisa and Geralf enters the battlefield, put the top four cards of your library into your graveyard.
|
||||
// During each of your turns, you may cast a Zombie creature card from your graveyard.
|
||||
addCard(Zone.HAND, playerA, "Gisa and Geralf"); // CREATURE {2}{U}{B} (4/4)
|
||||
|
||||
// prepare spels with same AsThough effects and puts creature to graveyard
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gisa and Geralf");
|
||||
|
||||
// you play any creatures due to two approve objects
|
||||
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Silvercoat Lion", true);
|
||||
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Accursed Horde", true);
|
||||
|
||||
// cast zombie creature and approves by Karagar
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Accursed Horde");
|
||||
setChoice(playerA, "During each of your turns, you may cast a Zombie creature card from your graveyard"); // Choose the permitting object
|
||||
setChoice(playerA, "Karador, Ghost Chieftain"); // choose the permitting object
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion");
|
||||
// you can't cast lion due to approving object (Gisa needs zombie)
|
||||
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Silvercoat Lion", false);
|
||||
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Accursed Horde", false);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1);
|
||||
assertPermanentCount(playerA, "Gisa and Geralf", 1);
|
||||
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||
assertPermanentCount(playerA, "Accursed Horde", 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1977,7 +1977,14 @@ public class TestPlayer implements Player {
|
|||
//Assert.fail("Wrong choice");
|
||||
}
|
||||
|
||||
this.chooseStrictModeFailed("choice", game, choice.getMessage());
|
||||
String choicesInfo;
|
||||
if (choice.isKeyChoice()) {
|
||||
choicesInfo = String.join("\n", choice.getKeyChoices().values());
|
||||
} else {
|
||||
choicesInfo = String.join("\n", choice.getChoices());
|
||||
}
|
||||
this.chooseStrictModeFailed("choice", game,
|
||||
"Message: " + choice.getMessage() + "\nPossible choices:\n" + choicesInfo);
|
||||
return computerPlayer.choose(outcome, choice, game);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package mage;
|
||||
|
||||
/**
|
||||
* Used to identify specific actions/events and to be able to assign them to the
|
||||
* correct watcher or other processing.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum MageIdentifier {
|
||||
GisaAndGeralfWatcher,
|
||||
KaradorGhostChieftainWatcher,
|
||||
KessDissidentMageWatcher,
|
||||
LurrusOfTheDreamDenWatcher,
|
||||
MuldrothaTheGravetideWatcher
|
||||
}
|
||||
package mage;
|
||||
|
||||
/**
|
||||
* Used to identify specific actions/events and to be able to assign them to the
|
||||
* correct watcher or other processing.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum MageIdentifier {
|
||||
GisaAndGeralfWatcher,
|
||||
KaradorGhostChieftainWatcher,
|
||||
KessDissidentMageWatcher,
|
||||
LurrusOfTheDreamDenWatcher,
|
||||
MuldrothaTheGravetideWatcher,
|
||||
WishWatcher
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum SideboardCardsYouControlCount implements DynamicValue {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
Player player = game.getPlayer(sourceAbility.getControllerId());
|
||||
if (player == null) {
|
||||
return 0;
|
||||
}
|
||||
return player.getSideboard().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SideboardCardsYouControlCount copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "cards in your sideboard";
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.common.SideboardCardsYouControlCount;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum OpenSideboardHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final Hint hint = new ValueHint("Cards in your sideboard", SideboardCardsYouControlCount.instance);
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability) + " (<i>Right click on battlefield to open player's sideboard at any time</i>)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
|
@ -59,5 +59,6 @@ public enum PlayerAction {
|
|||
HOLD_PRIORITY,
|
||||
UNHOLD_PRIORITY,
|
||||
VIEW_LIMITED_DECK,
|
||||
VIEW_SIDEBOARD,
|
||||
TOGGLE_RECORD_MACRO
|
||||
}
|
||||
|
|
|
@ -3646,13 +3646,22 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
// check to play companion cards
|
||||
// outside cards
|
||||
if (fromAll || fromZone == Zone.OUTSIDE) {
|
||||
// companion cards
|
||||
for (Cards companionCards : game.getState().getCompanion().values()) {
|
||||
for (Card card : companionCards.getCards(game)) {
|
||||
getPlayableFromObjectAll(game, Zone.OUTSIDE, card, availableMana, playable);
|
||||
}
|
||||
}
|
||||
|
||||
// sideboard cards (example: Wish)
|
||||
for (UUID sideboardCardId : this.getSideboard()) {
|
||||
Card sideboardCard = game.getCard(sideboardCardId);
|
||||
if (sideboardCard != null) {
|
||||
getPlayableFromObjectAll(game, Zone.OUTSIDE, sideboardCard, availableMana, playable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if it's possible to play the top card of a library
|
||||
|
|
Loading…
Reference in a new issue