Merge branch 'master' of https://github.com/magefree/mage.git into MorphRework_v2

# Conflicts:
#	Mage.Sets/src/mage/cards/b/Banefire.java
This commit is contained in:
Steven Knipe 2023-10-01 22:59:27 -07:00
commit 26af2602e4
484 changed files with 6960 additions and 5629 deletions

View file

@ -250,6 +250,11 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
LOGGER.fatal(null, ex); LOGGER.fatal(null, ex);
} }
// other settings
if (ClientCallback.SIMULATE_BAD_CONNECTION) {
LOGGER.info("Network: bad connection mode enabled");
}
// DATA PREPARE // DATA PREPARE
RepositoryUtil.bootstrapLocalDb(); RepositoryUtil.bootstrapLocalDb();
// re-create database on empty (e.g. after new build cleaned db on startup) // re-create database on empty (e.g. after new build cleaned db on startup)

View file

@ -1,15 +1,16 @@
package mage.client.cards; package mage.client.cards;
import mage.cards.CardDimensions;
import mage.abilities.icon.CardIconRenderSettings; import mage.abilities.icon.CardIconRenderSettings;
import mage.cards.CardDimensions;
import mage.cards.MageCard; import mage.cards.MageCard;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import mage.client.draft.DraftPanel;
import mage.client.plugins.impl.Plugins; import mage.client.plugins.impl.Plugins;
import mage.client.util.comparators.CardViewRarityComparator;
import mage.client.util.ClientEventType; import mage.client.util.ClientEventType;
import mage.client.util.Event; import mage.client.util.Event;
import mage.client.util.Listener; import mage.client.util.Listener;
import mage.client.util.audio.AudioManager; import mage.client.util.audio.AudioManager;
import mage.client.util.comparators.CardViewRarityComparator;
import mage.constants.Constants; import mage.constants.Constants;
import mage.view.CardView; import mage.view.CardView;
import mage.view.CardsView; import mage.view.CardsView;
@ -28,6 +29,8 @@ public class DraftGrid extends javax.swing.JPanel implements CardEventProducer {
private static final Logger logger = Logger.getLogger(DraftGrid.class); private static final Logger logger = Logger.getLogger(DraftGrid.class);
private final DraftPanel parentPanel;
protected final CardEventSource cardEventSource = new CardEventSource(); protected final CardEventSource cardEventSource = new CardEventSource();
protected BigCard bigCard; protected BigCard bigCard;
protected MageCard markedCard; protected MageCard markedCard;
@ -36,22 +39,28 @@ public class DraftGrid extends javax.swing.JPanel implements CardEventProducer {
/** /**
* Creates new form DraftGrid * Creates new form DraftGrid
*/ */
public DraftGrid() { public DraftGrid(DraftPanel panel) {
initComponents(); initComponents();
parentPanel = panel;
markedCard = null; markedCard = null;
emptyGrid = true; emptyGrid = true;
// ENABLE picks and other actions // ENABLE picks and other actions
cardEventSource.addListener(new Listener<Event>() { cardEventSource.addListener(event -> {
@Override if (event.getEventType() == ClientEventType.CARD_DOUBLE_CLICK
public void event(Event event) { || event.getEventType() == ClientEventType.CARD_CLICK) {
if (event.getEventType() == ClientEventType.CARD_DOUBLE_CLICK) { // There is a protection against picking too early in DraftPanel logic.
CardView card = (CardView) event.getSource(); // So, when double clicking early, we do mark the card as selected like
// a single click would.
CardView card = (CardView) event.getSource();
if(event.getEventType() == ClientEventType.CARD_DOUBLE_CLICK
&& parentPanel.isAllowedToPick()
) {
cardEventSource.fireEvent(card, ClientEventType.DRAFT_PICK_CARD); cardEventSource.fireEvent(card, ClientEventType.DRAFT_PICK_CARD);
hidePopup(); hidePopup();
AudioManager.playOnDraftSelect(); AudioManager.playOnDraftSelect();
} else if (event.getEventType() == ClientEventType.CARD_CLICK) { } else {
CardView card = (CardView) event.getSource();
MageCard cardPanel = (MageCard) event.getComponent(); MageCard cardPanel = (MageCard) event.getComponent();
if (markedCard != null) { if (markedCard != null) {
markedCard.setSelected(false); markedCard.setSelected(false);

View file

@ -22,11 +22,26 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="jSeparator2" alignment="1" max="32767" attributes="0"/>
<Component id="jSeparator4" alignment="1" max="32767" attributes="0"/> <Component id="jSeparator4" alignment="1" max="32767" attributes="0"/>
<Component id="jSeparator2" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnOK" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jSeparator3" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="txtEmblemCardsPerPlayer" max="32767" attributes="2"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="btnEmblemCardsPerPlayer" min="-2" pref="24" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="txtEmblemCardsStartingPlayer" max="32767" attributes="2"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="btnEmblemCardsStartingPlayer" min="-2" pref="24" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="lblMulliganType" min="-2" max="-2" attributes="0"/> <Component id="lblMulliganType" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -35,20 +50,21 @@
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="lblFreeMulligans" min="-2" max="-2" attributes="0"/> <Component id="lblFreeMulligans" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="spnFreeMulligans" pref="126" max="32767" attributes="0"/> <Component id="spnFreeMulligans" max="32767" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="chkPlaneChase" min="-2" max="-2" attributes="0"/>
<Component id="lblGeneralOptions" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblVariantOptions" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="lblVariantOptions" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="chkPlaneChase" min="-2" max="-2" attributes="0"/>
<Component id="chkEmblemCards" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblEmblemCardsPerPlayer" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblEmblemCardsStartingPlayer" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblGeneralOptions" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="0" pref="125" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnOK" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="planechaseDescriptionLabel" alignment="0" max="32767" attributes="0"/>
<Component id="emblemCardsDescriptionLabel" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
@ -76,6 +92,28 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="chkPlaneChase" min="-2" max="-2" attributes="0"/> <Component id="chkPlaneChase" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="planechaseDescriptionLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSeparator3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="chkEmblemCards" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="emblemCardsDescriptionLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblEmblemCardsPerPlayer" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtEmblemCardsPerPlayer" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnEmblemCardsPerPlayer" alignment="3" min="-2" pref="21" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblEmblemCardsStartingPlayer" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtEmblemCardsStartingPlayer" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnEmblemCardsStartingPlayer" alignment="3" min="-2" pref="21" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="jSeparator4" min="-2" max="-2" attributes="0"/> <Component id="jSeparator4" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="btnOK" min="-2" pref="30" max="-2" attributes="0"/> <Component id="btnOK" min="-2" pref="30" max="-2" attributes="0"/>
@ -173,7 +211,7 @@
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="chkPlaneChase"> <Component class="javax.swing.JCheckBox" name="chkPlaneChase">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="PlaneChase"/> <Property name="text" type="java.lang.String" value="Planechase"/>
<Property name="toolTipText" type="java.lang.String" value="Use the PlaneChase variant for your game."/> <Property name="toolTipText" type="java.lang.String" value="Use the PlaneChase variant for your game."/>
</Properties> </Properties>
<AccessibilityProperties> <AccessibilityProperties>
@ -185,6 +223,19 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkPlaneChaseActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkPlaneChaseActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="planechaseDescriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" value="&lt;html&gt;Shared planar deck of all implemented planes.&lt;br&gt;Uses a 9-sided planar die with 2 planeswalk sides and 2 chaos sides.&lt;br&gt;Some ability text may be incorrect.&lt;br&gt;Some rules details (such as who controls plane abilities) may be incorrect."/>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Planechase Description"/>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value="Shared planar deck of all implemented planes.&#xa;Uses a 9-sided planar die with 2 planeswalk sides and 2 chaos sides.&#xa;Some ability text may be incorrect.&#xa;Some rules details (such as who controls plane abilities) may be incorrect."/>
<Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="chkPlaneChase"/>
</Property>
</AccessibilityProperties>
</Component>
<Component class="javax.swing.JSeparator" name="jSeparator4"> <Component class="javax.swing.JSeparator" name="jSeparator4">
</Component> </Component>
<Component class="javax.swing.JButton" name="btnOK"> <Component class="javax.swing.JButton" name="btnOK">
@ -195,5 +246,80 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOKActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOKActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JSeparator" name="jSeparator3">
</Component>
<Component class="javax.swing.JCheckBox" name="chkEmblemCards">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="1"/>
</Property>
<Property name="text" type="java.lang.String" value="Emblem Cards (Experimental)"/>
<Property name="toolTipText" type="java.lang.String" value="If enabled, select cards to give players emblem copies of"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkEmblemCardsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnEmblemCardsPerPlayer">
<Properties>
<Property name="text" type="java.lang.String" value="..."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnEmblemCardsPerPlayerActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtEmblemCardsPerPlayer">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtEmblemCardsPerPlayerActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblEmblemCardsPerPlayer">
<Properties>
<Property name="text" type="java.lang.String" value="Per-Player File"/>
<Property name="toolTipText" type="java.lang.String" value="An emblem of each card in this file is given to each player"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="chkEmblemCards"/>
</Property>
</AccessibilityProperties>
</Component>
<Component class="javax.swing.JButton" name="btnEmblemCardsStartingPlayer">
<Properties>
<Property name="text" type="java.lang.String" value="..."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnEmblemCardsStartingPlayerActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtEmblemCardsStartingPlayer">
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value=""/>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtEmblemCardsStartingPlayerActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblEmblemCardsStartingPlayer">
<Properties>
<Property name="text" type="java.lang.String" value="Starting Player File"/>
<Property name="toolTipText" type="java.lang.String" value="An emblem of every card in this file is given to the starting player (useful for symmetric effects)"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="chkEmblemCards"/>
</Property>
</AccessibilityProperties>
</Component>
<Component class="javax.swing.JLabel" name="emblemCardsDescriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" value="&lt;html&gt;Give players emblems with the abilities of cards.&lt;br&gt;Note that some abilities may not function correctly from the command zone.&lt;br&gt;If anything breaks, please report it on GitHub."/>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Emblem Cards description"/>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value="Give players emblems with the abilities of cards.&#xa;Note that some abilities may not function correctly from the command zone.&#xa;If anything breaks, please report it on GitHub."/>
</AccessibilityProperties>
</Component>
</SubComponents> </SubComponents>
</Form> </Form>

View file

@ -1,12 +1,21 @@
package mage.client.dialog; package mage.client.dialog;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckFileFilter;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.constants.MultiplayerAttackOption; import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
import mage.game.GameException;
import mage.game.match.MatchOptions; import mage.game.match.MatchOptions;
import mage.game.mulligan.MulliganType; import mage.game.mulligan.MulliganType;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import javax.swing.*; import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
/** /**
* App GUI: custom options for match/tournament * App GUI: custom options for match/tournament
@ -19,28 +28,49 @@ public class CustomOptionsDialog extends MageDialog {
TABLE( TABLE(
PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS, PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS,
PreferencesDialog.KEY_NEW_TABLE_MULLIGAN_TYPE, PreferencesDialog.KEY_NEW_TABLE_MULLIGAN_TYPE,
PreferencesDialog.KEY_NEW_TABLE_PLANECHASE PreferencesDialog.KEY_NEW_TABLE_PLANECHASE,
PreferencesDialog.KEY_NEW_TABLE_EMBLEM_CARDS_ENABLED,
PreferencesDialog.KEY_NEW_TABLE_EMBLEM_CARDS_PER_PLAYER_FILE,
PreferencesDialog.KEY_NEW_TABLE_EMBLEM_CARDS_STARTING_PLAYER_FILE
), ),
TOURNEY( TOURNEY(
PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS, PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS,
PreferencesDialog.KEY_NEW_TOURNAMENT_MULLIGUN_TYPE, PreferencesDialog.KEY_NEW_TOURNAMENT_MULLIGUN_TYPE,
PreferencesDialog.KEY_NEW_TOURNAMENT_PLANE_CHASE PreferencesDialog.KEY_NEW_TOURNAMENT_PLANE_CHASE,
PreferencesDialog.KEY_NEW_TOURNAMENT_EMBLEM_CARDS_ENABLED,
PreferencesDialog.KEY_NEW_TOURNAMENT_EMBLEM_CARDS_PER_PLAYER_FILE,
PreferencesDialog.KEY_NEW_TOURNAMENT_EMBLEM_CARDS_STARTING_PLAYER_FILE
); );
public final String NUMBER_OF_FREE_MULLIGANS; public final String NUMBER_OF_FREE_MULLIGANS;
public final String MULLIGAN_TYPE; public final String MULLIGAN_TYPE;
public final String PLANECHASE; public final String PLANECHASE;
public final String EMBLEM_CARDS_ENABLED;
public final String EMBLEM_CARDS_PER_PLAYER_FILE;
public final String EMBLEM_CARDS_STARTING_PLAYER_FILE;
SaveLoadKeys(String numberOfFreeMulligans, String mulliganType, String planechase) { SaveLoadKeys(
String numberOfFreeMulligans,
String mulliganType,
String planechase,
String emblemCardsEnabled,
String emblemCardsPerPlayerFile,
String emblemCardsStartingPlayerFile
) {
NUMBER_OF_FREE_MULLIGANS = numberOfFreeMulligans; NUMBER_OF_FREE_MULLIGANS = numberOfFreeMulligans;
MULLIGAN_TYPE = mulliganType; MULLIGAN_TYPE = mulliganType;
PLANECHASE = planechase; PLANECHASE = planechase;
EMBLEM_CARDS_ENABLED = emblemCardsEnabled;
EMBLEM_CARDS_PER_PLAYER_FILE = emblemCardsPerPlayerFile;
EMBLEM_CARDS_STARTING_PLAYER_FILE = emblemCardsStartingPlayerFile;
} }
} }
private static final Logger logger = Logger.getLogger(CustomOptionsDialog.class); private static final Logger logger = Logger.getLogger(CustomOptionsDialog.class);
private final SaveLoadKeys saveLoadKeys; private final SaveLoadKeys saveLoadKeys;
private final JButton openButton; private final JButton openButton;
private final JFileChooser fcSelectEmblemCardsPerPlayer;
private final JFileChooser fcSelectEmblemCardsStartingPlayer;
/** /**
* Creates new form NewTableDialog * Creates new form NewTableDialog
@ -52,6 +82,12 @@ public class CustomOptionsDialog extends MageDialog {
this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1)); this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1));
cbMulliganType.setModel(new DefaultComboBoxModel(MulliganType.values())); cbMulliganType.setModel(new DefaultComboBoxModel(MulliganType.values()));
this.setModal(true); this.setModal(true);
fcSelectEmblemCardsPerPlayer = new JFileChooser();
fcSelectEmblemCardsPerPlayer.setAcceptAllFileFilterUsed(false);
fcSelectEmblemCardsPerPlayer.addChoosableFileFilter(new DeckFileFilter("dck", "XMage's deck files (*.dck)"));
fcSelectEmblemCardsStartingPlayer = new JFileChooser();
fcSelectEmblemCardsStartingPlayer.setAcceptAllFileFilterUsed(false);
fcSelectEmblemCardsStartingPlayer.addChoosableFileFilter(new DeckFileFilter("dck", "XMage's deck files (*.dck)"));
} }
/** /**
@ -71,8 +107,18 @@ public class CustomOptionsDialog extends MageDialog {
jSeparator2 = new javax.swing.JSeparator(); jSeparator2 = new javax.swing.JSeparator();
lblVariantOptions = new javax.swing.JLabel(); lblVariantOptions = new javax.swing.JLabel();
chkPlaneChase = new javax.swing.JCheckBox(); chkPlaneChase = new javax.swing.JCheckBox();
planechaseDescriptionLabel = new javax.swing.JLabel();
jSeparator4 = new javax.swing.JSeparator(); jSeparator4 = new javax.swing.JSeparator();
btnOK = new javax.swing.JButton(); btnOK = new javax.swing.JButton();
jSeparator3 = new javax.swing.JSeparator();
chkEmblemCards = new javax.swing.JCheckBox();
btnEmblemCardsPerPlayer = new javax.swing.JButton();
txtEmblemCardsPerPlayer = new javax.swing.JTextField();
lblEmblemCardsPerPlayer = new javax.swing.JLabel();
btnEmblemCardsStartingPlayer = new javax.swing.JButton();
txtEmblemCardsStartingPlayer = new javax.swing.JTextField();
lblEmblemCardsStartingPlayer = new javax.swing.JLabel();
emblemCardsDescriptionLabel = new javax.swing.JLabel();
setTitle("Custom Options"); setTitle("Custom Options");
@ -103,7 +149,7 @@ public class CustomOptionsDialog extends MageDialog {
lblVariantOptions.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N lblVariantOptions.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
lblVariantOptions.setText("Variant Options"); lblVariantOptions.setText("Variant Options");
chkPlaneChase.setText("PlaneChase"); chkPlaneChase.setText("Planechase");
chkPlaneChase.setToolTipText("Use the PlaneChase variant for your game."); chkPlaneChase.setToolTipText("Use the PlaneChase variant for your game.");
chkPlaneChase.addActionListener(new java.awt.event.ActionListener() { chkPlaneChase.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -111,6 +157,9 @@ public class CustomOptionsDialog extends MageDialog {
} }
}); });
planechaseDescriptionLabel.setText("<html>Shared planar deck of all implemented planes.<br>Uses a 9-sided planar die with 2 planeswalk sides and 2 chaos sides.<br>Some ability text may be incorrect.<br>Some rules details (such as who controls plane abilities) may be incorrect.");
planechaseDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
btnOK.setText("OK"); btnOK.setText("OK");
btnOK.addActionListener(new java.awt.event.ActionListener() { btnOK.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -118,32 +167,90 @@ public class CustomOptionsDialog extends MageDialog {
} }
}); });
chkEmblemCards.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
chkEmblemCards.setText("Emblem Cards (Experimental)");
chkEmblemCards.setToolTipText("If enabled, select cards to give players emblem copies of");
chkEmblemCards.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
chkEmblemCardsActionPerformed(evt);
}
});
btnEmblemCardsPerPlayer.setText("...");
btnEmblemCardsPerPlayer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnEmblemCardsPerPlayerActionPerformed(evt);
}
});
txtEmblemCardsPerPlayer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtEmblemCardsPerPlayerActionPerformed(evt);
}
});
lblEmblemCardsPerPlayer.setText("Per-Player File");
lblEmblemCardsPerPlayer.setToolTipText("An emblem of each card in this file is given to each player");
btnEmblemCardsStartingPlayer.setText("...");
btnEmblemCardsStartingPlayer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnEmblemCardsStartingPlayerActionPerformed(evt);
}
});
txtEmblemCardsStartingPlayer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtEmblemCardsStartingPlayerActionPerformed(evt);
}
});
lblEmblemCardsStartingPlayer.setText("Starting Player File");
lblEmblemCardsStartingPlayer.setToolTipText("An emblem of every card in this file is given to the starting player (useful for symmetric effects)");
emblemCardsDescriptionLabel.setText("<html>Give players emblems with the abilities of cards.<br>Note that some abilities may not function correctly from the command zone.<br>If anything breaks, please report it on GitHub.");
emblemCardsDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout); getContentPane().setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator2) .addComponent(jSeparator4, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jSeparator4) .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(btnOK))
.addComponent(jSeparator3)
.addGroup(layout.createSequentialGroup()
.addComponent(txtEmblemCardsPerPlayer)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnEmblemCardsPerPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(txtEmblemCardsStartingPlayer)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnEmblemCardsStartingPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(lblMulliganType) .addComponent(lblMulliganType)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cbMulliganType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addComponent(cbMulliganType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(lblFreeMulligans) .addComponent(lblFreeMulligans)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)) .addComponent(spnFreeMulligans))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(chkPlaneChase)
.addComponent(lblGeneralOptions)
.addComponent(lblVariantOptions))
.addGap(0, 125, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnOK))) .addComponent(lblVariantOptions)
.addComponent(chkPlaneChase)
.addComponent(chkEmblemCards)
.addComponent(lblEmblemCardsPerPlayer)
.addComponent(lblEmblemCardsStartingPlayer)
.addComponent(lblGeneralOptions))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(planechaseDescriptionLabel)
.addComponent(emblemCardsDescriptionLabel))
.addContainerGap()) .addContainerGap())
); );
layout.setVerticalGroup( layout.setVerticalGroup(
@ -166,6 +273,26 @@ public class CustomOptionsDialog extends MageDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkPlaneChase) .addComponent(chkPlaneChase)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(planechaseDescriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkEmblemCards)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(emblemCardsDescriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblEmblemCardsPerPlayer)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtEmblemCardsPerPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnEmblemCardsPerPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblEmblemCardsStartingPlayer)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtEmblemCardsStartingPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnEmblemCardsStartingPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jSeparator4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jSeparator4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0) .addGap(0, 0, 0)
.addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
@ -182,6 +309,14 @@ public class CustomOptionsDialog extends MageDialog {
spnFreeMulligans.getAccessibleContext().setAccessibleDescription("Select the number of free mulligans"); spnFreeMulligans.getAccessibleContext().setAccessibleDescription("Select the number of free mulligans");
spnFreeMulligans.getAccessibleContext().setAccessibleParent(lblFreeMulligans); spnFreeMulligans.getAccessibleContext().setAccessibleParent(lblFreeMulligans);
chkPlaneChase.getAccessibleContext().setAccessibleParent(lblVariantOptions); chkPlaneChase.getAccessibleContext().setAccessibleParent(lblVariantOptions);
planechaseDescriptionLabel.getAccessibleContext().setAccessibleName("Planechase Description");
planechaseDescriptionLabel.getAccessibleContext().setAccessibleDescription("Shared planar deck of all implemented planes.\nUses a 9-sided planar die with 2 planeswalk sides and 2 chaos sides.\nSome ability text may be incorrect.\nSome rules details (such as who controls plane abilities) may be incorrect.");
planechaseDescriptionLabel.getAccessibleContext().setAccessibleParent(chkPlaneChase);
lblEmblemCardsPerPlayer.getAccessibleContext().setAccessibleParent(chkEmblemCards);
txtEmblemCardsStartingPlayer.getAccessibleContext().setAccessibleDescription("");
lblEmblemCardsStartingPlayer.getAccessibleContext().setAccessibleParent(chkEmblemCards);
emblemCardsDescriptionLabel.getAccessibleContext().setAccessibleName("Emblem Cards description");
emblemCardsDescriptionLabel.getAccessibleContext().setAccessibleDescription("Give players emblems with the abilities of cards.\nNote that some abilities may not function correctly from the command zone.\nIf anything breaks, please report it on GitHub.");
pack(); pack();
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -205,10 +340,50 @@ public class CustomOptionsDialog extends MageDialog {
updateActiveCount(); updateActiveCount();
}//GEN-LAST:event_chkPlaneChaseActionPerformed }//GEN-LAST:event_chkPlaneChaseActionPerformed
private void chkEmblemCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkEmblemCardsActionPerformed
updateActiveCount();
}//GEN-LAST:event_chkEmblemCardsActionPerformed
private void btnEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsPerPlayerActionPerformed
loadEmblemCardFile(false);
}//GEN-LAST:event_btnEmblemCardsPerPlayerActionPerformed
private void txtEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtEmblemCardsPerPlayerActionPerformed
}//GEN-LAST:event_txtEmblemCardsPerPlayerActionPerformed
private void btnEmblemCardsStartingPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsStartingPlayerActionPerformed
loadEmblemCardFile(true);
}//GEN-LAST:event_btnEmblemCardsStartingPlayerActionPerformed
private void txtEmblemCardsStartingPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtEmblemCardsStartingPlayerActionPerformed
}//GEN-LAST:event_txtEmblemCardsStartingPlayerActionPerformed
public void showDialog() { public void showDialog() {
this.setLocation(150, 100); this.setLocation(150, 100);
this.setVisible(true); this.setVisible(true);
} }
private void loadEmblemCardFile(boolean isStartingPlayer) {
JFileChooser fileChooser = isStartingPlayer ? fcSelectEmblemCardsStartingPlayer : fcSelectEmblemCardsPerPlayer;
JTextField textField = isStartingPlayer ? txtEmblemCardsStartingPlayer : txtEmblemCardsPerPlayer;
String prefKey = isStartingPlayer ? "lastStartingPlayerEmblemCardsFolder" : "lastPerPlayerEmblemCardsFolder";
String lastFolder = MageFrame.getPreferences().get(prefKey, "");
if (!lastFolder.isEmpty()) {
fileChooser.setCurrentDirectory(new File(lastFolder));
}
int ret = fileChooser.showDialog(this, "Select Emblem Cards");
if (ret == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
textField.setText(file.getPath());
try {
MageFrame.getPreferences().put(prefKey, file.getCanonicalPath());
} catch (IOException ex) {
}
}
fileChooser.setSelectedFile(null);
}
public void onLoadSettings(int version) { public void onLoadSettings(int version) {
@ -231,6 +406,9 @@ public class CustomOptionsDialog extends MageDialog {
this.chkPlaneChase.setSelected(PreferencesDialog.getCachedValue(saveLoadKeys.PLANECHASE + versionStr, "No").equals("Yes")); this.chkPlaneChase.setSelected(PreferencesDialog.getCachedValue(saveLoadKeys.PLANECHASE + versionStr, "No").equals("Yes"));
this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(saveLoadKeys.NUMBER_OF_FREE_MULLIGANS + versionStr, "0"))); this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(saveLoadKeys.NUMBER_OF_FREE_MULLIGANS + versionStr, "0")));
this.cbMulliganType.setSelectedItem(MulliganType.valueByName(PreferencesDialog.getCachedValue(saveLoadKeys.MULLIGAN_TYPE + versionStr, MulliganType.GAME_DEFAULT.toString()))); this.cbMulliganType.setSelectedItem(MulliganType.valueByName(PreferencesDialog.getCachedValue(saveLoadKeys.MULLIGAN_TYPE + versionStr, MulliganType.GAME_DEFAULT.toString())));
this.chkEmblemCards.setSelected(PreferencesDialog.getCachedValue(saveLoadKeys.EMBLEM_CARDS_ENABLED + versionStr, "No").equals("Yes"));
this.txtEmblemCardsPerPlayer.setText(PreferencesDialog.getCachedValue(saveLoadKeys.EMBLEM_CARDS_PER_PLAYER_FILE, ""));
this.txtEmblemCardsStartingPlayer.setText(PreferencesDialog.getCachedValue(saveLoadKeys.EMBLEM_CARDS_STARTING_PLAYER_FILE, ""));
updateActiveCount(); updateActiveCount();
} }
@ -250,6 +428,10 @@ public class CustomOptionsDialog extends MageDialog {
PreferencesDialog.saveValue(saveLoadKeys.NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(options.getFreeMulligans())); PreferencesDialog.saveValue(saveLoadKeys.NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(options.getFreeMulligans()));
PreferencesDialog.saveValue(saveLoadKeys.MULLIGAN_TYPE + versionStr, options.getMulliganType().toString()); PreferencesDialog.saveValue(saveLoadKeys.MULLIGAN_TYPE + versionStr, options.getMulliganType().toString());
PreferencesDialog.saveValue(saveLoadKeys.PLANECHASE + versionStr, options.isPlaneChase() ? "Yes" : "No"); PreferencesDialog.saveValue(saveLoadKeys.PLANECHASE + versionStr, options.isPlaneChase() ? "Yes" : "No");
PreferencesDialog.saveValue(saveLoadKeys.EMBLEM_CARDS_ENABLED + versionStr,
!(options.getGlobalEmblemCards().isEmpty() && options.getPerPlayerEmblemCards().isEmpty()) ? "Yes" : "No");
PreferencesDialog.saveValue(saveLoadKeys.EMBLEM_CARDS_PER_PLAYER_FILE + versionStr, txtEmblemCardsPerPlayer.getText());
PreferencesDialog.saveValue(saveLoadKeys.EMBLEM_CARDS_STARTING_PLAYER_FILE + versionStr, txtEmblemCardsStartingPlayer.getText());
} }
/** /**
@ -259,6 +441,42 @@ public class CustomOptionsDialog extends MageDialog {
options.setFreeMulligans((Integer) spnFreeMulligans.getValue()); options.setFreeMulligans((Integer) spnFreeMulligans.getValue());
options.setMullgianType((MulliganType) cbMulliganType.getSelectedItem()); options.setMullgianType((MulliganType) cbMulliganType.getSelectedItem());
options.setPlaneChase(chkPlaneChase.isSelected()); options.setPlaneChase(chkPlaneChase.isSelected());
if (chkEmblemCards.isSelected()) {
if (!txtEmblemCardsPerPlayer.getText().isEmpty()) {
Deck perPlayerEmblemDeck = null;
try {
perPlayerEmblemDeck = Deck.load(DeckImporter.importDeckFromFile(txtEmblemCardsPerPlayer.getText(), true), true, true);
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
}
if (perPlayerEmblemDeck != null) {
perPlayerEmblemDeck.clearLayouts();
options.setPerPlayerEmblemCards(perPlayerEmblemDeck.getDeckCardLists().getCards());
}
else {
options.setPerPlayerEmblemCards(Collections.emptySet());
}
}
if (!txtEmblemCardsStartingPlayer.getText().isEmpty()) {
Deck startingPlayerEmblemDeck = null;
try {
startingPlayerEmblemDeck = Deck.load(DeckImporter.importDeckFromFile(txtEmblemCardsStartingPlayer.getText(), true), true, true);
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
}
if (startingPlayerEmblemDeck != null) {
startingPlayerEmblemDeck.clearLayouts();
options.setGlobalEmblemCards(startingPlayerEmblemDeck.getDeckCardLists().getCards());
}
else {
options.setGlobalEmblemCards(Collections.emptySet());
}
}
}
else {
options.setPerPlayerEmblemCards(Collections.emptySet());
options.setGlobalEmblemCards(Collections.emptySet());
}
} }
public void updateActiveCount() { public void updateActiveCount() {
@ -266,6 +484,7 @@ public class CustomOptionsDialog extends MageDialog {
if ((Integer)spnFreeMulligans.getValue() > 0) activeCount++; if ((Integer)spnFreeMulligans.getValue() > 0) activeCount++;
if (!cbMulliganType.getSelectedItem().toString().equals(MulliganType.GAME_DEFAULT.toString())) activeCount++; if (!cbMulliganType.getSelectedItem().toString().equals(MulliganType.GAME_DEFAULT.toString())) activeCount++;
if (chkPlaneChase.isSelected()) activeCount++; if (chkPlaneChase.isSelected()) activeCount++;
if (chkEmblemCards.isSelected()) activeCount++;
if (activeCount == 0) { if (activeCount == 0) {
openButton.setText("Custom Options..."); openButton.setText("Custom Options...");
} }
@ -275,15 +494,25 @@ public class CustomOptionsDialog extends MageDialog {
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnEmblemCardsPerPlayer;
private javax.swing.JButton btnEmblemCardsStartingPlayer;
private javax.swing.JButton btnOK; private javax.swing.JButton btnOK;
private javax.swing.JComboBox<String> cbMulliganType; private javax.swing.JComboBox<String> cbMulliganType;
private javax.swing.JCheckBox chkEmblemCards;
private javax.swing.JCheckBox chkPlaneChase; private javax.swing.JCheckBox chkPlaneChase;
private javax.swing.JLabel emblemCardsDescriptionLabel;
private javax.swing.JSeparator jSeparator2; private javax.swing.JSeparator jSeparator2;
private javax.swing.JSeparator jSeparator3;
private javax.swing.JSeparator jSeparator4; private javax.swing.JSeparator jSeparator4;
private javax.swing.JLabel lblEmblemCardsPerPlayer;
private javax.swing.JLabel lblEmblemCardsStartingPlayer;
private javax.swing.JLabel lblFreeMulligans; private javax.swing.JLabel lblFreeMulligans;
private javax.swing.JLabel lblGeneralOptions; private javax.swing.JLabel lblGeneralOptions;
private javax.swing.JLabel lblMulliganType; private javax.swing.JLabel lblMulliganType;
private javax.swing.JLabel lblVariantOptions; private javax.swing.JLabel lblVariantOptions;
private javax.swing.JLabel planechaseDescriptionLabel;
private javax.swing.JSpinner spnFreeMulligans; private javax.swing.JSpinner spnFreeMulligans;
private javax.swing.JTextField txtEmblemCardsPerPlayer;
private javax.swing.JTextField txtEmblemCardsStartingPlayer;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View file

@ -45,7 +45,7 @@
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="tabsPanel" pref="584" max="32767" attributes="0"/> <Component id="tabsPanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="saveButton" alignment="3" min="-2" pref="30" max="-2" attributes="0"/> <Component id="saveButton" alignment="3" min="-2" pref="30" max="-2" attributes="0"/>
@ -134,14 +134,14 @@
<Component class="javax.swing.JCheckBox" name="cbGameLogAutoSave"> <Component class="javax.swing.JCheckBox" name="cbGameLogAutoSave">
<Properties> <Properties>
<Property name="selected" type="boolean" value="true"/> <Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Save game logs (to &quot;../Mage.Client/gamelogs/&quot; directory)"/> <Property name="text" type="java.lang.String" value="Save game logs (dest folder: &quot;..\u005cxmage\u005cmage-client\u005cgamelogs&quot;)" containsInvalidXMLChars="true"/>
<Property name="toolTipText" type="java.lang.String" value="The logs of all your games will be saved to the mentioned folder if this option is switched on."/> <Property name="toolTipText" type="java.lang.String" value="The logs of all your games will be saved to the mentioned folder if this option is switched on."/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbDraftLogAutoSave"> <Component class="javax.swing.JCheckBox" name="cbDraftLogAutoSave">
<Properties> <Properties>
<Property name="selected" type="boolean" value="true"/> <Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Save draft logs (to &quot;../Mage.Client/gamelogs/&quot; directory)"/> <Property name="text" type="java.lang.String" value="Save draft logs (dest folder: &quot;..\u005cxmage\u005cmage-client\u005cgamelogs&quot;)" containsInvalidXMLChars="true"/>
<Property name="toolTipText" type="java.lang.String" value="The logs of all your games will be saved to the mentioned folder if this option is switched on."/> <Property name="toolTipText" type="java.lang.String" value="The logs of all your games will be saved to the mentioned folder if this option is switched on."/>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/> <Color id="Default Cursor"/>
@ -151,13 +151,13 @@
<Component class="javax.swing.JCheckBox" name="cbLimitedDeckAutoSave"> <Component class="javax.swing.JCheckBox" name="cbLimitedDeckAutoSave">
<Properties> <Properties>
<Property name="selected" type="boolean" value="true"/> <Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Save limited decks on submit (to &quot;../Mage.Client/gamelogs/&quot; directory)"/> <Property name="text" type="java.lang.String" value="Save limited decks on submit (dest folder: &quot;..\u005cxmage\u005cmage-client\u005cgamelogs&quot;)" containsInvalidXMLChars="true"/>
<Property name="toolTipText" type="java.lang.String" value="A .dck file for each limited tournament will be saved to the mentioned folder if this option is switched on."/> <Property name="toolTipText" type="java.lang.String" value="A .dck file for each limited tournament will be saved to the mentioned folder if this option is switched on."/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbGameJsonLogAutoSave"> <Component class="javax.swing.JCheckBox" name="cbGameJsonLogAutoSave">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Save JSON game logs (to &quot;../Mage.Client/gamelogsJson/&quot; directory)"/> <Property name="text" type="java.lang.String" value="Save JSON game logs (dest folder: &quot;..\u005cxmage\u005cmage-client\u005cgamelogs&quot;)" containsInvalidXMLChars="true"/>
<Property name="toolTipText" type="java.lang.String" value="The JSON logs of all your games will be saved to the mentioned folder if this option is switched on."/> <Property name="toolTipText" type="java.lang.String" value="The JSON logs of all your games will be saved to the mentioned folder if this option is switched on."/>
</Properties> </Properties>
</Component> </Component>
@ -280,27 +280,25 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="lblTargetAutoChoose" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbTargetAutoChooseLevel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Component id="displayLifeOnAvatar" alignment="0" max="32767" attributes="0"/> <Component id="displayLifeOnAvatar" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="lblTargetAutoChoose" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbTargetAutoChooseLevel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="cbAskMoveToGraveOrder" alignment="0" min="-2" pref="596" max="-2" attributes="0"/> <Component id="cbAskMoveToGraveOrder" alignment="0" min="-2" pref="596" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="0" max="-2" attributes="0"> <Group type="103" alignment="0" groupAlignment="0" max="-2" attributes="0">
<Component id="showPlayerNamesPermanently" alignment="0" max="32767" attributes="0"/> <Component id="showPlayerNamesPermanently" alignment="0" max="32767" attributes="0"/>
<Component id="nonLandPermanentsInOnePile" alignment="0" max="32767" attributes="0"/> <Component id="nonLandPermanentsInOnePile" alignment="0" max="32767" attributes="0"/>
<Component id="cbConfirmEmptyManaPool" alignment="0" max="32767" attributes="0"/> <Component id="cbConfirmEmptyManaPool" alignment="0" max="32767" attributes="0"/>
<Component id="cbAllowRequestToShowHandCards" alignment="0" max="32767" attributes="0"/> <Component id="cbAllowRequestToShowHandCards" alignment="0" max="32767" attributes="0"/>
<Component id="cbShowStormCounter" alignment="0" max="32767" attributes="0"/>
<Component id="showAbilityPickerForced" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="showAbilityPickerForced" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace min="0" pref="315" max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -317,8 +315,6 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cbAllowRequestToShowHandCards" min="-2" max="-2" attributes="0"/> <Component id="cbAllowRequestToShowHandCards" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cbShowStormCounter" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbConfirmEmptyManaPool" min="-2" max="-2" attributes="0"/> <Component id="cbConfirmEmptyManaPool" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cbAskMoveToGraveOrder" min="-2" max="-2" attributes="0"/> <Component id="cbAskMoveToGraveOrder" min="-2" max="-2" attributes="0"/>
@ -341,9 +337,6 @@
<AccessibilityProperties> <AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="nonLandPermanentsInOnePile"/> <Property name="AccessibleContext.accessibleName" type="java.lang.String" value="nonLandPermanentsInOnePile"/>
</AccessibilityProperties> </AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="nonLandPermanentsInOnePileActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="showPlayerNamesPermanently"> <Component class="javax.swing.JCheckBox" name="showPlayerNamesPermanently">
<Properties> <Properties>
@ -351,9 +344,6 @@
<Property name="text" type="java.lang.String" value="Show player names on avatar permanently"/> <Property name="text" type="java.lang.String" value="Show player names on avatar permanently"/>
<Property name="toolTipText" type="java.lang.String" value="Instead showing the names only if you hover over the avatar with the mouse, the name is shown all the time."/> <Property name="toolTipText" type="java.lang.String" value="Instead showing the names only if you hover over the avatar with the mouse, the name is shown all the time."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showPlayerNamesPermanentlyActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="displayLifeOnAvatar"> <Component class="javax.swing.JCheckBox" name="displayLifeOnAvatar">
<Properties> <Properties>
@ -361,9 +351,6 @@
<Property name="text" type="java.lang.String" value="Display life on avatar image"/> <Property name="text" type="java.lang.String" value="Display life on avatar image"/>
<Property name="toolTipText" type="java.lang.String" value="Display the player&apos;s life over its avatar image."/> <Property name="toolTipText" type="java.lang.String" value="Display the player&apos;s life over its avatar image."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="displayLifeOnAvatarActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="showAbilityPickerForced"> <Component class="javax.swing.JCheckBox" name="showAbilityPickerForced">
<Properties> <Properties>
@ -371,9 +358,6 @@
<Property name="text" type="java.lang.String" value="Show ability picker for 1 available option (spells without costs, mdf/split side, adventure)"/> <Property name="text" type="java.lang.String" value="Show ability picker for 1 available option (spells without costs, mdf/split side, adventure)"/>
<Property name="toolTipText" type="java.lang.String" value="This prevents you from accidently activating abilities what you don&apos;t want (example: if you haven&apos;t mana to cast main side, but clicks on mdf card and play land instead)"/> <Property name="toolTipText" type="java.lang.String" value="This prevents you from accidently activating abilities what you don&apos;t want (example: if you haven&apos;t mana to cast main side, but clicks on mdf card and play land instead)"/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showAbilityPickerForcedActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbAllowRequestToShowHandCards"> <Component class="javax.swing.JCheckBox" name="cbAllowRequestToShowHandCards">
<Properties> <Properties>
@ -381,19 +365,6 @@
<Property name="text" type="java.lang.String" value="Allow requests from players and spectators to show your hand cards"/> <Property name="text" type="java.lang.String" value="Allow requests from players and spectators to show your hand cards"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;This is the default setting used for your matches. If activated other players or spectators&lt;br&gt;&#xa;of your match can send a request so you can allow them to see your hand cards."/> <Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;This is the default setting used for your matches. If activated other players or spectators&lt;br&gt;&#xa;of your match can send a request so you can allow them to see your hand cards."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbAllowRequestToShowHandCardsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbShowStormCounter">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Show the number of spell casts during the current turn"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;Adds a little box left to the short keys line with the number&lt;br&gt;&#xa;of spells already cast during the current turn (storm counter)."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbShowStormCounterActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbConfirmEmptyManaPool"> <Component class="javax.swing.JCheckBox" name="cbConfirmEmptyManaPool">
<Properties> <Properties>
@ -401,9 +372,6 @@
<Property name="text" type="java.lang.String" value="Confirm if you want to pass a phase/step but there is still mana in your mana pool"/> <Property name="text" type="java.lang.String" value="Confirm if you want to pass a phase/step but there is still mana in your mana pool"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;If activated you get a confirm message if you pass priority while stack is empty&lt;br&gt;&#xa; and you still have mana in your mana pool."/> <Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;If activated you get a confirm message if you pass priority while stack is empty&lt;br&gt;&#xa; and you still have mana in your mana pool."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbConfirmEmptyManaPoolActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbAskMoveToGraveOrder"> <Component class="javax.swing.JCheckBox" name="cbAskMoveToGraveOrder">
<Properties> <Properties>
@ -411,9 +379,6 @@
<Property name="text" type="java.lang.String" value="Ask player for setting order cards go to graveyard"/> <Property name="text" type="java.lang.String" value="Ask player for setting order cards go to graveyard"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;If activated and multiple cards go to the graveyard at the same time&lt;br&gt;&#xa;the player is asked to set the order of the cards."/> <Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;If activated and multiple cards go to the graveyard at the same time&lt;br&gt;&#xa;the player is asked to set the order of the cards."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbAskMoveToGraveOrderActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblTargetAutoChoose"> <Component class="javax.swing.JLabel" name="lblTargetAutoChoose">
<Properties> <Properties>
@ -438,9 +403,6 @@
<AccessibilityProperties> <AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Auto-choose targets for player combo box"/> <Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Auto-choose targets for player combo box"/>
</AccessibilityProperties> </AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbTargetAutoChooseLevelActionPerformed"/>
</Events>
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/> <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues> </AuxValues>
@ -4237,9 +4199,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/> <Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/> <Property name="actionCommand" type="java.lang.String" value=""/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopAttackActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithAny"> <Component class="javax.swing.JCheckBox" name="cbStopBlockWithAny">
<Properties> <Properties>
@ -4248,9 +4207,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/> <Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/> <Property name="actionCommand" type="java.lang.String" value=""/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockWithAnyActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithZero"> <Component class="javax.swing.JCheckBox" name="cbStopBlockWithZero">
<Properties> <Properties>
@ -4258,9 +4214,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/> <Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/> <Property name="actionCommand" type="java.lang.String" value=""/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockWithZeroActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnNewStackObjects"> <Component class="javax.swing.JCheckBox" name="cbStopOnNewStackObjects">
<Properties> <Properties>
@ -4271,9 +4224,6 @@
<Dimension value="[300, 25]"/> <Dimension value="[300, 25]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopOnNewStackObjectsActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnAllMain"> <Component class="javax.swing.JCheckBox" name="cbStopOnAllMain">
<Properties> <Properties>
@ -4281,9 +4231,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/> <Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/> <Property name="actionCommand" type="java.lang.String" value=""/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopOnAllMainActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnAllEnd"> <Component class="javax.swing.JCheckBox" name="cbStopOnAllEnd">
<Properties> <Properties>
@ -4294,9 +4241,6 @@
<Dimension value="[300, 25]"/> <Dimension value="[300, 25]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopOnAllEndActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbPassPriorityCast"> <Component class="javax.swing.JCheckBox" name="cbPassPriorityCast">
<Properties> <Properties>
@ -4307,9 +4251,6 @@
<Dimension value="[300, 25]"/> <Dimension value="[300, 25]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbPassPriorityCastActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbPassPriorityActivation"> <Component class="javax.swing.JCheckBox" name="cbPassPriorityActivation">
<Properties> <Properties>
@ -4320,9 +4261,6 @@
<Dimension value="[300, 25]"/> <Dimension value="[300, 25]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbPassPriorityActivationActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbAutoOrderTrigger"> <Component class="javax.swing.JCheckBox" name="cbAutoOrderTrigger">
<Properties> <Properties>
@ -4333,9 +4271,6 @@
<Dimension value="[300, 25]"/> <Dimension value="[300, 25]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbAutoOrderTriggerActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbUseSameSettingsForReplacementEffect"> <Component class="javax.swing.JCheckBox" name="cbUseSameSettingsForReplacementEffect">
<Properties> <Properties>
@ -4346,9 +4281,6 @@
<Dimension value="[300, 25]"/> <Dimension value="[300, 25]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbUseSameSettingsForReplacementEffectActionPerformed"/>
</Events>
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </Container>
@ -4668,9 +4600,6 @@
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtBackgroundImagePath"> <Component class="javax.swing.JTextField" name="txtBackgroundImagePath">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtBackgroundImagePathActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="btnBrowseBackgroundImage"> <Component class="javax.swing.JButton" name="btnBrowseBackgroundImage">
<Properties> <Properties>
@ -4681,9 +4610,6 @@
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtBattlefieldImagePath"> <Component class="javax.swing.JTextField" name="txtBattlefieldImagePath">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtBattlefieldImagePathActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="btnBrowseBattlefieldImage"> <Component class="javax.swing.JButton" name="btnBrowseBattlefieldImage">
<Properties> <Properties>
@ -4774,36 +4700,24 @@
<Property name="text" type="java.lang.String" value="Enable game sounds"/> <Property name="text" type="java.lang.String" value="Enable game sounds"/>
<Property name="toolTipText" type="java.lang.String" value="Sounds that will be played for certain actions (e.g. play land, attack, etc.) during the game."/> <Property name="toolTipText" type="java.lang.String" value="Sounds that will be played for certain actions (e.g. play land, attack, etc.) during the game."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableGameSoundsActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbEnableDraftSounds"> <Component class="javax.swing.JCheckBox" name="cbEnableDraftSounds">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Enable draft sounds"/> <Property name="text" type="java.lang.String" value="Enable draft sounds"/>
<Property name="toolTipText" type="java.lang.String" value="Sounds that will be played during drafting for card picking or warining if time runs out."/> <Property name="toolTipText" type="java.lang.String" value="Sounds that will be played during drafting for card picking or warining if time runs out."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableDraftSoundsActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbEnableSkipButtonsSounds"> <Component class="javax.swing.JCheckBox" name="cbEnableSkipButtonsSounds">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Enable skip button sounds"/> <Property name="text" type="java.lang.String" value="Enable skip button sounds"/>
<Property name="toolTipText" type="java.lang.String" value="Sounds that will be played if a priority skip action (F4/F5/F7/F9) or cancel skip action (F3) is used."/> <Property name="toolTipText" type="java.lang.String" value="Sounds that will be played if a priority skip action (F4/F5/F7/F9) or cancel skip action (F3) is used."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableSkipButtonsSoundsActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="cbEnableOtherSounds"> <Component class="javax.swing.JCheckBox" name="cbEnableOtherSounds">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Enable other sounds"/> <Property name="text" type="java.lang.String" value="Enable other sounds"/>
<Property name="toolTipText" type="java.lang.String" value="Sounds that will be played for actions outside of games (e.g. whisper, player joins your game, player submits a deck ...)."/> <Property name="toolTipText" type="java.lang.String" value="Sounds that will be played for actions outside of games (e.g. whisper, player joins your game, player submits a deck ...)."/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableOtherSoundsActionPerformed"/>
</Events>
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </Container>
@ -4869,9 +4783,6 @@
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtBattlefieldIBGMPath"> <Component class="javax.swing.JTextField" name="txtBattlefieldIBGMPath">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtBattlefieldIBGMPathActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="btnBattlefieldBGMBrowse"> <Component class="javax.swing.JButton" name="btnBattlefieldBGMBrowse">
<Properties> <Properties>
@ -5993,9 +5904,6 @@
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtProxyPort"> <Component class="javax.swing.JTextField" name="txtProxyPort">
<Events>
<EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="txtProxyPortkeyTyped"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblProxyUserName"> <Component class="javax.swing.JLabel" name="lblProxyUserName">
<Properties> <Properties>
@ -6010,17 +5918,11 @@
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JPasswordField" name="txtPasswordField"> <Component class="javax.swing.JPasswordField" name="txtPasswordField">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtPasswordFieldActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="rememberPswd"> <Component class="javax.swing.JCheckBox" name="rememberPswd">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Remember Password"/> <Property name="text" type="java.lang.String" value="Remember Password"/>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="rememberPswdActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="jLabel11"> <Component class="javax.swing.JLabel" name="jLabel11">
<Properties> <Properties>
@ -6330,7 +6232,7 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="750" max="32767" attributes="0"/> <EmptySpace min="0" pref="807" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -6378,7 +6280,7 @@
<Component id="lbThemeHint" min="-2" max="-2" attributes="0"/> <Component id="lbThemeHint" min="-2" max="-2" attributes="0"/>
<Component id="cbTheme" min="-2" pref="303" max="-2" attributes="0"/> <Component id="cbTheme" min="-2" pref="303" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace pref="303" max="32767" attributes="0"/> <EmptySpace pref="360" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -6410,9 +6312,6 @@
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JComboBox" name="cbTheme"> <Component class="javax.swing.JComboBox" name="cbTheme">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbThemeActionPerformed"/>
</Events>
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ThemeType&gt;"/> <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ThemeType&gt;"/>
</AuxValues> </AuxValues>

View file

@ -49,7 +49,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_DISPLAY_LIVE_ON_AVATAR = "displayLiveOnAvatar"; public static final String KEY_DISPLAY_LIVE_ON_AVATAR = "displayLiveOnAvatar";
public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker"; public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker";
public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards"; public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards";
public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter";
public static final String KEY_GAME_CONFIRM_EMPTY_MANA_POOL = "gameConfirmEmptyManaPool"; public static final String KEY_GAME_CONFIRM_EMPTY_MANA_POOL = "gameConfirmEmptyManaPool";
public static final String KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder"; public static final String KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder";
public static final String KEY_GAME_USE_PROFANITY_FILTER = "gameUseProfanityFilter"; public static final String KEY_GAME_USE_PROFANITY_FILTER = "gameUseProfanityFilter";
@ -214,6 +213,9 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_NEW_TABLE_MINIMUM_RATING = "newTableMinimumRating"; public static final String KEY_NEW_TABLE_MINIMUM_RATING = "newTableMinimumRating";
public static final String KEY_NEW_TABLE_RATED = "newTableRated"; public static final String KEY_NEW_TABLE_RATED = "newTableRated";
public static final String KEY_NEW_TABLE_EDH_POWER_LEVEL = "newTableEdhPowerLevel"; public static final String KEY_NEW_TABLE_EDH_POWER_LEVEL = "newTableEdhPowerLevel";
public static final String KEY_NEW_TABLE_EMBLEM_CARDS_ENABLED = "newTableEmblemCardsEnabled";
public static final String KEY_NEW_TABLE_EMBLEM_CARDS_PER_PLAYER_FILE = "newTableEmblemCardsPerPlayerFile";
public static final String KEY_NEW_TABLE_EMBLEM_CARDS_STARTING_PLAYER_FILE = "newTableEmblemCardsStartingPlayerFile";
// pref setting for new tournament dialog // pref setting for new tournament dialog
public static final String KEY_NEW_TOURNAMENT_NAME = "newTournamentName"; public static final String KEY_NEW_TOURNAMENT_NAME = "newTournamentName";
@ -238,6 +240,9 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio"; public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio";
public static final String KEY_NEW_TOURNAMENT_MINIMUM_RATING = "newTournamentMinimumRating"; public static final String KEY_NEW_TOURNAMENT_MINIMUM_RATING = "newTournamentMinimumRating";
public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated"; public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated";
public static final String KEY_NEW_TOURNAMENT_EMBLEM_CARDS_ENABLED = "newTournamentEmblemCardsEnabled";
public static final String KEY_NEW_TOURNAMENT_EMBLEM_CARDS_PER_PLAYER_FILE = "newTournamentEmblemCardsPerPlayerFile";
public static final String KEY_NEW_TOURNAMENT_EMBLEM_CARDS_STARTING_PLAYER_FILE = "newTournamentEmblemCardsStartingPlayerFile";
// Settings for auto-choosing targets // Settings for auto-choosing targets
public static final String KEY_AUTO_TARGET_LEVEL = "autoTargetLevel"; public static final String KEY_AUTO_TARGET_LEVEL = "autoTargetLevel";
@ -439,7 +444,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
displayLifeOnAvatar = new javax.swing.JCheckBox(); displayLifeOnAvatar = new javax.swing.JCheckBox();
showAbilityPickerForced = new javax.swing.JCheckBox(); showAbilityPickerForced = new javax.swing.JCheckBox();
cbAllowRequestToShowHandCards = new javax.swing.JCheckBox(); cbAllowRequestToShowHandCards = new javax.swing.JCheckBox();
cbShowStormCounter = new javax.swing.JCheckBox();
cbConfirmEmptyManaPool = new javax.swing.JCheckBox(); cbConfirmEmptyManaPool = new javax.swing.JCheckBox();
cbAskMoveToGraveOrder = new javax.swing.JCheckBox(); cbAskMoveToGraveOrder = new javax.swing.JCheckBox();
lblTargetAutoChoose = new javax.swing.JLabel(); lblTargetAutoChoose = new javax.swing.JLabel();
@ -644,22 +648,22 @@ public class PreferencesDialog extends javax.swing.JDialog {
main_gamelog.add(cbGameLogShowTurnInfo); main_gamelog.add(cbGameLogShowTurnInfo);
cbGameLogAutoSave.setSelected(true); cbGameLogAutoSave.setSelected(true);
cbGameLogAutoSave.setText("Save game logs (to \"../Mage.Client/gamelogs/\" directory)"); cbGameLogAutoSave.setText("Save game logs (dest folder: \"..\\xmage\\mage-client\\gamelogs\")");
cbGameLogAutoSave.setToolTipText("The logs of all your games will be saved to the mentioned folder if this option is switched on."); cbGameLogAutoSave.setToolTipText("The logs of all your games will be saved to the mentioned folder if this option is switched on.");
main_gamelog.add(cbGameLogAutoSave); main_gamelog.add(cbGameLogAutoSave);
cbDraftLogAutoSave.setSelected(true); cbDraftLogAutoSave.setSelected(true);
cbDraftLogAutoSave.setText("Save draft logs (to \"../Mage.Client/gamelogs/\" directory)"); cbDraftLogAutoSave.setText("Save draft logs (dest folder: \"..\\xmage\\mage-client\\gamelogs\")");
cbDraftLogAutoSave.setToolTipText("The logs of all your games will be saved to the mentioned folder if this option is switched on."); cbDraftLogAutoSave.setToolTipText("The logs of all your games will be saved to the mentioned folder if this option is switched on.");
cbDraftLogAutoSave.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); cbDraftLogAutoSave.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
main_gamelog.add(cbDraftLogAutoSave); main_gamelog.add(cbDraftLogAutoSave);
cbLimitedDeckAutoSave.setSelected(true); cbLimitedDeckAutoSave.setSelected(true);
cbLimitedDeckAutoSave.setText("Save limited decks on submit (to \"../Mage.Client/gamelogs/\" directory)"); cbLimitedDeckAutoSave.setText("Save limited decks on submit (dest folder: \"..\\xmage\\mage-client\\gamelogs\")");
cbLimitedDeckAutoSave.setToolTipText("A .dck file for each limited tournament will be saved to the mentioned folder if this option is switched on."); cbLimitedDeckAutoSave.setToolTipText("A .dck file for each limited tournament will be saved to the mentioned folder if this option is switched on.");
main_gamelog.add(cbLimitedDeckAutoSave); main_gamelog.add(cbLimitedDeckAutoSave);
cbGameJsonLogAutoSave.setText("Save JSON game logs (to \"../Mage.Client/gamelogsJson/\" directory)"); cbGameJsonLogAutoSave.setText("Save JSON game logs (dest folder: \"..\\xmage\\mage-client\\gamelogs\")");
cbGameJsonLogAutoSave.setToolTipText("The JSON logs of all your games will be saved to the mentioned folder if this option is switched on."); cbGameJsonLogAutoSave.setToolTipText("The JSON logs of all your games will be saved to the mentioned folder if this option is switched on.");
main_gamelog.add(cbGameJsonLogAutoSave); main_gamelog.add(cbGameJsonLogAutoSave);
@ -733,74 +737,30 @@ public class PreferencesDialog extends javax.swing.JDialog {
nonLandPermanentsInOnePile.setSelected(true); nonLandPermanentsInOnePile.setSelected(true);
nonLandPermanentsInOnePile.setText("Put non-land permanents in same row as creatures"); nonLandPermanentsInOnePile.setText("Put non-land permanents in same row as creatures");
nonLandPermanentsInOnePile.setToolTipText("<html>If activated, all non land permanents are shown in one row.<br>\nFirst creatures than other permanents. If not activated, creatures are<br>\nshown in a separate row."); nonLandPermanentsInOnePile.setToolTipText("<html>If activated, all non land permanents are shown in one row.<br>\nFirst creatures than other permanents. If not activated, creatures are<br>\nshown in a separate row.");
nonLandPermanentsInOnePile.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
nonLandPermanentsInOnePileActionPerformed(evt);
}
});
showPlayerNamesPermanently.setSelected(true); showPlayerNamesPermanently.setSelected(true);
showPlayerNamesPermanently.setText("Show player names on avatar permanently"); showPlayerNamesPermanently.setText("Show player names on avatar permanently");
showPlayerNamesPermanently.setToolTipText("Instead showing the names only if you hover over the avatar with the mouse, the name is shown all the time."); showPlayerNamesPermanently.setToolTipText("Instead showing the names only if you hover over the avatar with the mouse, the name is shown all the time.");
showPlayerNamesPermanently.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showPlayerNamesPermanentlyActionPerformed(evt);
}
});
displayLifeOnAvatar.setSelected(true); displayLifeOnAvatar.setSelected(true);
displayLifeOnAvatar.setText("Display life on avatar image"); displayLifeOnAvatar.setText("Display life on avatar image");
displayLifeOnAvatar.setToolTipText("Display the player's life over its avatar image."); displayLifeOnAvatar.setToolTipText("Display the player's life over its avatar image.");
displayLifeOnAvatar.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
displayLifeOnAvatarActionPerformed(evt);
}
});
showAbilityPickerForced.setSelected(true); showAbilityPickerForced.setSelected(true);
showAbilityPickerForced.setText("Show ability picker for 1 available option (spells without costs, mdf/split side, adventure)"); showAbilityPickerForced.setText("Show ability picker for 1 available option (spells without costs, mdf/split side, adventure)");
showAbilityPickerForced.setToolTipText("This prevents you from accidently activating abilities what you don't want (example: if you haven't mana to cast main side, but clicks on mdf card and play land instead)"); showAbilityPickerForced.setToolTipText("This prevents you from accidently activating abilities what you don't want (example: if you haven't mana to cast main side, but clicks on mdf card and play land instead)");
showAbilityPickerForced.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showAbilityPickerForcedActionPerformed(evt);
}
});
cbAllowRequestToShowHandCards.setSelected(true); cbAllowRequestToShowHandCards.setSelected(true);
cbAllowRequestToShowHandCards.setText("Allow requests from players and spectators to show your hand cards"); cbAllowRequestToShowHandCards.setText("Allow requests from players and spectators to show your hand cards");
cbAllowRequestToShowHandCards.setToolTipText("<html>This is the default setting used for your matches. If activated other players or spectators<br>\nof your match can send a request so you can allow them to see your hand cards."); cbAllowRequestToShowHandCards.setToolTipText("<html>This is the default setting used for your matches. If activated other players or spectators<br>\nof your match can send a request so you can allow them to see your hand cards.");
cbAllowRequestToShowHandCards.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbAllowRequestToShowHandCardsActionPerformed(evt);
}
});
cbShowStormCounter.setSelected(true);
cbShowStormCounter.setText("Show the number of spell casts during the current turn");
cbShowStormCounter.setToolTipText("<html>Adds a little box left to the short keys line with the number<br>\nof spells already cast during the current turn (storm counter).");
cbShowStormCounter.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbShowStormCounterActionPerformed(evt);
}
});
cbConfirmEmptyManaPool.setSelected(true); cbConfirmEmptyManaPool.setSelected(true);
cbConfirmEmptyManaPool.setText("Confirm if you want to pass a phase/step but there is still mana in your mana pool"); cbConfirmEmptyManaPool.setText("Confirm if you want to pass a phase/step but there is still mana in your mana pool");
cbConfirmEmptyManaPool.setToolTipText("<html>If activated you get a confirm message if you pass priority while stack is empty<br>\n and you still have mana in your mana pool."); cbConfirmEmptyManaPool.setToolTipText("<html>If activated you get a confirm message if you pass priority while stack is empty<br>\n and you still have mana in your mana pool.");
cbConfirmEmptyManaPool.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbConfirmEmptyManaPoolActionPerformed(evt);
}
});
cbAskMoveToGraveOrder.setSelected(true); cbAskMoveToGraveOrder.setSelected(true);
cbAskMoveToGraveOrder.setText("Ask player for setting order cards go to graveyard"); cbAskMoveToGraveOrder.setText("Ask player for setting order cards go to graveyard");
cbAskMoveToGraveOrder.setToolTipText("<html>If activated and multiple cards go to the graveyard at the same time<br>\nthe player is asked to set the order of the cards."); cbAskMoveToGraveOrder.setToolTipText("<html>If activated and multiple cards go to the graveyard at the same time<br>\nthe player is asked to set the order of the cards.");
cbAskMoveToGraveOrder.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbAskMoveToGraveOrderActionPerformed(evt);
}
});
lblTargetAutoChoose.setText("Auto-choose targets for player:"); lblTargetAutoChoose.setText("Auto-choose targets for player:");
lblTargetAutoChoose.setToolTipText("<html>\nWhen there is only one possible outcome for targeting, the targets can be chosen for you.\n<br>\n<b>None:</b> All targeting must be done by the player.\n<br>\n<b>Most:</b> All targeting other than feel-bad effects (discarding, destroy, sacrifice, exile) that target you, a card you own, or a permanent/spell you control.\n<br>\n<b>All:</b> All targeting that can be automated will be."); lblTargetAutoChoose.setToolTipText("<html>\nWhen there is only one possible outcome for targeting, the targets can be chosen for you.\n<br>\n<b>None:</b> All targeting must be done by the player.\n<br>\n<b>Most:</b> All targeting other than feel-bad effects (discarding, destroy, sacrifice, exile) that target you, a card you own, or a permanent/spell you control.\n<br>\n<b>All:</b> All targeting that can be automated will be.");
@ -808,34 +768,27 @@ public class PreferencesDialog extends javax.swing.JDialog {
cbTargetAutoChooseLevel.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Off", "Most", "All" })); cbTargetAutoChooseLevel.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Off", "Most", "All" }));
cbTargetAutoChooseLevel.setSelectedIndex(1); cbTargetAutoChooseLevel.setSelectedIndex(1);
cbTargetAutoChooseLevel.setToolTipText(lblTargetAutoChoose.getToolTipText()); cbTargetAutoChooseLevel.setToolTipText(lblTargetAutoChoose.getToolTipText());
cbTargetAutoChooseLevel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbTargetAutoChooseLevelActionPerformed(evt);
}
});
org.jdesktop.layout.GroupLayout main_gameLayout = new org.jdesktop.layout.GroupLayout(main_game); org.jdesktop.layout.GroupLayout main_gameLayout = new org.jdesktop.layout.GroupLayout(main_game);
main_game.setLayout(main_gameLayout); main_game.setLayout(main_gameLayout);
main_gameLayout.setHorizontalGroup( main_gameLayout.setHorizontalGroup(
main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(main_gameLayout.createSequentialGroup()
.addContainerGap()
.add(lblTargetAutoChoose)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbTargetAutoChooseLevel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.add(displayLifeOnAvatar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(displayLifeOnAvatar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(main_gameLayout.createSequentialGroup() .add(main_gameLayout.createSequentialGroup()
.add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(main_gameLayout.createSequentialGroup()
.addContainerGap()
.add(lblTargetAutoChoose)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbTargetAutoChooseLevel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 596, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 596, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
.add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(cbConfirmEmptyManaPool, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(cbConfirmEmptyManaPool, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(showAbilityPickerForced))) .add(showAbilityPickerForced)))
.add(0, 315, Short.MAX_VALUE)) .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
); );
main_gameLayout.setVerticalGroup( main_gameLayout.setVerticalGroup(
main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -850,8 +803,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbAllowRequestToShowHandCards) .add(cbAllowRequestToShowHandCards)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbShowStormCounter)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbConfirmEmptyManaPool) .add(cbConfirmEmptyManaPool)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbAskMoveToGraveOrder) .add(cbAskMoveToGraveOrder)
@ -1443,108 +1394,58 @@ public class PreferencesDialog extends javax.swing.JDialog {
cbStopAttack.setText("STOP skips on declare attackers if attackers are available"); cbStopAttack.setText("STOP skips on declare attackers if attackers are available");
cbStopAttack.setToolTipText(""); cbStopAttack.setToolTipText("");
cbStopAttack.setActionCommand(""); cbStopAttack.setActionCommand("");
cbStopAttack.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopAttackActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopAttack); phases_stopSettings.add(cbStopAttack);
cbStopBlockWithAny.setSelected(true); cbStopBlockWithAny.setSelected(true);
cbStopBlockWithAny.setText("STOP skips on declare blockers if ANY blockers are available"); cbStopBlockWithAny.setText("STOP skips on declare blockers if ANY blockers are available");
cbStopBlockWithAny.setToolTipText(""); cbStopBlockWithAny.setToolTipText("");
cbStopBlockWithAny.setActionCommand(""); cbStopBlockWithAny.setActionCommand("");
cbStopBlockWithAny.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopBlockWithAnyActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopBlockWithAny); phases_stopSettings.add(cbStopBlockWithAny);
cbStopBlockWithZero.setText("STOP skips on declare blockers if ZERO blockers are available"); cbStopBlockWithZero.setText("STOP skips on declare blockers if ZERO blockers are available");
cbStopBlockWithZero.setToolTipText(""); cbStopBlockWithZero.setToolTipText("");
cbStopBlockWithZero.setActionCommand(""); cbStopBlockWithZero.setActionCommand("");
cbStopBlockWithZero.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopBlockWithZeroActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopBlockWithZero); phases_stopSettings.add(cbStopBlockWithZero);
cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)"); cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)");
cbStopOnNewStackObjects.setToolTipText(""); cbStopOnNewStackObjects.setToolTipText("");
cbStopOnNewStackObjects.setActionCommand(""); cbStopOnNewStackObjects.setActionCommand("");
cbStopOnNewStackObjects.setPreferredSize(new java.awt.Dimension(300, 25)); cbStopOnNewStackObjects.setPreferredSize(new java.awt.Dimension(300, 25));
cbStopOnNewStackObjects.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopOnNewStackObjectsActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopOnNewStackObjects); phases_stopSettings.add(cbStopOnNewStackObjects);
cbStopOnAllMain.setText("Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)"); cbStopOnAllMain.setText("Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)");
cbStopOnAllMain.setToolTipText(""); cbStopOnAllMain.setToolTipText("");
cbStopOnAllMain.setActionCommand(""); cbStopOnAllMain.setActionCommand("");
cbStopOnAllMain.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopOnAllMainActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopOnAllMain); phases_stopSettings.add(cbStopOnAllMain);
cbStopOnAllEnd.setText("Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)"); cbStopOnAllEnd.setText("Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)");
cbStopOnAllEnd.setToolTipText(""); cbStopOnAllEnd.setToolTipText("");
cbStopOnAllEnd.setActionCommand(""); cbStopOnAllEnd.setActionCommand("");
cbStopOnAllEnd.setPreferredSize(new java.awt.Dimension(300, 25)); cbStopOnAllEnd.setPreferredSize(new java.awt.Dimension(300, 25));
cbStopOnAllEnd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopOnAllEndActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopOnAllEnd); phases_stopSettings.add(cbStopOnAllEnd);
cbPassPriorityCast.setText("Pass priority automatically after you have put a spell on the stack"); cbPassPriorityCast.setText("Pass priority automatically after you have put a spell on the stack");
cbPassPriorityCast.setToolTipText("If activated the system passes priority automatically for you if you have put a spell on the stack."); cbPassPriorityCast.setToolTipText("If activated the system passes priority automatically for you if you have put a spell on the stack.");
cbPassPriorityCast.setActionCommand(""); cbPassPriorityCast.setActionCommand("");
cbPassPriorityCast.setPreferredSize(new java.awt.Dimension(300, 25)); cbPassPriorityCast.setPreferredSize(new java.awt.Dimension(300, 25));
cbPassPriorityCast.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbPassPriorityCastActionPerformed(evt);
}
});
phases_stopSettings.add(cbPassPriorityCast); phases_stopSettings.add(cbPassPriorityCast);
cbPassPriorityActivation.setText("Pass priority automatically after you have put an activated ability on the stack"); cbPassPriorityActivation.setText("Pass priority automatically after you have put an activated ability on the stack");
cbPassPriorityActivation.setToolTipText("If activated the system passes priority for you automatically after you have put an activated ability on the stack."); cbPassPriorityActivation.setToolTipText("If activated the system passes priority for you automatically after you have put an activated ability on the stack.");
cbPassPriorityActivation.setActionCommand(""); cbPassPriorityActivation.setActionCommand("");
cbPassPriorityActivation.setPreferredSize(new java.awt.Dimension(300, 25)); cbPassPriorityActivation.setPreferredSize(new java.awt.Dimension(300, 25));
cbPassPriorityActivation.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbPassPriorityActivationActionPerformed(evt);
}
});
phases_stopSettings.add(cbPassPriorityActivation); phases_stopSettings.add(cbPassPriorityActivation);
cbAutoOrderTrigger.setText("TRIGGERS: auto-choose triggers order for same rule texts (put same triggers to the stack at default order)"); cbAutoOrderTrigger.setText("TRIGGERS: auto-choose triggers order for same rule texts (put same triggers to the stack at default order)");
cbAutoOrderTrigger.setToolTipText("<HTML>If you put same triggers with same texts on the stack then auto-choose their order.<br/>\nYou can change that settings anytime at the game."); cbAutoOrderTrigger.setToolTipText("<HTML>If you put same triggers with same texts on the stack then auto-choose their order.<br/>\nYou can change that settings anytime at the game.");
cbAutoOrderTrigger.setActionCommand(""); cbAutoOrderTrigger.setActionCommand("");
cbAutoOrderTrigger.setPreferredSize(new java.awt.Dimension(300, 25)); cbAutoOrderTrigger.setPreferredSize(new java.awt.Dimension(300, 25));
cbAutoOrderTrigger.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbAutoOrderTriggerActionPerformed(evt);
}
});
phases_stopSettings.add(cbAutoOrderTrigger); phases_stopSettings.add(cbAutoOrderTrigger);
cbUseSameSettingsForReplacementEffect.setText("REPLACEMENT EFFECTS: use same auto-choose settings for same cards (choose replacement effects order dialog)"); cbUseSameSettingsForReplacementEffect.setText("REPLACEMENT EFFECTS: use same auto-choose settings for same cards (choose replacement effects order dialog)");
cbUseSameSettingsForReplacementEffect.setToolTipText("<HTML>If you setup auto-choose for one object/card then it will be applied for all other objects with same name.<br/>\nYou can change that settings anytime at the game."); cbUseSameSettingsForReplacementEffect.setToolTipText("<HTML>If you setup auto-choose for one object/card then it will be applied for all other objects with same name.<br/>\nYou can change that settings anytime at the game.");
cbUseSameSettingsForReplacementEffect.setActionCommand(""); cbUseSameSettingsForReplacementEffect.setActionCommand("");
cbUseSameSettingsForReplacementEffect.setPreferredSize(new java.awt.Dimension(300, 25)); cbUseSameSettingsForReplacementEffect.setPreferredSize(new java.awt.Dimension(300, 25));
cbUseSameSettingsForReplacementEffect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbUseSameSettingsForReplacementEffectActionPerformed(evt);
}
});
phases_stopSettings.add(cbUseSameSettingsForReplacementEffect); phases_stopSettings.add(cbUseSameSettingsForReplacementEffect);
org.jdesktop.layout.GroupLayout tabPhasesLayout = new org.jdesktop.layout.GroupLayout(tabPhases); org.jdesktop.layout.GroupLayout tabPhasesLayout = new org.jdesktop.layout.GroupLayout(tabPhases);
@ -1781,12 +1682,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}); });
txtBackgroundImagePath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtBackgroundImagePathActionPerformed(evt);
}
});
btnBrowseBackgroundImage.setText("Browse..."); btnBrowseBackgroundImage.setText("Browse...");
btnBrowseBackgroundImage.addActionListener(new java.awt.event.ActionListener() { btnBrowseBackgroundImage.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -1794,12 +1689,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}); });
txtBattlefieldImagePath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtBattlefieldImagePathActionPerformed(evt);
}
});
btnBrowseBattlefieldImage.setText("Browse..."); btnBrowseBattlefieldImage.setText("Browse...");
btnBrowseBattlefieldImage.addActionListener(new java.awt.event.ActionListener() { btnBrowseBattlefieldImage.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -1892,38 +1781,18 @@ public class PreferencesDialog extends javax.swing.JDialog {
cbEnableGameSounds.setText("Enable game sounds"); cbEnableGameSounds.setText("Enable game sounds");
cbEnableGameSounds.setToolTipText("Sounds that will be played for certain actions (e.g. play land, attack, etc.) during the game."); cbEnableGameSounds.setToolTipText("Sounds that will be played for certain actions (e.g. play land, attack, etc.) during the game.");
cbEnableGameSounds.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbEnableGameSoundsActionPerformed(evt);
}
});
sounds_clips.add(cbEnableGameSounds); sounds_clips.add(cbEnableGameSounds);
cbEnableDraftSounds.setText("Enable draft sounds"); cbEnableDraftSounds.setText("Enable draft sounds");
cbEnableDraftSounds.setToolTipText("Sounds that will be played during drafting for card picking or warining if time runs out."); cbEnableDraftSounds.setToolTipText("Sounds that will be played during drafting for card picking or warining if time runs out.");
cbEnableDraftSounds.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbEnableDraftSoundsActionPerformed(evt);
}
});
sounds_clips.add(cbEnableDraftSounds); sounds_clips.add(cbEnableDraftSounds);
cbEnableSkipButtonsSounds.setText("Enable skip button sounds"); cbEnableSkipButtonsSounds.setText("Enable skip button sounds");
cbEnableSkipButtonsSounds.setToolTipText("Sounds that will be played if a priority skip action (F4/F5/F7/F9) or cancel skip action (F3) is used."); cbEnableSkipButtonsSounds.setToolTipText("Sounds that will be played if a priority skip action (F4/F5/F7/F9) or cancel skip action (F3) is used.");
cbEnableSkipButtonsSounds.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbEnableSkipButtonsSoundsActionPerformed(evt);
}
});
sounds_clips.add(cbEnableSkipButtonsSounds); sounds_clips.add(cbEnableSkipButtonsSounds);
cbEnableOtherSounds.setText("Enable other sounds"); cbEnableOtherSounds.setText("Enable other sounds");
cbEnableOtherSounds.setToolTipText("Sounds that will be played for actions outside of games (e.g. whisper, player joins your game, player submits a deck ...)."); cbEnableOtherSounds.setToolTipText("Sounds that will be played for actions outside of games (e.g. whisper, player joins your game, player submits a deck ...).");
cbEnableOtherSounds.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbEnableOtherSoundsActionPerformed(evt);
}
});
sounds_clips.add(cbEnableOtherSounds); sounds_clips.add(cbEnableOtherSounds);
sounds_backgroundMusic.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Music")); sounds_backgroundMusic.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Music"));
@ -1940,12 +1809,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
jLabel16.setText("Playing from folder:"); jLabel16.setText("Playing from folder:");
jLabel16.setToolTipText(""); jLabel16.setToolTipText("");
txtBattlefieldIBGMPath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtBattlefieldIBGMPathActionPerformed(evt);
}
});
btnBattlefieldBGMBrowse.setText("Browse..."); btnBattlefieldBGMBrowse.setText("Browse...");
btnBattlefieldBGMBrowse.addActionListener(new java.awt.event.ActionListener() { btnBattlefieldBGMBrowse.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -2518,28 +2381,11 @@ public class PreferencesDialog extends javax.swing.JDialog {
lblProxyPort.setText("Port:"); lblProxyPort.setText("Port:");
txtProxyPort.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
txtProxyPortkeyTyped(evt);
}
});
lblProxyUserName.setText("User Name:"); lblProxyUserName.setText("User Name:");
lblProxyPassword.setText("Password:"); lblProxyPassword.setText("Password:");
txtPasswordField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtPasswordFieldActionPerformed(evt);
}
});
rememberPswd.setText("Remember Password"); rememberPswd.setText("Remember Password");
rememberPswd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rememberPswdActionPerformed(evt);
}
});
jLabel11.setFont(new java.awt.Font("Tahoma", 2, 10)); // NOI18N jLabel11.setFont(new java.awt.Font("Tahoma", 2, 10)); // NOI18N
jLabel11.setText("Note: password won't be encrypted!"); jLabel11.setText("Note: password won't be encrypted!");
@ -2804,12 +2650,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
lbSelectLabel.setPreferredSize(new java.awt.Dimension(110, 16)); lbSelectLabel.setPreferredSize(new java.awt.Dimension(110, 16));
lbSelectLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP); lbSelectLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
cbTheme.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbThemeActionPerformed(evt);
}
});
lbThemeHint.setText("Requires a restart to apply new theme."); lbThemeHint.setText("Requires a restart to apply new theme.");
org.jdesktop.layout.GroupLayout themesCategoryLayout = new org.jdesktop.layout.GroupLayout(themesCategory); org.jdesktop.layout.GroupLayout themesCategoryLayout = new org.jdesktop.layout.GroupLayout(themesCategory);
@ -2823,7 +2663,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(lbThemeHint) .add(lbThemeHint)
.add(cbTheme, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 303, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .add(cbTheme, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 303, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addContainerGap(303, Short.MAX_VALUE)) .addContainerGap(360, Short.MAX_VALUE))
); );
themesCategoryLayout.setVerticalGroup( themesCategoryLayout.setVerticalGroup(
themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -2840,7 +2680,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
tabThemes.setLayout(tabThemesLayout); tabThemes.setLayout(tabThemesLayout);
tabThemesLayout.setHorizontalGroup( tabThemesLayout.setHorizontalGroup(
tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 750, Short.MAX_VALUE) .add(0, 807, Short.MAX_VALUE)
.add(tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(tabThemesLayout.createSequentialGroup() .add(tabThemesLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
@ -2897,7 +2737,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup() .add(layout.createSequentialGroup()
.add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 584, Short.MAX_VALUE) .add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
@ -2920,7 +2760,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbGameLogShowTurnInfo, KEY_GAME_LOG_SHOW_TURN_INFO, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbGameLogShowTurnInfo, KEY_GAME_LOG_SHOW_TURN_INFO, "true", "false", UPDATE_CACHE_POLICY);
@ -3097,19 +2936,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
this.showProxySettings(); this.showProxySettings();
}//GEN-LAST:event_cbProxyTypeActionPerformed }//GEN-LAST:event_cbProxyTypeActionPerformed
private void txtPasswordFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtPasswordFieldActionPerformed
}//GEN-LAST:event_txtPasswordFieldActionPerformed
private void txtProxyPortkeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtProxyPortkeyTyped
}//GEN-LAST:event_txtProxyPortkeyTyped
private void rememberPswdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rememberPswdActionPerformed
}//GEN-LAST:event_rememberPswdActionPerformed
private void cbEnableGameSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableGameSoundsActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbEnableGameSoundsActionPerformed
private void cbEnableBattlefieldBGMActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableBattlefieldBGMActionPerformed private void cbEnableBattlefieldBGMActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableBattlefieldBGMActionPerformed
if (cbEnableBattlefieldBGM.isSelected()) { if (cbEnableBattlefieldBGM.isSelected()) {
txtBattlefieldIBGMPath.setEnabled(true); txtBattlefieldIBGMPath.setEnabled(true);
@ -3206,20 +3032,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
} }
private void txtBackgroundImagePathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBackgroundImagePathActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtBackgroundImagePathActionPerformed
private void txtBattlefieldImagePathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBattlefieldImagePathActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtBattlefieldImagePathActionPerformed
private void txtBattlefieldIBGMPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBattlefieldIBGMPathActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtBattlefieldIBGMPathActionPerformed
private void btnBattlefieldBGMBrowseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBattlefieldBGMBrowseActionPerformed private void btnBattlefieldBGMBrowseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBattlefieldBGMBrowseActionPerformed
// TODO add your handling code here:
int returnVal = fc.showOpenDialog(PreferencesDialog.this); int returnVal = fc.showOpenDialog(PreferencesDialog.this);
if (returnVal == JFileChooser.APPROVE_OPTION) { if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile(); File file = fc.getSelectedFile();
@ -3227,78 +3040,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}//GEN-LAST:event_btnBattlefieldBGMBrowseActionPerformed }//GEN-LAST:event_btnBattlefieldBGMBrowseActionPerformed
private void nonLandPermanentsInOnePileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nonLandPermanentsInOnePileActionPerformed
}//GEN-LAST:event_nonLandPermanentsInOnePileActionPerformed
private void showPlayerNamesPermanentlyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showPlayerNamesPermanentlyActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_showPlayerNamesPermanentlyActionPerformed
private void showCardNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCardNameActionPerformed private void showCardNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCardNameActionPerformed
}//GEN-LAST:event_showCardNameActionPerformed }//GEN-LAST:event_showCardNameActionPerformed
private void showAbilityPickerForcedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAbilityPickerForcedActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_showAbilityPickerForcedActionPerformed
private void cbEnableOtherSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableOtherSoundsActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbEnableOtherSoundsActionPerformed
private void cbStopAttackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopAttackActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopAttackActionPerformed
private void cbStopBlockWithAnyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockWithAnyActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopBlockWithAnyActionPerformed
private void cbStopOnAllMainActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnAllMainActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopOnAllMainActionPerformed
private void cbStopOnAllEndActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnAllEndActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopOnAllEndActionPerformed
private void cbEnableDraftSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableDraftSoundsActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbEnableDraftSoundsActionPerformed
private void cbEnableSkipButtonsSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableSkipButtonsSoundsActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbEnableSkipButtonsSoundsActionPerformed
private void cbAllowRequestToShowHandCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAllowRequestToShowHandCardsActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbAllowRequestToShowHandCardsActionPerformed
private void cbShowStormCounterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbShowStormCounterActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbShowStormCounterActionPerformed
private void cbConfirmEmptyManaPoolActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbConfirmEmptyManaPoolActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbConfirmEmptyManaPoolActionPerformed
private void cbAskMoveToGraveOrderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAskMoveToGraveOrderActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbAskMoveToGraveOrderActionPerformed
private void cbPassPriorityCastActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPassPriorityCastActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbPassPriorityCastActionPerformed
private void cbPassPriorityActivationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPassPriorityActivationActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbPassPriorityActivationActionPerformed
private void cbAutoOrderTriggerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAutoOrderTriggerActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbAutoOrderTriggerActionPerformed
private void bttnResetControlsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bttnResetControlsActionPerformed private void bttnResetControlsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bttnResetControlsActionPerformed
getKeybindButtons().forEach((bttn) -> { getKeybindButtons().forEach((bttn) -> {
String id = bttn.getKey(); String id = bttn.getKey();
@ -3316,18 +3061,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
}//GEN-LAST:event_cbBattlefieldFeedbackColorizingModeActionPerformed }//GEN-LAST:event_cbBattlefieldFeedbackColorizingModeActionPerformed
private void displayLifeOnAvatarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayLifeOnAvatarActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_displayLifeOnAvatarActionPerformed
private void cbStopOnNewStackObjectsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnNewStackObjectsActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopOnNewStackObjectsActionPerformed
private void cbStopBlockWithZeroActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockWithZeroActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbStopBlockWithZeroActionPerformed
private void cbSaveToZipFilesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbSaveToZipFilesActionPerformed private void cbSaveToZipFilesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbSaveToZipFilesActionPerformed
// TODO add your handling code here: // TODO add your handling code here:
}//GEN-LAST:event_cbSaveToZipFilesActionPerformed }//GEN-LAST:event_cbSaveToZipFilesActionPerformed
@ -3349,10 +3082,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}//GEN-LAST:event_cbUseDefaultImageFolderActionPerformed }//GEN-LAST:event_cbUseDefaultImageFolderActionPerformed
private void cbThemeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbThemeActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbThemeActionPerformed
private void sliderGUISizeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderGUISizeStateChanged private void sliderGUISizeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderGUISizeStateChanged
// This prevents this event from firing during the initial // This prevents this event from firing during the initial
// setting of the sliders from pref values // setting of the sliders from pref values
@ -3362,14 +3091,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}//GEN-LAST:event_sliderGUISizeStateChanged }//GEN-LAST:event_sliderGUISizeStateChanged
private void cbUseSameSettingsForReplacementEffectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseSameSettingsForReplacementEffectActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbUseSameSettingsForReplacementEffectActionPerformed
private void cbTargetAutoChooseLevelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbTargetAutoChooseLevelActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cbTargetAutoChooseLevelActionPerformed
private void showProxySettings() { private void showProxySettings() {
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
switch (proxyType) { switch (proxyType) {
@ -3482,7 +3203,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
load(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true"); load(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true");
load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true"); load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true");
load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true"); load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true");
load(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true");
load(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true"); load(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true");
load(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true"); load(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true");
@ -4133,7 +3853,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
private javax.swing.JComboBox<String> cbPreferredImageLanguage; private javax.swing.JComboBox<String> cbPreferredImageLanguage;
private javax.swing.JComboBox<ProxyType> cbProxyType; private javax.swing.JComboBox<ProxyType> cbProxyType;
private javax.swing.JCheckBox cbSaveToZipFiles; private javax.swing.JCheckBox cbSaveToZipFiles;
private javax.swing.JCheckBox cbShowStormCounter;
private javax.swing.JCheckBox cbStopAttack; private javax.swing.JCheckBox cbStopAttack;
private javax.swing.JCheckBox cbStopBlockWithAny; private javax.swing.JCheckBox cbStopBlockWithAny;
private javax.swing.JCheckBox cbStopBlockWithZero; private javax.swing.JCheckBox cbStopBlockWithZero;

View file

@ -19,7 +19,7 @@
import java.util.UUID; import java.util.UUID;
/** /**
* Game GUI: choose target card from the cards list (example: exile and choose card to cast) * Game GUI: choose target card from the cards list (example: exile and choose card to cast, choose triggers order, etc)
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */

View file

@ -19,7 +19,6 @@
import javax.swing.Timer; import javax.swing.Timer;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.dnd.DragSourceEvent;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
@ -42,6 +41,20 @@
private Timer countdown; private Timer countdown;
private int timeout; private int timeout;
/**
* ms delay between booster showing up and pick being allowed.
*/
private static final int protectionTime = 1500;
/**
* Timer starting at booster being displayed, to protect from early pick due to clicking
* a little too much on the last pick.
*/
private Timer protectionTimer;
/**
* Number of the latest card pick for which the protection timer has been set.
*/
private int protectionPickNo = 0;
// popup menu area picked cards // popup menu area picked cards
private final JPopupMenu popupMenuPickedArea; private final JPopupMenu popupMenuPickedArea;
// popup menu for a card // popup menu for a card
@ -108,6 +121,8 @@
} }
} }
); );
protectionTimer = new Timer(protectionTime, e -> protectionTimer.stop());
} }
public void cleanUp() { public void cleanUp() {
@ -120,6 +135,13 @@
countdown.removeActionListener(al); countdown.removeActionListener(al);
} }
} }
if (protectionTimer != null) {
protectionTimer.stop();
for (ActionListener al : protectionTimer.getActionListeners()) {
protectionTimer.removeActionListener(al);
}
}
} }
public void changeGUISize() { public void changeGUISize() {
@ -311,7 +333,13 @@
} }
if (!draftBooster.isEmptyGrid()) { if (!draftBooster.isEmptyGrid()) {
SessionHandler.setBoosterLoaded(draftId); // confirm to the server that the booster has been successfully loaded, otherwise the server will re-send the booster SessionHandler.setBoosterLoaded(draftId); // confirm to the server that the booster has been successfully loaded, otherwise the server will re-send the booster
if (pickNo != protectionPickNo && !protectionTimer.isRunning()) {
// Restart the protection timer.
protectionPickNo = pickNo;
protectionTimer.restart();
}
} }
} }
@ -345,6 +373,10 @@
} }
} }
public boolean isAllowedToPick() {
return !protectionTimer.isRunning();
}
public void hideDraft() { public void hideDraft() {
Component c = this.getParent(); Component c = this.getParent();
while (c != null && !(c instanceof DraftPane)) { while (c != null && !(c instanceof DraftPane)) {
@ -417,7 +449,7 @@
// that's why instead of proactively logging our pick we instead // that's why instead of proactively logging our pick we instead
// log *last* pick from the list of picks. // log *last* pick from the list of picks.
// To make this possible we cache the list of cards from the // To make this possible we cache the list of cards from the
// previous booster and it's sequence number (pack number / pick number) // previous booster and its sequence number (pack number / pick number)
// in fields currentBooster and currentBoosterHeader. // in fields currentBooster and currentBoosterHeader.
private void logLastPick(DraftPickView pickView) { private void logLastPick(DraftPickView pickView) {
if (!isLogging()) { if (!isLogging()) {
@ -438,11 +470,13 @@
private String getCurrentSetCode() { private String getCurrentSetCode() {
// TODO: Record set codes for random drafts correctly // TODO: Record set codes for random drafts correctly
if (setCodes.size() >= packNo) { if (setCodes != null && setCodes.size() >= packNo) {
return setCodes.get(packNo - 1); String setCode = setCodes.get(packNo - 1);
} else { if (setCode != null) { // Not sure how, but got a NPE from this method P1P2 in a ZEN/ZEN/WWK draft
return " "; return setCode;
}
} }
return " ";
} }
private static boolean isLogging() { private static boolean isLogging() {
@ -525,7 +559,7 @@
lblPlayer15 = new javax.swing.JLabel(); lblPlayer15 = new javax.swing.JLabel();
lblPlayer16 = new javax.swing.JLabel(); lblPlayer16 = new javax.swing.JLabel();
draftPicks = new mage.client.cards.CardsList(); draftPicks = new mage.client.cards.CardsList();
draftBooster = new mage.client.cards.DraftGrid(); draftBooster = new mage.client.cards.DraftGrid(this);
draftLeftPane.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); draftLeftPane.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
draftLeftPane.setFocusable(false); draftLeftPane.setFocusable(false);

View file

@ -38,7 +38,6 @@ public class FeedbackPanel extends javax.swing.JPanel {
private FeedbackMode mode; private FeedbackMode mode;
private MageDialog connectedDialog; private MageDialog connectedDialog;
private ChatPanelBasic connectedChatPanel; private ChatPanelBasic connectedChatPanel;
private int lastMessageId;
private Map<String, Serializable> lastOptions = new HashMap<>(); private Map<String, Serializable> lastOptions = new HashMap<>();
private static final ScheduledExecutorService WORKER = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService WORKER = Executors.newSingleThreadScheduledExecutor();
@ -66,14 +65,8 @@ public class FeedbackPanel extends javax.swing.JPanel {
} }
public void prepareFeedback(FeedbackMode mode, String message, boolean special, Map<String, Serializable> options, public void prepareFeedback(FeedbackMode mode, String message, boolean special, Map<String, Serializable> options,
int messageId, boolean gameNeedUserFeedback, TurnPhase gameTurnPhase) { boolean gameNeedUserFeedback, TurnPhase gameTurnPhase) {
synchronized (this) { synchronized (this) {
if (messageId < this.lastMessageId) {
// if too many warning messages here then look at GAME_REDRAW_GUI event logic
LOGGER.warn("catch un-synced message from later source (possible reason: connection or performance problems): " + messageId + ", text=" + message);
return;
}
this.lastMessageId = messageId;
this.lastOptions = options; this.lastOptions = options;
this.mode = mode; this.mode = mode;
} }

View file

@ -14,6 +14,7 @@ import mage.client.components.KeyboundButton;
import mage.client.components.MageComponents; import mage.client.components.MageComponents;
import mage.client.components.ext.dlg.DialogManager; import mage.client.components.ext.dlg.DialogManager;
import mage.client.components.layout.RelativeLayout; import mage.client.components.layout.RelativeLayout;
import mage.client.components.tray.MageTray;
import mage.client.dialog.*; import mage.client.dialog.*;
import mage.client.dialog.CardInfoWindowDialog.ShowType; import mage.client.dialog.CardInfoWindowDialog.ShowType;
import mage.client.game.FeedbackPanel.FeedbackMode; import mage.client.game.FeedbackPanel.FeedbackMode;
@ -122,8 +123,8 @@ public final class GamePanel extends javax.swing.JPanel {
private JPopupMenu popupMenuTriggerOrder; private JPopupMenu popupMenuTriggerOrder;
// keep game data for updates/re-draws // keep game data for updates/re-draws
// warning, it keeps updates from GAME_UPDATE events only and ignore another events with GameView
static class LastGameData { static class LastGameData {
int messageId;
GameView game; GameView game;
boolean showPlayable; boolean showPlayable;
Map<String, Serializable> options; Map<String, Serializable> options;
@ -366,7 +367,6 @@ public final class GamePanel extends javax.swing.JPanel {
jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize); jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize);
jSplitPane2.setDividerSize(GUISizeHelper.dividerBarSize); jSplitPane2.setDividerSize(GUISizeHelper.dividerBarSize);
txtSpellsCast.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize()));
txtHoldPriority.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); txtHoldPriority.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize()));
GUISizeHelper.changePopupMenuFont(popupMenuTriggerOrder); GUISizeHelper.changePopupMenuFont(popupMenuTriggerOrder);
@ -390,6 +390,7 @@ public final class GamePanel extends javax.swing.JPanel {
stackObjects.setPreferredSize(newDimension); stackObjects.setPreferredSize(newDimension);
stackObjects.setMinimumSize(newDimension); stackObjects.setMinimumSize(newDimension);
stackObjects.setMaximumSize(newDimension); stackObjects.setMaximumSize(newDimension);
stackObjects.changeGUISize(); // must call to cards fit
newDimension = new Dimension(newStackWidth, (int) pnlShortCuts.getPreferredSize().getHeight()); newDimension = new Dimension(newStackWidth, (int) pnlShortCuts.getPreferredSize().getHeight());
pnlShortCuts.setPreferredSize(newDimension); pnlShortCuts.setPreferredSize(newDimension);
@ -501,6 +502,10 @@ public final class GamePanel extends javax.swing.JPanel {
} else { } else {
// play start sound // play start sound
AudioManager.playYourGameStarted(); AudioManager.playYourGameStarted();
if (!AppUtil.isAppActive()) {
MageTray.instance.displayMessage("Your match has started!");
MageTray.instance.blink();
}
} }
} }
@ -571,7 +576,7 @@ public final class GamePanel extends javax.swing.JPanel {
} }
} }
public synchronized void init(GameView game) { public synchronized void init(int messageId, GameView game) {
addPlayers(game); addPlayers(game);
// default menu states // default menu states
setMenuStates( setMenuStates(
@ -581,7 +586,7 @@ public final class GamePanel extends javax.swing.JPanel {
holdingPriority holdingPriority
); );
updateGame(game); updateGame(messageId, game);
} }
private void addPlayers(GameView game) { private void addPlayers(GameView game) {
@ -706,12 +711,12 @@ public final class GamePanel extends javax.swing.JPanel {
*/ */
} }
public synchronized void updateGame(GameView game) { public synchronized void updateGame(int messageId, GameView game) {
updateGame(game, false, null, null); updateGame(messageId, game, false, null, null);
} }
public synchronized void updateGame(GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) { public synchronized void updateGame(int messageId, GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) {
keepLastGameData(game, showPlayable, options, targets); keepLastGameData(messageId, game, showPlayable, options, targets);
prepareSelectableView(); prepareSelectableView();
updateGame(); updateGame();
} }
@ -777,12 +782,6 @@ public final class GamePanel extends javax.swing.JPanel {
logger.debug("Step is empty"); logger.debug("Step is empty");
this.txtStep.setText(""); this.txtStep.setText("");
} }
if (lastGameData.game.getSpellsCastCurrentTurn() > 0 && PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_SHOW_STORM_COUNTER, "true").equals("true")) {
this.txtSpellsCast.setVisible(true);
this.txtSpellsCast.setText(' ' + Integer.toString(lastGameData.game.getSpellsCastCurrentTurn()) + ' ');
} else {
this.txtSpellsCast.setVisible(false);
}
this.txtActivePlayer.setText(lastGameData.game.getActivePlayerName()); this.txtActivePlayer.setText(lastGameData.game.getActivePlayerName());
this.txtPriority.setText(lastGameData.game.getPriorityPlayerName()); this.txtPriority.setText(lastGameData.game.getPriorityPlayerName());
@ -946,6 +945,7 @@ public final class GamePanel extends javax.swing.JPanel {
} }
} }
//logger.info("game update, message = " + lastGameData.messageId + ", options = " + lastGameData.options + ", priority = " + lastGameData.game.getPriorityPlayerName());
feedbackPanel.disableUndo(); feedbackPanel.disableUndo();
feedbackPanel.updateOptions(lastGameData.options); feedbackPanel.updateOptions(lastGameData.options);
@ -1361,12 +1361,13 @@ public final class GamePanel extends javax.swing.JPanel {
windowMap.entrySet().removeIf(entry -> entry.getValue().isClosed()); windowMap.entrySet().removeIf(entry -> entry.getValue().isClosed());
} }
public void ask(String question, GameView gameView, int messageId, Map<String, Serializable> options) { public void ask(int messageId, GameView gameView, String question, Map<String, Serializable> options) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
this.feedbackPanel.prepareFeedback(FeedbackMode.QUESTION, question, false, options, messageId, true, gameView.getPhase()); this.feedbackPanel.prepareFeedback(FeedbackMode.QUESTION, question, false, options, true, gameView.getPhase());
} }
private void keepLastGameData(GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) { private void keepLastGameData(int messageId, GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) {
lastGameData.messageId = messageId;
lastGameData.game = game; lastGameData.game = game;
lastGameData.showPlayable = showPlayable; lastGameData.showPlayable = showPlayable;
lastGameData.options = options; lastGameData.options = options;
@ -1623,8 +1624,8 @@ public final class GamePanel extends javax.swing.JPanel {
* @param options * @param options
* @param messageId * @param messageId
*/ */
public void pickTarget(GameView gameView, Map<String, Serializable> options, String message, CardsView cardsView, Set<UUID> targets, boolean required, int messageId) { public void pickTarget(int messageId, GameView gameView, Map<String, Serializable> options, String message, CardsView cardsView, Set<UUID> targets, boolean required) {
updateGame(gameView, false, options, targets); updateGame(messageId, gameView, false, options, targets);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
clearPickTargetDialogs(); clearPickTargetDialogs();
@ -1652,28 +1653,28 @@ public final class GamePanel extends javax.swing.JPanel {
dialog = prepareCardsDialog(message, cardsView, required, options0, popupMenuType); dialog = prepareCardsDialog(message, cardsView, required, options0, popupMenuType);
options0.put("dialog", dialog); options0.put("dialog", dialog);
} }
this.feedbackPanel.prepareFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, messageId, true, gameView.getPhase()); this.feedbackPanel.prepareFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, true, gameView.getPhase());
if (dialog != null) { if (dialog != null) {
this.pickTarget.add(dialog); this.pickTarget.add(dialog);
} }
} }
public void inform(String information, GameView gameView, int messageId) { public void inform(int messageId, GameView gameView, String information) {
updateGame(gameView); updateGame(messageId, gameView);
this.feedbackPanel.prepareFeedback(FeedbackMode.INFORM, information, gameView.getSpecial(), null, messageId, false, gameView.getPhase()); this.feedbackPanel.prepareFeedback(FeedbackMode.INFORM, information, gameView.getSpecial(), null, false, gameView.getPhase());
} }
public void endMessage(GameView gameView, Map<String, Serializable> options, String message, int messageId) { public void endMessage(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
this.feedbackPanel.prepareFeedback(FeedbackMode.END, message, false, null, messageId, true, null); this.feedbackPanel.prepareFeedback(FeedbackMode.END, message, false, null, true, null);
ArrowBuilder.getBuilder().removeAllArrows(gameId); ArrowBuilder.getBuilder().removeAllArrows(gameId);
} }
public void select(GameView gameView, Map<String, Serializable> options, String message, int messageId) { public void select(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(gameView, true, options, null); updateGame(messageId, gameView, true, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
@ -1716,31 +1717,31 @@ public final class GamePanel extends javax.swing.JPanel {
priorityPlayerText = " / priority " + gameView.getPriorityPlayerName(); priorityPlayerText = " / priority " + gameView.getPriorityPlayerName();
} }
String messageToDisplay = message + FeedbackPanel.getSmallText(activePlayerText + " / " + gameView.getStep().toString() + priorityPlayerText); String messageToDisplay = message + FeedbackPanel.getSmallText(activePlayerText + " / " + gameView.getStep().toString() + priorityPlayerText);
this.feedbackPanel.prepareFeedback(FeedbackMode.SELECT, messageToDisplay, gameView.getSpecial(), panelOptions, messageId, true, gameView.getPhase()); this.feedbackPanel.prepareFeedback(FeedbackMode.SELECT, messageToDisplay, gameView.getSpecial(), panelOptions, true, gameView.getPhase());
} }
public void playMana(GameView gameView, Map<String, Serializable> options, String message, int messageId) { public void playMana(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(gameView, true, options, null); updateGame(messageId, gameView, true, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
this.feedbackPanel.prepareFeedback(FeedbackMode.CANCEL, message, gameView.getSpecial(), options, messageId, true, gameView.getPhase()); this.feedbackPanel.prepareFeedback(FeedbackMode.CANCEL, message, gameView.getSpecial(), options, true, gameView.getPhase());
} }
public void playXMana(GameView gameView, Map<String, Serializable> options, String message, int messageId) { public void playXMana(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(gameView, true, options, null); updateGame(messageId, gameView, true, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
this.feedbackPanel.prepareFeedback(FeedbackMode.CONFIRM, message, gameView.getSpecial(), null, messageId, true, gameView.getPhase()); this.feedbackPanel.prepareFeedback(FeedbackMode.CONFIRM, message, gameView.getSpecial(), null, true, gameView.getPhase());
} }
public void replayMessage(String message) { public void replayMessage(String message) {
//TODO: implement this //TODO: implement this
} }
public void pickAbility(GameView gameView, Map<String, Serializable> options, AbilityPickerView choices) { public void pickAbility(int messageId, GameView gameView, Map<String, Serializable> options, AbilityPickerView choices) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
@ -1764,8 +1765,8 @@ public final class GamePanel extends javax.swing.JPanel {
return showCards; return showCards;
} }
public void getAmount(GameView gameView, Map<String, Serializable> options, int min, int max, String message) { public void getAmount(int messageId, GameView gameView, Map<String, Serializable> options, int min, int max, String message) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
@ -1777,9 +1778,9 @@ public final class GamePanel extends javax.swing.JPanel {
} }
} }
public void getMultiAmount(List<MultiAmountMessage> messages, GameView gameView, Map<String, Serializable> options, public void getMultiAmount(int messageId, GameView gameView, List<MultiAmountMessage> messages, Map<String, Serializable> options,
int min, int max) { int min, int max) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
@ -1787,8 +1788,8 @@ public final class GamePanel extends javax.swing.JPanel {
SessionHandler.sendPlayerString(gameId, pickMultiNumber.getMultiAmount()); SessionHandler.sendPlayerString(gameId, pickMultiNumber.getMultiAmount());
} }
public void getChoice(GameView gameView, Map<String, Serializable> options, Choice choice, UUID objectId) { public void getChoice(int messageId, GameView gameView, Map<String, Serializable> options, Choice choice, UUID objectId) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
@ -1813,8 +1814,8 @@ public final class GamePanel extends javax.swing.JPanel {
pickChoice.removeDialog(); pickChoice.removeDialog();
} }
public void pickPile(GameView gameView, Map<String, Serializable> options, String message, CardsView pile1, CardsView pile2) { public void pickPile(int messageId, GameView gameView, Map<String, Serializable> options, String message, CardsView pile1, CardsView pile2) {
updateGame(gameView, false, options, null); updateGame(messageId, gameView, false, options, null);
hideAll(); hideAll();
DialogManager.getManager(gameId).fadeOut(); DialogManager.getManager(gameId).fadeOut();
@ -1856,14 +1857,8 @@ public final class GamePanel extends javax.swing.JPanel {
lblPriority = new javax.swing.JLabel(); lblPriority = new javax.swing.JLabel();
feedbackPanel = new mage.client.game.FeedbackPanel(); feedbackPanel = new mage.client.game.FeedbackPanel();
txtSpellsCast = new javax.swing.JLabel();
Border paddingBorder = BorderFactory.createEmptyBorder(4, 4, 4, 4); Border paddingBorder = BorderFactory.createEmptyBorder(4, 4, 4, 4);
Border border = BorderFactory.createLineBorder(Color.DARK_GRAY, 2); Border border = BorderFactory.createLineBorder(Color.DARK_GRAY, 2);
txtSpellsCast.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder));
txtSpellsCast.setBackground(Color.LIGHT_GRAY);
txtSpellsCast.setOpaque(true);
txtSpellsCast.setToolTipText("spells cast during the current turn");
txtHoldPriority = new javax.swing.JLabel(); txtHoldPriority = new javax.swing.JLabel();
txtHoldPriority.setText("Hold"); txtHoldPriority.setText("Hold");
txtHoldPriority.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder)); txtHoldPriority.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder));
@ -2336,7 +2331,6 @@ public final class GamePanel extends javax.swing.JPanel {
) )
.addGroup(gl_pnlShortCuts.createSequentialGroup() .addGroup(gl_pnlShortCuts.createSequentialGroup()
.addComponent(txtHoldPriority) .addComponent(txtHoldPriority)
.addComponent(txtSpellsCast)
/*.addComponent(btnToggleMacro)*/ /*.addComponent(btnToggleMacro)*/
.addComponent(btnSwitchHands) .addComponent(btnSwitchHands)
.addComponent(btnCancelSkip) .addComponent(btnCancelSkip)
@ -2372,7 +2366,6 @@ public final class GamePanel extends javax.swing.JPanel {
.addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
/*.addComponent(btnToggleMacro)*/ /*.addComponent(btnToggleMacro)*/
.addComponent(txtHoldPriority) .addComponent(txtHoldPriority)
.addComponent(txtSpellsCast)
.addComponent(btnSwitchHands) .addComponent(btnSwitchHands)
.addComponent(btnCancelSkip) .addComponent(btnCancelSkip)
.addComponent(btnConcede) .addComponent(btnConcede)
@ -2808,6 +2801,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (!cardViewPopupMenu.getAbility().getRules().isEmpty() if (!cardViewPopupMenu.getAbility().getRules().isEmpty()
&& !cardViewPopupMenu.getAbility().getRules().get(0).isEmpty()) { && !cardViewPopupMenu.getAbility().getRules().get(0).isEmpty()) {
abilityRuleText = cardViewPopupMenu.getAbility().getRules().get(0); abilityRuleText = cardViewPopupMenu.getAbility().getRules().get(0);
abilityRuleText = abilityRuleText.replace("{this}", cardViewPopupMenu.getName());
} }
} }
switch (e.getActionCommand()) { switch (e.getActionCommand()) {
@ -3001,7 +2995,6 @@ public final class GamePanel extends javax.swing.JPanel {
private javax.swing.JSplitPane jSplitPane2; private javax.swing.JSplitPane jSplitPane2;
private JPanel jPhases; private JPanel jPhases;
private JPanel phasesContainer; private JPanel phasesContainer;
private javax.swing.JLabel txtSpellsCast;
private javax.swing.JLabel txtHoldPriority; private javax.swing.JLabel txtHoldPriority;
private HoverButton currentStep; private HoverButton currentStep;

View file

@ -105,12 +105,20 @@ public class PlayerPanelExt extends javax.swing.JPanel {
timer.setTaskOnTick(() -> { timer.setTaskOnTick(() -> {
int priorityTimeValue = pt.getCount() + pt.getBufferCount(); int priorityTimeValue = pt.getCount() + pt.getBufferCount();
String text = getPriorityTimeLeftString(priorityTimeValue); String text = getPriorityTimeLeftString(priorityTimeValue);
// Set timer text colors (note, if you change it here, change it in update() as well)
Color textColor = null; // use default in HoverButton
Color foregroundColor = Color.BLACK;
if (pt.getBufferCount() > 0) {
textColor = Color.GREEN;
foregroundColor = Color.GREEN.darker().darker();
} else if (pt.getCount() < 300) { // visual indication for under 5 minutes
textColor = Color.RED;
foregroundColor = Color.RED.darker().darker();
}
PlayerPanelExt.this.avatar.setTopText(text); PlayerPanelExt.this.avatar.setTopText(text);
PlayerPanelExt.this.avatar.setTopTextColor(pt.getBufferCount() > 0 ? Color.GREEN : null); PlayerPanelExt.this.avatar.setTopTextColor(textColor);
PlayerPanelExt.this.timerLabel.setText(text); PlayerPanelExt.this.timerLabel.setText(text);
PlayerPanelExt.this.timerLabel PlayerPanelExt.this.timerLabel.setForeground(foregroundColor);
.setForeground(pt.getBufferCount() > 0 ? Color.GREEN.darker().darker() : Color.BLACK);
PlayerPanelExt.this.avatar.repaint(); PlayerPanelExt.this.avatar.repaint();
}); });
timer.init(gameId); timer.init(gameId);
@ -195,10 +203,10 @@ public class PlayerPanelExt extends javax.swing.JPanel {
if (playerLife != pastLife) { if (playerLife != pastLife) {
if (playerLife > pastLife) { if (playerLife > pastLife) {
avatar.gainLifeDisplay(); avatar.gainLifeDisplay();
} else if (playerLife < pastLife) { } else {
avatar.loseLifeDisplay(); avatar.loseLifeDisplay();
} }
} else if (playerLife == pastLife) { } else {
avatar.stopLifeDisplay(); avatar.stopLifeDisplay();
} }
} }
@ -311,10 +319,18 @@ public class PlayerPanelExt extends javax.swing.JPanel {
this.timer.setBufferCount(player.getBufferTimeLeft()); this.timer.setBufferCount(player.getBufferTimeLeft());
this.avatar.setTopText(priorityTimeValue); this.avatar.setTopText(priorityTimeValue);
this.timerLabel.setText(priorityTimeValue); this.timerLabel.setText(priorityTimeValue);
// Set timer text colors (note, if you change it here, change it in init()::timer.setTaskOnTick() as well)
this.avatar.setTopTextColor(player.getBufferTimeLeft() > 0 ? Color.GREEN : null); Color textColor = null; // use default in HoverButton
this.timerLabel Color foregroundColor = Color.BLACK;
.setForeground(player.getBufferTimeLeft() > 0 ? Color.GREEN.darker().darker() : Color.BLACK); if (player.getBufferTimeLeft() > 0) {
textColor = Color.GREEN;
foregroundColor = Color.GREEN.darker().darker();
} else if (player.getPriorityTimeLeft() < 300) { // visual indication for under 5 minutes
textColor = Color.RED;
foregroundColor = Color.RED.darker().darker();
}
this.avatar.setTopTextColor(textColor);
this.timerLabel.setForeground(foregroundColor);
} }
if (player.isTimerActive()) { if (player.isTimerActive()) {
this.timer.resume(); this.timer.resume();
@ -360,25 +376,17 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private void updateAvatar() { private void updateAvatar() {
if (flagName == null) { // do only once if (flagName == null) { // do only once
avatar.setText(this.player.getName()); avatar.setText(this.player.getName());
if (!player.getUserData().getFlagName().equals(flagName)) { flagName = player.getUserData().getFlagName();
flagName = player.getUserData().getFlagName(); this.avatar.setTopTextImage(CountryUtil.getCountryFlagIconSize(flagName, 11).getImage());
this.avatar.setTopTextImage(CountryUtil.getCountryFlagIconSize(flagName, 11).getImage()); String countryName = CountryUtil.getCountryName(flagName);
}
// TODO: Add the wins to the tooltiptext of the avatar
String countryname = CountryUtil.getCountryName(flagName);
if (countryname == null) {
countryname = "Unknown";
}
basicTooltipText = "<HTML>Name: " + player.getName() basicTooltipText = "<HTML>Name: " + player.getName()
+ "<br/>Flag: " + countryname + "<br/>Flag: " + (countryName == null ? "Unknown" : countryName)
+ "<br/>Constructed rating: " + player.getUserData().getConstructedRating()
+ "<br/>Limited rating: " + player.getUserData().getLimitedRating()
+ "<br/>Deck hash code: " + player.getDeckHashCode() + "<br/>Deck hash code: " + player.getDeckHashCode()
+ "<br/>This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)" + "<br/>This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)";
+ (player.getUserData() == null ? "" : "<br/>History: " + player.getUserData().getHistory());
} }
// Extend tooltip // Extend tooltip
StringBuilder tooltipText = new StringBuilder(basicTooltipText); StringBuilder tooltipText = new StringBuilder(basicTooltipText);
tooltipText.append("<br/>Match time remaining: ").append(getPriorityTimeLeftString(player));
this.avatar.setTopTextImageRight(null); this.avatar.setTopTextImageRight(null);
for (String name : player.getDesignationNames()) { for (String name : player.getDesignationNames()) {
tooltipText.append("<br/>").append(name); tooltipText.append("<br/>").append(name);

View file

@ -16,6 +16,7 @@ import mage.client.util.audio.AudioManager;
import mage.client.util.object.SaveObjectUtil; import mage.client.util.object.SaveObjectUtil;
import mage.interfaces.callback.CallbackClient; import mage.interfaces.callback.CallbackClient;
import mage.interfaces.callback.ClientCallback; import mage.interfaces.callback.ClientCallback;
import mage.interfaces.callback.ClientCallbackType;
import mage.remote.ActionData; import mage.remote.ActionData;
import mage.remote.Session; import mage.remote.Session;
import mage.view.*; import mage.view.*;
@ -24,8 +25,7 @@ import org.apache.log4j.Logger;
import javax.swing.*; import javax.swing.*;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.List; import java.util.*;
import java.util.UUID;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -34,38 +34,76 @@ public class CallbackClientImpl implements CallbackClient {
private static final Logger logger = Logger.getLogger(CallbackClientImpl.class); private static final Logger logger = Logger.getLogger(CallbackClientImpl.class);
private final MageFrame frame; private final MageFrame frame;
private int messageId = 0; private final Map<ClientCallbackType, Integer> lastMessages;
private int gameInformMessageId = 0;
public CallbackClientImpl(MageFrame frame) { public CallbackClientImpl(MageFrame frame) {
this.frame = frame; this.frame = frame;
this.lastMessages = new HashMap<>();
Arrays.stream(ClientCallbackType.values()).forEach(t -> this.lastMessages.put(t, 0));
} }
@Override @Override
public synchronized void processCallback(final ClientCallback callback) { public synchronized void processCallback(final ClientCallback callback) {
callback.decompressData(); callback.decompressData();
// put replay related code here
SaveObjectUtil.saveObject(callback.getData(), callback.getMethod().toString()); SaveObjectUtil.saveObject(callback.getData(), callback.getMethod().toString());
// all GUI related code must be executed in swing thread
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
try { try {
logger.debug(callback.getMessageId() + " -- " + callback.getMethod()); logger.debug("message " + callback.getMessageId() + " - " + callback.getMethod().getType() + " - " + callback.getMethod());
// process bad connection (events can income in wrong order, so outdated data must be ignored)
// - table/dialog events like game start, game end, choose dialog - must be processed anyway
// - messages events like chat, inform, error - must be processed anyway
// - update events like opponent priority - can be ignored
if (!callback.getMethod().getType().equals(ClientCallbackType.CLIENT_SIDE_EVENT)) {
int lastAnyMessageId = this.lastMessages.values().stream().mapToInt(x -> x).max().orElse(0);
if (lastAnyMessageId > callback.getMessageId()) {
// un-synced message
if (callback.getMethod().getType().mustIgnoreOnOutdated()) {
// ignore
logger.warn(String.format("ignore un-synced message %d - %s - %s, possible reason: slow connection/performance",
callback.getMessageId(),
callback.getMethod().getType(),
callback.getMethod()
));
return;
} else {
// process it anyway
logger.debug(String.format("processing un-synced message %d - %s - %s, possible reason: slow connection/performance",
callback.getMessageId(),
callback.getMethod().getType(),
callback.getMethod()
));
}
}
// keep track of synced messages only
if (!callback.getMethod().getType().canComeInAnyOrder()) {
this.lastMessages.put(callback.getMethod().getType(), callback.getMessageId());
}
}
switch (callback.getMethod()) { switch (callback.getMethod()) {
case START_GAME: { case START_GAME: {
TableClientMessage message = (TableClientMessage) callback.getData(); TableClientMessage message = (TableClientMessage) callback.getData();
GameManager.instance.setCurrentPlayerUUID(message.getPlayerId()); GameManager.instance.setCurrentPlayerUUID(message.getPlayerId());
gameStarted(message.getGameId(), message.getPlayerId()); gameStarted(callback.getMessageId(), message.getGameId(), message.getPlayerId());
break; break;
} }
case START_TOURNAMENT: { case START_TOURNAMENT: {
TableClientMessage message = (TableClientMessage) callback.getData(); TableClientMessage message = (TableClientMessage) callback.getData();
tournamentStarted(message.getGameId(), message.getPlayerId()); tournamentStarted(callback.getMessageId(), message.getGameId(), message.getPlayerId());
break; break;
} }
case START_DRAFT: { case START_DRAFT: {
TableClientMessage message = (TableClientMessage) callback.getData(); TableClientMessage message = (TableClientMessage) callback.getData();
draftStarted(message.getGameId(), message.getPlayerId()); draftStarted(callback.getMessageId(), message.getGameId(), message.getPlayerId());
break; break;
} }
@ -149,7 +187,7 @@ public class CallbackClientImpl implements CallbackClient {
case REPLAY_INIT: { case REPLAY_INIT: {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
panel.init((GameView) callback.getData()); panel.init(callback.getMessageId(), (GameView) callback.getData());
} }
break; break;
} }
@ -157,7 +195,7 @@ public class CallbackClientImpl implements CallbackClient {
case REPLAY_DONE: { case REPLAY_DONE: {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
panel.endMessage(null, null, (String) callback.getData(), callback.getMessageId()); panel.endMessage(callback.getMessageId(), null, null, (String) callback.getData());
} }
break; break;
} }
@ -165,7 +203,7 @@ public class CallbackClientImpl implements CallbackClient {
case REPLAY_UPDATE: { case REPLAY_UPDATE: {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
panel.updateGame((GameView) callback.getData()); panel.updateGame(callback.getMessageId(), (GameView) callback.getData());
} }
break; break;
} }
@ -174,7 +212,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_INIT", callback.getObjectId(), callback.getData()); appendJsonEvent("GAME_INIT", callback.getObjectId(), callback.getData());
panel.init((GameView) callback.getData()); panel.init(callback.getMessageId(), (GameView) callback.getData());
} }
break; break;
} }
@ -190,7 +228,7 @@ public class CallbackClientImpl implements CallbackClient {
String logFileName = "game-" + gameId + ".json"; String logFileName = "game-" + gameId + ".json";
S3Uploader.upload(logFileName, gameId.toString()); S3Uploader.upload(logFileName, gameId.toString());
} }
panel.endMessage(message.getGameView(), message.getOptions(), message.getMessage(), callback.getMessageId()); panel.endMessage(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage());
} }
break; break;
} }
@ -205,7 +243,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_ASK", callback.getObjectId(), message); appendJsonEvent("GAME_ASK", callback.getObjectId(), message);
panel.ask(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions()); panel.ask(callback.getMessageId(), message.getGameView(), message.getMessage(), message.getOptions());
} }
break; break;
} }
@ -216,8 +254,8 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_TARGET", callback.getObjectId(), message); appendJsonEvent("GAME_TARGET", callback.getObjectId(), message);
panel.pickTarget(message.getGameView(), message.getOptions(), message.getMessage(), panel.pickTarget(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage(),
message.getCardsView1(), message.getTargets(), message.isFlag(), callback.getMessageId()); message.getCardsView1(), message.getTargets(), message.isFlag());
} }
break; break;
} }
@ -227,7 +265,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_SELECT", callback.getObjectId(), message); appendJsonEvent("GAME_SELECT", callback.getObjectId(), message);
panel.select(message.getGameView(), message.getOptions(), message.getMessage(), callback.getMessageId()); panel.select(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage());
} }
break; break;
} }
@ -237,7 +275,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_CHOOSE_ABILITY", callback.getObjectId(), callback.getData()); appendJsonEvent("GAME_CHOOSE_ABILITY", callback.getObjectId(), callback.getData());
panel.pickAbility(abilityPickerView.getGameView(), null, abilityPickerView); panel.pickAbility(callback.getMessageId(), abilityPickerView.getGameView(), null, abilityPickerView);
} }
break; break;
} }
@ -247,7 +285,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), message); appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), message);
panel.pickPile(message.getGameView(), message.getOptions(), message.getMessage(), message.getCardsView1(), message.getCardsView2()); panel.pickPile(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage(), message.getCardsView1(), message.getCardsView2());
} }
break; break;
} }
@ -257,7 +295,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_CHOOSE_CHOICE", callback.getObjectId(), message); appendJsonEvent("GAME_CHOOSE_CHOICE", callback.getObjectId(), message);
panel.getChoice(message.getGameView(), message.getOptions(), message.getChoice(), callback.getObjectId()); panel.getChoice(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getChoice(), callback.getObjectId());
} }
break; break;
} }
@ -267,7 +305,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_PLAY_MANA", callback.getObjectId(), message); appendJsonEvent("GAME_PLAY_MANA", callback.getObjectId(), message);
panel.playMana(message.getGameView(), message.getOptions(), message.getMessage(), callback.getMessageId()); panel.playMana(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage());
} }
break; break;
} }
@ -277,7 +315,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_PLAY_XMANA", callback.getObjectId(), message); appendJsonEvent("GAME_PLAY_XMANA", callback.getObjectId(), message);
panel.playXMana(message.getGameView(), message.getOptions(), message.getMessage(), callback.getMessageId()); panel.playXMana(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage());
} }
break; break;
} }
@ -287,8 +325,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message); appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message);
panel.getAmount(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMin(), message.getMax(), message.getMessage());
panel.getAmount(message.getGameView(), message.getOptions(), message.getMin(), message.getMax(), message.getMessage());
} }
break; break;
} }
@ -298,8 +335,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_GET_MULTI_AMOUNT", callback.getObjectId(), message); appendJsonEvent("GAME_GET_MULTI_AMOUNT", callback.getObjectId(), message);
panel.getMultiAmount(callback.getMessageId(), message.getGameView(), message.getMessages(), message.getOptions(), message.getMin(), message.getMax());
panel.getMultiAmount(message.getMessages(), message.getGameView(), message.getOptions(), message.getMin(), message.getMax());
} }
break; break;
} }
@ -308,7 +344,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) { if (panel != null) {
appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData()); appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData());
panel.updateGame((GameView) callback.getData(), true, null, null); // update after undo wtf?! panel.updateGame(callback.getMessageId(), (GameView) callback.getData(), true, null, null); // update after undo wtf?! // TODO: clean dialogs?!
} }
break; break;
} }
@ -336,21 +372,13 @@ public class CallbackClientImpl implements CallbackClient {
break; break;
} }
case GAME_INFORM: { case GAME_UPDATE_AND_INFORM: {
if (callback.getMessageId() > gameInformMessageId) { GameClientMessage message = (GameClientMessage) callback.getData();
{ GamePanel panel = MageFrame.getGame(callback.getObjectId());
GameClientMessage message = (GameClientMessage) callback.getData(); if (panel != null) {
GamePanel panel = MageFrame.getGame(callback.getObjectId()); appendJsonEvent("GAME_INFORM", callback.getObjectId(), message);
if (panel != null) { panel.inform(callback.getMessageId(), message.getGameView(), message.getMessage());
appendJsonEvent("GAME_INFORM", callback.getObjectId(), message);
panel.inform(message.getMessage(), message.getGameView(), callback.getMessageId());
}
}
// no longer needed because phase skip handling on server side now
} else {
logger.warn(new StringBuilder("message out of sequence - ignoring").append("MessageId = ").append(callback.getMessageId()).append(" method = ").append(callback.getMethod()));
} }
gameInformMessageId = messageId;
break; break;
} }
@ -432,14 +460,10 @@ public class CallbackClientImpl implements CallbackClient {
} }
default: { default: {
// TODO: add exception here and process miss events like TOURNAMENT_UPDATE
break; break;
} }
} }
// sync message for server side events only
if (!callback.getMethod().isClientSideMessage()) {
messageId = callback.getMessageId();
}
} catch (Exception ex) { } catch (Exception ex) {
handleException(ex); handleException(ex);
} }
@ -466,50 +490,50 @@ public class CallbackClientImpl implements CallbackClient {
switch (usedPanel.getChatType()) { switch (usedPanel.getChatType()) {
case GAME: case GAME:
usedPanel.receiveMessage("", new StringBuilder() usedPanel.receiveMessage("", new StringBuilder()
.append("HOTKEYS:") .append("HOTKEYS:")
.append("<br/>Turn mousewheel up (ALT-e) - enlarge image of card the mousepointer hovers over") .append("<br/>Turn mousewheel up (ALT-e) - enlarge image of card the mousepointer hovers over")
.append("<br/>Turn mousewheel down (ALT-s) - enlarge original/alternate image of card the mousepointer hovers over") .append("<br/>Turn mousewheel down (ALT-s) - enlarge original/alternate image of card the mousepointer hovers over")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CONFIRM)))
.append("</b> - Confirm \"Ok\", \"Yes\" or \"Done\" button")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_NEXT_TURN)))
.append("</b> - Skip current turn but stop on declare attackers/blockers and something on the stack")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_END_STEP)))
.append("</b> - Skip to next end step but stop on declare attackers/blockers and something on the stack")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SKIP_STEP)))
.append("</b> - Skip current turn but stop on declare attackers/blockers")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_MAIN_STEP)))
.append("</b> - Skip to next main phase but stop on declare attackers/blockers and something on the stack")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_YOUR_TURN)))
.append("</b> - Skip everything until your next turn")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_PRIOR_END)))
.append("</b> - Skip everything until the end step just prior to your turn")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CANCEL_SKIP)))
.append("</b> - Undo F4/F5/F7/F9/F11")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SWITCH_CHAT)))
.append("</b> - Switch in/out to chat text field")
/*
.append("<br/><b>") .append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_TOGGLE_MACRO))) .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CONFIRM)))
.append("</b> - Toggle recording a sequence of actions to repeat. Will not pause if interrupted and can fail if a selected card changes such as when scrying top card to bottom.") .append("</b> - Confirm \"Ok\", \"Yes\" or \"Done\" button")
.append("<br/><b>").append(System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl").append(" + click</b> - Hold priority while casting a spell or activating an ability") .append("<br/><b>")
*/ .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_NEXT_TURN)))
.append("<br/>") .append("</b> - Skip current turn but stop on declare attackers/blockers and something on the stack")
.append("<br/>") .append("<br/><b>")
.append("CHAT COMMANDS:") .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_END_STEP)))
.append("<br/>").append("<b>/h username </b> - show player's stats (history)") .append("</b> - Skip to next end step but stop on declare attackers/blockers and something on the stack")
.append("<br/>").append("<b>/w username message</b> - send private message to player (whisper)") .append("<br/><b>")
.append("<br/>").append("<b>/pings</b> - show players and watchers ping") .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SKIP_STEP)))
.append("<br/>").append("<b>/fix</b> - fix frozen game") .append("</b> - Skip current turn but stop on declare attackers/blockers")
.toString(), .append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_MAIN_STEP)))
.append("</b> - Skip to next main phase but stop on declare attackers/blockers and something on the stack")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_YOUR_TURN)))
.append("</b> - Skip everything until your next turn")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_PRIOR_END)))
.append("</b> - Skip everything until the end step just prior to your turn")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CANCEL_SKIP)))
.append("</b> - Undo F4/F5/F7/F9/F11")
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SWITCH_CHAT)))
.append("</b> - Switch in/out to chat text field")
/*
.append("<br/><b>")
.append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_TOGGLE_MACRO)))
.append("</b> - Toggle recording a sequence of actions to repeat. Will not pause if interrupted and can fail if a selected card changes such as when scrying top card to bottom.")
.append("<br/><b>").append(System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl").append(" + click</b> - Hold priority while casting a spell or activating an ability")
*/
.append("<br/>")
.append("<br/>")
.append("CHAT COMMANDS:")
.append("<br/>").append("<b>/h username </b> - show player's stats (history)")
.append("<br/>").append("<b>/w username message</b> - send private message to player (whisper)")
.append("<br/>").append("<b>/pings</b> - show players and watchers ping")
.append("<br/>").append("<b>/fix</b> - fix frozen game")
.toString(),
null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE);
break; break;
case TOURNAMENT: case TOURNAMENT:
@ -519,10 +543,10 @@ public class CallbackClientImpl implements CallbackClient {
case TABLES: case TABLES:
String serverAddress = SessionHandler.getSession().getServerHostname().orElse(""); String serverAddress = SessionHandler.getSession().getServerHostname().orElse("");
usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" main menu.") usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" main menu.")
.append("<br/>Download icons and symbols by using the \"Symbols\" main menu.") .append("<br/>Download icons and symbols by using the \"Symbols\" main menu.")
.append("<br/>\\list - show a list of available chat commands.") .append("<br/>\\list - show a list of available chat commands.")
.append("<br/>").append(IgnoreList.usage(serverAddress)) .append("<br/>").append(IgnoreList.usage(serverAddress))
.append("<br/>Type <font color=green>\\w yourUserName profanity 0 (or 1 or 2)</font> to turn off/on the profanity filter").toString(), .append("<br/>Type <font color=green>\\w yourUserName profanity 0 (or 1 or 2)</font> to turn off/on the profanity filter").toString(),
null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE);
break; break;
default: default:
@ -539,7 +563,7 @@ public class CallbackClientImpl implements CallbackClient {
} }
} }
protected void gameStarted(final UUID gameId, final UUID playerId) { protected void gameStarted(final int messageId, final UUID gameId, final UUID playerId) {
try { try {
frame.showGame(gameId, playerId); frame.showGame(gameId, playerId);
logger.info("Game " + gameId + " started for player " + playerId); logger.info("Game " + gameId + " started for player " + playerId);
@ -552,7 +576,7 @@ public class CallbackClientImpl implements CallbackClient {
} }
} }
protected void draftStarted(UUID draftId, UUID playerId) { protected void draftStarted(int messageId, UUID draftId, UUID playerId) {
try { try {
frame.showDraft(draftId); frame.showDraft(draftId);
logger.info("Draft " + draftId + " started for player " + playerId); logger.info("Draft " + draftId + " started for player " + playerId);
@ -561,7 +585,7 @@ public class CallbackClientImpl implements CallbackClient {
} }
} }
protected void tournamentStarted(UUID tournamentId, UUID playerId) { protected void tournamentStarted(int messageId, UUID tournamentId, UUID playerId) {
try { try {
frame.showTournament(tournamentId); frame.showTournament(tournamentId);
AudioManager.playTournamentStarted(); AudioManager.playTournamentStarted();

View file

@ -122,7 +122,7 @@ public class NewPlayerPanel extends javax.swing.JPanel {
lblLevel.setText("Skill:"); lblLevel.setText("Skill:");
spnLevel.setModel(new javax.swing.SpinnerNumberModel(6, 1, 10, 1)); spnLevel.setModel(new javax.swing.SpinnerNumberModel(2, 1, 10, 1));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
@ -186,4 +186,4 @@ public class NewPlayerPanel extends javax.swing.JPanel {
private javax.swing.JTextField txtPlayerName; private javax.swing.JTextField txtPlayerName;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View file

@ -99,7 +99,8 @@ public class TablesPanel extends javax.swing.JPanel {
+ "<br>FM: = Numbers of freee mulligans" + "<br>FM: = Numbers of freee mulligans"
+ "<br>Constr.: = Construction time for limited tournament formats" + "<br>Constr.: = Construction time for limited tournament formats"
+ "<br>RB = Rollback allowed" + "<br>RB = Rollback allowed"
+ "<br>PC = Planechase active" + "<br>PC = Planechase active"
+ "<br>EC = One or more emblem cards in use"
+ "<br>SP = Spectators allowed" + "<br>SP = Spectators allowed"
+ "<br>Rng: Range of visibility for multiplayer matches" + "<br>Rng: Range of visibility for multiplayer matches"
) )

View file

@ -78,7 +78,7 @@ public class TournamentPlayerPanel extends javax.swing.JPanel {
jLabel3.setText("Skill:"); jLabel3.setText("Skill:");
spnLevel.setModel(new javax.swing.SpinnerNumberModel(6, 1, 10, 1)); spnLevel.setModel(new javax.swing.SpinnerNumberModel(2, 1, 10, 1));
spnLevel.setRequestFocusEnabled(false); spnLevel.setRequestFocusEnabled(false);
javax.swing.GroupLayout pnlPlayerNameLayout = new javax.swing.GroupLayout(pnlPlayerName); javax.swing.GroupLayout pnlPlayerNameLayout = new javax.swing.GroupLayout(pnlPlayerName);

View file

@ -9,6 +9,8 @@ import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
/** /**
* TODO: part of replay system? Un-used, can be deleted
*
* Utility class to save an object on disk. * Utility class to save an object on disk.
* *
* @author ayrat * @author ayrat

View file

@ -6,14 +6,13 @@ import mage.client.constants.Constants;
import mage.constants.Rarity; import mage.constants.Rarity;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadJob; import org.mage.plugins.card.dl.DownloadJob;
import java.io.File;
import java.util.*;
import static org.mage.plugins.card.dl.DownloadJob.fromURL; import static org.mage.plugins.card.dl.DownloadJob.fromURL;
import static org.mage.plugins.card.dl.DownloadJob.toFile; import static org.mage.plugins.card.dl.DownloadJob.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
import java.io.File;
import java.util.*;
/** /**
* WARNING, unsupported images plugin, last updates from 2018 * WARNING, unsupported images plugin, last updates from 2018
*/ */
@ -103,7 +102,8 @@ public class GathererSets implements Iterable<DownloadJob> {
"C21","MH2","AFR","AFC","J21","MID","MIC","VOW","VOC","YMID", "C21","MH2","AFR","AFC","J21","MID","MIC","VOW","VOC","YMID",
"NEC","NEO","SNC","NCC","CLB","2X2","DMU","DMC","40K","GN3", "NEC","NEO","SNC","NCC","CLB","2X2","DMU","DMC","40K","GN3",
"UNF","BRO","BRC","BOT","30A","J22","SCD","DMR","ONE","ONC", "UNF","BRO","BRC","BOT","30A","J22","SCD","DMR","ONE","ONC",
"MOM","MOC","MUL","MAT","LTR","CMM","WOE","WHO","RVR","WOT","WOC" "MOM","MOC","MUL","MAT","LTR","CMM","WOE","WHO","RVR","WOT",
"WOC","SPG","LCI","LCC","REX"
// "HHO", "ANA" -- do not exist on gatherer // "HHO", "ANA" -- do not exist on gatherer
}; };

View file

@ -533,6 +533,13 @@ public class ScryfallImageSupportCards {
add("WOE"); // Wilds of Eldraine add("WOE"); // Wilds of Eldraine
add("WOT"); // Wilds of Eldraine: Enchanting Tales add("WOT"); // Wilds of Eldraine: Enchanting Tales
add("WOC"); // Wilds of Eldraine Commander add("WOC"); // Wilds of Eldraine Commander
add("LCI"); // Lost Caverns of Ixalan
add("LCC"); // Lost Caverns of Ixalan Commander
add("REX"); // Jurassic World Collection
add("SPG"); // Special Guests
// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks
add("CALC"); // Custom Alchemized versions of existing cards
} }
}; };
@ -999,6 +1006,9 @@ public class ScryfallImageSupportCards {
put("PMEI/Jamuraan Lion/10*", "https://api.scryfall.com/cards/pmei/10★/"); put("PMEI/Jamuraan Lion/10*", "https://api.scryfall.com/cards/pmei/10★/");
// PRES // PRES
put("PRES/Lathliss, Dragon Queen/149*", "https://api.scryfall.com/cards/pres/149★/"); put("PRES/Lathliss, Dragon Queen/149*", "https://api.scryfall.com/cards/pres/149★/");
// CALC -- custom alchemy version of cards.
put("CALC/C-Pillar of the Paruns", "https://api.scryfall.com/cards/dis/176/");
} }
}; };

View file

@ -2,6 +2,7 @@ package mage.interfaces.callback;
import mage.remote.traffic.ZippedObject; import mage.remote.traffic.ZippedObject;
import mage.utils.CompressUtil; import mage.utils.CompressUtil;
import mage.utils.ThreadUtils;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
@ -11,11 +12,23 @@ import java.util.UUID;
*/ */
public class ClientCallback implements Serializable { public class ClientCallback implements Serializable {
// for debug only: simulate bad connection on client side, use launcher's client param like -Dxmage.badconnection
private static final String SIMULATE_BAD_CONNECTION_PROP = "xmage.badconnection";
public static final boolean SIMULATE_BAD_CONNECTION;
static {
SIMULATE_BAD_CONNECTION = System.getProperty(SIMULATE_BAD_CONNECTION_PROP) != null;
}
private UUID objectId; private UUID objectId;
private Object data; private Object data;
private ClientCallbackMethod method; private ClientCallbackMethod method;
private int messageId; private int messageId;
public ClientCallback(ClientCallbackMethod method, UUID objectId) {
this(method, objectId, null);
}
public ClientCallback(ClientCallbackMethod method, UUID objectId, Object data) { public ClientCallback(ClientCallbackMethod method, UUID objectId, Object data) {
this(method, objectId, data, true); this(method, objectId, data, true);
} }
@ -26,8 +39,10 @@ public class ClientCallback implements Serializable {
this.setData(data, useCompress); this.setData(data, useCompress);
} }
public ClientCallback(ClientCallbackMethod method, UUID objectId) { private void simulateBadConnection() {
this(method, objectId, null); if (SIMULATE_BAD_CONNECTION) {
ThreadUtils.sleep(100);
}
} }
public void clear() { public void clear() {
@ -55,12 +70,14 @@ public class ClientCallback implements Serializable {
this.data = data; this.data = data;
} else { } else {
this.data = CompressUtil.compress(data); this.data = CompressUtil.compress(data);
simulateBadConnection();
} }
} }
public void decompressData() { public void decompressData() {
if (this.data instanceof ZippedObject) { if (this.data instanceof ZippedObject) {
this.data = CompressUtil.decompress(this.data); this.data = CompressUtil.decompress(this.data);
simulateBadConnection();
} }
} }

View file

@ -1,68 +1,86 @@
package mage.interfaces.callback; package mage.interfaces.callback;
/** /**
* Created by IGOUDT on 4-4-2017. * Server's commands to process on client side. Commands can come in un-synced state due bad/slow network
* <p>
* Can be:
* - critical events (messages, game events, choose dialogs, etc)
* - non-critical events (game updates, messages)
*/ */
public enum ClientCallbackMethod { public enum ClientCallbackMethod {
CHATMESSAGE("chatMessage"), // TODO: rename events due place/action like GAME_STARTED, GAME_ASK_DIALOG, GAME_TARGET_DIALOG
TOURNAMENT_INIT("tournamentInit"),
TOURNAMENT_UPDATE("tournamentUpdate"),
TOURNAMENT_OVER("tournamentOver"),
JOINED_TABLE("joinedTable"),
START_DRAFT("startDraft"),
START_TOURNAMENT("startTournament"),
SIDEBOARD("sideboard"),
VIEW_LIMITED_DECK("viewLimitedDeck"),
VIEW_SIDEBOARD("viewSideboard"),
CONSTRUCT("construct"),
SHOW_USERMESSAGE("showUserMessage"),
WATCHGAME("watchGame"),
REPLAY_GAME("replayGame"),
START_GAME("startGame"),
SHOW_TOURNAMENT("showTournament"),
SHOW_GAME_END_DIALOG("showGameEndDialog"),
SERVER_MESSAGE("serverMessage"),
GAME_INIT("gameInit"),
GAME_OVER("gameOver"),
GAME_INFORM("gameInform"),
GAME_INFORM_PERSONAL("gameInformPersonal"),
GAME_ERROR("gameError"),
GAME_UPDATE("gameUpdate"),
GAME_REDRAW_GUI("gameRedrawGUI", true),
DRAFT_OVER("draftOver"),
REPLAY_DONE("replayDone"),
USER_REQUEST_DIALOG("userRequestDialog"),
REPLAY_UPDATE("replayUpdate"),
REPLAY_INIT("replayInit"),
END_GAME_INFO("endGameInfo"),
GAME_TARGET("gameTarget"),
GAME_CHOOSE_ABILITY("gameChooseAbility"),
GAME_CHOOSE_PILE("gameChoosePile"),
GAME_CHOOSE_CHOICE("gameChooseChoice"),
GAME_ASK("gameAsk"),
GAME_SELECT("gameSelect"),
GAME_PLAY_MANA("gamePlayMana"),
GAME_PLAY_XMANA("gamePlayXMana"),
GAME_GET_AMOUNT("gameSelectAmount"),
GAME_GET_MULTI_AMOUNT("gameSelectMultiAmount"),
DRAFT_INIT("draftInit"),
DRAFT_PICK("draftPick"),
DRAFT_UPDATE("draftUpdate");
String code; // messages
boolean isClientSideMessage; CHATMESSAGE(ClientCallbackType.MESSAGE, "chatMessage"),
SHOW_USERMESSAGE(ClientCallbackType.MESSAGE, "showUserMessage"),
SERVER_MESSAGE(ClientCallbackType.MESSAGE, "serverMessage"),
ClientCallbackMethod(String code) { // table
this(code, false); JOINED_TABLE(ClientCallbackType.TABLE_CHANGE, "joinedTable"),
}
ClientCallbackMethod(String code, boolean isClientSideMessage) { // tournament
START_TOURNAMENT(ClientCallbackType.TABLE_CHANGE, "startTournament"),
TOURNAMENT_INIT(ClientCallbackType.TABLE_CHANGE, "tournamentInit"), // TODO: unused on client
TOURNAMENT_UPDATE(ClientCallbackType.UPDATE, "tournamentUpdate"), // TODO: unused on client
TOURNAMENT_OVER(ClientCallbackType.TABLE_CHANGE, "tournamentOver"), // TODO: unused on client
// draft/sideboard
START_DRAFT(ClientCallbackType.TABLE_CHANGE, "startDraft"),
SIDEBOARD(ClientCallbackType.TABLE_CHANGE, "sideboard"),
CONSTRUCT(ClientCallbackType.TABLE_CHANGE, "construct"),
DRAFT_OVER(ClientCallbackType.TABLE_CHANGE, "draftOver"),
DRAFT_INIT(ClientCallbackType.TABLE_CHANGE, "draftInit"),
DRAFT_PICK(ClientCallbackType.TABLE_CHANGE, "draftPick"),
DRAFT_UPDATE(ClientCallbackType.UPDATE, "draftUpdate"),
// watch
SHOW_TOURNAMENT(ClientCallbackType.TABLE_CHANGE, "showTournament"),
WATCHGAME(ClientCallbackType.TABLE_CHANGE, "watchGame"),
// in-game actions
VIEW_LIMITED_DECK(ClientCallbackType.MESSAGE, "viewLimitedDeck"),
VIEW_SIDEBOARD(ClientCallbackType.MESSAGE, "viewSideboard"),
// other
USER_REQUEST_DIALOG(ClientCallbackType.DIALOG, "userRequestDialog"),
GAME_REDRAW_GUI(ClientCallbackType.CLIENT_SIDE_EVENT, "gameRedrawGUI"),
// game
START_GAME(ClientCallbackType.TABLE_CHANGE, "startGame"),
GAME_INIT(ClientCallbackType.TABLE_CHANGE, "gameInit"),
GAME_UPDATE_AND_INFORM(ClientCallbackType.UPDATE, "gameInform"), // update game and feedback panel with current status (e.g. on non our priority)
GAME_INFORM_PERSONAL(ClientCallbackType.MESSAGE, "gameInformPersonal"),
GAME_ERROR(ClientCallbackType.MESSAGE, "gameError"),
GAME_UPDATE(ClientCallbackType.UPDATE, "gameUpdate"),
GAME_TARGET(ClientCallbackType.DIALOG, "gameTarget"),
GAME_CHOOSE_ABILITY(ClientCallbackType.DIALOG, "gameChooseAbility"),
GAME_CHOOSE_PILE(ClientCallbackType.DIALOG, "gameChoosePile"),
GAME_CHOOSE_CHOICE(ClientCallbackType.DIALOG, "gameChooseChoice"),
GAME_ASK(ClientCallbackType.DIALOG, "gameAsk"),
GAME_SELECT(ClientCallbackType.DIALOG, "gameSelect"),
GAME_PLAY_MANA(ClientCallbackType.DIALOG, "gamePlayMana"),
GAME_PLAY_XMANA(ClientCallbackType.DIALOG, "gamePlayXMana"),
GAME_GET_AMOUNT(ClientCallbackType.DIALOG, "gameSelectAmount"),
GAME_GET_MULTI_AMOUNT(ClientCallbackType.DIALOG, "gameSelectMultiAmount"),
GAME_OVER(ClientCallbackType.TABLE_CHANGE, "gameOver"),
END_GAME_INFO(ClientCallbackType.TABLE_CHANGE, "endGameInfo"),
// replay (unsupported)
REPLAY_GAME(ClientCallbackType.TABLE_CHANGE, "replayGame"),
REPLAY_INIT(ClientCallbackType.TABLE_CHANGE, "replayInit"),
REPLAY_UPDATE(ClientCallbackType.UPDATE, "replayUpdate"),
REPLAY_DONE(ClientCallbackType.TABLE_CHANGE, "replayDone");
final ClientCallbackType type;
final String code;
ClientCallbackMethod(ClientCallbackType type, String code) {
this.type = type;
this.code = code; this.code = code;
this.isClientSideMessage = isClientSideMessage;
} }
public boolean isClientSideMessage() { public ClientCallbackType getType() {
return this.isClientSideMessage; return this.type;
} }
} }

View file

@ -0,0 +1,35 @@
package mage.interfaces.callback;
/**
* Server event type for processing on the client
*
* @author JayDi85
*/
public enum ClientCallbackType {
UPDATE(true, true), // game update
TABLE_CHANGE, // all important game events + game update
MESSAGE(true, false), // show message/log without game update
DIALOG, // all dialogs + game update
CLIENT_SIDE_EVENT(true, true); // without game uodate
final boolean canComeInAnyOrder;
final boolean mustIgnoreOnOutdated; // if event come in any order and contain game update then it must be ignored on outdate
ClientCallbackType() {
this(false, false);
}
ClientCallbackType(boolean canComeInAnyOrder, boolean mustIgnoreOnOutdated) {
this.canComeInAnyOrder = canComeInAnyOrder;
this.mustIgnoreOnOutdated = mustIgnoreOnOutdated;
}
public boolean canComeInAnyOrder() {
return this.canComeInAnyOrder;
}
public boolean mustIgnoreOnOutdated() {
return this.mustIgnoreOnOutdated;
}
}

View file

@ -716,8 +716,9 @@ public class CardView extends SimpleCardView {
// emblem images are always with common (black) symbol // emblem images are always with common (black) symbol
this.frameStyle = FrameStyle.M15_NORMAL; this.frameStyle = FrameStyle.M15_NORMAL;
this.expansionSetCode = emblem.getExpansionSetCode(); this.expansionSetCode = emblem.getExpansionSetCode();
this.cardNumber = ""; this.cardNumber = emblem.getCardNumber();
this.imageNumber = emblem.getImageNumber(); this.imageNumber = emblem.getImageNumber();
this.usesVariousArt = emblem.getUsesVariousArt();
this.rarity = Rarity.COMMON; this.rarity = Rarity.COMMON;
this.playableStats = emblem.playableStats.copy(); this.playableStats = emblem.playableStats.copy();

View file

@ -1,7 +1,7 @@
package mage.view; package mage.view;
import mage.cards.Card;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.emblems.EmblemOfCard;
import mage.players.PlayableObjectStats; import mage.players.PlayableObjectStats;
import java.io.Serializable; import java.io.Serializable;
@ -15,7 +15,9 @@ public class EmblemView implements CommandObjectView, Serializable {
protected UUID id; protected UUID id;
protected String name; protected String name;
protected String cardNumber = "";
protected int imageNum; protected int imageNum;
protected boolean usesVariousArt = false;
protected String expansionSetCode; protected String expansionSetCode;
protected List<String> rules; protected List<String> rules;
protected PlayableObjectStats playableStats = new PlayableObjectStats(); protected PlayableObjectStats playableStats = new PlayableObjectStats();
@ -26,6 +28,10 @@ public class EmblemView implements CommandObjectView, Serializable {
this.imageNum = emblem.getImageNumber(); this.imageNum = emblem.getImageNumber();
this.expansionSetCode = emblem.getExpansionSetCode(); this.expansionSetCode = emblem.getExpansionSetCode();
this.rules = emblem.getAbilities().getRules(emblem.getName()); this.rules = emblem.getAbilities().getRules(emblem.getName());
if (emblem instanceof EmblemOfCard) {
cardNumber = emblem.getCardNumber();
usesVariousArt = ((EmblemOfCard) emblem).getUsesVariousArt();
}
} }
@Override @Override
@ -43,10 +49,17 @@ public class EmblemView implements CommandObjectView, Serializable {
return id; return id;
} }
public String getCardNumber() {
return cardNumber;
}
@Override @Override
public int getImageNumber() { public int getImageNumber() {
return imageNum; return imageNum;
} }
public boolean getUsesVariousArt() {
return this.usesVariousArt;
}
@Override @Override
public List<String> getRules() { public List<String> getRules() {

View file

@ -62,7 +62,6 @@ public class GameView implements Serializable {
private final int turn; private final int turn;
private boolean special = false; private boolean special = false;
private final boolean isPlayer; // false = watching user private final boolean isPlayer; // false = watching user
private final int spellsCastCurrentTurn;
private final boolean rollbackTurnsAllowed; private final boolean rollbackTurnsAllowed;
public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) { public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) {
@ -195,13 +194,6 @@ public class GameView implements Serializable {
} else { } else {
this.special = false; this.special = false;
} }
CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class);
if (watcher != null) {
spellsCastCurrentTurn = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn();
} else {
spellsCastCurrentTurn = 0;
}
rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed; rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed;
} }
@ -335,10 +327,6 @@ public class GameView implements Serializable {
this.canPlayObjects = canPlayObjects; this.canPlayObjects = canPlayObjects;
} }
public int getSpellsCastCurrentTurn() {
return spellsCastCurrentTurn;
}
public boolean isRollbackTurnsAllowed() { public boolean isRollbackTurnsAllowed() {
return rollbackTurnsAllowed; return rollbackTurnsAllowed;
} }

View file

@ -117,6 +117,10 @@ public class TableView implements Serializable {
if (table.getMatch().getOptions().isPlaneChase()) { if (table.getMatch().getOptions().isPlaneChase()) {
addInfo.append(" PC"); addInfo.append(" PC");
} }
if (!(table.getMatch().getOptions().getPerPlayerEmblemCards().isEmpty())
|| !(table.getMatch().getOptions().getGlobalEmblemCards().isEmpty())) {
addInfo.append(" EC");
}
if (table.getMatch().getOptions().isSpectatorsAllowed()) { if (table.getMatch().getOptions().isSpectatorsAllowed()) {
addInfo.append(" SP"); addInfo.append(" SP");
} }
@ -177,6 +181,10 @@ public class TableView implements Serializable {
if (tourneyMatchOptions.isPlaneChase()) { if (tourneyMatchOptions.isPlaneChase()) {
infoText.append(" PC"); infoText.append(" PC");
} }
if (!(table.getTournament().getOptions().getMatchOptions().getPerPlayerEmblemCards().isEmpty())
|| !(table.getTournament().getOptions().getMatchOptions().getGlobalEmblemCards().isEmpty())) {
infoText.append(" EC");
}
if (table.getTournament().getOptions().isWatchingAllowed()) { if (table.getTournament().getOptions().isWatchingAllowed()) {
infoText.append(" SP"); infoText.append(" SP");
} }

View file

@ -68,7 +68,7 @@ public class Modern extends Constructed {
banned.add("Tree of Tales"); banned.add("Tree of Tales");
banned.add("Umezawa's Jitte"); banned.add("Umezawa's Jitte");
banned.add("Uro, Titan of Nature's Wrath"); banned.add("Uro, Titan of Nature's Wrath");
banned.add("Yorion, the Sky Nomad"); banned.add("Yorion, Sky Nomad");
banned.add("Vault of Whispers"); banned.add("Vault of Whispers");
} }
} }

