mirror of
https://github.com/correl/mage.git
synced 2025-04-02 03:18:09 -09:00
Merge branch 'master' into GlitterLionTextFix
This commit is contained in:
commit
653ca9cc5a
2083 changed files with 40145 additions and 16096 deletions
Mage.Client
pom.xml
src/main
java
mage/client
MageFrame.java
cards
components
deckeditor/collection/viewer
dialog
CardInfoWindowDialog.javaNewTableDialog.javaNewTournamentDialog.javaPickChoiceDialog.formPickChoiceDialog.java
game
table
util
org/mage
resources
Mage.Common
pom.xml
src/main/java/mage
Mage.Plugins
Mage.Server.Console
Mage.Server.Plugins
Mage.Deck.Constructed
Mage.Deck.Limited
Mage.Game.BrawlDuel
Mage.Game.BrawlFreeForAll
Mage.Game.CanadianHighlanderDuel
Mage.Game.CommanderDuel
Mage.Game.CommanderFreeForAll
Mage.Game.FreeForAll
Mage.Game.FreeformCommanderDuel
Mage.Game.FreeformCommanderFreeForAll
Mage.Game.FreeformUnlimitedCommander
Mage.Game.MomirDuel
Mage.Game.MomirGame
Mage.Game.OathbreakerDuel
Mage.Game.OathbreakerFreeForAll
Mage.Game.PennyDreadfulCommanderFreeForAll
Mage.Game.TinyLeadersDuel
Mage.Game.TwoPlayerDuel
Mage.Player.AI.DraftBot
Mage.Player.AI.MA
Mage.Player.AI
Mage.Player.AIMCTS
Mage.Player.AIMinimax
Mage.Player.Human
Mage.Tournament.BoosterDraft
Mage.Tournament.Constructed
Mage.Tournament.Sealed
pom.xml
pom.xmlsrc/mage/tournament
Mage.Server
Mage.Sets
pom.xml
src/mage/cards/a
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-client</artifactId>
|
||||
|
|
|
@ -202,7 +202,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
config.setAccessPreference(FsAccessOption.STORE, true);
|
||||
try {
|
||||
UIManager.put("desktop", new Color(0, 0, 0, 0));
|
||||
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
|
||||
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
|
||||
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
// stop JSplitPane from eating F6 and F8 or any other function keys
|
||||
{
|
||||
|
|
|
@ -562,6 +562,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
JButton selectByButton;
|
||||
JButton analyseButton;
|
||||
JButton blingButton;
|
||||
JButton oldVersionButton;
|
||||
|
||||
// Popup for toolbar
|
||||
final JPopupMenu filterPopup;
|
||||
|
@ -716,6 +717,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
selectByButton = new JButton("Select By");
|
||||
analyseButton = new JButton("M"); // "Mana" button
|
||||
blingButton = new JButton("B"); // "Bling" button
|
||||
oldVersionButton = new JButton("O"); // "Old version" button
|
||||
|
||||
// Name and count label
|
||||
deckNameAndCountLabel = new JLabel();
|
||||
|
@ -740,6 +742,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
toolbarInner.add(visibilityButton);
|
||||
toolbarInner.add(analyseButton);
|
||||
toolbarInner.add(blingButton);
|
||||
toolbarInner.add(oldVersionButton);
|
||||
toolbar.add(toolbarInner, BorderLayout.WEST);
|
||||
JPanel sliderPanel = new JPanel(new GridBagLayout());
|
||||
sliderPanel.setOpaque(false);
|
||||
|
@ -982,6 +985,11 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
|
||||
blingButton.addActionListener(evt -> blingDeck());
|
||||
|
||||
// Old version button - Switch cards to the oldest non-promo printing. In case of multiples in a set, take the lowest card number.
|
||||
oldVersionButton.setToolTipText("Switch cards to the oldest non-promo printing");
|
||||
|
||||
oldVersionButton.addActionListener(evt -> oldVersionDeck());
|
||||
|
||||
// Filter popup
|
||||
filterPopup = new JPopupMenu();
|
||||
filterPopup.setPreferredSize(new Dimension(300, 300));
|
||||
|
@ -1567,6 +1575,44 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
}
|
||||
}
|
||||
|
||||
private void oldVersionDeck() {
|
||||
if (this.mode != Constants.DeckEditorMode.FREE_BUILDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you want to switch your card versions to the oldest ones?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<List<List<CardView>>> newCardGrid = new ArrayList<>();
|
||||
for (List<List<CardView>> gridRow : cardGrid) {
|
||||
List<List<CardView>> newGridRow = new ArrayList<>();
|
||||
for (List<CardView> stack : gridRow) {
|
||||
List<CardView> newStack = new ArrayList<>();
|
||||
for (CardView card : stack) {
|
||||
CardInfo oldestCardInfo = CardRepository.instance.findOldestNonPromoVersionCard(card.getName());
|
||||
if (oldestCardInfo != null) {
|
||||
CardView oldestCardView = new CardView(oldestCardInfo.getMockCard());
|
||||
this.removeCardView(card);
|
||||
eventSource.fireEvent(card, ClientEventType.REMOVE_SPECIFIC_CARD);
|
||||
this.addCardView(oldestCardView, false);
|
||||
eventSource.fireEvent(oldestCardView, ClientEventType.ADD_SPECIFIC_CARD);
|
||||
newStack.add(oldestCardView);
|
||||
} else {
|
||||
newStack.add(card);
|
||||
}
|
||||
}
|
||||
newGridRow.add(newStack);
|
||||
}
|
||||
newCardGrid.add(newGridRow);
|
||||
}
|
||||
cardGrid = newCardGrid;
|
||||
layoutGrid();
|
||||
cardScroll.revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
// Update the contents of the card grid
|
||||
public void setCards(CardsView cardsView, DeckCardLayout layout, BigCard bigCard) {
|
||||
if (bigCard != null) {
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
package mage.client.components;
|
||||
|
||||
//import com.sun.java.swing.Painter;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import javax.swing.JDesktopPane;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIManager;
|
||||
|
@ -22,7 +17,7 @@ public class MageJDesktop extends JDesktopPane {
|
|||
public void updateUI() {
|
||||
if ("Nimbus".equals(UIManager.getLookAndFeel().getName())) {
|
||||
UIDefaults map = new UIDefaults();
|
||||
Painter painter = (g, c, w, h) -> {
|
||||
Painter<?> painter = (g, c, w, h) -> {
|
||||
g.setColor( UIManager.getDefaults().getColor("desktop") );
|
||||
g.fillRect(0,0,w,h);
|
||||
};
|
||||
|
|
|
@ -383,7 +383,7 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener {
|
|||
|
||||
public static void main(String[] argv) {
|
||||
try {
|
||||
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
|
||||
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
|
|
|
@ -562,8 +562,8 @@ public class MageBook extends JComponent {
|
|||
Constructor<?> cons = c.getConstructor();
|
||||
Object newToken = cons.newInstance();
|
||||
if (newToken instanceof Token) {
|
||||
((Token) newToken).setExpansionSetCodeForImage(set);
|
||||
((Token) newToken).setOriginalExpansionSetCode(set);
|
||||
((Token) newToken).setExpansionSetCodeForImage(set);
|
||||
((Token) newToken).setTokenType(token.getType());
|
||||
tokens.add((Token) newToken);
|
||||
}
|
||||
|
@ -634,6 +634,10 @@ public class MageBook extends JComponent {
|
|||
}
|
||||
}
|
||||
|
||||
if (emblems.size() == 0) {
|
||||
return emblems;
|
||||
}
|
||||
|
||||
int totalTokens = getTotalNumTokens(set);
|
||||
int start = 0;
|
||||
if (!(page * conf.CARDS_PER_PAGE <= totalTokens && (page + 1) * conf.CARDS_PER_PAGE >= totalTokens)) {
|
||||
|
@ -917,8 +921,8 @@ public class MageBook extends JComponent {
|
|||
|
||||
private int currentPage = 0;
|
||||
private String currentSet = "RTR";
|
||||
private int currentCardsInSet = 0;
|
||||
private int currentCardsNotInSet = 0;
|
||||
private final int currentCardsInSet = 0;
|
||||
private final int currentCardsNotInSet = 0;
|
||||
|
||||
private static CardDimensions cardDimensions = new CardDimensions(1.2d);
|
||||
private static final Logger log = Logger.getLogger(MageBook.class);
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
package mage.client.dialog;
|
||||
|
||||
import java.awt.*;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.InternalFrameAdapter;
|
||||
import javax.swing.event.InternalFrameEvent;
|
||||
import mage.client.cards.BigCard;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.ImageHelper;
|
||||
|
@ -13,15 +22,6 @@ import mage.view.SimpleCardsView;
|
|||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.InternalFrameAdapter;
|
||||
import javax.swing.event.InternalFrameEvent;
|
||||
import java.awt.*;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||
*/
|
||||
|
@ -77,7 +77,7 @@ public class CardInfoWindowDialog extends MageDialog {
|
|||
this.setClosable(false);
|
||||
break;
|
||||
default:
|
||||
// no icon yet
|
||||
// no icon yet
|
||||
}
|
||||
this.setTitelBarToolTip(name);
|
||||
setGUISize();
|
||||
|
@ -174,13 +174,17 @@ public class CardInfoWindowDialog extends MageDialog {
|
|||
Set<String> cardTypesPresent = new LinkedHashSet<String>() {
|
||||
};
|
||||
for (CardView card : cardsView.values()) {
|
||||
Set<CardType> cardTypes = card.getCardTypes();
|
||||
Set<CardType> cardTypes = EnumSet.noneOf(CardType.class);
|
||||
cardTypes.addAll(card.getCardTypes());
|
||||
for (CardType cardType : cardTypes) {
|
||||
cardTypesPresent.add(cardType.toString());
|
||||
}
|
||||
}
|
||||
if (cardTypesPresent.isEmpty()) return 0;
|
||||
else return cardTypesPresent.size();
|
||||
if (cardTypesPresent.isEmpty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return cardTypesPresent.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -890,7 +890,7 @@ public class NewTableDialog extends MageDialog {
|
|||
this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS + versionStr, "0")));
|
||||
this.cbMulligan.setSelectedItem(MulliganType.valueByName(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_MULLIGAN_TYPE + versionStr, MulliganType.GAME_DEFAULT.toString())));
|
||||
|
||||
int range = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, "1"));
|
||||
int range = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, "0"));
|
||||
for (RangeOfInfluence roi : RangeOfInfluence.values()) {
|
||||
if (roi.getRange() == range) {
|
||||
this.cbRange.setSelectedItem(roi);
|
||||
|
|
|
@ -1203,6 +1203,7 @@ public class NewTournamentDialog extends MageDialog {
|
|||
tOptions.getLimitedOptions().setConstructionTime((Integer) this.spnConstructTime.getValue() * 60);
|
||||
tOptions.getLimitedOptions().setIsRandom(tournamentType.isRandom());
|
||||
tOptions.getLimitedOptions().setIsRichMan(tournamentType.isRichMan());
|
||||
tOptions.getLimitedOptions().setIsJumpstart(tournamentType.isJumpstart());
|
||||
if (tournamentType.isCubeBooster()) {
|
||||
tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString());
|
||||
if (!(cubeFromDeckFilename.isEmpty())) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="resizable" type="boolean" value="true"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
</SyntheticProperties>
|
||||
|
@ -39,7 +42,7 @@
|
|||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="panelSearch" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="scrollList" pref="246" max="32767" attributes="0"/>
|
||||
<Component id="scrollList" pref="282" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="panelCommands" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
|
@ -55,8 +58,8 @@
|
|||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="labelMessage" alignment="1" pref="210" max="32767" attributes="0"/>
|
||||
<Component id="labelSubMessage" alignment="1" pref="210" max="32767" attributes="0"/>
|
||||
<Component id="labelMessage" alignment="1" pref="337" max="32767" attributes="0"/>
|
||||
<Component id="labelSubMessage" alignment="1" pref="337" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
|
@ -203,4 +206,4 @@
|
|||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
</Form>
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
package mage.client.dialog;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import mage.choices.Choice;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.util.gui.MageDialogState;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
||||
public class PickChoiceDialog extends MageDialog {
|
||||
|
||||
Choice choice;
|
||||
List<KeyValueItem> allItems = new ArrayList<>();
|
||||
java.util.List<KeyValueItem> allItems = new ArrayList<>();
|
||||
DefaultListModel<KeyValueItem> dataModel = new DefaultListModel<>();
|
||||
|
||||
final private static String HTML_TEMPLATE = "<html><div style='text-align: center;'>%s</div></html>";
|
||||
|
@ -79,7 +76,7 @@ public class PickChoiceDialog extends MageDialog {
|
|||
this.editSearch.setText("");
|
||||
}
|
||||
|
||||
// listeners for inremental filtering
|
||||
// listeners for inremental filtering
|
||||
editSearch.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
|
@ -104,7 +101,7 @@ public class PickChoiceDialog extends MageDialog {
|
|||
editSearch.addKeyListener(new KeyListener() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
//System.out.println("types");
|
||||
//System.out.println("types");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,8 +149,11 @@ public class PickChoiceDialog extends MageDialog {
|
|||
} else {
|
||||
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
|
||||
}
|
||||
if (mageDialogState != null) mageDialogState.setStateToDialog(this);
|
||||
else this.makeWindowCentered();
|
||||
if (mageDialogState != null) {
|
||||
mageDialogState.setStateToDialog(this);
|
||||
} else {
|
||||
this.makeWindowCentered();
|
||||
}
|
||||
|
||||
// final load
|
||||
loadData();
|
||||
|
@ -269,6 +269,7 @@ public class PickChoiceDialog extends MageDialog {
|
|||
}
|
||||
|
||||
class KeyValueItem {
|
||||
|
||||
private final String Key;
|
||||
private final String Value;
|
||||
|
||||
|
@ -312,6 +313,8 @@ public class PickChoiceDialog extends MageDialog {
|
|||
btOK = new javax.swing.JButton();
|
||||
btCancel = new javax.swing.JButton();
|
||||
|
||||
setResizable(true);
|
||||
|
||||
labelMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
labelMessage.setText("<html><div style='text-align: center;'>example long message example long message example long message example long message example long message</div></html>");
|
||||
|
||||
|
@ -322,20 +325,20 @@ public class PickChoiceDialog extends MageDialog {
|
|||
javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader);
|
||||
panelHeader.setLayout(panelHeaderLayout);
|
||||
panelHeaderLayout.setHorizontalGroup(
|
||||
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelHeaderLayout.createSequentialGroup()
|
||||
.addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)
|
||||
.addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE))
|
||||
.addGap(0, 0, 0))
|
||||
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelHeaderLayout.createSequentialGroup()
|
||||
.addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 337, Short.MAX_VALUE)
|
||||
.addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 337, Short.MAX_VALUE))
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
panelHeaderLayout.setVerticalGroup(
|
||||
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelHeaderLayout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(labelMessage)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(labelSubMessage))
|
||||
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelHeaderLayout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(labelMessage)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(labelSubMessage))
|
||||
);
|
||||
|
||||
labelSearch.setText("Search:");
|
||||
|
@ -345,34 +348,28 @@ public class PickChoiceDialog extends MageDialog {
|
|||
javax.swing.GroupLayout panelSearchLayout = new javax.swing.GroupLayout(panelSearch);
|
||||
panelSearch.setLayout(panelSearchLayout);
|
||||
panelSearchLayout.setHorizontalGroup(
|
||||
panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelSearchLayout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(labelSearch)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(editSearch)
|
||||
.addGap(0, 0, 0))
|
||||
panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelSearchLayout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(labelSearch)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(editSearch)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
panelSearchLayout.setVerticalGroup(
|
||||
panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelSearchLayout.createSequentialGroup()
|
||||
.addGap(3, 3, 3)
|
||||
.addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(labelSearch)
|
||||
.addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(3, 3, 3))
|
||||
panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelSearchLayout.createSequentialGroup()
|
||||
.addGap(3, 3, 3)
|
||||
.addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(labelSearch)
|
||||
.addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(3, 3, 3))
|
||||
);
|
||||
|
||||
listChoices.setModel(new javax.swing.AbstractListModel() {
|
||||
String[] strings = {"item1", "item2", "item3"};
|
||||
|
||||
public int getSize() {
|
||||
return strings.length;
|
||||
}
|
||||
|
||||
public Object getElementAt(int i) {
|
||||
return strings[i];
|
||||
}
|
||||
String[] strings = { "item1", "item2", "item3" };
|
||||
public int getSize() { return strings.length; }
|
||||
public Object getElementAt(int i) { return strings[i]; }
|
||||
});
|
||||
scrollList.setViewportView(listChoices);
|
||||
|
||||
|
@ -393,25 +390,25 @@ public class PickChoiceDialog extends MageDialog {
|
|||
javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands);
|
||||
panelCommands.setLayout(panelCommandsLayout);
|
||||
panelCommandsLayout.setHorizontalGroup(
|
||||
panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelCommandsLayout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(btOK)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelCommandsLayout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(btOK)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, btCancel, btOK);
|
||||
panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {btCancel, btOK});
|
||||
|
||||
panelCommandsLayout.setVerticalGroup(
|
||||
panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelCommandsLayout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(btCancel)
|
||||
.addComponent(btOK))
|
||||
.addContainerGap())
|
||||
panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelCommandsLayout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(btCancel)
|
||||
.addComponent(btOK))
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
getRootPane().setDefaultButton(btOK);
|
||||
|
@ -419,28 +416,28 @@ public class PickChoiceDialog extends MageDialog {
|
|||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 282, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
pack();
|
||||
|
@ -474,4 +471,4 @@ public class PickChoiceDialog extends MageDialog {
|
|||
private javax.swing.JPanel panelSearch;
|
||||
private javax.swing.JScrollPane scrollList;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package mage.client.game;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.GroupLayout.Alignment;
|
||||
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.LineBorder;
|
||||
import mage.cards.decks.importer.DckDeckImporter;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
|
@ -15,6 +23,7 @@ import mage.client.util.gui.countryBox.CountryUtil;
|
|||
import mage.components.ImagePanel;
|
||||
import mage.components.ImagePanelStyle;
|
||||
import mage.constants.CardType;
|
||||
import static mage.constants.Constants.*;
|
||||
import mage.constants.ManaType;
|
||||
import mage.counters.Counter;
|
||||
import mage.counters.CounterType;
|
||||
|
@ -23,17 +32,6 @@ import mage.utils.timer.PriorityTimer;
|
|||
import mage.view.*;
|
||||
import org.mage.card.arcane.ManaSymbols;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.GroupLayout.Alignment;
|
||||
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.LineBorder;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.*;
|
||||
|
||||
import static mage.constants.Constants.*;
|
||||
|
||||
/**
|
||||
* Enhanced player pane.
|
||||
*
|
||||
|
@ -42,7 +40,6 @@ import static mage.constants.Constants.*;
|
|||
public class PlayerPanelExt extends javax.swing.JPanel {
|
||||
|
||||
// TODO: *.form file was lost, panel must be reworks in designer
|
||||
|
||||
private UUID playerId;
|
||||
private UUID gameId;
|
||||
private PlayerView player;
|
||||
|
@ -612,7 +609,6 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
|||
manaCountLabelW.addMouseListener(manaMouseAdapter);
|
||||
manaLabels.put(manaCountLabelW, ManaType.WHITE);l
|
||||
//*/
|
||||
|
||||
///*
|
||||
JLabel manaCountLabelW = new JLabel();
|
||||
manaCountLabelW.setToolTipText("White mana");
|
||||
|
@ -944,7 +940,8 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
|||
Set<String> cardTypesPresent = new LinkedHashSet<String>() {
|
||||
};
|
||||
for (CardView card : cardsView.values()) {
|
||||
Set<CardType> cardTypes = card.getCardTypes();
|
||||
Set<CardType> cardTypes = EnumSet.noneOf(CardType.class);
|
||||
cardTypes.addAll(card.getCardTypes());
|
||||
for (CardType cardType : cardTypes) {
|
||||
cardTypesPresent.add(cardType.toString());
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class NewPlayerPanel extends javax.swing.JPanel {
|
|||
this.txtPlayerName.setEditable(false);
|
||||
this.txtPlayerName.setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
protected void playerLoadDeck() {
|
||||
String lastFolder = MageFrame.getPreferences().get("lastDeckFolder", "");
|
||||
if (!lastFolder.isEmpty()) {
|
||||
|
|
|
@ -126,7 +126,9 @@ public class TablePlayerPanel extends javax.swing.JPanel {
|
|||
private void cbPlayerTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPlayerTypeActionPerformed
|
||||
if (getPlayerType() != PlayerType.HUMAN) {
|
||||
this.newPlayerPanel.setVisible(true);
|
||||
} else {
|
||||
this.newPlayerPanel.setPlayerName("Computer " + this.lblPlayerNum.getText().charAt(this.lblPlayerNum.getText().length() - 1));
|
||||
}
|
||||
else {
|
||||
this.newPlayerPanel.setVisible(false);
|
||||
}
|
||||
this.revalidate();
|
||||
|
|
|
@ -15,16 +15,10 @@ public class CardViewRarityComparator implements Comparator<CardView> {
|
|||
Rarity r1 = o1.getRarity();
|
||||
Rarity r2 = o2.getRarity();
|
||||
|
||||
int val = Integer.compare(
|
||||
return Integer.compare(
|
||||
r1 == null ? 0 : r1.getSorting(),
|
||||
r2 == null ? 0 : r2.getSorting()
|
||||
);
|
||||
|
||||
if (val == 0) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -14,9 +14,8 @@ import org.mage.card.arcane.UI;
|
|||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.*;
|
||||
|
||||
import static mage.client.dialog.PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE;
|
||||
|
||||
|
@ -344,6 +343,9 @@ public final class GuiDisplayUtil {
|
|||
}
|
||||
buffer.append("</td></tr></table>");
|
||||
|
||||
// split card rules shows up by parts, so no needs to duplicate it later (only dynamic abilities must be shown)
|
||||
Set<String> duplicatedRules = new HashSet<>();
|
||||
|
||||
StringBuilder rule = new StringBuilder("<br/>");
|
||||
if (card.isSplitCard()) {
|
||||
rule.append("<table cellspacing=0 cellpadding=0 border=0 width='100%'>");
|
||||
|
@ -356,7 +358,9 @@ public final class GuiDisplayUtil {
|
|||
rule.append("</td></tr></table>");
|
||||
for (String ruling : card.getLeftSplitRules()) {
|
||||
if (ruling != null && !ruling.replace(".", "").trim().isEmpty()) {
|
||||
rule.append("<p style='margin: 2px'>").append(ruling).append("</p>");
|
||||
// split names must be replaced
|
||||
duplicatedRules.add(ruling);
|
||||
rule.append("<p style='margin: 2px'>").append(replaceNamesInRule(ruling, card.getLeftSplitName())).append("</p>");
|
||||
}
|
||||
}
|
||||
rule.append("<table cellspacing=0 cellpadding=0 border=0 width='100%'>");
|
||||
|
@ -369,13 +373,18 @@ public final class GuiDisplayUtil {
|
|||
rule.append("</td></tr></table>");
|
||||
for (String ruling : card.getRightSplitRules()) {
|
||||
if (ruling != null && !ruling.replace(".", "").trim().isEmpty()) {
|
||||
rule.append("<p style='margin: 2px'>").append(ruling).append("</p>");
|
||||
// split names must be replaced
|
||||
duplicatedRules.add(ruling);
|
||||
rule.append("<p style='margin: 2px'>").append(replaceNamesInRule(ruling, card.getRightSplitName())).append("</p>");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!textLines.getLines().isEmpty()) {
|
||||
for (String textLine : textLines.getLines()) {
|
||||
if (textLine != null && !textLine.replace(".", "").trim().isEmpty()) {
|
||||
if (duplicatedRules.contains(textLine)) {
|
||||
continue;
|
||||
}
|
||||
rule.append("<p style='margin: 2px'>").append(textLine).append("</p>");
|
||||
}
|
||||
}
|
||||
|
@ -383,8 +392,7 @@ public final class GuiDisplayUtil {
|
|||
|
||||
String legal = rule.toString();
|
||||
if (!legal.isEmpty()) {
|
||||
legal = legal.replaceAll("\\{this\\}", card.getName().isEmpty() ? "this" : card.getName());
|
||||
legal = legal.replaceAll("\\{source\\}", card.getName().isEmpty() ? "this" : card.getName());
|
||||
legal = replaceNamesInRule(legal, card.getDisplayName()); // must show real display name (e.g. split part, not original card)
|
||||
buffer.append(ManaSymbols.replaceSymbolsWithHTML(legal, ManaSymbols.Type.TOOLTIP));
|
||||
}
|
||||
|
||||
|
@ -397,6 +405,12 @@ public final class GuiDisplayUtil {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
private static String replaceNamesInRule(String rule, String cardName) {
|
||||
String res = rule.replaceAll("\\{this\\}", cardName.isEmpty() ? "this" : cardName);
|
||||
res = res.replaceAll("\\{source\\}", cardName.isEmpty() ? "this" : cardName);
|
||||
return res;
|
||||
}
|
||||
|
||||
private static String getResourcePath(String image) {
|
||||
return GuiDisplayUtil.class.getClassLoader().getResource(image).toString();
|
||||
}
|
||||
|
|
|
@ -154,6 +154,7 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
sb.append(this.view.getToughness());
|
||||
sb.append(this.view.getLoyalty());
|
||||
sb.append(this.view.getColor().toString());
|
||||
sb.append(this.view.getType());
|
||||
sb.append(this.view.getExpansionSetCode());
|
||||
for (CardType type : this.view.getCardTypes()) {
|
||||
sb.append((char) type.ordinal());
|
||||
|
@ -227,7 +228,7 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
private BufferedImage faceArtImage;
|
||||
|
||||
// Factory to generate card appropriate views
|
||||
private CardRendererFactory cardRendererFactory = new CardRendererFactory();
|
||||
private final CardRendererFactory cardRendererFactory = new CardRendererFactory();
|
||||
|
||||
// The rendered card image, with or without the art image loaded yet
|
||||
// = null while invalid
|
||||
|
|
|
@ -140,13 +140,30 @@ public abstract class CardRenderer {
|
|||
break;
|
||||
}
|
||||
|
||||
// workaround to use real split card names
|
||||
String realCardName = cardView.getDisplayName();
|
||||
if (cardView.isSplitCard()) {
|
||||
for (String partRule : cardView.getLeftSplitRules()) {
|
||||
if (partRule.equals(rule)) {
|
||||
realCardName = cardView.getLeftSplitName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (String partRule : cardView.getRightSplitRules()) {
|
||||
if (partRule.equals(rule)) {
|
||||
realCardName = cardView.getRightSplitName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kill reminder text
|
||||
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_REMINDER_TEXT, "false").equals("false")) {
|
||||
rule = CardRendererUtils.killReminderText(rule).trim();
|
||||
}
|
||||
|
||||
if (!rule.isEmpty()) {
|
||||
TextboxRule tbRule = TextboxRuleParser.parse(cardView, rule);
|
||||
TextboxRule tbRule = TextboxRuleParser.parse(cardView, rule, realCardName);
|
||||
if (tbRule.type == TextboxRuleType.SIMPLE_KEYWORD) {
|
||||
keywords.add(tbRule);
|
||||
} else if (tbRule.text.isEmpty()) {
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.mage.card.arcane;
|
|||
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.font.GraphicAttribute;
|
||||
import java.awt.font.ImageGraphicAttribute;
|
||||
import java.awt.font.TextAttribute;
|
||||
|
@ -47,6 +48,25 @@ public class TextboxRule {
|
|||
}
|
||||
}
|
||||
|
||||
public static class ColorRegion implements AttributeRegion {
|
||||
|
||||
ColorRegion(int start, int end, Paint color) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.color = color;
|
||||
}
|
||||
private final int start;
|
||||
private final int end;
|
||||
private final Paint color;
|
||||
|
||||
@Override
|
||||
public void applyToAttributedString(AttributedString str, Font normal, Font italic) {
|
||||
if (end > start + 1) {
|
||||
str.addAttribute(TextAttribute.FOREGROUND, color, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A special symbol embedded at some point in a string
|
||||
public static class EmbeddedSymbol implements AttributeRegion {
|
||||
|
||||
|
|
|
@ -23,13 +23,14 @@ public final class TextboxRuleParser {
|
|||
private static final Pattern LevelAbilityPattern = Pattern.compile("Level (\\d+)-?(\\d*)(\\+?)");
|
||||
private static final Pattern LoyaltyAbilityPattern = Pattern.compile("^(\\+|\\-)(\\d+|X): ");
|
||||
private static final Pattern SimpleKeywordPattern = Pattern.compile("^(\\w+( \\w+)?)\\s*(\\([^\\)]*\\))?\\s*$");
|
||||
private static final Pattern FontColorValuePattern = Pattern.compile("color\\s*=\\s*[\"'](\\w+)[\"']");
|
||||
|
||||
// Parse a given rule (given as a string) into a TextboxRule, replacing
|
||||
// symbol annotations, italics, etc, parsing out information such as
|
||||
// if the ability is a loyalty ability, and returning an TextboxRule
|
||||
// representing that information, which can be used to render the rule in
|
||||
// the textbox of a card.
|
||||
public static TextboxRule parse(CardView source, String rule) {
|
||||
public static TextboxRule parse(CardView source, String rule, String cardNameToUse) {
|
||||
// List of regions to apply
|
||||
List<TextboxRule.AttributeRegion> regions = new ArrayList<>();
|
||||
|
||||
|
@ -103,10 +104,9 @@ public final class TextboxRuleParser {
|
|||
String contents = rule.substring(index + 1, closeIndex);
|
||||
if (contents.equals("this") || contents.equals("source")) {
|
||||
// Replace {this} with the card's name
|
||||
String cardName = source.getName();
|
||||
build.append(cardName);
|
||||
build.append(cardNameToUse);
|
||||
index += contents.length() + 2;
|
||||
outputIndex += cardName.length();
|
||||
outputIndex += cardNameToUse.length();
|
||||
} else {
|
||||
Image symbol = ManaSymbols.getSizedManaSymbol(contents.replace("/", ""), 10);
|
||||
if (symbol != null) {
|
||||
|
@ -200,6 +200,11 @@ public final class TextboxRuleParser {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case "/font":
|
||||
// Font it is an additional info of a card
|
||||
// lets make it blue like it is in tooltip
|
||||
regions.add(new TextboxRule.ColorRegion(openingIndex, outputIndex, Color.BLUE));
|
||||
break;
|
||||
default:
|
||||
// Unknown
|
||||
build.append('<').append(tag).append('>');
|
||||
|
|
|
@ -18,14 +18,13 @@ public enum GrabbagImageSource implements CardImageSource {
|
|||
|
||||
private static final Set<String> supportedSets = new LinkedHashSet<String>() {
|
||||
{
|
||||
add("PTC");
|
||||
add("SWS");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
return "";
|
||||
return "Grabbag";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,16 +75,6 @@ public enum GrabbagImageSource implements CardImageSource {
|
|||
return;
|
||||
}
|
||||
singleLinks = new HashMap<>();
|
||||
singleLinks.put("PTC/Arbiter of the Ideal", "MTG/BNG/en/promo/ArbiterOfTheIdeal.jpg");
|
||||
singleLinks.put("PTC/Courser of Kruphix", "MTG/BNG/en/promo/CourserOfKruphix.jpg");
|
||||
singleLinks.put("PTC/Eater of Hope", "MTG/BNG/en/promo/EaterOfHope.jpg");
|
||||
singleLinks.put("PTC/Fated Return", "MTG/BNG/en/promo/FatedReturn.jpg");
|
||||
singleLinks.put("PTC/Forgestoker Dragon", "MTG/BNG/en/promo/ForgestokerDragon.jpg");
|
||||
singleLinks.put("PTC/Nessian Wilds Ravager", "MTG/BNG/en/promo/NessianWildsRavager.jpg");
|
||||
singleLinks.put("PTC/Pain Seer", "MTG/BNG/en/promo/PainSeer.jpg");
|
||||
singleLinks.put("PTC/Silent Sentinel", "MTG/BNG/en/promo/SilentSentinel.jpg");
|
||||
singleLinks.put("PTC/Tromokratis", "MTG/BNG/en/promo/Tromokratis.jpg");
|
||||
|
||||
singleLinks.put("SWS/AAT-1", "CqmDY8V.jpg");
|
||||
singleLinks.put("SWS/Acklay of the Arena", "ESVRm6F.jpg");
|
||||
singleLinks.put("SWS/Acquire Target", "FOskB4q.jpg");
|
||||
|
@ -478,7 +467,7 @@ public enum GrabbagImageSource implements CardImageSource {
|
|||
if (card.getSet().equals("MTG")) {
|
||||
return "http://static.starcitygames.com/sales/cardscans/";
|
||||
} else if (card.getSet().equals("SWS")) {
|
||||
return "http://i.imgur.com/";
|
||||
return "https://i.imgur.com/";
|
||||
} else {
|
||||
return "http://magiccards.info/scans/en/";
|
||||
}
|
||||
|
|
|
@ -260,6 +260,8 @@ public class ScryfallImageSupportCards {
|
|||
add("PPP1");
|
||||
add("PF19");
|
||||
add("MPS-AKH");
|
||||
add("M21");
|
||||
add("JMP");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -94,16 +94,33 @@ public class ScryfallImageSupportTokens {
|
|||
put("HOU/Insect", "https://api.scryfall.com/cards/thou/12/en?format=image");
|
||||
put("HOU/Snake", "https://api.scryfall.com/cards/thou/11/en?format=image");
|
||||
|
||||
//AKH
|
||||
//AKH - tokens
|
||||
put("AKH/Beast", "https://api.scryfall.com/cards/takh/21/en?format=image");
|
||||
put("AKH/Cat", "https://api.scryfall.com/cards/takh/16/en?format=image");
|
||||
put("AKH/Drake", "https://api.scryfall.com/cards/takh/18/en?format=image");
|
||||
put("AKH/Emblem Gideon", "https://api.scryfall.com/cards/takh/25/en?format=image");
|
||||
put("AKH/Hippo", "https://api.scryfall.com/cards/takh/22/en?format=image");
|
||||
put("AKH/Insect", "https://api.scryfall.com/cards/takh/19/en?format=image");
|
||||
put("AKH/Snake", "https://api.scryfall.com/cards/takh/23/en?format=image");
|
||||
put("AKH/Warrior", "https://api.scryfall.com/cards/takh/17/en?format=image");
|
||||
put("AKH/Wurm", "https://api.scryfall.com/cards/takh/24/en?format=image");
|
||||
put("AKH/Zombie", "https://api.scryfall.com/cards/takh/20/en?format=image");
|
||||
//AKH - embalm ability (token from card)
|
||||
put("AKH/Angel of Sanctions", "https://api.scryfall.com/cards/takh/1/en?format=image");
|
||||
put("AKH/Anointer Priest", "https://api.scryfall.com/cards/takh/2/en?format=image");
|
||||
put("AKH/Aven Initiate", "https://api.scryfall.com/cards/takh/3/en?format=image");
|
||||
put("AKH/Aven Wind Guide", "https://api.scryfall.com/cards/takh/4/en?format=image");
|
||||
put("AKH/Glyph Keeper", "https://api.scryfall.com/cards/takh/5/en?format=image");
|
||||
put("AKH/Heart-Piercer Manticore", "https://api.scryfall.com/cards/takh/6/en?format=image");
|
||||
put("AKH/Honored Hydra", "https://api.scryfall.com/cards/takh/7/en?format=image");
|
||||
put("AKH/Labyrinth Guardian", "https://api.scryfall.com/cards/takh/8/en?format=image");
|
||||
put("AKH/Oketra's Attendant", "https://api.scryfall.com/cards/takh/9/en?format=image");
|
||||
put("AKH/Sacred Cat", "https://api.scryfall.com/cards/takh/10/en?format=image");
|
||||
put("AKH/Tah-Crop Skirmisher", "https://api.scryfall.com/cards/takh/11/en?format=image");
|
||||
put("AKH/Temmet, Vizier of Naktamun", "https://api.scryfall.com/cards/takh/12/en?format=image");
|
||||
put("AKH/Trueheart Duelist", "https://api.scryfall.com/cards/takh/13/en?format=image");
|
||||
put("AKH/Unwavering Initiate", "https://api.scryfall.com/cards/takh/14/en?format=image");
|
||||
put("AKH/Vizier of Many Faces", "https://api.scryfall.com/cards/takh/15/en?format=image");
|
||||
|
||||
//AER
|
||||
put("AER/Etherium Cell", "https://api.scryfall.com/cards/taer/3/en?format=image");
|
||||
|
@ -350,6 +367,20 @@ public class ScryfallImageSupportTokens {
|
|||
put("THB/Wolf", "https://api.scryfall.com/cards/tthb/11/en?format=image");
|
||||
put("THB/Zombie", "https://api.scryfall.com/cards/tthb/7/en?format=image");
|
||||
|
||||
// IKO
|
||||
put("IKO/Emblem Narset Of The Ancient Way", "https://api.scryfall.com/cards/tiko/12/en?format=image");
|
||||
put("IKO/Beast", "https://api.scryfall.com/cards/tiko/10/en?format=image");
|
||||
put("IKO/Cat Bird", "https://api.scryfall.com/cards/tiko/2/en?format=image");
|
||||
put("IKO/Cat", "https://api.scryfall.com/cards/tiko/1/en?format=image");
|
||||
put("IKO/Dinosaur Beast", "https://api.scryfall.com/cards/tiko/11/en?format=image");
|
||||
put("IKO/Dinosaur", "https://api.scryfall.com/cards/tiko/8/en?format=image");
|
||||
put("IKO/Feather", "https://api.scryfall.com/cards/tiko/9/en?format=image");
|
||||
put("IKO/Human Soldier/1", "https://api.scryfall.com/cards/tiko/3/en?format=image");
|
||||
put("IKO/Human Soldier/2", "https://api.scryfall.com/cards/tiko/4/en?format=image");
|
||||
put("IKO/Human Soldier/3", "https://api.scryfall.com/cards/tiko/5/en?format=image");
|
||||
put("IKO/Kraken", "https://api.scryfall.com/cards/tiko/6/en?format=image");
|
||||
put("IKO/Shark", "https://api.scryfall.com/cards/tiko/7/en?format=image");
|
||||
|
||||
// PCA (planes)
|
||||
put("PCA/Eldrazi", "https://api.scryfall.com/cards/tpca/1/en?format=image");
|
||||
put("PCA/Plane - Academy at Tolaria West", "https://api.scryfall.com/cards/opca/9/en?format=image");
|
||||
|
@ -374,6 +405,27 @@ public class ScryfallImageSupportTokens {
|
|||
put("PCA/Plane - Turri Island", "https://api.scryfall.com/cards/opca/82/en?format=image");
|
||||
put("PCA/Plane - Undercity Reaches", "https://api.scryfall.com/cards/opca/83/en?format=image");
|
||||
|
||||
// C20
|
||||
put("C20/Angel", "https://api.scryfall.com/cards/tc20/1/en?format=image");
|
||||
put("C20/Beast", "https://api.scryfall.com/cards/tc20/11/en?format=image");
|
||||
put("C20/Bird Illusion", "https://api.scryfall.com/cards/tc20/7/en?format=image");
|
||||
put("C20/Bird", "https://api.scryfall.com/cards/tc20/2/en?format=image");
|
||||
put("C20/Dinosaur Cat", "https://api.scryfall.com/cards/tc20/16/en?format=image");
|
||||
put("C20/Drake", "https://api.scryfall.com/cards/tc20/8/en?format=image");
|
||||
put("C20/Elemental/1", "https://api.scryfall.com/cards/tc20/10/en?format=image"); // 3/1
|
||||
put("C20/Elemental/2", "https://api.scryfall.com/cards/tc20/3/en?format=image"); // 4/4
|
||||
put("C20/Goblin Warrior", "https://api.scryfall.com/cards/tc20/17/en?format=image");
|
||||
put("C20/Human", "https://api.scryfall.com/cards/tc20/4/en?format=image");
|
||||
put("C20/Hydra", "https://api.scryfall.com/cards/tc20/12/en?format=image");
|
||||
put("C20/Insect/1", "https://api.scryfall.com/cards/tc20/13/en?format=image"); // deathtouch
|
||||
put("C20/Insect/2", "https://api.scryfall.com/cards/tc20/18/en?format=image"); // haste
|
||||
put("C20/Saproling", "https://api.scryfall.com/cards/tc20/14/en?format=image");
|
||||
put("C20/Snake", "https://api.scryfall.com/cards/tc20/15/en?format=image");
|
||||
put("C20/Soldier", "https://api.scryfall.com/cards/tc20/5/en?format=image");
|
||||
put("C20/Spirit", "https://api.scryfall.com/cards/tc20/6/en?format=image");
|
||||
put("C20/Treasure", "https://api.scryfall.com/cards/tc20/19/en?format=image");
|
||||
put("C20/Zombie", "https://api.scryfall.com/cards/tc20/9/en?format=image");
|
||||
|
||||
// generate supported sets
|
||||
supportedSets.clear();
|
||||
for (String cardName : this.keySet()) {
|
||||
|
|
|
@ -47,7 +47,7 @@ public final class ImageCache {
|
|||
private static final SoftValuesLoadingCache<String, BufferedImage> FACE_IMAGE_CACHE;
|
||||
|
||||
/**
|
||||
* Common pattern for keys. Format: "<cardname>#<setname>#<collectorID>"
|
||||
* Common pattern for keys. See ImageCache.getKey for structure info
|
||||
*/
|
||||
private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)#(.*)");
|
||||
|
||||
|
@ -84,13 +84,21 @@ public final class ImageCache {
|
|||
|
||||
boolean cardback = false;
|
||||
String path;
|
||||
if (collectorId.isEmpty() || "0".equals(collectorId)) {
|
||||
if (collectorId.isEmpty() || "0".equals(collectorId) || !tokenDescriptor.isEmpty()) { // tokenDescriptor for embalm ability
|
||||
info.setToken(true);
|
||||
path = CardImageUtils.generateTokenImagePath(info);
|
||||
if (path == null) {
|
||||
cardback = true;
|
||||
// TODO: replace empty token by other default card, not cardback
|
||||
path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
|
||||
// try token image from card
|
||||
CardDownloadData newInfo = new CardDownloadData(info);
|
||||
newInfo.setToken(false);
|
||||
path = CardImageUtils.buildImagePathToCard(newInfo);
|
||||
TFile tokenFile = getTFile(path);
|
||||
if (tokenFile == null || !tokenFile.exists()) {
|
||||
// token empty token image
|
||||
// TODO: replace empty token by other default card, not cardback
|
||||
path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
path = CardImageUtils.buildImagePathToCard(info);
|
||||
|
@ -245,12 +253,20 @@ public final class ImageCache {
|
|||
CardDownloadData info = new CardDownloadData(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor);
|
||||
|
||||
String path;
|
||||
if (collectorId.isEmpty() || "0".equals(collectorId)) {
|
||||
if (collectorId.isEmpty() || "0".equals(collectorId) || !tokenDescriptor.isEmpty()) { // tokenDescriptor for embalm ability
|
||||
info.setToken(true);
|
||||
path = CardImageUtils.generateFullTokenImagePath(info);
|
||||
path = CardImageUtils.generateTokenImagePath(info);
|
||||
if (path == null) {
|
||||
// TODO: replace empty token by other default card, not cardback
|
||||
path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
|
||||
// try token image from card
|
||||
CardDownloadData newInfo = new CardDownloadData(info);
|
||||
newInfo.setToken(false);
|
||||
path = CardImageUtils.buildImagePathToCard(newInfo);
|
||||
TFile tokenFile = getTFile(path);
|
||||
if (tokenFile == null || !tokenFile.exists()) {
|
||||
// token empty token image
|
||||
// TODO: replace empty token by other default card, not cardback
|
||||
path = CardImageUtils.buildImagePathToDefault(DirectLinksForDownload.cardbackFilename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
path = CardImageUtils.buildImagePathToCard(info);
|
||||
|
@ -428,11 +444,14 @@ public final class ImageCache {
|
|||
* Returns the map key for a card, without any suffixes for the image size.
|
||||
*/
|
||||
private static String getKey(CardView card, String name, String suffix) {
|
||||
return name + '#' + card.getExpansionSetCode() + '#' + card.getType() + '#' + card.getCardNumber() + '#'
|
||||
+ (card.getTokenSetCode() == null ? "" : card.getTokenSetCode())
|
||||
return name
|
||||
+ '#' + card.getExpansionSetCode()
|
||||
+ '#' + card.getType()
|
||||
+ '#' + card.getCardNumber()
|
||||
+ '#' + (card.getTokenSetCode() == null ? "" : card.getTokenSetCode())
|
||||
+ suffix
|
||||
+ (card.getUsesVariousArt() ? "#usesVariousArt" : "")
|
||||
+ (card.getTokenDescriptor() != null ? '#' + card.getTokenDescriptor() : "#");
|
||||
+ '#' + (card.getTokenDescriptor() != null ? card.getTokenDescriptor() : "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
|Generate|EMBLEM:DOM|Teferi, Hero of Dominaria||Emblem Teferi|TeferiHeroOfDominariaEmblem|
|
||||
|Generate|EMBLEM:AER|Tezzeret the Schemer||Emblem Tezzeret|TezzeretTheSchemerEmblem|
|
||||
|Generate|EMBLEM:ELD|Garruk, Cursed Huntsman||Emblem Garruk|GarrukCursedHuntsmanEmblem|
|
||||
|Generate|EMBLEM:IKO|Narset Of The Ancient Way||Emblem Narset|NarsetOfTheAncientWayEmblem|
|
||||
|Generate|PLANE:PCA|Plane - Academy at Tolaria West|||AcademyAtTolariaWestPlane|
|
||||
|Generate|PLANE:PCA|Plane - Agyrem|||AgyremPlane|
|
||||
|Generate|PLANE:PCA|Plane - Akoum|||AkoumPlane|
|
||||
|
@ -153,7 +154,7 @@
|
|||
|Generate|TOK:5ED|Serf|||SerfToken|
|
||||
|Generate|TOK:5ED|Snake|||SerpentGeneratorSnakeToken|
|
||||
|Generate|TOK:5ED|Thrull|||BreedingPitBlackInsectToken|
|
||||
|Generate|TOK:6ED|Cat|||WaitingInTheWeedsCatToken|
|
||||
|Generate|TOK:6ED|Cat|||GreenCatToken|
|
||||
|Generate|TOK:6ED|Citizen|||CitizenToken|
|
||||
|Generate|TOK:6ED|Djinn|||DjinnToken|
|
||||
|Generate|TOK:6ED|Goblin|||GoblinToken|
|
||||
|
@ -167,30 +168,34 @@
|
|||
|Generate|TOK:AER|Etherium Cell|||EtheriumCellToken|
|
||||
|Generate|TOK:AER|Gremlin|||GremlinToken|
|
||||
|Generate|TOK:AER|Ragavan|||RagavanToken|
|
||||
|
||||
# AKH
|
||||
|Generate|TOK:AKH|Beast|||BeastToken3|
|
||||
|Generate|TOK:AKH|Cat|||CatToken2|
|
||||
|Generate|TOK:AKH|Drake|||DrakeToken|
|
||||
|Generate|TOK:AKH|Hippo|||HippoToken2|
|
||||
|Generate|TOK:AKH|Insect|||NestOfScarabsBlackInsectToken|
|
||||
|Generate|TOK:AKH|Snake|||DeathtouchSnakeToken|
|
||||
|Generate|TOK:AKH|Warrior|||WarriorVigilantToken|
|
||||
|Generate|TOK:AKH|Wurm|||WurmToken3|
|
||||
|Generate|TOK:AKH|Zombie|||ZombieToken
|
||||
|Generate|TOK:AKH|Wurm|||Wurm55Token|
|
||||
|Generate|TOK:AKH|Zombie|||ZombieToken|
|
||||
#TOK:AKH - some tokens from real cards (see Embalm ability)
|
||||
#|Generate|TOK:AKH|Angel of Sanctions||
|
||||
#|Generate|TOK:AKH|Anointer Priest||
|
||||
#|Generate|TOK:AKH|Aven Initiate||
|
||||
#|Generate|TOK:AKH|Aven Wind Guide||
|
||||
#|Generate|TOK:AKH|Glyph Keeper||
|
||||
#|Generate|TOK:AKH|Heart-Piercer Manticore||
|
||||
#|Generate|TOK:AKH|Honored Hydra||
|
||||
#|Generate|TOK:AKH|Labyrinth Guardian||
|
||||
#|Generate|TOK:AKH|Oketra's Attendant||
|
||||
#|Generate|TOK:AKH|Sacred Cat||
|
||||
#|Generate|TOK:AKH|Tah-Crop Skirmisher||
|
||||
#|Generate|TOK:AKH|Temmet, Vizier of Naktamun||
|
||||
#|Generate|TOK:AKH|Trueheart Duelist||
|
||||
#|Generate|TOK:AKH|Unwavering Initiate||
|
||||
#|Generate|TOK:AKH|Vizier of Many Faces||
|
||||
|Generate|TOK:AKH|Angel of Sanctions||
|
||||
|Generate|TOK:AKH|Anointer Priest||
|
||||
|Generate|TOK:AKH|Aven Initiate||
|
||||
|Generate|TOK:AKH|Aven Wind Guide||
|
||||
|Generate|TOK:AKH|Glyph Keeper||
|
||||
|Generate|TOK:AKH|Heart-Piercer Manticore||
|
||||
|Generate|TOK:AKH|Honored Hydra||
|
||||
|Generate|TOK:AKH|Labyrinth Guardian||
|
||||
|Generate|TOK:AKH|Oketra's Attendant||
|
||||
|Generate|TOK:AKH|Sacred Cat||
|
||||
|Generate|TOK:AKH|Tah-Crop Skirmisher||
|
||||
|Generate|TOK:AKH|Temmet, Vizier of Naktamun||
|
||||
|Generate|TOK:AKH|Trueheart Duelist||
|
||||
|Generate|TOK:AKH|Unwavering Initiate||
|
||||
|Generate|TOK:AKH|Vizier of Many Faces||
|
||||
|
||||
|Generate|TOK:ALA|Beast|||GodSireBeastToken|
|
||||
|Generate|TOK:ALA|Dragon|||DragonToken|
|
||||
|Generate|TOK:ALA|Goblin|||GoblinTokenWithHaste|
|
||||
|
@ -269,9 +274,9 @@
|
|||
|Generate|TOK:C13|Beast|||OneDozenEyesBeastToken|
|
||||
|Generate|TOK:C13|Beast|||SpawningGroundsBeastToken|
|
||||
|Generate|TOK:C13|Drake|||LeafdrakeRoostDrakeToken|
|
||||
|Generate|TOK:C13|Elemental|||SeedGuardianToken|
|
||||
|Generate|TOK:C13|Elemental|||WalkerOfTheGroveToken|
|
||||
|Generate|TOK:C13|Elemental|||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:C13|Elemental|1||SeedGuardianToken|
|
||||
|Generate|TOK:C13|Elemental|2||WalkerOfTheGroveToken|
|
||||
|Generate|TOK:C13|Elemental|3||RedElementalToken|
|
||||
|Generate|TOK:C13|Elephant|||ElephantToken|
|
||||
|Generate|TOK:C13|Elf Warrior|||ElfToken|
|
||||
|Generate|TOK:C13|Goat|||GoatToken|
|
||||
|
@ -318,8 +323,8 @@
|
|||
|Generate|TOK:C14|Treefolk|||SylvanOfferingTreefolkToken|
|
||||
|Generate|TOK:C14|Whale|||ReefWormWhaleToken|
|
||||
|Generate|TOK:C14|Wolf|||WolfToken|
|
||||
|Generate|TOK:C14|Wurm|1||Wurm1Token|
|
||||
|Generate|TOK:C14|Wurm|2||Wurm2Token|
|
||||
|Generate|TOK:C14|Wurm|1||WurmWithDeathtouchToken|
|
||||
|Generate|TOK:C14|Wurm|2||WurmWithLifelinkToken|
|
||||
|Generate|TOK:C14|Zombie|1||ZombieToken|
|
||||
|Generate|TOK:C14|Zombie|2||StitcherGeralfZombieToken|
|
||||
|Generate|TOK:C15|Angel|||AngelToken|
|
||||
|
@ -350,7 +355,7 @@
|
|||
|Generate|TOK:C16|Beast||
|
||||
|Generate|TOK:C16|Bird|1|
|
||||
|Generate|TOK:C16|Bird|2|
|
||||
|Generate|TOK:C16|Elemental||
|
||||
|Generate|TOK:C16|Elemental|||WhiteElementalToken|
|
||||
|Generate|TOK:C16|Elf Warrior||
|
||||
|Generate|TOK:C16|Germ||
|
||||
|Generate|TOK:C16|Goat||
|
||||
|
@ -368,7 +373,7 @@
|
|||
|Generate|TOK:C16|Worm||
|
||||
|Generate|TOK:C16|Zombie||
|
||||
|Generate|TOK:C17|Bat||
|
||||
|Generate|TOK:C17|Cat||
|
||||
|Generate|TOK:C17|Cat|||CatToken|
|
||||
|Generate|TOK:C17|Cat Dragon|||WasitoraCatDragonToken|
|
||||
|Generate|TOK:C17|Cat Warrior||
|
||||
|Generate|TOK:C17|Dragon|1||DragonToken|
|
||||
|
@ -566,11 +571,11 @@
|
|||
|Generate|TOK:DGM|Rhino|||RhinoToken|
|
||||
|Generate|TOK:DGM|Soldier|||SoldierTokenWithHaste|
|
||||
|Generate|TOK:DGM|Spirit|||TeysaEnvoyOfGhostsToken|
|
||||
|Generate|TOK:DGM|Wurm|||WurmToken2|
|
||||
|Generate|TOK:DGM|Wurm|||WurmToken3|
|
||||
|Generate|TOK:DGM|Wurm|1||WurmWithTrampleToken|
|
||||
|Generate|TOK:DGM|Wurm|2||Wurm55Token|
|
||||
|Generate|TOK:DIS|Bird|||DovescapeToken|
|
||||
|Generate|TOK:DIS|Drake|||LeafdrakeRoostDrakeToken|
|
||||
|Generate|TOK:DIS|Elemental|||ElementalToken|
|
||||
|Generate|TOK:DIS|Elemental|||ResearchDevelopmentToken|
|
||||
|Generate|TOK:DIS|Goblin|||RakdosGuildmageGoblinToken|
|
||||
|Generate|TOK:DIS|Saproling|||SaprolingToken|
|
||||
|Generate|TOK:DIS|Snake|||PatagiaViperSnakeToken|
|
||||
|
@ -618,7 +623,7 @@
|
|||
|Generate|TOK:EMA|Beast|||CarnivoreToken|
|
||||
|Generate|TOK:EMA|Carnivore||
|
||||
|Generate|TOK:EMA|Dragon|||DragonEggDragonToken|
|
||||
|Generate|TOK:EMA|Elemental|1||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:EMA|Elemental|1||RedElementalToken|
|
||||
|Generate|TOK:EMA|Elemental|2||CallTheSkyBreakerElementalToken|
|
||||
|Generate|TOK:EMA|Elephant|||ElephantToken|
|
||||
|Generate|TOK:EMA|Elf Warrior|||ElfToken|
|
||||
|
@ -654,7 +659,7 @@
|
|||
|Generate|TOK:EVE|Spirit|||BeckonApparitionToken|
|
||||
|Generate|TOK:EVE|Wolf|||WolfToken|
|
||||
|Generate|TOK:EVE|Worm|||WormHarvestToken|
|
||||
|Generate|TOK:EVG|Elemental||
|
||||
|Generate|TOK:EVG|Elemental|||VoiceOfTheWoodsElementalToken|
|
||||
|Generate|TOK:EVG|Elf Warrior|||ElfToken|
|
||||
|Generate|TOK:EVG|Goblin|||GoblinToken|
|
||||
|Generate|TOK:EXO|Pegasus|||PegasusToken|
|
||||
|
@ -790,8 +795,8 @@
|
|||
|Generate|TOK:LRW|Avatar|||AvatarToken|
|
||||
|Generate|TOK:LRW|Beast|||BeastToken|
|
||||
|Generate|TOK:LRW|Elemental Shaman|||ElementalShamanToken|
|
||||
|Generate|TOK:LRW|Elemental|||WalkerOfTheGroveToken|
|
||||
|Generate|TOK:LRW|Elemental|||WhiteElementalToken|
|
||||
|Generate|TOK:LRW|Elemental|1||WalkerOfTheGroveToken|
|
||||
|Generate|TOK:LRW|Elemental|2||WhiteElementalToken|
|
||||
|Generate|TOK:LRW|Elf Warrior|||ElfToken|
|
||||
|Generate|TOK:LRW|Goblin Rogue|||GoblinRogueToken|
|
||||
|Generate|TOK:LRW|Kithkin Soldier|||KithkinToken|
|
||||
|
@ -833,8 +838,8 @@
|
|||
|Generate|TOK:M14|Beast|||BeastToken|
|
||||
|Generate|TOK:M14|Cat|||CatToken|
|
||||
|Generate|TOK:M14|Dragon|||DragonEggDragonToken|
|
||||
|Generate|TOK:M14|Elemental|1||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:M14|Elemental|2||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:M14|Elemental|1||RedElementalToken|
|
||||
|Generate|TOK:M14|Elemental|2||RedElementalToken|
|
||||
|Generate|TOK:M14|Goat|||GoatToken|
|
||||
|Generate|TOK:M14|Saproling|||SaprolingToken|
|
||||
|Generate|TOK:M14|Sliver||
|
||||
|
@ -908,7 +913,7 @@
|
|||
|Generate|TOK:MM3|Bird||
|
||||
|Generate|TOK:MM3|Centaur||
|
||||
|Generate|TOK:MM3|Dragon||
|
||||
|Generate|TOK:MM3|Elemental||
|
||||
|Generate|TOK:MM3|Elemental|||VoiceOfResurgenceToken|
|
||||
|Generate|TOK:MM3|Elephant||
|
||||
|Generate|TOK:MM3|Giant Warrior||
|
||||
|Generate|TOK:MM3|Goblin Warrior||
|
||||
|
@ -955,7 +960,7 @@
|
|||
|Generate|TOK:MOR|Wolf|||WolfToken|
|
||||
|Generate|TOK:MRD|Beast|||OneDozenEyesBeastToken|
|
||||
|Generate|TOK:MRD|Demon|||ReignOfThePitToken|
|
||||
|Generate|TOK:MRD|Elemental|||ElementalToken|
|
||||
|Generate|TOK:MRD|Elemental|||ElementalTokenWithHaste|
|
||||
|Generate|TOK:MRD|Insect|||InsectToken|
|
||||
|Generate|TOK:MRD|Myr|||MyrToken|
|
||||
|Generate|TOK:MRD|Pentavite|||PentaviteToken|
|
||||
|
@ -989,7 +994,7 @@
|
|||
|Generate|TOK:OGW|Eldrazi Scion|5||EldraziScionToken|
|
||||
|Generate|TOK:OGW|Eldrazi Scion|6||EldraziScionToken|
|
||||
|Generate|TOK:OGW|Elemental|1||SeedGuardianToken|
|
||||
|Generate|TOK:OGW|Elemental|2||ElementalToken|
|
||||
|Generate|TOK:OGW|Elemental|2||ElementalTokenWithHaste|
|
||||
|Generate|TOK:OGW|Knight Ally|||KnightAllyToken|
|
||||
|Generate|TOK:OGW|Kor Ally|||KorAllyToken|
|
||||
|Generate|TOK:OGW|Octopus|||OctopusToken|
|
||||
|
@ -1062,21 +1067,21 @@
|
|||
|Generate|TOK:RTR|Bird|||BirdToken|
|
||||
|Generate|TOK:RTR|Centaur|||CentaurToken|
|
||||
|Generate|TOK:RTR|Dragon|||UtvaraHellkiteDragonToken|
|
||||
|Generate|TOK:RTR|Elemental||
|
||||
|Generate|TOK:RTR|Elemental|||GreenAndWhiteElementalToken|
|
||||
|Generate|TOK:RTR|Goblin|||GoblinToken|
|
||||
|Generate|TOK:RTR|Knight|||KnightToken|
|
||||
|Generate|TOK:RTR|Ooze|||MysticGenesisOozeToken|
|
||||
|Generate|TOK:RTR|Rhino|||RhinoToken|
|
||||
|Generate|TOK:RTR|Saproling|||SaprolingToken|
|
||||
|Generate|TOK:RTR|Soldier|||SoldierToken|
|
||||
|Generate|TOK:RTR|Wurm|||WurmToken2|
|
||||
|Generate|TOK:RTR|Wurm|||WurmWithTrampleToken|
|
||||
|Generate|TOK:SCG|Angel|||AngelToken|
|
||||
|Generate|TOK:SCG|Beast|||BeastToken2|
|
||||
|Generate|TOK:SCG|Dragon|||DragonToken2|
|
||||
|Generate|TOK:SCG|Goblin|||GoblinToken|
|
||||
|Generate|TOK:SCG|Soldier|||SoldierToken|
|
||||
|Generate|TOK:SHM|Elemental|1||DinOfTheFireherdToken|
|
||||
|Generate|TOK:SHM|Elemental|2||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:SHM|Elemental|2||RedElementalToken|
|
||||
|Generate|TOK:SHM|Elf Warrior|1|
|
||||
|Generate|TOK:SHM|Elf Warrior|2|
|
||||
|Generate|TOK:SHM|Elf Warrior|||ElfToken|
|
||||
|
@ -1105,7 +1110,7 @@
|
|||
|Generate|TOK:SOI|Vampire Knight|||VampireKnightToken|
|
||||
|Generate|TOK:SOI|Wolf|||WolfToken|
|
||||
|Generate|TOK:SOI|Zombie|||ZombieToken|
|
||||
|Generate|TOK:SOK|Elemental|||ElementalToken|
|
||||
|Generate|TOK:SOK|Elemental|||ElementalTokenWithHaste|
|
||||
|Generate|TOK:SOK|Snake|||SnakeToken|
|
||||
|Generate|TOK:SOK|Spirit|||SpiritToken|
|
||||
|Generate|TOK:SOK|Urami|||UramiToken|
|
||||
|
@ -1117,8 +1122,8 @@
|
|||
|Generate|TOK:SOM|Myr|||MyrToken|
|
||||
|Generate|TOK:SOM|Soldier|||SoldierToken|
|
||||
|Generate|TOK:SOM|Wolf|||WolfToken|
|
||||
|Generate|TOK:SOM|Wurm|1||Wurm1Token|
|
||||
|Generate|TOK:SOM|Wurm|2||Wurm2Token|
|
||||
|Generate|TOK:SOM|Wurm|1||WurmWithDeathtouchToken|
|
||||
|Generate|TOK:SOM|Wurm|2||WurmWithLifelinkToken|
|
||||
|Generate|TOK:STH|Goblin|||GoblinToken|
|
||||
|Generate|TOK:STH|Insect|||HornetToken|
|
||||
|Generate|TOK:STH|Insect|||WaspToken|
|
||||
|
@ -1146,7 +1151,7 @@
|
|||
|Generate|TOK:THS|Soldier|1||SoldierToken|
|
||||
|Generate|TOK:THS|Soldier|2||SoldierToken|
|
||||
|Generate|TOK:TMP|Beast|||CarnivoreToken|
|
||||
|Generate|TOK:TMP|Hound|||HoundToken|
|
||||
|Generate|TOK:TMP|Dog|||GreenDogToken|
|
||||
|Generate|TOK:TMP|Pegasus|||PegasusToken|
|
||||
|Generate|TOK:TMP|Reflection|||ReflectionToken|
|
||||
|Generate|TOK:TMP|Saproling|||SaprolingToken|
|
||||
|
@ -1213,8 +1218,8 @@
|
|||
|Generate|TOK:VMA|Spirit|||SpiritWhiteToken|
|
||||
|Generate|TOK:VMA|Squirrel|||SquirrelToken|
|
||||
|Generate|TOK:VMA|Thopter|||ThopterColorlessToken|
|
||||
|Generate|TOK:VMA|Wurm|||PenumbraWurmToken|
|
||||
|Generate|TOK:VMA|Wurm|||WurmToken|
|
||||
|Generate|TOK:VMA|Wurm|1||PenumbraWurmToken|
|
||||
|Generate|TOK:VMA|Wurm|2||WurmToken|
|
||||
|Generate|TOK:VMA|Zombie|||ZombieToken|
|
||||
|Generate|TOK:WTH|Squirrel|||SquirrelToken|
|
||||
|Generate|TOK:WWK|Construct|||StoneTrapIdolToken|
|
||||
|
@ -1238,8 +1243,8 @@
|
|||
|Generate|TOK:ZEN|Angel|||AngelToken|
|
||||
|Generate|TOK:ZEN|Beast|||BeastToken2|
|
||||
|Generate|TOK:ZEN|Bird|||BirdToken|
|
||||
|Generate|TOK:ZEN|Elemental||
|
||||
|Generate|TOK:ZEN|Elemental|||ZektarShrineElementalToken|
|
||||
|Generate|TOK:ZEN|Elemental|1||RedElementalWithTrampleAndHaste|
|
||||
|Generate|TOK:ZEN|Elemental|2||RedElementalWithTrampleAndHaste|
|
||||
|Generate|TOK:ZEN|Illusion|||IllusionToken|
|
||||
|Generate|TOK:ZEN|Kor Soldier|||KorSoldierToken|
|
||||
|Generate|TOK:ZEN|Merfolk||
|
||||
|
@ -1268,6 +1273,7 @@
|
|||
|Generate|TOK:GRN|Soldier|||SoldierLifelinkToken|
|
||||
|Generate|TOK:WAR|Angel|||AngelVigilanceToken|
|
||||
|Generate|TOK:WAR|Assassin|||AssassinToken2|
|
||||
|Generate|TOK:WAR|Citizen|||PlanewideCelebrationToken|
|
||||
|Generate|TOK:WAR|Devil|||DevilToken|
|
||||
|Generate|TOK:WAR|Dragon|||DragonToken|
|
||||
|Generate|TOK:WAR|Goblin|||GoblinToken|
|
||||
|
@ -1288,7 +1294,7 @@
|
|||
|Generate|TOK:MH1|Bear|||BearToken|
|
||||
|Generate|TOK:MH1|Bird|||BirdToken|
|
||||
|Generate|TOK:MH1|Construct|||KarnConstructToken|
|
||||
|Generate|TOK:MH1|Elemental|1||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:MH1|Elemental|1||RedElementalToken|
|
||||
|Generate|TOK:MH1|Elemental|2||AkoumStonewakerElementalToken|
|
||||
|Generate|TOK:MH1|Elephant|||ElephantToken|
|
||||
|Generate|TOK:MH1|Goblin|||GoblinToken|
|
||||
|
@ -1318,7 +1324,7 @@
|
|||
|Generate|TOK:M19|Zombie|||ZombieToken|
|
||||
|Generate|TOK:M20|Ajani's Pridemate|||AjanisPridemateToken|
|
||||
|Generate|TOK:M20|Demon|||DemonToken|
|
||||
|Generate|TOK:M20|Elemental|||YoungPyromancerElementalToken|
|
||||
|Generate|TOK:M20|Elemental|||RedElementalToken|
|
||||
|Generate|TOK:M20|Elemental Bird|||MuYanlingSkyDancerToken|
|
||||
|Generate|TOK:M20|Golem|||GolemToken|
|
||||
|Generate|TOK:M20|Soldier|||SoldierToken|
|
||||
|
@ -1326,6 +1332,8 @@
|
|||
|Generate|TOK:M20|Treasure|||TreasureToken|
|
||||
|Generate|TOK:M20|Wolf|||WolfToken|
|
||||
|Generate|TOK:M20|Zombie|||ZombieToken|
|
||||
|
||||
# ELD
|
||||
|Generate|TOK:ELD|Bear|||BearToken|
|
||||
|Generate|TOK:ELD|Boar|||WolfsQuarryToken|
|
||||
|Generate|TOK:ELD|Dwarf|||DwarfToken|
|
||||
|
@ -1344,6 +1352,8 @@
|
|||
|Generate|TOK:ELD|Mouse|||MouseToken|
|
||||
|Generate|TOK:ELD|Rat|||RatToken|
|
||||
|Generate|TOK:ELD|Wolf|||GarrukCursedHuntsmanToken|
|
||||
|
||||
# THB
|
||||
|Generate|TOK:THB|Goat|||GoatToken|
|
||||
|Generate|TOK:THB|Human Soldier|||HumanSoldierToken|
|
||||
|Generate|TOK:THB|Pegasus|||PegasusToken2|
|
||||
|
@ -1356,5 +1366,42 @@
|
|||
|Generate|TOK:THB|Spider|||SpiderToken|
|
||||
|Generate|TOK:THB|Wolf|||WolfToken|
|
||||
|Generate|TOK:THB|Nightmare|||AshiokNightmareMuseToken|
|
||||
|Generate|TOK:THB|GoldToken|||Gold|
|
||||
|Generate|TOK:THB|ArtifactWallToken|||Wall|
|
||||
|Generate|TOK:THB|Gold|||GoldToken|
|
||||
|Generate|TOK:THB|Wall|||ArtifactWallToken|
|
||||
|
||||
# IKO
|
||||
|Generate|TOK:IKO|Beast|||BeastToken|
|
||||
|Generate|TOK:IKO|Cat Bird|||CatBirdToken|
|
||||
|Generate|TOK:IKO|Cat|||CatToken2|
|
||||
|Generate|TOK:IKO|Dinosaur Beast|||DinosaurBeastToken|
|
||||
|Generate|TOK:IKO|Dinosaur|||DinosaurHasteToken|
|
||||
|Generate|TOK:IKO|Feather|||FeatherToken|
|
||||
|Generate|TOK:IKO|Human Soldier|1||HumanSoldierToken|
|
||||
|Generate|TOK:IKO|Human Soldier|2||HumanSoldierToken|
|
||||
|Generate|TOK:IKO|Human Soldier|3||HumanSoldierToken|
|
||||
|Generate|TOK:IKO|Kraken|||KrakenToken|
|
||||
|Generate|TOK:IKO|Shark|||SharkToken|
|
||||
|
||||
# C20
|
||||
|Generate|TOK:C20|Angel|||AngelToken|
|
||||
|Generate|TOK:C20|Beast|||BeastToken2|
|
||||
|Generate|TOK:C20|Bird|||BirdToken|
|
||||
|Generate|TOK:C20|Bird Illusion|||BirdIllusionToken|
|
||||
|Generate|TOK:C20|Dinosaur Cat|||DinosaurCatToken|
|
||||
|Generate|TOK:C20|Drake|||DrakeToken|
|
||||
|Generate|TOK:C20|Elemental|1||ElementalTokenWithHaste|
|
||||
|Generate|TOK:C20|Elemental|2||WhiteElementalToken|
|
||||
|Generate|TOK:C20|Goblin Warrior|||GoblinWarriorToken|
|
||||
|Generate|TOK:C20|Human|||HumanToken|
|
||||
|Generate|TOK:C20|Hydra|||ZaxaraTheExemplaryHydraToken|
|
||||
|Generate|TOK:C20|Insect|1||HornetQueenInsectToken|
|
||||
|Generate|TOK:C20|Insect|2||TheLocustGodInsectToken|
|
||||
|Generate|TOK:C20|Saproling|||SaprolingToken|
|
||||
|Generate|TOK:C20|Snake|||SnakeToken|
|
||||
|Generate|TOK:C20|Soldier|||SoldierToken|
|
||||
|Generate|TOK:C20|Spirit|||SpiritWhiteToken|
|
||||
|Generate|TOK:C20|Treasure|||TreasureToken|
|
||||
|Generate|TOK:C20|Zombie|||ZombieToken|
|
||||
|
||||
# JMP
|
||||
|Generate|TOK:JMP|Unicorn|||UnicornToken|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-common</artifactId>
|
||||
|
|
|
@ -16,7 +16,6 @@ import mage.utils.MageVersion;
|
|||
import mage.view.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -84,7 +83,7 @@ public interface MageServer {
|
|||
|
||||
boolean isTableOwner(String sessionId, UUID roomId, UUID tableId) throws MageException;
|
||||
|
||||
Optional<TableView> getTable(UUID roomId, UUID tableId) throws MageException;
|
||||
TableView getTable(UUID roomId, UUID tableId) throws MageException;
|
||||
|
||||
List<TableView> getTables(UUID roomId) throws MageException;
|
||||
|
||||
|
@ -95,13 +94,13 @@ public interface MageServer {
|
|||
|
||||
void leaveChat(UUID chatId, String sessionId) throws MageException;
|
||||
|
||||
Optional<UUID> getTableChatId(UUID tableId) throws MageException;
|
||||
UUID getTableChatId(UUID tableId) throws MageException;
|
||||
|
||||
Optional<UUID> getGameChatId(UUID gameId) throws MageException;
|
||||
UUID getGameChatId(UUID gameId) throws MageException;
|
||||
|
||||
Optional<UUID> getRoomChatId(UUID roomId) throws MageException;
|
||||
UUID getRoomChatId(UUID roomId) throws MageException;
|
||||
|
||||
Optional<UUID> getTournamentChatId(UUID tournamentId) throws MageException;
|
||||
UUID getTournamentChatId(UUID tournamentId) throws MageException;
|
||||
|
||||
//room methods
|
||||
UUID getMainRoomId() throws MageException;
|
||||
|
|
|
@ -42,6 +42,7 @@ public class Connection {
|
|||
// private UserSkipPrioritySteps userSkipPrioritySteps;
|
||||
private static final String serialization = "?serializationtype=jboss";
|
||||
private static final String transport = "bisocket";
|
||||
private static final String threadpool = "onewayThreadPool=mage.remote.CustomThreadPool";
|
||||
|
||||
private final String parameter;
|
||||
|
||||
|
@ -78,13 +79,13 @@ public class Connection {
|
|||
try {
|
||||
InetAddress inet = getLocalAddress();
|
||||
if (inet != null) {
|
||||
return transport + "://" + inet.getHostAddress() + ':' + port + '/' + serialization + parameter;
|
||||
return transport + "://" + inet.getHostAddress() + ':' + port + '/' + serialization + "&" + threadpool + parameter;
|
||||
}
|
||||
} catch (SocketException ex) {
|
||||
// just use localhost if can't find local ip
|
||||
}
|
||||
}
|
||||
return transport + "://" + host + ':' + port + '/' + serialization + parameter;
|
||||
return transport + "://" + host + ':' + port + '/' + serialization + "&" + threadpool + parameter;
|
||||
}
|
||||
|
||||
public ProxyType getProxyType() {
|
||||
|
|
32
Mage.Common/src/main/java/mage/remote/CustomThreadPool.java
Normal file
32
Mage.Common/src/main/java/mage/remote/CustomThreadPool.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package mage.remote;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jboss.util.threadpool.BasicThreadPool;
|
||||
|
||||
public class CustomThreadPool extends BasicThreadPool {
|
||||
private static final Logger logger = Logger.getLogger(SessionImpl.class);
|
||||
|
||||
@Override
|
||||
public void setMaximumPoolSize(int size) {
|
||||
/*
|
||||
* I really don't want to implement a whole new threadpool
|
||||
* just to fix this and the executor is private
|
||||
*/
|
||||
try {
|
||||
Field executorField = BasicThreadPool.class.getField("executor");
|
||||
executorField.setAccessible(true);
|
||||
ThreadPoolExecutor executor = (ThreadPoolExecutor) executorField.get(this);
|
||||
synchronized (executor) {
|
||||
executor.setMaximumPoolSize(size);
|
||||
executor.setCorePoolSize(size);
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
logger.error("Failed to get field executor from BasicThreadPool", e);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
logger.error("Failed to get executor object from BasicThreadPool", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -647,7 +647,7 @@ public class SessionImpl implements Session {
|
|||
public Optional<UUID> getRoomChatId(UUID roomId) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return server.getRoomChatId(roomId);
|
||||
return Optional.of(server.getRoomChatId(roomId));
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -659,7 +659,7 @@ public class SessionImpl implements Session {
|
|||
public Optional<UUID> getTableChatId(UUID tableId) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return server.getTableChatId(tableId);
|
||||
return Optional.of(server.getTableChatId(tableId));
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -671,7 +671,7 @@ public class SessionImpl implements Session {
|
|||
public Optional<UUID> getGameChatId(UUID gameId) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return server.getGameChatId(gameId);
|
||||
return Optional.of(server.getGameChatId(gameId));
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -685,7 +685,7 @@ public class SessionImpl implements Session {
|
|||
public Optional<TableView> getTable(UUID roomId, UUID tableId) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return server.getTable(roomId, tableId);
|
||||
return Optional.of(server.getTable(roomId, tableId));
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -829,7 +829,7 @@ public class SessionImpl implements Session {
|
|||
public Optional<UUID> getTournamentChatId(UUID tournamentId) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return server.getTournamentChatId(tournamentId);
|
||||
return Optional.of(server.getTournamentChatId(tournamentId));
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
|
|
@ -11,11 +11,11 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
|
|||
|
||||
public static final int MAGE_VERSION_MAJOR = 1;
|
||||
public static final int MAGE_VERSION_MINOR = 4;
|
||||
public static final int MAGE_VERSION_PATCH = 42;
|
||||
public static final int MAGE_VERSION_PATCH = 43;
|
||||
public static final String MAGE_EDITION_INFO = ""; // set "-beta2" for 1.4.32V1-beta2
|
||||
public static final String MAGE_VERSION_MINOR_PATCH = "V7"; // default
|
||||
public static final String MAGE_VERSION_MINOR_PATCH = "V0"; // default
|
||||
// strict mode
|
||||
private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = true; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes)
|
||||
private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = false; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes)
|
||||
|
||||
public static final boolean MAGE_VERSION_SHOW_BUILD_TIME = true;
|
||||
private final int major;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mage.view;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -28,15 +29,32 @@ public class AbilityPickerView implements Serializable {
|
|||
if (objectName == null) {
|
||||
rule = ability.getRule(true);
|
||||
} else {
|
||||
rule = ability.getRule(objectName);
|
||||
if (rule.isEmpty()) {
|
||||
rule = ability.toString();
|
||||
// spell abilities must start with "Cast name" (split cards have different names for each spell part)
|
||||
if (ability instanceof SpellAbility) {
|
||||
SpellAbility spell = (SpellAbility) ability;
|
||||
rule = getAbilityRules(spell, spell.getCardName());
|
||||
if (!rule.startsWith("Cast ")) {
|
||||
rule = spell.toString() + ": " + rule; // spell.toString() must return this.name (example: Cast Armed)
|
||||
}
|
||||
} else {
|
||||
rule = getAbilityRules(ability, objectName);
|
||||
}
|
||||
}
|
||||
choices.put(ability.getId(), num + ". " + rule);
|
||||
}
|
||||
}
|
||||
|
||||
private String getAbilityRules(Ability ability, String objectName) {
|
||||
String rule = ability.getRule(objectName);
|
||||
if (rule.isEmpty()) {
|
||||
rule = ability.toString();
|
||||
}
|
||||
if (!rule.isEmpty()) {
|
||||
rule = Character.toUpperCase(rule.charAt(0)) + rule.substring(1);
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
public AbilityPickerView(Map<UUID, String> modes, String message) {
|
||||
this.choices = modes;
|
||||
this.message = message;
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package mage.view;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -29,7 +28,7 @@ public class AbilityView extends CardView {
|
|||
this.power = "";
|
||||
this.toughness = "";
|
||||
this.loyalty = "";
|
||||
this.cardTypes = EnumSet.noneOf(CardType.class);
|
||||
this.cardTypes = new ArrayList<CardType>();
|
||||
this.subTypes = new SubTypeList();
|
||||
this.superTypes = EnumSet.noneOf(SuperType.class);
|
||||
this.color = new ObjectColor();
|
||||
|
@ -45,5 +44,4 @@ public class AbilityView extends CardView {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package mage.view;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Abilities;
|
||||
|
@ -29,9 +31,6 @@ import mage.target.Targets;
|
|||
import mage.util.CardUtil;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -55,7 +54,7 @@ public class CardView extends SimpleCardView {
|
|||
@Expose
|
||||
protected String loyalty = "";
|
||||
protected String startingLoyalty;
|
||||
protected Set<CardType> cardTypes;
|
||||
protected ArrayList<CardType> cardTypes;
|
||||
protected SubTypeList subTypes;
|
||||
protected Set<SuperType> superTypes;
|
||||
protected ObjectColor color;
|
||||
|
@ -151,7 +150,7 @@ public class CardView extends SimpleCardView {
|
|||
this.toughness = cardView.toughness;
|
||||
this.loyalty = cardView.loyalty;
|
||||
this.startingLoyalty = cardView.startingLoyalty;
|
||||
this.cardTypes = new HashSet<>(cardView.cardTypes);
|
||||
this.cardTypes = new ArrayList<>(cardView.cardTypes);
|
||||
this.subTypes = new SubTypeList(cardView.subTypes);
|
||||
this.superTypes = cardView.superTypes;
|
||||
|
||||
|
@ -213,8 +212,8 @@ public class CardView extends SimpleCardView {
|
|||
* @param card
|
||||
* @param game
|
||||
* @param controlled is the card view created for the card controller - used
|
||||
* for morph / face down cards to know which player may see information for
|
||||
* the card
|
||||
* for morph / face down cards to know which player may see information for
|
||||
* the card
|
||||
*/
|
||||
public CardView(Card card, Game game, boolean controlled) {
|
||||
this(card, game, controlled, false, false);
|
||||
|
@ -240,12 +239,12 @@ public class CardView extends SimpleCardView {
|
|||
/**
|
||||
* @param card
|
||||
* @param game
|
||||
* @param controlled is the card view created for the card controller - used
|
||||
* for morph / face down cards to know which player may see information for
|
||||
* the card
|
||||
* @param controlled is the card view created for the card controller - used
|
||||
* for morph / face down cards to know which player may see information for
|
||||
* the card
|
||||
* @param showFaceDownCard if true and the card is not on the battlefield,
|
||||
* also a face down card is shown in the view, face down cards will be shown
|
||||
* @param storeZone if true the card zone will be set in the zone attribute.
|
||||
* also a face down card is shown in the view, face down cards will be shown
|
||||
* @param storeZone if true the card zone will be set in the zone attribute.
|
||||
*/
|
||||
public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) {
|
||||
super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null, card.getTokenDescriptor());
|
||||
|
@ -318,13 +317,6 @@ public class CardView extends SimpleCardView {
|
|||
}
|
||||
}
|
||||
|
||||
AdventureCard adventureCard = null;
|
||||
AdventureCardSpell adventureCardSpell = null;
|
||||
if (card instanceof AdventureCard) {
|
||||
adventureCard = (AdventureCard) card;
|
||||
adventureCardSpell = (AdventureCardSpell) adventureCard.getSpellCard();
|
||||
}
|
||||
|
||||
String fullCardName;
|
||||
if (splitCard != null) {
|
||||
this.isSplitCard = true;
|
||||
|
@ -340,7 +332,9 @@ public class CardView extends SimpleCardView {
|
|||
fullCardName = card.getName(); // split card contains full name as normal
|
||||
this.manaCostLeft = splitCard.getLeftHalfCard().getManaCost().getSymbols();
|
||||
this.manaCostRight = splitCard.getRightHalfCard().getManaCost().getSymbols();
|
||||
} else if (adventureCard != null) {
|
||||
} else if (card instanceof AdventureCard) {
|
||||
AdventureCard adventureCard = ((AdventureCard) card);
|
||||
AdventureCardSpell adventureCardSpell = ((AdventureCardSpell) adventureCard.getSpellCard());
|
||||
fullCardName = adventureCard.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + adventureCardSpell.getName();
|
||||
this.manaCostLeft = adventureCardSpell.getManaCost().getSymbols();
|
||||
this.manaCostRight = adventureCard.getManaCost().getSymbols();
|
||||
|
@ -467,7 +461,7 @@ public class CardView extends SimpleCardView {
|
|||
} else if (spell.getCard() != null) {
|
||||
SplitCard wholeCard = ((SplitCardHalf) spell.getCard()).getParentCard();
|
||||
Abilities<Ability> aftermathHalfAbilities = wholeCard.getRightHalfCard().getAbilities(game);
|
||||
if (aftermathHalfAbilities.stream().anyMatch(ability -> ability instanceof AftermathAbility)) {
|
||||
if (aftermathHalfAbilities.stream().anyMatch(halfAbility -> halfAbility instanceof AftermathAbility)) {
|
||||
if (ty == SpellAbilityType.SPLIT_RIGHT) {
|
||||
artRect = ArtRect.AFTERMATH_BOTTOM;
|
||||
} else {
|
||||
|
@ -636,7 +630,7 @@ public class CardView extends SimpleCardView {
|
|||
this.toughness = "";
|
||||
this.loyalty = "";
|
||||
this.startingLoyalty = "";
|
||||
this.cardTypes = EnumSet.noneOf(CardType.class);
|
||||
this.cardTypes = new ArrayList<>();
|
||||
this.subTypes = new SubTypeList();
|
||||
this.superTypes = EnumSet.noneOf(SuperType.class);
|
||||
this.color = new ObjectColor();
|
||||
|
@ -764,7 +758,7 @@ public class CardView extends SimpleCardView {
|
|||
return startingLoyalty;
|
||||
}
|
||||
|
||||
public Set<CardType> getCardTypes() {
|
||||
public ArrayList<CardType> getCardTypes() {
|
||||
return cardTypes;
|
||||
}
|
||||
|
||||
|
@ -1030,26 +1024,25 @@ public class CardView extends SimpleCardView {
|
|||
}
|
||||
|
||||
public String getColorText() {
|
||||
|
||||
String color = getColor().getDescription();
|
||||
return color.substring(0, 1).toUpperCase(Locale.ENGLISH) + color.substring(1);
|
||||
String colorText = getColor().getDescription();
|
||||
return colorText.substring(0, 1).toUpperCase(Locale.ENGLISH) + colorText.substring(1);
|
||||
}
|
||||
|
||||
public String getTypeText() {
|
||||
StringBuilder type = new StringBuilder();
|
||||
StringBuilder typeText = new StringBuilder();
|
||||
if (!getSuperTypes().isEmpty()) {
|
||||
type.append(String.join(" ", getSuperTypes().stream().map(SuperType::toString).collect(Collectors.toList())));
|
||||
type.append(" ");
|
||||
typeText.append(String.join(" ", getSuperTypes().stream().map(SuperType::toString).collect(Collectors.toList())));
|
||||
typeText.append(" ");
|
||||
}
|
||||
if (!getCardTypes().isEmpty()) {
|
||||
type.append(String.join(" ", getCardTypes().stream().map(CardType::toString).collect(Collectors.toList())));
|
||||
type.append(" ");
|
||||
typeText.append(String.join(" ", getCardTypes().stream().map(CardType::toString).collect(Collectors.toList())));
|
||||
typeText.append(" ");
|
||||
}
|
||||
if (!getSubTypes().isEmpty()) {
|
||||
type.append(" - ");
|
||||
type.append(String.join(" ", getSubTypes().stream().map(SubType::toString).collect(Collectors.toList())));
|
||||
typeText.append(" - ");
|
||||
typeText.append(String.join(" ", getSubTypes().stream().map(SubType::toString).collect(Collectors.toList())));
|
||||
}
|
||||
return type.toString();
|
||||
return typeText.toString();
|
||||
}
|
||||
|
||||
public boolean isLand() {
|
||||
|
|
|
@ -95,10 +95,9 @@ public class PermanentView extends CardView {
|
|||
if (controlled) {
|
||||
// must be a morphed or manifested card
|
||||
for (Ability permanentAbility : permanent.getAbilities()) {
|
||||
if (permanentAbility instanceof TurnFaceUpAbility && !permanentAbility.getRuleVisible()) {
|
||||
this.rules.add(permanentAbility.getRule(true));
|
||||
}
|
||||
if (permanentAbility.getWorksFaceDown()) {
|
||||
this.rules.add(permanentAbility.getRule(true));
|
||||
} else if (permanentAbility instanceof TurnFaceUpAbility && !permanentAbility.getRuleVisible()) {
|
||||
this.rules.add(permanentAbility.getRule());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ public class TournamentTypeView implements Serializable {
|
|||
private final boolean elimination;
|
||||
private final boolean random;
|
||||
private final boolean richMan;
|
||||
private final boolean jumpstart;
|
||||
|
||||
public TournamentTypeView(TournamentType tournamentType) {
|
||||
this.name = tournamentType.getName();
|
||||
|
@ -34,6 +35,7 @@ public class TournamentTypeView implements Serializable {
|
|||
this.elimination = tournamentType.isElimination();
|
||||
this.random = tournamentType.isRandom();
|
||||
this.richMan = tournamentType.isRichMan();
|
||||
this.jumpstart = tournamentType.isJumpstart();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,4 +82,9 @@ public class TournamentTypeView implements Serializable {
|
|||
public boolean isRichMan() {
|
||||
return richMan;
|
||||
}
|
||||
|
||||
public boolean isJumpstart() {
|
||||
return jumpstart;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-counter-plugin</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-plugins</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage.server.console</artifactId>
|
||||
|
|
|
@ -60,7 +60,7 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient {
|
|||
|
||||
initComponents();
|
||||
try {
|
||||
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
|
||||
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
|
||||
session = new SessionImpl(this);
|
||||
connectDialog = new ConnectDialog();
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-deck-constructed</artifactId>
|
||||
|
|
|
@ -25,9 +25,11 @@ public class Brawl extends Constructed {
|
|||
setCodes.addAll(Standard.makeLegalSets());
|
||||
|
||||
banned.add("Golos, Tireless Pilgrim");
|
||||
banned.add("Drannith Magistrate");
|
||||
banned.add("Lutri, the Spellchaser");
|
||||
banned.add("Oko, Thief of Crowns");
|
||||
banned.add("Sorcerous Spyglass");
|
||||
banned.add("Winota, Joiner of Forces");
|
||||
}
|
||||
|
||||
public Brawl(String name) {
|
||||
|
|
|
@ -13,24 +13,31 @@ public class DuelCommander extends Commander {
|
|||
banned.add("Ancient Tomb");
|
||||
banned.add("Back to Basics");
|
||||
banned.add("Black Lotus");
|
||||
banned.add("Capture of Jingzhou");
|
||||
banned.add("Cavern of Souls");
|
||||
banned.add("Channel");
|
||||
banned.add("Chrome Mox");
|
||||
banned.add("Deflecting Swat");
|
||||
banned.add("Dig Through Time");
|
||||
banned.add("Eidolon of the Great Revel");
|
||||
banned.add("Emrakul, the Aeons Torn");
|
||||
banned.add("Entomb");
|
||||
banned.add("Fastbond");
|
||||
banned.add("Field of the Dead");
|
||||
banned.add("Fierce Guardianship");
|
||||
banned.add("Fireblast");
|
||||
banned.add("Food Chain");
|
||||
banned.add("Gaea's Cradle");
|
||||
banned.add("Gifts Ungiven");
|
||||
banned.add("Grim Monolith");
|
||||
banned.add("Hermit Druid");
|
||||
banned.add("High Tide");
|
||||
banned.add("Humility");
|
||||
banned.add("Imperial Seal");
|
||||
banned.add("Karakas");
|
||||
banned.add("Library of Alexandria");
|
||||
banned.add("Lion's Eye Diamond");
|
||||
banned.add("Loyal Retainers");
|
||||
banned.add("Lutri, the Spellchaser");
|
||||
banned.add("Mana Crypt");
|
||||
banned.add("Mana Drain");
|
||||
banned.add("Mana Vault");
|
||||
|
@ -53,15 +60,18 @@ public class DuelCommander extends Commander {
|
|||
banned.add("Sensei's Divining Top");
|
||||
banned.add("Sol Ring");
|
||||
banned.add("Strip Mine");
|
||||
banned.add("Temporal Manipulation");
|
||||
banned.add("Thassa's Oracle");
|
||||
banned.add("The Tabernacle at Pendrell Vale");
|
||||
banned.add("Time Vault");
|
||||
banned.add("Time Walk");
|
||||
banned.add("Timetwister");
|
||||
banned.add("Time Warp");
|
||||
banned.add("Tinker");
|
||||
banned.add("Tolarian Academy");
|
||||
banned.add("Treasure Cruise");
|
||||
banned.add("Vampiric Tutor");
|
||||
banned.add("Wasteland");
|
||||
|
||||
bannedCommander.add("Arahbo, Roar of the World");
|
||||
bannedCommander.add("Baral, Chief of Compliance");
|
||||
|
@ -72,7 +82,6 @@ public class DuelCommander extends Commander {
|
|||
bannedCommander.add("Edric, Spymaster of Trest");
|
||||
bannedCommander.add("Emry, Lurker of the Loch");
|
||||
bannedCommander.add("Geist of Saint Traft");
|
||||
bannedCommander.add("Jace, Vryn's Prodigy");
|
||||
bannedCommander.add("Marath, Will of the Wild");
|
||||
bannedCommander.add("Najeela, the Blade-Blossom");
|
||||
bannedCommander.add("Oloro, Ageless Ascetic");
|
||||
|
|
|
@ -49,6 +49,7 @@ public class Legacy extends Constructed {
|
|||
banned.add("Iterative Analysis");
|
||||
banned.add("Jeweled Bird");
|
||||
banned.add("Library of Alexandria");
|
||||
banned.add("Lurrus of the Dream-Den");
|
||||
banned.add("Mana Crypt");
|
||||
banned.add("Mana Drain");
|
||||
banned.add("Mana Vault");
|
||||
|
@ -94,6 +95,6 @@ public class Legacy extends Constructed {
|
|||
banned.add("Wrenn and Six");
|
||||
banned.add("Yawgmoth's Bargain");
|
||||
banned.add("Yawgmoth's Will");
|
||||
|
||||
banned.add("Zirda, the Dawnwaker");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ public class Standard extends Constructed {
|
|||
|
||||
setCodes.addAll(makeLegalSets());
|
||||
|
||||
banned.add("Agent of Treachery");
|
||||
banned.add("Field of the Dead");
|
||||
banned.add("Fires of Invention");
|
||||
banned.add("Oko, Thief of Crowns");
|
||||
banned.add("Once Upon a Time");
|
||||
banned.add("Veil of Summer");
|
||||
|
|
|
@ -30,6 +30,7 @@ public class Vintage extends Constructed {
|
|||
banned.add("Immediate Action");
|
||||
banned.add("Iterative Analysis");
|
||||
banned.add("Jeweled Bird");
|
||||
banned.add("Lurrus of the Dream-Den");
|
||||
banned.add("Muzzio's Preparations");
|
||||
banned.add("Power Play");
|
||||
banned.add("Rebirth");
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-deck-limited</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-brawlduel</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-brawlfreeforall</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-canadianhighlanderduel</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-commanderduel</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-commanderfreeforall</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-freeforall</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-freeformcommanderduel</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-freeformunlimitedcommander</artifactId>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<dependency>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-momirduel</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-momirfreeforall</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-oathbreakerduel</artifactId>
|
||||
|
@ -22,7 +22,7 @@
|
|||
<dependency>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.util.*;
|
|||
public class OathbreakerFreeForAll extends GameCommanderImpl {
|
||||
|
||||
private int numPlayers;
|
||||
private Map<UUID, Set<UUID>> playerSignatureSpells = new HashMap<>();
|
||||
private Map<UUID, Set<UUID>> playerOathbreakers = new HashMap<>();
|
||||
private final Map<UUID, Set<UUID>> playerSignatureSpells = new HashMap<>();
|
||||
private final Map<UUID, Set<UUID>> playerOathbreakers = new HashMap<>();
|
||||
|
||||
private static final String COMMANDER_NAME_OATHBREAKER = "Oathbreaker";
|
||||
private static final String COMMANDER_NAME_SIGNATURE_SPELL = "Signature Spell";
|
||||
|
@ -122,19 +122,19 @@ public class OathbreakerFreeForAll extends GameCommanderImpl {
|
|||
if (player != null) {
|
||||
Set<UUID> commanders = this.playerOathbreakers.getOrDefault(player.getId(), new HashSet<>());
|
||||
Set<UUID> spells = this.playerSignatureSpells.getOrDefault(player.getId(), new HashSet<>());
|
||||
for (UUID id : player.getCommandersIds()) {
|
||||
for (UUID commanderId : super.getCommandersIds(player, commanderCardType)) {
|
||||
switch (commanderCardType) {
|
||||
case ANY:
|
||||
res.add(id);
|
||||
res.add(commanderId);
|
||||
break;
|
||||
case COMMANDER_OR_OATHBREAKER:
|
||||
if (commanders.contains(id)) {
|
||||
res.add(id);
|
||||
if (commanders.contains(commanderId)) {
|
||||
res.add(commanderId);
|
||||
}
|
||||
break;
|
||||
case SIGNATURE_SPELL:
|
||||
if (spells.contains(id)) {
|
||||
res.add(id);
|
||||
if (spells.contains(commanderId)) {
|
||||
res.add(commanderId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-pennydreadfulcommanderfreeforall</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-tinyleadersduel</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-game-twoplayerduel</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-player-ai-draftbot</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-player-ai-ma</artifactId>
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.player.ai;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.AbilityImpl;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.PassAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
|
@ -94,9 +95,9 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
|||
}
|
||||
|
||||
protected void simulateOptions(Game game) {
|
||||
List<Ability> playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer);
|
||||
List<ActivatedAbility> playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer);
|
||||
playables = filterAbilities(game, playables, suggested);
|
||||
for (Ability ability : playables) {
|
||||
for (ActivatedAbility ability : playables) {
|
||||
if (ability.getAbilityType() == AbilityType.MANA) {
|
||||
continue;
|
||||
}
|
||||
|
@ -186,15 +187,15 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
|||
* @param suggested
|
||||
* @return
|
||||
*/
|
||||
protected List<Ability> filterAbilities(Game game, List<Ability> playables, List<String> suggested) {
|
||||
protected List<ActivatedAbility> filterAbilities(Game game, List<ActivatedAbility> playables, List<String> suggested) {
|
||||
if (playables.isEmpty()) {
|
||||
return playables;
|
||||
}
|
||||
if (suggested == null || suggested.isEmpty()) {
|
||||
return playables;
|
||||
}
|
||||
List<Ability> filtered = new ArrayList<>();
|
||||
for (Ability ability : playables) {
|
||||
List<ActivatedAbility> filtered = new ArrayList<>();
|
||||
for (ActivatedAbility ability : playables) {
|
||||
Card card = game.getCard(ability.getSourceId());
|
||||
if (card != null) {
|
||||
for (String s : suggested) {
|
||||
|
@ -212,7 +213,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
|||
return playables;
|
||||
}
|
||||
|
||||
protected List<Ability> filterOptions(Game game, List<Ability> options, Ability ability, List<String> suggested) {
|
||||
protected List<Ability> filterOptions(Game game, List<Ability> options, ActivatedAbility ability, List<String> suggested) {
|
||||
if (options.isEmpty()) {
|
||||
return options;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-player-ai</artifactId>
|
||||
|
|
|
@ -396,12 +396,16 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
|
||||
while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen())
|
||||
// exile cost workaround: exile is bad, but exile from graveyard in most cases is good (more exiled -- more good things you get, e.g. delve's pay)
|
||||
boolean isRealGood = outcome.isGood() || outcome == Outcome.Exile;
|
||||
while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen())
|
||||
&& !cards.isEmpty()) {
|
||||
Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
|
||||
if (pick != null) {
|
||||
target.addTarget(pick.getId(), null, game);
|
||||
cards.remove(pick);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1267,7 +1271,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
//play a land that will allow us to play an unplayable
|
||||
for (Mana mana : unplayable.keySet()) {
|
||||
for (Card card : lands) {
|
||||
for (ActivatedManaAbilityImpl ability : card.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
||||
for (ActivatedManaAbilityImpl ability : card.getAbilities(game).getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
if (netMana.enough(mana)) {
|
||||
this.playLand(card, game, false);
|
||||
|
@ -1281,7 +1285,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
//play a land that will get us closer to playing an unplayable
|
||||
for (Mana mana : unplayable.keySet()) {
|
||||
for (Card card : lands) {
|
||||
for (ActivatedManaAbilityImpl ability : card.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
||||
for (ActivatedManaAbilityImpl ability : card.getAbilities(game).getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
if (mana.contains(netMana)) {
|
||||
this.playLand(card, game, false);
|
||||
|
@ -1321,7 +1325,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
if (ability != null && ability.canActivate(playerId, game).canActivate()
|
||||
&& !game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
|
||||
if (card.getCardType().contains(CardType.INSTANT)
|
||||
|| card.hasAbility(FlashAbility.getInstance().getId(), game)) {
|
||||
|| card.hasAbility(FlashAbility.getInstance(), game)) {
|
||||
playableInstant.add(card);
|
||||
} else {
|
||||
playableNonInstant.add(card);
|
||||
|
@ -1362,7 +1366,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
for (Card card : graveyard.getCards(game)) {
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD)) {
|
||||
for (ActivatedAbility ability : card.getAbilities(game).getActivatedAbilities(Zone.GRAVEYARD)) {
|
||||
if (ability.canActivate(playerId, game).canActivate()) {
|
||||
ManaOptions abilityOptions = ability.getManaCosts().getOptions();
|
||||
if (abilityOptions.isEmpty()) {
|
||||
|
@ -1529,10 +1533,34 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pay phyrexian life costs
|
||||
if (cost instanceof PhyrexianManaCost) {
|
||||
return cost.pay(null, game, null, playerId, false, null) || permittingObject != null;
|
||||
}
|
||||
|
||||
// pay special mana like convoke cost (tap for pay)
|
||||
// GUI: user see "special" button while pay spell's cost
|
||||
// TODO: AI can't prioritize special mana types to pay, e.g. it will use first available
|
||||
SpecialAction specialAction = game.getState().getSpecialActions().getControlledBy(this.getId(), true)
|
||||
.values().stream().findFirst().orElse(null);
|
||||
ManaOptions specialMana = specialAction == null ? null : specialAction.getManaOptions(ability, game, unpaid);
|
||||
if (specialMana != null) {
|
||||
for (Mana netMana : specialMana) {
|
||||
if (cost.testPay(netMana) || permittingObject != null) {
|
||||
if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) {
|
||||
continue;
|
||||
}
|
||||
specialAction.setUnpaidMana(unpaid);
|
||||
if (activateAbility(specialAction, game)) {
|
||||
return true;
|
||||
}
|
||||
// only one time try to pay
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1895,27 +1923,6 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) {
|
||||
switch (ability.getSpellAbilityType()) {
|
||||
case SPLIT:
|
||||
case SPLIT_FUSED:
|
||||
case SPLIT_AFTERMATH:
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
if (object != null) {
|
||||
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game);
|
||||
if (useableAbilities != null && !useableAbilities.isEmpty()) {
|
||||
// game.fireGetChoiceEvent(playerId, name, object, new ArrayList<>(useableAbilities.values()));
|
||||
// TODO: Improve this
|
||||
return (SpellAbility) useableAbilities.values().iterator().next();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
default:
|
||||
return ability;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mode chooseMode(Modes modes, Ability source, Game game) {
|
||||
log.debug("chooseMode");
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-player-ai-mcts</artifactId>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package mage.player.ai;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.PassAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
|
@ -45,16 +46,16 @@ public class MCTSPlayer extends ComputerPlayer {
|
|||
return new MCTSPlayer(this);
|
||||
}
|
||||
|
||||
protected List<Ability> getPlayableAbilities(Game game) {
|
||||
List<Ability> playables = getPlayable(game, true);
|
||||
protected List<ActivatedAbility> getPlayableAbilities(Game game) {
|
||||
List<ActivatedAbility> playables = getPlayable(game, true);
|
||||
playables.add(pass);
|
||||
return playables;
|
||||
}
|
||||
|
||||
public List<Ability> getPlayableOptions(Game game) {
|
||||
List<Ability> all = new ArrayList<>();
|
||||
List<Ability> playables = getPlayableAbilities(game);
|
||||
for (Ability ability: playables) {
|
||||
List<ActivatedAbility> playables = getPlayableAbilities(game);
|
||||
for (ActivatedAbility ability: playables) {
|
||||
List<Ability> options = game.getPlayer(playerId).getPlayableOptions(ability, game);
|
||||
if (options.isEmpty()) {
|
||||
if (!ability.getManaCosts().getVariableCosts().isEmpty()) {
|
||||
|
|
|
@ -73,7 +73,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
|
|||
}
|
||||
|
||||
private Ability getAction(Game game) {
|
||||
List<Ability> playables = getPlayableAbilities(game);
|
||||
List<ActivatedAbility> playables = getPlayableAbilities(game);
|
||||
Ability ability;
|
||||
while (true) {
|
||||
if (playables.size() == 1) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-player-aiminimax</artifactId>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package mage.player.ai;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.PassAbility;
|
||||
|
@ -59,10 +60,10 @@ public class SimulatedPlayer extends ComputerPlayer {
|
|||
return list;
|
||||
}
|
||||
|
||||
protected void simulateOptions(Game game, Ability previousActions) {
|
||||
protected void simulateOptions(Game game, ActivatedAbility previousActions) {
|
||||
allActions.add(previousActions);
|
||||
List<Ability> playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer);
|
||||
for (Ability ability: playables) {
|
||||
List<ActivatedAbility> playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer);
|
||||
for (ActivatedAbility ability: playables) {
|
||||
List<Ability> options = game.getPlayer(playerId).getPlayableOptions(ability, game);
|
||||
if (options.isEmpty()) {
|
||||
if (!ability.getManaCosts().getVariableCosts().isEmpty()) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-player-human</artifactId>
|
||||
|
|
|
@ -10,6 +10,7 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
|||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.abilities.hint.HintUtils;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.decks.Deck;
|
||||
|
@ -61,6 +62,8 @@ import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
|
|||
*/
|
||||
public class HumanPlayer extends PlayerImpl {
|
||||
|
||||
private static final boolean ALLOW_USERS_TO_PUT_NON_PLAYABLE_SPELLS_ON_STACK_WORKAROUND = false; // warning, see workaround's info on usage
|
||||
|
||||
private transient Boolean responseOpenedForAnswer = false; // can't get response until prepared target (e.g. until send all fire events to all players)
|
||||
private final transient PlayerResponse response = new PlayerResponse();
|
||||
|
||||
|
@ -1039,7 +1042,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
if (response.getString() != null
|
||||
&& response.getString().equals("special")) {
|
||||
specialAction(game);
|
||||
activateSpecialAction(game, null);
|
||||
} else if (response.getUUID() != null) {
|
||||
boolean result = false;
|
||||
MageObject object = game.getObject(response.getUUID());
|
||||
|
@ -1047,24 +1050,42 @@ public class HumanPlayer extends PlayerImpl {
|
|||
Zone zone = game.getState().getZone(object.getId());
|
||||
if (zone != null) {
|
||||
// look at card or try to cast/activate abilities
|
||||
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = new LinkedHashMap<>();
|
||||
|
||||
Player actingPlayer = null;
|
||||
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = null;
|
||||
if (playerId.equals(game.getPriorityPlayerId())) {
|
||||
actingPlayer = this;
|
||||
} else if (getPlayersUnderYourControl().contains(game.getPriorityPlayerId())) {
|
||||
actingPlayer = game.getPlayer(game.getPriorityPlayerId());
|
||||
}
|
||||
if (actingPlayer != null) {
|
||||
useableAbilities = actingPlayer.getUseableActivatedAbilities(object, zone, game);
|
||||
useableAbilities = actingPlayer.getPlayableActivatedAbilities(object, zone, game);
|
||||
|
||||
// GUI: workaround to enable users to put spells on stack without real available mana
|
||||
// (without highlighting, like it was in old versions before June 2020)
|
||||
// Reason: some gain ability adds cost modification and other things to spells on stack only,
|
||||
// e.g. xmage can't find playable ability before put that spell on stack (wtf example: Chief Engineer,
|
||||
// see ConvokeTest)
|
||||
// TODO: it's a BAD workaround -- users can't see that card/ability is broken and will not report to us, AI can't play that ability too
|
||||
// Enable it on massive broken cards/abilities only or for manual tests
|
||||
if (ALLOW_USERS_TO_PUT_NON_PLAYABLE_SPELLS_ON_STACK_WORKAROUND) {
|
||||
if (object instanceof Card) {
|
||||
for (Ability ability : ((Card) object).getAbilities(game)) {
|
||||
if (ability instanceof SpellAbility && ((SpellAbility) ability).canActivate(actingPlayer.getId(), game).canActivate()
|
||||
|| ability instanceof PlayLandAbility) {
|
||||
useableAbilities.putIfAbsent(ability.getId(), (ActivatedAbility) ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (object instanceof Card
|
||||
&& ((Card) object).isFaceDown(game)
|
||||
&& lookAtFaceDownCard((Card) object, game, useableAbilities == null ? 0 : useableAbilities.size())) {
|
||||
&& lookAtFaceDownCard((Card) object, game, useableAbilities.size())) {
|
||||
result = true;
|
||||
} else {
|
||||
if (useableAbilities != null
|
||||
&& !useableAbilities.isEmpty()) {
|
||||
if (!useableAbilities.isEmpty()) {
|
||||
activateAbility(useableAbilities, object, game);
|
||||
result = true;
|
||||
}
|
||||
|
@ -1221,7 +1242,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
} else if (response.getString() != null
|
||||
&& response.getString().equals("special")) {
|
||||
if (unpaid instanceof ManaCostsImpl) {
|
||||
specialManaAction(unpaid, game);
|
||||
activateSpecialAction(game, unpaid);
|
||||
}
|
||||
} else if (response.getManaType() != null) {
|
||||
// this mana type can be paid once from pool
|
||||
|
@ -1336,19 +1357,30 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (object == null) {
|
||||
return;
|
||||
}
|
||||
if (AbilityType.SPELL.equals(abilityToCast.getAbilityType())) {
|
||||
|
||||
// GUI: for user's information only - check if mana abilities allows to use here (getUseableManaAbilities already filter it)
|
||||
// Reason: when you use special mana ability then normal mana abilities will be restricted to pay. Users
|
||||
// can't see lands as playable and must know the reason (if they click on land then they get that message)
|
||||
if (abilityToCast.getAbilityType() == AbilityType.SPELL) {
|
||||
Spell spell = game.getStack().getSpell(abilityToCast.getSourceId());
|
||||
if (spell != null && !spell.isResolving()
|
||||
&& spell.isDoneActivatingManaAbilities()) {
|
||||
game.informPlayer(this, "You can no longer use activated mana abilities to pay for the current spell. Cancel and recast the spell and activate mana abilities first.");
|
||||
return;
|
||||
boolean haveManaAbilities = object.getAbilities().stream().anyMatch(a -> a instanceof ManaAbility);
|
||||
if (spell != null && !spell.isResolving() && haveManaAbilities) {
|
||||
switch (spell.getCurrentActivatingManaAbilitiesStep()) {
|
||||
// if you used special mana ability like convoke then normal mana abilities will be restricted to use, see Convoke for details
|
||||
case BEFORE:
|
||||
case NORMAL:
|
||||
break;
|
||||
case AFTER:
|
||||
game.informPlayer(this, "You can no longer use activated mana abilities to pay for the current spell (special mana pay already used). Cancel and recast the spell to activate mana abilities first.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zone zone = game.getState().getZone(object.getId());
|
||||
if (zone != null) {
|
||||
LinkedHashMap<UUID, ActivatedManaAbilityImpl> useableAbilities = getUseableManaAbilities(object, zone, game);
|
||||
if (useableAbilities != null
|
||||
&& !useableAbilities.isEmpty()) {
|
||||
if (!useableAbilities.isEmpty()) {
|
||||
useableAbilities = ManaUtil.tryToAutoPay(unpaid, useableAbilities); // eliminates other abilities if one fits perfectly
|
||||
currentlyUnpaidMana = unpaid;
|
||||
activateAbility(useableAbilities, object, game);
|
||||
|
@ -1845,7 +1877,13 @@ public class HumanPlayer extends PlayerImpl {
|
|||
draft.firePickCardEvent(playerId);
|
||||
}
|
||||
|
||||
protected void specialAction(Game game) {
|
||||
/**
|
||||
* Activate special action (normal or mana)
|
||||
*
|
||||
* @param game
|
||||
* @param unpaidForManaAction - set unpaid for mana actions like convoke
|
||||
*/
|
||||
protected void activateSpecialAction(Game game, ManaCost unpaidForManaAction) {
|
||||
if (gameInCheckPlayableState(game)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1854,7 +1892,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return;
|
||||
}
|
||||
|
||||
Map<UUID, SpecialAction> specialActions = game.getState().getSpecialActions().getControlledBy(playerId, false);
|
||||
Map<UUID, SpecialAction> specialActions = game.getState().getSpecialActions().getControlledBy(playerId, unpaidForManaAction != null);
|
||||
if (!specialActions.isEmpty()) {
|
||||
|
||||
updateGameStatePriority("specialAction", game);
|
||||
|
@ -1864,39 +1902,13 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
waitForResponse(game);
|
||||
|
||||
if (response.getUUID() != null) {
|
||||
if (specialActions.containsKey(response.getUUID())) {
|
||||
activateAbility(specialActions.get(response.getUUID()), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void specialManaAction(ManaCost unpaid, Game game) {
|
||||
if (gameInCheckPlayableState(game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canRespond()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<UUID, SpecialAction> specialActions = game.getState().getSpecialActions().getControlledBy(playerId, true);
|
||||
if (!specialActions.isEmpty()) {
|
||||
updateGameStatePriority("specialAction", game);
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetChoiceEvent(playerId, name, null, new ArrayList<>(specialActions.values()));
|
||||
}
|
||||
waitForResponse(game);
|
||||
|
||||
if (response.getUUID() != null) {
|
||||
if (specialActions.containsKey(response.getUUID())) {
|
||||
SpecialAction specialAction = specialActions.get(response.getUUID());
|
||||
if (specialAction != null) {
|
||||
specialAction.setUnpaidMana(unpaid);
|
||||
activateAbility(specialActions.get(response.getUUID()), game);
|
||||
if (unpaidForManaAction != null) {
|
||||
specialAction.setUnpaidMana(unpaidForManaAction);
|
||||
}
|
||||
activateAbility(specialAction, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1973,51 +1985,6 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) {
|
||||
if (gameInCheckPlayableState(game)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: add canRespond cycle?
|
||||
if (!canRespond()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (ability.getSpellAbilityType()) {
|
||||
case SPLIT:
|
||||
case SPLIT_FUSED:
|
||||
case SPLIT_AFTERMATH:
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
if (object != null) {
|
||||
String message = "Choose ability to cast" + (noMana ? " for FREE" : "") + "<br>" + object.getLogName();
|
||||
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game);
|
||||
if (useableAbilities != null
|
||||
&& useableAbilities.size() == 1) {
|
||||
return (SpellAbility) useableAbilities.values().iterator().next();
|
||||
} else if (useableAbilities != null
|
||||
&& !useableAbilities.isEmpty()) {
|
||||
|
||||
updateGameStatePriority("chooseSpellAbilityForCast", game);
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetChoiceEvent(playerId, message, object, new ArrayList<>(useableAbilities.values()));
|
||||
}
|
||||
waitForResponse(game);
|
||||
|
||||
if (response.getUUID() != null) {
|
||||
if (useableAbilities.containsKey(response.getUUID())) {
|
||||
return (SpellAbility) useableAbilities.get(response.getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
default:
|
||||
return ability;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility chooseAbilityForCast(Card card, Game game, boolean nonMana) {
|
||||
if (gameInCheckPlayableState(game)) {
|
||||
|
@ -2096,6 +2063,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
modeText = "(selected " + timesSelected + "x) " + modeText;
|
||||
}
|
||||
}
|
||||
if (!modeText.isEmpty()) {
|
||||
modeText = Character.toUpperCase(modeText.charAt(0)) + modeText.substring(1);
|
||||
}
|
||||
modeMap.put(mode.getId(), modeIndex + ". " + modeText);
|
||||
}
|
||||
}
|
||||
|
@ -2141,13 +2111,14 @@ public class HumanPlayer extends PlayerImpl {
|
|||
// cancel choice (remove all selections)
|
||||
if (Modes.CHOOSE_OPTION_CANCEL_ID.equals(response.getUUID())) {
|
||||
modes.getSelectedModes().clear();
|
||||
return null;
|
||||
}
|
||||
} else if (canEndChoice) {
|
||||
// end choice by done button in feedback panel
|
||||
// disable after done option implemented
|
||||
// done = true;
|
||||
}
|
||||
|
||||
// triggered abilities can't be skipped by cancel or wrong answer
|
||||
if (source.getAbilityType() != AbilityType.TRIGGERED) {
|
||||
done = true;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-tournament-boosterdraft</artifactId>
|
||||
|
|
|
@ -0,0 +1,552 @@
|
|||
package mage.tournament.cubes;
|
||||
|
||||
import mage.game.draft.DraftCube;
|
||||
|
||||
public class VintageCubeApril2020 extends DraftCube {
|
||||
|
||||
public VintageCubeApril2020() {
|
||||
super("MTGO Vintage Cube April 2020");
|
||||
|
||||
cubeCards.add(new CardIdentity("Kytheon, Hero of Akros", ""));
|
||||
cubeCards.add(new CardIdentity("Mother of Runes", ""));
|
||||
cubeCards.add(new CardIdentity("Student of Warfare", ""));
|
||||
cubeCards.add(new CardIdentity("Adanto Vanguard", ""));
|
||||
cubeCards.add(new CardIdentity("Containment Priest", ""));
|
||||
cubeCards.add(new CardIdentity("Leonin Relic-Warder", ""));
|
||||
cubeCards.add(new CardIdentity("Porcelain Legionnaire", ""));
|
||||
cubeCards.add(new CardIdentity("Selfless Spirit", ""));
|
||||
cubeCards.add(new CardIdentity("Soulfire Grand Master", ""));
|
||||
cubeCards.add(new CardIdentity("Stoneforge Mystic", ""));
|
||||
cubeCards.add(new CardIdentity("Thalia, Guardian of Thraben", ""));
|
||||
cubeCards.add(new CardIdentity("Tithe Taker", ""));
|
||||
cubeCards.add(new CardIdentity("Wall of Omens", ""));
|
||||
cubeCards.add(new CardIdentity("Blade Splicer", ""));
|
||||
cubeCards.add(new CardIdentity("Brightling", ""));
|
||||
cubeCards.add(new CardIdentity("Brimaz, King of Oreskos", ""));
|
||||
cubeCards.add(new CardIdentity("Fairgrounds Warden", ""));
|
||||
cubeCards.add(new CardIdentity("Flickerwisp", ""));
|
||||
cubeCards.add(new CardIdentity("Monastery Mentor", ""));
|
||||
cubeCards.add(new CardIdentity("Recruiter of the Guard", ""));
|
||||
cubeCards.add(new CardIdentity("Silverblade Paladin", ""));
|
||||
cubeCards.add(new CardIdentity("Emeria Angel", ""));
|
||||
cubeCards.add(new CardIdentity("Hero of Bladehold", ""));
|
||||
cubeCards.add(new CardIdentity("Linvala, Keeper of Silence", ""));
|
||||
cubeCards.add(new CardIdentity("Restoration Angel", ""));
|
||||
cubeCards.add(new CardIdentity("Angel of Invention", ""));
|
||||
cubeCards.add(new CardIdentity("Elspeth Conquers Death", ""));
|
||||
cubeCards.add(new CardIdentity("Archangel Avacyn", ""));
|
||||
cubeCards.add(new CardIdentity("Baneslayer Angel", ""));
|
||||
cubeCards.add(new CardIdentity("Lyra Dawnbringer", ""));
|
||||
cubeCards.add(new CardIdentity("Reveillark", ""));
|
||||
cubeCards.add(new CardIdentity("Sun Titan", ""));
|
||||
cubeCards.add(new CardIdentity("Angel of Serenity", ""));
|
||||
cubeCards.add(new CardIdentity("Elesh Norn, Grand Cenobite", ""));
|
||||
cubeCards.add(new CardIdentity("Iona, Shield of Emeria", ""));
|
||||
cubeCards.add(new CardIdentity("Gideon Blackblade", ""));
|
||||
cubeCards.add(new CardIdentity("Elspeth, Sun's Nemesis", ""));
|
||||
cubeCards.add(new CardIdentity("Gideon, Ally of Zendikar", ""));
|
||||
cubeCards.add(new CardIdentity("Gideon Jura", ""));
|
||||
cubeCards.add(new CardIdentity("Elspeth, Sun's Champion", ""));
|
||||
cubeCards.add(new CardIdentity("Condemn", ""));
|
||||
cubeCards.add(new CardIdentity("Enlightened Tutor", ""));
|
||||
cubeCards.add(new CardIdentity("Mana Tithe", ""));
|
||||
cubeCards.add(new CardIdentity("Path to Exile", ""));
|
||||
cubeCards.add(new CardIdentity("Swords to Plowshares", ""));
|
||||
cubeCards.add(new CardIdentity("Disenchant", ""));
|
||||
cubeCards.add(new CardIdentity("Unexpectedly Absent", ""));
|
||||
cubeCards.add(new CardIdentity("Balance", ""));
|
||||
cubeCards.add(new CardIdentity("Council's Judgment", ""));
|
||||
cubeCards.add(new CardIdentity("Spectral Procession", ""));
|
||||
cubeCards.add(new CardIdentity("Armageddon", ""));
|
||||
cubeCards.add(new CardIdentity("Day of Judgment", ""));
|
||||
cubeCards.add(new CardIdentity("Ravages of War", ""));
|
||||
cubeCards.add(new CardIdentity("Wrath of God", ""));
|
||||
cubeCards.add(new CardIdentity("Terminus", ""));
|
||||
cubeCards.add(new CardIdentity("Land Tax", ""));
|
||||
cubeCards.add(new CardIdentity("Legion's Landing", ""));
|
||||
cubeCards.add(new CardIdentity("Honor of the Pure", ""));
|
||||
cubeCards.add(new CardIdentity("Banishing Light", ""));
|
||||
cubeCards.add(new CardIdentity("Oblivion Ring", ""));
|
||||
cubeCards.add(new CardIdentity("Faith's Fetters", ""));
|
||||
cubeCards.add(new CardIdentity("Moat", ""));
|
||||
cubeCards.add(new CardIdentity("Parallax Wave", ""));
|
||||
cubeCards.add(new CardIdentity("Spear of Heliod", ""));
|
||||
cubeCards.add(new CardIdentity("Karakas", ""));
|
||||
cubeCards.add(new CardIdentity("Thassa's Oracle", ""));
|
||||
cubeCards.add(new CardIdentity("Baral, Chief of Compliance", ""));
|
||||
cubeCards.add(new CardIdentity("Jace, Vryn's Prodigy", ""));
|
||||
cubeCards.add(new CardIdentity("Looter il-Kor", ""));
|
||||
cubeCards.add(new CardIdentity("Phantasmal Image", ""));
|
||||
cubeCards.add(new CardIdentity("Snapcaster Mage", ""));
|
||||
cubeCards.add(new CardIdentity("Thing in the Ice", ""));
|
||||
cubeCards.add(new CardIdentity("Arcane Artisan", ""));
|
||||
cubeCards.add(new CardIdentity("Deceiver Exarch", ""));
|
||||
cubeCards.add(new CardIdentity("Pestermite", ""));
|
||||
cubeCards.add(new CardIdentity("Spellseeker", ""));
|
||||
cubeCards.add(new CardIdentity("Trinket Mage", ""));
|
||||
cubeCards.add(new CardIdentity("Vendilion Clique", ""));
|
||||
cubeCards.add(new CardIdentity("Glen Elendra Archmage", ""));
|
||||
cubeCards.add(new CardIdentity("Phyrexian Metamorph", ""));
|
||||
cubeCards.add(new CardIdentity("Sower of Temptation", ""));
|
||||
cubeCards.add(new CardIdentity("Venser, Shaper Savant", ""));
|
||||
cubeCards.add(new CardIdentity("Mulldrifter", ""));
|
||||
cubeCards.add(new CardIdentity("Riftwing Cloudskate", ""));
|
||||
cubeCards.add(new CardIdentity("Consecrated Sphinx", ""));
|
||||
cubeCards.add(new CardIdentity("Frost Titan", ""));
|
||||
cubeCards.add(new CardIdentity("Torrential Gearhulk", ""));
|
||||
cubeCards.add(new CardIdentity("Palinchron", ""));
|
||||
cubeCards.add(new CardIdentity("Inkwell Leviathan", ""));
|
||||
cubeCards.add(new CardIdentity("Jace Beleren", ""));
|
||||
cubeCards.add(new CardIdentity("Jace, the Mind Sculptor", ""));
|
||||
cubeCards.add(new CardIdentity("Tezzeret the Seeker", ""));
|
||||
cubeCards.add(new CardIdentity("Ancestral Recall", ""));
|
||||
cubeCards.add(new CardIdentity("Brainstorm", ""));
|
||||
cubeCards.add(new CardIdentity("High Tide", ""));
|
||||
cubeCards.add(new CardIdentity("Mystical Tutor", ""));
|
||||
cubeCards.add(new CardIdentity("Spell Pierce", ""));
|
||||
cubeCards.add(new CardIdentity("Brain Freeze", ""));
|
||||
cubeCards.add(new CardIdentity("Counterspell", ""));
|
||||
cubeCards.add(new CardIdentity("Daze", ""));
|
||||
cubeCards.add(new CardIdentity("Impulse", ""));
|
||||
cubeCards.add(new CardIdentity("Mana Drain", ""));
|
||||
cubeCards.add(new CardIdentity("Mana Leak", ""));
|
||||
cubeCards.add(new CardIdentity("Miscalculation", ""));
|
||||
cubeCards.add(new CardIdentity("Remand", ""));
|
||||
cubeCards.add(new CardIdentity("Frantic Search", ""));
|
||||
cubeCards.add(new CardIdentity("Thirst for Knowledge", ""));
|
||||
cubeCards.add(new CardIdentity("Cryptic Command", ""));
|
||||
cubeCards.add(new CardIdentity("Fact or Fiction", ""));
|
||||
cubeCards.add(new CardIdentity("Gifts Ungiven", ""));
|
||||
cubeCards.add(new CardIdentity("Turnabout", ""));
|
||||
cubeCards.add(new CardIdentity("Force of Will", ""));
|
||||
cubeCards.add(new CardIdentity("Gush", ""));
|
||||
cubeCards.add(new CardIdentity("Mystic Confluence", ""));
|
||||
cubeCards.add(new CardIdentity("Repeal", ""));
|
||||
cubeCards.add(new CardIdentity("Dig Through Time", ""));
|
||||
cubeCards.add(new CardIdentity("Ancestral Vision", ""));
|
||||
cubeCards.add(new CardIdentity("Gitaxian Probe", ""));
|
||||
cubeCards.add(new CardIdentity("Ponder", ""));
|
||||
cubeCards.add(new CardIdentity("Preordain", ""));
|
||||
cubeCards.add(new CardIdentity("Chart a Course", ""));
|
||||
cubeCards.add(new CardIdentity("Time Walk", ""));
|
||||
cubeCards.add(new CardIdentity("Show and Tell", ""));
|
||||
cubeCards.add(new CardIdentity("Timetwister", ""));
|
||||
cubeCards.add(new CardIdentity("Tinker", ""));
|
||||
cubeCards.add(new CardIdentity("Bribery", ""));
|
||||
cubeCards.add(new CardIdentity("Time Warp", ""));
|
||||
cubeCards.add(new CardIdentity("Mind's Desire", ""));
|
||||
cubeCards.add(new CardIdentity("Time Spiral", ""));
|
||||
cubeCards.add(new CardIdentity("Upheaval", ""));
|
||||
cubeCards.add(new CardIdentity("Treasure Cruise", ""));
|
||||
cubeCards.add(new CardIdentity("Search for Azcanta", ""));
|
||||
cubeCards.add(new CardIdentity("Control Magic", ""));
|
||||
cubeCards.add(new CardIdentity("Opposition", ""));
|
||||
cubeCards.add(new CardIdentity("Treachery", ""));
|
||||
cubeCards.add(new CardIdentity("Shelldock Isle", ""));
|
||||
cubeCards.add(new CardIdentity("Tolarian Academy", ""));
|
||||
cubeCards.add(new CardIdentity("Putrid Imp", ""));
|
||||
cubeCards.add(new CardIdentity("Dark Confidant", ""));
|
||||
cubeCards.add(new CardIdentity("Kitesail Freebooter", ""));
|
||||
cubeCards.add(new CardIdentity("Mesmeric Fiend", ""));
|
||||
cubeCards.add(new CardIdentity("Oona's Prowler", ""));
|
||||
cubeCards.add(new CardIdentity("Pack Rat", ""));
|
||||
cubeCards.add(new CardIdentity("Vampire Hexmage", ""));
|
||||
cubeCards.add(new CardIdentity("Bone Shredder", ""));
|
||||
cubeCards.add(new CardIdentity("Hypnotic Specter", ""));
|
||||
cubeCards.add(new CardIdentity("Ophiomancer", ""));
|
||||
cubeCards.add(new CardIdentity("Plaguecrafter", ""));
|
||||
cubeCards.add(new CardIdentity("Vampire Nighthawk", ""));
|
||||
cubeCards.add(new CardIdentity("Gonti, Lord of Luxury", ""));
|
||||
cubeCards.add(new CardIdentity("Nekrataal", ""));
|
||||
cubeCards.add(new CardIdentity("Ravenous Chupacabra", ""));
|
||||
cubeCards.add(new CardIdentity("Shriekmaw", ""));
|
||||
cubeCards.add(new CardIdentity("Grave Titan", ""));
|
||||
cubeCards.add(new CardIdentity("Ink-Eyes, Servant of Oni", ""));
|
||||
cubeCards.add(new CardIdentity("Massacre Wurm", ""));
|
||||
cubeCards.add(new CardIdentity("Tasigur, the Golden Fang", ""));
|
||||
cubeCards.add(new CardIdentity("Sheoldred, Whispering One", ""));
|
||||
cubeCards.add(new CardIdentity("Griselbrand", ""));
|
||||
cubeCards.add(new CardIdentity("Liliana of the Veil", ""));
|
||||
cubeCards.add(new CardIdentity("Liliana, Death's Majesty", ""));
|
||||
cubeCards.add(new CardIdentity("Dark Ritual", ""));
|
||||
cubeCards.add(new CardIdentity("Entomb", ""));
|
||||
cubeCards.add(new CardIdentity("Fatal Push", ""));
|
||||
cubeCards.add(new CardIdentity("Vampiric Tutor", ""));
|
||||
cubeCards.add(new CardIdentity("Cabal Ritual", ""));
|
||||
cubeCards.add(new CardIdentity("Go for the Throat", ""));
|
||||
cubeCards.add(new CardIdentity("Liliana's Triumph", ""));
|
||||
cubeCards.add(new CardIdentity("Shallow Grave", ""));
|
||||
cubeCards.add(new CardIdentity("Ultimate Price", ""));
|
||||
cubeCards.add(new CardIdentity("Corpse Dance", ""));
|
||||
cubeCards.add(new CardIdentity("Dismember", ""));
|
||||
cubeCards.add(new CardIdentity("Hero's Downfall", ""));
|
||||
cubeCards.add(new CardIdentity("Makeshift Mannequin", ""));
|
||||
cubeCards.add(new CardIdentity("Duress", ""));
|
||||
cubeCards.add(new CardIdentity("Imperial Seal", ""));
|
||||
cubeCards.add(new CardIdentity("Inquisition of Kozilek", ""));
|
||||
cubeCards.add(new CardIdentity("Reanimate", ""));
|
||||
cubeCards.add(new CardIdentity("Thoughtseize", ""));
|
||||
cubeCards.add(new CardIdentity("Collective Brutality", ""));
|
||||
cubeCards.add(new CardIdentity("Demonic Tutor", ""));
|
||||
cubeCards.add(new CardIdentity("Exhume", ""));
|
||||
cubeCards.add(new CardIdentity("Hymn to Tourach", ""));
|
||||
cubeCards.add(new CardIdentity("Night's Whisper", ""));
|
||||
cubeCards.add(new CardIdentity("Buried Alive", ""));
|
||||
cubeCards.add(new CardIdentity("Toxic Deluge", ""));
|
||||
cubeCards.add(new CardIdentity("Yawgmoth's Will", ""));
|
||||
cubeCards.add(new CardIdentity("Damnation", ""));
|
||||
cubeCards.add(new CardIdentity("Languish", ""));
|
||||
cubeCards.add(new CardIdentity("Mastermind's Acquisition", ""));
|
||||
cubeCards.add(new CardIdentity("Tendrils of Agony", ""));
|
||||
cubeCards.add(new CardIdentity("Dark Petition", ""));
|
||||
cubeCards.add(new CardIdentity("Living Death", ""));
|
||||
cubeCards.add(new CardIdentity("Mind Twist", ""));
|
||||
cubeCards.add(new CardIdentity("Animate Dead", ""));
|
||||
cubeCards.add(new CardIdentity("Bitterblossom", ""));
|
||||
cubeCards.add(new CardIdentity("Necromancy", ""));
|
||||
cubeCards.add(new CardIdentity("Phyrexian Arena", ""));
|
||||
cubeCards.add(new CardIdentity("Recurring Nightmare", ""));
|
||||
cubeCards.add(new CardIdentity("Yawgmoth's Bargain", ""));
|
||||
cubeCards.add(new CardIdentity("Goblin Guide", ""));
|
||||
cubeCards.add(new CardIdentity("Goblin Welder", ""));
|
||||
cubeCards.add(new CardIdentity("Grim Lavamancer", ""));
|
||||
cubeCards.add(new CardIdentity("Jackal Pup", ""));
|
||||
cubeCards.add(new CardIdentity("Monastery Swiftspear", ""));
|
||||
cubeCards.add(new CardIdentity("Zurgo Bellstriker", ""));
|
||||
cubeCards.add(new CardIdentity("Abbot of Keral Keep", ""));
|
||||
cubeCards.add(new CardIdentity("Dire Fleet Daredevil", ""));
|
||||
cubeCards.add(new CardIdentity("Eidolon of the Great Revel", ""));
|
||||
cubeCards.add(new CardIdentity("Runaway Steam-Kin", ""));
|
||||
cubeCards.add(new CardIdentity("Young Pyromancer", ""));
|
||||
cubeCards.add(new CardIdentity("Goblin Rabblemaster", ""));
|
||||
cubeCards.add(new CardIdentity("Imperial Recruiter", ""));
|
||||
cubeCards.add(new CardIdentity("Magus of the Moon", ""));
|
||||
cubeCards.add(new CardIdentity("Avalanche Riders", ""));
|
||||
cubeCards.add(new CardIdentity("Flametongue Kavu", ""));
|
||||
cubeCards.add(new CardIdentity("Hazoret the Fervent", ""));
|
||||
cubeCards.add(new CardIdentity("Hellrider", ""));
|
||||
cubeCards.add(new CardIdentity("Pia and Kiran Nalaar", ""));
|
||||
cubeCards.add(new CardIdentity("Rekindling Phoenix", ""));
|
||||
cubeCards.add(new CardIdentity("Glorybringer", ""));
|
||||
cubeCards.add(new CardIdentity("Goblin Dark-Dwellers", ""));
|
||||
cubeCards.add(new CardIdentity("Kiki-Jiki, Mirror Breaker", ""));
|
||||
cubeCards.add(new CardIdentity("Siege-Gang Commander", ""));
|
||||
cubeCards.add(new CardIdentity("Thundermaw Hellkite", ""));
|
||||
cubeCards.add(new CardIdentity("Zealous Conscripts", ""));
|
||||
cubeCards.add(new CardIdentity("Inferno Titan", ""));
|
||||
cubeCards.add(new CardIdentity("Chandra, Torch of Defiance", ""));
|
||||
cubeCards.add(new CardIdentity("Daretti, Scrap Savant", ""));
|
||||
cubeCards.add(new CardIdentity("Koth of the Hammer", ""));
|
||||
cubeCards.add(new CardIdentity("Burst Lightning", ""));
|
||||
cubeCards.add(new CardIdentity("Lightning Bolt", ""));
|
||||
cubeCards.add(new CardIdentity("Abrade", ""));
|
||||
cubeCards.add(new CardIdentity("Ancient Grudge", ""));
|
||||
cubeCards.add(new CardIdentity("Desperate Ritual", ""));
|
||||
cubeCards.add(new CardIdentity("Fire // Ice", ""));
|
||||
cubeCards.add(new CardIdentity("Incinerate", ""));
|
||||
cubeCards.add(new CardIdentity("Lightning Strike", ""));
|
||||
cubeCards.add(new CardIdentity("Pyretic Ritual", ""));
|
||||
cubeCards.add(new CardIdentity("Char", ""));
|
||||
cubeCards.add(new CardIdentity("Seething Song", ""));
|
||||
cubeCards.add(new CardIdentity("Through the Breach", ""));
|
||||
cubeCards.add(new CardIdentity("Fireblast", ""));
|
||||
cubeCards.add(new CardIdentity("Chain Lightning", ""));
|
||||
cubeCards.add(new CardIdentity("Faithless Looting", ""));
|
||||
cubeCards.add(new CardIdentity("Firebolt", ""));
|
||||
cubeCards.add(new CardIdentity("Flame Slash", ""));
|
||||
cubeCards.add(new CardIdentity("Mizzium Mortars", ""));
|
||||
cubeCards.add(new CardIdentity("Pyroclasm", ""));
|
||||
cubeCards.add(new CardIdentity("Light Up the Stage", ""));
|
||||
cubeCards.add(new CardIdentity("Underworld Breach", ""));
|
||||
cubeCards.add(new CardIdentity("Wheel of Fortune", ""));
|
||||
cubeCards.add(new CardIdentity("Empty the Warrens", ""));
|
||||
cubeCards.add(new CardIdentity("Fiery Confluence", ""));
|
||||
cubeCards.add(new CardIdentity("Past in Flames", ""));
|
||||
cubeCards.add(new CardIdentity("Banefire", ""));
|
||||
cubeCards.add(new CardIdentity("Burning of Xinye", ""));
|
||||
cubeCards.add(new CardIdentity("Wildfire", ""));
|
||||
cubeCards.add(new CardIdentity("Bonfire of the Damned", ""));
|
||||
cubeCards.add(new CardIdentity("Mana Flare", ""));
|
||||
cubeCards.add(new CardIdentity("Sulfuric Vortex", ""));
|
||||
cubeCards.add(new CardIdentity("Sneak Attack", ""));
|
||||
cubeCards.add(new CardIdentity("Splinter Twin", ""));
|
||||
cubeCards.add(new CardIdentity("Arbor Elf", ""));
|
||||
cubeCards.add(new CardIdentity("Avacyn's Pilgrim", ""));
|
||||
cubeCards.add(new CardIdentity("Birds of Paradise", ""));
|
||||
cubeCards.add(new CardIdentity("Elves of Deep Shadow", ""));
|
||||
cubeCards.add(new CardIdentity("Elvish Mystic", ""));
|
||||
cubeCards.add(new CardIdentity("Fyndhorn Elves", ""));
|
||||
cubeCards.add(new CardIdentity("Joraga Treespeaker", ""));
|
||||
cubeCards.add(new CardIdentity("Llanowar Elves", ""));
|
||||
cubeCards.add(new CardIdentity("Noble Hierarch", ""));
|
||||
cubeCards.add(new CardIdentity("Den Protector", ""));
|
||||
cubeCards.add(new CardIdentity("Devoted Druid", ""));
|
||||
cubeCards.add(new CardIdentity("Fauna Shaman", ""));
|
||||
cubeCards.add(new CardIdentity("Gilded Goose", ""));
|
||||
cubeCards.add(new CardIdentity("Lotus Cobra", ""));
|
||||
cubeCards.add(new CardIdentity("Rofellos, Llanowar Emissary", ""));
|
||||
cubeCards.add(new CardIdentity("Sakura-Tribe Elder", ""));
|
||||
cubeCards.add(new CardIdentity("Scavenging Ooze", ""));
|
||||
cubeCards.add(new CardIdentity("Sylvan Caryatid", ""));
|
||||
cubeCards.add(new CardIdentity("Wall of Blossoms", ""));
|
||||
cubeCards.add(new CardIdentity("Wall of Roots", ""));
|
||||
cubeCards.add(new CardIdentity("Courser of Kruphix", ""));
|
||||
cubeCards.add(new CardIdentity("Eternal Witness", ""));
|
||||
cubeCards.add(new CardIdentity("Ramunap Excavator", ""));
|
||||
cubeCards.add(new CardIdentity("Reclamation Sage", ""));
|
||||
cubeCards.add(new CardIdentity("Tireless Tracker", ""));
|
||||
cubeCards.add(new CardIdentity("Yavimaya Elder", ""));
|
||||
cubeCards.add(new CardIdentity("Master of the Wild Hunt", ""));
|
||||
cubeCards.add(new CardIdentity("Oracle of Mul Daya", ""));
|
||||
cubeCards.add(new CardIdentity("Polukranos, World Eater", ""));
|
||||
cubeCards.add(new CardIdentity("Acidic Slime", ""));
|
||||
cubeCards.add(new CardIdentity("Biogenic Ooze", ""));
|
||||
cubeCards.add(new CardIdentity("Deranged Hermit", ""));
|
||||
cubeCards.add(new CardIdentity("Thragtusk", ""));
|
||||
cubeCards.add(new CardIdentity("Whisperwood Elemental", ""));
|
||||
cubeCards.add(new CardIdentity("Carnage Tyrant", ""));
|
||||
cubeCards.add(new CardIdentity("Primeval Titan", ""));
|
||||
cubeCards.add(new CardIdentity("Avenger of Zendikar", ""));
|
||||
cubeCards.add(new CardIdentity("Craterhoof Behemoth", ""));
|
||||
cubeCards.add(new CardIdentity("Terastodon", ""));
|
||||
cubeCards.add(new CardIdentity("Woodfall Primus", ""));
|
||||
cubeCards.add(new CardIdentity("Dryad of the Ilysian Grove", ""));
|
||||
cubeCards.add(new CardIdentity("Garruk Relentless", ""));
|
||||
cubeCards.add(new CardIdentity("Garruk Wildspeaker", ""));
|
||||
cubeCards.add(new CardIdentity("Garruk, Primal Hunter", ""));
|
||||
cubeCards.add(new CardIdentity("Vivien Reid", ""));
|
||||
cubeCards.add(new CardIdentity("Nature's Claim", ""));
|
||||
cubeCards.add(new CardIdentity("Beast Within", ""));
|
||||
cubeCards.add(new CardIdentity("Channel", ""));
|
||||
cubeCards.add(new CardIdentity("Regrowth", ""));
|
||||
cubeCards.add(new CardIdentity("Kodama's Reach", ""));
|
||||
cubeCards.add(new CardIdentity("Search for Tomorrow", ""));
|
||||
cubeCards.add(new CardIdentity("Eureka", ""));
|
||||
cubeCards.add(new CardIdentity("Harmonize", ""));
|
||||
cubeCards.add(new CardIdentity("Natural Order", ""));
|
||||
cubeCards.add(new CardIdentity("Plow Under", ""));
|
||||
cubeCards.add(new CardIdentity("Primal Command", ""));
|
||||
cubeCards.add(new CardIdentity("Green Sun's Zenith", ""));
|
||||
cubeCards.add(new CardIdentity("Finale of Devastation", ""));
|
||||
cubeCards.add(new CardIdentity("Tooth and Nail", ""));
|
||||
cubeCards.add(new CardIdentity("Fastbond", ""));
|
||||
cubeCards.add(new CardIdentity("Oath of Druids", ""));
|
||||
cubeCards.add(new CardIdentity("Survival of the Fittest", ""));
|
||||
cubeCards.add(new CardIdentity("Sylvan Library", ""));
|
||||
cubeCards.add(new CardIdentity("Heartbeat of Spring", ""));
|
||||
cubeCards.add(new CardIdentity("Wilderness Reclamation", ""));
|
||||
cubeCards.add(new CardIdentity("Gaea's Cradle", ""));
|
||||
cubeCards.add(new CardIdentity("Geist of Saint Traft", ""));
|
||||
cubeCards.add(new CardIdentity("Teferi, Hero of Dominaria", ""));
|
||||
cubeCards.add(new CardIdentity("Sphinx's Revelation", ""));
|
||||
cubeCards.add(new CardIdentity("Fractured Identity", ""));
|
||||
cubeCards.add(new CardIdentity("Celestial Colonnade", ""));
|
||||
cubeCards.add(new CardIdentity("Flooded Strand", ""));
|
||||
cubeCards.add(new CardIdentity("Hallowed Fountain", ""));
|
||||
cubeCards.add(new CardIdentity("Seachrome Coast", ""));
|
||||
cubeCards.add(new CardIdentity("Tundra", ""));
|
||||
cubeCards.add(new CardIdentity("Thief of Sanity", ""));
|
||||
cubeCards.add(new CardIdentity("The Scarab God", ""));
|
||||
cubeCards.add(new CardIdentity("Ashiok, Nightmare Weaver", ""));
|
||||
cubeCards.add(new CardIdentity("Baleful Strix", ""));
|
||||
cubeCards.add(new CardIdentity("Creeping Tar Pit", ""));
|
||||
cubeCards.add(new CardIdentity("Darkslick Shores", ""));
|
||||
cubeCards.add(new CardIdentity("Polluted Delta", ""));
|
||||
cubeCards.add(new CardIdentity("Underground Sea", ""));
|
||||
cubeCards.add(new CardIdentity("Watery Grave", ""));
|
||||
cubeCards.add(new CardIdentity("Daretti, Ingenious Iconoclast", ""));
|
||||
cubeCards.add(new CardIdentity("Kroxa, Titan of Death's Hunger", ""));
|
||||
cubeCards.add(new CardIdentity("Kolaghan's Command", ""));
|
||||
cubeCards.add(new CardIdentity("Rakdos's Return", ""));
|
||||
cubeCards.add(new CardIdentity("Badlands", ""));
|
||||
cubeCards.add(new CardIdentity("Blackcleave Cliffs", ""));
|
||||
cubeCards.add(new CardIdentity("Blood Crypt", ""));
|
||||
cubeCards.add(new CardIdentity("Bloodstained Mire", ""));
|
||||
cubeCards.add(new CardIdentity("Lavaclaw Reaches", ""));
|
||||
cubeCards.add(new CardIdentity("Bloodbraid Elf", ""));
|
||||
cubeCards.add(new CardIdentity("Huntmaster of the Fells", ""));
|
||||
cubeCards.add(new CardIdentity("Dragonlord Atarka", ""));
|
||||
cubeCards.add(new CardIdentity("Manamorphose", ""));
|
||||
cubeCards.add(new CardIdentity("Copperline Gorge", ""));
|
||||
cubeCards.add(new CardIdentity("Raging Ravine", ""));
|
||||
cubeCards.add(new CardIdentity("Stomping Ground", ""));
|
||||
cubeCards.add(new CardIdentity("Taiga", ""));
|
||||
cubeCards.add(new CardIdentity("Wooded Foothills", ""));
|
||||
cubeCards.add(new CardIdentity("Kitchen Finks", ""));
|
||||
cubeCards.add(new CardIdentity("Knight of Autumn", ""));
|
||||
cubeCards.add(new CardIdentity("Knight of the Reliquary", ""));
|
||||
cubeCards.add(new CardIdentity("Trostani Discordant", ""));
|
||||
cubeCards.add(new CardIdentity("Mirari's Wake", ""));
|
||||
cubeCards.add(new CardIdentity("Razorverge Thicket", ""));
|
||||
cubeCards.add(new CardIdentity("Savannah", ""));
|
||||
cubeCards.add(new CardIdentity("Stirring Wildwood", ""));
|
||||
cubeCards.add(new CardIdentity("Temple Garden", ""));
|
||||
cubeCards.add(new CardIdentity("Windswept Heath", ""));
|
||||
cubeCards.add(new CardIdentity("Ashen Rider", ""));
|
||||
cubeCards.add(new CardIdentity("Kaya, Orzhov Usurper", ""));
|
||||
cubeCards.add(new CardIdentity("Tidehollow Sculler", ""));
|
||||
cubeCards.add(new CardIdentity("Anguished Unmaking", ""));
|
||||
cubeCards.add(new CardIdentity("Lingering Souls", ""));
|
||||
cubeCards.add(new CardIdentity("Vindicate", ""));
|
||||
cubeCards.add(new CardIdentity("Unburial Rites", ""));
|
||||
cubeCards.add(new CardIdentity("Concealed Courtyard", ""));
|
||||
cubeCards.add(new CardIdentity("Godless Shrine", ""));
|
||||
cubeCards.add(new CardIdentity("Marsh Flats", ""));
|
||||
cubeCards.add(new CardIdentity("Scrubland", ""));
|
||||
cubeCards.add(new CardIdentity("Shambling Vent", ""));
|
||||
cubeCards.add(new CardIdentity("Vraska, Golgari Queen", ""));
|
||||
cubeCards.add(new CardIdentity("Assassin's Trophy", ""));
|
||||
cubeCards.add(new CardIdentity("Maelstrom Pulse", ""));
|
||||
cubeCards.add(new CardIdentity("Pernicious Deed", ""));
|
||||
cubeCards.add(new CardIdentity("Bayou", ""));
|
||||
cubeCards.add(new CardIdentity("Blooming Marsh", ""));
|
||||
cubeCards.add(new CardIdentity("Hissing Quagmire", ""));
|
||||
cubeCards.add(new CardIdentity("Overgrown Tomb", ""));
|
||||
cubeCards.add(new CardIdentity("Verdant Catacombs", ""));
|
||||
cubeCards.add(new CardIdentity("Edric, Spymaster of Trest", ""));
|
||||
cubeCards.add(new CardIdentity("Trygon Predator", ""));
|
||||
cubeCards.add(new CardIdentity("Hydroid Krasis", ""));
|
||||
cubeCards.add(new CardIdentity("Uro, Titan of Nature's Wrath", ""));
|
||||
cubeCards.add(new CardIdentity("Botanical Sanctum", ""));
|
||||
cubeCards.add(new CardIdentity("Breeding Pool", ""));
|
||||
cubeCards.add(new CardIdentity("Lumbering Falls", ""));
|
||||
cubeCards.add(new CardIdentity("Misty Rainforest", ""));
|
||||
cubeCards.add(new CardIdentity("Tropical Island", ""));
|
||||
cubeCards.add(new CardIdentity("Goblin Electromancer", ""));
|
||||
cubeCards.add(new CardIdentity("Dack Fayden", ""));
|
||||
cubeCards.add(new CardIdentity("Thousand-Year Storm", ""));
|
||||
cubeCards.add(new CardIdentity("Scalding Tarn", ""));
|
||||
cubeCards.add(new CardIdentity("Spirebluff Canal", ""));
|
||||
cubeCards.add(new CardIdentity("Steam Vents", ""));
|
||||
cubeCards.add(new CardIdentity("Volcanic Island", ""));
|
||||
cubeCards.add(new CardIdentity("Wandering Fumarole", ""));
|
||||
cubeCards.add(new CardIdentity("Figure of Destiny", ""));
|
||||
cubeCards.add(new CardIdentity("Ajani Vengeant", ""));
|
||||
cubeCards.add(new CardIdentity("Nahiri, the Harbinger", ""));
|
||||
cubeCards.add(new CardIdentity("Wear // Tear", ""));
|
||||
cubeCards.add(new CardIdentity("Lightning Helix", ""));
|
||||
cubeCards.add(new CardIdentity("Arid Mesa", ""));
|
||||
cubeCards.add(new CardIdentity("Inspiring Vantage", ""));
|
||||
cubeCards.add(new CardIdentity("Needle Spires", ""));
|
||||
cubeCards.add(new CardIdentity("Plateau", ""));
|
||||
cubeCards.add(new CardIdentity("Sacred Foundry", ""));
|
||||
cubeCards.add(new CardIdentity("Sphinx of the Steel Wind", ""));
|
||||
cubeCards.add(new CardIdentity("Nicol Bolas, Dragon-God", ""));
|
||||
cubeCards.add(new CardIdentity("Leovold, Emissary of Trest", ""));
|
||||
cubeCards.add(new CardIdentity("Progenitus", ""));
|
||||
cubeCards.add(new CardIdentity("Kozilek, Butcher of Truth", ""));
|
||||
cubeCards.add(new CardIdentity("Ulamog, the Ceaseless Hunger", ""));
|
||||
cubeCards.add(new CardIdentity("Ulamog, the Infinite Gyre", ""));
|
||||
cubeCards.add(new CardIdentity("Emrakul, the Promised End", ""));
|
||||
cubeCards.add(new CardIdentity("Emrakul, the Aeons Torn", ""));
|
||||
cubeCards.add(new CardIdentity("Karn, Scion of Urza", ""));
|
||||
cubeCards.add(new CardIdentity("Karn Liberated", ""));
|
||||
cubeCards.add(new CardIdentity("Ugin, the Spirit Dragon", ""));
|
||||
cubeCards.add(new CardIdentity("Bomat Courier", ""));
|
||||
cubeCards.add(new CardIdentity("Hangarback Walker", ""));
|
||||
cubeCards.add(new CardIdentity("Phyrexian Revoker", ""));
|
||||
cubeCards.add(new CardIdentity("Metalworker", ""));
|
||||
cubeCards.add(new CardIdentity("Lodestone Golem", ""));
|
||||
cubeCards.add(new CardIdentity("Solemn Simulacrum", ""));
|
||||
cubeCards.add(new CardIdentity("Kuldotha Forgemaster", ""));
|
||||
cubeCards.add(new CardIdentity("Wurmcoil Engine", ""));
|
||||
cubeCards.add(new CardIdentity("Myr Battlesphere", ""));
|
||||
cubeCards.add(new CardIdentity("Sundering Titan", ""));
|
||||
cubeCards.add(new CardIdentity("Walking Ballista", ""));
|
||||
cubeCards.add(new CardIdentity("Blightsteel Colossus", ""));
|
||||
cubeCards.add(new CardIdentity("Black Lotus", ""));
|
||||
cubeCards.add(new CardIdentity("Chrome Mox", ""));
|
||||
cubeCards.add(new CardIdentity("Everflowing Chalice", ""));
|
||||
cubeCards.add(new CardIdentity("Lion's Eye Diamond", ""));
|
||||
cubeCards.add(new CardIdentity("Lotus Bloom", ""));
|
||||
cubeCards.add(new CardIdentity("Mana Crypt", ""));
|
||||
cubeCards.add(new CardIdentity("Mox Diamond", ""));
|
||||
cubeCards.add(new CardIdentity("Mox Emerald", ""));
|
||||
cubeCards.add(new CardIdentity("Mox Jet", ""));
|
||||
cubeCards.add(new CardIdentity("Mox Pearl", ""));
|
||||
cubeCards.add(new CardIdentity("Mox Ruby", ""));
|
||||
cubeCards.add(new CardIdentity("Mox Sapphire", ""));
|
||||
cubeCards.add(new CardIdentity("Mana Vault", ""));
|
||||
cubeCards.add(new CardIdentity("Relic of Progenitus", ""));
|
||||
cubeCards.add(new CardIdentity("Sensei's Divining Top", ""));
|
||||
cubeCards.add(new CardIdentity("Skullclamp", ""));
|
||||
cubeCards.add(new CardIdentity("Sol Ring", ""));
|
||||
cubeCards.add(new CardIdentity("Azorius Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Boros Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Dimir Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Golgari Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Grim Monolith", ""));
|
||||
cubeCards.add(new CardIdentity("Gruul Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Izzet Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Lightning Greaves", ""));
|
||||
cubeCards.add(new CardIdentity("Orzhov Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Rakdos Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Selesnya Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Shrine of Burning Rage", ""));
|
||||
cubeCards.add(new CardIdentity("Simic Signet", ""));
|
||||
cubeCards.add(new CardIdentity("Smuggler's Copter", ""));
|
||||
cubeCards.add(new CardIdentity("Umezawa's Jitte", ""));
|
||||
cubeCards.add(new CardIdentity("Winter Orb", ""));
|
||||
cubeCards.add(new CardIdentity("Basalt Monolith", ""));
|
||||
cubeCards.add(new CardIdentity("Coalition Relic", ""));
|
||||
cubeCards.add(new CardIdentity("Crucible of Worlds", ""));
|
||||
cubeCards.add(new CardIdentity("Oblivion Stone", ""));
|
||||
cubeCards.add(new CardIdentity("Sword of Body and Mind", ""));
|
||||
cubeCards.add(new CardIdentity("Sword of Feast and Famine", ""));
|
||||
cubeCards.add(new CardIdentity("Sword of Fire and Ice", ""));
|
||||
cubeCards.add(new CardIdentity("Sword of Light and Shadow", ""));
|
||||
cubeCards.add(new CardIdentity("Sword of War and Peace", ""));
|
||||
cubeCards.add(new CardIdentity("Tangle Wire", ""));
|
||||
cubeCards.add(new CardIdentity("Worn Powerstone", ""));
|
||||
cubeCards.add(new CardIdentity("Coercive Portal", ""));
|
||||
cubeCards.add(new CardIdentity("Smokestack", ""));
|
||||
cubeCards.add(new CardIdentity("Thran Dynamo", ""));
|
||||
cubeCards.add(new CardIdentity("Batterskull", ""));
|
||||
cubeCards.add(new CardIdentity("Memory Jar", ""));
|
||||
cubeCards.add(new CardIdentity("Mindslaver", ""));
|
||||
cubeCards.add(new CardIdentity("Academy Ruins", ""));
|
||||
cubeCards.add(new CardIdentity("Ancient Tomb", ""));
|
||||
cubeCards.add(new CardIdentity("Bazaar of Baghdad", ""));
|
||||
cubeCards.add(new CardIdentity("Blast Zone", ""));
|
||||
cubeCards.add(new CardIdentity("Field of Ruin", ""));
|
||||
cubeCards.add(new CardIdentity("Library of Alexandria", ""));
|
||||
cubeCards.add(new CardIdentity("Maze of Ith", ""));
|
||||
cubeCards.add(new CardIdentity("Mishra's Factory", ""));
|
||||
cubeCards.add(new CardIdentity("Mishra's Workshop", ""));
|
||||
cubeCards.add(new CardIdentity("Mutavault", ""));
|
||||
cubeCards.add(new CardIdentity("Nykthos, Shrine to Nyx", ""));
|
||||
cubeCards.add(new CardIdentity("Rishadan Port", ""));
|
||||
cubeCards.add(new CardIdentity("Strip Mine", ""));
|
||||
cubeCards.add(new CardIdentity("Wasteland", ""));
|
||||
cubeCards.add(new CardIdentity("Expansion // Explosion", ""));
|
||||
cubeCards.add(new CardIdentity("Giver of Runes", ""));
|
||||
cubeCards.add(new CardIdentity("Winds of Abandon", ""));
|
||||
cubeCards.add(new CardIdentity("Hallowed Spiritkeeper", ""));
|
||||
cubeCards.add(new CardIdentity("Thraben Inspector", ""));
|
||||
cubeCards.add(new CardIdentity("Narset, Parter of Veils", ""));
|
||||
cubeCards.add(new CardIdentity("Force of Negation", ""));
|
||||
cubeCards.add(new CardIdentity("Urza, Lord High Artificer", ""));
|
||||
cubeCards.add(new CardIdentity("Emry, Lurker of the Loch", ""));
|
||||
cubeCards.add(new CardIdentity("Brazen Borrower", ""));
|
||||
cubeCards.add(new CardIdentity("Bolas's Citadel", ""));
|
||||
cubeCards.add(new CardIdentity("Yawgmoth, Thran Physician", ""));
|
||||
cubeCards.add(new CardIdentity("Rotting Regisaur", ""));
|
||||
cubeCards.add(new CardIdentity("Murderous Rider", ""));
|
||||
cubeCards.add(new CardIdentity("Wishclaw Talisman", ""));
|
||||
cubeCards.add(new CardIdentity("Dreadhorde Arcanist", ""));
|
||||
cubeCards.add(new CardIdentity("Seasoned Pyromancer", ""));
|
||||
cubeCards.add(new CardIdentity("Embereth Shieldbreaker", ""));
|
||||
cubeCards.add(new CardIdentity("Nissa, Who Shakes the World", ""));
|
||||
cubeCards.add(new CardIdentity("Questing Beast", ""));
|
||||
cubeCards.add(new CardIdentity("Teferi, Time Raveler", ""));
|
||||
cubeCards.add(new CardIdentity("Angrath's Rampage", ""));
|
||||
cubeCards.add(new CardIdentity("Fallen Shinobi", ""));
|
||||
cubeCards.add(new CardIdentity("Wrenn and Six", ""));
|
||||
cubeCards.add(new CardIdentity("Oko, Thief of Crowns", ""));
|
||||
cubeCards.add(new CardIdentity("Garruk, Cursed Huntsman", ""));
|
||||
cubeCards.add(new CardIdentity("Prismatic Vista", ""));
|
||||
cubeCards.add(new CardIdentity("Golos, Tireless Pilgrim", ""));
|
||||
cubeCards.add(new CardIdentity("Stonecoil Serpent", ""));
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-tournament-constructed</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-tournament-sealed</artifactId>
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
|
||||
package mage.tournament;
|
||||
|
||||
import mage.game.tournament.TournamentOptions;
|
||||
import mage.game.tournament.TournamentSingleElimination;
|
||||
|
||||
public class JumpstartEliminationTournament extends TournamentSingleElimination {
|
||||
|
||||
protected enum TournamentStep {
|
||||
START, OPEN_BOOSTERS, CONSTRUCT, COMPETE, WINNERS
|
||||
}
|
||||
|
||||
protected TournamentStep currentStep;
|
||||
|
||||
public JumpstartEliminationTournament(TournamentOptions options) {
|
||||
super(options);
|
||||
currentStep = TournamentStep.START;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextStep() {
|
||||
switch (currentStep) {
|
||||
case START:
|
||||
currentStep = TournamentStep.OPEN_BOOSTERS;
|
||||
openBoosters();
|
||||
break;
|
||||
case OPEN_BOOSTERS:
|
||||
currentStep = TournamentStep.CONSTRUCT;
|
||||
construct();
|
||||
break;
|
||||
case CONSTRUCT:
|
||||
currentStep = TournamentStep.COMPETE;
|
||||
runTournament();
|
||||
break;
|
||||
case COMPETE:
|
||||
currentStep = TournamentStep.WINNERS;
|
||||
winners();
|
||||
end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
|
||||
package mage.tournament;
|
||||
|
||||
import mage.game.tournament.TournamentType;
|
||||
|
||||
public class JumpstartEliminationTournamentType extends TournamentType {
|
||||
|
||||
public JumpstartEliminationTournamentType() {
|
||||
this.name = "Jumpstart Elimination";
|
||||
this.maxPlayers = 16;
|
||||
this.minPlayers = 2;
|
||||
this.numBoosters = 0;
|
||||
this.isJumpstart = true;
|
||||
this.elimination = true;
|
||||
this.limited = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
|
||||
package mage.tournament;
|
||||
|
||||
import mage.game.tournament.TournamentOptions;
|
||||
import mage.game.tournament.TournamentSwiss;
|
||||
|
||||
public class JumpstartSwissTournament extends TournamentSwiss {
|
||||
|
||||
protected enum TournamentStep {
|
||||
START, OPEN_BOOSTERS, CONSTRUCT, COMPETE, WINNERS
|
||||
}
|
||||
|
||||
protected TournamentStep currentStep;
|
||||
|
||||
public JumpstartSwissTournament(TournamentOptions options) {
|
||||
super(options);
|
||||
currentStep = TournamentStep.START;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextStep() {
|
||||
switch (currentStep) {
|
||||
case START:
|
||||
currentStep = TournamentStep.OPEN_BOOSTERS;
|
||||
openBoosters();
|
||||
break;
|
||||
case OPEN_BOOSTERS:
|
||||
currentStep = TournamentStep.CONSTRUCT;
|
||||
construct();
|
||||
break;
|
||||
case CONSTRUCT:
|
||||
currentStep = TournamentStep.COMPETE;
|
||||
runTournament();
|
||||
break;
|
||||
case COMPETE:
|
||||
currentStep = TournamentStep.WINNERS;
|
||||
winners();
|
||||
end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
|
||||
package mage.tournament;
|
||||
|
||||
import mage.game.tournament.TournamentType;
|
||||
|
||||
public class JumpstartSwissTournamentType extends TournamentType {
|
||||
|
||||
public JumpstartSwissTournamentType() {
|
||||
this.name = "Jumpstart Swiss";
|
||||
this.maxPlayers = 16;
|
||||
this.minPlayers = 2;
|
||||
this.numBoosters = 0;
|
||||
this.isJumpstart = true;
|
||||
this.limited = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-server-plugins</artifactId>
|
||||
|
|
|
@ -56,13 +56,13 @@
|
|||
saveGameActivated="false"
|
||||
authenticationActivated="false"
|
||||
googleAccount=""
|
||||
mailgunApiKey="key-d93e81f19a9c9ed243ebb7cc9381385c"
|
||||
mailgunDomain="sandbox401a433f30d445309a5e86b6c53f7812.mailgun.org"
|
||||
mailSmtpHost="smtp.1und1.de"
|
||||
mailSmtpPort="465"
|
||||
mailUser="xmageserver@online.de"
|
||||
mailPassword="24wrsfxv"
|
||||
mailFromAddress="xmageserver@online.de"
|
||||
mailgunApiKey=""
|
||||
mailgunDomain=""
|
||||
mailSmtpHost=""
|
||||
mailSmtpPort=""
|
||||
mailUser=""
|
||||
mailPassword=""
|
||||
mailFromAddress=""
|
||||
/>
|
||||
<playerTypes>
|
||||
<playerType name="Human" jar="mage-player-human.jar" className="mage.player.human.HumanPlayer"/>
|
||||
|
@ -104,6 +104,8 @@
|
|||
<tournamentType name="Sealed Elimination (Cube)" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedEliminationTournament" typeName="mage.tournament.SealedEliminationCubeTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss (Cube)" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissCubeTournamentType"/>
|
||||
<tournamentType name="Jumpstart Elimination" jar="mage-tournament-sealed.jar" className="mage.tournament.JumpstartEliminationTournament" typeName="mage.tournament.JumpstartEliminationTournamentType"/>
|
||||
<tournamentType name="Jumpstart Swiss" jar="mage-tournament-sealed.jar" className="mage.tournament.JumpstartSwissTournament" typeName="mage.tournament.JumpstartSwissTournamentType"/>
|
||||
</tournamentTypes>
|
||||
<draftCubes>
|
||||
<draftCube name="Adam Styborski's Pauper Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.AdamStyborskisPauperCube"/>
|
||||
|
@ -143,6 +145,7 @@
|
|||
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2018"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2019"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
|
||||
<draftCube name="MTGO Vintage Cube April 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeApril2020"/>
|
||||
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
|
||||
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
|
||||
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-server</artifactId>
|
||||
|
|
|
@ -98,6 +98,8 @@
|
|||
<tournamentType name="Sealed Elimination (Cube)" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.SealedEliminationTournament" typeName="mage.tournament.SealedEliminationCubeTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss (Cube)" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissCubeTournamentType"/>
|
||||
<tournamentType name="Jumpstart Elimination" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.JumpstartEliminationTournament" typeName="mage.tournament.JumpstartEliminationTournamentType"/>
|
||||
<tournamentType name="Jumpstart Swiss" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.JumpstartSwissTournament" typeName="mage.tournament.JumpstartSwissTournamentType"/>
|
||||
</tournamentTypes>
|
||||
<draftCubes>
|
||||
<draftCube name="Adam Styborski's Pauper Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.AdamStyborskisPauperCube"/>
|
||||
|
@ -137,6 +139,7 @@
|
|||
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2018"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2019"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
|
||||
<draftCube name="MTGO Vintage Cube April 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeApril2020"/>
|
||||
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
|
||||
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
|
||||
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGCube"/>
|
||||
|
|
|
@ -397,15 +397,15 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
//FIXME: why no sessionId here???
|
||||
public Optional<TableView> getTable(UUID roomId, UUID tableId) throws MageException {
|
||||
public TableView getTable(UUID roomId, UUID tableId) throws MageException {
|
||||
try {
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
return room.flatMap(r -> r.getTable(tableId));
|
||||
return room.flatMap(r -> r.getTable(tableId)).orElse(null);
|
||||
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -536,18 +536,18 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
//FIXME: why no sessionId here???
|
||||
public Optional<UUID> getRoomChatId(UUID roomId) throws MageException {
|
||||
public UUID getRoomChatId(UUID roomId) throws MageException {
|
||||
try {
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
if (!room.isPresent()) {
|
||||
logger.error("roomId not found : " + roomId);
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
return Optional.of(room.get().getChatId());
|
||||
return room.get().getChatId();
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -602,13 +602,13 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
//FIXME: why no sessionId here???
|
||||
public Optional<UUID> getTableChatId(UUID tableId) throws MageException {
|
||||
public UUID getTableChatId(UUID tableId) throws MageException {
|
||||
try {
|
||||
return TableManager.instance.getChatId(tableId);
|
||||
return TableManager.instance.getChatId(tableId).orElse(null);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -646,24 +646,24 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
//FIXME: why no sessionId here???
|
||||
public Optional<UUID> getGameChatId(UUID gameId) throws MageException {
|
||||
public UUID getGameChatId(UUID gameId) throws MageException {
|
||||
try {
|
||||
return GameManager.instance.getChatId(gameId);
|
||||
return GameManager.instance.getChatId(gameId).orElse(null);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
//FIXME: why no sessionId here???
|
||||
public Optional<UUID> getTournamentChatId(UUID tournamentId) throws MageException {
|
||||
public UUID getTournamentChatId(UUID tournamentId) throws MageException {
|
||||
try {
|
||||
return TournamentManager.instance.getChatId(tournamentId);
|
||||
return TournamentManager.instance.getChatId(tournamentId).orElse(null);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1259,10 +1259,10 @@ public class GameController implements GameCallback {
|
|||
.collect(Collectors.joining(", ")));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<font color='red'>FIX command called by " + user.getName() + "</font>");
|
||||
sb.append("<font color='red'>FIX command called by ").append(user.getName()).append("</font>");
|
||||
sb.append("<font size='-2'>"); // font resize start for all next logs
|
||||
sb.append("<br>Game ID: " + game.getId());
|
||||
|
||||
sb.append("<br>Game ID: ").append(game.getId());
|
||||
sb.append("<br>Phase: ").append(game.getTurn().getPhaseType().toString()).append(" Step: ").append(game.getTurn().getStepType().toString());
|
||||
// pings info
|
||||
sb.append("<br>");
|
||||
sb.append(getPingsInfo());
|
||||
|
@ -1272,7 +1272,7 @@ public class GameController implements GameCallback {
|
|||
|
||||
// fix active
|
||||
Player playerActive = game.getPlayer(state.getActivePlayerId());
|
||||
sb.append("<br>Fixing active player: " + getName(playerActive));
|
||||
sb.append("<br>Fixing active player: ").append(getName(playerActive));
|
||||
if (playerActive != null && !playerActive.canRespond()) {
|
||||
fixActions.add("active player fix");
|
||||
|
||||
|
@ -1280,16 +1280,16 @@ public class GameController implements GameCallback {
|
|||
sb.append("<br>Try to concede...");
|
||||
playerActive.concede(game);
|
||||
playerActive.leave(); // abort any wait response actions
|
||||
sb.append(" (" + asWarning("OK") + ", concede done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", concede done)");
|
||||
|
||||
sb.append("<br>Try to skip step...");
|
||||
Phase currentPhase = game.getPhase();
|
||||
if (currentPhase != null) {
|
||||
currentPhase.getStep().skipStep(game, state.getActivePlayerId());
|
||||
fixedAlready = true;
|
||||
sb.append(" (" + asWarning("OK") + ", skip step done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", skip step done)");
|
||||
} else {
|
||||
sb.append(" (" + asBad("FAIL") + ", step is null)");
|
||||
sb.append(" (").append(asBad("FAIL")).append(", step is null)");
|
||||
}
|
||||
} else {
|
||||
sb.append(playerActive != null ? " (" + asGood("OK") + ", can respond)" : " (" + asGood("OK") + ", no player)");
|
||||
|
@ -1297,7 +1297,7 @@ public class GameController implements GameCallback {
|
|||
|
||||
// fix lost choosing dialog
|
||||
Player choosingPlayer = game.getPlayer(state.getChoosingPlayerId());
|
||||
sb.append("<br>Fixing choosing player: " + getName(choosingPlayer));
|
||||
sb.append("<br>Fixing choosing player: ").append(getName(choosingPlayer));
|
||||
if (choosingPlayer != null && !choosingPlayer.canRespond()) {
|
||||
fixActions.add("choosing player fix");
|
||||
|
||||
|
@ -1305,7 +1305,7 @@ public class GameController implements GameCallback {
|
|||
sb.append("<br>Try to concede...");
|
||||
choosingPlayer.concede(game);
|
||||
choosingPlayer.leave(); // abort any wait response actions
|
||||
sb.append(" (" + asWarning("OK") + ", concede done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", concede done)");
|
||||
|
||||
sb.append("<br>Try to skip step...");
|
||||
if (fixedAlready) {
|
||||
|
@ -1315,9 +1315,9 @@ public class GameController implements GameCallback {
|
|||
if (currentPhase != null) {
|
||||
currentPhase.getStep().skipStep(game, state.getActivePlayerId());
|
||||
fixedAlready = true;
|
||||
sb.append(" (" + asWarning("OK") + ", skip step done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", skip step done)");
|
||||
} else {
|
||||
sb.append(" (" + asBad("FAIL") + ", step is null)");
|
||||
sb.append(" (").append(asBad("FAIL")).append(", step is null)");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1326,7 +1326,7 @@ public class GameController implements GameCallback {
|
|||
|
||||
// fix lost priority
|
||||
Player priorityPlayer = game.getPlayer(state.getPriorityPlayerId());
|
||||
sb.append("<br>Fixing priority player: " + getName(priorityPlayer));
|
||||
sb.append("<br>Fixing priority player: ").append(getName(priorityPlayer));
|
||||
if (priorityPlayer != null && !priorityPlayer.canRespond()) {
|
||||
fixActions.add("priority player fix");
|
||||
|
||||
|
@ -1334,19 +1334,19 @@ public class GameController implements GameCallback {
|
|||
sb.append("<br>Try to concede...");
|
||||
priorityPlayer.concede(game);
|
||||
priorityPlayer.leave(); // abort any wait response actions
|
||||
sb.append(" (" + asWarning("OK") + ", concede done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", concede done)");
|
||||
|
||||
sb.append("<br>Try to skip step...");
|
||||
if (fixedAlready) {
|
||||
sb.append(" (" + asWarning("OK") + ", already skipped before)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", already skipped before)");
|
||||
} else {
|
||||
Phase currentPhase = game.getPhase();
|
||||
if (currentPhase != null) {
|
||||
currentPhase.getStep().skipStep(game, state.getActivePlayerId());
|
||||
fixedAlready = true;
|
||||
sb.append(" (" + asWarning("OK") + ", skip step done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", skip step done)");
|
||||
} else {
|
||||
sb.append(" (" + asBad("FAIL") + ", step is null)");
|
||||
sb.append(" (").append(asBad("FAIL")).append(", step is null)");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1356,10 +1356,10 @@ public class GameController implements GameCallback {
|
|||
// fix timeout
|
||||
sb.append("<br>Fixing future timeout: ");
|
||||
if (futureTimeout != null) {
|
||||
sb.append("cancelled?=" + futureTimeout.isCancelled());
|
||||
sb.append("...done?=" + futureTimeout.isDone());
|
||||
sb.append("cancelled?=").append(futureTimeout.isCancelled());
|
||||
sb.append("...done?=").append(futureTimeout.isDone());
|
||||
int delay = (int) futureTimeout.getDelay(TimeUnit.SECONDS);
|
||||
sb.append("...getDelay?=" + delay);
|
||||
sb.append("...getDelay?=").append(delay);
|
||||
if (delay < 25) {
|
||||
fixActions.add("future timeout fix");
|
||||
|
||||
|
@ -1367,12 +1367,12 @@ public class GameController implements GameCallback {
|
|||
sb.append("<br>Try to pass...");
|
||||
PassAbility pass = new PassAbility();
|
||||
game.endTurn(pass);
|
||||
sb.append(" (" + asWarning("OK") + ", pass done)");
|
||||
sb.append(" (").append(asWarning("OK")).append(", pass done)");
|
||||
} else {
|
||||
sb.append(" (" + asGood("OK") + ", delay > 25)");
|
||||
sb.append(" (").append(asGood("OK")).append(", delay > 25)");
|
||||
}
|
||||
} else {
|
||||
sb.append(" (" + asGood("OK") + ", timeout is not using)");
|
||||
sb.append(" (").append(asGood("OK")).append(", timeout is not using)");
|
||||
}
|
||||
|
||||
// TODO: fix non started game (send game started event to user?)
|
||||
|
@ -1382,7 +1382,7 @@ public class GameController implements GameCallback {
|
|||
fixActions.add("none");
|
||||
}
|
||||
String appliedFixes = fixActions.stream().collect(Collectors.joining(", "));
|
||||
sb.append("<br>Applied fixes: " + appliedFixes);
|
||||
sb.append("<br>Applied fixes: ").append(appliedFixes);
|
||||
sb.append("</font>"); // font resize end
|
||||
sb.append("<br>");
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ public final class SystemUtil {
|
|||
}
|
||||
|
||||
private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card]
|
||||
private static final Pattern patternCommand = Pattern.compile("([\\w]+):([\\S]+?):([\\S ]+):([\\d]+)"); // battlefield:Human:Island:10
|
||||
private static final Pattern patternCommand = Pattern.compile("([\\w]+):([\\S ]+?):([\\S ]+):([\\d]+)"); // battlefield:Human:Island:10
|
||||
private static final Pattern patternCardInfo = Pattern.compile("([\\S ]+):([\\S ]+)"); // Island:XLN
|
||||
|
||||
// show ext info for special commands
|
||||
|
@ -425,7 +425,7 @@ public final class SystemUtil {
|
|||
game.firePriorityEvent(opponent.getId());
|
||||
}
|
||||
|
||||
List<Ability> abilities = opponent.getPlayable(game, true);
|
||||
List<ActivatedAbility> abilities = opponent.getPlayable(game, true);
|
||||
Map<String, String> choices = new HashMap<>();
|
||||
abilities.forEach(ability -> {
|
||||
MageObject object = ability.getSourceObject(game);
|
||||
|
@ -437,10 +437,10 @@ public final class SystemUtil {
|
|||
choice.setKeyChoices(choices);
|
||||
if (feedbackPlayer.choose(Outcome.Detriment, choice, game) && choice.getChoiceKey() != null) {
|
||||
String needId = choice.getChoiceKey();
|
||||
Optional<Ability> ability = abilities.stream().filter(a -> a.getId().toString().equals(needId)).findFirst();
|
||||
Optional<ActivatedAbility> ability = abilities.stream().filter(a -> a.getId().toString().equals(needId)).findFirst();
|
||||
if (ability.isPresent()) {
|
||||
// TODO: set priority for player?
|
||||
ActivatedAbility activatedAbility = (ActivatedAbility) ability.get();
|
||||
ActivatedAbility activatedAbility = ability.get();
|
||||
game.informPlayers(feedbackPlayer.getLogName() + " as another player " + opponent.getLogName()
|
||||
+ " trying to force an activate ability: " + activatedAbility.getGameLogMessage(game));
|
||||
if (opponent.activateAbility(activatedAbility, game)) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.42</version>
|
||||
<version>1.4.43</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage-sets</artifactId>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.cards.a;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
@ -15,8 +14,8 @@ import mage.constants.TargetController;
|
|||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -29,18 +28,21 @@ public final class AbandonHope extends CardImpl {
|
|||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}");
|
||||
|
||||
// As an additional cost to cast Abandon Hope, discard X cards.
|
||||
Ability ability = new SimpleStaticAbility(Zone.ALL, new InfoEffect("As an additional cost to cast this spell, discard X cards"));
|
||||
Ability ability = new SimpleStaticAbility(
|
||||
Zone.ALL, new InfoEffect("As an additional cost to cast this spell, discard X cards")
|
||||
);
|
||||
ability.setRuleAtTheTop(true);
|
||||
this.addAbility(ability);
|
||||
|
||||
// Look at target opponent's hand and choose X cards from it. That player discards those cards.
|
||||
ManacostVariableValue manaX = ManacostVariableValue.instance;
|
||||
this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect(manaX, TargetController.ANY));
|
||||
this.getSpellAbility().addTarget(new TargetPlayer());
|
||||
this.getSpellAbility().addEffect(
|
||||
new DiscardCardYouChooseTargetEffect(ManacostVariableValue.instance, TargetController.ANY)
|
||||
.setText("Look at target opponent's hand and choose X cards from it. That player discards those cards"));
|
||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
||||
this.getSpellAbility().setCostAdjuster(AbandonHopeAdjuster.instance);
|
||||
}
|
||||
|
||||
public AbandonHope(final AbandonHope card) {
|
||||
private AbandonHope(final AbandonHope card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
|
@ -60,4 +62,4 @@ enum AbandonHopeAdjuster implements CostAdjuster {
|
|||
ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, StaticFilters.FILTER_CARD_CARDS)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.TransformSourceEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author fireshoes
|
||||
*/
|
||||
|
@ -54,7 +54,7 @@ class AberrantResearcherEffect extends OneShotEffect {
|
|||
|
||||
public AberrantResearcherEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "put the top card of your library into your graveyard. If it's an instant or sorcery card, transform {this}";
|
||||
staticText = "mill a card. If an instant or sorcery card was milled this way, transform {this}";
|
||||
}
|
||||
|
||||
public AberrantResearcherEffect(final AberrantResearcherEffect effect) {
|
||||
|
@ -64,15 +64,16 @@ class AberrantResearcherEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && controller.getLibrary().hasCards()) {
|
||||
Card card = controller.getLibrary().getFromTop(game);
|
||||
controller.moveCards(card, Zone.GRAVEYARD, source, game);
|
||||
if (card.isInstant() || card.isSorcery()) {
|
||||
new TransformSourceEffect(true).apply(game, source);
|
||||
}
|
||||
return true;
|
||||
if (controller == null
|
||||
|| controller
|
||||
.millCards(1, source, game)
|
||||
.getCards(game)
|
||||
.stream()
|
||||
.noneMatch(MageObject::isInstantOrSorcery)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
new TransformSourceEffect(true).apply(game, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.common.DiesTriggeredAbility;
|
||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
|
@ -26,7 +26,7 @@ public final class AbnormalEndurance extends CardImpl {
|
|||
.setText("Until end of turn, target creature gets +2/+0")
|
||||
);
|
||||
getSpellAbility().addEffect(new GainAbilityTargetEffect(
|
||||
new DiesTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true, true), false),
|
||||
new DiesSourceTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true, true), false),
|
||||
Duration.EndOfTurn,
|
||||
"and gains \"When this creature dies, return it to the battlefield tapped under its owner's control.\""
|
||||
));
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.cards.a;
|
||||
|
||||
import mage.abilities.costs.AlternativeCostSourceAbility;
|
||||
|
@ -16,7 +15,6 @@ import mage.target.common.TargetCardInHand;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Backfir3
|
||||
*/
|
||||
public final class Abolish extends CardImpl {
|
||||
|
@ -28,8 +26,7 @@ public final class Abolish extends CardImpl {
|
|||
}
|
||||
|
||||
public Abolish(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}{W}");
|
||||
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{W}");
|
||||
|
||||
// You may discard a Plains card rather than pay Abolish's mana cost.
|
||||
this.addAbility(new AlternativeCostSourceAbility(new DiscardTargetCost(new TargetCardInHand(filterCost))));
|
||||
|
|
|
@ -4,7 +4,7 @@ package mage.cards.a;
|
|||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility;
|
||||
import mage.abilities.common.BlocksOrBecomesBlockedSourceTriggeredAbility;
|
||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
|
@ -39,7 +39,7 @@ public final class Abomination extends CardImpl {
|
|||
// Whenever Abomination blocks or becomes blocked by a green or white creature, destroy that creature at end of combat.
|
||||
Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect()), true);
|
||||
effect.setText("destroy that creature at end of combat");
|
||||
this.addAbility(new BlocksOrBecomesBlockedTriggeredAbility(effect, filter, false));
|
||||
this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(effect, filter, false));
|
||||
}
|
||||
|
||||
public Abomination(final Abomination card) {
|
||||
|
|
|
@ -3,7 +3,7 @@ package mage.cards.a;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.DiesTriggeredAbility;
|
||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.DestroyAllEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -31,7 +31,7 @@ public final class AbuJafar extends CardImpl {
|
|||
new BlockingAttackerIdPredicate(this.getId())));
|
||||
|
||||
// When Abu Ja'far dies, destroy all creatures blocking or blocked by it. They can't be regenerated.
|
||||
this.addAbility(new DiesTriggeredAbility(new DestroyAllEffect(filter, true), false));
|
||||
this.addAbility(new DiesSourceTriggeredAbility(new DestroyAllEffect(filter, true), false));
|
||||
}
|
||||
|
||||
public AbuJafar(final AbuJafar card) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
|
@ -15,14 +13,15 @@ import mage.constants.CardType;
|
|||
import mage.constants.SubType;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
|
||||
*/
|
||||
public final class AbundantMaw extends CardImpl {
|
||||
|
||||
public AbundantMaw(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{8}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{8}");
|
||||
this.subtype.add(SubType.ELDRAZI);
|
||||
this.subtype.add(SubType.LEECH);
|
||||
this.power = new MageInt(6);
|
||||
|
@ -30,11 +29,11 @@ public final class AbundantMaw extends CardImpl {
|
|||
|
||||
// Emerge {6}{B}
|
||||
this.addAbility(new EmergeAbility(this, new ManaCostsImpl<>("{6}{B}")));
|
||||
|
||||
|
||||
// When you cast Abundant Maw, target opponent loses 3 life and you gain 3 life.
|
||||
Ability ability = new CastSourceTriggeredAbility(new GainLifeEffect(3));
|
||||
ability.addEffect(new LoseLifeTargetEffect(3).concatBy("and"));
|
||||
ability.addTarget(new TargetOpponent());
|
||||
ability.addEffect(new LoseLifeTargetEffect(3));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package mage.cards.a;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.DiesTriggeredAbility;
|
||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.SacrificeAllEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -24,7 +24,7 @@ public final class AbyssalGatekeeper extends CardImpl {
|
|||
this.toughness = new MageInt(1);
|
||||
|
||||
// When Abyssal Gatekeeper dies, each player sacrifices a creature.
|
||||
this.addAbility(new DiesTriggeredAbility(new SacrificeAllEffect(1, new FilterControlledCreaturePermanent("creature"))));
|
||||
this.addAbility(new DiesSourceTriggeredAbility(new SacrificeAllEffect(1, new FilterControlledCreaturePermanent("creature"))));
|
||||
}
|
||||
|
||||
public AbyssalGatekeeper(final AbyssalGatekeeper card) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue