Add custom options for starting life total and starting hand size (#11259)

* add startHandSize / startLife to the custom option panel

* use the custom startLife/startHandsize in all Game Modes
This commit is contained in:
Susucre 2023-10-07 05:22:48 +02:00 committed by GitHub
parent 3e6097b70e
commit f14479c53c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 1230 additions and 929 deletions

View file

@ -52,6 +52,8 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="spnFreeMulligans" max="32767" attributes="0"/>
</Group>
<Component id="planechaseDescriptionLabel" alignment="0" max="32767" attributes="0"/>
<Component id="emblemCardsDescriptionLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblVariantOptions" alignment="0" min="-2" max="-2" attributes="0"/>
@ -63,8 +65,15 @@
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="planechaseDescriptionLabel" alignment="0" max="32767" attributes="0"/>
<Component id="emblemCardsDescriptionLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="checkStartingLife" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="spnCustomLifeTotal" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="checkStartingHandSize" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="spnCustomStartingHand" min="-2" pref="46" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -86,6 +95,17 @@
<Component id="lblFreeMulligans" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
<Component id="spnCustomStartingHand" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="checkStartingHandSize" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="spnCustomLifeTotal" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="checkStartingLife" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSeparator2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblVariantOptions" min="-2" max="-2" attributes="0"/>
@ -321,5 +341,47 @@
<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>
<Component class="javax.swing.JSpinner" name="spnCustomLifeTotal">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="Custom starting life total"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Custom starting life total"/>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value="Set a custom starting life total"/>
</AccessibilityProperties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnCustomLifeTotalStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="checkStartingLife">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="Check to use a specific starting life total"/>
<Property name="actionCommand" type="java.lang.String" value="checkCustomLife"/>
<Property name="horizontalTextPosition" type="int" value="10"/>
<Property name="label" type="java.lang.String" value="Custom Starting Life"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Custom starting life"/>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkStartingLifeActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="checkStartingHandSize">
<Properties>
<Property name="text" type="java.lang.String" value="Custom Starting Hand"/>
<Property name="toolTipText" type="java.lang.String" value="Check to use a specific starting hand size"/>
<Property name="actionCommand" type="java.lang.String" value="checkCustomHandSize"/>
<Property name="horizontalTextPosition" type="int" value="10"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkStartingHandSizeActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JSpinner" name="spnCustomStartingHand">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnCustomStartingHandStateChanged"/>
</Events>
</Component>
</SubComponents>
</Form>

View file

@ -4,8 +4,6 @@ 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;
@ -15,7 +13,6 @@ 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
@ -28,6 +25,10 @@ public class CustomOptionsDialog extends MageDialog {
TABLE(
PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS,
PreferencesDialog.KEY_NEW_TABLE_MULLIGAN_TYPE,
PreferencesDialog.KEY_NEW_TABLE_CUSTOM_STARTING_LIFE,
PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_LIFE_AT_START,
PreferencesDialog.KEY_NEW_TABLE_CUSTOM_STARTING_HAND_SIZE,
PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_HAND_SIZE_AT_START,
PreferencesDialog.KEY_NEW_TABLE_PLANECHASE,
PreferencesDialog.KEY_NEW_TABLE_EMBLEM_CARDS_ENABLED,
PreferencesDialog.KEY_NEW_TABLE_EMBLEM_CARDS_PER_PLAYER_FILE,
@ -37,6 +38,10 @@ public class CustomOptionsDialog extends MageDialog {
TOURNEY(
PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS,
PreferencesDialog.KEY_NEW_TOURNAMENT_MULLIGUN_TYPE,
PreferencesDialog.KEY_NEW_TOURNAMENT_CUSTOM_STARTING_LIFE,
PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_LIFE_AT_START,
PreferencesDialog.KEY_NEW_TOURNAMENT_CUSTOM_STARTING_HAND_SIZE,
PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_HAND_SIZE_AT_START,
PreferencesDialog.KEY_NEW_TOURNAMENT_PLANE_CHASE,
PreferencesDialog.KEY_NEW_TOURNAMENT_EMBLEM_CARDS_ENABLED,
PreferencesDialog.KEY_NEW_TOURNAMENT_EMBLEM_CARDS_PER_PLAYER_FILE,
@ -44,6 +49,10 @@ public class CustomOptionsDialog extends MageDialog {
);
public final String NUMBER_OF_FREE_MULLIGANS;
public final String MULLIGAN_TYPE;
public final String BOOL_CUSTOM_STARTING_LIFE;
public final String NUMBER_OF_LIFE_AT_START;
public final String BOOL_CUSTOM_STARTING_HAND_SIZE;
public final String NUMBER_OF_HAND_SIZE_AT_START;
public final String PLANECHASE;
public final String EMBLEM_CARDS_ENABLED;
public final String EMBLEM_CARDS_PER_PLAYER_FILE;
@ -52,6 +61,10 @@ public class CustomOptionsDialog extends MageDialog {
SaveLoadKeys(
String numberOfFreeMulligans,
String mulliganType,
String customStartLife,
String valueStartLife,
String customStartHandSize,
String valueStartHandSize,
String planechase,
String emblemCardsEnabled,
String emblemCardsPerPlayerFile,
@ -59,6 +72,10 @@ public class CustomOptionsDialog extends MageDialog {
) {
NUMBER_OF_FREE_MULLIGANS = numberOfFreeMulligans;
MULLIGAN_TYPE = mulliganType;
BOOL_CUSTOM_STARTING_LIFE = customStartLife;
NUMBER_OF_LIFE_AT_START = valueStartLife;
BOOL_CUSTOM_STARTING_HAND_SIZE = customStartHandSize;
NUMBER_OF_HAND_SIZE_AT_START = valueStartHandSize;
PLANECHASE = planechase;
EMBLEM_CARDS_ENABLED = emblemCardsEnabled;
EMBLEM_CARDS_PER_PLAYER_FILE = emblemCardsPerPlayerFile;
@ -81,6 +98,10 @@ public class CustomOptionsDialog extends MageDialog {
initComponents();
this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1));
cbMulliganType.setModel(new DefaultComboBoxModel(MulliganType.values()));
this.spnCustomLifeTotal.setModel(new SpinnerNumberModel(20, 1, 100, 1));
this.spnCustomLifeTotal.setEnabled(false);
this.spnCustomStartingHand.setModel(new SpinnerNumberModel(7, 0, 20, 1));
this.spnCustomStartingHand.setEnabled(false);
this.setModal(true);
fcSelectEmblemCardsPerPlayer = new JFileChooser();
fcSelectEmblemCardsPerPlayer.setAcceptAllFileFilterUsed(false);
@ -119,6 +140,10 @@ public class CustomOptionsDialog extends MageDialog {
txtEmblemCardsStartingPlayer = new javax.swing.JTextField();
lblEmblemCardsStartingPlayer = new javax.swing.JLabel();
emblemCardsDescriptionLabel = new javax.swing.JLabel();
spnCustomLifeTotal = new javax.swing.JSpinner();
checkStartingLife = new javax.swing.JCheckBox();
checkStartingHandSize = new javax.swing.JCheckBox();
spnCustomStartingHand = new javax.swing.JSpinner();
setTitle("Custom Options");
@ -211,6 +236,39 @@ public class CustomOptionsDialog extends MageDialog {
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);
spnCustomLifeTotal.setToolTipText("Custom starting life total");
spnCustomLifeTotal.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
spnCustomLifeTotalStateChanged(evt);
}
});
checkStartingLife.setToolTipText("Check to use a specific starting life total");
checkStartingLife.setActionCommand("checkCustomLife");
checkStartingLife.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
checkStartingLife.setLabel("Custom Starting Life");
checkStartingLife.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkStartingLifeActionPerformed(evt);
}
});
checkStartingHandSize.setText("Custom Starting Hand");
checkStartingHandSize.setToolTipText("Check to use a specific starting hand size");
checkStartingHandSize.setActionCommand("checkCustomHandSize");
checkStartingHandSize.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
checkStartingHandSize.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkStartingHandSizeActionPerformed(evt);
}
});
spnCustomStartingHand.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
spnCustomStartingHandStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
@ -240,6 +298,8 @@ public class CustomOptionsDialog extends MageDialog {
.addComponent(lblFreeMulligans)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnFreeMulligans))
.addComponent(planechaseDescriptionLabel)
.addComponent(emblemCardsDescriptionLabel)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblVariantOptions)
@ -249,8 +309,14 @@ public class CustomOptionsDialog extends MageDialog {
.addComponent(lblEmblemCardsStartingPlayer)
.addComponent(lblGeneralOptions))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(planechaseDescriptionLabel)
.addComponent(emblemCardsDescriptionLabel))
.addGroup(layout.createSequentialGroup()
.addComponent(checkStartingLife)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnCustomLifeTotal)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(checkStartingHandSize)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnCustomStartingHand, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.setVerticalGroup(
@ -267,6 +333,14 @@ public class CustomOptionsDialog extends MageDialog {
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblFreeMulligans))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(spnCustomStartingHand, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(checkStartingHandSize))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(spnCustomLifeTotal, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(checkStartingLife)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblVariantOptions)
@ -317,6 +391,9 @@ public class CustomOptionsDialog extends MageDialog {
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.");
spnCustomLifeTotal.getAccessibleContext().setAccessibleName("Custom starting life total");
spnCustomLifeTotal.getAccessibleContext().setAccessibleDescription("Set a custom starting life total");
checkStartingLife.getAccessibleContext().setAccessibleName("Custom starting life");
pack();
}// </editor-fold>//GEN-END:initComponents
@ -360,10 +437,27 @@ public class CustomOptionsDialog extends MageDialog {
}//GEN-LAST:event_txtEmblemCardsStartingPlayerActionPerformed
private void spnCustomLifeTotalStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnCustomLifeTotalStateChanged
updateActiveCount();
}//GEN-LAST:event_spnCustomLifeTotalStateChanged
private void spnCustomStartingHandStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnCustomStartingHandStateChanged
updateActiveCount();
}//GEN-LAST:event_spnCustomStartingHandStateChanged
private void checkStartingLifeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkStartingLifeActionPerformed
updateActiveCount();
}//GEN-LAST:event_checkStartingLifeActionPerformed
private void checkStartingHandSizeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkStartingHandSizeActionPerformed
updateActiveCount();
}//GEN-LAST:event_checkStartingHandSizeActionPerformed
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;
@ -406,6 +500,10 @@ 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.checkStartingLife.setSelected(PreferencesDialog.getCachedValue(saveLoadKeys.BOOL_CUSTOM_STARTING_LIFE + versionStr, "No").equals("Yes"));
this.spnCustomLifeTotal.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(saveLoadKeys.NUMBER_OF_LIFE_AT_START + versionStr, "20")));
this.checkStartingHandSize.setSelected(PreferencesDialog.getCachedValue(saveLoadKeys.BOOL_CUSTOM_STARTING_HAND_SIZE + versionStr, "No").equals("Yes"));
this.spnCustomStartingHand.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(saveLoadKeys.NUMBER_OF_HAND_SIZE_AT_START + versionStr, "7")));
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, ""));
@ -427,6 +525,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.BOOL_CUSTOM_STARTING_LIFE + versionStr, options.isCustomStartLifeEnabled() ? "Yes" : "No");
PreferencesDialog.saveValue(saveLoadKeys.NUMBER_OF_LIFE_AT_START + versionStr, Integer.toString(options.getCustomStartLife()));
PreferencesDialog.saveValue(saveLoadKeys.BOOL_CUSTOM_STARTING_HAND_SIZE + versionStr, options.isCustomStartHandSizeEnabled() ? "Yes" : "No");
PreferencesDialog.saveValue(saveLoadKeys.NUMBER_OF_HAND_SIZE_AT_START + versionStr, Integer.toString(options.getCustomStartHandSize()));
PreferencesDialog.saveValue(saveLoadKeys.PLANECHASE + versionStr, options.isPlaneChase() ? "Yes" : "No");
PreferencesDialog.saveValue(saveLoadKeys.EMBLEM_CARDS_ENABLED + versionStr,
!(options.getGlobalEmblemCards().isEmpty() && options.getPerPlayerEmblemCards().isEmpty()) ? "Yes" : "No");
@ -440,6 +542,10 @@ public class CustomOptionsDialog extends MageDialog {
public void writeMatchOptionsTo(MatchOptions options) {
options.setFreeMulligans((Integer) spnFreeMulligans.getValue());
options.setMullgianType((MulliganType) cbMulliganType.getSelectedItem());
options.setCustomStartLifeEnabled(checkStartingLife.isSelected());
options.setCustomStartLife((Integer) spnCustomLifeTotal.getValue());
options.setCustomStartHandSizeEnabled(checkStartingHandSize.isSelected());
options.setCustomStartHandSize((Integer) spnCustomStartingHand.getValue());
options.setPlaneChase(chkPlaneChase.isSelected());
if (chkEmblemCards.isSelected()) {
if (!txtEmblemCardsPerPlayer.getText().isEmpty()) {
@ -452,8 +558,7 @@ public class CustomOptionsDialog extends MageDialog {
if (perPlayerEmblemDeck != null) {
perPlayerEmblemDeck.clearLayouts();
options.setPerPlayerEmblemCards(perPlayerEmblemDeck.getDeckCardLists().getCards());
}
else {
} else {
options.setPerPlayerEmblemCards(Collections.emptySet());
}
}
@ -467,13 +572,11 @@ public class CustomOptionsDialog extends MageDialog {
if (startingPlayerEmblemDeck != null) {
startingPlayerEmblemDeck.clearLayouts();
options.setGlobalEmblemCards(startingPlayerEmblemDeck.getDeckCardLists().getCards());
}
else {
} else {
options.setGlobalEmblemCards(Collections.emptySet());
}
}
}
else {
} else {
options.setPerPlayerEmblemCards(Collections.emptySet());
options.setGlobalEmblemCards(Collections.emptySet());
}
@ -481,14 +584,17 @@ public class CustomOptionsDialog extends MageDialog {
public void updateActiveCount() {
int activeCount = 0;
if ((Integer)spnFreeMulligans.getValue() > 0) activeCount++;
if ((Integer) spnFreeMulligans.getValue() > 0) activeCount++;
if (checkStartingLife.isSelected()) activeCount++;
spnCustomLifeTotal.setEnabled(checkStartingLife.isSelected());
if (checkStartingHandSize.isSelected()) activeCount++;
spnCustomStartingHand.setEnabled(checkStartingHandSize.isSelected());
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...");
}
else {
} else {
openButton.setText("Custom Options (" + activeCount + ")");
}
}
@ -498,6 +604,8 @@ public class CustomOptionsDialog extends MageDialog {
private javax.swing.JButton btnEmblemCardsStartingPlayer;
private javax.swing.JButton btnOK;
private javax.swing.JComboBox<String> cbMulliganType;
private javax.swing.JCheckBox checkStartingHandSize;
private javax.swing.JCheckBox checkStartingLife;
private javax.swing.JCheckBox chkEmblemCards;
private javax.swing.JCheckBox chkPlaneChase;
private javax.swing.JLabel emblemCardsDescriptionLabel;
@ -511,6 +619,8 @@ public class CustomOptionsDialog extends MageDialog {
private javax.swing.JLabel lblMulliganType;
private javax.swing.JLabel lblVariantOptions;
private javax.swing.JLabel planechaseDescriptionLabel;
private javax.swing.JSpinner spnCustomLifeTotal;
private javax.swing.JSpinner spnCustomStartingHand;
private javax.swing.JSpinner spnFreeMulligans;
private javax.swing.JTextField txtEmblemCardsPerPlayer;
private javax.swing.JTextField txtEmblemCardsStartingPlayer;

View file

@ -288,7 +288,7 @@ public class TestCardRenderDialog extends MageDialog {
cardsPanel.addCardEventListener(this.cardListener);
}
game = new TestGame(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
game = new TestGame(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
Deck deck = new Deck();
Player playerYou = new StubPlayer("player1", RangeOfInfluence.ALL);
game.addPlayer(playerYou, deck);
@ -750,8 +750,8 @@ class TestGame extends GameImpl {
private int numPlayers;
public TestGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60, 7);
public TestGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public TestGame(final TestGame game) {

View file

@ -101,12 +101,18 @@ public class TableView implements Serializable {
addInfo.append("Wins:").append(table.getMatch().getWinsNeeded());
addInfo.append(" Time: ").append(table.getMatch().getOptions().getMatchTimeLimit().toString());
addInfo.append(" Buffer: ").append(table.getMatch().getOptions().getMatchBufferTime().toString());
if (table.getMatch().getOptions().getMulliganType() != MulliganType.GAME_DEFAULT){
if (table.getMatch().getOptions().getMulliganType() != MulliganType.GAME_DEFAULT) {
addInfo.append(" Mulligan: \"").append(table.getMatch().getOptions().getMulliganType().toString()).append("\"");
}
if (table.getMatch().getFreeMulligans() > 0) {
addInfo.append(" FM: ").append(table.getMatch().getFreeMulligans());
}
if (table.getMatch().getOptions().isCustomStartLifeEnabled()) {
addInfo.append(" StartLife: ").append(table.getMatch().getOptions().getCustomStartLife());
}
if (table.getMatch().getOptions().isCustomStartHandSizeEnabled()) {
addInfo.append(" StartHandSize: ").append(table.getMatch().getOptions().getCustomStartHandSize());
}
} else {
addInfo.append("Wins:").append(table.getMatch().getWinsNeeded());
addInfo.append(sbScore.toString());
@ -118,7 +124,7 @@ public class TableView implements Serializable {
addInfo.append(" PC");
}
if (!(table.getMatch().getOptions().getPerPlayerEmblemCards().isEmpty())
|| !(table.getMatch().getOptions().getGlobalEmblemCards().isEmpty())) {
|| !(table.getMatch().getOptions().getGlobalEmblemCards().isEmpty())) {
addInfo.append(" EC");
}
if (table.getMatch().getOptions().isSpectatorsAllowed()) {
@ -162,12 +168,18 @@ public class TableView implements Serializable {
MatchOptions tourneyMatchOptions = table.getTournament().getOptions().getMatchOptions();
infoText.append(" Time: ").append(tourneyMatchOptions.getMatchTimeLimit().toString());
infoText.append(" Buffer: ").append(tourneyMatchOptions.getMatchBufferTime().toString());
if (tourneyMatchOptions.getMulliganType() != MulliganType.GAME_DEFAULT){
if (tourneyMatchOptions.getMulliganType() != MulliganType.GAME_DEFAULT) {
infoText.append(" Mulligan: \"").append(tourneyMatchOptions.getMulliganType().toString()).append("\"");
}
if (tourneyMatchOptions.getFreeMulligans() > 0) {
infoText.append(" FM: ").append(tourneyMatchOptions.getFreeMulligans());
}
if (table.getMatch().getOptions().isCustomStartLifeEnabled()) {
infoText.append(" StartLife: ").append(table.getMatch().getOptions().getCustomStartLife());
}
if (table.getMatch().getOptions().isCustomStartHandSizeEnabled()) {
infoText.append(" StartHandSize: ").append(table.getMatch().getOptions().getCustomStartHandSize());
}
if (table.getTournament().getTournamentType().isLimited()) {
infoText.append(" Constr.: ").append(table.getTournament().getOptions().getLimitedOptions().getConstructionTime() / 60).append(" Min.");
}

View file

@ -9,8 +9,8 @@ import mage.game.mulligan.Mulligan;
public class BrawlDuel extends GameCommanderImpl {
public BrawlDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60);
public BrawlDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public BrawlDuel(final BrawlDuel game) {

View file

@ -17,7 +17,12 @@ public class BrawlDuelMatch extends MatchImpl {
public void startGame() throws GameException {
int startLife = 25;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
BrawlDuel game = new BrawlDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
BrawlDuel game = new BrawlDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setCheckCommanderDamage(false);
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -2,22 +2,22 @@
package mage.game;
import java.util.UUID;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
import java.util.UUID;
/**
*
* @author spjspj
*/
public class BrawlFreeForAll extends GameCommanderImpl {
private int numPlayers;
public BrawlFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60);
public BrawlFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public BrawlFreeForAll(final BrawlFreeForAll game) {

View file

@ -17,7 +17,12 @@ public class BrawlFreeForAllMatch extends MatchImpl {
public void startGame() throws GameException {
int startLife = 30;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
BrawlFreeForAll game = new BrawlFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
BrawlFreeForAll game = new BrawlFreeForAll(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
game.setCheckCommanderDamage(false);
initGame(game);

View file

@ -9,8 +9,8 @@ import mage.game.mulligan.Mulligan;
public class CanadianHighlanderDuel extends GameCanadianHighlanderImpl {
public CanadianHighlanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife);
public CanadianHighlanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, startLife, startHandSize);
}
public CanadianHighlanderDuel(final CanadianHighlanderDuel game) {

View file

@ -7,7 +7,6 @@ import mage.game.mulligan.Mulligan;
import mage.game.mulligan.MulliganType;
/**
*
* @author spjspj
*/
public class CanadianHighlanderDuelMatch extends MatchImpl {
@ -20,7 +19,12 @@ public class CanadianHighlanderDuelMatch extends MatchImpl {
public void startGame() throws GameException {
int startLife = 20;
Mulligan mulligan = options.getMulliganType().orDefault(MulliganType.CANADIAN_HIGHLANDER).getMulligan(options.getFreeMulligans());
CanadianHighlanderDuel game = new CanadianHighlanderDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
CanadianHighlanderDuel game = new CanadianHighlanderDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);
games.add(game);

View file

@ -9,8 +9,8 @@ import mage.game.mulligan.Mulligan;
public class CommanderDuel extends GameCommanderImpl {
public CommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 100);
public CommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 100, startLife, startHandSize);
}
public CommanderDuel(final CommanderDuel game) {

View file

@ -29,7 +29,12 @@ public class CommanderDuelMatch extends MatchImpl {
startLife = 25;
}
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
CommanderDuel game = new CommanderDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
CommanderDuel game = new CommanderDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setCheckCommanderDamage(checkCommanderDamage);
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -16,8 +16,8 @@ public class CommanderFreeForAll extends GameCommanderImpl {
private int numPlayers;
public CommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 100);
public CommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 100, startLife, startHandSize);
}
public CommanderFreeForAll(final CommanderFreeForAll game) {

View file

@ -20,7 +20,12 @@ public class CommanderFreeForAllMatch extends MatchImpl {
startLife = 30;
}
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
CommanderFreeForAll game = new CommanderFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
CommanderFreeForAll game = new CommanderFreeForAll(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);
games.add(game);

View file

@ -49,8 +49,8 @@ import java.util.UUID;
*/
public class CustomPillarOfTheParunsDuel extends GameImpl {
public CustomPillarOfTheParunsDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan) {
super(attackOption, range, mulligan, 25, 40, 6);
public CustomPillarOfTheParunsDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 40, startLife, startHandSize);
}
@Override
@ -58,10 +58,10 @@ public class CustomPillarOfTheParunsDuel extends GameImpl {
super.init(choosingPlayerId);
getPlayers().forEach((playerId, p) -> {
addDelayedTriggeredAbility(
new AtTheBeginOfPlayerFirstMainPhase(playerId, "C-Pillar of the Paruns"),
null // TODO: Not sure how to mock something to be displayed instead.
);
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));

View file

@ -16,7 +16,12 @@ public class CustomPillarOfTheParunsDuelMatch extends MatchImpl {
@Override
public void startGame() throws GameException {
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
CustomPillarOfTheParunsDuel game = new CustomPillarOfTheParunsDuel(options.getAttackOption(), options.getRange(), mulligan);
int startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : 25;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 6;
CustomPillarOfTheParunsDuel game = new CustomPillarOfTheParunsDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -7,15 +7,15 @@ import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class FreeForAll extends GameImpl {
private int numPlayers;
public FreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60, 7);
public FreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public FreeForAll(final FreeForAll game) {

View file

@ -7,7 +7,6 @@ import mage.game.match.MatchOptions;
import mage.game.mulligan.Mulligan;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class FreeForAllMatch extends MatchImpl {
@ -19,7 +18,12 @@ public class FreeForAllMatch extends MatchImpl {
@Override
public void startGame() throws GameException {
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange(), mulligan, 20);
int startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : 20;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
FreeForAll game = new FreeForAll(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);
games.add(game);

View file

@ -10,8 +10,9 @@ import mage.game.mulligan.Mulligan;
*/
public class FreeformCommanderDuel extends GameCommanderImpl {
public FreeformCommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60);
public FreeformCommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public FreeformCommanderDuel(final FreeformCommanderDuel game) {

View file

@ -18,7 +18,12 @@ public class FreeformCommanderDuelMatch extends MatchImpl {
int startLife = 40;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
FreeformCommanderDuel game = new FreeformCommanderDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
FreeformCommanderDuel game = new FreeformCommanderDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setCheckCommanderDamage(true);
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -2,22 +2,23 @@
package mage.game;
import java.util.UUID;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
import java.util.UUID;
/**
*
* @author spjspj
*/
public class FreeformCommanderFreeForAll extends GameCommanderImpl {
private int numPlayers;
public FreeformCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60);
public FreeformCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public FreeformCommanderFreeForAll(final FreeformCommanderFreeForAll game) {

View file

@ -17,7 +17,12 @@ public class FreeformCommanderFreeForAllMatch extends MatchImpl {
public void startGame() throws GameException {
int startLife = 40;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
FreeformCommanderFreeForAll game = new FreeformCommanderFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
FreeformCommanderFreeForAll game = new FreeformCommanderFreeForAll(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);
games.add(game);

View file

@ -1,18 +1,20 @@
package mage.game;
import java.util.UUID;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
import java.util.UUID;
public class FreeformUnlimitedCommander extends GameCommanderImpl {
private int numPlayers;
public FreeformUnlimitedCommander(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60);
public FreeformUnlimitedCommander(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public FreeformUnlimitedCommander(final FreeformUnlimitedCommander game) {

View file

@ -14,7 +14,12 @@ public class FreeformUnlimitedCommanderMatch extends MatchImpl {
public void startGame() throws GameException {
int startLife = 40;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
FreeformUnlimitedCommander game = new FreeformUnlimitedCommander(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
FreeformUnlimitedCommander game = new FreeformUnlimitedCommander(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);
games.add(game);

View file

@ -19,13 +19,13 @@ import mage.players.Player;
import java.util.UUID;
/**
*
* @author nigelzor
*/
public class MomirDuel extends GameImpl {
public MomirDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60, 7);
public MomirDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public MomirDuel(final MomirDuel game) {

View file

@ -6,7 +6,6 @@ import mage.game.match.MatchOptions;
import mage.game.mulligan.Mulligan;
/**
*
* @author nigelzor
*/
public class MomirDuelMatch extends MatchImpl {
@ -21,7 +20,12 @@ public class MomirDuelMatch extends MatchImpl {
int startLife = 24;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
MomirDuel game = new MomirDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
MomirDuel game = new MomirDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
this.initGame(game);

View file

@ -6,7 +6,6 @@ import mage.game.match.MatchOptions;
import mage.game.mulligan.Mulligan;
/**
*
* @author nigelzor
*/
public class MomirFreeForAllMatch extends MatchImpl {
@ -21,7 +20,12 @@ public class MomirFreeForAllMatch extends MatchImpl {
int startLife = 24;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
MomirGame game = new MomirGame(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
MomirGame game = new MomirGame(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
this.initGame(game);

View file

@ -19,15 +19,15 @@ import mage.players.Player;
import java.util.UUID;
/**
*
* @author nigelzor
*/
public class MomirGame extends GameImpl {
private int numPlayers;
public MomirGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60, 7);
public MomirGame(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public MomirGame(final MomirGame game) {

View file

@ -12,8 +12,8 @@ import java.util.UUID;
*/
public class OathbreakerDuel extends OathbreakerFreeForAll {
public OathbreakerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife);
public OathbreakerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, startLife, startHandSize);
this.startingPlayerSkipsDraw = true;
}

View file

@ -15,9 +15,13 @@ public class OathbreakerDuelMatch extends MatchImpl {
@Override
public void startGame() throws GameException {
int startLife = 20;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
OathbreakerDuel game = new OathbreakerDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
int startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : 20;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
OathbreakerDuel game = new OathbreakerDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setCheckCommanderDamage(false);
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -31,8 +31,9 @@ public class OathbreakerFreeForAll extends GameCommanderImpl {
private static final String COMMANDER_NAME_OATHBREAKER = "Oathbreaker";
private static final String COMMANDER_NAME_SIGNATURE_SPELL = "Signature Spell";
public OathbreakerFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 100);
public OathbreakerFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 100, startLife, startHandSize);
this.startingPlayerSkipsDraw = false;
}

View file

@ -15,9 +15,13 @@ public class OathbreakerFreeForAllMatch extends MatchImpl {
@Override
public void startGame() throws GameException {
int startLife = 20;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
OathbreakerFreeForAll game = new OathbreakerFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife);
int startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : 20;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
OathbreakerFreeForAll game = new OathbreakerFreeForAll(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setCheckCommanderDamage(false);
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -2,22 +2,22 @@
package mage.game;
import java.util.UUID;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
import java.util.UUID;
/**
*
* @author spjspj
*/
public class PennyDreadfulCommanderFreeForAll extends GameCommanderImpl {
private int numPlayers;
public PennyDreadfulCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 60);
public PennyDreadfulCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public PennyDreadfulCommanderFreeForAll(final PennyDreadfulCommanderFreeForAll game) {

View file

@ -20,7 +20,12 @@ public class PennyDreadfulCommanderFreeForAllMatch extends MatchImpl {
startLife = 30;
}
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
PennyDreadfulCommanderFreeForAll game = new PennyDreadfulCommanderFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
PennyDreadfulCommanderFreeForAll game = new PennyDreadfulCommanderFreeForAll(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
initGame(game);
games.add(game);

View file

@ -8,13 +8,13 @@ import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
/**
*
* @author JRHerlehy
*/
public class TinyLeadersDuel extends GameTinyLeadersImpl {
public TinyLeadersDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife);
public TinyLeadersDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range,
Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, startLife, startHandSize);
}
public TinyLeadersDuel(final TinyLeadersDuel game) {

View file

@ -7,7 +7,6 @@ import mage.game.match.MatchOptions;
import mage.game.mulligan.Mulligan;
/**
*
* @author JRHerlehy
*/
public class TinyLeadersDuelMatch extends MatchImpl {
@ -22,7 +21,12 @@ public class TinyLeadersDuelMatch extends MatchImpl {
int startLife = 25;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
TinyLeadersDuel game = new TinyLeadersDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : startLife;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
TinyLeadersDuel game = new TinyLeadersDuel(
options.getAttackOption(), options.getRange(),
mulligan, startLife, startHandSize
);
game.setStartMessage(this.createGameStartMessage());
//Tucking a Tiny Leader is legal

View file

@ -11,16 +11,9 @@ import java.util.UUID;
public class TwoPlayerDuel extends GameImpl {
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
this(attackOption, range, mulligan, startLife, 60);
}
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int minimumDeckSize) {
this(attackOption, range, mulligan, startingLife, minimumDeckSize, 7);
}
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int minimumDeckSize, int startingHandSize) {
super(attackOption, range, mulligan, startingLife, minimumDeckSize, startingHandSize);
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan,
int minimumDeckSize, int startLife, int startHandSize) {
super(attackOption, range, mulligan, minimumDeckSize, startLife, startHandSize);
}
public TwoPlayerDuel(final TwoPlayerDuel game) {

View file

@ -21,7 +21,12 @@ public class TwoPlayerMatch extends MatchImpl {
// see comments from https://github.com/magefree/mage/commit/4874ad31c199ea573187ea2790268be3a4d4c95a
boolean isLimitedDeck = options.isLimited() || "Limited".equals(options.getDeckType());
TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange(), mulligan, 20, isLimitedDeck ? 40 : 60);
int startLife = options.isCustomStartLifeEnabled() ? options.getCustomStartLife() : 20;
int startHandSize = options.isCustomStartHandSizeEnabled() ? options.getCustomStartHandSize() : 7;
TwoPlayerDuel game = new TwoPlayerDuel(
options.getAttackOption(), options.getRange(), mulligan,
isLimitedDeck ? 40 : 60, startLife, startHandSize
);
// Sets a start message about the match score
game.setStartMessage(this.createGameStartMessage());
initGame(game);

View file

@ -34,7 +34,7 @@ public class GoadTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");
@ -65,8 +65,8 @@ public class GoadTest extends CardTestMultiPlayerBase {
/**
* Checks whether the given attacker is NOT goaded by the provided player(s).
*
* @param attacker the name of the attacker
* @param players the player(s) that the attacker is supposed to be goaded by.
* @param attacker the name of the attacker
* @param players the player(s) that the attacker is supposed to be goaded by.
*/
private void assertNotGoaded(String attacker, TestPlayer... players) {
Assert.assertTrue("At least one player should be provided", players.length > 0);
@ -87,8 +87,8 @@ public class GoadTest extends CardTestMultiPlayerBase {
/**
* Checks whether the given attacker is goaded by the provided player(s).
*
* @param attacker the name of the attacker
* @param players the player(s) that the attacker is supposed to be goaded by.
* @param attacker the name of the attacker
* @param players the player(s) that the attacker is supposed to be goaded by.
*/
private void assertGoaded(String attacker, TestPlayer... players) {
Assert.assertTrue("At least one player should be provided", players.length > 0);
@ -220,10 +220,10 @@ public class GoadTest extends CardTestMultiPlayerBase {
/**
* Reported bug: https://github.com/magefree/mage/issues/9227
* Geode Rager (and other goad all effects) goad creatures that enter the battlefield after the effect resolved.
*
* <p>
* Ruling:
* Creatures that enter the battlefield or come under the target players control after Geode Ragers ability has resolved wont be goaded.
* (2020-09-25)
* Creatures that enter the battlefield or come under the target players control after Geode Ragers ability has resolved wont be goaded.
* (2020-09-25)
*/
@Test
public void goadAllCorrectAffect() {

View file

@ -16,7 +16,7 @@ import java.io.FileNotFoundException;
public class NaturesWillTest extends CardTestPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");
playerC = createPlayer(game, "PlayerC");

View file

@ -16,7 +16,7 @@ import java.io.FileNotFoundException;
public class StormTheVaultTest extends CardTestPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");
playerC = createPlayer(game, "PlayerC");

View file

@ -23,7 +23,7 @@ public class BattleMultiplayerTest extends BattleBaseTest {
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(
MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL,
MulliganType.GAME_DEFAULT.getMulligan(0), 20
MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7
);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");

View file

@ -21,7 +21,7 @@ public class MonarchTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// reason: must use MultiplayerAttackOption.MULTIPLE
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -19,7 +19,7 @@ import java.io.FileNotFoundException;
public class RagsRichesTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -1,6 +1,5 @@
package org.mage.test.cards.single.c19;
import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
@ -12,14 +11,15 @@ import mage.game.mulligan.MulliganType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
import java.io.FileNotFoundException;
/**
*
* @author azra1l <algee2005@gmail.com>
*/
public class AeonEngineTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException {
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -19,7 +19,7 @@ public class PramikonSkyRampartTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -1,7 +1,5 @@
package org.mage.test.cards.single.hou;
import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
@ -14,8 +12,9 @@ import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
import java.io.FileNotFoundException;
/**
*
* @author LevelX2
*/
public class TormentOfHailfireTest extends CardTestMultiPlayerBase {
@ -23,7 +22,7 @@ public class TormentOfHailfireTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// Start Life = 2
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -16,13 +16,15 @@ public class FreeformUnlimitedCommanderTest extends MageTestPlayerBase {
// Arrange
Mulligan mulligan = new LondonMulligan(1);
int startLife = 40;
int startHandSize = 7;
// Assert
FreeformUnlimitedCommander game = new FreeformUnlimitedCommander(
MultiplayerAttackOption.MULTIPLE,
RangeOfInfluence.ALL,
mulligan,
startLife
startLife,
startHandSize
);
// Assert

View file

@ -1,10 +1,18 @@
package org.mage.test.mulligan;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableSet;
import mage.cards.CardSetInfo;
import mage.cards.basiclands.Forest;
import mage.cards.decks.Deck;
import mage.cards.s.Squire;
import static mage.constants.MultiplayerAttackOption.LEFT;
import mage.constants.RangeOfInfluence;
import static mage.constants.RangeOfInfluence.ONE;
import static mage.constants.Rarity.LAND;
import mage.game.Game;
import mage.game.GameOptions;
import mage.game.TwoPlayerDuel;
@ -12,6 +20,7 @@ import mage.game.mulligan.Mulligan;
import mage.game.mulligan.MulliganType;
import mage.players.StubPlayer;
import org.apache.log4j.Logger;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
@ -19,16 +28,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableSet;
import static mage.constants.MultiplayerAttackOption.LEFT;
import static mage.constants.RangeOfInfluence.ONE;
import static mage.constants.Rarity.LAND;
import static org.junit.Assert.*;
public class MulliganTestBase {
protected static Logger logger = Logger.getLogger(MulliganTestBase.class);
@ -60,7 +59,7 @@ public class MulliganTestBase {
public void run(Runnable callback) {
Mulligan mulligan = mulliganType.getMulligan(freeMulligans);
Game game = new TwoPlayerDuel(LEFT, ONE, mulligan, 20) {
Game game = new TwoPlayerDuel(LEFT, ONE, mulligan, 60, 20, 7) {
@Override
public void fireStatusEvent(String message, boolean withTime, boolean withTurnInfo) {
super.fireStatusEvent(message, withTime, withTurnInfo);
@ -142,10 +141,10 @@ public class MulliganTestBase {
public static Deck generateDeck(UUID playerId, int count) {
Deck deck = new Deck();
Stream.generate(() -> new Forest(playerId, new CardSetInfo("Forest", "TEST", "1", LAND)))
.limit(count/2+(count & 1)) //If odd number of cards, add one extra forest
.limit(count / 2 + (count & 1)) //If odd number of cards, add one extra forest
.forEach(deck.getCards()::add);
Stream.generate(() -> new Squire(playerId, new CardSetInfo("Squire", "TEST", "2", LAND)))
.limit(count/2)
.limit(count / 2)
.forEach(deck.getCards()::add);
return deck;
}

View file

@ -18,7 +18,7 @@ public class AngelOfSerenityTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// Start Life = 2
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 2);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 2, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -20,7 +20,7 @@ public class BlatantThieveryTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -25,7 +25,7 @@ public class CreepingDreadTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -17,7 +17,7 @@ public class MultiplayerTriggerTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -20,7 +20,7 @@ public class MyriadTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -22,7 +22,7 @@ public class PlayerDiedStackTargetHandlingTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// Start Life = 2
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 3);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 3, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -9,7 +9,6 @@ import mage.game.FreeForAll;
import mage.game.Game;
import mage.game.GameException;
import mage.game.mulligan.MulliganType;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
@ -24,7 +23,7 @@ public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// Start Life = 2
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 2);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 2, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -1,6 +1,5 @@
package org.mage.test.multiplayer;
import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
@ -14,6 +13,8 @@ import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
import java.io.FileNotFoundException;
/**
* @author LevelX2
*/
@ -22,7 +23,7 @@ public class PlayerLeftGameRangeAllTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// Start Life = 2
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 2);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 2, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");
@ -419,14 +420,14 @@ public class PlayerLeftGameRangeAllTest extends CardTestMultiPlayerBase {
/**
* https://github.com/magefree/mage/issues/6997
Some continuous effects should stay in play even after the player that set them leaves the game.
Example:
* Player A: Casts Vorinclex, Voice of Hunger
* Player D: Taps all lands and do stuff (lands shouldn't untap during his next untap step)
* Player C: Kills Player A Player D: Lands untapped normally, though they shouldn't
*
* This happened playing commander against 3 AIs. One of the AIs played Vorinclex, I tapped all my lands during my turn to do stuff.
* Next AI killed the one that had Vorinclex. When the game got to my turn, my lands untapped normally.
* Some continuous effects should stay in play even after the player that set them leaves the game.
* Example:
* Player A: Casts Vorinclex, Voice of Hunger
* Player D: Taps all lands and do stuff (lands shouldn't untap during his next untap step)
* Player C: Kills Player A Player D: Lands untapped normally, though they shouldn't
* <p>
* This happened playing commander against 3 AIs. One of the AIs played Vorinclex, I tapped all my lands during my turn to do stuff.
* Next AI killed the one that had Vorinclex. When the game got to my turn, my lands untapped normally.
*/
@Test
public void TestContinuousEffectStaysAfterCreatingPlayerLeft() {
@ -465,7 +466,7 @@ public class PlayerLeftGameRangeAllTest extends CardTestMultiPlayerBase {
Assert.assertFalse("Player A is no longer in the game", playerA.isInGame());
Assert.assertTrue("Player D is the active player",currentGame.getActivePlayerId().equals(playerD.getId()));
Assert.assertTrue("Player D is the active player", currentGame.getActivePlayerId().equals(playerD.getId()));
assertTappedCount("Plains", true, 2); // Do not untap because of Vorinclex do not untap effect

View file

@ -1,6 +1,5 @@
package org.mage.test.multiplayer;
import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
@ -13,6 +12,8 @@ import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
import java.io.FileNotFoundException;
/**
* @author LevelX2
@ -21,7 +22,7 @@ public class PlayerWinsTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");
@ -119,7 +120,7 @@ public class PlayerWinsTest extends CardTestMultiPlayerBase {
Assert.assertTrue("Player A should be in the game but has lost", playerA.isInGame());
}
/**
/**
* Test that player can't win while Platinium Angel ist in range.
*/
@Test

View file

@ -22,7 +22,7 @@ public class PrivilegedPositionTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -20,7 +20,7 @@ public class VindictiveLichTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -36,7 +36,7 @@ public class PlayGameTest extends MageTestBase {
@Ignore
@Test
public void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException {
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 60, 20, 7);
Player computerA = createPlayer("ComputerA", PlayerType.COMPUTER_MINIMAX_HYBRID);
// Player playerA = createPlayer("ComputerA", "Computer - mad");

View file

@ -24,7 +24,7 @@ public abstract class CardTestCommander3PlayersFFA extends CardTestPlayerAPIImpl
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new CommanderFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new CommanderFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
playerA = createPlayer(game, "PlayerA", deckNameA);
playerB = createPlayer(game, "PlayerB", deckNameB);
playerC = createPlayer(game, "PlayerC", deckNameC);

View file

@ -17,7 +17,7 @@ public abstract class CardTestCommander4Players extends CardTestPlayerAPIImpl {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new CommanderFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new CommanderFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -23,7 +23,7 @@ public abstract class CardTestCommanderDuelBase extends CardTestPlayerAPIImpl {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new CommanderDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
Game game = new CommanderDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 40, 7);
playerA = createPlayer(game, "PlayerA", deckNameA);
playerB = createPlayer(game, "PlayerB", deckNameB);

View file

@ -21,7 +21,7 @@ public abstract class CardTestMultiPlayerBase extends CardTestPlayerAPIImpl {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -17,7 +17,7 @@ public abstract class CardTestMultiPlayerBaseWithRangeAll extends CardTestPlayer
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -1,6 +1,5 @@
package org.mage.test.serverside.base;
import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.Game;
@ -9,6 +8,8 @@ import mage.game.OathbreakerFreeForAll;
import mage.game.mulligan.MulliganType;
import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl;
import java.io.FileNotFoundException;
/**
* @author LevelX2
*/
@ -23,7 +24,7 @@ public abstract class CardTestOathbreaker3PlayersFFA extends CardTestPlayerAPIIm
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new OathbreakerFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new OathbreakerFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
playerA = createPlayer(game, "PlayerA", deckNameA);
playerB = createPlayer(game, "PlayerB", deckNameB);
playerC = createPlayer(game, "PlayerC", deckNameC);

View file

@ -24,7 +24,7 @@ public abstract class CardTestPlayerBase extends CardTestPlayerAPIImpl {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 60, 20, 7);
playerA = createPlayer(game, "PlayerA", deckNameA);
playerB = createPlayer(game, "PlayerB", deckNameB);

View file

@ -14,7 +14,7 @@ import java.io.FileNotFoundException;
/**
* PlayerA is full AI player and process all actions as AI logic. You don't need aiXXX commands in that tests.
*
* <p>
* If you need custom AI tests then use CardTestPlayerBaseWithAIHelps with aiXXX commands
*
* @author LevelX2
@ -25,7 +25,7 @@ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, MulliganType.GAME_DEFAULT.getMulligan(0), 60, 20, 7);
playerA = createPlayer(game, "PlayerA");
playerB = createPlayer(game, "PlayerB");

View file

@ -94,7 +94,7 @@ public class RandomTest {
String dest = "f:/test/xmage/";
//RandomUtil.setSeed(123);
Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 50);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 60, 50, 7);
int height = 512;
int weight = 512;
@ -117,7 +117,7 @@ public class RandomTest {
String dest = "f:/test/xmage/";
//RandomUtil.setSeed(123);
Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 50);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 60, 50, 7);
int height = 512;
int weight = 512;
@ -142,7 +142,7 @@ public class RandomTest {
String dest = "f:/test/xmage/";
//RandomUtil.setSeed(123);
Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 50);
Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 60, 50, 7);
Deck deck = DeckTestUtils.buildRandomDeck("WGUBR", false, "GRN");
player.getLibrary().addAll(deck.getMaindeckCards(), game);

View file

@ -11,8 +11,8 @@ import java.util.UUID;
public abstract class GameCanadianHighlanderImpl extends GameImpl {
public GameCanadianHighlanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 100, 7);
public GameCanadianHighlanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 100, startLife, startHandSize);
}
protected GameCanadianHighlanderImpl(final GameCanadianHighlanderImpl game) {

View file

@ -33,8 +33,8 @@ public abstract class GameCommanderImpl extends GameImpl {
// (see rule 504, "Draw Step") of his or her first turn.
protected boolean startingPlayerSkipsDraw = true;
public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int minimumDeckSize) {
super(attackOption, range, mulligan, startingLife, minimumDeckSize, 7);
public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int minimumDeckSize, int startLife, int startHandSize) {
super(attackOption, range, mulligan, minimumDeckSize, startLife, startHandSize);
}
protected GameCommanderImpl(final GameCommanderImpl game) {

View file

@ -157,7 +157,7 @@ public abstract class GameImpl implements Game {
// temporary store for income concede commands, don't copy
private final LinkedList<UUID> concedingPlayers = new LinkedList<>();
public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int minimumDeckSize, int startingHandSize) {
public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int minimumDeckSize, int startingLife, int startingHandSize) {
this.id = UUID.randomUUID();
this.range = range;
this.mulligan = mulligan;

View file

@ -34,8 +34,8 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
// (see rule 504, "Draw Step") of his or her first turn.
protected boolean startingPlayerSkipsDraw = true;
public GameTinyLeadersImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife, 50, 7);
public GameTinyLeadersImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 50, startLife, startHandSize);
}
protected GameTinyLeadersImpl(final GameTinyLeadersImpl game) {

View file

@ -15,7 +15,6 @@ import java.io.Serializable;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class MatchOptions implements Serializable {
@ -25,6 +24,10 @@ public class MatchOptions implements Serializable {
protected RangeOfInfluence range;
protected int winsNeeded;
protected int freeMulligans;
protected boolean customStartLifeEnabled;
protected int customStartLife; // Only use if customStartLifeEnabled is True
protected boolean customStartHandSizeEnabled;
protected int customStartHandSize; // Only use if customStartHandSizeEnabled is True
protected String gameType;
protected String deckType;
protected boolean limited;
@ -53,13 +56,6 @@ public class MatchOptions implements Serializable {
protected Collection<DeckCardInfo> perPlayerEmblemCards;
protected Collection<DeckCardInfo> globalEmblemCards;
/*public MatchOptions(String name, String gameType) {
this.name = name;
this.gameType = gameType;
this.password = "";
this.multiPlayer = false;
this.numSeats = 2;
}*/
public MatchOptions(String name, String gameType, boolean multiPlayer, int numSeats) {
this.name = name;
this.gameType = gameType;
@ -70,11 +66,11 @@ public class MatchOptions implements Serializable {
this.globalEmblemCards = Collections.emptySet();
}
public void setNumSeats (int numSeats) {
public void setNumSeats(int numSeats) {
this.numSeats = numSeats;
}
public int getNumSeats () {
public int getNumSeats() {
return numSeats;
}
@ -122,6 +118,38 @@ public class MatchOptions implements Serializable {
this.freeMulligans = freeMulligans;
}
public boolean isCustomStartLifeEnabled() {
return customStartLifeEnabled;
}
public void setCustomStartLifeEnabled(boolean value) {
this.customStartLifeEnabled = value;
}
public int getCustomStartLife() {
return customStartLife;
}
public void setCustomStartLife(int startLife) {
this.customStartLife = startLife;
}
public boolean isCustomStartHandSizeEnabled() {
return customStartHandSizeEnabled;
}
public void setCustomStartHandSizeEnabled(boolean value) {
this.customStartHandSizeEnabled = value;
}
public int getCustomStartHandSize() {
return customStartHandSize;
}
public void setCustomStartHandSize(int startHandSize) {
this.customStartHandSize = startHandSize;
}
public String getGameType() {
return gameType;
}
@ -228,9 +256,13 @@ public class MatchOptions implements Serializable {
this.quitRatio = quitRatio;
}
public int getMinimumRating() { return minimumRating; }
public int getMinimumRating() {
return minimumRating;
}
public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; }
public void setMinimumRating(int minimumRating) {
this.minimumRating = minimumRating;
}
public int getEdhPowerLevel() {
return edhPowerLevel;