View file

@ -32,9 +32,10 @@ import java.util.UUID;
* To summarize, this uses the default rules for a 1v1 limited match, * To summarize, this uses the default rules for a 1v1 limited match,
* with two additional custom rules: <p> * with two additional custom rules: <p>
* -> At the beginning of each player's first main phase, that player * -> At the beginning of each player's first main phase, that player
* conjure into play a Pillar of the Paruns. This does count as a * conjure into play a custom version of Pillar of the Paruns. This
* land drop for the turn. <p> * does count as a land drop for the turn. The custom Pillar has
* -> The starting hand size is 6, not 7. * hexproof and gain "{T}: add {1}."<p>
* -> The starting hand size is 6, and the starting life count is 25.
* <p> <p> * <p> <p>
* I did took the inspiration for the mode from this cube list (not * I did took the inspiration for the mode from this cube list (not
* sure it is the original source for the idea, but i did not found * sure it is the original source for the idea, but i did not found
@ -49,7 +50,7 @@ import java.util.UUID;
public class CustomPillarOfTheParunsDuel extends GameImpl { public class CustomPillarOfTheParunsDuel extends GameImpl {
public CustomPillarOfTheParunsDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan) { public CustomPillarOfTheParunsDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan) {
super(attackOption, range, mulligan, 20, 40, 6); super(attackOption, range, mulligan, 25, 40, 6);
} }
@Override @Override
@ -57,7 +58,10 @@ public class CustomPillarOfTheParunsDuel extends GameImpl {
super.init(choosingPlayerId); super.init(choosingPlayerId);
getPlayers().forEach((playerId, p) -> { getPlayers().forEach((playerId, p) -> {
addDelayedTriggeredAbility(new AtTheBeginOfPlayerFirstMainPhase(playerId, "Pillar of the Paruns"), null); addDelayedTriggeredAbility(
new AtTheBeginOfPlayerFirstMainPhase(playerId, "C-Pillar of the Paruns"),
null // TODO: Not sure how to mock something to be displayed instead.
);
}); });
state.getTurnMods().add(new TurnMod(startingPlayerId).withSkipStep(PhaseStep.DRAW)); state.getTurnMods().add(new TurnMod(startingPlayerId).withSkipStep(PhaseStep.DRAW));
@ -89,28 +93,28 @@ class InitPillarOfTheParunsEffect extends OneShotEffect {
private UUID playerId; private UUID playerId;
private String cardName; private String cardName;
InitPillarOfTheParunsEffect(UUID playerId, String cardName){ InitPillarOfTheParunsEffect(UUID playerId, String cardName) {
super(Outcome.PutLandInPlay); super(Outcome.PutLandInPlay);
this.playerId = playerId; this.playerId = playerId;
this.cardName = cardName; this.cardName = cardName;
this.staticText = "conjure " + cardName + " in play. It does count as a land played for the turn."; this.staticText = "conjure " + cardName + " in play. It does count as a land played for the turn.";
} }
private InitPillarOfTheParunsEffect(final InitPillarOfTheParunsEffect effect){ private InitPillarOfTheParunsEffect(final InitPillarOfTheParunsEffect effect) {
super(effect); super(effect);
this.playerId = effect.playerId; this.playerId = effect.playerId;
this.cardName = effect.cardName; this.cardName = effect.cardName;
} }
@Override @Override
public InitPillarOfTheParunsEffect copy(){ public InitPillarOfTheParunsEffect copy() {
return new InitPillarOfTheParunsEffect(this); return new InitPillarOfTheParunsEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source){ public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if(player == null){ if (player == null) {
return false; return false;
} }

View file

@ -61,6 +61,8 @@ 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 static final boolean ALLOW_USERS_TO_PUT_NON_PLAYABLE_SPELLS_ON_STACK_WORKAROUND = false; // warning, see workaround's info on usage
// TODO: all user feedback actions executed and waited in diff threads and can't catch exeptions, e.g. on wrong code usage
// must catch and log such errors
private transient Boolean responseOpenedForAnswer = false; // can't get response until prepared target (e.g. until send all fire events to all players) 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(); private final transient PlayerResponse response = new PlayerResponse();
@ -1315,7 +1317,7 @@ public class HumanPlayer extends PlayerImpl {
while (canRespond()) { while (canRespond()) {
// try to set trigger auto order // try to set trigger auto order
java.util.List<TriggeredAbility> abilitiesWithNoOrderSet = new ArrayList<>(); java.util.List<TriggeredAbility> abilitiesWithNoOrderSet = new ArrayList<>();
TriggeredAbility abilityOrderLast = null; java.util.List<TriggeredAbility> abilitiesOrderLast = new ArrayList<>();
for (TriggeredAbility ability : abilities) { for (TriggeredAbility ability : abilities) {
if (triggerAutoOrderAbilityFirst.contains(ability.getOriginalId())) { if (triggerAutoOrderAbilityFirst.contains(ability.getOriginalId())) {
return ability; return ability;
@ -1326,17 +1328,20 @@ public class HumanPlayer extends PlayerImpl {
return ability; return ability;
} }
if (triggerAutoOrderAbilityLast.contains(ability.getOriginalId())) { if (triggerAutoOrderAbilityLast.contains(ability.getOriginalId())) {
abilityOrderLast = ability; // multiple instances of same trigger has same originalId, no need to select order for it
abilitiesOrderLast.add(ability);
continue; continue;
} }
if (triggerAutoOrderNameLast.contains(rule)) { if (triggerAutoOrderNameLast.contains(rule)) {
abilityOrderLast = ability; abilitiesOrderLast.add(ability);
continue; continue;
} }
if (autoOrderUse) { if (autoOrderUse) {
// multiple triggers with same rule text will be auto-ordered
if (autoOrderRuleText == null) { if (autoOrderRuleText == null) {
autoOrderRuleText = rule; autoOrderRuleText = rule;
} else if (!rule.equals(autoOrderRuleText)) { } else if (!rule.equals(autoOrderRuleText)) {
// diff triggers, so must use choose dialog
autoOrderUse = false; autoOrderUse = false;
} }
} }
@ -1344,7 +1349,8 @@ public class HumanPlayer extends PlayerImpl {
} }
if (abilitiesWithNoOrderSet.isEmpty()) { if (abilitiesWithNoOrderSet.isEmpty()) {
return abilityOrderLast; // user can send diff abilities to the last, will be selected by "first" like first ordered ability above
return abilitiesOrderLast.stream().findFirst().orElse(null);
} }
if (abilitiesWithNoOrderSet.size() == 1 if (abilitiesWithNoOrderSet.size() == 1
@ -1352,6 +1358,21 @@ public class HumanPlayer extends PlayerImpl {
return abilitiesWithNoOrderSet.iterator().next(); return abilitiesWithNoOrderSet.iterator().next();
} }
// runtime check: lost triggers for GUI
List<Ability> processingAbilities = new ArrayList<>(abilitiesWithNoOrderSet);
processingAbilities.addAll(abilitiesOrderLast);
if (abilities.size() != processingAbilities.size()) {
throw new IllegalStateException(String.format("Choose dialog lost some of the triggered abilities:\n"
+ "Must %d:\n%s\n"
+ "Has %d:\n%s",
abilities.size(),
abilities.stream().map(Ability::getRule).collect(Collectors.joining("\n")),
processingAbilities.size(),
processingAbilities.stream().map(Ability::getRule).collect(Collectors.joining("\n"))
));
}
macroTriggeredSelectionFlag = true; macroTriggeredSelectionFlag = true;
updateGameStatePriority("chooseTriggeredAbility", game); updateGameStatePriority("chooseTriggeredAbility", game);
prepareForResponse(game); prepareForResponse(game);
@ -2662,6 +2683,13 @@ public class HumanPlayer extends PlayerImpl {
} }
} }
/**
* GUI related, remember choices for choose trigger dialog
*
* @param playerAction
* @param game
* @param data
*/
private void setTriggerAutoOrder(PlayerAction playerAction, Game game, Object data) { private void setTriggerAutoOrder(PlayerAction playerAction, Game game, Object data) {
if (playerAction == TRIGGER_AUTO_ORDER_RESET_ALL) { if (playerAction == TRIGGER_AUTO_ORDER_RESET_ALL) {
triggerAutoOrderAbilityFirst.clear(); triggerAutoOrderAbilityFirst.clear();
@ -2670,7 +2698,9 @@ public class HumanPlayer extends PlayerImpl {
triggerAutoOrderNameLast.clear(); triggerAutoOrderNameLast.clear();
return; return;
} }
if (data instanceof UUID) { if (data instanceof UUID) {
// remember by id
UUID abilityId = (UUID) data; UUID abilityId = (UUID) data;
UUID originalId = null; UUID originalId = null;
for (TriggeredAbility ability : game.getState().getTriggered(getId())) { for (TriggeredAbility ability : game.getState().getTriggered(getId())) {
@ -2685,12 +2715,17 @@ public class HumanPlayer extends PlayerImpl {
triggerAutoOrderAbilityFirst.add(originalId); triggerAutoOrderAbilityFirst.add(originalId);
break; break;
case TRIGGER_AUTO_ORDER_ABILITY_LAST: case TRIGGER_AUTO_ORDER_ABILITY_LAST:
triggerAutoOrderAbilityFirst.add(originalId); triggerAutoOrderAbilityLast.add(originalId);
break; break;
} }
} }
} else if (data instanceof String) { } else if (data instanceof String) {
// remember by name
String abilityName = (String) data; String abilityName = (String) data;
if (abilityName.contains("{this}")) {
throw new IllegalArgumentException("Wrong code usage. Remembering trigger must contains full rules name without {this}.");
}
switch (playerAction) { switch (playerAction) {
case TRIGGER_AUTO_ORDER_NAME_FIRST: case TRIGGER_AUTO_ORDER_NAME_FIRST:
triggerAutoOrderNameFirst.add(abilityName); triggerAutoOrderNameFirst.add(abilityName);

View file

@ -628,6 +628,8 @@ public class TableController {
gameOptions.rollbackTurnsAllowed = match.getOptions().isRollbackTurnsAllowed(); gameOptions.rollbackTurnsAllowed = match.getOptions().isRollbackTurnsAllowed();
gameOptions.bannedUsers = match.getOptions().getBannedUsers(); gameOptions.bannedUsers = match.getOptions().getBannedUsers();
gameOptions.planeChase = match.getOptions().isPlaneChase(); gameOptions.planeChase = match.getOptions().isPlaneChase();
gameOptions.perPlayerEmblemCards = match.getOptions().getPerPlayerEmblemCards();
gameOptions.globalEmblemCards = match.getOptions().getGlobalEmblemCards();
match.getGame().setGameOptions(gameOptions); match.getGame().setGameOptions(gameOptions);
managerFactory.gameManager().createGameSession(match.getGame(), userPlayerMap, table.getId(), choosingPlayerId, gameOptions); managerFactory.gameManager().createGameSession(match.getGame(), userPlayerMap, table.getId(), choosingPlayerId, gameOptions);
String creator = null; String creator = null;

View file

@ -271,10 +271,6 @@ public class User {
fireCallback(new ClientCallback(ClientCallbackMethod.SHOW_TOURNAMENT, tournamentId)); fireCallback(new ClientCallback(ClientCallbackMethod.SHOW_TOURNAMENT, tournamentId));
} }
public void ccShowGameEndDialog(final UUID gameId) {
fireCallback(new ClientCallback(ClientCallbackMethod.SHOW_GAME_END_DIALOG, gameId));
}
public void showUserMessage(final String titel, String message) { public void showUserMessage(final String titel, String message) {
List<String> messageData = new LinkedList<>(); List<String> messageData = new LinkedList<>();
messageData.add(titel); messageData.add(titel);

View file

@ -58,7 +58,7 @@ public class GameSessionWatcher {
public void inform(final String message) { public void inform(final String message) {
if (!killed) { if (!killed) {
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_INFORM, game.getId(), new GameClientMessage(getGameView(), null, message)))); userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_UPDATE_AND_INFORM, game.getId(), new GameClientMessage(getGameView(), null, message))));
} }
} }

View file

@ -61,11 +61,6 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl {
return new AbeyanceEffect(this); return new AbeyanceEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);
@ -76,6 +71,12 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl {
return null; return null;
} }
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL
|| event.getType() == GameEvent.EventType.ACTIVATE_ABILITY;
}
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (source.getFirstTarget() != null if (source.getFirstTarget() != null

View file

@ -57,11 +57,6 @@ class AetherStormReplacementEffect extends ContinuousRuleModifyingEffectImpl {
super(effect); super(effect);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public AetherStormReplacementEffect copy() { public AetherStormReplacementEffect copy() {
return new AetherStormReplacementEffect(this); return new AetherStormReplacementEffect(this);

View file

@ -64,11 +64,6 @@ class AggressiveMiningEffect extends ContinuousRuleModifyingEffectImpl {
public AggressiveMiningEffect copy() { public AggressiveMiningEffect copy() {
return new AggressiveMiningEffect(this); return new AggressiveMiningEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {

View file

@ -19,9 +19,11 @@ import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.util.CardUtil;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -88,11 +90,14 @@ class AgrusKosEternalSoldierTriggeredAbility extends TriggeredAbilityImpl {
if (!event.getTargetId().equals(getSourceId())) { if (!event.getTargetId().equals(getSourceId())) {
return false; return false;
} }
StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
if (stackObject == null) { if (targetingObject == null || targetingObject instanceof Spell) {
return false; return false;
} }
Set<UUID> targets = stackObject if (CardUtil.checkTargetedEventAlreadyUsed(this.id.toString(), targetingObject, event, game)) {
return false;
}
Set<UUID> targets = targetingObject
.getStackAbility() .getStackAbility()
.getTargets() .getTargets()
.stream() .stream()
@ -102,7 +107,7 @@ class AgrusKosEternalSoldierTriggeredAbility extends TriggeredAbilityImpl {
if (targets.isEmpty() || !targets.stream().allMatch(getSourceId()::equals)) { if (targets.isEmpty() || !targets.stream().allMatch(getSourceId()::equals)) {
return false; return false;
} }
this.getEffects().setValue("triggeringAbility", stackObject); this.getEffects().setValue("triggeringAbility", targetingObject);
return true; return true;
} }
} }

View file

@ -1,18 +1,19 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.SacrificeEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID; import java.util.UUID;
@ -36,21 +37,12 @@ public class AllegiantGeneralPryde extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Trooper creatures you control have "When this creature enters the battlefield, you may sacrifice a creature. If you do, draw two cards and lose 2 life." // Trooper creatures you control have "When this creature enters the battlefield, you may sacrifice a creature. If you do, draw two cards and lose 2 life."
SacrificeEffect sacrifceEffect = new SacrificeEffect( Ability gainedAbility = new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(
StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, 1, ""); new DrawCardSourceControllerEffect(2),
EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(sacrifceEffect, true, true); new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)
ability.setTriggerPhrase("When this creature enters the battlefield, "); ).addEffect(new LoseLifeSourceControllerEffect(2).concatBy("and")))
ability.addTarget(new TargetControlledCreaturePermanent(1)); .setTriggerPhrase("When this creature enters the battlefield, ");
DrawCardSourceControllerEffect drawCardSourceControllerEffect = new DrawCardSourceControllerEffect(2); this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(gainedAbility, Duration.WhileOnBattlefield, filter)));
drawCardSourceControllerEffect.setText("If you do, draw two cards");
ability.addEffect(drawCardSourceControllerEffect);
LoseLifeSourceControllerEffect loseLifeSourceControllerEffect = new LoseLifeSourceControllerEffect(2);
loseLifeSourceControllerEffect.setText("and lose 2 life.");
ability.addEffect(loseLifeSourceControllerEffect);
//EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2), true);
GainAbilityControlledEffect effect = new GainAbilityControlledEffect(
ability, Duration.WhileOnBattlefield, filter);
this.addAbility(new SimpleStaticAbility(effect));
} }
private AllegiantGeneralPryde(final AllegiantGeneralPryde card) { private AllegiantGeneralPryde(final AllegiantGeneralPryde card) {

View file

@ -1,7 +1,7 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.common.BecomesTargetControllerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.TargetOfOpponentsSpellOrAbilityTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.CounterUnlessPaysEffect; import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostAllEffect;
@ -9,6 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.SetTargetPointer;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
@ -24,7 +25,8 @@ public final class AmuletOfSafekeeping extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// Whenever you become the target of a spell or ability an opponent controls, counter that spell or ability unless its controller pays {1}. // Whenever you become the target of a spell or ability an opponent controls, counter that spell or ability unless its controller pays {1}.
this.addAbility(new TargetOfOpponentsSpellOrAbilityTriggeredAbility(new CounterUnlessPaysEffect(new GenericManaCost(1)), false, true)); this.addAbility(new BecomesTargetControllerTriggeredAbility(new CounterUnlessPaysEffect(new GenericManaCost(1)),
null, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.SPELL, false));
// Creature tokens get -1/-0. // Creature tokens get -1/-0.
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(

View file

@ -2,12 +2,11 @@ package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessAllEffect; import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessControlledEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
import mage.game.Game; import mage.game.Game;
@ -21,11 +20,10 @@ import java.util.UUID;
public final class AncientLumberknot extends CardImpl { public final class AncientLumberknot extends CardImpl {
private static final FilterCreaturePermanent filter private static final FilterCreaturePermanent filter
= new FilterCreaturePermanent("each creature you control with toughness greater than its power"); = new FilterCreaturePermanent("creature you control with toughness greater than its power");
static { static {
filter.add(AncientLumberknotPredicate.instance); filter.add(AncientLumberknotPredicate.instance);
filter.add(TargetController.YOU.getControllerPredicate());
} }
public AncientLumberknot(UUID ownerId, CardSetInfo setInfo) { public AncientLumberknot(UUID ownerId, CardSetInfo setInfo) {
@ -36,7 +34,7 @@ public final class AncientLumberknot extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Each creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power. // Each creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power.
this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessAllEffect(filter))); this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect(filter)));
} }
private AncientLumberknot(final AncientLumberknot card) { private AncientLumberknot(final AncientLumberknot card) {

View file

@ -98,11 +98,6 @@ class AngelicArbiterEffect2 extends ContinuousRuleModifyingEffectImpl {
return new AngelicArbiterEffect2(this); return new AngelicArbiterEffect2(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL; return event.getType() == GameEvent.EventType.CAST_SPELL;

View file

@ -1,7 +1,7 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BecomesTargetSourceFirstTimeTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
@ -12,18 +12,15 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.SetTargetPointer;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.filter.StaticFilters;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.common.NumberOfTimesPermanentTargetedATurnWatcher;
import java.util.UUID; import java.util.UUID;
/** /**
* @author AustinYQM * @author AustinYQM, xenohedron
*/ */
public final class AngelicCub extends CardImpl { public final class AngelicCub extends CardImpl {
@ -36,7 +33,11 @@ public final class AngelicCub extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Whenever Angelic Cub becomes the target of a spell or ability for the first time each turn, put a +1/+1 counter on it. // Whenever Angelic Cub becomes the target of a spell or ability for the first time each turn, put a +1/+1 counter on it.
this.addAbility(new AngelicCubAbility(), new NumberOfTimesPermanentTargetedATurnWatcher()); this.addAbility(new BecomesTargetSourceFirstTimeTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance())
.setText("put a +1/+1 counter on it"),
StaticFilters.FILTER_SPELL_OR_ABILITY_A, SetTargetPointer.NONE, false
));
// As long as Angelic Cub has three or more +1/+1 counters on it, it has flying. // As long as Angelic Cub has three or more +1/+1 counters on it, it has flying.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.P1P1, 3), "As long as {this} has three or more +1/+1 counters on it, it has flying."))); this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.P1P1, 3), "As long as {this} has three or more +1/+1 counters on it, it has flying.")));
} }
@ -50,41 +51,3 @@ public final class AngelicCub extends CardImpl {
return new AngelicCub(this); return new AngelicCub(this);
} }
} }
class AngelicCubAbility extends TriggeredAbilityImpl {
public AngelicCubAbility() {
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false);
}
public AngelicCubAbility(final mage.cards.a.AngelicCubAbility ability) {
super(ability);
}
@Override
public mage.cards.a.AngelicCubAbility copy() {
return new mage.cards.a.AngelicCubAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getTargetId().equals(this.getSourceId())) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.isCreature(game)) {
NumberOfTimesPermanentTargetedATurnWatcher watcher = game.getState().getWatcher(NumberOfTimesPermanentTargetedATurnWatcher.class);
return watcher != null && watcher.notMoreThanOnceTargetedThisTurn(permanent, game);
}
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} becomes the target of a spell or ability for the first time each turn, put a +1/+1 counter on it.";
}
}

View file

@ -1,7 +1,7 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -25,9 +25,9 @@ public final class AngelicProtector extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
this.addAbility(new SourceBecomesTargetTriggeredAbility( this.addAbility(new BecomesTargetSourceTriggeredAbility(
new BoostSourceEffect(0, 3, Duration.EndOfTurn) new BoostSourceEffect(0, 3, Duration.EndOfTurn)
).setTriggerPhrase("Whenever {this} becomes the target of a spell or ability, ")); ).withRuleTextReplacement(false));
} }
private AngelicProtector(final AngelicProtector card) { private AngelicProtector(final AngelicProtector card) {

View file

@ -1,6 +1,8 @@
package mage.cards.a; package mage.cards.a;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -14,7 +16,7 @@ import mage.constants.CardType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.ExpansionSetPredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.TokenPredicate; import mage.filter.predicate.permanent.TokenPredicate;
/** /**
@ -26,10 +28,14 @@ public final class ApocalypseChime extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("nontoken permanents with a name originally printed in the Homelands expansion"); private static final FilterPermanent filter = new FilterPermanent("nontoken permanents with a name originally printed in the Homelands expansion");
static { static {
filter.add(Predicates.and( // Homelands names per CR 206.3c
TokenPredicate.FALSE, List<String> nameStrings = Arrays.asList("Abbey Gargoyles", "Abbey Matron", "Aether Storm", "Aliban's Tower", "Ambush", "Ambush Party", "Anaba Ancestor", "Anaba Bodyguard", "Anaba Shaman", "Anaba Spirit Crafter", "An-Havva Constable", "An-Havva Inn", "An-Havva Township", "An-Zerrin Ruins", "Apocalypse Chime", "Autumn Willow", "Aysen Abbey", "Aysen Bureaucrats", "Aysen Crusader", "Aysen Highway", "Baki's Curse", "Baron Sengir", "Beast Walkers", "Black Carriage", "Broken Visage", "Carapace", "Castle Sengir", "Cemetery Gate", "Chain Stasis", "Chandler", "Clockwork Gnomes", "Clockwork Steed", "Clockwork Swarm", "Coral Reef", "Dark Maze", "Daughter of Autumn", "Death Speakers", "Didgeridoo", "Drudge Spell", "Dry Spell", "Dwarven Pony", "Dwarven Sea Clan", "Dwarven Trader", "Ebony Rhino", "Eron the Relentless", "Evaporate", "Faerie Noble", "Feast of the Unicorn", "Feroz's Ban", "Folk of An-Havva", "Forget", "Funeral March", "Ghost Hounds", "Giant Albatross", "Giant Oyster", "Grandmother Sengir", "Greater Werewolf", "Hazduhr the Abbot", "Headstone", "Heart Wolf", "Hungry Mist", "Ihsan's Shade", "Irini Sengir", "Ironclaw Curse", "Jinx", "Joven", "Joven's Ferrets", "Joven's Tools", "Koskun Falls", "Koskun Keep", "Labyrinth Minotaur", "Leaping Lizard", "Leeches", "Mammoth Harness", "Marjhan", "Memory Lapse", "Merchant Scroll", "Mesa Falcon", "Mystic Decree", "Narwhal", "Orcish Mine", "Primal Order", "Prophecy", "Rashka the Slayer", "Reef Pirates", "Renewal", "Retribution", "Reveka, Wizard Savant", "Root Spider", "Roots", "Roterothopter", "Rysorian Badger", "Samite Alchemist", "Sea Sprite", "Sea Troll", "Sengir Autocrat", "Sengir Bats", "Serra Aviary", "Serra Bestiary", "Serra Inquisitors", "Serra Paladin", "Serrated Arrows", "Shrink", "Soraya the Falconer", "Spectral Bears", "Timmerian Fiends", "Torture", "Trade Caravan", "Truce", "Veldrane of Sengir", "Wall of Kelp", "Willow Faerie", "Willow Priestess", "Winter Sky", "Wizards' School");
new ExpansionSetPredicate("HML") List<NamePredicate> namePredicates = new ArrayList<>();
)); for (String name: nameStrings) {
namePredicates.add(new NamePredicate(name));
}
filter.add(TokenPredicate.FALSE);
filter.add(Predicates.or(namePredicates));
} }
public ApocalypseChime(UUID ownerId, CardSetInfo setInfo) { public ApocalypseChime(UUID ownerId, CardSetInfo setInfo) {

View file

@ -0,0 +1,72 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.PopulateEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.token.SylvanOfferingTreefolkToken;
import java.util.UUID;
/**
* @author Susucr
*/
public final class ArborealAlliance extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent(SubType.ELF, "Elves");
public ArborealAlliance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{X}{G}{G}");
// When Arboreal Alliance enters the battlefield, create an X/X green Treefolk creature token.
this.addAbility(new EntersBattlefieldTriggeredAbility(new ArborealAllianceEffect()));
// Whenever you attack with one or more Elves, populate.
this.addAbility(new AttacksWithCreaturesTriggeredAbility(
new PopulateEffect(), 1, filter
));
}
private ArborealAlliance(final ArborealAlliance card) {
super(card);
}
@Override
public ArborealAlliance copy() {
return new ArborealAlliance(this);
}
}
class ArborealAllianceEffect extends OneShotEffect {
ArborealAllianceEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "create an X/X green Treefolk creature token";
}
private ArborealAllianceEffect(final ArborealAllianceEffect effect) {
super(effect);
}
@Override
public ArborealAllianceEffect copy() {
return new ArborealAllianceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return new CreateTokenEffect(
new SylvanOfferingTreefolkToken(ManacostVariableValue.ETB.calculate(game, source, this))
).apply(game, source);
}
}

View file

@ -6,7 +6,7 @@ import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderAllEffect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderAllEffect;
import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessAllEffect; import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessControlledEffect;
import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.DefenderAbility;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
@ -25,12 +25,10 @@ import java.util.UUID;
public final class ArcadesTheStrategist extends CardImpl { public final class ArcadesTheStrategist extends CardImpl {
private static final FilterControlledCreaturePermanent defenderSingle = new FilterControlledCreaturePermanent("a creature with defender"); private static final FilterControlledCreaturePermanent defenderSingle = new FilterControlledCreaturePermanent("a creature with defender");
private static final FilterCreaturePermanent defenderPlural = new FilterCreaturePermanent("Each creature you control with defender"); private static final FilterCreaturePermanent defenderPlural = new FilterCreaturePermanent("creature you control with defender");
static { static {
defenderSingle.add(new AbilityPredicate(DefenderAbility.class)); defenderSingle.add(new AbilityPredicate(DefenderAbility.class));
defenderPlural.add(TargetController.YOU.getControllerPredicate());
defenderPlural.add(new AbilityPredicate(DefenderAbility.class)); defenderPlural.add(new AbilityPredicate(DefenderAbility.class));
} }
@ -55,7 +53,7 @@ public final class ArcadesTheStrategist extends CardImpl {
)); ));
// Each creature you control with defender assigns combat damage equal to its toughness rather than its power and can attack as though it didn't have defender. // Each creature you control with defender assigns combat damage equal to its toughness rather than its power and can attack as though it didn't have defender.
Ability ability = new SimpleStaticAbility(new CombatDamageByToughnessAllEffect(defenderPlural)); Ability ability = new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect(defenderPlural));
ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderAllEffect( ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderAllEffect(
Duration.WhileOnBattlefield, defenderSingle Duration.WhileOnBattlefield, defenderSingle
).setText("and can attack as though it didn't have defender")); ).setText("and can attack as though it didn't have defender"));

