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);
}
// other settings
if (ClientCallback.SIMULATE_BAD_CONNECTION) {
LOGGER.info("Network: bad connection mode enabled");
}
// DATA PREPARE
RepositoryUtil.bootstrapLocalDb();
// re-create database on empty (e.g. after new build cleaned db on startup)

View file

@ -1,15 +1,16 @@
package mage.client.cards;
import mage.cards.CardDimensions;
import mage.abilities.icon.CardIconRenderSettings;
import mage.cards.CardDimensions;
import mage.cards.MageCard;
import mage.client.dialog.PreferencesDialog;
import mage.client.draft.DraftPanel;
import mage.client.plugins.impl.Plugins;
import mage.client.util.comparators.CardViewRarityComparator;
import mage.client.util.ClientEventType;
import mage.client.util.Event;
import mage.client.util.Listener;
import mage.client.util.audio.AudioManager;
import mage.client.util.comparators.CardViewRarityComparator;
import mage.constants.Constants;
import mage.view.CardView;
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 final DraftPanel parentPanel;
protected final CardEventSource cardEventSource = new CardEventSource();
protected BigCard bigCard;
protected MageCard markedCard;
@ -36,22 +39,28 @@ public class DraftGrid extends javax.swing.JPanel implements CardEventProducer {
/**
* Creates new form DraftGrid
*/
public DraftGrid() {
public DraftGrid(DraftPanel panel) {
initComponents();
parentPanel = panel;
markedCard = null;
emptyGrid = true;
// ENABLE picks and other actions
cardEventSource.addListener(new Listener<Event>() {
@Override
public void event(Event event) {
if (event.getEventType() == ClientEventType.CARD_DOUBLE_CLICK) {
CardView card = (CardView) event.getSource();
cardEventSource.addListener(event -> {
if (event.getEventType() == ClientEventType.CARD_DOUBLE_CLICK
|| event.getEventType() == ClientEventType.CARD_CLICK) {
// There is a protection against picking too early in DraftPanel logic.
// 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);
hidePopup();
AudioManager.playOnDraftSelect();
} else if (event.getEventType() == ClientEventType.CARD_CLICK) {
CardView card = (CardView) event.getSource();
} else {
MageCard cardPanel = (MageCard) event.getComponent();
if (markedCard != null) {
markedCard.setSelected(false);

View file

@ -22,11 +22,26 @@
<Layout>
<DimensionLayout dim="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"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jSeparator2" alignment="1" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" 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">
<Component id="lblMulliganType" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -35,20 +50,21 @@
<Group type="102" alignment="0" attributes="0">
<Component id="lblFreeMulligans" min="-2" 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 type="102" alignment="0" attributes="0">
<Group type="102" 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="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>
<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"/>
<Component id="btnOK" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="planechaseDescriptionLabel" alignment="0" max="32767" attributes="0"/>
<Component id="emblemCardsDescriptionLabel" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -76,6 +92,28 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="chkPlaneChase" min="-2" 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"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="btnOK" min="-2" pref="30" max="-2" attributes="0"/>
@ -173,7 +211,7 @@
</Component>
<Component class="javax.swing.JCheckBox" name="chkPlaneChase">
<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."/>
</Properties>
<AccessibilityProperties>
@ -185,6 +223,19 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkPlaneChaseActionPerformed"/>
</Events>
</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>
<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"/>
</Events>
</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>
</Form>

View file

@ -1,12 +1,21 @@
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.RangeOfInfluence;
import mage.game.GameException;
import mage.game.match.MatchOptions;
import mage.game.mulligan.MulliganType;
import org.apache.log4j.Logger;
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
@ -19,28 +28,49 @@ public class CustomOptionsDialog extends MageDialog {
TABLE(
PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS,
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(
PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS,
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 MULLIGAN_TYPE;
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;
MULLIGAN_TYPE = mulliganType;
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 final SaveLoadKeys saveLoadKeys;
private final JButton openButton;
private final JFileChooser fcSelectEmblemCardsPerPlayer;
private final JFileChooser fcSelectEmblemCardsStartingPlayer;
/**
* Creates new form NewTableDialog
@ -52,6 +82,12 @@ public class CustomOptionsDialog extends MageDialog {
this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1));
cbMulliganType.setModel(new DefaultComboBoxModel(MulliganType.values()));
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();
lblVariantOptions = new javax.swing.JLabel();
chkPlaneChase = new javax.swing.JCheckBox();
planechaseDescriptionLabel = new javax.swing.JLabel();
jSeparator4 = new javax.swing.JSeparator();
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");
@ -103,7 +149,7 @@ public class CustomOptionsDialog extends MageDialog {
lblVariantOptions.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
lblVariantOptions.setText("Variant Options");
chkPlaneChase.setText("PlaneChase");
chkPlaneChase.setText("Planechase");
chkPlaneChase.setToolTipText("Use the PlaneChase variant for your game.");
chkPlaneChase.addActionListener(new java.awt.event.ActionListener() {
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.addActionListener(new java.awt.event.ActionListener() {
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());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jSeparator2)
.addComponent(jSeparator4)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator4, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING)
.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)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cbMulliganType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGroup(layout.createSequentialGroup()
.addComponent(lblFreeMulligans)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE))
.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))
.addComponent(spnFreeMulligans))
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(btnOK)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblVariantOptions)
.addComponent(chkPlaneChase)
.addComponent(chkEmblemCards)
.addComponent(lblEmblemCardsPerPlayer)
.addComponent(lblEmblemCardsStartingPlayer)
.addComponent(lblGeneralOptions))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(planechaseDescriptionLabel)
.addComponent(emblemCardsDescriptionLabel))
.addContainerGap())
);
layout.setVerticalGroup(
@ -166,6 +273,26 @@ public class CustomOptionsDialog extends MageDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkPlaneChase)
.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)
.addGap(0, 0, 0)
.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().setAccessibleParent(lblFreeMulligans);
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();
}// </editor-fold>//GEN-END:initComponents
@ -205,10 +340,50 @@ public class CustomOptionsDialog extends MageDialog {
updateActiveCount();
}//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() {
this.setLocation(150, 100);
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) {
@ -231,6 +406,9 @@ public class CustomOptionsDialog extends MageDialog {
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.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();
}
@ -250,6 +428,10 @@ public class CustomOptionsDialog extends MageDialog {
PreferencesDialog.saveValue(saveLoadKeys.NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(options.getFreeMulligans()));
PreferencesDialog.saveValue(saveLoadKeys.MULLIGAN_TYPE + versionStr, options.getMulliganType().toString());
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.setMullgianType((MulliganType) cbMulliganType.getSelectedItem());
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() {
@ -266,6 +484,7 @@ public class CustomOptionsDialog extends MageDialog {
if ((Integer)spnFreeMulligans.getValue() > 0) activeCount++;
if (!cbMulliganType.getSelectedItem().toString().equals(MulliganType.GAME_DEFAULT.toString())) activeCount++;
if (chkPlaneChase.isSelected()) activeCount++;
if (chkEmblemCards.isSelected()) activeCount++;
if (activeCount == 0) {
openButton.setText("Custom Options...");
}
@ -275,15 +494,25 @@ public class CustomOptionsDialog extends MageDialog {
}
// 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.JComboBox<String> cbMulliganType;
private javax.swing.JCheckBox chkEmblemCards;
private javax.swing.JCheckBox chkPlaneChase;
private javax.swing.JLabel emblemCardsDescriptionLabel;
private javax.swing.JSeparator jSeparator2;
private javax.swing.JSeparator jSeparator3;
private javax.swing.JSeparator jSeparator4;
private javax.swing.JLabel lblEmblemCardsPerPlayer;
private javax.swing.JLabel lblEmblemCardsStartingPlayer;
private javax.swing.JLabel lblFreeMulligans;
private javax.swing.JLabel lblGeneralOptions;
private javax.swing.JLabel lblMulliganType;
private javax.swing.JLabel lblVariantOptions;
private javax.swing.JLabel planechaseDescriptionLabel;
private javax.swing.JSpinner spnFreeMulligans;
private javax.swing.JTextField txtEmblemCardsPerPlayer;
private javax.swing.JTextField txtEmblemCardsStartingPlayer;
// End of variables declaration//GEN-END:variables
}

View file

@ -45,7 +45,7 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="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"/>
<Group type="103" groupAlignment="3" 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">
<Properties>
<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."/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="cbDraftLogAutoSave">
<Properties>
<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="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/>
@ -151,13 +151,13 @@
<Component class="javax.swing.JCheckBox" name="cbLimitedDeckAutoSave">
<Properties>
<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."/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="cbGameJsonLogAutoSave">
<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."/>
</Properties>
</Component>
@ -280,27 +280,25 @@
<Layout>
<DimensionLayout dim="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"/>
<Group type="102" 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"/>
<Group type="103" alignment="0" groupAlignment="0" max="-2" attributes="0">
<Component id="showPlayerNamesPermanently" 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="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"/>
</Group>
</Group>
<EmptySpace min="0" pref="315" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -317,8 +315,6 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="cbAllowRequestToShowHandCards" min="-2" 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"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbAskMoveToGraveOrder" min="-2" max="-2" attributes="0"/>
@ -341,9 +337,6 @@
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="nonLandPermanentsInOnePile"/>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="nonLandPermanentsInOnePileActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="showPlayerNamesPermanently">
<Properties>
@ -351,9 +344,6 @@
<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."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showPlayerNamesPermanentlyActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="displayLifeOnAvatar">
<Properties>
@ -361,9 +351,6 @@
<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."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="displayLifeOnAvatarActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="showAbilityPickerForced">
<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="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>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showAbilityPickerForcedActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbAllowRequestToShowHandCards">
<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="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>
<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 class="javax.swing.JCheckBox" name="cbConfirmEmptyManaPool">
<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="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>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbConfirmEmptyManaPoolActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbAskMoveToGraveOrder">
<Properties>
@ -411,9 +379,6 @@
<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."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbAskMoveToGraveOrderActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblTargetAutoChoose">
<Properties>
@ -438,9 +403,6 @@
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Auto-choose targets for player combo box"/>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbTargetAutoChooseLevelActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
@ -4237,9 +4199,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopAttackActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithAny">
<Properties>
@ -4248,9 +4207,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockWithAnyActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithZero">
<Properties>
@ -4258,9 +4214,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopBlockWithZeroActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnNewStackObjects">
<Properties>
@ -4271,9 +4224,6 @@
<Dimension value="[300, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopOnNewStackObjectsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnAllMain">
<Properties>
@ -4281,9 +4231,6 @@
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="actionCommand" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopOnAllMainActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbStopOnAllEnd">
<Properties>
@ -4294,9 +4241,6 @@
<Dimension value="[300, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbStopOnAllEndActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbPassPriorityCast">
<Properties>
@ -4307,9 +4251,6 @@
<Dimension value="[300, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbPassPriorityCastActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbPassPriorityActivation">
<Properties>
@ -4320,9 +4261,6 @@
<Dimension value="[300, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbPassPriorityActivationActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbAutoOrderTrigger">
<Properties>
@ -4333,9 +4271,6 @@
<Dimension value="[300, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbAutoOrderTriggerActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbUseSameSettingsForReplacementEffect">
<Properties>
@ -4346,9 +4281,6 @@
<Dimension value="[300, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbUseSameSettingsForReplacementEffectActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
@ -4668,9 +4600,6 @@
</Events>
</Component>
<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 class="javax.swing.JButton" name="btnBrowseBackgroundImage">
<Properties>
@ -4681,9 +4610,6 @@
</Events>
</Component>
<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 class="javax.swing.JButton" name="btnBrowseBattlefieldImage">
<Properties>
@ -4774,36 +4700,24 @@
<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."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableGameSoundsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbEnableDraftSounds">
<Properties>
<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."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableDraftSoundsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbEnableSkipButtonsSounds">
<Properties>
<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."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableSkipButtonsSoundsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbEnableOtherSounds">
<Properties>
<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 ...)."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbEnableOtherSoundsActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
@ -4869,9 +4783,6 @@
</Properties>
</Component>
<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 class="javax.swing.JButton" name="btnBattlefieldBGMBrowse">
<Properties>
@ -5993,9 +5904,6 @@
</Properties>
</Component>
<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 class="javax.swing.JLabel" name="lblProxyUserName">
<Properties>
@ -6010,17 +5918,11 @@
</Properties>
</Component>
<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 class="javax.swing.JCheckBox" name="rememberPswd">
<Properties>
<Property name="text" type="java.lang.String" value="Remember Password"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="rememberPswdActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabel11">
<Properties>
@ -6330,7 +6232,7 @@
<Layout>
<DimensionLayout dim="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="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
@ -6378,7 +6280,7 @@
<Component id="lbThemeHint" min="-2" max="-2" attributes="0"/>
<Component id="cbTheme" min="-2" pref="303" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="303" max="32767" attributes="0"/>
<EmptySpace pref="360" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -6410,9 +6312,6 @@
</Properties>
</Component>
<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>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ThemeType&gt;"/>
</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_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker";
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_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder";
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_RATED = "newTableRated";
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
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_MINIMUM_RATING = "newTournamentMinimumRating";
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
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();
showAbilityPickerForced = new javax.swing.JCheckBox();
cbAllowRequestToShowHandCards = new javax.swing.JCheckBox();
cbShowStormCounter = new javax.swing.JCheckBox();
cbConfirmEmptyManaPool = new javax.swing.JCheckBox();
cbAskMoveToGraveOrder = new javax.swing.JCheckBox();
lblTargetAutoChoose = new javax.swing.JLabel();
@ -644,22 +648,22 @@ public class PreferencesDialog extends javax.swing.JDialog {
main_gamelog.add(cbGameLogShowTurnInfo);
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.");
main_gamelog.add(cbGameLogAutoSave);
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.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
main_gamelog.add(cbDraftLogAutoSave);
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.");
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.");
main_gamelog.add(cbGameJsonLogAutoSave);
@ -733,74 +737,30 @@ public class PreferencesDialog extends javax.swing.JDialog {
nonLandPermanentsInOnePile.setSelected(true);
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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
nonLandPermanentsInOnePileActionPerformed(evt);
}
});
showPlayerNamesPermanently.setSelected(true);
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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showPlayerNamesPermanentlyActionPerformed(evt);
}
});
displayLifeOnAvatar.setSelected(true);
displayLifeOnAvatar.setText("Display life on 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.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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showAbilityPickerForcedActionPerformed(evt);
}
});
cbAllowRequestToShowHandCards.setSelected(true);
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.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.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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbConfirmEmptyManaPoolActionPerformed(evt);
}
});
cbAskMoveToGraveOrder.setSelected(true);
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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbAskMoveToGraveOrderActionPerformed(evt);
}
});
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.");
@ -808,34 +768,27 @@ public class PreferencesDialog extends javax.swing.JDialog {
cbTargetAutoChooseLevel.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Off", "Most", "All" }));
cbTargetAutoChooseLevel.setSelectedIndex(1);
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);
main_game.setLayout(main_gameLayout);
main_gameLayout.setHorizontalGroup(
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(main_gameLayout.createSequentialGroup()
.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(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(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(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(0, 315, Short.MAX_VALUE))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
main_gameLayout.setVerticalGroup(
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)
.add(cbAllowRequestToShowHandCards)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbShowStormCounter)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbConfirmEmptyManaPool)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.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.setToolTipText("");
cbStopAttack.setActionCommand("");
cbStopAttack.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopAttackActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopAttack);
cbStopBlockWithAny.setSelected(true);
cbStopBlockWithAny.setText("STOP skips on declare blockers if ANY blockers are available");
cbStopBlockWithAny.setToolTipText("");
cbStopBlockWithAny.setActionCommand("");
cbStopBlockWithAny.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopBlockWithAnyActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopBlockWithAny);
cbStopBlockWithZero.setText("STOP skips on declare blockers if ZERO blockers are available");
cbStopBlockWithZero.setToolTipText("");
cbStopBlockWithZero.setActionCommand("");
cbStopBlockWithZero.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopBlockWithZeroActionPerformed(evt);
}
});
phases_stopSettings.add(cbStopBlockWithZero);
cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)");
cbStopOnNewStackObjects.setToolTipText("");
cbStopOnNewStackObjects.setActionCommand("");
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);
cbStopOnAllMain.setText("Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)");
cbStopOnAllMain.setToolTipText("");
cbStopOnAllMain.setActionCommand("");
cbStopOnAllMain.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbStopOnAllMainActionPerformed(evt);
}
});
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.setToolTipText("");
cbStopOnAllEnd.setActionCommand("");
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);
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.setActionCommand("");
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);
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.setActionCommand("");
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);
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.setActionCommand("");
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);
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.setActionCommand("");
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);
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.addActionListener(new java.awt.event.ActionListener() {
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.addActionListener(new java.awt.event.ActionListener() {
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.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);
cbEnableDraftSounds.setText("Enable draft sounds");
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);
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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbEnableSkipButtonsSoundsActionPerformed(evt);
}
});
sounds_clips.add(cbEnableSkipButtonsSounds);
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.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbEnableOtherSoundsActionPerformed(evt);
}
});
sounds_clips.add(cbEnableOtherSounds);
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.setToolTipText("");
txtBattlefieldIBGMPath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtBattlefieldIBGMPathActionPerformed(evt);
}
});
btnBattlefieldBGMBrowse.setText("Browse...");
btnBattlefieldBGMBrowse.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -2518,28 +2381,11 @@ public class PreferencesDialog extends javax.swing.JDialog {
lblProxyPort.setText("Port:");
txtProxyPort.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
txtProxyPortkeyTyped(evt);
}
});
lblProxyUserName.setText("User Name:");
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.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.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.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.");
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(lbThemeHint)
.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.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -2840,7 +2680,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
tabThemes.setLayout(tabThemesLayout);
tabThemesLayout.setHorizontalGroup(
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.createSequentialGroup()
.addContainerGap()
@ -2897,7 +2737,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.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)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.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.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.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.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);
@ -3097,19 +2936,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
this.showProxySettings();
}//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
if (cbEnableBattlefieldBGM.isSelected()) {
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
// TODO add your handling code here:
int returnVal = fc.showOpenDialog(PreferencesDialog.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
@ -3227,78 +3040,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
}
}//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
}//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
getKeybindButtons().forEach((bttn) -> {
String id = bttn.getKey();
@ -3316,18 +3061,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
}//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
// TODO add your handling code here:
}//GEN-LAST:event_cbSaveToZipFilesActionPerformed
@ -3349,10 +3082,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
}
}//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
// This prevents this event from firing during the initial
// setting of the sliders from pref values
@ -3362,14 +3091,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
}
}//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() {
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
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.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "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.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<ProxyType> cbProxyType;
private javax.swing.JCheckBox cbSaveToZipFiles;
private javax.swing.JCheckBox cbShowStormCounter;
private javax.swing.JCheckBox cbStopAttack;
private javax.swing.JCheckBox cbStopBlockWithAny;
private javax.swing.JCheckBox cbStopBlockWithZero;

View file

@ -19,7 +19,7 @@
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
*/

View file

@ -19,7 +19,6 @@
import javax.swing.Timer;
import javax.swing.*;
import java.awt.*;
import java.awt.dnd.DragSourceEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
@ -42,6 +41,20 @@
private Timer countdown;
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
private final JPopupMenu popupMenuPickedArea;
// popup menu for a card
@ -108,6 +121,8 @@
}
}
);
protectionTimer = new Timer(protectionTime, e -> protectionTimer.stop());
}
public void cleanUp() {
@ -120,6 +135,13 @@
countdown.removeActionListener(al);
}
}
if (protectionTimer != null) {
protectionTimer.stop();
for (ActionListener al : protectionTimer.getActionListeners()) {
protectionTimer.removeActionListener(al);
}
}
}
public void changeGUISize() {
@ -311,7 +333,13 @@
}
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() {
Component c = this.getParent();
while (c != null && !(c instanceof DraftPane)) {
@ -417,7 +449,7 @@
// that's why instead of proactively logging our pick we instead
// log *last* pick from the list of picks.
// 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.
private void logLastPick(DraftPickView pickView) {
if (!isLogging()) {
@ -438,11 +470,13 @@
private String getCurrentSetCode() {
// TODO: Record set codes for random drafts correctly
if (setCodes.size() >= packNo) {
return setCodes.get(packNo - 1);
} else {
return " ";
if (setCodes != null && setCodes.size() >= packNo) {
String setCode = setCodes.get(packNo - 1);
if (setCode != null) { // Not sure how, but got a NPE from this method P1P2 in a ZEN/ZEN/WWK draft
return setCode;
}
}
return " ";
}
private static boolean isLogging() {
@ -525,7 +559,7 @@
lblPlayer15 = new javax.swing.JLabel();
lblPlayer16 = new javax.swing.JLabel();
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.setFocusable(false);

View file

@ -38,7 +38,6 @@ public class FeedbackPanel extends javax.swing.JPanel {
private FeedbackMode mode;
private MageDialog connectedDialog;
private ChatPanelBasic connectedChatPanel;
private int lastMessageId;
private Map<String, Serializable> lastOptions = new HashMap<>();
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,
int messageId, boolean gameNeedUserFeedback, TurnPhase gameTurnPhase) {
boolean gameNeedUserFeedback, TurnPhase gameTurnPhase) {
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.mode = mode;
}

View file

@ -14,6 +14,7 @@ import mage.client.components.KeyboundButton;
import mage.client.components.MageComponents;
import mage.client.components.ext.dlg.DialogManager;
import mage.client.components.layout.RelativeLayout;
import mage.client.components.tray.MageTray;
import mage.client.dialog.*;
import mage.client.dialog.CardInfoWindowDialog.ShowType;
import mage.client.game.FeedbackPanel.FeedbackMode;
@ -122,8 +123,8 @@ public final class GamePanel extends javax.swing.JPanel {
private JPopupMenu popupMenuTriggerOrder;
// 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 {
int messageId;
GameView game;
boolean showPlayable;
Map<String, Serializable> options;
@ -366,7 +367,6 @@ public final class GamePanel extends javax.swing.JPanel {
jSplitPane1.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()));
GUISizeHelper.changePopupMenuFont(popupMenuTriggerOrder);
@ -390,6 +390,7 @@ public final class GamePanel extends javax.swing.JPanel {
stackObjects.setPreferredSize(newDimension);
stackObjects.setMinimumSize(newDimension);
stackObjects.setMaximumSize(newDimension);
stackObjects.changeGUISize(); // must call to cards fit
newDimension = new Dimension(newStackWidth, (int) pnlShortCuts.getPreferredSize().getHeight());
pnlShortCuts.setPreferredSize(newDimension);
@ -501,6 +502,10 @@ public final class GamePanel extends javax.swing.JPanel {
} else {
// play start sound
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);
// default menu states
setMenuStates(
@ -581,7 +586,7 @@ public final class GamePanel extends javax.swing.JPanel {
holdingPriority
);
updateGame(game);
updateGame(messageId, game);
}
private void addPlayers(GameView game) {
@ -706,12 +711,12 @@ public final class GamePanel extends javax.swing.JPanel {
*/
}
public synchronized void updateGame(GameView game) {
updateGame(game, false, null, null);
public synchronized void updateGame(int messageId, GameView game) {
updateGame(messageId, game, false, null, null);
}
public synchronized void updateGame(GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) {
keepLastGameData(game, showPlayable, options, targets);
public synchronized void updateGame(int messageId, GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) {
keepLastGameData(messageId, game, showPlayable, options, targets);
prepareSelectableView();
updateGame();
}
@ -777,12 +782,6 @@ public final class GamePanel extends javax.swing.JPanel {
logger.debug("Step is empty");
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.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.updateOptions(lastGameData.options);
@ -1361,12 +1361,13 @@ public final class GamePanel extends javax.swing.JPanel {
windowMap.entrySet().removeIf(entry -> entry.getValue().isClosed());
}
public void ask(String question, GameView gameView, int messageId, Map<String, Serializable> options) {
updateGame(gameView, false, options, null);
this.feedbackPanel.prepareFeedback(FeedbackMode.QUESTION, question, false, options, messageId, true, gameView.getPhase());
public void ask(int messageId, GameView gameView, String question, Map<String, Serializable> options) {
updateGame(messageId, gameView, false, options, null);
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.showPlayable = showPlayable;
lastGameData.options = options;
@ -1623,8 +1624,8 @@ public final class GamePanel extends javax.swing.JPanel {
* @param options
* @param messageId
*/
public void pickTarget(GameView gameView, Map<String, Serializable> options, String message, CardsView cardsView, Set<UUID> targets, boolean required, int messageId) {
updateGame(gameView, false, options, targets);
public void pickTarget(int messageId, GameView gameView, Map<String, Serializable> options, String message, CardsView cardsView, Set<UUID> targets, boolean required) {
updateGame(messageId, gameView, false, options, targets);
hideAll();
DialogManager.getManager(gameId).fadeOut();
clearPickTargetDialogs();
@ -1652,28 +1653,28 @@ public final class GamePanel extends javax.swing.JPanel {
dialog = prepareCardsDialog(message, cardsView, required, options0, popupMenuType);
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) {
this.pickTarget.add(dialog);
}
}
public void inform(String information, GameView gameView, int messageId) {
updateGame(gameView);
this.feedbackPanel.prepareFeedback(FeedbackMode.INFORM, information, gameView.getSpecial(), null, messageId, false, gameView.getPhase());
public void inform(int messageId, GameView gameView, String information) {
updateGame(messageId, gameView);
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) {
updateGame(gameView, false, options, null);
public void endMessage(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(messageId, gameView, false, options, null);
hideAll();
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);
}
public void select(GameView gameView, Map<String, Serializable> options, String message, int messageId) {
updateGame(gameView, true, options, null);
public void select(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(messageId, gameView, true, options, null);
hideAll();
DialogManager.getManager(gameId).fadeOut();
@ -1716,31 +1717,31 @@ public final class GamePanel extends javax.swing.JPanel {
priorityPlayerText = " / priority " + gameView.getPriorityPlayerName();
}
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) {
updateGame(gameView, true, options, null);
public void playMana(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(messageId, gameView, true, options, null);
hideAll();
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) {
updateGame(gameView, true, options, null);
public void playXMana(int messageId, GameView gameView, Map<String, Serializable> options, String message) {
updateGame(messageId, gameView, true, options, null);
hideAll();
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) {
//TODO: implement this
}
public void pickAbility(GameView gameView, Map<String, Serializable> options, AbilityPickerView choices) {
updateGame(gameView, false, options, null);
public void pickAbility(int messageId, GameView gameView, Map<String, Serializable> options, AbilityPickerView choices) {
updateGame(messageId, gameView, false, options, null);
hideAll();
DialogManager.getManager(gameId).fadeOut();
@ -1764,8 +1765,8 @@ public final class GamePanel extends javax.swing.JPanel {
return showCards;
}
public void getAmount(GameView gameView, Map<String, Serializable> options, int min, int max, String message) {
updateGame(gameView, false, options, null);
public void getAmount(int messageId, GameView gameView, Map<String, Serializable> options, int min, int max, String message) {
updateGame(messageId, gameView, false, options, null);
hideAll();
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) {
updateGame(gameView, false, options, null);
updateGame(messageId, gameView, false, options, null);
hideAll();
DialogManager.getManager(gameId).fadeOut();
@ -1787,8 +1788,8 @@ public final class GamePanel extends javax.swing.JPanel {
SessionHandler.sendPlayerString(gameId, pickMultiNumber.getMultiAmount());
}
public void getChoice(GameView gameView, Map<String, Serializable> options, Choice choice, UUID objectId) {
updateGame(gameView, false, options, null);
public void getChoice(int messageId, GameView gameView, Map<String, Serializable> options, Choice choice, UUID objectId) {
updateGame(messageId, gameView, false, options, null);
hideAll();
DialogManager.getManager(gameId).fadeOut();
@ -1813,8 +1814,8 @@ public final class GamePanel extends javax.swing.JPanel {
pickChoice.removeDialog();
}
public void pickPile(GameView gameView, Map<String, Serializable> options, String message, CardsView pile1, CardsView pile2) {
updateGame(gameView, false, options, null);
public void pickPile(int messageId, GameView gameView, Map<String, Serializable> options, String message, CardsView pile1, CardsView pile2) {
updateGame(messageId, gameView, false, options, null);
hideAll();
DialogManager.getManager(gameId).fadeOut();
@ -1856,14 +1857,8 @@ public final class GamePanel extends javax.swing.JPanel {
lblPriority = new javax.swing.JLabel();
feedbackPanel = new mage.client.game.FeedbackPanel();
txtSpellsCast = new javax.swing.JLabel();
Border paddingBorder = BorderFactory.createEmptyBorder(4, 4, 4, 4);
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.setText("Hold");
txtHoldPriority.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder));
@ -2336,7 +2331,6 @@ public final class GamePanel extends javax.swing.JPanel {
)
.addGroup(gl_pnlShortCuts.createSequentialGroup()
.addComponent(txtHoldPriority)
.addComponent(txtSpellsCast)
/*.addComponent(btnToggleMacro)*/
.addComponent(btnSwitchHands)
.addComponent(btnCancelSkip)
@ -2372,7 +2366,6 @@ public final class GamePanel extends javax.swing.JPanel {
.addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
/*.addComponent(btnToggleMacro)*/
.addComponent(txtHoldPriority)
.addComponent(txtSpellsCast)
.addComponent(btnSwitchHands)
.addComponent(btnCancelSkip)
.addComponent(btnConcede)
@ -2808,6 +2801,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (!cardViewPopupMenu.getAbility().getRules().isEmpty()
&& !cardViewPopupMenu.getAbility().getRules().get(0).isEmpty()) {
abilityRuleText = cardViewPopupMenu.getAbility().getRules().get(0);
abilityRuleText = abilityRuleText.replace("{this}", cardViewPopupMenu.getName());
}
}
switch (e.getActionCommand()) {
@ -3001,7 +2995,6 @@ public final class GamePanel extends javax.swing.JPanel {
private javax.swing.JSplitPane jSplitPane2;
private JPanel jPhases;
private JPanel phasesContainer;
private javax.swing.JLabel txtSpellsCast;
private javax.swing.JLabel txtHoldPriority;
private HoverButton currentStep;

View file

@ -105,12 +105,20 @@ public class PlayerPanelExt extends javax.swing.JPanel {
timer.setTaskOnTick(() -> {
int priorityTimeValue = pt.getCount() + pt.getBufferCount();
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.setTopTextColor(pt.getBufferCount() > 0 ? Color.GREEN : null);
PlayerPanelExt.this.avatar.setTopTextColor(textColor);
PlayerPanelExt.this.timerLabel.setText(text);
PlayerPanelExt.this.timerLabel
.setForeground(pt.getBufferCount() > 0 ? Color.GREEN.darker().darker() : Color.BLACK);
PlayerPanelExt.this.timerLabel.setForeground(foregroundColor);
PlayerPanelExt.this.avatar.repaint();
});
timer.init(gameId);
@ -195,10 +203,10 @@ public class PlayerPanelExt extends javax.swing.JPanel {
if (playerLife != pastLife) {
if (playerLife > pastLife) {
avatar.gainLifeDisplay();
} else if (playerLife < pastLife) {
} else {
avatar.loseLifeDisplay();
}
} else if (playerLife == pastLife) {
} else {
avatar.stopLifeDisplay();
}
}
@ -311,10 +319,18 @@ public class PlayerPanelExt extends javax.swing.JPanel {
this.timer.setBufferCount(player.getBufferTimeLeft());
this.avatar.setTopText(priorityTimeValue);
this.timerLabel.setText(priorityTimeValue);
this.avatar.setTopTextColor(player.getBufferTimeLeft() > 0 ? Color.GREEN : null);
this.timerLabel
.setForeground(player.getBufferTimeLeft() > 0 ? Color.GREEN.darker().darker() : Color.BLACK);
// Set timer text colors (note, if you change it here, change it in init()::timer.setTaskOnTick() as well)
Color textColor = null; // use default in HoverButton
Color foregroundColor = 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()) {
this.timer.resume();
@ -360,25 +376,17 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private void updateAvatar() {
if (flagName == null) { // do only once
avatar.setText(this.player.getName());
if (!player.getUserData().getFlagName().equals(flagName)) {
flagName = player.getUserData().getFlagName();
this.avatar.setTopTextImage(CountryUtil.getCountryFlagIconSize(flagName, 11).getImage());
}
// TODO: Add the wins to the tooltiptext of the avatar
String countryname = CountryUtil.getCountryName(flagName);
if (countryname == null) {
countryname = "Unknown";
}
flagName = player.getUserData().getFlagName();
this.avatar.setTopTextImage(CountryUtil.getCountryFlagIconSize(flagName, 11).getImage());
String countryName = CountryUtil.getCountryName(flagName);
basicTooltipText = "<HTML>Name: " + player.getName()
+ "<br/>Flag: " + countryname
+ "<br/>Constructed rating: " + player.getUserData().getConstructedRating()
+ "<br/>Limited rating: " + player.getUserData().getLimitedRating()
+ "<br/>Flag: " + (countryName == null ? "Unknown" : countryName)
+ "<br/>Deck hash code: " + player.getDeckHashCode()
+ "<br/>This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)"
+ (player.getUserData() == null ? "" : "<br/>History: " + player.getUserData().getHistory());
+ "<br/>This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)";
}
// Extend tooltip
StringBuilder tooltipText = new StringBuilder(basicTooltipText);
tooltipText.append("<br/>Match time remaining: ").append(getPriorityTimeLeftString(player));
this.avatar.setTopTextImageRight(null);
for (String name : player.getDesignationNames()) {
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.interfaces.callback.CallbackClient;
import mage.interfaces.callback.ClientCallback;
import mage.interfaces.callback.ClientCallbackType;
import mage.remote.ActionData;
import mage.remote.Session;
import mage.view.*;
@ -24,8 +25,7 @@ import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.UUID;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com
@ -34,38 +34,76 @@ public class CallbackClientImpl implements CallbackClient {
private static final Logger logger = Logger.getLogger(CallbackClientImpl.class);
private final MageFrame frame;
private int messageId = 0;
private int gameInformMessageId = 0;
private final Map<ClientCallbackType, Integer> lastMessages;
public CallbackClientImpl(MageFrame frame) {
this.frame = frame;
this.lastMessages = new HashMap<>();
Arrays.stream(ClientCallbackType.values()).forEach(t -> this.lastMessages.put(t, 0));
}
@Override
public synchronized void processCallback(final ClientCallback callback) {
callback.decompressData();
// put replay related code here
SaveObjectUtil.saveObject(callback.getData(), callback.getMethod().toString());
// all GUI related code must be executed in swing thread
SwingUtilities.invokeLater(() -> {
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()) {
case START_GAME: {
TableClientMessage message = (TableClientMessage) callback.getData();
GameManager.instance.setCurrentPlayerUUID(message.getPlayerId());
gameStarted(message.getGameId(), message.getPlayerId());
gameStarted(callback.getMessageId(), message.getGameId(), message.getPlayerId());
break;
}
case START_TOURNAMENT: {
TableClientMessage message = (TableClientMessage) callback.getData();
tournamentStarted(message.getGameId(), message.getPlayerId());
tournamentStarted(callback.getMessageId(), message.getGameId(), message.getPlayerId());
break;
}
case START_DRAFT: {
TableClientMessage message = (TableClientMessage) callback.getData();
draftStarted(message.getGameId(), message.getPlayerId());
draftStarted(callback.getMessageId(), message.getGameId(), message.getPlayerId());
break;
}
@ -149,7 +187,7 @@ public class CallbackClientImpl implements CallbackClient {
case REPLAY_INIT: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
panel.init((GameView) callback.getData());
panel.init(callback.getMessageId(), (GameView) callback.getData());
}
break;
}
@ -157,7 +195,7 @@ public class CallbackClientImpl implements CallbackClient {
case REPLAY_DONE: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
panel.endMessage(null, null, (String) callback.getData(), callback.getMessageId());
panel.endMessage(callback.getMessageId(), null, null, (String) callback.getData());
}
break;
}
@ -165,7 +203,7 @@ public class CallbackClientImpl implements CallbackClient {
case REPLAY_UPDATE: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
panel.updateGame((GameView) callback.getData());
panel.updateGame(callback.getMessageId(), (GameView) callback.getData());
}
break;
}
@ -174,7 +212,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_INIT", callback.getObjectId(), callback.getData());
panel.init((GameView) callback.getData());
panel.init(callback.getMessageId(), (GameView) callback.getData());
}
break;
}
@ -190,7 +228,7 @@ public class CallbackClientImpl implements CallbackClient {
String logFileName = "game-" + gameId + ".json";
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;
}
@ -205,7 +243,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -216,8 +254,8 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_TARGET", callback.getObjectId(), message);
panel.pickTarget(message.getGameView(), message.getOptions(), message.getMessage(),
message.getCardsView1(), message.getTargets(), message.isFlag(), callback.getMessageId());
panel.pickTarget(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMessage(),
message.getCardsView1(), message.getTargets(), message.isFlag());
}
break;
}
@ -227,7 +265,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -237,7 +275,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_CHOOSE_ABILITY", callback.getObjectId(), callback.getData());
panel.pickAbility(abilityPickerView.getGameView(), null, abilityPickerView);
panel.pickAbility(callback.getMessageId(), abilityPickerView.getGameView(), null, abilityPickerView);
}
break;
}
@ -247,7 +285,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -257,7 +295,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -267,7 +305,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -277,7 +315,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -287,8 +325,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message);
panel.getAmount(message.getGameView(), message.getOptions(), message.getMin(), message.getMax(), message.getMessage());
panel.getAmount(callback.getMessageId(), message.getGameView(), message.getOptions(), message.getMin(), message.getMax(), message.getMessage());
}
break;
}
@ -298,8 +335,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_GET_MULTI_AMOUNT", callback.getObjectId(), message);
panel.getMultiAmount(message.getMessages(), message.getGameView(), message.getOptions(), message.getMin(), message.getMax());
panel.getMultiAmount(callback.getMessageId(), message.getGameView(), message.getMessages(), message.getOptions(), message.getMin(), message.getMax());
}
break;
}
@ -308,7 +344,7 @@ public class CallbackClientImpl implements CallbackClient {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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;
}
@ -336,21 +372,13 @@ public class CallbackClientImpl implements CallbackClient {
break;
}
case GAME_INFORM: {
if (callback.getMessageId() > gameInformMessageId) {
{
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
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()));
case GAME_UPDATE_AND_INFORM: {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_INFORM", callback.getObjectId(), message);
panel.inform(callback.getMessageId(), message.getGameView(), message.getMessage());
}
gameInformMessageId = messageId;
break;
}
@ -432,14 +460,10 @@ public class CallbackClientImpl implements CallbackClient {
}
default: {
// TODO: add exception here and process miss events like TOURNAMENT_UPDATE
break;
}
}
// sync message for server side events only
if (!callback.getMethod().isClientSideMessage()) {
messageId = callback.getMessageId();
}
} catch (Exception ex) {
handleException(ex);
}
@ -466,50 +490,50 @@ public class CallbackClientImpl implements CallbackClient {
switch (usedPanel.getChatType()) {
case GAME:
usedPanel.receiveMessage("", new StringBuilder()
.append("HOTKEYS:")
.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/><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("HOTKEYS:")
.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/><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(),
.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(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);
break;
case TOURNAMENT:
@ -519,10 +543,10 @@ public class CallbackClientImpl implements CallbackClient {
case TABLES:
String serverAddress = SessionHandler.getSession().getServerHostname().orElse("");
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/>\\list - show a list of available chat commands.")
.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/>Download icons and symbols by using the \"Symbols\" main menu.")
.append("<br/>\\list - show a list of available chat commands.")
.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(),
null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE);
break;
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 {
frame.showGame(gameId, 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 {
frame.showDraft(draftId);
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 {
frame.showTournament(tournamentId);
AudioManager.playTournamentStarted();

View file

@ -122,7 +122,7 @@ public class NewPlayerPanel extends javax.swing.JPanel {
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);
this.setLayout(layout);

View file

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

View file

@ -78,7 +78,7 @@ public class TournamentPlayerPanel extends javax.swing.JPanel {
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);
javax.swing.GroupLayout pnlPlayerNameLayout = new javax.swing.GroupLayout(pnlPlayerName);

View file

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

View file

@ -6,14 +6,13 @@ import mage.client.constants.Constants;
import mage.constants.Rarity;
import org.apache.log4j.Logger;
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.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
import java.io.File;
import java.util.*;
/**
* 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",
"NEC","NEO","SNC","NCC","CLB","2X2","DMU","DMC","40K","GN3",
"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
};

View file

@ -533,6 +533,13 @@ public class ScryfallImageSupportCards {
add("WOE"); // Wilds of Eldraine
add("WOT"); // Wilds of Eldraine: Enchanting Tales
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★/");
// PRES
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.utils.CompressUtil;
import mage.utils.ThreadUtils;
import java.io.Serializable;
import java.util.UUID;
@ -11,11 +12,23 @@ import java.util.UUID;
*/
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 Object data;
private ClientCallbackMethod method;
private int messageId;
public ClientCallback(ClientCallbackMethod method, UUID objectId) {
this(method, objectId, null);
}
public ClientCallback(ClientCallbackMethod method, UUID objectId, Object data) {
this(method, objectId, data, true);
}
@ -26,8 +39,10 @@ public class ClientCallback implements Serializable {
this.setData(data, useCompress);
}
public ClientCallback(ClientCallbackMethod method, UUID objectId) {
this(method, objectId, null);
private void simulateBadConnection() {
if (SIMULATE_BAD_CONNECTION) {
ThreadUtils.sleep(100);
}
}
public void clear() {
@ -55,12 +70,14 @@ public class ClientCallback implements Serializable {
this.data = data;
} else {
this.data = CompressUtil.compress(data);
simulateBadConnection();
}
}
public void decompressData() {
if (this.data instanceof ZippedObject) {
this.data = CompressUtil.decompress(this.data);
simulateBadConnection();
}
}

View file

@ -1,68 +1,86 @@
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 {
CHATMESSAGE("chatMessage"),
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");
// TODO: rename events due place/action like GAME_STARTED, GAME_ASK_DIALOG, GAME_TARGET_DIALOG
String code;
boolean isClientSideMessage;
// messages
CHATMESSAGE(ClientCallbackType.MESSAGE, "chatMessage"),
SHOW_USERMESSAGE(ClientCallbackType.MESSAGE, "showUserMessage"),
SERVER_MESSAGE(ClientCallbackType.MESSAGE, "serverMessage"),
ClientCallbackMethod(String code) {
this(code, false);
}
// table
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.isClientSideMessage = isClientSideMessage;
}
public boolean isClientSideMessage() {
return this.isClientSideMessage;
public ClientCallbackType getType() {
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
this.frameStyle = FrameStyle.M15_NORMAL;
this.expansionSetCode = emblem.getExpansionSetCode();
this.cardNumber = "";
this.cardNumber = emblem.getCardNumber();
this.imageNumber = emblem.getImageNumber();
this.usesVariousArt = emblem.getUsesVariousArt();
this.rarity = Rarity.COMMON;
this.playableStats = emblem.playableStats.copy();

View file

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

View file

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

View file

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

View file

@ -68,7 +68,7 @@ public class Modern extends Constructed {
banned.add("Tree of Tales");
banned.add("Umezawa's Jitte");
banned.add("Uro, Titan of Nature's Wrath");
banned.add("Yorion, the Sky Nomad");
banned.add("Yorion, Sky Nomad");
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,
* with two additional custom rules: <p>
* -> 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
* land drop for the turn. <p>
* -> The starting hand size is 6, not 7.
* conjure into play a custom version of Pillar of the Paruns. This
* does count as a land drop for the turn. The custom Pillar has
* hexproof and gain "{T}: add {1}."<p>
* -> The starting hand size is 6, and the starting life count is 25.
* <p> <p>
* 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
@ -49,7 +50,7 @@ import java.util.UUID;
public class CustomPillarOfTheParunsDuel extends GameImpl {
public CustomPillarOfTheParunsDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan) {
super(attackOption, range, mulligan, 20, 40, 6);
super(attackOption, range, mulligan, 25, 40, 6);
}
@Override
@ -57,7 +58,10 @@ public class CustomPillarOfTheParunsDuel extends GameImpl {
super.init(choosingPlayerId);
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));
@ -89,28 +93,28 @@ class InitPillarOfTheParunsEffect extends OneShotEffect {
private UUID playerId;
private String cardName;
InitPillarOfTheParunsEffect(UUID playerId, String cardName){
InitPillarOfTheParunsEffect(UUID playerId, String cardName) {
super(Outcome.PutLandInPlay);
this.playerId = playerId;
this.cardName = cardName;
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);
this.playerId = effect.playerId;
this.cardName = effect.cardName;
}
@Override
public InitPillarOfTheParunsEffect copy(){
public InitPillarOfTheParunsEffect copy() {
return new InitPillarOfTheParunsEffect(this);
}
@Override
public boolean apply(Game game, Ability source){
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(playerId);
if(player == null){
if (player == null) {
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
// 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 final transient PlayerResponse response = new PlayerResponse();
@ -1315,7 +1317,7 @@ public class HumanPlayer extends PlayerImpl {
while (canRespond()) {
// try to set trigger auto order
java.util.List<TriggeredAbility> abilitiesWithNoOrderSet = new ArrayList<>();
TriggeredAbility abilityOrderLast = null;
java.util.List<TriggeredAbility> abilitiesOrderLast = new ArrayList<>();
for (TriggeredAbility ability : abilities) {
if (triggerAutoOrderAbilityFirst.contains(ability.getOriginalId())) {
return ability;
@ -1326,17 +1328,20 @@ public class HumanPlayer extends PlayerImpl {
return ability;
}
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;
}
if (triggerAutoOrderNameLast.contains(rule)) {
abilityOrderLast = ability;
abilitiesOrderLast.add(ability);
continue;
}
if (autoOrderUse) {
// multiple triggers with same rule text will be auto-ordered
if (autoOrderRuleText == null) {
autoOrderRuleText = rule;
} else if (!rule.equals(autoOrderRuleText)) {
// diff triggers, so must use choose dialog
autoOrderUse = false;
}
}
@ -1344,7 +1349,8 @@ public class HumanPlayer extends PlayerImpl {
}
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
@ -1352,6 +1358,21 @@ public class HumanPlayer extends PlayerImpl {
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;
updateGameStatePriority("chooseTriggeredAbility", 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) {
if (playerAction == TRIGGER_AUTO_ORDER_RESET_ALL) {
triggerAutoOrderAbilityFirst.clear();
@ -2670,7 +2698,9 @@ public class HumanPlayer extends PlayerImpl {
triggerAutoOrderNameLast.clear();
return;
}
if (data instanceof UUID) {
// remember by id
UUID abilityId = (UUID) data;
UUID originalId = null;
for (TriggeredAbility ability : game.getState().getTriggered(getId())) {
@ -2685,12 +2715,17 @@ public class HumanPlayer extends PlayerImpl {
triggerAutoOrderAbilityFirst.add(originalId);
break;
case TRIGGER_AUTO_ORDER_ABILITY_LAST:
triggerAutoOrderAbilityFirst.add(originalId);
triggerAutoOrderAbilityLast.add(originalId);
break;
}
}
} else if (data instanceof String) {
// remember by name
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) {
case TRIGGER_AUTO_ORDER_NAME_FIRST:
triggerAutoOrderNameFirst.add(abilityName);

View file

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

View file

@ -271,10 +271,6 @@ public class User {
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) {
List<String> messageData = new LinkedList<>();
messageData.add(titel);

View file

@ -58,7 +58,7 @@ public class GameSessionWatcher {
public void inform(final String message) {
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);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source);
@ -76,6 +71,12 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl {
return null;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL
|| event.getType() == GameEvent.EventType.ACTIVATE_ABILITY;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (source.getFirstTarget() != null

View file

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

View file

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

View file

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

View file

@ -1,18 +1,19 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
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.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.SacrificeEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
@ -36,21 +37,12 @@ public class AllegiantGeneralPryde extends CardImpl {
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."
SacrificeEffect sacrifceEffect = new SacrificeEffect(
StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, 1, "");
EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(sacrifceEffect, true, true);
ability.setTriggerPhrase("When this creature enters the battlefield, ");
ability.addTarget(new TargetControlledCreaturePermanent(1));
DrawCardSourceControllerEffect drawCardSourceControllerEffect = new DrawCardSourceControllerEffect(2);
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));
Ability gainedAbility = new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(
new DrawCardSourceControllerEffect(2),
new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)
).addEffect(new LoseLifeSourceControllerEffect(2).concatBy("and")))
.setTriggerPhrase("When this creature enters the battlefield, ");
this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(gainedAbility, Duration.WhileOnBattlefield, filter)));
}
private AllegiantGeneralPryde(final AllegiantGeneralPryde card) {

View file

@ -1,7 +1,7 @@
package mage.cards.a;
import mage.abilities.common.BecomesTargetControllerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.TargetOfOpponentsSpellOrAbilityTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
@ -9,6 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SetTargetPointer;
import mage.constants.Zone;
import mage.filter.StaticFilters;
@ -24,7 +25,8 @@ public final class AmuletOfSafekeeping extends CardImpl {
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}.
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.
this.addAbility(new SimpleStaticAbility(

View file

@ -2,12 +2,11 @@ package mage.cards.a;
import mage.MageInt;
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.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicate;
import mage.game.Game;
@ -21,11 +20,10 @@ import java.util.UUID;
public final class AncientLumberknot extends CardImpl {
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 {
filter.add(AncientLumberknotPredicate.instance);
filter.add(TargetController.YOU.getControllerPredicate());
}
public AncientLumberknot(UUID ownerId, CardSetInfo setInfo) {
@ -36,7 +34,7 @@ public final class AncientLumberknot extends CardImpl {
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.
this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessAllEffect(filter)));
this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect(filter)));
}
private AncientLumberknot(final AncientLumberknot card) {

View file

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

View file

@ -1,7 +1,7 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BecomesTargetSourceFirstTimeTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
@ -12,18 +12,15 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.common.NumberOfTimesPermanentTargetedATurnWatcher;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author AustinYQM
* @author AustinYQM, xenohedron
*/
public final class AngelicCub extends CardImpl {
@ -36,7 +33,11 @@ public final class AngelicCub extends CardImpl {
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.
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.
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);
}
}
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;
import mage.MageInt;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
@ -25,9 +25,9 @@ public final class AngelicProtector extends CardImpl {
this.toughness = new MageInt(2);
this.addAbility(FlyingAbility.getInstance());
this.addAbility(new SourceBecomesTargetTriggeredAbility(
this.addAbility(new BecomesTargetSourceTriggeredAbility(
new BoostSourceEffect(0, 3, Duration.EndOfTurn)
).setTriggerPhrase("Whenever {this} becomes the target of a spell or ability, "));
).withRuleTextReplacement(false));
}
private AngelicProtector(final AngelicProtector card) {

View file

@ -1,6 +1,8 @@
package mage.cards.a;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -14,7 +16,7 @@ import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.ExpansionSetPredicate;
import mage.filter.predicate.mageobject.NamePredicate;
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");
static {
filter.add(Predicates.and(
TokenPredicate.FALSE,
new ExpansionSetPredicate("HML")
));
// Homelands names per CR 206.3c
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");
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) {

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.effects.common.DrawCardSourceControllerEffect;
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.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
@ -25,12 +25,10 @@ import java.util.UUID;
public final class ArcadesTheStrategist extends CardImpl {
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 {
defenderSingle.add(new AbilityPredicate(DefenderAbility.class));
defenderPlural.add(TargetController.YOU.getControllerPredicate());
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.
Ability ability = new SimpleStaticAbility(new CombatDamageByToughnessAllEffect(defenderPlural));
Ability ability = new SimpleStaticAbility(new CombatDamageByToughnessControlledEffect(defenderPlural));
ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderAllEffect(
Duration.WhileOnBattlefield, defenderSingle
).setText("and can attack as though it didn't have defender"));

View file

@ -1,25 +1,19 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
@ -35,7 +29,6 @@ public final class AshenmoorLiege extends CardImpl {
filterRedCreature.add(new ColorPredicate(ObjectColor.RED));
}
public AshenmoorLiege(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B/R}{B/R}{B/R}");
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)));
// 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) {
@ -65,39 +56,3 @@ public final class AshenmoorLiege extends CardImpl {
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);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL

View file

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

View file

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

View file

@ -1,4 +1,3 @@
package mage.cards.a;
import mage.abilities.Ability;
@ -7,14 +6,13 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderTargetEffect;
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.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.target.common.TargetCreaturePermanent;
@ -36,7 +34,7 @@ public final class AssaultFormation extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}");
// 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.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanAttackAsThoughItDidntHaveDefenderTargetEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{G}"));

View file

@ -1,7 +1,6 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -25,14 +24,15 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class AssaultSuit extends CardImpl {
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);
// 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() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, true, false);
@ -81,25 +81,20 @@ public final class AssaultSuit extends CardImpl {
return new AssaultSuitCantBeSacrificed(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
return "This creature can't be sacrificed.";
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT) {
Permanent equipment = game.getPermanent(source.getSourceId());
if (equipment != null) {
return equipment.isAttachedTo(event.getTargetId());
}
}
return false;
Permanent equipment = game.getPermanent(source.getSourceId());
return equipment != null && equipment.isAttachedTo(event.getTargetId());
}
}

View file

@ -42,7 +42,7 @@ public final class AstralDragon extends CardImpl {
false, null, 3, 3, true);
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");
effect.setAdditionalSubType(SubType.DRAGON);
effect.withAdditionalSubType(SubType.DRAGON);
Ability ability = new EntersBattlefieldTriggeredAbility(effect);
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability.withFlavorWord("Project Image"));

View file

@ -133,11 +133,6 @@ class AureliasFuryCantCastEffect extends ContinuousRuleModifyingEffectImpl {
return new AureliasFuryCantCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source);
@ -176,22 +171,27 @@ class AureliasFuryDamagedByWatcher extends Watcher {
@Override
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()) {
case DAMAGED_PERMANENT:
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());
}
return;
break;
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
public void reset() {
super.reset();

View file

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

View file

@ -16,7 +16,6 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.target.common.TargetCreaturePermanent;
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.
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 " +
"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);
// 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));
this.addAbility(ability);
}

View file

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

View file

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

View file

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

View file

@ -26,7 +26,7 @@ public final class BasilicaScreecher extends CardImpl {
// Flying
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());
}

View file

@ -1,14 +1,16 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.BecomesTargetOpponentAllTriggeredAbility;
import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.ForetellAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import java.util.UUID;
@ -28,8 +30,8 @@ public final class BattleMammoth extends CardImpl {
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.
this.addAbility(new BecomesTargetOpponentAllTriggeredAbility(
new DrawCardSourceControllerEffect(1), true
this.addAbility(new BecomesTargetAnyTriggeredAbility(new DrawCardSourceControllerEffect(1),
StaticFilters.FILTER_CONTROLLED_A_PERMANENT, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.NONE, true
));
// Foretell {2}{G}{G}

View file

@ -1,15 +1,13 @@
package mage.cards.b;
import mage.MageInt;
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.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
@ -25,7 +23,7 @@ public final class BelligerentBrontodon extends CardImpl {
this.toughness = new MageInt(6);
// 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) {

View file

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

View file

@ -72,20 +72,20 @@ class BerserkReplacementEffect extends ContinuousRuleModifyingEffectImpl {
super(effect);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
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);
return watcher == null || watcher.conditionMet();
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public BerserkReplacementEffect copy() {
return new BerserkReplacementEffect(this);

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect;
import mage.cards.AdventureCard;
@ -28,11 +28,11 @@ public final class BonecrusherGiant extends AdventureCard {
this.toughness = new MageInt(3);
// 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(
2, true, "that spell's controller", "{this}"
), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER
).setTriggerPhrase("Whenever {this} becomes the target of a spell, "));
), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER, false)
.withRuleTextReplacement(false));
// Stomp
// 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 mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CardsInControllerGraveyardCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
@ -35,7 +35,7 @@ public final class BoneshardSlasher extends CardImpl {
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveyardCondition(7),
"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.\"");
ability.addEffect(effect);
ability.setAbilityWord(AbilityWord.THRESHOLD);

View file

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

View file

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

View file

@ -66,11 +66,6 @@ class BrandOfIllOmenEffect extends ContinuousRuleModifyingEffectImpl {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public BrandOfIllOmenEffect copy() {
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.setBecomesArtifact(true);
effect.setAdditionalSubType(SubType.FOOD);
effect.setAdditionalSubType(SubType.GOLEM);
effect.withAdditionalSubType(SubType.FOOD);
effect.withAdditionalSubType(SubType.GOLEM);
effect.addAdditionalAbilities(new FoodAbility(false));
player.moveCards(card, Zone.EXILED, source, game);

View file

@ -1,19 +1,19 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.meta.OrTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.filter.FilterSpell;
import mage.filter.predicate.other.AuraSpellPredicate;
import mage.game.permanent.token.SpiritWhiteToken;
import mage.game.stack.Spell;
import java.util.UUID;
@ -22,6 +22,12 @@ import java.util.UUID;
*/
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) {
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;
// 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}
this.addAbility(new DisturbAbility(this, "{W}{U}"));
@ -46,54 +55,3 @@ public final class BrineComber extends CardImpl {
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;
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.effects.common.AttachEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.ExileSourceEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.meta.OrTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.constants.*;
import mage.filter.FilterSpell;
import mage.filter.predicate.other.AuraSpellPredicate;
import mage.game.permanent.token.SpiritWhiteToken;
import mage.game.stack.Spell;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
@ -28,6 +25,12 @@ import java.util.UUID;
*/
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) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "");
@ -44,7 +47,10 @@ public final class BrineboundGift extends CardImpl {
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.
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.
this.addAbility(new PutIntoGraveFromAnywhereSourceAbility(new ExileSourceEffect().setText("exile it instead")));
@ -59,49 +65,3 @@ public final class BrineboundGift extends CardImpl {
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);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
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 {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Nontoken trooper creatures");
private static final FilterCreatureCard filterCard = new FilterCreatureCard("Trooper card");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken Trooper creatures");
private static final FilterCreatureCard filterCard = new FilterCreatureCard("Trooper creature card");
static {
filter.add(SubType.TROOPER.getPredicate());
@ -44,11 +44,9 @@ public final class CaptainPhasma extends CardImpl {
this.toughness = new MageInt(4);
// 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())
.setText("When this creature enters the battlefield, create a 1/1 white Trooper creature token"),
false, true);
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new GainAbilityControlledEffect(ability, Duration.WhileOnBattlefield, filter, false)));
Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TrooperToken()), false)
.setTriggerPhrase("When this creature enters the battlefield, ");
this.addAbility(new SimpleStaticAbility(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.
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);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject sourceObject = game.getObject(source);

View file

@ -1,7 +1,7 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.effects.common.MillCardsControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -22,7 +22,7 @@ public final class CephalidAristocrat extends CardImpl {
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.
this.addAbility(new SourceBecomesTargetTriggeredAbility(new MillCardsControllerEffect(2)));
this.addAbility(new BecomesTargetSourceTriggeredAbility(new MillCardsControllerEffect(2)));
}
private CephalidAristocrat(final CephalidAristocrat card) {

View file

@ -4,7 +4,7 @@ package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
@ -35,7 +35,7 @@ public final class CephalidIllusionist extends CardImpl {
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.
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
Effect effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, true);

View file

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

View file

@ -5,6 +5,7 @@ import mage.MageInt;
import mage.Mana;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.hint.ValueHint;
import mage.abilities.mana.DynamicManaAbility;
import mage.constants.SubType;
import mage.cards.CardImpl;
@ -29,7 +30,7 @@ public final class CircleOfDreamsDruid extends CardImpl {
this.toughness = new MageInt(1);
// {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) {

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) + '.';
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() != GameEvent.EventType.CAST_SPELL
|| !game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
return false;
}
MageObject object = game.getObject(event.getSourceId());

View file

@ -15,6 +15,7 @@ import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
@ -22,16 +23,24 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import static mage.cards.c.CityInABottle.getArabianNightsNamePredicates;
/**
* @author emerald000
*/
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) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
@ -39,7 +48,7 @@ public final class CityInABottle extends CardImpl {
this.addAbility(new CityInABottleStateTriggeredAbility());
// 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) {
@ -51,100 +60,20 @@ public final class CityInABottle extends CardImpl {
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 {
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 {
filter.add(TokenPredicate.FALSE);
filter.add(Predicates.or(getArabianNightsNamePredicates()));
filter.add(Predicates.or(CityInABottle.ARABIAN_NIGHTS_CARD_NAME_PREDICATES));
filter.add(AnotherPredicate.instance);
}
CityInABottleStateTriggeredAbility() {
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) {
@ -161,24 +90,21 @@ class CityInABottleStateTriggeredAbility extends StateTriggeredAbility {
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 {
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 {
filter.add(TokenPredicate.FALSE);
filter.add(Predicates.or(getArabianNightsNamePredicates()));
filter.add(Predicates.or(CityInABottle.ARABIAN_NIGHTS_CARD_NAME_PREDICATES));
filter.add(AnotherPredicate.instance);
}
CityInABottleSacrificeEffect() {
super(Outcome.Sacrifice);
this.staticText = "its controller sacrifices it";
this.staticText = "their controllers sacrifice them";
}
private CityInABottleSacrificeEffect(final CityInABottleSacrificeEffect effect) {
@ -201,26 +127,21 @@ class CityInABottleSacrificeEffect extends OneShotEffect {
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 {
filter.add(Predicates.or(getArabianNightsNamePredicates()));
filter.add(Predicates.or(CityInABottle.ARABIAN_NIGHTS_CARD_NAME_PREDICATES));
}
CityInABottleCantPlayEffect() {
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) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public CityInABottleCantPlayEffect copy() {
return new CityInABottleCantPlayEffect(this);
@ -228,7 +149,7 @@ class CityInABottleCantPlayEffect extends ContinuousRuleModifyingEffectImpl {
@Override
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

View file

@ -1,31 +1,35 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.constants.SetTargetPointer;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID;
/**
*
* @author fireshoes
* @author xenohedron
*/
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) {
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.
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) {
@ -37,44 +41,3 @@ public final class CloudCover extends CardImpl {
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
public boolean apply(Game game, Ability source) {
return true;
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.WINS
|| event.getType() == GameEvent.EventType.LOSES;
}
@Override

View file

@ -53,24 +53,22 @@ class ConjurersBanEffect extends ContinuousRuleModifyingEffectImpl {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public ConjurersBanEffect copy() {
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
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());
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
return CardUtil.haveSameNames(object, cardName, game);
}
return false;
MageObject object = game.getObject(event.getSourceId());
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
return CardUtil.haveSameNames(object, cardName, game);
}
@Override

View file

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

View file

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

View file

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

View file

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

View file

@ -1,21 +1,16 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author dustinconrad
* @author xenohedron
*/
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}");
// 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) {
@ -35,39 +30,3 @@ public final class Cowardice extends CardImpl {
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.SubType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
@ -57,12 +56,7 @@ enum CreatureBondValue implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
// In the case that the enchantment is blinked
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());
}
Permanent enchantment = sourceAbility.getSourcePermanentOrLKI(game);
if (enchantment == null) {
return 0;
}

View file

@ -4,7 +4,7 @@ package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SourceBecomesTargetTriggeredAbility;
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.SacrificeSourceEffect;
@ -36,13 +36,13 @@ public final class CrystallineNautilus extends CardImpl {
this.addAbility(new BestowAbility(this, "{3}{U}{U}"));
// 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."
Effect effect = new BoostEnchantedEffect(4,4,Duration.WhileOnBattlefield);
effect.setText("Enchanted creature gets +4/+4");
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.\"");
ability.addEffect(effect);
this.addAbility(ability);

View file

@ -18,7 +18,6 @@ import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
import mage.abilities.common.EnchantedPlayerAttackedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.players.Player;
@ -71,12 +70,7 @@ class CurseOfBountyEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked
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());
}
Permanent enchantment = source.getSourcePermanentOrLKI(game);
if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) {

View file

@ -15,7 +15,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.ZombieToken;
@ -72,12 +71,7 @@ class CurseOfDisturbanceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked
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());
}
Permanent enchantment = source.getSourcePermanentOrLKI(game);
if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) {

View file

@ -19,13 +19,12 @@ import mage.watchers.common.CastSpellLastTurnWatcher;
import java.util.UUID;
/**
*
* @author BetaSteward
*/
public final class CurseOfExhaustion extends CardImpl {
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);
@ -66,22 +65,18 @@ class CurseOfExhaustionEffect extends ContinuousRuleModifyingEffectImpl {
}
@Override
public boolean apply(Game game, Ability source) {
return true;
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.CAST_SPELL) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null && enchantment.getAttachedTo() != null) {
Player player = game.getPlayer(enchantment.getAttachedTo());
if (player != null && event.getPlayerId().equals(player.getId())) {
CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class);
if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > 0) {
return true;
}
}
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null && enchantment.getAttachedTo() != null) {
Player player = game.getPlayer(enchantment.getAttachedTo());
if (player != null && event.getPlayerId().equals(player.getId())) {
CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class);
return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > 0;
}
}
return false;

View file

@ -22,7 +22,6 @@ import mage.target.targetpointer.FixedTarget;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.constants.Zone;
/**
* @author Saga
@ -72,12 +71,7 @@ class CurseOfOpulenceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked
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());
}
Permanent enchantment = source.getSourcePermanentOrLKI(game);
if (enchantment == null) {
return false;
}

View file

@ -15,7 +15,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -70,12 +69,7 @@ class CurseOfVerbosityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked
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());
}
Permanent enchantment = source.getSourcePermanentOrLKI(game);
if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) {

View file

@ -19,7 +19,6 @@ import mage.abilities.Ability;
import mage.abilities.common.EnchantedPlayerAttackedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeTargetEffect;
import mage.constants.Zone;
import mage.players.Player;
/**
@ -70,12 +69,7 @@ class CurseOfVitalityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// In the case that the enchantment is blinked
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());
}
Permanent enchantment = source.getSourcePermanentOrLKI(game);
if (enchantment != null) {
Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo());
if (enchantedPlayer != null) {

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