From 5e39e1372b66ceba38f5f3759b016e691dd0028b Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Mon, 19 Jun 2023 19:44:55 -0500 Subject: [PATCH 01/17] new feature: Emblem Cards Allows match/tournament creator to specify cards to give each player emblem versions of (or just the starting player for symmetric effects). Technical details: - new UI for specifying emblem cards (.dck files) - available for all match/tournament types - new class `EmblemOfCard` - new method `copyWithZone` on `AbilityImpl` (used to make abilities work from command zone) - new fields on `GameOptions` and `MatchOptions` for emblem cards - emblems are granted after mulligans, before first turn (technically after Planechase starting plane creation) --- .../mage/client/dialog/NewTableDialog.form | 88 ++- .../mage/client/dialog/NewTableDialog.java | 526 ++++++++++------ .../client/dialog/NewTournamentDialog.form | 79 ++- .../client/dialog/NewTournamentDialog.java | 581 +++++++++++------- .../java/mage/client/table/TablesPanel.java | 3 +- .../src/main/java/mage/view/TableView.java | 8 + .../java/mage/server/TableController.java | 2 + .../main/java/mage/abilities/AbilityImpl.java | 6 + Mage/src/main/java/mage/game/GameImpl.java | 28 + Mage/src/main/java/mage/game/GameOptions.java | 14 + .../game/command/emblems/EmblemOfCard.java | 68 ++ .../java/mage/game/match/MatchOptions.java | 24 +- 12 files changed, 1018 insertions(+), 409 deletions(-) create mode 100644 Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form index 28d100eb0901..7a07198d570b 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form @@ -95,9 +95,9 @@ - + - + @@ -110,7 +110,7 @@ - + @@ -208,13 +208,28 @@ + + + + + + + + + + + + + + + - + @@ -296,6 +311,16 @@ + + + + + + + + + + @@ -305,7 +330,7 @@ - + @@ -322,7 +347,7 @@ - + @@ -476,6 +501,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java index 38153e1bf8ce..67124c776bd0 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -1,5 +1,9 @@ package mage.client.dialog; +import mage.cards.Card; +import mage.cards.decks.Deck; +import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckFileFilter; import mage.cards.decks.importer.DeckImporter; import mage.client.MageFrame; import mage.client.SessionHandler; @@ -12,6 +16,7 @@ import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.constants.SkillLevel; +import mage.game.GameException; import mage.game.match.MatchOptions; import mage.game.mulligan.MulliganType; import mage.players.PlayerType; @@ -20,10 +25,9 @@ import org.apache.log4j.Logger; import javax.swing.*; +import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * App GUI: create new GAME @@ -56,6 +60,12 @@ public NewTableDialog() { this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10)); this.spnEdhPowerLevel.setModel(new SpinnerNumberModel(100, 0, 100, 5)); MageFrame.getUI().addButton(MageComponents.NEW_TABLE_OK_BUTTON, btnOK); + 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)")); } /** @@ -102,6 +112,13 @@ private void initComponents() { cbSkillLevel = new javax.swing.JComboBox(); lblNumWins = new javax.swing.JLabel(); spnNumWins = new javax.swing.JSpinner(); + chkEmblemCards = new javax.swing.JCheckBox(); + lblEmblemCardsPerPlayer = new javax.swing.JLabel(); + txtEmblemCardsPerPlayer = new javax.swing.JTextField(); + btnEmblemCardsPerPlayer = new javax.swing.JButton(); + lblEmblemCardsStartingPlayer = new javax.swing.JLabel(); + txtEmblemCardsStartingPlayer = new javax.swing.JTextField(); + btnEmblemCardsStartingPlayer = new javax.swing.JButton(); jSeparator2 = new javax.swing.JSeparator(); jLabel1 = new javax.swing.JLabel(); player1Panel = new mage.client.table.NewPlayerPanel(); @@ -240,6 +257,48 @@ public void stateChanged(javax.swing.event.ChangeEvent evt) { lblNumWins.setText("Wins:"); lblNumWins.setToolTipText("How many games has a player to win to win the match."); + chkEmblemCards.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + chkEmblemCards.setText("Emblem Cards - "); + chkEmblemCards.setToolTipText("If enabled, select cards to give players emblem copies of"); + chkEmblemCards.setActionCommand("Emblem Cards - "); + chkEmblemCards.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkEmblemCardsActionPerformed(evt); + } + }); + + lblEmblemCardsPerPlayer.setText("Per-Player File"); + lblEmblemCardsPerPlayer.setToolTipText("An emblem of each card in this file is given to each player"); + + txtEmblemCardsPerPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtEmblemCardsPerPlayerActionPerformed(evt); + } + }); + + btnEmblemCardsPerPlayer.setText("..."); + btnEmblemCardsPerPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnEmblemCardsPerPlayerActionPerformed(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)"); + + txtEmblemCardsStartingPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtEmblemCardsStartingPlayerActionPerformed(evt); + } + }); + + btnEmblemCardsStartingPlayer.setText("..."); + btnEmblemCardsStartingPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnEmblemCardsStartingPlayerActionPerformed(evt); + } + }); + jLabel1.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N jLabel1.setText("Player 1 (You)"); @@ -300,194 +359,217 @@ public void mouseClicked(java.awt.event.MouseEvent evt) { 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() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(lblSettings) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(lblSettings) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSettingsLoad) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSettingsSave) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(player1Panel, javax.swing.GroupLayout.DEFAULT_SIZE, 940, Short.MAX_VALUE) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator1) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblName) + .addComponent(lbDeckType) + .addComponent(lblGameType)) + .addGap(6, 6, 6) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbTimeLimit) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkSpectatorsAllowed)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(cbDeckType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(cbGameType, 0, 270, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(chkRollbackTurnsAllowed) + .addGroup(layout.createSequentialGroup() + .addComponent(chkRated) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSettingsLoad) + .addComponent(lblMinimumRating) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSettingsSave) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jSeparator2) - .addComponent(player1Panel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 863, Short.MAX_VALUE) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblName) - .addComponent(lbDeckType) - .addComponent(lblGameType)) - .addGap(6, 6, 6) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbTimeLimit) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPassword) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkSpectatorsAllowed)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(cbDeckType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(cbGameType, 0, 270, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(chkRollbackTurnsAllowed) - .addGroup(layout.createSequentialGroup() - .addComponent(chkRated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblMinimumRating) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblQuitRatio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblEdhPowerLevel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))))) - .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblNumPlayers) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblRange) - .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(8, 8, 8) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblAttack)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblSkillLevel)) - .addGap(4, 4, 4) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblNumWins)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblMullgian) - .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, 149, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkPlaneChase)) - .addComponent(lblFreeMulligans)))) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jSeparator3, javax.swing.GroupLayout.DEFAULT_SIZE, 863, Short.MAX_VALUE) - .addContainerGap())) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(3, 3, 3) + .addComponent(lblQuitRatio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblEdhPowerLevel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))))) + .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtName) - .addComponent(lblName)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbTimeLimit) - .addComponent(lbTimeLimit) - .addComponent(lblPassword) - .addComponent(txtPassword) - .addComponent(chkSpectatorsAllowed))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbDeckType) - .addComponent(lblQuitRatio) - .addComponent(lblEdhPowerLevel) - .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblMinimumRating) - .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(chkRated)) + .addComponent(lblNumPlayers) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblGameType) - .addComponent(chkRollbackTurnsAllowed)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(lblRange) - .addGap(0, 0, 0) - .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblNumPlayers) - .addGap(0, 0, 0) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblAttack) - .addGap(0, 0, 0) - .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblSkillLevel) - .addGap(0, 0, 0) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblNumWins) - .addGap(0, 0, 0) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblMullgian) - .addGap(0, 0, 0) - .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblFreeMulligans) - .addGap(0, 0, 0) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(chkPlaneChase)))) - .addGap(14, 14, 14) - .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblRange) + .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(8, 8, 8) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblAttack)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel1) - .addGap(0, 0, 0) - .addComponent(player1Panel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(16, 16, 16) - .addComponent(jLabel2) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblSkillLevel)) + .addGap(4, 4, 4) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblNumWins)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE) - .addGap(9, 9, 9) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblMullgian) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, 149, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnSettingsLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnSettingsSave, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblSettings)) - .addContainerGap()) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(201, 201, 201) - .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(180, Short.MAX_VALUE))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkPlaneChase)) + .addComponent(lblFreeMulligans)))) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(chkEmblemCards) + .addGap(0, 0, 0) + .addComponent(lblEmblemCardsPerPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtEmblemCardsPerPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnEmblemCardsPerPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblEmblemCardsStartingPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtEmblemCardsStartingPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnEmblemCardsStartingPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jSeparator3, javax.swing.GroupLayout.DEFAULT_SIZE, 940, Short.MAX_VALUE) + .addContainerGap())) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtName) + .addComponent(lblName)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbTimeLimit) + .addComponent(lbTimeLimit) + .addComponent(lblPassword) + .addComponent(txtPassword) + .addComponent(chkSpectatorsAllowed))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbDeckType) + .addComponent(lblQuitRatio) + .addComponent(lblEdhPowerLevel) + .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblMinimumRating) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(chkRated)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblGameType) + .addComponent(chkRollbackTurnsAllowed)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblRange) + .addGap(0, 0, 0) + .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNumPlayers) + .addGap(0, 0, 0) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAttack) + .addGap(0, 0, 0) + .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblSkillLevel) + .addGap(0, 0, 0) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNumWins) + .addGap(0, 0, 0) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblMullgian) + .addGap(0, 0, 0) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblFreeMulligans) + .addGap(0, 0, 0) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(chkPlaneChase)))) + .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) + .addComponent(lblEmblemCardsStartingPlayer) + .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) + .addComponent(lblEmblemCardsPerPlayer) + .addComponent(chkEmblemCards)) + .addGap(14, 14, 14) + .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1) + .addGap(0, 0, 0) + .addComponent(player1Panel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(16, 16, 16) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 41, Short.MAX_VALUE) + .addGap(9, 9, 9) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnSettingsLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnSettingsSave, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblSettings)) + .addContainerGap()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(201, 201, 201) + .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(184, Short.MAX_VALUE))) ); lblMullgian.getAccessibleContext().setAccessibleName("Mullgian"); @@ -594,6 +676,45 @@ private void menuLoadSettingsDefaultActionPerformed(java.awt.event.ActionEvent e onLoadSettings(-1); }//GEN-LAST:event_menuLoadSettingsDefaultActionPerformed + private void chkEmblemCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkEmblemCardsActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkEmblemCardsActionPerformed + private void txtEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtEmblemCardsPerPlayerActionPerformed + }//GEN-LAST:event_txtEmblemCardsPerPlayerActionPerformed + + private void txtEmblemCardsStartingPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtEmblemCardsStartingPlayerActionPerformed + }//GEN-LAST:event_txtEmblemCardsStartingPlayerActionPerformed + private void btnEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsPerPlayerActionPerformed + loadEmblemCardFile(false); + }//GEN-LAST:event_btnEmblemCardsPerPlayerActionPerformed + + private void btnEmblemCardsStartingPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsStartingPlayerActionPerformed + loadEmblemCardFile(true); + }//GEN-LAST:event_btnEmblemCardsStartingPlayerActionPerformed + + private final JFileChooser fcSelectEmblemCardsPerPlayer; + private final JFileChooser fcSelectEmblemCardsStartingPlayer; + 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); + } + private MatchOptions getMatchOptions() { // current settings GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); @@ -624,6 +745,38 @@ private MatchOptions getMatchOptions() { if (options.getDeckType().startsWith("Variant Magic - Freeform Unlimited Commander")) { options.setLimited(true); // limited-style sideboarding with unlimited basics enabled for Freeform Unlimited Commander } + 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(); + // copy the cards set so deck can be garbage collected + options.setPerPlayerEmblemCards(new HashSet<>(perPlayerEmblemDeck.getCards())); + } + } + 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(); + // copy the cards set so deck can be garbage collected + options.setGlobalEmblemCards(new HashSet<>(startingPlayerEmblemDeck.getCards())); + } + } + } + else { + options.setPerPlayerEmblemCards(Collections.emptySet()); + options.setGlobalEmblemCards(Collections.emptySet()); + } return options; } @@ -975,6 +1128,8 @@ private void onSaveSettings(int version, MatchOptions options, String deckFile) // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; + private javax.swing.JButton btnEmblemCardsPerPlayer; + private javax.swing.JButton btnEmblemCardsStartingPlayer; private javax.swing.JButton btnOK; private javax.swing.JButton btnSettingsLoad; private javax.swing.JButton btnSettingsSave; @@ -985,6 +1140,7 @@ private void onSaveSettings(int version, MatchOptions options, String deckFile) private javax.swing.JComboBox cbRange; private javax.swing.JComboBox cbSkillLevel; private javax.swing.JComboBox cbTimeLimit; + private javax.swing.JCheckBox chkEmblemCards; private javax.swing.JCheckBox chkPlaneChase; private javax.swing.JCheckBox chkRated; private javax.swing.JCheckBox chkRollbackTurnsAllowed; @@ -998,6 +1154,8 @@ private void onSaveSettings(int version, MatchOptions options, String deckFile) private javax.swing.JLabel lbTimeLimit; private javax.swing.JLabel lblAttack; private javax.swing.JLabel lblEdhPowerLevel; + private javax.swing.JLabel lblEmblemCardsPerPlayer; + private javax.swing.JLabel lblEmblemCardsStartingPlayer; private javax.swing.JLabel lblFreeMulligans; private javax.swing.JLabel lblGameType; private javax.swing.JLabel lblMinimumRating; @@ -1028,6 +1186,8 @@ private void onSaveSettings(int version, MatchOptions options, String deckFile) private javax.swing.JSpinner spnNumPlayers; private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnQuitRatio; + private javax.swing.JTextField txtEmblemCardsPerPlayer; + private javax.swing.JTextField txtEmblemCardsStartingPlayer; private javax.swing.JTextField txtName; private javax.swing.JTextField txtPassword; // End of variables declaration//GEN-END:variables diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form index 01be5c944cd4..507540e295d6 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form @@ -227,6 +227,21 @@ + + + + + + + + + + + + + + + @@ -299,13 +314,23 @@ + + + + + + + + + + - + @@ -598,6 +623,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -639,7 +714,7 @@ - + diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java index 1b77225df993..d9919f5d8788 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -71,6 +71,12 @@ public NewTournamentDialog() { this.spnNumRounds.setModel(new SpinnerNumberModel(2, 2, 10, 1)); this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5)); this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10)); + 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)")); } public void showDialog(UUID roomId) { @@ -160,6 +166,13 @@ private void initComponents() { cbDraftTiming = new javax.swing.JComboBox(); cbAllowSpectators = new javax.swing.JCheckBox(); cbPlaneChase = new javax.swing.JCheckBox(); + chkEmblemCards = new javax.swing.JCheckBox(); + lblEmblemCardsStartingPlayer = new javax.swing.JLabel(); + txtEmblemCardsStartingPlayer = new javax.swing.JTextField(); + btnEmblemCardsStartingPlayer = new javax.swing.JButton(); + lblEmblemCardsPerPlayer = new javax.swing.JLabel(); + txtEmblemCardsPerPlayer = new javax.swing.JTextField(); + btnEmblemCardsPerPlayer = new javax.swing.JButton(); lblPlayer1 = new javax.swing.JLabel(); lblConstructionTime = new javax.swing.JLabel(); chkRollbackTurnsAllowed = new javax.swing.JCheckBox(); @@ -258,7 +271,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { lblTournamentType.setText("Tournament Type:"); - cbTournamentType.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + cbTournamentType.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); cbTournamentType.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cbTournamentTypeActionPerformed(evt); @@ -293,7 +306,7 @@ public void stateChanged(javax.swing.event.ChangeEvent evt) { lblDraftCube.setText("Draft Cube:"); - cbDraftCube.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + cbDraftCube.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); cbDraftCube.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cbDraftCubeActionPerformed(evt); @@ -334,7 +347,7 @@ public void stateChanged(javax.swing.event.ChangeEvent evt) { jLabel6.setText("Timing:"); - cbDraftTiming.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + cbDraftTiming.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); cbDraftTiming.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cbDraftTimingActionPerformed(evt); @@ -344,21 +357,21 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { javax.swing.GroupLayout pnlDraftOptionsLayout = new javax.swing.GroupLayout(pnlDraftOptions); pnlDraftOptions.setLayout(pnlDraftOptionsLayout); pnlDraftOptionsLayout.setHorizontalGroup( - pnlDraftOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnlDraftOptionsLayout.createSequentialGroup() - .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbDraftTiming, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(19, Short.MAX_VALUE)) + pnlDraftOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnlDraftOptionsLayout.createSequentialGroup() + .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbDraftTiming, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(19, Short.MAX_VALUE)) ); pnlDraftOptionsLayout.setVerticalGroup( - pnlDraftOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnlDraftOptionsLayout.createSequentialGroup() - .addGap(3, 3, 3) - .addGroup(pnlDraftOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbDraftTiming, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + pnlDraftOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnlDraftOptionsLayout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(pnlDraftOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbDraftTiming, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); cbAllowSpectators.setText("Allow spectators"); @@ -367,6 +380,47 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { cbPlaneChase.setText("PlaneChase"); cbPlaneChase.setToolTipText("Use Plane Chase for the tournament."); + chkEmblemCards.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + chkEmblemCards.setText("Emblem Cards - "); + 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); + } + }); + + 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)"); + + txtEmblemCardsStartingPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtEmblemCardsStartingPlayerActionPerformed(evt); + } + }); + + btnEmblemCardsStartingPlayer.setText("..."); + btnEmblemCardsStartingPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnEmblemCardsStartingPlayerActionPerformed(evt); + } + }); + + lblEmblemCardsPerPlayer.setText("Per-Player File"); + lblEmblemCardsPerPlayer.setToolTipText("An emblem of each card in this file is given to each player"); + + txtEmblemCardsPerPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtEmblemCardsPerPlayerActionPerformed(evt); + } + }); + + btnEmblemCardsPerPlayer.setText("..."); + btnEmblemCardsPerPlayer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnEmblemCardsPerPlayerActionPerformed(evt); + } + }); + lblPlayer1.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N lblPlayer1.setText("Player 1 (You)"); @@ -385,12 +439,12 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { javax.swing.GroupLayout pnlPlayersLayout = new javax.swing.GroupLayout(pnlPlayers); pnlPlayers.setLayout(pnlPlayersLayout); pnlPlayersLayout.setHorizontalGroup( - pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); pnlPlayersLayout.setVerticalGroup( - pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 5, Short.MAX_VALUE) + pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); btnOk.setText("Create"); @@ -453,209 +507,232 @@ public void mouseClicked(java.awt.event.MouseEvent evt) { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnlPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pnlPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(lblNbrPlayers) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblNbrSeats) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnNumSeats, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(lblPacks) - .addComponent(lblPlayer1)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(28, 28, 28) - .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblNumRounds)) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblConstructionTime))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkRollbackTurnsAllowed)) - .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(95, 95, 95)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(lblSettings) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSettingsLoad) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSettingsSave) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblDraftCube) - .addComponent(lblTournamentType) - .addComponent(lbDeckType) - .addComponent(lblGameType)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(chkRated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblMinimumRating) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblNumWins) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblMullgian) - .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lblFreeMulligans, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(spnFreeMulligans)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbPlaneChase)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(layout.createSequentialGroup() - .addComponent(lblQuitRatio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnQuitRatio)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(lbSkillLevel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addGap(45, 45, 45)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblName) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbTimeLimit) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPassword) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbAllowSpectators) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(player1Panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pnlRandomPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(3, 3, 3) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblName) - .addComponent(lbTimeLimit) - .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPassword) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbAllowSpectators, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblQuitRatio) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblNumWins) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(chkRated) - .addComponent(lblMinimumRating) - .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnlPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnlPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNbrPlayers) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblTournamentType) - .addComponent(lbSkillLevel) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNbrSeats) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblDraftCube)) + .addComponent(spnNumSeats, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblPacks) + .addComponent(lblPlayer1)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(28, 28, 28) + .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblNumRounds)) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblConstructionTime))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkRollbackTurnsAllowed)) + .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(95, 95, 95)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(lblSettings) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSettingsLoad) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSettingsSave) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbDeckType)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblGameType) - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblMullgian) - .addComponent(lblFreeMulligans)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbPlaneChase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addComponent(lblDraftCube) + .addComponent(lblTournamentType) + .addComponent(lbDeckType) + .addComponent(lblGameType)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPacks) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(chkRated) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnlRandomPacks, javax.swing.GroupLayout.DEFAULT_SIZE, 10, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblNumRounds)) - .addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE) - .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(lblNbrSeats, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(spnNumSeats)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblConstructionTime) - .addComponent(chkRollbackTurnsAllowed))) + .addComponent(lblMinimumRating) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(player1Panel, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnlPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblNumWins) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnSettingsLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnSettingsSave, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblSettings)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap()) + .addComponent(lblMullgian) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblFreeMulligans, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spnFreeMulligans)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbPlaneChase)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(lblQuitRatio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnQuitRatio)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(lbSkillLevel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addGap(45, 45, 45)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblName) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbTimeLimit) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbAllowSpectators) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(player1Panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnlRandomPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(chkEmblemCards) + .addGap(0, 0, 0) + .addComponent(lblEmblemCardsPerPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtEmblemCardsPerPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnEmblemCardsPerPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblEmblemCardsStartingPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtEmblemCardsStartingPlayer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnEmblemCardsStartingPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblName) + .addComponent(lbTimeLimit) + .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPassword) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbAllowSpectators, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblQuitRatio) + .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblNumWins) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkRated) + .addComponent(lblMinimumRating) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblTournamentType) + .addComponent(lbSkillLevel) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblDraftCube)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbDeckType)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblGameType) + .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblMullgian) + .addComponent(lblFreeMulligans)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbPlaneChase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .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) + .addComponent(lblEmblemCardsStartingPlayer) + .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) + .addComponent(lblEmblemCardsPerPlayer) + .addComponent(chkEmblemCards)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPacks) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlRandomPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblNumRounds)) + .addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE) + .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(lblNbrSeats, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spnNumSeats)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblConstructionTime) + .addComponent(chkRollbackTurnsAllowed))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(player1Panel, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnSettingsLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnSettingsSave, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblSettings)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) ); bindingGroup.bind(); @@ -882,6 +959,45 @@ private void btnSettingsLoadMouseClicked(java.awt.event.MouseEvent evt) {//GEN-F popupLoadSettings.show(evt.getComponent(), evt.getX(), evt.getY()); }//GEN-LAST:event_btnSettingsLoadMouseClicked + private void chkEmblemCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkEmblemCardsActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkEmblemCardsActionPerformed + private void txtEmblemCardsStartingPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtEmblemCardsPerPlayerActionPerformed + }//GEN-LAST:event_txtEmblemCardsPerPlayerActionPerformed + + private void txtEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtEmblemCardsStartingPlayerActionPerformed + }//GEN-LAST:event_txtEmblemCardsStartingPlayerActionPerformed + private void btnEmblemCardsStartingPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsStartingPlayerActionPerformed + loadEmblemCardFile(true); + }//GEN-LAST:event_btnEmblemCardsStartingPlayerActionPerformed + + private void btnEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsPerPlayerActionPerformed + loadEmblemCardFile(false); + }//GEN-LAST:event_btnEmblemCardsPerPlayerActionPerformed + + private final JFileChooser fcSelectEmblemCardsPerPlayer; + private final JFileChooser fcSelectEmblemCardsStartingPlayer; + 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); + } + private void setGameOptions() { GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); // int oldValue = (Integer) this.spnNumPlayers.getValue(); @@ -1346,6 +1462,38 @@ private TournamentOptions getTournamentOptions() { tOptions.getMatchOptions().setRange(RangeOfInfluence.ALL); tOptions.getMatchOptions().setRollbackTurnsAllowed(this.chkRollbackTurnsAllowed.isSelected()); tOptions.getMatchOptions().setRated(this.chkRated.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(); + // copy the cards set so deck can be garbage collected + tOptions.getMatchOptions().setPerPlayerEmblemCards(new HashSet<>(perPlayerEmblemDeck.getCards())); + } + } + 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(); + // copy the cards set so deck can be garbage collected + tOptions.getMatchOptions().setGlobalEmblemCards(new HashSet<>(startingPlayerEmblemDeck.getCards())); + } + } + } + else { + tOptions.getMatchOptions().setPerPlayerEmblemCards(Collections.emptySet()); + tOptions.getMatchOptions().setGlobalEmblemCards(Collections.emptySet()); + } return tOptions; } @@ -1472,6 +1620,8 @@ public TableView getTable() { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; + private javax.swing.JButton btnEmblemCardsPerPlayer; + private javax.swing.JButton btnEmblemCardsStartingPlayer; private javax.swing.JButton btnOk; private javax.swing.JButton btnSettingsLoad; private javax.swing.JButton btnSettingsSave; @@ -1485,6 +1635,7 @@ public TableView getTable() { private javax.swing.JComboBox cbSkillLevel; private javax.swing.JComboBox cbTimeLimit; private javax.swing.JComboBox cbTournamentType; + private javax.swing.JCheckBox chkEmblemCards; private javax.swing.JCheckBox chkRated; private javax.swing.JCheckBox chkRollbackTurnsAllowed; private javax.swing.JLabel jLabel6; @@ -1493,6 +1644,8 @@ public TableView getTable() { private javax.swing.JLabel lbTimeLimit; private javax.swing.JLabel lblConstructionTime; private javax.swing.JLabel lblDraftCube; + private javax.swing.JLabel lblEmblemCardsPerPlayer; + private javax.swing.JLabel lblEmblemCardsStartingPlayer; private javax.swing.JLabel lblFreeMulligans; private javax.swing.JLabel lblGameType; private javax.swing.JLabel lblMinimumRating; @@ -1532,6 +1685,8 @@ public TableView getTable() { private javax.swing.JSpinner spnNumSeats; private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnQuitRatio; + private javax.swing.JTextField txtEmblemCardsPerPlayer; + private javax.swing.JTextField txtEmblemCardsStartingPlayer; private javax.swing.JTextField txtName; private javax.swing.JTextField txtPassword; private org.jdesktop.beansbinding.BindingGroup bindingGroup; diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 8282e14b8e21..69b1d752fce1 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -99,7 +99,8 @@ public class TablesPanel extends javax.swing.JPanel { + "
FM: = Numbers of freee mulligans" + "
Constr.: = Construction time for limited tournament formats" + "
RB = Rollback allowed" - + "
PC = Planechase active" + + "
PC = Planechase active" + + "
EC = One or more emblem cards in use" + "
SP = Spectators allowed" + "
Rng: Range of visibility for multiplayer matches" ) diff --git a/Mage.Common/src/main/java/mage/view/TableView.java b/Mage.Common/src/main/java/mage/view/TableView.java index 32d09ee79a2b..22e3bb75e092 100644 --- a/Mage.Common/src/main/java/mage/view/TableView.java +++ b/Mage.Common/src/main/java/mage/view/TableView.java @@ -111,6 +111,10 @@ public TableView(Table table) { 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"); } @@ -166,6 +170,10 @@ public TableView(Table table) { if (table.getTournament().getOptions().getMatchOptions().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"); } diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 3d91adbff26b..7468a1950fd4 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -628,6 +628,8 @@ private void startGame(UUID choosingPlayerId) throws GameException { 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; diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index a721ae1c49ed..9d40064b1fd8 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1455,4 +1455,10 @@ public boolean caresAboutManaColor() { .filter(Objects::nonNull) .anyMatch(Condition::caresAboutManaColor); } + + public AbilityImpl copyWithZone(Zone zone) { + AbilityImpl copy = ((AbilityImpl)this.copy()); + copy.zone = zone; + return copy; + } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index b438e9c47f03..0e6f7f70891c 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -41,6 +41,7 @@ import mage.game.combat.CombatGroup; import mage.game.command.*; import mage.game.command.dungeons.UndercityDungeon; +import mage.game.command.emblems.EmblemOfCard; import mage.game.command.emblems.TheRingEmblem; import mage.game.events.*; import mage.game.events.TableEvent.EventType; @@ -1310,6 +1311,24 @@ protected void init(UUID choosingPlayerId) { addPlane(plane, startingPlayerId); state.setPlaneChase(this, gameOptions.planeChase); } + + if (!gameOptions.perPlayerEmblemCards.isEmpty()) { + for (UUID playerId : state.getPlayerList(startingPlayerId)) { + for (Card card : gameOptions.perPlayerEmblemCards) { + logger.info("Creating emblem for " + card.getLogName() + " (player: " + playerId + ")"); + addEmblem(new EmblemOfCard(card), card, playerId); + logger.info("Created."); + } + } + } + + if (!gameOptions.globalEmblemCards.isEmpty()) { + for (Card card : gameOptions.globalEmblemCards) { + logger.info("Creating emblem for " + card.getLogName() + " (player: " + startingPlayerId + ")"); + addEmblem(new EmblemOfCard(card), card, startingPlayerId); + logger.info("Created."); + } + } } public void initGameDefaultWatchers() { @@ -1843,15 +1862,24 @@ public void addEmblem(Emblem emblem, MageObject sourceObject, Ability source) { */ @Override public void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId) { + logger.info("Copying..."); + logger.info("Original class: " + emblem.getClass().getName()); Emblem newEmblem = emblem.copy(); + logger.info("Copy class: " + newEmblem.getClass().getName()); + logger.info("Setting source object..."); newEmblem.setSourceObject(sourceObject); + logger.info("Setting controller ID..."); newEmblem.setControllerId(toPlayerId); + logger.info("Assigning new ID..."); newEmblem.assignNewId(); + logger.info("Assigning new abilities ID..."); newEmblem.getAbilities().newId(); for (Ability ability : newEmblem.getAbilities()) { + logger.info("Setting source ID for ability \"" + ability.getRule() + "\"..."); ability.setSourceId(newEmblem.getId()); } + logger.info("Adding command object..."); state.addCommandObject(newEmblem); // TODO: generate image for emblem here? } diff --git a/Mage/src/main/java/mage/game/GameOptions.java b/Mage/src/main/java/mage/game/GameOptions.java index 918b05fd6c9c..21a1c430cec2 100644 --- a/Mage/src/main/java/mage/game/GameOptions.java +++ b/Mage/src/main/java/mage/game/GameOptions.java @@ -2,9 +2,12 @@ import mage.constants.PhaseStep; import mage.util.Copyable; +import mage.cards.Card; import java.io.Serializable; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Set; /** @@ -52,6 +55,15 @@ public static GameOptions getDefault() { */ public Set bannedUsers = Collections.emptySet(); + /** + * Cards to be given to each player as emblems + */ + public Collection perPlayerEmblemCards = Collections.emptySet(); + /** + * Cards to be given to the starting player as emblems + */ + public Collection globalEmblemCards = Collections.emptySet(); + // PLANECHASE game mode public boolean planeChase = false; @@ -73,6 +85,8 @@ private GameOptions(final GameOptions options) { this.rollbackTurnsAllowed = options.rollbackTurnsAllowed; this.bannedUsers.addAll(options.bannedUsers); this.planeChase = options.planeChase; + this.perPlayerEmblemCards = new HashSet<>(options.perPlayerEmblemCards); + this.globalEmblemCards = new HashSet<>(options.globalEmblemCards); } @Override diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java new file mode 100644 index 000000000000..f0c71ba5b7bb --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -0,0 +1,68 @@ +package mage.game.command.emblems; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.AbilityImpl; +import mage.abilities.StaticAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.cards.Card; +import mage.cards.decks.importer.CardLookup; +import mage.cards.mock.MockCard; +import mage.constants.Zone; +import mage.game.GameImpl; +import mage.game.command.Emblem; +import org.apache.log4j.Logger; + +import java.lang.reflect.Field; +import java.util.stream.Collectors; + +public final class EmblemOfCard extends Emblem { + private static final Logger logger = Logger.getLogger(EmblemOfCard.class); + public EmblemOfCard(Card card, Zone zone) { + super(card.getName()); + if (card instanceof MockCard) { + MockCard mock = (MockCard)card; + card = CardLookup.instance.lookupCardInfo(card.getName(), card.getExpansionSetCode(), card.getCardNumber()) + .orElseThrow(() -> new IllegalArgumentException("No real card for mock card " + mock.getFullName(true))) + .getCard(); + } + this.getAbilities().addAll(card.getAbilities().stream().filter( + ability -> ability.getZone() == zone || ability.getZone() == Zone.ALL + ).map(ability -> { + if (ability instanceof AbilityImpl && ability.getZone() == zone) { + return ((AbilityImpl)ability).copyWithZone(Zone.COMMAND); + } + return ability; + }).collect(Collectors.toList())); + this.getAbilities().setSourceId(this.getId()); + this.setExpansionSetCode(card.getExpansionSetCode()); + this.setCardNumber(card.getCardNumber()); + this.setImageNumber(card.getImageNumber()); + } + public EmblemOfCard(Card card) { + this(card, Zone.BATTLEFIELD); + } + + public EmblemOfCard(EmblemOfCard eoc) { + super(eoc); + } + @Override + public Emblem copy() { + return new EmblemOfCard(this); + } + + @Override + public void setSourceObject(MageObject sourceObject) { + logger.info("In override setSourceObject"); + try { + super.setSourceObject(sourceObject); + } + catch (IllegalArgumentException e) { + logger.info("caught exception from base class"); + // happens because this isn't a real emblem, but the source object gets set before throwing so it's fine + } + } +} + diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index 0fd193193e38..c244454fc5ad 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -1,6 +1,7 @@ package mage.game.match; +import mage.cards.Card; import mage.constants.MatchTimeLimit; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; @@ -10,10 +11,7 @@ import mage.players.PlayerType; import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @@ -50,6 +48,9 @@ public class MatchOptions implements Serializable { protected MatchTimeLimit matchTimeLimit; // 0 = no priorityTime handling protected MulliganType mulliganType; + protected Collection perPlayerEmblemCards; + protected Collection globalEmblemCards; + /*public MatchOptions(String name, String gameType) { this.name = name; this.gameType = gameType; @@ -271,4 +272,19 @@ public MulliganType getMulliganType() { return mulliganType; } + public Collection getPerPlayerEmblemCards() { + return perPlayerEmblemCards; + } + + public void setPerPlayerEmblemCards(Collection perPlayerEmblemCards) { + this.perPlayerEmblemCards = perPlayerEmblemCards; + } + + public Collection getGlobalEmblemCards() { + return globalEmblemCards; + } + + public void setGlobalEmblemCards(Collection globalEmblemCards) { + this.globalEmblemCards = globalEmblemCards; + } } From a842dc844ee730716498b17fae00567f899934b2 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Mon, 19 Jun 2023 23:24:35 -0500 Subject: [PATCH 02/17] fixes --- .../mage/game/command/emblems/EmblemOfCard.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index f0c71ba5b7bb..5df5ca576dc4 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -1,21 +1,14 @@ package mage.game.command.emblems; import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.AbilityImpl; -import mage.abilities.StaticAbility; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.cards.Card; import mage.cards.decks.importer.CardLookup; import mage.cards.mock.MockCard; import mage.constants.Zone; -import mage.game.GameImpl; import mage.game.command.Emblem; import org.apache.log4j.Logger; -import java.lang.reflect.Field; import java.util.stream.Collectors; public final class EmblemOfCard extends Emblem { @@ -29,7 +22,7 @@ public EmblemOfCard(Card card, Zone zone) { .getCard(); } this.getAbilities().addAll(card.getAbilities().stream().filter( - ability -> ability.getZone() == zone || ability.getZone() == Zone.ALL + ability -> zone.match(ability.getZone()) ).map(ability -> { if (ability instanceof AbilityImpl && ability.getZone() == zone) { return ((AbilityImpl)ability).copyWithZone(Zone.COMMAND); @@ -45,7 +38,7 @@ public EmblemOfCard(Card card) { this(card, Zone.BATTLEFIELD); } - public EmblemOfCard(EmblemOfCard eoc) { + private EmblemOfCard(EmblemOfCard eoc) { super(eoc); } @Override @@ -55,12 +48,10 @@ public Emblem copy() { @Override public void setSourceObject(MageObject sourceObject) { - logger.info("In override setSourceObject"); try { super.setSourceObject(sourceObject); } catch (IllegalArgumentException e) { - logger.info("caught exception from base class"); // happens because this isn't a real emblem, but the source object gets set before throwing so it's fine } } From bd71a1254b9d6006c315d47e05ba93c7f3f936d2 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 20 Jun 2023 03:11:30 -0500 Subject: [PATCH 03/17] defaults for emblem cards in match options (fixes quick game buttons) --- Mage/src/main/java/mage/game/GameImpl.java | 13 ------------- .../src/main/java/mage/game/match/MatchOptions.java | 2 ++ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 0e6f7f70891c..838820919131 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1315,18 +1315,14 @@ protected void init(UUID choosingPlayerId) { if (!gameOptions.perPlayerEmblemCards.isEmpty()) { for (UUID playerId : state.getPlayerList(startingPlayerId)) { for (Card card : gameOptions.perPlayerEmblemCards) { - logger.info("Creating emblem for " + card.getLogName() + " (player: " + playerId + ")"); addEmblem(new EmblemOfCard(card), card, playerId); - logger.info("Created."); } } } if (!gameOptions.globalEmblemCards.isEmpty()) { for (Card card : gameOptions.globalEmblemCards) { - logger.info("Creating emblem for " + card.getLogName() + " (player: " + startingPlayerId + ")"); addEmblem(new EmblemOfCard(card), card, startingPlayerId); - logger.info("Created."); } } } @@ -1862,24 +1858,15 @@ public void addEmblem(Emblem emblem, MageObject sourceObject, Ability source) { */ @Override public void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId) { - logger.info("Copying..."); - logger.info("Original class: " + emblem.getClass().getName()); Emblem newEmblem = emblem.copy(); - logger.info("Copy class: " + newEmblem.getClass().getName()); - logger.info("Setting source object..."); newEmblem.setSourceObject(sourceObject); - logger.info("Setting controller ID..."); newEmblem.setControllerId(toPlayerId); - logger.info("Assigning new ID..."); newEmblem.assignNewId(); - logger.info("Assigning new abilities ID..."); newEmblem.getAbilities().newId(); for (Ability ability : newEmblem.getAbilities()) { - logger.info("Setting source ID for ability \"" + ability.getRule() + "\"..."); ability.setSourceId(newEmblem.getId()); } - logger.info("Adding command object..."); state.addCommandObject(newEmblem); // TODO: generate image for emblem here? } diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index c244454fc5ad..37aaac6c5dda 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -64,6 +64,8 @@ public MatchOptions(String name, String gameType, boolean multiPlayer, int numSe this.password = ""; this.multiPlayer = multiPlayer; this.numSeats = numSeats; + this.perPlayerEmblemCards = Collections.emptySet(); + this.globalEmblemCards = Collections.emptySet(); } public void setNumSeats (int numSeats) { From 0022814fc2563ad7d4dc178a02dae04aa7e565e9 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 8 Aug 2023 22:57:56 -0500 Subject: [PATCH 04/17] minor fixes --- .../main/java/mage/client/dialog/CustomOptionsDialog.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java index 66fcdcb01ba0..e130184330d7 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java @@ -333,7 +333,7 @@ private void chkPlaneChaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN }//GEN-LAST:event_chkPlaneChaseActionPerformed private void chkEmblemCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkEmblemCardsActionPerformed - // TODO add your handling code here: + updateActiveCount(); }//GEN-LAST:event_chkEmblemCardsActionPerformed private void btnEmblemCardsPerPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEmblemCardsPerPlayerActionPerformed @@ -446,6 +446,9 @@ public void writeMatchOptionsTo(MatchOptions options) { // copy the cards set so deck can be garbage collected options.setPerPlayerEmblemCards(new HashSet<>(perPlayerEmblemDeck.getCards())); } + else { + options.setPerPlayerEmblemCards(Collections.emptySet()); + } } if (!txtEmblemCardsStartingPlayer.getText().isEmpty()) { Deck startingPlayerEmblemDeck = null; @@ -459,6 +462,9 @@ public void writeMatchOptionsTo(MatchOptions options) { // copy the cards set so deck can be garbage collected options.setGlobalEmblemCards(new HashSet<>(startingPlayerEmblemDeck.getCards())); } + else { + options.setGlobalEmblemCards(Collections.emptySet()); + } } } else { From 08d7426d9313fb8674327141e58dab186de33775 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Fri, 11 Aug 2023 19:48:39 -0500 Subject: [PATCH 05/17] use DeckCardInfo instead of Card for emblem cards options --- .../client/dialog/CustomOptionsDialog.form | 18 ------------------ .../client/dialog/CustomOptionsDialog.java | 6 ++---- Mage/src/main/java/mage/game/GameImpl.java | 7 +++++-- Mage/src/main/java/mage/game/GameOptions.java | 6 +++--- .../game/command/emblems/EmblemOfCard.java | 6 ++++++ .../java/mage/game/match/MatchOptions.java | 14 +++++++------- 6 files changed, 23 insertions(+), 34 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form index c9b4f90015f8..3a682a6c0e1c 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form @@ -256,21 +256,11 @@ - - - - - - - - - - @@ -290,11 +280,6 @@ - - - - - @@ -302,9 +287,6 @@ - - - diff --git a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java index e130184330d7..ea06e7dced89 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java @@ -443,8 +443,7 @@ public void writeMatchOptionsTo(MatchOptions options) { } if (perPlayerEmblemDeck != null) { perPlayerEmblemDeck.clearLayouts(); - // copy the cards set so deck can be garbage collected - options.setPerPlayerEmblemCards(new HashSet<>(perPlayerEmblemDeck.getCards())); + options.setPerPlayerEmblemCards(perPlayerEmblemDeck.getDeckCardLists().getCards()); } else { options.setPerPlayerEmblemCards(Collections.emptySet()); @@ -459,8 +458,7 @@ public void writeMatchOptionsTo(MatchOptions options) { } if (startingPlayerEmblemDeck != null) { startingPlayerEmblemDeck.clearLayouts(); - // copy the cards set so deck can be garbage collected - options.setGlobalEmblemCards(new HashSet<>(startingPlayerEmblemDeck.getCards())); + options.setGlobalEmblemCards(startingPlayerEmblemDeck.getDeckCardLists().getCards()); } else { options.setGlobalEmblemCards(Collections.emptySet()); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 9bf436867ecb..661da6cd026c 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -22,6 +22,7 @@ import mage.actions.impl.MageAction; import mage.cards.*; import mage.cards.decks.Deck; +import mage.cards.decks.DeckCardInfo; import mage.choices.Choice; import mage.constants.*; import mage.counters.CounterType; @@ -1325,14 +1326,16 @@ protected void init(UUID choosingPlayerId) { if (!gameOptions.perPlayerEmblemCards.isEmpty()) { for (UUID playerId : state.getPlayerList(startingPlayerId)) { - for (Card card : gameOptions.perPlayerEmblemCards) { + for (DeckCardInfo info : gameOptions.perPlayerEmblemCards) { + Card card = EmblemOfCard.cardFromDeckInfo(info); addEmblem(new EmblemOfCard(card), card, playerId); } } } if (!gameOptions.globalEmblemCards.isEmpty()) { - for (Card card : gameOptions.globalEmblemCards) { + for (DeckCardInfo info : gameOptions.globalEmblemCards) { + Card card = EmblemOfCard.cardFromDeckInfo(info); addEmblem(new EmblemOfCard(card), card, startingPlayerId); } } diff --git a/Mage/src/main/java/mage/game/GameOptions.java b/Mage/src/main/java/mage/game/GameOptions.java index 21a1c430cec2..f9fe54a77278 100644 --- a/Mage/src/main/java/mage/game/GameOptions.java +++ b/Mage/src/main/java/mage/game/GameOptions.java @@ -1,8 +1,8 @@ package mage.game; +import mage.cards.decks.DeckCardInfo; import mage.constants.PhaseStep; import mage.util.Copyable; -import mage.cards.Card; import java.io.Serializable; import java.util.Collection; @@ -58,11 +58,11 @@ public static GameOptions getDefault() { /** * Cards to be given to each player as emblems */ - public Collection perPlayerEmblemCards = Collections.emptySet(); + public Collection perPlayerEmblemCards = Collections.emptySet(); /** * Cards to be given to the starting player as emblems */ - public Collection globalEmblemCards = Collections.emptySet(); + public Collection globalEmblemCards = Collections.emptySet(); // PLANECHASE game mode diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index 5df5ca576dc4..ba393614f87b 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -3,6 +3,7 @@ import mage.MageObject; import mage.abilities.AbilityImpl; import mage.cards.Card; +import mage.cards.decks.DeckCardInfo; import mage.cards.decks.importer.CardLookup; import mage.cards.mock.MockCard; import mage.constants.Zone; @@ -13,6 +14,11 @@ public final class EmblemOfCard extends Emblem { private static final Logger logger = Logger.getLogger(EmblemOfCard.class); + public static Card cardFromDeckInfo(DeckCardInfo info) { + return CardLookup.instance.lookupCardInfo(info.getCardName(), info.getSetCode(), info.getCardNum()) + .orElseThrow(() -> new IllegalArgumentException("No real card for DeckCardInfo" + info.getCardName())) + .getCard(); + } public EmblemOfCard(Card card, Zone zone) { super(card.getName()); if (card instanceof MockCard) { diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index 923a8cb0ff91..16047fc41a38 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -1,7 +1,7 @@ package mage.game.match; -import mage.cards.Card; +import mage.cards.decks.DeckCardInfo; import mage.constants.MatchBufferTime; import mage.constants.MatchTimeLimit; import mage.constants.MultiplayerAttackOption; @@ -50,8 +50,8 @@ public class MatchOptions implements Serializable { protected MatchBufferTime matchBufferTime; // Amount of time each player gets before their normal time limit counts down. Refreshes each time the normal timer is invoked. protected MulliganType mulliganType; - protected Collection perPlayerEmblemCards; - protected Collection globalEmblemCards; + protected Collection perPlayerEmblemCards; + protected Collection globalEmblemCards; /*public MatchOptions(String name, String gameType) { this.name = name; @@ -291,19 +291,19 @@ public MulliganType getMulliganType() { return mulliganType; } - public Collection getPerPlayerEmblemCards() { + public Collection getPerPlayerEmblemCards() { return perPlayerEmblemCards; } - public void setPerPlayerEmblemCards(Collection perPlayerEmblemCards) { + public void setPerPlayerEmblemCards(Collection perPlayerEmblemCards) { this.perPlayerEmblemCards = perPlayerEmblemCards; } - public Collection getGlobalEmblemCards() { + public Collection getGlobalEmblemCards() { return globalEmblemCards; } - public void setGlobalEmblemCards(Collection globalEmblemCards) { + public void setGlobalEmblemCards(Collection globalEmblemCards) { this.globalEmblemCards = globalEmblemCards; } } From 303327bffb77f7a7222f0290755b4530b6735184 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Fri, 11 Aug 2023 19:52:13 -0500 Subject: [PATCH 06/17] restore accessible parent properties --- .../client/dialog/CustomOptionsDialog.form | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form index 3a682a6c0e1c..c9b4f90015f8 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form @@ -256,11 +256,21 @@ + + + + + + + + + + @@ -280,6 +290,11 @@ + + + + + @@ -287,6 +302,9 @@ + + + From 03f72c8503a4e34f17a0497f4bd4e380108a6c5a Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Sat, 12 Aug 2023 14:34:01 -0500 Subject: [PATCH 07/17] fix images for card emblems --- .../src/main/java/mage/view/CardView.java | 5 +++-- .../src/main/java/mage/view/EmblemView.java | 19 ++++++++++++++++++- .../game/command/emblems/EmblemOfCard.java | 6 ++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 34db51e5225b..256308a647ca 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -705,8 +705,9 @@ public CardView(EmblemView emblem) { // emblem images are always with common (black) symbol this.frameStyle = FrameStyle.M15_NORMAL; this.expansionSetCode = emblem.getExpansionSetCode(); - this.cardNumber = ""; - this.imageNumber = 0; + this.cardNumber = emblem.getCardNumber(); + this.imageNumber = emblem.getImageNumber(); + this.usesVariousArt = emblem.getUsesVariousArt(); this.rarity = Rarity.COMMON; this.playableStats = emblem.playableStats.copy(); diff --git a/Mage.Common/src/main/java/mage/view/EmblemView.java b/Mage.Common/src/main/java/mage/view/EmblemView.java index 774d60784259..dd24c0d155cf 100644 --- a/Mage.Common/src/main/java/mage/view/EmblemView.java +++ b/Mage.Common/src/main/java/mage/view/EmblemView.java @@ -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; @@ -18,12 +18,20 @@ public class EmblemView implements CommandObjectView, Serializable { protected String expansionSetCode; protected List rules; protected PlayableObjectStats playableStats = new PlayableObjectStats(); + protected String cardNumber = ""; + protected int imageNumber = 0; + protected boolean usesVariousArt = false; public EmblemView(Emblem emblem) { this.id = emblem.getId(); this.name = emblem.getName(); this.expansionSetCode = emblem.getExpansionSetCode(); this.rules = emblem.getAbilities().getRules(emblem.getName()); + if (emblem instanceof EmblemOfCard) { + cardNumber = emblem.getCardNumber(); + imageNumber = emblem.getImageNumber(); + usesVariousArt = ((EmblemOfCard) emblem).getUsesVariousArt(); + } } @Override @@ -82,4 +90,13 @@ public boolean isSelected() { public void setSelected(boolean isSelected) { // unsupported } + public String getCardNumber() { + return cardNumber; + } + public int getImageNumber() { + return imageNumber; + } + public boolean getUsesVariousArt() { + return this.usesVariousArt; + } } diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index ba393614f87b..0c5086917fab 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -13,6 +13,7 @@ import java.util.stream.Collectors; public final class EmblemOfCard extends Emblem { + private boolean usesVariousArt; private static final Logger logger = Logger.getLogger(EmblemOfCard.class); public static Card cardFromDeckInfo(DeckCardInfo info) { return CardLookup.instance.lookupCardInfo(info.getCardName(), info.getSetCode(), info.getCardNum()) @@ -39,6 +40,7 @@ public EmblemOfCard(Card card, Zone zone) { this.setExpansionSetCode(card.getExpansionSetCode()); this.setCardNumber(card.getCardNumber()); this.setImageNumber(card.getImageNumber()); + this.usesVariousArt = card.getUsesVariousArt(); } public EmblemOfCard(Card card) { this(card, Zone.BATTLEFIELD); @@ -46,6 +48,7 @@ public EmblemOfCard(Card card) { private EmblemOfCard(EmblemOfCard eoc) { super(eoc); + this.usesVariousArt = eoc.usesVariousArt; } @Override public Emblem copy() { @@ -61,5 +64,8 @@ public void setSourceObject(MageObject sourceObject) { // happens because this isn't a real emblem, but the source object gets set before throwing so it's fine } } + public boolean getUsesVariousArt() { + return usesVariousArt; + } } From ff65b261ccb95fa8dc68d9a19d11f83dac1da2bd Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Sat, 12 Aug 2023 16:46:32 -0500 Subject: [PATCH 08/17] look up cards in a way that preserves which art --- .../game/command/emblems/EmblemOfCard.java | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index 0c5086917fab..a8084f1b5b19 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -4,29 +4,58 @@ import mage.abilities.AbilityImpl; import mage.cards.Card; import mage.cards.decks.DeckCardInfo; -import mage.cards.decks.importer.CardLookup; import mage.cards.mock.MockCard; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.constants.Zone; import mage.game.command.Emblem; +import mage.util.CardUtil; import org.apache.log4j.Logger; +import java.util.List; import java.util.stream.Collectors; public final class EmblemOfCard extends Emblem { private boolean usesVariousArt; private static final Logger logger = Logger.getLogger(EmblemOfCard.class); - public static Card cardFromDeckInfo(DeckCardInfo info) { - return CardLookup.instance.lookupCardInfo(info.getCardName(), info.getSetCode(), info.getCardNum()) - .orElseThrow(() -> new IllegalArgumentException("No real card for DeckCardInfo" + info.getCardName())) + public static Card lookupCard( + String cardName, + String cardNumber, + String setCode, + String infoTypeForError + ) { + int cardNumberInt = CardUtil.parseCardNumberAsInt(cardNumber); + List found = CardRepository.instance.findCards(new CardCriteria() + .name(cardName) + .minCardNumber(cardNumberInt) + .maxCardNumber(cardNumberInt) + .setCodes(setCode); + return found.stream() + .filter(ci -> ci.getCardNumber().equals(cardNumber)) + .findFirst() + .orElseGet(() -> found.stream() + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("No real card for " + infoTypeForError + " " + cardName))) .getCard(); } + public static Card cardFromDeckInfo(DeckCardInfo info) { + return lookupCard( + info.getCardName(), + info.getCardNum(), + info.getSetCode(), + "DeckCardInfo" + ) + } public EmblemOfCard(Card card, Zone zone) { super(card.getName()); if (card instanceof MockCard) { - MockCard mock = (MockCard)card; - card = CardLookup.instance.lookupCardInfo(card.getName(), card.getExpansionSetCode(), card.getCardNumber()) - .orElseThrow(() -> new IllegalArgumentException("No real card for mock card " + mock.getFullName(true))) - .getCard(); + card = lookupCard( + card.getName(), + card.getCardNumber() + card.getExpansionSetCode(), + "MockCard" + ); } this.getAbilities().addAll(card.getAbilities().stream().filter( ability -> zone.match(ability.getZone()) From 583850e379869d936d303091d73060c76212b724 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Sat, 12 Aug 2023 17:09:15 -0500 Subject: [PATCH 09/17] fix typos; make Emblem.sourceObject protected --- Mage/src/main/java/mage/game/command/Emblem.java | 2 +- .../mage/game/command/emblems/EmblemOfCard.java | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index 7ca863fd12cf..b34bb6ba2f7a 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -33,7 +33,7 @@ public abstract class Emblem extends CommandObjectImpl { private static final ManaCosts emptyCost = new ManaCostsImpl<>(); private UUID controllerId; - private MageObject sourceObject; + protected MageObject sourceObject; private boolean copy; private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index a8084f1b5b19..36133aae7017 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -30,7 +30,7 @@ public static Card lookupCard( .name(cardName) .minCardNumber(cardNumberInt) .maxCardNumber(cardNumberInt) - .setCodes(setCode); + .setCodes(setCode)); return found.stream() .filter(ci -> ci.getCardNumber().equals(cardNumber)) .findFirst() @@ -45,14 +45,14 @@ public static Card cardFromDeckInfo(DeckCardInfo info) { info.getCardNum(), info.getSetCode(), "DeckCardInfo" - ) + ); } public EmblemOfCard(Card card, Zone zone) { super(card.getName()); if (card instanceof MockCard) { card = lookupCard( card.getName(), - card.getCardNumber() + card.getCardNumber(), card.getExpansionSetCode(), "MockCard" ); @@ -86,12 +86,7 @@ public Emblem copy() { @Override public void setSourceObject(MageObject sourceObject) { - try { - super.setSourceObject(sourceObject); - } - catch (IllegalArgumentException e) { - // happens because this isn't a real emblem, but the source object gets set before throwing so it's fine - } + this.sourceObject = sourceObject; } public boolean getUsesVariousArt() { return usesVariousArt; From 090c662efd35438181ea6dad2393df0df9ce3d77 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Sat, 12 Aug 2023 18:04:00 -0500 Subject: [PATCH 10/17] add descriptions to planechase and emblem cards --- .../client/dialog/CustomOptionsDialog.form | 106 +++++++++--------- .../client/dialog/CustomOptionsDialog.java | 76 +++++++------ 2 files changed, 96 insertions(+), 86 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form index c9b4f90015f8..ee584f9b3257 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.form @@ -25,53 +25,49 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + - - - - - + + - - - - - - - @@ -95,9 +91,15 @@ - + + + + + + + @@ -117,13 +119,6 @@ - - - - - - - @@ -216,7 +211,7 @@ - + @@ -228,6 +223,19 @@ + + + + + + + + + + + + + @@ -245,7 +253,7 @@ - + @@ -256,21 +264,11 @@ - - - - - - - - - - @@ -290,11 +288,6 @@ - - - - - @@ -302,9 +295,6 @@ - - - @@ -321,5 +311,15 @@ + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java index ea06e7dced89..29d4759abfb3 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/CustomOptionsDialog.java @@ -107,6 +107,7 @@ private void initComponents() { 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(); @@ -117,6 +118,7 @@ private void initComponents() { btnEmblemCardsStartingPlayer = new javax.swing.JButton(); txtEmblemCardsStartingPlayer = new javax.swing.JTextField(); lblEmblemCardsStartingPlayer = new javax.swing.JLabel(); + emblemCardsDescriptionLabel = new javax.swing.JLabel(); setTitle("Custom Options"); @@ -147,7 +149,7 @@ public void stateChanged(javax.swing.event.ChangeEvent evt) { 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) { @@ -155,6 +157,9 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { } }); + planechaseDescriptionLabel.setText("Shared planar deck of all implemented planes.
Uses a 9-sided planar die with 2 planeswalk sides and 2 chaos sides.
Some ability text may be incorrect.
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) { @@ -163,7 +168,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); chkEmblemCards.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N - chkEmblemCards.setText("Emblem Cards"); + 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) { @@ -203,6 +208,9 @@ public void actionPerformed(java.awt.event.ActionEvent 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("Give players emblems with the abilities of cards.
Note that some abilities may not function correctly from the command zone.
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( @@ -210,42 +218,40 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jSeparator4, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(lblMulliganType) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbMulliganType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblFreeMulligans) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)) + .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(layout.createSequentialGroup() + .addComponent(lblFreeMulligans) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnFreeMulligans)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(chkPlaneChase) - .addComponent(lblGeneralOptions) .addComponent(lblVariantOptions) + .addComponent(chkPlaneChase) .addComponent(chkEmblemCards) .addComponent(lblEmblemCardsPerPlayer) - .addComponent(lblEmblemCardsStartingPlayer)) + .addComponent(lblEmblemCardsStartingPlayer) + .addComponent(lblGeneralOptions)) .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(txtEmblemCardsStartingPlayer) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnEmblemCardsStartingPlayer, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(planechaseDescriptionLabel) + .addComponent(emblemCardsDescriptionLabel)) .addContainerGap()) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jSeparator3) - .addContainerGap())) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -266,9 +272,15 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addComponent(lblVariantOptions) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(chkPlaneChase) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .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) @@ -285,11 +297,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addGap(0, 0, 0) .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(147, 147, 147) - .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(176, Short.MAX_VALUE))) ); lblMulliganType.getAccessibleContext().setAccessibleName("Mulligan Type:"); @@ -302,13 +309,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { spnFreeMulligans.getAccessibleContext().setAccessibleDescription("Select the number of free mulligans"); spnFreeMulligans.getAccessibleContext().setAccessibleParent(lblFreeMulligans); chkPlaneChase.getAccessibleContext().setAccessibleParent(lblVariantOptions); - btnEmblemCardsPerPlayer.getAccessibleContext().setAccessibleParent(txtEmblemCardsPerPlayer); - txtEmblemCardsPerPlayer.getAccessibleContext().setAccessibleParent(lblEmblemCardsPerPlayer); + 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); - btnEmblemCardsStartingPlayer.getAccessibleContext().setAccessibleParent(txtEmblemCardsStartingPlayer); txtEmblemCardsStartingPlayer.getAccessibleContext().setAccessibleDescription(""); - txtEmblemCardsStartingPlayer.getAccessibleContext().setAccessibleParent(lblEmblemCardsStartingPlayer); 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(); }// //GEN-END:initComponents @@ -492,6 +500,7 @@ public void updateActiveCount() { private javax.swing.JComboBox 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; @@ -501,6 +510,7 @@ public void updateActiveCount() { 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; From ad605eb0f53ff7dd513b92a9d5306659ff342c03 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Mon, 18 Sep 2023 01:06:26 -0500 Subject: [PATCH 11/17] fixes --- .../java/mage/game/command/emblems/EmblemOfCard.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index 36133aae7017..65014b10e208 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -17,8 +17,9 @@ import java.util.stream.Collectors; public final class EmblemOfCard extends Emblem { - private boolean usesVariousArt; + private final boolean usesVariousArt; private static final Logger logger = Logger.getLogger(EmblemOfCard.class); + public static Card lookupCard( String cardName, String cardNumber, @@ -39,6 +40,7 @@ public static Card lookupCard( .orElseThrow(() -> new IllegalArgumentException("No real card for " + infoTypeForError + " " + cardName))) .getCard(); } + public static Card cardFromDeckInfo(DeckCardInfo info) { return lookupCard( info.getCardName(), @@ -47,6 +49,7 @@ public static Card cardFromDeckInfo(DeckCardInfo info) { "DeckCardInfo" ); } + public EmblemOfCard(Card card, Zone zone) { super(card.getName()); if (card instanceof MockCard) { @@ -71,6 +74,7 @@ public EmblemOfCard(Card card, Zone zone) { this.setImageNumber(card.getImageNumber()); this.usesVariousArt = card.getUsesVariousArt(); } + public EmblemOfCard(Card card) { this(card, Zone.BATTLEFIELD); } @@ -80,14 +84,17 @@ private EmblemOfCard(EmblemOfCard eoc) { this.usesVariousArt = eoc.usesVariousArt; } @Override - public Emblem copy() { + public EmblemOfCard copy() { return new EmblemOfCard(this); } @Override public void setSourceObject(MageObject sourceObject) { this.sourceObject = sourceObject; + // super method would try and fail to find the emblem image here + // (not sure why that would be setSoureObject's job; we get our image during construction) } + public boolean getUsesVariousArt() { return usesVariousArt; } From 10aa6e8470b49d7ed660df7068d661e7508393ae Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 19 Sep 2023 21:23:15 -0500 Subject: [PATCH 12/17] add some unit tests for known working cards --- .../test/cards/emblems/EmblemOfCardTest.java | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java new file mode 100644 index 000000000000..f0f393a4234a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java @@ -0,0 +1,179 @@ +package org.mage.test.cards.emblems; + +import mage.cards.Card; +import mage.cards.repository.CardRepository; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.command.emblems.EmblemOfCard; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author noxx + */ +public class EmblemOfCardTest extends CardTestPlayerBase { + + @Test + public void testEmblemOfGriselbrand() { + // Flying, lifelink + // Pay 7 life: Draw seven cards. + addEmblem(playerA, new EmblemOfCard( + CardRepository.instance.findCard("Griselbrand", true).getMockCard() + )); + + setLife(playerA, 20); + + assertHandCount(playerA, 0); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pay 7 life: Draw"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertHandCount(playerA, 7); + assertLife(playerA, 13); + } + @Test + public void testEmblemOfYurlok() { + // Vigilance + // A player losing unspent mana causes that player to lose that much life. + // {1}, {T}: Each player adds {B}{R}{G}. + addEmblem(playerA, new EmblemOfCard( + CardRepository.instance.findCard("Yurlok of Scorch Thrash", true).getMockCard() + )); + + setLife(playerA, 20); + + // {T}: Add {R}. + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); + + checkManaPool("after tapping Mountain", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1); + checkPlayableAbility("can't tap emblem", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}:", false); + + execute(); + + // wait for mana burn + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + checkLife("takes 1 point of mana burn", 1, PhaseStep.BEGIN_COMBAT, playerA, 19); + } + + @Test + public void testEmblemOfOmniscience() { + // You may cast spells from your hand without paying their mana costs. + addEmblem(playerA, new EmblemOfCard( + CardRepository.instance.findCard("Omniscience", true).getMockCard() + )); + + // Colossal Dreadmaw {4}{G}{G} + // Creature - Dinosaur 6/6 + // Trample + addCard(Zone.HAND, playerA, "Colossal Dreadmaw"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Colossal Dreadmaw"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + assertPermanentCount(playerA, "Colossal Dreadmaw", 1); + } + @Test + public void testEmblemOfParadoxEngine() { + // Whenever you cast a spell, untap all nonland permanents you control. + addEmblem(playerA, new EmblemOfCard( + CardRepository.instance.findCard("Paradox Engine", true).getMockCard() + )); + + // {T}: Add {G}. + addCard(Zone.BATTLEFIELD, playerA, "Mox Emerald"); + + // Sol Ring {1} + // Artifact + // {T}: Add {C}{C}. + addCard(Zone.HAND, playerA, "Sol Ring"); + + // Basalt Monolith {3} + // Artifact + // Basalt Monolith doesn’t untap during your untap step. + // {T}: Add {C}{C}{C}. + // {3}: Untap Basalt Monolith. + addCard(Zone.HAND, playerA, "Basalt Monolith"); + + // Book of Rass {6} + // Artifact + // {2}, Pay 2 life: Draw a card. + // (just a dummy artifact to cast and spend the mana with) + addCard(Zone.HAND, playerA, "Book of Rass"); + + setLife(playerA, 20); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sol Ring"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basalt Monolith"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Book of Rass"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, Pay"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, Pay"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, Pay"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 14); + } + @Test + public void testEmblemOfDoublingSeason() { + // If an effect would create one or more tokens under your control, it + // creates twice that many of those tokens instead. + // If an effect would put one or more counters on a permanent you + // control, it puts twice that many of those counters on that permanent instead. + addEmblem(playerA, new EmblemOfCard( + CardRepository.instance.findCard("Doubling Season", true).getMockCard() + )); + + // {T}: Add {W}. + addCard(Zone.BATTLEFIELD, playerA, "Plains", 6); + + // Elspeth, Sun's Champion {4}{W}{W} + // Legendary Planeswalker — Elspeth + // +1: Create three 1/1 white Soldier creature tokens. + // −3: Destroy all creatures with power 4 or greater. + // −7: You get an emblem with “Creatures you control get +2/+2 and have flying.” + // Loyalty: 4 + addCard(Zone.HAND, playerA, "Elspeth, Sun's Champion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elspeth, Sun's Champion"); + checkCardCounters( + "Elspeth's loyalty is doubled", + 1, + PhaseStep.PRECOMBAT_MAIN, + playerA, + "Elspeth, Sun's Champion", + CounterType.LOYALTY, + 8 + ); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Create"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkCardCounters( + "+1 is not doubled", + 1, + PhaseStep.PRECOMBAT_MAIN, + playerA, + "Elspeth, Sun's Champion", + CounterType.LOYALTY, + 9 + ); + checkPermanentCount( + "Soldier tokens doubled", + 1, + PhaseStep.PRECOMBAT_MAIN, + playerA, + "Soldier Token", + 6 + ); + } +} From 21f02bccf5b60e93a67462d3f547c67b5ce885cf Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 19 Sep 2023 21:23:45 -0500 Subject: [PATCH 13/17] fix author name --- .../test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java index f0f393a4234a..394eefc46bbc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java @@ -11,7 +11,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** - * @author noxx + * @author Arti */ public class EmblemOfCardTest extends CardTestPlayerBase { From 3b41d12f247b5041f2da70e89cdc3c0c221ee271 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 19 Sep 2023 21:32:43 -0500 Subject: [PATCH 14/17] add explanation comment --- .../java/org/mage/test/cards/emblems/EmblemOfCardTest.java | 4 +--- .../main/java/mage/game/command/emblems/EmblemOfCard.java | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java index 394eefc46bbc..1e52c2c8e4a8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java @@ -1,17 +1,15 @@ package org.mage.test.cards.emblems; -import mage.cards.Card; import mage.cards.repository.CardRepository; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.command.emblems.EmblemOfCard; -import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * @author Arti + * @author artemiswkearney */ public class EmblemOfCardTest extends CardTestPlayerBase { diff --git a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java index 65014b10e208..74c16dbb2e2a 100644 --- a/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java +++ b/Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java @@ -16,6 +16,12 @@ import java.util.List; import java.util.stream.Collectors; +/** + * @author artemiswkearney + * Emblem with all the abilities of an existing card. + * Can be used for custom gamemodes like Omniscience Draft (as seen on Arena), + * mana burn with Yurlok of Scorch Thrash, and anything else players might think of. + */ public final class EmblemOfCard extends Emblem { private final boolean usesVariousArt; private static final Logger logger = Logger.getLogger(EmblemOfCard.class); From 5048ec8a9be5e78f53ba88fd602481a08f9bce8c Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 19 Sep 2023 23:45:12 -0500 Subject: [PATCH 15/17] fix up tests --- .../test/cards/emblems/EmblemOfCardTest.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java index 1e52c2c8e4a8..e480a360f994 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemOfCardTest.java @@ -31,6 +31,7 @@ public void testEmblemOfGriselbrand() { assertHandCount(playerA, 7); assertLife(playerA, 13); + assertEmblemCount(playerA, 1); } @Test public void testEmblemOfYurlok() { @@ -51,13 +52,13 @@ public void testEmblemOfYurlok() { checkManaPool("after tapping Mountain", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1); checkPlayableAbility("can't tap emblem", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}:", false); - execute(); - // wait for mana burn setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); checkLife("takes 1 point of mana burn", 1, PhaseStep.BEGIN_COMBAT, playerA, 19); + execute(); + + assertEmblemCount(playerA, 1); } @Test @@ -76,6 +77,7 @@ public void testEmblemOfOmniscience() { setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); assertPermanentCount(playerA, "Colossal Dreadmaw", 1); + assertEmblemCount(playerA, 1); } @Test public void testEmblemOfParadoxEngine() { @@ -122,6 +124,7 @@ public void testEmblemOfParadoxEngine() { execute(); assertLife(playerA, 14); + assertEmblemCount(playerA, 1); } @Test public void testEmblemOfDoublingSeason() { @@ -145,7 +148,8 @@ public void testEmblemOfDoublingSeason() { addCard(Zone.HAND, playerA, "Elspeth, Sun's Champion"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elspeth, Sun's Champion"); - checkCardCounters( + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCounters( "Elspeth's loyalty is doubled", 1, PhaseStep.PRECOMBAT_MAIN, @@ -155,8 +159,9 @@ public void testEmblemOfDoublingSeason() { 8 ); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Create"); + checkPlayableAbility("can't still activate Griselbrand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pay 7 life:", false); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkCardCounters( + checkPermanentCounters( "+1 is not doubled", 1, PhaseStep.PRECOMBAT_MAIN, @@ -173,5 +178,7 @@ public void testEmblemOfDoublingSeason() { "Soldier Token", 6 ); + execute(); + assertEmblemCount(playerA, 1); } } From 5c2ee31248022b5589cb4f9d442ec3900dc6784a Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Tue, 19 Sep 2023 23:45:43 -0500 Subject: [PATCH 16/17] copyWithZone: no longer modifies zone for singleton abilities --- Mage/src/main/java/mage/abilities/AbilityImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 3d0a830b9647..38ce00639e20 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1482,6 +1482,10 @@ public boolean caresAboutManaColor() { public AbilityImpl copyWithZone(Zone zone) { AbilityImpl copy = ((AbilityImpl)this.copy()); + if (copy == this) { + // singleton, not safe to change its zone + return this; + } copy.zone = zone; copy.newId(); return copy; From 8e38bb7630466267a1f5dc095d878eda650c5f94 Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Wed, 20 Sep 2023 14:09:03 -0500 Subject: [PATCH 17/17] directly check for MageSingleton --- Mage/src/main/java/mage/abilities/AbilityImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 38ce00639e20..f68a131b98ae 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1481,11 +1481,14 @@ public boolean caresAboutManaColor() { } public AbilityImpl copyWithZone(Zone zone) { - AbilityImpl copy = ((AbilityImpl)this.copy()); - if (copy == this) { - // singleton, not safe to change its zone + if (this instanceof MageSingleton) { + // not safe to change zone for singletons + // in theory there could be some sort of wrapper to effectively change + // the zone here, but currently no use of copyWithZone actually needs + // to change the zone of any existing singleton abilities return this; } + AbilityImpl copy = ((AbilityImpl)this.copy()); copy.zone = zone; copy.newId(); return copy;