View file

@ -1,25 +1,19 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration; import mage.filter.StaticFilters;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent; import java.util.UUID;
import mage.game.events.GameEvent.EventType;
import mage.target.targetpointer.FixedTarget;
/** /**
* *
@ -35,7 +29,6 @@ public final class AshenmoorLiege extends CardImpl {
filterRedCreature.add(new ColorPredicate(ObjectColor.RED)); filterRedCreature.add(new ColorPredicate(ObjectColor.RED));
} }
public AshenmoorLiege(UUID ownerId, CardSetInfo setInfo) { public AshenmoorLiege(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B/R}{B/R}{B/R}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B/R}{B/R}{B/R}");
this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.ELEMENTAL);
@ -50,10 +43,8 @@ public final class AshenmoorLiege extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filterRedCreature, true))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filterRedCreature, true)));
// Whenever Ashenmoor Liege becomes the target of a spell or ability an opponent controls, that player loses 4 life. // Whenever Ashenmoor Liege becomes the target of a spell or ability an opponent controls, that player loses 4 life.
this.addAbility(new AshenmoorLiegeTriggeredAbility()); this.addAbility(new BecomesTargetSourceTriggeredAbility(new LoseLifeTargetEffect(4),
StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.PLAYER, false));
} }
private AshenmoorLiege(final AshenmoorLiege card) { private AshenmoorLiege(final AshenmoorLiege card) {
@ -65,39 +56,3 @@ public final class AshenmoorLiege extends CardImpl {
return new AshenmoorLiege(this); return new AshenmoorLiege(this);
} }
} }
class AshenmoorLiegeTriggeredAbility extends TriggeredAbilityImpl {
public AshenmoorLiegeTriggeredAbility() {
super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(4), false);
}
private AshenmoorLiegeTriggeredAbility(final AshenmoorLiegeTriggeredAbility ability) {
super(ability);
}
@Override
public AshenmoorLiegeTriggeredAbility copy() {
return new AshenmoorLiegeTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getTargetId().equals(this.getSourceId()) && game.getOpponents(this.controllerId).contains(event.getPlayerId())) {
getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId()));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} becomes the target of a spell or ability an opponent controls, that player loses 4 life.";
}
}

View file

@ -59,11 +59,6 @@ class AshesOfTheAbhorrentEffect extends ContinuousRuleModifyingEffectImpl {
return new AshesOfTheAbhorrentEffect(this); return new AshesOfTheAbhorrentEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL return event.getType() == GameEvent.EventType.CAST_SPELL

View file

@ -66,11 +66,6 @@ class AshiokDreamRenderEffect extends ContinuousRuleModifyingEffectImpl {
return new AshiokDreamRenderEffect(this); return new AshiokDreamRenderEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);

View file

@ -151,11 +151,6 @@ class AshioksErasureReplacementEffect extends ContinuousRuleModifyingEffectImpl
return false; return false;
} }
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override @Override
public AshioksErasureReplacementEffect copy() { public AshioksErasureReplacementEffect copy() {
return new AshioksErasureReplacementEffect(this); return new AshioksErasureReplacementEffect(this);

View file

@ -1,4 +1,3 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -7,14 +6,13 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderTargetEffect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderTargetEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessAllEffect; import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessControlledEffect;
import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.DefenderAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -36,7 +34,7 @@ public final class AssaultFormation extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}");
// Each creature you control assigns combat damage equal to its toughness rather than its power. // Each creature you control assigns combat damage equal to its toughness rather than its power.
this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURE_EACH))); this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect()));
// {G}: Target creature with defender can attack this turn as though it didn't have defender. // {G}: Target creature with defender can attack this turn as though it didn't have defender.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanAttackAsThoughItDidntHaveDefenderTargetEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{G}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanAttackAsThoughItDidntHaveDefenderTargetEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{G}"));

View file

@ -1,7 +1,6 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -25,14 +24,15 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class AssaultSuit extends CardImpl { public final class AssaultSuit extends CardImpl {
public AssaultSuit(UUID ownerId, CardSetInfo setInfo) { public AssaultSuit(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
this.subtype.add(SubType.EQUIPMENT); this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +2/+2, has haste, can't attack you or a planeswalker you control, and can't be sacrificed. // Equipped creature gets +2/+2, has haste, can't attack you or a planeswalker you control, and can't be sacrificed.
@ -65,7 +65,7 @@ public final class AssaultSuit extends CardImpl {
} }
} }
class AssaultSuitCantBeSacrificed extends ContinuousRuleModifyingEffectImpl { class AssaultSuitCantBeSacrificed extends ContinuousRuleModifyingEffectImpl {
public AssaultSuitCantBeSacrificed() { public AssaultSuitCantBeSacrificed() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, true, false); super(Duration.WhileOnBattlefield, Outcome.Detriment, true, false);
@ -81,25 +81,20 @@ public final class AssaultSuit extends CardImpl {
return new AssaultSuitCantBeSacrificed(this); return new AssaultSuitCantBeSacrificed(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
return "This creature can't be sacrificed."; return "This creature can't be sacrificed.";
} }
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT;
}
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT) { Permanent equipment = game.getPermanent(source.getSourceId());
Permanent equipment = game.getPermanent(source.getSourceId()); return equipment != null && equipment.isAttachedTo(event.getTargetId());
if (equipment != null) {
return equipment.isAttachedTo(event.getTargetId());
}
}
return false;
} }
} }

View file

@ -42,7 +42,7 @@ public final class AstralDragon extends CardImpl {
false, null, 3, 3, true); false, null, 3, 3, true);
effect.setText("create two tokens that are copies of target noncreature permanent, " + effect.setText("create two tokens that are copies of target noncreature permanent, " +
"except they're 3/3 Dragon creatures in addition to their other types, and they have flying"); "except they're 3/3 Dragon creatures in addition to their other types, and they have flying");
effect.setAdditionalSubType(SubType.DRAGON); effect.withAdditionalSubType(SubType.DRAGON);
Ability ability = new EntersBattlefieldTriggeredAbility(effect); Ability ability = new EntersBattlefieldTriggeredAbility(effect);
ability.addTarget(new TargetPermanent(filter)); ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability.withFlavorWord("Project Image")); this.addAbility(ability.withFlavorWord("Project Image"));

View file

@ -133,11 +133,6 @@ class AureliasFuryCantCastEffect extends ContinuousRuleModifyingEffectImpl {
return new AureliasFuryCantCastEffect(this); return new AureliasFuryCantCastEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);
@ -176,22 +171,27 @@ class AureliasFuryDamagedByWatcher extends Watcher {
@Override @Override
public void watch(GameEvent event, Game game) { public void watch(GameEvent event, Game game) {
MageObject obj = game.getObject(event.getSourceId());
if (!(obj instanceof Spell) || !sourceId.equals(((Spell) obj).getSourceId())) {
return;
}
switch (event.getType()) { switch (event.getType()) {
case DAMAGED_PERMANENT: case DAMAGED_PERMANENT:
Permanent permanent = game.getPermanent(event.getTargetId()); Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.isCreature(game)) { if (isOurSource(event, game) && permanent != null && permanent.isCreature(game)) {
damagedCreatures.add(event.getTargetId()); damagedCreatures.add(event.getTargetId());
} }
return; break;
case DAMAGED_PLAYER: case DAMAGED_PLAYER:
damagedPlayers.add(event.getTargetId()); if (isOurSource(event, game)) {
damagedPlayers.add(event.getTargetId());
}
break;
} }
} }
private boolean isOurSource(GameEvent event, Game game) {
// must call after event filter
MageObject obj = game.getObject(event.getSourceId());
return obj instanceof Spell && sourceId.equals(((Spell) obj).getSourceId());
}
@Override @Override
public void reset() { public void reset() {
super.reset(); super.reset();

View file

@ -106,11 +106,6 @@ class AzorTheLawbringerCantCastEffect extends ContinuousRuleModifyingEffectImpl
return new AzorTheLawbringerCantCastEffect(this); return new AzorTheLawbringerCantCastEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);
@ -120,6 +115,11 @@ class AzorTheLawbringerCantCastEffect extends ContinuousRuleModifyingEffectImpl
return null; return null;
} }
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
UUID opponentId = getTargetPointer().getFirst(game, source); UUID opponentId = getTargetPointer().getFirst(game, source);

View file

@ -16,7 +16,6 @@ import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID; import java.util.UUID;
@ -37,7 +36,7 @@ public final class BaldinCenturyHerdmaster extends CardImpl {
// As long as it's your turn, each creature assigns combat damage equal to its toughness rather than its power. // As long as it's your turn, each creature assigns combat damage equal to its toughness rather than its power.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new CombatDamageByToughnessAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE), new CombatDamageByToughnessAllEffect(),
MyTurnCondition.instance, "as long as it's your turn, each creature " + MyTurnCondition.instance, "as long as it's your turn, each creature " +
"assigns combat damage equal to its toughness rather than its power" "assigns combat damage equal to its toughness rather than its power"
))); )));

View file

@ -39,7 +39,7 @@ public final class BallroomBrawlers extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Whenever Ballroom Brawlers attacks, Ballroom Brawlers and up to one other target creature you control each gain your choice of first strike or lifelink until end of turn. // Whenever Ballroom Brawlers attacks, Ballroom Brawlers and up to one other target creature you control each gain your choice of first strike or lifelink until end of turn.
Ability ability = new AttacksTriggeredAbility(new BallroomBrawlersEffect()).setReplaceRuleText(false); Ability ability = new AttacksTriggeredAbility(new BallroomBrawlersEffect()).withRuleTextReplacement(false);
ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -124,16 +124,12 @@ class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl {
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean checksEventType(GameEvent event, Game game) {
return true; return event.getType() == GameEvent.EventType.COUNTER;
} }
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() != GameEvent.EventType.COUNTER) {
return false;
}
Card card = game.getCard(source.getSourceId()); Card card = game.getCard(source.getSourceId());
if (card == null) { if (card == null) {
return false; return false;

View file

@ -65,11 +65,6 @@ class BartelRuneaxeEffect extends ContinuousRuleModifyingEffectImpl {
return event.getType() == GameEvent.EventType.TARGET; return event.getType() == GameEvent.EventType.TARGET;
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());

View file

@ -72,11 +72,6 @@ class BasandraBattleSeraphEffect extends ContinuousRuleModifyingEffectImpl {
return new BasandraBattleSeraphEffect(this); return new BasandraBattleSeraphEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL; return event.getType() == GameEvent.EventType.CAST_SPELL;

View file

@ -26,7 +26,7 @@ public final class BasilicaScreecher extends CardImpl {
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Extort (Whenever you cast a spell, you pay {WB}. If you do, each opponent loses 1 life and you gain that much life.) // Extort (Whenever you cast a spell, you may pay {WB}. If you do, each opponent loses 1 life and you gain that much life.)
this.addAbility(new ExtortAbility()); this.addAbility(new ExtortAbility());
} }

View file

@ -1,14 +1,16 @@
package mage.cards.b; package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.BecomesTargetOpponentAllTriggeredAbility; import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.ForetellAbility; import mage.abilities.keyword.ForetellAbility;
import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters;
import java.util.UUID; import java.util.UUID;
@ -28,8 +30,8 @@ public final class BattleMammoth extends CardImpl {
this.addAbility(TrampleAbility.getInstance()); this.addAbility(TrampleAbility.getInstance());
// Whenever a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card. // Whenever a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card.
this.addAbility(new BecomesTargetOpponentAllTriggeredAbility( this.addAbility(new BecomesTargetAnyTriggeredAbility(new DrawCardSourceControllerEffect(1),
new DrawCardSourceControllerEffect(1), true StaticFilters.FILTER_CONTROLLED_A_PERMANENT, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.NONE, true
)); ));
// Foretell {2}{G}{G} // Foretell {2}{G}{G}

View file

@ -1,15 +1,13 @@
package mage.cards.b; package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessAllEffect; import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessControlledEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import java.util.UUID; import java.util.UUID;
/** /**
@ -25,7 +23,7 @@ public final class BelligerentBrontodon extends CardImpl {
this.toughness = new MageInt(6); this.toughness = new MageInt(6);
// Each creature you control assigns combat damage equal to its toughness rather than its power. // Each creature you control assigns combat damage equal to its toughness rather than its power.
this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURE_EACH))); this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect()));
} }
private BelligerentBrontodon(final BelligerentBrontodon card) { private BelligerentBrontodon(final BelligerentBrontodon card) {

View file

@ -19,11 +19,7 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetLandPermanent; import mage.target.common.TargetLandPermanent;
import java.util.ArrayList; import java.util.*;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/** /**
* @author jeffwadsworth * @author jeffwadsworth
@ -110,22 +106,32 @@ class BenthicExplorersManaEffect extends ManaEffect {
@Override @Override
public Mana produceMana(Game game, Ability source) { public Mana produceMana(Game game, Ability source) {
Mana mana = new Mana(); Mana mana = new Mana();
if (game == null) { return mana; } if (game == null) {
return mana;
Choice choice = ManaType.getChoiceOfManaTypes(getManaTypes(game, source), false); }
if (choice.getChoices().isEmpty()) { return mana; }
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return mana;
}
Choice choice = ManaType.getChoiceOfManaTypes(getManaTypes(game, source), false);
if (choice.getChoices().isEmpty()) {
return mana;
}
if (choice.getChoices().size() == 1) { if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next()); choice.setChoice(choice.getChoices().iterator().next());
} else { } else {
if (player == null if (!player.choose(Outcome.PutManaInPool, choice, game)) {
|| !player.choose(Outcome.Neutral, choice, game)) {
return mana; return mana;
} }
} }
if (choice.getChoice() == null) { return mana; } if (choice.getChoice() == null) {
return mana;
}
switch (choice.getChoice()) { switch (choice.getChoice()) {
case "Black": case "Black":
@ -160,7 +166,9 @@ class BenthicExplorersManaEffect extends ManaEffect {
List<UUID> untapped = (List<UUID>) game.getState() List<UUID> untapped = (List<UUID>) game.getState()
.getValue("UntapTargetCost" + source.getSourceId().toString()); .getValue("UntapTargetCost" + source.getSourceId().toString());
Permanent land = game.getPermanentOrLKIBattlefield(untapped.get(0)); Permanent land = game.getPermanentOrLKIBattlefield(untapped.get(0));
if (land == null) { return types; } if (land == null) {
return types;
}
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : mana) { for (ActivatedManaAbilityImpl ability : mana) {

View file

@ -72,20 +72,20 @@ class BerserkReplacementEffect extends ContinuousRuleModifyingEffectImpl {
super(effect); super(effect);
} }
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.CAST_SPELL && event.getSourceId().equals(source.getSourceId())) { if (event.getSourceId().equals(source.getSourceId())) {
CombatDamageStepStartedWatcher watcher = game.getState().getWatcher(CombatDamageStepStartedWatcher.class); CombatDamageStepStartedWatcher watcher = game.getState().getWatcher(CombatDamageStepStartedWatcher.class);
return watcher == null || watcher.conditionMet(); return watcher == null || watcher.conditionMet();
} }
return false; return false;
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public BerserkReplacementEffect copy() { public BerserkReplacementEffect copy() {
return new BerserkReplacementEffect(this); return new BerserkReplacementEffect(this);

View file

@ -73,7 +73,7 @@ class BindTheMonsterEffect extends OneShotEffect {
@Override @Override
public boolean apply (Game game, Ability source) { public boolean apply (Game game, Ability source) {
Permanent attachment = source.getSourcePermanentIfItStillExists(game); Permanent attachment = source.getSourcePermanentOrLKI(game);
if (attachment != null) { if (attachment != null) {
Permanent creature = game.getPermanent(attachment.getAttachedTo()); Permanent creature = game.getPermanent(attachment.getAttachedTo());
if (creature != null) { if (creature != null) {

View file

@ -108,11 +108,6 @@ class BlindingBeamEffect2 extends ContinuousRuleModifyingEffectImpl {
return new BlindingBeamEffect2(this); return new BlindingBeamEffect2(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override @Override
public boolean isInactive(Ability source, Game game) { public boolean isInactive(Ability source, Game game) {
// the PRE step part is directly after the UNTAP events for permanents // the PRE step part is directly after the UNTAP events for permanents

View file

@ -79,9 +79,4 @@ class BloodFrenzyCastRestriction extends ContinuousRuleModifyingEffectImpl {
} }
return false; return false;
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
} }

View file

@ -1,7 +1,7 @@
package mage.cards.b; package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect; import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect;
import mage.cards.AdventureCard; import mage.cards.AdventureCard;
@ -28,11 +28,11 @@ public final class BonecrusherGiant extends AdventureCard {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller. // Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller.
this.addAbility(new SourceBecomesTargetTriggeredAbility( this.addAbility(new BecomesTargetSourceTriggeredAbility(
new DamageTargetEffect( new DamageTargetEffect(
2, true, "that spell's controller", "{this}" 2, true, "that spell's controller", "{this}"
), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER ), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER, false)
).setTriggerPhrase("Whenever {this} becomes the target of a spell, ")); .withRuleTextReplacement(false));
// Stomp // Stomp
// Damage cant be prevented this turn. Stomp deals 2 damage to any target. // Damage cant be prevented this turn. Stomp deals 2 damage to any target.

View file

@ -4,7 +4,7 @@ package mage.cards.b;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
@ -35,7 +35,7 @@ public final class BoneshardSlasher extends CardImpl {
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveyardCondition(7), new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveyardCondition(7),
"As long as seven or more cards are in your graveyard, {this} gets +2/+2")); "As long as seven or more cards are in your graveyard, {this} gets +2/+2"));
Effect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(new SourceBecomesTargetTriggeredAbility(new SacrificeSourceEffect())), Effect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(new BecomesTargetSourceTriggeredAbility(new SacrificeSourceEffect())),
new CardsInControllerGraveyardCondition(7), "and has \"When {this} becomes the target of a spell or ability, sacrifice it.\""); new CardsInControllerGraveyardCondition(7), "and has \"When {this} becomes the target of a spell or ability, sacrifice it.\"");
ability.addEffect(effect); ability.addEffect(effect);
ability.setAbilityWord(AbilityWord.THRESHOLD); ability.setAbilityWord(AbilityWord.THRESHOLD);

View file

@ -105,11 +105,6 @@ class BoseijuWhoSheltersAllCantCounterEffect extends ContinuousRuleModifyingEffe
return new BoseijuWhoSheltersAllCantCounterEffect(this); return new BoseijuWhoSheltersAllCantCounterEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);

View file

@ -119,11 +119,6 @@ class DeterminedEffect extends ContinuousRuleModifyingEffectImpl {
return new DeterminedEffect(this); return new DeterminedEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);

View file

@ -66,11 +66,6 @@ class BrandOfIllOmenEffect extends ContinuousRuleModifyingEffectImpl {
super(effect); super(effect);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public BrandOfIllOmenEffect copy() { public BrandOfIllOmenEffect copy() {
return new BrandOfIllOmenEffect(this); return new BrandOfIllOmenEffect(this);

View file

@ -106,8 +106,8 @@ class BrenardGingerSculptorEffect extends OneShotEffect {
); );
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1)); effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1));
effect.setBecomesArtifact(true); effect.setBecomesArtifact(true);
effect.setAdditionalSubType(SubType.FOOD); effect.withAdditionalSubType(SubType.FOOD);
effect.setAdditionalSubType(SubType.GOLEM); effect.withAdditionalSubType(SubType.GOLEM);
effect.addAdditionalAbilities(new FoodAbility(false)); effect.addAdditionalAbilities(new FoodAbility(false));
player.moveCards(card, Zone.EXILED, source, game); player.moveCards(card, Zone.EXILED, source, game);

View file

@ -1,19 +1,19 @@
package mage.cards.b; package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.SpellAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.DisturbAbility;
import mage.abilities.meta.OrTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.filter.FilterSpell;
import mage.game.events.GameEvent; import mage.filter.predicate.other.AuraSpellPredicate;
import mage.game.permanent.token.SpiritWhiteToken; import mage.game.permanent.token.SpiritWhiteToken;
import mage.game.stack.Spell;
import java.util.UUID; import java.util.UUID;
@ -22,6 +22,12 @@ import java.util.UUID;
*/ */
public final class BrineComber extends CardImpl { public final class BrineComber extends CardImpl {
private static final FilterSpell filter = new FilterSpell("an Aura spell");
static {
filter.add(AuraSpellPredicate.instance);
}
public BrineComber(UUID ownerId, CardSetInfo setInfo) { public BrineComber(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}");
@ -31,7 +37,10 @@ public final class BrineComber extends CardImpl {
this.secondSideCardClazz = mage.cards.b.BrineboundGift.class; this.secondSideCardClazz = mage.cards.b.BrineboundGift.class;
// Whenever Brine Comber enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. // Whenever Brine Comber enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.
this.addAbility(new BrineComberTriggeredAbility()); this.addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false,
"Whenever {this} enters the battlefield or becomes the target of an Aura spell, ",
new EntersBattlefieldTriggeredAbility(null),
new BecomesTargetSourceTriggeredAbility(null, filter)));
// Disturb {W}{U} // Disturb {W}{U}
this.addAbility(new DisturbAbility(this, "{W}{U}")); this.addAbility(new DisturbAbility(this, "{W}{U}"));
@ -46,54 +55,3 @@ public final class BrineComber extends CardImpl {
return new BrineComber(this); return new BrineComber(this);
} }
} }
class BrineComberTriggeredAbility extends TriggeredAbilityImpl {
BrineComberTriggeredAbility() {
super(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()));
}
private BrineComberTriggeredAbility(final BrineComberTriggeredAbility effect) {
super(effect);
}
@Override
public BrineComberTriggeredAbility copy() {
return new BrineComberTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|| event.getType() == GameEvent.EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
switch (event.getType()) {
case ENTERS_THE_BATTLEFIELD:
return event.getTargetId().equals(getSourceId());
case TARGETED:
break;
default:
return false;
}
if (this.getSourcePermanentIfItStillExists(game) == null
|| !event.getTargetId().equals(getSourceId())) {
return false;
}
Spell spell = game.getSpell(event.getSourceId());
if(spell == null) {
return false;
}
SpellAbility spellAbility = (SpellAbility) spell.getStackAbility();
return spellAbility != null
&& spellAbility.getCharacteristics(game).hasSubtype(SubType.AURA, game);
}
@Override
public String getRule() {
return "Whenever {this} enters the battlefield or becomes the target " +
"of an Aura spell, create a 1/1 white Spirit creature token with flying.";
}
}

View file

@ -1,23 +1,20 @@
package mage.cards.b; package mage.cards.b;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BecomesTargetAttachedTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.PutIntoGraveFromAnywhereSourceAbility; import mage.abilities.common.PutIntoGraveFromAnywhereSourceAbility;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.ExileSourceEffect; import mage.abilities.effects.common.ExileSourceEffect;
import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.EnchantAbility;
import mage.abilities.meta.OrTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Outcome; import mage.filter.FilterSpell;
import mage.constants.SubType; import mage.filter.predicate.other.AuraSpellPredicate;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.SpiritWhiteToken; import mage.game.permanent.token.SpiritWhiteToken;
import mage.game.stack.Spell;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -28,6 +25,12 @@ import java.util.UUID;
*/ */
public final class BrineboundGift extends CardImpl { public final class BrineboundGift extends CardImpl {
private static final FilterSpell filter = new FilterSpell("an Aura spell");
static {
filter.add(AuraSpellPredicate.instance);
}
public BrineboundGift(UUID ownerId, CardSetInfo setInfo) { public BrineboundGift(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "");
@ -44,7 +47,10 @@ public final class BrineboundGift extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// Whenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. // Whenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.
this.addAbility(new BrineboundGiftTriggeredAbility()); this.addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false,
"Whenever {this} enters the battlefield or enchanted creature becomes the target of an Aura spell, ",
new EntersBattlefieldTriggeredAbility(null),
new BecomesTargetAttachedTriggeredAbility(null, filter, SetTargetPointer.NONE, false)));
// If Brinebound Gift would be put into a graveyard from anywhere, exile it instead. // If Brinebound Gift would be put into a graveyard from anywhere, exile it instead.
this.addAbility(new PutIntoGraveFromAnywhereSourceAbility(new ExileSourceEffect().setText("exile it instead"))); this.addAbility(new PutIntoGraveFromAnywhereSourceAbility(new ExileSourceEffect().setText("exile it instead")));
@ -59,49 +65,3 @@ public final class BrineboundGift extends CardImpl {
return new BrineboundGift(this); return new BrineboundGift(this);
} }
} }
class BrineboundGiftTriggeredAbility extends TriggeredAbilityImpl {
BrineboundGiftTriggeredAbility() {
super(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()));
}
private BrineboundGiftTriggeredAbility(final BrineboundGiftTriggeredAbility effect) {
super(effect);
}
@Override
public BrineboundGiftTriggeredAbility copy() {
return new BrineboundGiftTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|| event.getType() == GameEvent.EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
switch (event.getType()) {
case ENTERS_THE_BATTLEFIELD:
return event.getTargetId().equals(getSourceId());
case TARGETED:
break;
default:
return false;
}
Permanent permanent = this.getSourcePermanentOrLKI(game);
if (permanent == null || !event.getTargetId().equals(permanent.getAttachedTo())) {
return false;
}
Spell spell = game.getSpell(event.getSourceId());
return spell != null && spell.hasSubtype(SubType.AURA, game);
}
@Override
public String getRule() {
return "Whenever {this} enters the battlefield or enchanted creature becomes the target " +
"of an Aura spell, create a 1/1 white Spirit creature token with flying.";
}
}

View file

@ -71,11 +71,6 @@ class BriselaVoiceOfNightmaresCantCastEffect extends ContinuousRuleModifyingEffe
return new BriselaVoiceOfNightmaresCantCastEffect(this); return new BriselaVoiceOfNightmaresCantCastEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source); MageObject mageObject = game.getObject(source);

View file

@ -0,0 +1,85 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.CascadeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.watchers.common.SpellsCastWatcher;
import java.util.UUID;
/**
* @author Susucr
*/
public final class CallForthTheTempest extends CardImpl {
private static Hint hint = new ValueHint("Total mana value of other spells you've cast this turn", CallForthTheTempestDynamicValue.instance);
public CallForthTheTempest(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{R}{R}{R}");
// Cascade
this.addAbility(new CascadeAbility(false).setRuleAtTheTop(true));
// Cascade
this.addAbility(new CascadeAbility(false).setRuleAtTheTop(true));
// Call Forth the Tempest deals damage to each creature your opponents control equal to the total mana value of other spells you've cast this turn.
this.getSpellAbility().addEffect(new DamageAllEffect(
CallForthTheTempestDynamicValue.instance,
StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE
));
this.getSpellAbility().addHint(hint);
}
private CallForthTheTempest(final CallForthTheTempest card) {
super(card);
}
@Override
public CallForthTheTempest copy() {
return new CallForthTheTempest(this);
}
}
enum CallForthTheTempestDynamicValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
if (watcher == null) {
return 0;
}
return watcher
.getSpellsCastThisTurn(sourceAbility.getControllerId())
.stream()
.filter(s -> s != null && !s.getSourceId().equals(sourceAbility.getSourceId()))
.mapToInt(s -> s.getManaValue())
.sum();
}
@Override
public CallForthTheTempestDynamicValue copy() {
return this;
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return "total mana value of other spells you've cast this turn";
}
}

View file

@ -25,8 +25,8 @@ import mage.target.common.TargetCardInLibrary;
*/ */
public final class CaptainPhasma extends CardImpl { public final class CaptainPhasma extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Nontoken trooper creatures"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken Trooper creatures");
private static final FilterCreatureCard filterCard = new FilterCreatureCard("Trooper card"); private static final FilterCreatureCard filterCard = new FilterCreatureCard("Trooper creature card");
static { static {
filter.add(SubType.TROOPER.getPredicate()); filter.add(SubType.TROOPER.getPredicate());
@ -44,11 +44,9 @@ public final class CaptainPhasma extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Nontoken Trooper creatures you control have "When this creature enters the battlefield, create 1/1/ white Trooper creature token." // Nontoken Trooper creatures you control have "When this creature enters the battlefield, create 1/1/ white Trooper creature token."
Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TrooperToken()) Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TrooperToken()), false)
.setText("When this creature enters the battlefield, create a 1/1 white Trooper creature token"), .setTriggerPhrase("When this creature enters the battlefield, ");
false, true); this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(ability, Duration.WhileOnBattlefield, filter, false)));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new GainAbilityControlledEffect(ability, Duration.WhileOnBattlefield, filter, false)));
// {W}{U}{B}{R}{G}: Search your library for a Trooper creature card, reveal it, put it into your hand, then shuffle your library. // {W}{U}{B}{R}{G}: Search your library for a Trooper creature card, reveal it, put it into your hand, then shuffle your library.
this.addAbility(new SimpleActivatedAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true), new ManaCostsImpl<>("{W}{U}{B}{R}{G}"))); this.addAbility(new SimpleActivatedAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true), new ManaCostsImpl<>("{W}{U}{B}{R}{G}")));

View file

@ -177,11 +177,6 @@ class CavernOfSoulsCantCounterEffect extends ContinuousRuleModifyingEffectImpl {
return new CavernOfSoulsCantCounterEffect(this); return new CavernOfSoulsCantCounterEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);

View file

@ -1,7 +1,7 @@
package mage.cards.c; package mage.cards.c;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.MillCardsControllerEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -22,7 +22,7 @@ public final class CephalidAristocrat extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Whenever Cephalid Aristocrat becomes the target of a spell or ability, put the top two cards of your library into your graveyard. // Whenever Cephalid Aristocrat becomes the target of a spell or ability, put the top two cards of your library into your graveyard.
this.addAbility(new SourceBecomesTargetTriggeredAbility(new MillCardsControllerEffect(2))); this.addAbility(new BecomesTargetSourceTriggeredAbility(new MillCardsControllerEffect(2)));
} }
private CephalidAristocrat(final CephalidAristocrat card) { private CephalidAristocrat(final CephalidAristocrat card) {

View file

@ -4,7 +4,7 @@ package mage.cards.c;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
@ -35,7 +35,7 @@ public final class CephalidIllusionist extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Whenever Cephalid Illusionist becomes the target of a spell or ability, put the top three cards of your library into your graveyard. // Whenever Cephalid Illusionist becomes the target of a spell or ability, put the top three cards of your library into your graveyard.
this.addAbility(new SourceBecomesTargetTriggeredAbility(new MillCardsControllerEffect(3))); this.addAbility(new BecomesTargetSourceTriggeredAbility(new MillCardsControllerEffect(3)));
// {2}{U}, {tap}: Prevent all combat damage that would be dealt to // {2}{U}, {tap}: Prevent all combat damage that would be dealt to
Effect effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, true); Effect effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, true);

View file

@ -192,7 +192,7 @@ class ChromeMoxManaEffect extends ManaEffect {
if (choice.getChoices().size() == 1) { if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next()); choice.setChoice(choice.getChoices().iterator().next());
} else { } else {
if (!player.choose(outcome, choice, game)) { if (!player.choose(Outcome.PutManaInPool, choice, game)) {
return mana; return mana;
} }
} }

View file

@ -5,6 +5,7 @@ import mage.MageInt;
import mage.Mana; import mage.Mana;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.hint.ValueHint;
import mage.abilities.mana.DynamicManaAbility; import mage.abilities.mana.DynamicManaAbility;
import mage.constants.SubType; import mage.constants.SubType;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -29,7 +30,7 @@ public final class CircleOfDreamsDruid extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// {T}: Add {G} for each creature you control. // {T}: Add {G} for each creature you control.
this.addAbility(new DynamicManaAbility(Mana.GreenMana(1), xValue)); this.addAbility(new DynamicManaAbility(Mana.GreenMana(1), xValue).addHint(new ValueHint("Creatures you control", xValue)));
} }
private CircleOfDreamsDruid(final CircleOfDreamsDruid card) { private CircleOfDreamsDruid(final CircleOfDreamsDruid card) {

View file

@ -120,10 +120,14 @@ class CircuDimirLobotomistRuleModifyingEffect extends ContinuousRuleModifyingEff
return "You can't cast this spell because a card with the same name is exiled by " + CardUtil.getSourceName(game, source) + '.'; return "You can't cast this spell because a card with the same name is exiled by " + CardUtil.getSourceName(game, source) + '.';
} }
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() != GameEvent.EventType.CAST_SPELL if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|| !game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
return false; return false;
} }
MageObject object = game.getObject(event.getSourceId()); MageObject object = game.getObject(event.getSourceId());

View file

@ -15,6 +15,7 @@ import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.TokenPredicate; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game; import mage.game.Game;
@ -22,16 +23,24 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static mage.cards.c.CityInABottle.getArabianNightsNamePredicates;
/** /**
* @author emerald000 * @author emerald000
*/ */
public final class CityInABottle extends CardImpl { public final class CityInABottle extends CardImpl {
// Arabian Nights names per CR 206.3a
static final List<NamePredicate> ARABIAN_NIGHTS_CARD_NAME_PREDICATES = new ArrayList<>();
static {
List<String> nameStrings = Arrays.asList("Abu Ja'far", "Aladdin", "Aladdin's Lamp", "Aladdin's Ring", "Ali Baba", "Ali from Cairo", "Army of Allah", "Bazaar of Baghdad", "Bird Maiden", "Bottle of Suleiman", "Brass Man", "Camel", "City in a Bottle", "City of Brass", "Cuombajj Witches", "Cyclone", "Dancing Scimitar", "Dandan", "Desert", "Desert Nomads", "Desert Twister", "Diamond Valley", "Drop of Honey", "Ebony Horse", "Elephant Graveyard", "El-Hajjaj", "Erg Raiders", "Erhnam Djinn", "Eye for an Eye", "Fishliver Oil", "Flying Carpet", "Flying Men", "Ghazban Ogre", "Giant Tortoise", "Guardian Beast", "Hasran Ogress", "Hurr Jackal", "Ifh-Biff Efreet", "Island Fish Jasconius", "Island of Wak-Wak", "Jandor's Ring", "Jandor's Saddlebags", "Jeweled Bird", "Jihad", "Junun Efreet", "Juzam Djinn", "Khabal Ghoul", "King Suleiman", "Kird Ape", "Library of Alexandria", "Magnetic Mountain", "Merchant Ship", "Metamorphosis", "Mijae Djinn", "Moorish Cavalry", "Nafs Asp", "Oasis", "Old Man of the Sea", "Oubliette", "Piety", "Pyramids", "Repentant Blacksmith", "Ring of Ma'ruf", "Rukh Egg", "Sandals of Abdallah", "Sandstorm", "Serendib Djinn", "Serendib Efreet", "Shahrazad", "Sindbad", "Singing Tree", "Sorceress Queen", "Stone-Throwing Devils", "Unstable Mutation", "War Elephant", "Wyluli Wolf", "Ydwen Efreet");
for (String name : nameStrings) {
ARABIAN_NIGHTS_CARD_NAME_PREDICATES.add(new NamePredicate(name));
}
}
public CityInABottle(UUID ownerId, CardSetInfo setInfo) { public CityInABottle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
@ -39,7 +48,7 @@ public final class CityInABottle extends CardImpl {
this.addAbility(new CityInABottleStateTriggeredAbility()); this.addAbility(new CityInABottleStateTriggeredAbility());
// Players can't play cards originally printed in the Arabian Nights expansion. // Players can't play cards originally printed in the Arabian Nights expansion.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CityInABottleCantPlayEffect())); this.addAbility(new SimpleStaticAbility(new CityInABottleCantPlayEffect()));
} }
private CityInABottle(final CityInABottle card) { private CityInABottle(final CityInABottle card) {
@ -51,100 +60,20 @@ public final class CityInABottle extends CardImpl {
return new CityInABottle(this); return new CityInABottle(this);
} }
static public List<NamePredicate> getArabianNightsNamePredicates() {
List<NamePredicate> namePredicatesArabianNights = new ArrayList<>();
namePredicatesArabianNights.add(new NamePredicate("Abu Ja'far"));
namePredicatesArabianNights.add(new NamePredicate("Aladdin"));
namePredicatesArabianNights.add(new NamePredicate("Aladdin's Lamp"));
namePredicatesArabianNights.add(new NamePredicate("Aladdin's Ring"));
namePredicatesArabianNights.add(new NamePredicate("Ali Baba"));
namePredicatesArabianNights.add(new NamePredicate("Ali from Cairo"));
namePredicatesArabianNights.add(new NamePredicate("Army of Allah"));
namePredicatesArabianNights.add(new NamePredicate("Bazaar of Baghdad"));
namePredicatesArabianNights.add(new NamePredicate("Bird Maiden"));
namePredicatesArabianNights.add(new NamePredicate("Bottle of Suleiman"));
namePredicatesArabianNights.add(new NamePredicate("Brass Man"));
namePredicatesArabianNights.add(new NamePredicate("Camel"));
namePredicatesArabianNights.add(new NamePredicate("City of Brass"));
namePredicatesArabianNights.add(new NamePredicate("Cuombajj Witches"));
namePredicatesArabianNights.add(new NamePredicate("Cyclone"));
namePredicatesArabianNights.add(new NamePredicate("Dancing Scimitar"));
namePredicatesArabianNights.add(new NamePredicate("Dandan"));
namePredicatesArabianNights.add(new NamePredicate("Desert"));
namePredicatesArabianNights.add(new NamePredicate("Desert Nomads"));
namePredicatesArabianNights.add(new NamePredicate("Desert Twister"));
namePredicatesArabianNights.add(new NamePredicate("Diamond Valley"));
namePredicatesArabianNights.add(new NamePredicate("Drop of Honey"));
namePredicatesArabianNights.add(new NamePredicate("Ebony Horse"));
namePredicatesArabianNights.add(new NamePredicate("El-Hajjaj"));
namePredicatesArabianNights.add(new NamePredicate("Elephant Graveyard"));
namePredicatesArabianNights.add(new NamePredicate("Erg Raiders"));
namePredicatesArabianNights.add(new NamePredicate("Erhnam Djinn"));
namePredicatesArabianNights.add(new NamePredicate("Eye for an Eye"));
namePredicatesArabianNights.add(new NamePredicate("Fishliver Oil"));
namePredicatesArabianNights.add(new NamePredicate("Flying Carpet"));
namePredicatesArabianNights.add(new NamePredicate("Flying Men"));
namePredicatesArabianNights.add(new NamePredicate("Ghazban Ogre"));
namePredicatesArabianNights.add(new NamePredicate("Giant Tortoise"));
namePredicatesArabianNights.add(new NamePredicate("Guardian Beast"));
namePredicatesArabianNights.add(new NamePredicate("Hasran Ogress"));
namePredicatesArabianNights.add(new NamePredicate("Hurr Jackal"));
namePredicatesArabianNights.add(new NamePredicate("Ifh-Biff Efreet"));
namePredicatesArabianNights.add(new NamePredicate("Island Fish Jasconius"));
namePredicatesArabianNights.add(new NamePredicate("Island of Wak-Wak"));
namePredicatesArabianNights.add(new NamePredicate("Jandor's Ring"));
namePredicatesArabianNights.add(new NamePredicate("Jandor's Saddlebags"));
namePredicatesArabianNights.add(new NamePredicate("Jeweled Bird"));
namePredicatesArabianNights.add(new NamePredicate("Jihad"));
namePredicatesArabianNights.add(new NamePredicate("Junun Efreet"));
namePredicatesArabianNights.add(new NamePredicate("Juzam Djinn"));
namePredicatesArabianNights.add(new NamePredicate("Khabal Ghoul"));
namePredicatesArabianNights.add(new NamePredicate("King Suleiman"));
namePredicatesArabianNights.add(new NamePredicate("Kird Ape"));
namePredicatesArabianNights.add(new NamePredicate("Library of Alexandria"));
namePredicatesArabianNights.add(new NamePredicate("Magnetic Mountain"));
namePredicatesArabianNights.add(new NamePredicate("Merchant Ship"));
namePredicatesArabianNights.add(new NamePredicate("Metamorphosis"));
namePredicatesArabianNights.add(new NamePredicate("Mijae Djinn"));
namePredicatesArabianNights.add(new NamePredicate("Moorish Cavalry"));
namePredicatesArabianNights.add(new NamePredicate("Nafs Asp"));
namePredicatesArabianNights.add(new NamePredicate("Oasis"));
namePredicatesArabianNights.add(new NamePredicate("Old Man of the Sea"));
namePredicatesArabianNights.add(new NamePredicate("Oubliette"));
namePredicatesArabianNights.add(new NamePredicate("Piety"));
namePredicatesArabianNights.add(new NamePredicate("Pyramids"));
namePredicatesArabianNights.add(new NamePredicate("Repentant Blacksmith"));
namePredicatesArabianNights.add(new NamePredicate("Ring of Ma'ruf"));
namePredicatesArabianNights.add(new NamePredicate("Rukh Egg"));
namePredicatesArabianNights.add(new NamePredicate("Sandals of Abdallah"));
namePredicatesArabianNights.add(new NamePredicate("Sandstorm"));
namePredicatesArabianNights.add(new NamePredicate("Serendib Djinn"));
namePredicatesArabianNights.add(new NamePredicate("Serendib Efreet"));
namePredicatesArabianNights.add(new NamePredicate("Shahrazad"));
namePredicatesArabianNights.add(new NamePredicate("Sindbad"));
namePredicatesArabianNights.add(new NamePredicate("Singing Tree"));
namePredicatesArabianNights.add(new NamePredicate("Sorceress Queen"));
namePredicatesArabianNights.add(new NamePredicate("Stone-Throwing Devils"));
namePredicatesArabianNights.add(new NamePredicate("Unstable Mutation"));
namePredicatesArabianNights.add(new NamePredicate("War Elephant"));
namePredicatesArabianNights.add(new NamePredicate("Wyluli Wolf"));
namePredicatesArabianNights.add(new NamePredicate("Ydwen Efreet"));
return namePredicatesArabianNights;
}
} }
class CityInABottleStateTriggeredAbility extends StateTriggeredAbility { class CityInABottleStateTriggeredAbility extends StateTriggeredAbility {
private static final FilterPermanent filter = new FilterPermanent("a nontoken permanent originally printed in the Arabian Nights expansion other than City in a Bottle"); private static final FilterPermanent filter = new FilterPermanent("other nontoken permanents with a name originally printed in the Arabian Nights expansion");
static { static {
filter.add(TokenPredicate.FALSE); filter.add(TokenPredicate.FALSE);
filter.add(Predicates.or(getArabianNightsNamePredicates())); filter.add(Predicates.or(CityInABottle.ARABIAN_NIGHTS_CARD_NAME_PREDICATES));
filter.add(AnotherPredicate.instance);
} }
CityInABottleStateTriggeredAbility() { CityInABottleStateTriggeredAbility() {
super(Zone.BATTLEFIELD, new CityInABottleSacrificeEffect()); super(Zone.BATTLEFIELD, new CityInABottleSacrificeEffect());
setTriggerPhrase("Whenever one or more other nontoken permanents with a name originally printed in the <i>Arabian Nights</i> expansion are on the battlefield, ");
} }
private CityInABottleStateTriggeredAbility(final CityInABottleStateTriggeredAbility ability) { private CityInABottleStateTriggeredAbility(final CityInABottleStateTriggeredAbility ability) {
@ -161,24 +90,21 @@ class CityInABottleStateTriggeredAbility extends StateTriggeredAbility {
return game.getBattlefield().contains(filter, this.getControllerId(), this, game, 1); return game.getBattlefield().contains(filter, this.getControllerId(), this, game, 1);
} }
@Override
public String getRule() {
return "Whenever one or more other nontoken permanents with a name originally printed in the <i>Arabian Nights</i> expansion are on the battlefield, their controllers sacrifice them";
}
} }
class CityInABottleSacrificeEffect extends OneShotEffect { class CityInABottleSacrificeEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent("a nontoken permanent originally printed in the Arabian Nights expansion other than City in a Bottle"); private static final FilterPermanent filter = new FilterPermanent("other nontoken permanents with a name originally printed in the Arabian Nights expansion");
static { static {
filter.add(TokenPredicate.FALSE); filter.add(TokenPredicate.FALSE);
filter.add(Predicates.or(getArabianNightsNamePredicates())); filter.add(Predicates.or(CityInABottle.ARABIAN_NIGHTS_CARD_NAME_PREDICATES));
filter.add(AnotherPredicate.instance);
} }
CityInABottleSacrificeEffect() { CityInABottleSacrificeEffect() {
super(Outcome.Sacrifice); super(Outcome.Sacrifice);
this.staticText = "its controller sacrifices it"; this.staticText = "their controllers sacrifice them";
} }
private CityInABottleSacrificeEffect(final CityInABottleSacrificeEffect effect) { private CityInABottleSacrificeEffect(final CityInABottleSacrificeEffect effect) {
@ -201,26 +127,21 @@ class CityInABottleSacrificeEffect extends OneShotEffect {
class CityInABottleCantPlayEffect extends ContinuousRuleModifyingEffectImpl { class CityInABottleCantPlayEffect extends ContinuousRuleModifyingEffectImpl {
private static final FilterCard filter = new FilterCard("cards originally printed in the Arabian Nights expansion"); private static final FilterCard filter = new FilterCard();
static { static {
filter.add(Predicates.or(getArabianNightsNamePredicates())); filter.add(Predicates.or(CityInABottle.ARABIAN_NIGHTS_CARD_NAME_PREDICATES));
} }
CityInABottleCantPlayEffect() { CityInABottleCantPlayEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment); super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "Players can't play cards originally printed in the <i>Arabian Nights</i> expansion"; staticText = "Players can't cast spells or play lands with a name originally printed in the <i>Arabian Nights</i> expansion";
} }
private CityInABottleCantPlayEffect(final CityInABottleCantPlayEffect effect) { private CityInABottleCantPlayEffect(final CityInABottleCantPlayEffect effect) {
super(effect); super(effect);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public CityInABottleCantPlayEffect copy() { public CityInABottleCantPlayEffect copy() {
return new CityInABottleCantPlayEffect(this); return new CityInABottleCantPlayEffect(this);
@ -228,7 +149,7 @@ class CityInABottleCantPlayEffect extends ContinuousRuleModifyingEffectImpl {
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public String getInfoMessage(Ability source, GameEvent event, Game game) {
return "You can't play cards originally printed in the Arabian Nights expansion"; return "You can't play cards with a name originally printed in the Arabian Nights expansion";
} }
@Override @Override

View file

@ -1,31 +1,35 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID; import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone; import mage.constants.SetTargetPointer;
import mage.game.Game; import mage.filter.FilterPermanent;
import mage.game.events.GameEvent; import mage.filter.StaticFilters;
import mage.game.events.GameEvent.EventType; import mage.filter.common.FilterControlledPermanent;
import mage.game.permanent.Permanent; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget; import java.util.UUID;
/** /**
* *
* @author fireshoes * @author xenohedron
*/ */
public final class CloudCover extends CardImpl { public final class CloudCover extends CardImpl {
private static final FilterPermanent filter = new FilterControlledPermanent("another permanent you control");
static {
filter.add(AnotherPredicate.instance);
}
public CloudCover(UUID ownerId, CardSetInfo setInfo) { public CloudCover(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{U}"); super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{U}");
// Whenever another permanent you control becomes the target of a spell or ability an opponent controls, you may return that permanent to its owner's hand. // Whenever another permanent you control becomes the target of a spell or ability an opponent controls, you may return that permanent to its owner's hand.
this.addAbility(new CloudCoverAbility()); this.addAbility(new BecomesTargetAnyTriggeredAbility(new ReturnToHandTargetEffect().setText("return that permanent to its owner's hand"),
filter, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.PERMANENT, true));
} }
private CloudCover(final CloudCover card) { private CloudCover(final CloudCover card) {
@ -37,44 +41,3 @@ public final class CloudCover extends CardImpl {
return new CloudCover(this); return new CloudCover(this);
} }
} }
class CloudCoverAbility extends TriggeredAbilityImpl {
public CloudCoverAbility() {
super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), true);
}
private CloudCoverAbility(final CloudCoverAbility ability) {
super(ability);
}
@Override
public CloudCoverAbility copy() {
return new CloudCoverAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
Player controller = game.getPlayer(this.getControllerId());
if (permanent != null
&& permanent.isControlledBy(getControllerId())
&& !permanent.getId().equals(this.getSourceId())
&& controller != null
&& controller.hasOpponent(event.getPlayerId(), game)) {
getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever another permanent you control becomes the target of a spell or ability an opponent controls, you may return that permanent to its owner's hand.";
}
}

View file

@ -71,8 +71,9 @@ class CloudsteelKirinEffect extends ContinuousRuleModifyingEffectImpl {
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean checksEventType(GameEvent event, Game game) {
return true; return event.getType() == GameEvent.EventType.WINS
|| event.getType() == GameEvent.EventType.LOSES;
} }
@Override @Override

View file

@ -53,24 +53,22 @@ class ConjurersBanEffect extends ContinuousRuleModifyingEffectImpl {
super(effect); super(effect);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public ConjurersBanEffect copy() { public ConjurersBanEffect copy() {
return new ConjurersBanEffect(this); return new ConjurersBanEffect(this);
} }
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL
|| event.getType() == GameEvent.EventType.PLAY_LAND;
}
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.CAST_SPELL || event.getType() == GameEvent.EventType.PLAY_LAND) { MageObject object = game.getObject(event.getSourceId());
MageObject object = game.getObject(event.getSourceId()); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); return CardUtil.haveSameNames(object, cardName, game);
return CardUtil.haveSameNames(object, cardName, game);
}
return false;
} }
@Override @Override

View file

@ -101,11 +101,6 @@ class ConquerorsFlailEffect extends ContinuousRuleModifyingEffectImpl {
return new ConquerorsFlailEffect(this); return new ConquerorsFlailEffect(this);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL; return event.getType() == GameEvent.EventType.CAST_SPELL;

View file

@ -110,11 +110,6 @@ class CorneredMarketReplacementEffect extends ContinuousRuleModifyingEffectImpl
return false; return false;
} }
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override @Override
public CorneredMarketReplacementEffect copy() { public CorneredMarketReplacementEffect copy() {
return new CorneredMarketReplacementEffect(this); return new CorneredMarketReplacementEffect(this);

View file

@ -14,6 +14,7 @@ import mage.choices.Choice;
import mage.choices.ChoiceColor; import mage.choices.ChoiceColor;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ColoredManaSymbol; import mage.constants.ColoredManaSymbol;
import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -148,7 +149,7 @@ class CorruptedGrafstoneManaEffect extends ManaEffect {
if (choice.getChoices().size() == 1) { if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next()); choice.setChoice(choice.getChoices().iterator().next());
} else { } else {
if (!player.choose(outcome, choice, game)) { if (!player.choose(Outcome.PutManaInPool, choice, game)) {
return mana; return mana;
} }
} }

View file

@ -64,11 +64,6 @@ class CouncilOfTheAbsoluteReplacementEffect extends ContinuousRuleModifyingEffec
super(effect); super(effect);
} }
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override @Override
public CouncilOfTheAbsoluteReplacementEffect copy() { public CouncilOfTheAbsoluteReplacementEffect copy() {
return new CouncilOfTheAbsoluteReplacementEffect(this); return new CouncilOfTheAbsoluteReplacementEffect(this);

View file

@ -1,21 +1,16 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID; import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent; import java.util.UUID;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
/** /**
* * @author xenohedron
* @author dustinconrad
*/ */
public final class Cowardice extends CardImpl { public final class Cowardice extends CardImpl {
@ -23,7 +18,7 @@ public final class Cowardice extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{U}"); super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{U}");
// Whenever a creature becomes the target of a spell or ability, return that creature to its owner's hand. // Whenever a creature becomes the target of a spell or ability, return that creature to its owner's hand.
this.addAbility(new CowardiceTriggeredAbility()); this.addAbility(new BecomesTargetAnyTriggeredAbility(new ReturnToHandTargetEffect(), StaticFilters.FILTER_PERMANENT_A_CREATURE));
} }
private Cowardice(final Cowardice card) { private Cowardice(final Cowardice card) {
@ -35,39 +30,3 @@ public final class Cowardice extends CardImpl {
return new Cowardice(this); return new Cowardice(this);
} }
} }
class CowardiceTriggeredAbility extends TriggeredAbilityImpl {
public CowardiceTriggeredAbility() {
super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), false);
}
private CowardiceTriggeredAbility(final CowardiceTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.isCreature(game)) {
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever a creature becomes the target of a spell or ability, return that creature to its owner's hand.";
}
@Override
public CowardiceTriggeredAbility copy() {
return new CowardiceTriggeredAbility(this);
}
}

View file

@ -13,7 +13,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
@ -57,12 +56,7 @@ enum CreatureBondValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
// In the case that the enchantment is blinked Permanent enchantment = sourceAbility.getSourcePermanentOrLKI(game);
Permanent enchantment = (Permanent) game.getLastKnownInformation(sourceAbility.getSourceId(), Zone.BATTLEFIELD);
if (enchantment == null) {
// It was not blinked, use the standard method
enchantment = game.getPermanentOrLKIBattlefield(sourceAbility.getSourceId());
}
if (enchantment == null) { if (enchantment == null) {
return 0; return 0;
} }

View file

@ -4,7 +4,7 @@ package mage.cards.c;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect;
@ -36,13 +36,13 @@ public final class CrystallineNautilus extends CardImpl {
this.addAbility(new BestowAbility(this, "{3}{U}{U}")); this.addAbility(new BestowAbility(this, "{3}{U}{U}"));
// When Crystalline Nautilus becomes the target of a spell or ability, sacrifice it. // When Crystalline Nautilus becomes the target of a spell or ability, sacrifice it.
this.addAbility(new SourceBecomesTargetTriggeredAbility(new SacrificeSourceEffect())); this.addAbility(new BecomesTargetSourceTriggeredAbility(new SacrificeSourceEffect()));
// Enchanted creature gets +4/+4 and has "When this creature becomes the target of a spell or ability, sacrifice it." // Enchanted creature gets +4/+4 and has "When this creature becomes the target of a spell or ability, sacrifice it."
Effect effect = new BoostEnchantedEffect(4,4,Duration.WhileOnBattlefield); Effect effect = new BoostEnchantedEffect(4,4,Duration.WhileOnBattlefield);
effect.setText("Enchanted creature gets +4/+4"); effect.setText("Enchanted creature gets +4/+4");
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
effect = new GainAbilityAttachedEffect(new SourceBecomesTargetTriggeredAbility(new SacrificeSourceEffect()), AttachmentType.AURA, Duration.WhileOnBattlefield); effect = new GainAbilityAttachedEffect(new BecomesTargetSourceTriggeredAbility(new SacrificeSourceEffect()), AttachmentType.AURA, Duration.WhileOnBattlefield);
effect.setText("and has \"When this creature becomes the target of a spell or ability, sacrifice it.\""); effect.setText("and has \"When this creature becomes the target of a spell or ability, sacrifice it.\"");
ability.addEffect(effect); ability.addEffect(effect);
this.addAbility(ability); this.addAbility(ability);

View file

@ -18,7 +18,6 @@ import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
import mage.abilities.common.EnchantedPlayerAttackedTriggeredAbility; import mage.abilities.common.EnchantedPlayerAttackedTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.players.Player; import mage.players.Player;
@ -71,12 +70,7 @@ class CurseOfBountyEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked Permanent enchantment = source.getSourcePermanentOrLKI(game);
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if (enchantment == null) {
// It was not blinked, use the standard method
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
}
if (enchantment != null) { if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) { if (enchantedPlayer != null) {

View file

@ -15,7 +15,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.ZombieToken; import mage.game.permanent.token.ZombieToken;
@ -72,12 +71,7 @@ class CurseOfDisturbanceEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked Permanent enchantment = source.getSourcePermanentOrLKI(game);
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if (enchantment == null) {
// It was not blinked, use the standard method
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
}
if (enchantment != null) { if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) { if (enchantedPlayer != null) {

View file

@ -19,13 +19,12 @@ import mage.watchers.common.CastSpellLastTurnWatcher;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author BetaSteward * @author BetaSteward
*/ */
public final class CurseOfExhaustion extends CardImpl { public final class CurseOfExhaustion extends CardImpl {
public CurseOfExhaustion(UUID ownerId, CardSetInfo setInfo) { public CurseOfExhaustion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
this.subtype.add(SubType.AURA, SubType.CURSE); this.subtype.add(SubType.AURA, SubType.CURSE);
@ -66,22 +65,18 @@ class CurseOfExhaustionEffect extends ContinuousRuleModifyingEffectImpl {
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean checksEventType(GameEvent event, Game game) {
return true; return event.getType() == GameEvent.EventType.CAST_SPELL;
} }
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.CAST_SPELL) { Permanent enchantment = game.getPermanent(source.getSourceId());
Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) {
if (enchantment != null && enchantment.getAttachedTo() != null) { Player player = game.getPlayer(enchantment.getAttachedTo());
Player player = game.getPlayer(enchantment.getAttachedTo()); if (player != null && event.getPlayerId().equals(player.getId())) {
if (player != null && event.getPlayerId().equals(player.getId())) { CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class);
CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > 0;
if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > 0) {
return true;
}
}
} }
} }
return false; return false;

View file

@ -22,7 +22,6 @@ import mage.target.targetpointer.FixedTarget;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.constants.Zone;
/** /**
* @author Saga * @author Saga
@ -72,12 +71,7 @@ class CurseOfOpulenceEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked Permanent enchantment = source.getSourcePermanentOrLKI(game);
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if (enchantment == null) {
// It was not blinked, use the standard method
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
}
if (enchantment == null) { if (enchantment == null) {
return false; return false;
} }

View file

@ -15,7 +15,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
@ -70,12 +69,7 @@ class CurseOfVerbosityEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked Permanent enchantment = source.getSourcePermanentOrLKI(game);
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if (enchantment == null) {
// It was not blinked, use the standard method
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
}
if (enchantment != null) { if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) { if (enchantedPlayer != null) {

View file

@ -19,7 +19,6 @@ import mage.abilities.Ability;
import mage.abilities.common.EnchantedPlayerAttackedTriggeredAbility; import mage.abilities.common.EnchantedPlayerAttackedTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeTargetEffect; import mage.abilities.effects.common.GainLifeTargetEffect;
import mage.constants.Zone;
import mage.players.Player; import mage.players.Player;
/** /**
@ -70,12 +69,7 @@ class CurseOfVitalityEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked Permanent enchantment = source.getSourcePermanentOrLKI(game);
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if (enchantment == null) {
// It was not blinked, use the standard method
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
}
if (enchantment != null) { if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) { if (enchantedPlayer != null) {

Some files were not shown because too many files have changed in this diff Show more