Merge pull request #1 from magefree/master

Merge magefree/mage
This commit is contained in:
Eirkei 2016-09-24 19:26:43 +02:00 committed by GitHub
commit 738c11a0e3
64 changed files with 751 additions and 261 deletions

View file

@ -378,7 +378,7 @@ public class NewTableDialog extends MageDialog {
private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem();
MatchOptions options = new MatchOptions(this.txtName.getText(), gameType.getName()); MatchOptions options = new MatchOptions(this.txtName.getText(), gameType.getName(), false, 2);
options.getPlayerTypes().add("Human"); options.getPlayerTypes().add("Human");
for (TablePlayerPanel player : players) { for (TablePlayerPanel player : players) {
options.getPlayerTypes().add(player.getPlayerType()); options.getPlayerTypes().add(player.getPlayerType());

View file

@ -29,11 +29,8 @@
<Component id="pnlPacks" alignment="1" max="32767" attributes="0"/> <Component id="pnlPacks" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> <Component id="lblNbrPlayers" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="spnNumPlayers" min="-2" pref="46" max="-2" attributes="0"/> </Group>
<Component id="lblNbrPlayers" min="-2" max="-2" attributes="0"/> <Group type="102" alignment="0" attributes="0"> <Component id="lblNbrSeats" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="spnNumSeats" min="-2" pref="46" max="-2" attributes="0"/> </Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="spnNumPlayers" min="-2" pref="46" max="-2" attributes="0"/>
</Group>
<Component id="lblPacks" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="lblPacks" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblPlayer1" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="lblPlayer1" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
@ -175,6 +172,7 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="lblPacks" min="-2" max="-2" attributes="0"/> <Component id="lblPacks" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Component id="pnlPacks" min="-2" max="-2" attributes="0"/> <Component id="pnlPacks" min="-2" max="-2" attributes="0"/>
@ -192,6 +190,11 @@
<Component id="pnlDraftOptions" alignment="1" pref="0" max="32767" attributes="1"/> <Component id="pnlDraftOptions" alignment="1" pref="0" max="32767" attributes="1"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="lblNbrSeats" alignment="1" max="32767" attributes="0"/>
<Component id="spnNumSeats" alignment="1" max="32767" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblPlayer1" min="-2" pref="25" max="-2" attributes="0"/> <Component id="lblPlayer1" min="-2" pref="25" max="-2" attributes="0"/>
</Group> </Group>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
@ -200,6 +203,7 @@
<Component id="chkRollbackTurnsAllowed" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="chkRollbackTurnsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="player1Panel" min="-2" pref="62" max="-2" attributes="0"/> <Component id="player1Panel" min="-2" pref="62" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -377,15 +381,17 @@
<Property name="rows" type="int" value="0"/> <Property name="rows" type="int" value="0"/>
</Layout> </Layout>
</Container> </Container>
<Component class="javax.swing.JLabel" name="lblNbrPlayers"> <Component class="javax.swing.JLabel" name="lblNbrPlayers"> <Properties> <Property name="text" type="java.lang.String" value="Players:"/> </Properties> </Component>
<Properties> <Component class="javax.swing.JLabel" name="lblNbrSeats"> <Properties> <Property name="text" type="java.lang.String" value="Seats:"/> </Properties> </Component>
<Property name="text" type="java.lang.String" value="Players:"/>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="spnNumPlayers"> <Component class="javax.swing.JSpinner" name="spnNumPlayers">
<Events> <Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnNumPlayersStateChanged"/> <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnNumPlayersStateChanged"/>
</Events> </Events>
</Component>
<Component class="javax.swing.JSpinner" name="spnNumSeats">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnNumSeatsStateChanged"/>
</Events>
</Component> </Component>
<Container class="javax.swing.JPanel" name="pnlDraftOptions"> <Container class="javax.swing.JPanel" name="pnlDraftOptions">

View file

@ -170,6 +170,8 @@ public class NewTournamentDialog extends MageDialog {
pnlPacks = new javax.swing.JPanel(); pnlPacks = new javax.swing.JPanel();
lblNbrPlayers = new javax.swing.JLabel(); lblNbrPlayers = new javax.swing.JLabel();
spnNumPlayers = new javax.swing.JSpinner(); spnNumPlayers = new javax.swing.JSpinner();
lblNbrSeats = new javax.swing.JLabel();
spnNumSeats = new javax.swing.JSpinner();
pnlDraftOptions = new javax.swing.JPanel(); pnlDraftOptions = new javax.swing.JPanel();
jLabel6 = new javax.swing.JLabel(); jLabel6 = new javax.swing.JLabel();
cbDraftTiming = new javax.swing.JComboBox(); cbDraftTiming = new javax.swing.JComboBox();
@ -277,6 +279,14 @@ public class NewTournamentDialog extends MageDialog {
} }
}); });
lblNbrSeats.setText("Seats:");
spnNumSeats.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
spnNumSeatsStateChanged(evt);
}
});
jLabel6.setText("Timing:"); 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" }));
@ -358,6 +368,8 @@ public class NewTournamentDialog extends MageDialog {
lblQuitRatio.setText("Allowed quit %:"); lblQuitRatio.setText("Allowed quit %:");
spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table"); spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table");
spnNumSeats.setToolTipText("The number of seats for each duel. If more than 2, will set number of wins to 1");
spnNumPlayers.setToolTipText("The total number of players who will draft");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout); getContentPane().setLayout(layout);
@ -373,7 +385,11 @@ public class NewTournamentDialog extends MageDialog {
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(lblNbrPlayers) .addComponent(lblNbrPlayers)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblNbrSeats)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnNumSeats, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lblPacks) .addComponent(lblPacks)
.addComponent(lblPlayer1)) .addComponent(lblPlayer1))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -504,6 +520,8 @@ public class NewTournamentDialog extends MageDialog {
.addComponent(lblNumRounds)) .addComponent(lblNumRounds))
.addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(spnNumPlayers) .addComponent(spnNumPlayers)
.addComponent(lblNbrSeats, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(spnNumSeats)
.addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
@ -533,7 +551,8 @@ public class NewTournamentDialog extends MageDialog {
private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem(); TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
TournamentOptions tOptions = new TournamentOptions(this.txtName.getText()); int numSeats = (Integer)this.spnNumSeats.getValue();
TournamentOptions tOptions = new TournamentOptions(this.txtName.getText(), "", numSeats);
tOptions.setTournamentType(tournamentType.getName()); tOptions.setTournamentType(tournamentType.getName());
tOptions.setPassword(txtPassword.getText()); tOptions.setPassword(txtPassword.getText());
tOptions.getPlayerTypes().add("Human"); tOptions.getPlayerTypes().add("Human");
@ -653,13 +672,51 @@ public class NewTournamentDialog extends MageDialog {
this.hideDialog(); this.hideDialog();
}//GEN-LAST:event_btnCancelActionPerformed }//GEN-LAST:event_btnCancelActionPerformed
private void updateNumSeats() {
int numPlayers = (Integer)this.spnNumPlayers.getValue();
int numSeats = (Integer)this.spnNumSeats.getValue();
if (numSeats > 2) {
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
if (numSeats >= tournamentType.getMinPlayers()) {
createPlayers(numSeats - 1);
spnNumPlayers.setValue(numSeats);
} else {
numSeats = tournamentType.getMinPlayers();
createPlayers(numSeats - 1);
spnNumPlayers.setValue(numSeats);
spnNumSeats.setValue(numSeats);
}
spnNumWins.setValue(1);
}
}
private void spnNumPlayersStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumPlayersStateChanged private void spnNumPlayersStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumPlayersStateChanged
int numPlayers = (Integer)this.spnNumPlayers.getValue() - 1; int numPlayers = (Integer)this.spnNumPlayers.getValue();
createPlayers(numPlayers); createPlayers(numPlayers - 1);
int numSeats = (Integer)this.spnNumSeats.getValue();
if (numSeats > 2 && numPlayers != numSeats) {
updateNumSeats();
}
}//GEN-LAST:event_spnNumPlayersStateChanged }//GEN-LAST:event_spnNumPlayersStateChanged
private void spnNumSeatsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumSeatsStateChanged
int numSeats = (Integer)this.spnNumSeats.getValue();
if (numSeats > 2) {
this.spnNumPlayers.setEnabled(false);
} else {
this.spnNumPlayers.setEnabled(true);
}
updateNumSeats();
}//GEN-LAST:event_spnNumSeatsStateChanged
private void spnNumWinsnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumWinsnumPlayersChanged private void spnNumWinsnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumWinsnumPlayersChanged
// TODO add your handling code here: int numSeats = (Integer)this.spnNumSeats.getValue();
int numWins = (Integer)this.spnNumSeats.getValue();
if (numSeats > 2) {
spnNumWins.setValue(1);
}
}//GEN-LAST:event_spnNumWinsnumPlayersChanged }//GEN-LAST:event_spnNumWinsnumPlayersChanged
private JFileChooser fcSelectDeck = null; private JFileChooser fcSelectDeck = null;
@ -726,6 +783,8 @@ public class NewTournamentDialog extends MageDialog {
this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers()); this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers());
createPlayers((Integer) spnNumPlayers.getValue() - 1); createPlayers((Integer) spnNumPlayers.getValue() - 1);
this.spnNumSeats.setModel(new SpinnerNumberModel(2, 2, tournamentType.getMaxPlayers(), 1));
if (tournamentType.isLimited()) { if (tournamentType.isLimited()) {
this.isRandom = tournamentType.isRandom(); this.isRandom = tournamentType.isRandom();
this.isRichMan = tournamentType.isRichMan(); this.isRichMan = tournamentType.isRichMan();
@ -914,6 +973,8 @@ public class NewTournamentDialog extends MageDialog {
} }
private void drawPlayers() { private void drawPlayers() {
this.pnlOtherPlayers.removeAll(); this.pnlOtherPlayers.removeAll();
for (TournamentPlayerPanel panel: players) { for (TournamentPlayerPanel panel: players) {
@ -1119,6 +1180,7 @@ public class NewTournamentDialog extends MageDialog {
private javax.swing.JLabel lblGameType; private javax.swing.JLabel lblGameType;
private javax.swing.JLabel lblName; private javax.swing.JLabel lblName;
private javax.swing.JLabel lblNbrPlayers; private javax.swing.JLabel lblNbrPlayers;
private javax.swing.JLabel lblNbrSeats;
private javax.swing.JLabel lblNumRounds; private javax.swing.JLabel lblNumRounds;
private javax.swing.JLabel lblNumWins; private javax.swing.JLabel lblNumWins;
private javax.swing.JLabel lblPacks; private javax.swing.JLabel lblPacks;
@ -1135,6 +1197,7 @@ public class NewTournamentDialog extends MageDialog {
private javax.swing.JSpinner spnConstructTime; private javax.swing.JSpinner spnConstructTime;
private javax.swing.JSpinner spnFreeMulligans; private javax.swing.JSpinner spnFreeMulligans;
private javax.swing.JSpinner spnNumPlayers; private javax.swing.JSpinner spnNumPlayers;
private javax.swing.JSpinner spnNumSeats;
private javax.swing.JSpinner spnNumRounds; private javax.swing.JSpinner spnNumRounds;
private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnNumWins;
private javax.swing.JSpinner spnQuitRatio; private javax.swing.JSpinner spnQuitRatio;

View file

@ -1272,7 +1272,7 @@ public class TablesPanel extends javax.swing.JPanel {
return; return;
} }
MatchOptions options = new MatchOptions("1", "Two Player Duel"); MatchOptions options = new MatchOptions("1", "Two Player Duel", false, 2);
options.getPlayerTypes().add("Human"); options.getPlayerTypes().add("Human");
options.getPlayerTypes().add("Computer - mad"); options.getPlayerTypes().add("Computer - mad");
options.setDeckType("Limited"); options.setDeckType("Limited");

View file

@ -13,8 +13,6 @@ import javax.swing.JMenuItem;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import mage.sets.avacynrestored.GuiseOfFire;
import org.apache.log4j.Logger;
import org.mage.card.arcane.CardRenderer; import org.mage.card.arcane.CardRenderer;
/** /**
@ -145,13 +143,11 @@ public class GUISizeHelper {
otherZonesCardDimension = new Dimension(CARD_IMAGE_WIDTH * otherZonesCardSize / 42, CARD_IMAGE_HEIGHT * otherZonesCardSize / 42); otherZonesCardDimension = new Dimension(CARD_IMAGE_WIDTH * otherZonesCardSize / 42, CARD_IMAGE_HEIGHT * otherZonesCardSize / 42);
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_FALLBACK, "false").equals("false")) { if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_FALLBACK, "false").equals("false")) {
otherZonesCardVerticalOffset = CardRenderer.getCardTopHeight(otherZonesCardDimension.width); otherZonesCardVerticalOffset = CardRenderer.getCardTopHeight(otherZonesCardDimension.width);
} else { } else if (otherZonesCardSize > 29) {
if (otherZonesCardSize > 29) {
otherZonesCardVerticalOffset = otherZonesCardDimension.height / 8; otherZonesCardVerticalOffset = otherZonesCardDimension.height / 8;
} else { } else {
otherZonesCardVerticalOffset = otherZonesCardDimension.height / 10; otherZonesCardVerticalOffset = otherZonesCardDimension.height / 10;
} }
}
int battlefieldCardMinSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, 10); int battlefieldCardMinSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, 10);
battlefieldCardMinDimension = new Dimension(CARD_IMAGE_WIDTH * battlefieldCardMinSize / 42, CARD_IMAGE_HEIGHT * battlefieldCardMinSize / 42); battlefieldCardMinDimension = new Dimension(CARD_IMAGE_WIDTH * battlefieldCardMinSize / 42, CARD_IMAGE_HEIGHT * battlefieldCardMinSize / 42);

View file

@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 15; public final static int MAGE_VERSION_PATCH = 15;
public final static String MAGE_VERSION_MINOR_PATCH = "v4"; public final static String MAGE_VERSION_MINOR_PATCH = "v5";
public final static String MAGE_VERSION_INFO = ""; public final static String MAGE_VERSION_INFO = "";
private final int major; private final int major;

View file

@ -30,7 +30,6 @@ package mage.view;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Mode; import mage.abilities.Mode;
@ -55,7 +54,6 @@ import mage.game.stack.Spell;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
import mage.target.Target; import mage.target.Target;
import mage.target.Targets; import mage.target.Targets;
import org.apache.log4j.Logger;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -323,7 +321,8 @@ public class CardView extends SimpleCardView {
this.mageObjectType = MageObjectType.SPELL; this.mageObjectType = MageObjectType.SPELL;
Spell spell = (Spell) card; Spell spell = (Spell) card;
for (SpellAbility spellAbility : spell.getSpellAbilities()) { for (SpellAbility spellAbility : spell.getSpellAbilities()) {
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
if (mode.getTargets().size() > 0) { if (mode.getTargets().size() > 0) {
setTargets(spellAbility.getTargets()); setTargets(spellAbility.getTargets());
} }
@ -331,7 +330,8 @@ public class CardView extends SimpleCardView {
} }
// show for modal spell, which mode was choosen // show for modal spell, which mode was choosen
if (spell.getSpellAbility().isModal()) { if (spell.getSpellAbility().isModal()) {
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) { for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
Mode mode = spell.getSpellAbility().getModes().get(modeId);
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>"); this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
} }
} }
@ -807,4 +807,3 @@ public class CardView extends SimpleCardView {
} }
} }

View file

@ -99,7 +99,8 @@ public class StackAbilityView extends CardView {
private void updateTargets(Game game, StackAbility ability) { private void updateTargets(Game game, StackAbility ability) {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
if (mode.getTargets().size() > 0) { if (mode.getTargets().size() > 0) {
setTargets(mode.getTargets()); setTargets(mode.getTargets());
} else { } else {
@ -132,7 +133,8 @@ public class StackAbilityView extends CardView {
// show for modal ability, which mode was choosen // show for modal ability, which mode was choosen
if (ability.isModal()) { if (ability.isModal()) {
Modes modes = ability.getModes(); Modes modes = ability.getModes();
for (Mode mode : modes.getSelectedModes()) { for (UUID modeId : modes.getSelectedModes()) {
Mode mode = modes.get(modeId);
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>"); this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
} }
} }

View file

@ -1516,7 +1516,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
//TODO: improve this; //TODO: improve this;
AvailableMode: AvailableMode:
for (Mode mode : modes.getAvailableModes(source, game)) { for (Mode mode : modes.getAvailableModes(source, game)) {
for (Mode selectedMode : modes.getSelectedModes()) { for (UUID selectedModeId : modes.getSelectedModes()) {
Mode selectedMode = modes.get(selectedModeId);
if (selectedMode.getId().equals(mode.getId())) { if (selectedMode.getId().equals(mode.getId())) {
continue AvailableMode; continue AvailableMode;
} }

View file

@ -1326,7 +1326,8 @@ public class HumanPlayer extends PlayerImpl {
AvailableModes: AvailableModes:
for (Mode mode : modes.getAvailableModes(source, game)) { for (Mode mode : modes.getAvailableModes(source, game)) {
int timesSelected = 0; int timesSelected = 0;
for (Mode selectedMode : modes.getSelectedModes()) { for (UUID selectedModeId : modes.getSelectedModes()) {
Mode selectedMode = modes.get(selectedModeId);
if (mode.getId().equals(selectedMode.getId())) { if (mode.getId().equals(selectedMode.getId())) {
if (modes.isEachModeMoreThanOnce()) { if (modes.isEachModeMoreThanOnce()) {
timesSelected++; timesSelected++;

View file

@ -43,6 +43,7 @@ import mage.game.events.TableEvent;
import mage.game.match.Match; import mage.game.match.Match;
import mage.game.match.MatchOptions; import mage.game.match.MatchOptions;
import mage.game.result.ResultProtos.TourneyQuitStatus; import mage.game.result.ResultProtos.TourneyQuitStatus;
import mage.game.tournament.MultiplayerRound;
import mage.game.tournament.Tournament; import mage.game.tournament.Tournament;
import mage.game.tournament.TournamentPairing; import mage.game.tournament.TournamentPairing;
import mage.game.tournament.TournamentPlayer; import mage.game.tournament.TournamentPlayer;
@ -114,6 +115,19 @@ public class TournamentController {
startMatch(event.getPair(), event.getMatchOptions()); startMatch(event.getPair(), event.getMatchOptions());
} }
break; break;
case START_MULTIPLAYER_MATCH:
if (!isAbort()) {
initTournament(); // set state
MatchOptions matchOptions = event.getMatchOptions();
if (matchOptions != null && event.getMultiplayerRound() != null) {
for (TournamentPlayer player : event.getMultiplayerRound().getAllPlayers()) {
matchOptions.getPlayerTypes().add(player.getPlayerType());
}
}
startMultiplayerMatch(event.getMultiplayerRound(), event.getMatchOptions());
}
break;
case END: case END:
endTournament(); endTournament();
break; break;
@ -265,6 +279,31 @@ public class TournamentController {
} }
} }
private void startMultiplayerMatch(MultiplayerRound round, MatchOptions matchOptions) {
try {
TableManager tableManager = TableManager.getInstance();
Table table = tableManager.createTable(GamesRoomManager.getInstance().getMainRoomId(), matchOptions);
table.setTournamentSubTable(true);
table.setTournament(tournament);
table.setState(TableState.WAITING);
for (TournamentPlayer player : round.getAllPlayers()) {
tableManager.addPlayer(getPlayerUserId(player.getPlayer().getId()), table.getId(), player.getPlayer(), player.getPlayerType(), player.getDeck());
}
table.setState(TableState.STARTING);
tableManager.startTournamentSubMatch(null, table.getId());
Match match = tableManager.getMatch(table.getId());
match.setTableId(tableId);
round.setMatch(match);
round.setTableId(table.getId());
for (TournamentPlayer player : round.getAllPlayers()) {
player.setState(TournamentPlayerState.DUELING);
}
} catch (GameException ex) {
logger.fatal("TournamentController startMatch error", ex);
}
}
private void startDraft(Draft draft) { private void startDraft(Draft draft) {
TableManager.getInstance().startDraft(tableId, draft); TableManager.getInstance().startDraft(tableId, draft);
} }

View file

@ -104,7 +104,8 @@ class ZadaHedronGrinderTriggeredAbility extends TriggeredAbilityImpl {
if (isControlledInstantOrSorcery(spell)) { if (isControlledInstantOrSorcery(spell)) {
boolean targetsSource = false; boolean targetsSource = false;
for (Ability ability : spell.getSpellAbilities()) { for (Ability ability : spell.getSpellAbilities()) {
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (!target.isNotTarget()) { if (!target.isNotTarget()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
@ -167,7 +168,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
Target usedTarget = null; Target usedTarget = null;
setUsedTarget: setUsedTarget:
for (Ability ability : spell.getSpellAbilities()) { for (Ability ability : spell.getSpellAbilities()) {
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (!target.isNotTarget() && target.getFirstTarget().equals(source.getSourceId())) { if (!target.isNotTarget() && target.getFirstTarget().equals(source.getSourceId())) {
usedTarget = target.copy(); usedTarget = target.copy();
@ -185,7 +187,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
Spell copy = spell.copySpell(source.getControllerId()); Spell copy = spell.copySpell(source.getControllerId());
game.getStack().push(copy); game.getStack().push(copy);
setTarget: setTarget:
for (Mode mode : copy.getSpellAbility().getModes().getSelectedModes()) { for (UUID modeId : copy.getSpellAbility().getModes().getSelectedModes()) {
Mode mode = copy.getSpellAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (target.getClass().equals(usedTarget.getClass())) { if (target.getClass().equals(usedTarget.getClass())) {
target.clearChosen(); // For targets with Max > 1 we need to clear before the text is comapred target.clearChosen(); // For targets with Max > 1 we need to clear before the text is comapred

View file

@ -83,7 +83,6 @@ public class GoblinArtisans extends CardImpl {
} }
} }
class GoblinArtisansEffect extends OneShotEffect { class GoblinArtisansEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent("permanent named Goblin Artisans"); private static final FilterPermanent filter = new FilterPermanent("permanent named Goblin Artisans");
@ -118,7 +117,8 @@ class GoblinArtisansEffect extends OneShotEffect {
List<Permanent> list = game.getBattlefield().getAllActivePermanents(filter, game); List<Permanent> list = game.getBattlefield().getAllActivePermanents(filter, game);
for (Permanent perm : list) { // should I limit below for a particular kind of ability? Going for the most general, it's unlikely there'll be any other artisans anyway, so not concerned about efficiency :p for (Permanent perm : list) { // should I limit below for a particular kind of ability? Going for the most general, it's unlikely there'll be any other artisans anyway, so not concerned about efficiency :p
for (Ability abil : perm.getAbilities(game)) {//below is copied from TargetsPermanentPredicate, but why only "selectedModes"? Shouldnt be more general as well? for (Ability abil : perm.getAbilities(game)) {//below is copied from TargetsPermanentPredicate, but why only "selectedModes"? Shouldnt be more general as well?
for (Mode mode : abil.getModes().getSelectedModes()){ for (UUID modeId : abil.getModes().getSelectedModes()) {
Mode mode = abil.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
artifacts.remove(game.getPermanentOrLKIBattlefield(targetId)); artifacts.remove(game.getPermanentOrLKIBattlefield(targetId));

View file

@ -120,7 +120,7 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect {
for (int i = 0; i < cardsToExile; i++) { for (int i = 0; i < cardsToExile; i++) {
Card card = player.getLibrary().removeFromTop(game); Card card = player.getLibrary().removeFromTop(game);
if (card != null) { if (card != null) {
card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceCard.getName(), source.getSourceId(), game); card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceCard.getIdName(), source.getSourceId(), game);
} }
} }
} }

View file

@ -227,7 +227,8 @@ class IcefallRegentCostIncreaseEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
if (targetUUID.equals(source.getSourceId())) { if (targetUUID.equals(source.getSourceId())) {

View file

@ -109,7 +109,8 @@ class MonasterySiegeCostIncreaseEffect extends CostModificationEffectImpl {
if (new ModeChoiceSourceCondition("Dragons").apply(game, source)) { if (new ModeChoiceSourceCondition("Dragons").apply(game, source)) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
if (targetUUID.equals(source.getControllerId())) { if (targetUUID.equals(source.getControllerId())) {

View file

@ -45,7 +45,6 @@ import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
import mage.players.PlayerList;
/** /**
* *
@ -106,28 +105,27 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl {
player.revealCards(sourceObject.getIdName() + " next draw of " + player.getName() + " (" + game.getTurnNum() + "|" + game.getPhase().getType() + ")", new CardsImpl(card), game); player.revealCards(sourceObject.getIdName() + " next draw of " + player.getName() + " (" + game.getTurnNum() + "|" + game.getPhase().getType() + ")", new CardsImpl(card), game);
// Then any other player may pay 2 life. If a player does, put that card into its owner's graveyard // Then any other player may pay 2 life. If a player does, put that card into its owner's graveyard
PlayerList playerList = game.getPlayerList().copy(); String message = "Pay 2 life to put " + card.getLogName() + " into graveyard?";
playerList.setCurrent(player.getId()); for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) {
Player currentPlayer = playerList.getNext(game); if (playerId.equals(player.getId())) {
String message = new StringBuilder("Pay 2 life to put ").append(card.getLogName()).append(" into graveyard?").toString(); continue;
while (!currentPlayer.getId().equals(player.getId())) { }
if (currentPlayer.canPayLifeCost() && Player otherPlayer = game.getPlayer(playerId);
currentPlayer.getLife() >= 2 && if (otherPlayer.canPayLifeCost()
currentPlayer.chooseUse(Outcome.Benefit, message, source, game)) { && otherPlayer.getLife() >= 2
currentPlayer.loseLife(2, game); && otherPlayer.chooseUse(Outcome.Benefit, message, source, game)) {
otherPlayer.loseLife(2, game);
player.moveCards(card, Zone.GRAVEYARD, source, game); player.moveCards(card, Zone.GRAVEYARD, source, game);
// game.getState().getRevealed().reset(); break;
}
}
}
return true; return true;
} }
currentPlayer = playerList.getNext(game);
}
// game.getState().getRevealed().reset();
}
}
return false; return false;
} }
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DRAW_CARD; return event.getType() == GameEvent.EventType.DRAW_CARD;

View file

@ -141,7 +141,8 @@ class CapturedByTheConsulateTriggeredAbility extends TriggeredAbilityImpl {
} }
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size(); numberOfTargets += target.getTargets().size();
} }

View file

@ -93,7 +93,7 @@ class DeadlockTrapCantActivateEffect extends RestrictionEffect {
@Override @Override
public boolean applies(Permanent permanent, Ability source, Game game) { public boolean applies(Permanent permanent, Ability source, Game game) {
return getTargetPointer().getFirst(game, source).equals(permanent.getId()); return permanent.getId().equals(getTargetPointer().getFirst(game, source));
} }
@Override @Override

View file

@ -135,7 +135,8 @@ class PsychicRebuttalPredicate implements ObjectPlayerPredicate<ObjectPlayer<Sta
if (controllerId == null) { if (controllerId == null) {
return false; return false;
} }
for (Mode mode : input.getObject().getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : input.getObject().getStackAbility().getModes().getSelectedModes()) {
Mode mode = input.getObject().getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (controllerId.equals(targetId)) { if (controllerId.equals(targetId)) {

View file

@ -106,7 +106,8 @@ class ElderwoodScionCostReductionEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) {
if (abilityToModify.getControllerId().equals(source.getControllerId())) { if (abilityToModify.getControllerId().equals(source.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
if (targetUUID.equals(source.getSourceId())) { if (targetUUID.equals(source.getSourceId())) {

View file

@ -28,7 +28,6 @@
package mage.sets.scourge; package mage.sets.scourge;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -108,7 +107,8 @@ class GripOfChaosTriggeredAbility extends TriggeredAbilityImpl {
} }
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size(); numberOfTargets += target.getTargets().size();
} }
@ -149,7 +149,8 @@ class GripOfChaosEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source)); StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source));
if (stackObject != null) { if (stackObject != null) {
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
UUID oldTargetId = target.getFirstTarget(); UUID oldTargetId = target.getFirstTarget();
Set<UUID> possibleTargets = target.possibleTargets(source.getSourceId(), source.getControllerId(), game); Set<UUID> possibleTargets = target.possibleTargets(source.getSourceId(), source.getControllerId(), game);

View file

@ -140,7 +140,8 @@ class AccursedWitchSpellsCostReductionEffect extends CostModificationEffectImpl
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
Permanent permanent = game.getPermanent(targetUUID); Permanent permanent = game.getPermanent(targetUUID);

View file

@ -100,9 +100,11 @@ class ForkInTheRoadEffect extends OneShotEffect {
if (target.getTargets().size() > 0) { if (target.getTargets().size() > 0) {
Cards revealed = new CardsImpl(); Cards revealed = new CardsImpl();
for (UUID cardId : target.getTargets()) { for (UUID cardId : target.getTargets()) {
Card card = controller.getLibrary().getCard(cardId, game); Card card = game.getCard(cardId);
if (card != null) {
revealed.add(card); revealed.add(card);
} }
}
controller.revealCards(sourceObject.getIdName(), revealed, game); controller.revealCards(sourceObject.getIdName(), revealed, game);
if (target.getTargets().size() > 0) { if (target.getTargets().size() > 0) {
TargetCard target2 = new TargetCard(Zone.LIBRARY, filter); TargetCard target2 = new TargetCard(Zone.LIBRARY, filter);

View file

@ -155,7 +155,8 @@ class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility) { if (abilityToModify instanceof SpellAbility) {
if (source.getControllerId().equals(abilityToModify.getControllerId())) { if (source.getControllerId().equals(abilityToModify.getControllerId())) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetUUID : target.getTargets()) { for (UUID targetUUID : target.getTargets()) {
Permanent enchantment = game.getPermanent(source.getSourceId()); Permanent enchantment = game.getPermanent(source.getSourceId());

View file

@ -84,7 +84,8 @@ class HinderingLightPredicate implements ObjectPlayerPredicate<ObjectPlayer<Stac
if (controllerId == null) { if (controllerId == null) {
return false; return false;
} }
for (Mode mode : input.getObject().getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : input.getObject().getStackAbility().getModes().getSelectedModes()) {
Mode mode = input.getObject().getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (controllerId.equals(targetId)) { if (controllerId.equals(targetId)) {

View file

@ -113,13 +113,13 @@ class TorchlingTargetPredicate implements Predicate<MageObject> {
if (spell != null) { if (spell != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) { for (SpellAbility spellAbility : spell.getSpellAbilities()) {
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (!targetId.equals(sourceId)) { if (!targetId.equals(sourceId)) {
return false; return false;
} } else {
else {
numberOfTargets++; numberOfTargets++;
} }
} }

View file

@ -96,7 +96,8 @@ class KaerveksTorchCostIncreaseEffect extends CostModificationEffectImpl {
@Override @Override
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) {
for (Mode mode : abilityToModify.getModes().getSelectedModes()) { for (UUID modeId : abilityToModify.getModes().getSelectedModes()) {
Mode mode = abilityToModify.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
if (targetId.equals(source.getSourceObject(game).getId())) { if (targetId.equals(source.getSourceObject(game).getId())) {

View file

@ -28,12 +28,6 @@
package mage.sets.worldwake; package mage.sets.worldwake;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.condition.common.SourceHasCounterCondition;
@ -41,6 +35,11 @@ import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
@ -54,7 +53,7 @@ import mage.filter.predicate.permanent.ControllerPredicate;
*/ */
public class QuestForTheGoblinLord extends CardImpl { public class QuestForTheGoblinLord extends CardImpl {
private static final String rule = "As long as Quest for the Goblin Lord has five or more quest counters on it, creatures you control get +2/+0."; private static final String rule = "As long as {this} has five or more quest counters on it, creatures you control get +2/+0";
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
private static final FilterPermanent goblinFilter = new FilterControlledCreaturePermanent(); private static final FilterPermanent goblinFilter = new FilterControlledCreaturePermanent();
@ -67,7 +66,6 @@ public class QuestForTheGoblinLord extends CardImpl {
super(ownerId, 86, "Quest for the Goblin Lord", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}"); super(ownerId, 86, "Quest for the Goblin Lord", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}");
this.expansionSetCode = "WWK"; this.expansionSetCode = "WWK";
// Whenever a Goblin enters the battlefield under your control, you may put a quest counter on Quest for the Goblin Lord. // Whenever a Goblin enters the battlefield under your control, you may put a quest counter on Quest for the Goblin Lord.
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), goblinFilter, true)); this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), goblinFilter, true));

View file

@ -38,10 +38,6 @@ import org.mage.test.serverside.base.CardTestPlayerBaseAI;
*/ */
public class CastDestroySpellsTest extends CardTestPlayerBaseAI { public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
/**
*
*
*/
@Test @Test
public void testOrzhovCharm() { public void testOrzhovCharm() {
// Choose one - // Choose one -
@ -58,6 +54,8 @@ public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
// Cycling abilities you activate cost you up to {2} less to activate. // Cycling abilities you activate cost you up to {2} less to activate.
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Orzhov Charm", "Silvercoat Lion");
setModeChoice(playerA, "2");
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute(); execute();

View file

@ -367,6 +367,31 @@ public class FlashbackTest extends CardTestPlayerBase {
} }
@Test
public void testSnapcasterMageWithBuyback() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
// Buyback {5}(You may pay an additional {5} as you cast this spell. If you do, put this card into your hand as it resolves.)
// Draw a card.
addCard(Zone.GRAVEYARD, playerA, "Whispers of the Muse", 1); // {U}
// When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
setChoice(playerA, "Whispers of the Muse");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); // Flashback Whispers of the Muse
setChoice(playerA, "Yes");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Snapcaster Mage", 1);
assertGraveyardCount(playerA, "Whispers of the Muse", 0);
assertHandCount(playerA, 1);
assertExileCount("Whispers of the Muse", 1);
}
/** /**
* Deep Analysis doesn't cost mana when flashbacked. * Deep Analysis doesn't cost mana when flashbacked.
*/ */

View file

@ -219,7 +219,7 @@ public class UndyingTest extends CardTestPlayerBase {
} }
/** /**
* Tatterkite is getting counters on it, i have him in a edh deck with * Tatterkite is getting counters on it, I have him in a edh deck with
* Mikaeus, the Lunarch and when Tatterkite dies it triggers the undying and * Mikaeus, the Lunarch and when Tatterkite dies it triggers the undying and
* he gets the +1/+1 counters * he gets the +1/+1 counters
*/ */

View file

@ -0,0 +1,107 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.modal;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class OneOrBothTest extends CardTestPlayerBase {
@Test
public void testSubtleStrikeFirstMode() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Choose one or both
// Target creature gets -1/-1 until end of turn.
// Put a +1/+1 counter on target creature.
addCard(Zone.HAND, playerA, "Subtle Strike"); // Instant {1}{B}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Subtle Strike", "Pillarfield Ox");
setModeChoice(playerA, "1");
setModeChoice(playerA, null);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Silvercoat Lion", 2, 2);
assertPowerToughness(playerB, "Pillarfield Ox", 1, 3);
}
@Test
public void testSubtleStrikeSecondMode() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Choose one or both
// Target creature gets -1/-1 until end of turn.
// Put a +1/+1 counter on target creature.
addCard(Zone.HAND, playerA, "Subtle Strike"); // Instant {1}{B}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Subtle Strike", "Pillarfield Ox");
setModeChoice(playerA, "2");
setModeChoice(playerA, null);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Silvercoat Lion", 2, 2);
assertPowerToughness(playerB, "Pillarfield Ox", 3, 5);
}
@Test
public void testSubtleStrikeBothModes() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// Choose one or both
// Target creature gets -1/-1 until end of turn.
// Put a +1/+1 counter on target creature.
addCard(Zone.HAND, playerA, "Subtle Strike"); // Instant {1}{B}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Subtle Strike", "Pillarfield Ox");
addTarget(playerA, "Silvercoat Lion");
setModeChoice(playerA, "1");
setModeChoice(playerA, "2");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Silvercoat Lion", 3, 3);
assertPowerToughness(playerB, "Pillarfield Ox", 1, 3);
}
}

View file

@ -39,20 +39,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
public class BrutalExpulsionTest extends CardTestPlayerBase { public class BrutalExpulsionTest extends CardTestPlayerBase {
/** /**
* Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3 loyalty. Brutal Expulsion resolves, * Brutal Expulsion targeting Gideon, Ally of Zendikar. Gideon has 3
* leaves 1 loyalty. I attack Gideon for 1 with a Scion token, Gideon dies. Instead of going to graveyard, * loyalty. Brutal Expulsion resolves, leaves 1 loyalty. I attack Gideon for
* Expulsion sends Gideon to exile. However, in game Gideon went to graveyard. * 1 with a Scion token, Gideon dies. Instead of going to graveyard,
* Expulsion sends Gideon to exile. However, in game Gideon went to
* graveyard.
*/ */
@Test @Test
public void testPlaneswalkerExile() { public void testPlaneswalkerExile() {
// Choose one or both // Choose one or both
// - Return target spell or creature to its owner's hand; // - Return target spell or creature to its owner's hand;
// or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead. // or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
addCard(Zone.HAND, playerA, "Brutal Expulsion"); addCard(Zone.HAND, playerA, "Brutal Expulsion"); // {2}{U}{R}
// Shock deals 2 damage to target creature or player. // Shock deals 2 damage to target creature or player.
addCard(Zone.HAND, playerA, "Shock"); addCard(Zone.HAND, playerA, "Shock"); // {R}
addCard(Zone.BATTLEFIELD, playerA, "Island", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
// Planeswalker with 4 loyalty. // Planeswalker with 4 loyalty.
addCard(Zone.BATTLEFIELD, playerB, "Gideon, Ally of Zendikar"); addCard(Zone.BATTLEFIELD, playerB, "Gideon, Ally of Zendikar");
@ -60,12 +62,12 @@ public class BrutalExpulsionTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", playerB); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", playerB);
setModeChoice(playerA, "2"); setModeChoice(playerA, "2");
setModeChoice(playerA, null); setModeChoice(playerA, null);
setChoice(playerA, "Yes"); setChoice(playerA, "Yes"); // Redirect to planeswalker
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", playerB); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Shock", playerB);
setChoice(playerA, "Yes"); setChoice(playerA, "Yes"); // Redirect to planeswalker
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); setStopAt(1, PhaseStep.END_COMBAT);
execute(); execute();
assertPermanentCount(playerB, "Gideon, Ally of Zendikar", 0); assertPermanentCount(playerB, "Gideon, Ally of Zendikar", 0);

View file

@ -267,7 +267,7 @@ public class LoadTest {
* @return * @return
*/ */
private MatchOptions createGameOptions(GameTypeView gameTypeView, Session session) { private MatchOptions createGameOptions(GameTypeView gameTypeView, Session session) {
MatchOptions options = new MatchOptions("Test game", gameTypeView.getName()); MatchOptions options = new MatchOptions("Test game", gameTypeView.getName(), false, 2);
options.getPlayerTypes().add("Human"); options.getPlayerTypes().add("Human");
options.getPlayerTypes().add("Human"); options.getPlayerTypes().add("Human");

View file

@ -287,7 +287,8 @@ public class TestPlayer implements Player {
} }
UUID modeId = ability.getModes().getModeId(modeNr); UUID modeId = ability.getModes().getModeId(modeNr);
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID currentModeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(currentModeId);
if (mode.getId().equals(modeId)) { if (mode.getId().equals(modeId)) {
selectedMode = mode; selectedMode = mode;
ability.getModes().setActiveMode(mode); ability.getModes().setActiveMode(mode);

View file

@ -306,7 +306,8 @@ public abstract class AbilityImpl implements Ability {
&& game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) { && game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) {
return false; return false;
} }
for (Mode mode : this.getModes().getSelectedModes()) { for (UUID modeId : this.getModes().getSelectedModes()) {
Mode mode = this.getModes().get(modeId);
this.getModes().setActiveMode(mode); this.getModes().setActiveMode(mode);
//20121001 - 601.2c //20121001 - 601.2c
// 601.2c The player announces his or her choice of an appropriate player, object, or zone for // 601.2c The player announces his or her choice of an appropriate player, object, or zone for
@ -1060,7 +1061,8 @@ public abstract class AbilityImpl implements Ability {
} }
} else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) { } else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
Modes spellModes = ((Spell) object).getSpellAbility().getModes(); Modes spellModes = ((Spell) object).getSpellAbility().getModes();
for (Mode selectedMode : spellModes.getSelectedModes()) { for (UUID selectedModeId : spellModes.getSelectedModes()) {
Mode selectedMode = spellModes.get(selectedModeId);
int item = 0; int item = 0;
for (Mode mode : spellModes.values()) { for (Mode mode : spellModes.values()) {
item++; item++;

View file

@ -41,7 +41,6 @@ import mage.constants.TargetController;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
/** /**
* *
@ -49,8 +48,8 @@ import mage.util.CardUtil;
*/ */
public class Modes extends LinkedHashMap<UUID, Mode> { public class Modes extends LinkedHashMap<UUID, Mode> {
private Mode mode; // the current mode of the selected modes private Mode currentMode; // the current mode of the selected modes
private final ArrayList<Mode> selectedModes = new ArrayList<>(); private final ArrayList<UUID> selectedModes = new ArrayList<>();
private int minModes; private int minModes;
private int maxModes; private int maxModes;
private TargetController modeChooser; private TargetController modeChooser;
@ -58,11 +57,11 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
public Modes() { public Modes() {
this.mode = new Mode(); this.currentMode = new Mode();
this.put(mode.getId(), mode); this.put(currentMode.getId(), currentMode);
this.minModes = 1; this.minModes = 1;
this.maxModes = 1; this.maxModes = 1;
this.selectedModes.add(mode); this.selectedModes.add(currentMode.getId());
this.modeChooser = TargetController.YOU; this.modeChooser = TargetController.YOU;
this.eachModeOnlyOnce = false; this.eachModeOnlyOnce = false;
this.eachModeMoreThanOnce = false; this.eachModeMoreThanOnce = false;
@ -75,23 +74,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
this.minModes = modes.minModes; this.minModes = modes.minModes;
this.maxModes = modes.maxModes; this.maxModes = modes.maxModes;
if (modes.size() == 1) { this.currentMode = values().iterator().next();
this.mode = values().iterator().next(); selectedModes.addAll(modes.getSelectedModes());
this.selectedModes.add(mode);
} else {
// probably there is still a problem with copying modes with the same mode selected multiple times.
for (Mode selectedMode : modes.getSelectedModes()) {
Mode copiedMode = selectedMode.copy();
this.selectedModes.add(copiedMode);
if (modes.getSelectedModes().size() == 1) {
this.mode = copiedMode;
} else {
if (selectedMode.equals(modes.getMode())) {
this.mode = copiedMode;
}
}
}
}
this.modeChooser = modes.modeChooser; this.modeChooser = modes.modeChooser;
this.eachModeOnlyOnce = modes.eachModeOnlyOnce; this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce; this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
@ -102,21 +86,21 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
public Mode getMode() { public Mode getMode() {
return mode; return currentMode;
} }
public UUID getModeId(int index) { public UUID getModeId(int index) {
int idx = 0; int idx = 0;
for (Mode currentMode : this.values()) { for (Mode mode : this.values()) {
idx++; idx++;
if (idx == index) { if (idx == index) {
return currentMode.getId(); return mode.getId();
} }
} }
return null; return null;
} }
public ArrayList<Mode> getSelectedModes() { public ArrayList<UUID> getSelectedModes() {
return selectedModes; return selectedModes;
} }
@ -145,8 +129,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
public void setActiveMode(Mode mode) { public void setActiveMode(Mode mode) {
if (selectedModes.contains(mode)) { if (selectedModes.contains(mode.getId())) {
this.mode = mode; this.currentMode = mode;
} }
} }
@ -175,7 +159,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
for (Mode mode : this.values()) { for (Mode mode : this.values()) {
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId())) if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
this.selectedModes.add(mode.copy()); this.selectedModes.add(mode.getId());
} }
} }
if (isEachModeOnlyOnce()) { if (isEachModeOnlyOnce()) {
@ -203,7 +187,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
// player chooses modes manually // player chooses modes manually
this.mode = null; this.currentMode = null;
while (this.selectedModes.size() < this.getMaxModes()) { while (this.selectedModes.size() < this.getMaxModes()) {
Mode choice = player.chooseMode(this, source, game); Mode choice = player.chooseMode(this, source, game);
if (choice == null) { if (choice == null) {
@ -212,9 +196,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
return this.selectedModes.size() >= this.getMinModes(); return this.selectedModes.size() >= this.getMinModes();
} }
this.selectedModes.add(choice.copy()); this.selectedModes.add(choice.getId());
if (mode == null) { if (currentMode == null) {
mode = choice; currentMode = choice;
} }
} }
if (isEachModeOnlyOnce()) { if (isEachModeOnlyOnce()) {
@ -222,10 +206,10 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} }
return true; return true;
} }
if (mode == null) { if (currentMode == null) {
this.selectedModes.clear(); this.selectedModes.clear();
Mode copiedMode = this.values().iterator().next().copy(); Mode copiedMode = this.values().iterator().next().copy();
this.selectedModes.add(copiedMode); this.selectedModes.add(copiedMode.getId());
this.setActiveMode(copiedMode); this.setActiveMode(copiedMode);
} }
if (isEachModeOnlyOnce()) { if (isEachModeOnlyOnce()) {
@ -234,27 +218,46 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
return true; return true;
} }
private void setAlreadySelectedModes(ArrayList<Mode> selectedModes, Ability source, Game game) { /**
String key = getKey(source, game); * Saves the already selected modes to the state value
Set<UUID> onceSelectedModes = (Set<UUID>) game.getState().getValue(key); *
if (onceSelectedModes == null) { * @param selectedModes
onceSelectedModes = new HashSet<>(); * @param source
* @param game
*/
private void setAlreadySelectedModes(ArrayList<UUID> selectedModes, Ability source, Game game) {
for (UUID modeId : selectedModes) {
String key = getKey(source, game, modeId);
game.getState().setValue(key, true);
} }
for (Mode mode : selectedModes) {
onceSelectedModes.add(mode.getId());
}
game.getState().setValue(key, onceSelectedModes);
} }
// The already once selected modes for a modal card are stored as a state value
// That's important for modal abilities with modes that can only selected once while the object stays in its zone
@SuppressWarnings("unchecked")
private Set<UUID> getAlreadySelectedModes(Ability source, Game game) { private Set<UUID> getAlreadySelectedModes(Ability source, Game game) {
return (Set<UUID>) game.getState().getValue(getKey(source, game)); Set<UUID> onceSelectedModes = new HashSet<>();
for (UUID modeId : this.keySet()) {
Object exist = game.getState().getValue(getKey(source, game, modeId));
if (exist != null) {
onceSelectedModes.add(modeId);
}
}
return onceSelectedModes;
} }
private String getKey(Ability source, Game game) { // creates the key the selected modes are saved with to the state values
return CardUtil.getObjectZoneString("selectedModes", source.getSourceId(), game, game.getState().getZoneChangeCounter(source.getSourceId()), false); private String getKey(Ability source, Game game, UUID modeId) {
return source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()) + modeId.toString();
} }
/**
* Returns all (still) available modes of the ability
*
* @param source
* @param game
* @return
*/
public List<Mode> getAvailableModes(Ability source, Game game) { public List<Mode> getAvailableModes(Ability source, Game game) {
List<Mode> availableModes = new ArrayList<>(); List<Mode> availableModes = new ArrayList<>();
Set<UUID> nonAvailableModes; Set<UUID> nonAvailableModes;

View file

@ -56,6 +56,9 @@ public abstract class StaticAbility extends AbilityImpl {
if (game.getShortLivingLKI(getSourceId(), zone)) { if (game.getShortLivingLKI(getSourceId(), zone)) {
return true; // maybe this can be a problem if effects removed the ability from the object return true; // maybe this can be a problem if effects removed the ability from the object
} }
if (game.getPermanentEntering(getSourceId()) != null && zone.equals(Zone.BATTLEFIELD)) {
return true; // abilities of permanents entering battlefield are countes as on battlefield
}
return super.isInUseableZone(game, source, event); return super.isInUseableZone(game, source, event);
} }

View file

@ -88,7 +88,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
MageObject object = game.getObject(getSourceId()); MageObject object = game.getObject(getSourceId());
Player player = game.getPlayer(this.getControllerId()); Player player = game.getPlayer(this.getControllerId());
if (player != null && object != null) { if (player != null && object != null) {
if (!player.chooseUse(getEffects().get(0).getOutcome(), (object != null ? this.getRule(object.getLogName()) : this.getRule()), this, game)) { if (!player.chooseUse(getEffects().get(0).getOutcome(), this.getRule(object.getLogName()), this, game)) {
return false; return false;
} }
} else { } else {
@ -216,7 +216,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
/* /*
603.6c,603.6d 603.6c,603.6d
This has to be set, if the triggered ability has to check back in time if the permanent the ability is connected to had the ability on the battlefeild while the trigger is checked This has to be set, if the triggered ability has to check back in time if the permanent the ability is connected to had the ability on the battlefield while the trigger is checked
*/ */
@Override @Override
public final void setLeavesTheBattlefieldTrigger(boolean leavesTheBattlefieldTrigger) { public final void setLeavesTheBattlefieldTrigger(boolean leavesTheBattlefieldTrigger) {

View file

@ -51,7 +51,8 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
} else { } else {
return false; return false;
} }
for (Mode mode : sourceAbility.getModes().getSelectedModes()) { for (UUID modeId : sourceAbility.getModes().getSelectedModes()) {
Mode mode = sourceAbility.getModes().get(modeId);
targets.addAll(mode.getTargets()); targets.addAll(mode.getTargets());
} }
@ -102,13 +103,11 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
} }
if (oldTargetName != null) { if (oldTargetName != null) {
game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " to " + sourceObject.getLogName()); game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " to " + sourceObject.getLogName());
} else { } else if (twoTimesTarget) {
if (twoTimesTarget) {
game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName()); game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName());
} else { } else {
game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName()); game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName());
} }
}
return true; return true;
} }
return false; return false;

View file

@ -186,7 +186,7 @@ class BuybackEffect extends ReplacementEffectImpl {
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getSourceId())) { if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event; ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.STACK if (zEvent.getFromZone() == Zone.STACK && zEvent.getToZone() == Zone.GRAVEYARD
&& source.getSourceId().equals(event.getSourceId())) { // if spell fizzled, the sourceId is null && source.getSourceId().equals(event.getSourceId())) { // if spell fizzled, the sourceId is null
return true; return true;
} }

View file

@ -274,7 +274,8 @@ class FlashbackReplacementEffect extends ReplacementEffectImpl {
if (controller != null) { if (controller != null) {
Card card = game.getCard(event.getTargetId()); Card card = game.getCard(event.getTargetId());
if (card != null) { if (card != null) {
return controller.moveCards(card, Zone.EXILED, source, game); return controller.moveCards(
card, Zone.EXILED, source, game, false, false, false, event.getAppliedEffects());
} }
} }
return false; return false;

View file

@ -82,7 +82,8 @@ public class HeroicAbility extends TriggeredAbilityImpl {
private boolean checkSpell(Spell spell, Game game) { private boolean checkSpell(Spell spell, Game game) {
if (spell != null) { if (spell != null) {
SpellAbility sa = spell.getSpellAbility(); SpellAbility sa = spell.getSpellAbility();
for (Mode mode : sa.getModes().getSelectedModes()) { for (UUID modeId : sa.getModes().getSelectedModes()) {
Mode mode = sa.getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) { if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) {
return true; return true;

View file

@ -63,7 +63,7 @@ public enum CardRepository {
// raise this if db structure was changed // raise this if db structure was changed
private static final long CARD_DB_VERSION = 47; private static final long CARD_DB_VERSION = 47;
// raise this if new cards were added to the server // raise this if new cards were added to the server
private static final long CARD_CONTENT_VERSION = 61; private static final long CARD_CONTENT_VERSION = 62;
private Dao<CardInfo, Object> cardDao; private Dao<CardInfo, Object> cardDao;
private Set<String> classNames; private Set<String> classNames;

View file

@ -27,6 +27,7 @@
*/ */
package mage.filter.predicate.mageobject; package mage.filter.predicate.mageobject;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
@ -51,7 +52,8 @@ public class NumberOfTargetsPredicate implements Predicate<MageObject> {
StackObject stackObject = game.getState().getStack().getStackObject(input.getId()); StackObject stackObject = game.getState().getStack().getStackObject(input.getId());
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) {
Mode mode = stackObject.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size(); numberOfTargets += target.getTargets().size();
} }

View file

@ -54,7 +54,8 @@ public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate<Ob
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) { public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
StackObject object = game.getStack().getStackObject(input.getObject().getId()); StackObject object = game.getStack().getStackObject(input.getObject().getId());
if (object != null) { if (object != null) {
for (Mode mode : object.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : object.getStackAbility().getModes().getSelectedModes()) {
Mode mode = object.getStackAbility().getModes().get(modeId);
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);

View file

@ -314,7 +314,8 @@ public class GameState implements Serializable, Copyable<GameState> {
for (StackObject spell : stack) { for (StackObject spell : stack) {
sb.append(spell.getControllerId()).append(spell.getName()); sb.append(spell.getControllerId()).append(spell.getName());
sb.append(spell.getStackAbility().toString()); sb.append(spell.getStackAbility().toString());
for (Mode mode : spell.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : spell.getStackAbility().getModes().getSelectedModes()) {
Mode mode = spell.getStackAbility().getModes().get(modeId);
if (!mode.getTargets().isEmpty()) { if (!mode.getTargets().isEmpty()) {
sb.append("targets"); sb.append("targets");
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
@ -366,7 +367,8 @@ public class GameState implements Serializable, Copyable<GameState> {
for (StackObject spell : stack) { for (StackObject spell : stack) {
sb.append(spell.getControllerId()).append(spell.getName()); sb.append(spell.getControllerId()).append(spell.getName());
sb.append(spell.getStackAbility().toString()); sb.append(spell.getStackAbility().toString());
for (Mode mode : spell.getStackAbility().getModes().getSelectedModes()) { for (UUID modeId : spell.getStackAbility().getModes().getSelectedModes()) {
Mode mode = spell.getStackAbility().getModes().get(modeId);
if (!mode.getTargets().isEmpty()) { if (!mode.getTargets().isEmpty()) {
sb.append("targets"); sb.append("targets");
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
@ -784,7 +786,8 @@ public class GameState implements Serializable, Copyable<GameState> {
public void addAbility(Ability ability, MageObject attachedTo) { public void addAbility(Ability ability, MageObject attachedTo) {
if (ability instanceof StaticAbility) { if (ability instanceof StaticAbility) {
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
for (Effect effect : mode.getEffects()) { for (Effect effect : mode.getEffects()) {
if (effect instanceof ContinuousEffect) { if (effect instanceof ContinuousEffect) {
addEffect((ContinuousEffect) effect, ability); addEffect((ContinuousEffect) effect, ability);
@ -806,7 +809,8 @@ public class GameState implements Serializable, Copyable<GameState> {
*/ */
public void addAbility(Ability ability, UUID sourceId, Card attachedTo) { public void addAbility(Ability ability, UUID sourceId, Card attachedTo) {
if (ability instanceof StaticAbility) { if (ability instanceof StaticAbility) {
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
for (Effect effect : mode.getEffects()) { for (Effect effect : mode.getEffects()) {
if (effect instanceof ContinuousEffect) { if (effect instanceof ContinuousEffect) {
addEffect((ContinuousEffect) effect, sourceId, ability); addEffect((ContinuousEffect) effect, sourceId, ability);

View file

@ -237,6 +237,9 @@ public class Combat implements Serializable, Copyable<Combat> {
possibleDefenders = new HashSet<>(defenders); possibleDefenders = new HashSet<>(defenders);
} }
Player player = game.getPlayer(attackerId); Player player = game.getPlayer(attackerId);
if (player == null) {
return false;
}
if (possibleDefenders.size() == 1) { if (possibleDefenders.size() == 1) {
addAttackerToCombat(creatureId, possibleDefenders.iterator().next(), game); addAttackerToCombat(creatureId, possibleDefenders.iterator().next(), game);
return true; return true;
@ -866,6 +869,7 @@ public class Combat implements Serializable, Copyable<Combat> {
blockIsValid = true; blockIsValid = true;
break CombatGroups; break CombatGroups;
} else // check if the blocker blocks a attacker that must be blocked at least by one and is the only blocker, this block is also valid } else // check if the blocker blocks a attacker that must be blocked at least by one and is the only blocker, this block is also valid
{
if (combatGroup.getBlockers().size() == 1) { if (combatGroup.getBlockers().size() == 1) {
if (mustBeBlockedByAtLeastOne.containsKey(forcingAttackerId)) { if (mustBeBlockedByAtLeastOne.containsKey(forcingAttackerId)) {
if (mustBeBlockedByAtLeastOne.get(forcingAttackerId).contains(creatureForcedToBlock.getId())) { if (mustBeBlockedByAtLeastOne.get(forcingAttackerId).contains(creatureForcedToBlock.getId())) {
@ -877,6 +881,7 @@ public class Combat implements Serializable, Copyable<Combat> {
} }
} }
} }
}
} }
if (!blockIsValid) { if (!blockIsValid) {

View file

@ -36,6 +36,7 @@ import mage.cards.decks.Deck;
import mage.game.Game; import mage.game.Game;
import mage.game.draft.Draft; import mage.game.draft.Draft;
import mage.game.match.MatchOptions; import mage.game.match.MatchOptions;
import mage.game.tournament.MultiplayerRound;
import mage.game.tournament.TournamentPairing; import mage.game.tournament.TournamentPairing;
/** /**
@ -46,7 +47,7 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab
public enum EventType { public enum EventType {
UPDATE, INFO, STATUS, START_DRAFT, START_MATCH, SIDEBOARD, CONSTRUCT, SUBMIT_DECK, END, END_GAME_INFO, ERROR, UPDATE, INFO, STATUS, START_DRAFT, START_MATCH, SIDEBOARD, CONSTRUCT, SUBMIT_DECK, END, END_GAME_INFO, ERROR,
INIT_TIMER, RESUME_TIMER, PAUSE_TIMER, CHECK_STATE_PLAYERS INIT_TIMER, RESUME_TIMER, PAUSE_TIMER, CHECK_STATE_PLAYERS, START_MULTIPLAYER_MATCH
} }
private Game game; private Game game;
@ -58,6 +59,7 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab
private UUID playerId; private UUID playerId;
private Deck deck; private Deck deck;
private TournamentPairing pair; private TournamentPairing pair;
private MultiplayerRound round;
private MatchOptions options; private MatchOptions options;
private int timeout; private int timeout;
private boolean withTime; private boolean withTime;
@ -116,6 +118,13 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab
this.eventType = eventType; this.eventType = eventType;
} }
public TableEvent(EventType eventType, MultiplayerRound round, MatchOptions options) {
super(options);
this.round = round;
this.options = options;
this.eventType = eventType;
}
public Game getGame() { public Game getGame() {
return game; return game;
} }
@ -152,6 +161,10 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab
return pair; return pair;
} }
public MultiplayerRound getMultiplayerRound() {
return round;
}
public MatchOptions getMatchOptions() { public MatchOptions getMatchOptions() {
return options; return options;
} }

View file

@ -38,6 +38,7 @@ import mage.game.tournament.TournamentPairing;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
import mage.game.tournament.MultiplayerRound;
/** /**
* *
@ -93,4 +94,8 @@ public class TableEventSource implements EventSource<TableEvent>, Serializable {
public void fireTableEvent(EventType eventType, TournamentPairing pair, MatchOptions options) { public void fireTableEvent(EventType eventType, TournamentPairing pair, MatchOptions options) {
dispatcher.fireEvent(new TableEvent(eventType, pair, options)); dispatcher.fireEvent(new TableEvent(eventType, pair, options));
} }
public void fireTableEvent(EventType eventType, MultiplayerRound round, MatchOptions options) {
dispatcher.fireEvent(new TableEvent(eventType, round, options));
}
} }

View file

@ -52,21 +52,50 @@ public class MatchOptions implements Serializable {
protected String deckType; protected String deckType;
protected boolean limited; protected boolean limited;
protected List<String> playerTypes = new ArrayList<>(); protected List<String> playerTypes = new ArrayList<>();
protected boolean multiPlayer;
protected int numSeats;
protected String password; protected String password;
protected SkillLevel skillLevel; protected SkillLevel skillLevel;
protected boolean rollbackTurnsAllowed; protected boolean rollbackTurnsAllowed;
protected int quitRatio; protected int quitRatio;
protected boolean rated; protected boolean rated;
protected int numSeatsForMatch;
/** /**
* Time each player has during the game to play using his\her priority. * Time each player has during the game to play using his\her priority.
*/ */
protected MatchTimeLimit matchTimeLimit; // 0 = no priorityTime handling protected MatchTimeLimit matchTimeLimit; // 0 = no priorityTime handling
public MatchOptions(String name, String gameType) { /*public MatchOptions(String name, String gameType) {
this.name = name; this.name = name;
this.gameType = gameType; this.gameType = gameType;
this.password = ""; this.password = "";
this.multiPlayer = false;
this.numSeats = 2;
}*/
public MatchOptions(String name, String gameType, boolean multiPlayer, int numSeats ) {
this.name = name;
this.gameType = gameType;
this.password = "";
this.multiPlayer = multiPlayer;
this.numSeats = numSeats;
}
public void setNumSeats (int numSeats) {
this.numSeats = numSeats;
}
public int getNumSeats () {
return numSeats;
}
public void setMultiPlayer(boolean multiPlayer) {
this.multiPlayer = multiPlayer;
}
public boolean getMultiPlayer() {
return multiPlayer;
} }
public String getName() { public String getName() {

View file

@ -210,7 +210,8 @@ public class Spell extends StackObjImpl implements Card {
if (notTargeted || legalParts) { if (notTargeted || legalParts) {
for (SpellAbility spellAbility : this.spellAbilities) { for (SpellAbility spellAbility : this.spellAbilities) {
if (spellAbilityHasLegalParts(spellAbility, game)) { if (spellAbilityHasLegalParts(spellAbility, game)) {
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
spellAbility.getModes().setActiveMode(mode); spellAbility.getModes().setActiveMode(mode);
if (mode.getTargets().stillLegal(spellAbility, game)) { if (mode.getTargets().stillLegal(spellAbility, game)) {
if (!spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE)) { if (!spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE)) {
@ -283,7 +284,8 @@ public class Spell extends StackObjImpl implements Card {
private boolean hasTargets(SpellAbility spellAbility, Game game) { private boolean hasTargets(SpellAbility spellAbility, Game game) {
if (spellAbility.getModes().getSelectedModes().size() > 1) { if (spellAbility.getModes().getSelectedModes().size() > 1) {
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
if (!mode.getTargets().isEmpty()) { if (!mode.getTargets().isEmpty()) {
return true; return true;
} }
@ -299,7 +301,8 @@ public class Spell extends StackObjImpl implements Card {
if (spellAbility.getModes().getSelectedModes().size() > 1) { if (spellAbility.getModes().getSelectedModes().size() > 1) {
boolean targetedMode = false; boolean targetedMode = false;
boolean legalTargetedMode = false; boolean legalTargetedMode = false;
for (Mode mode : spellAbility.getModes().getSelectedModes()) { for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
Mode mode = spellAbility.getModes().get(modeId);
if (mode.getTargets().size() > 0) { if (mode.getTargets().size() > 0) {
targetedMode = true; targetedMode = true;
if (mode.getTargets().stillLegal(spellAbility, game)) { if (mode.getTargets().stillLegal(spellAbility, game)) {

View file

@ -117,7 +117,8 @@ public abstract class StackObjImpl implements StackObject {
} }
for (Ability ability : objectAbilities) { for (Ability ability : objectAbilities) {
// Some spells can have more than one mode // Some spells can have more than one mode
for (Mode mode : ability.getModes().getSelectedModes()) { for (UUID modeId : ability.getModes().getSelectedModes()) {
Mode mode = ability.getModes().get(modeId);
ability.getModes().setActiveMode(mode); ability.getModes().setActiveMode(mode);
oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game)); oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game));
for (Target target : mode.getTargets()) { for (Target target : mode.getTargets()) {
@ -210,7 +211,6 @@ public abstract class StackObjImpl implements StackObject {
again = true; again = true;
} }
} else // if possible add the alternate Target - it may not be included in the old definition nor in the already selected targets of the new definition } else // if possible add the alternate Target - it may not be included in the old definition nor in the already selected targets of the new definition
{
if (newTarget.getTargets().contains(tempTarget.getFirstTarget()) || target.getTargets().contains(tempTarget.getFirstTarget())) { if (newTarget.getTargets().contains(tempTarget.getFirstTarget()) || target.getTargets().contains(tempTarget.getFirstTarget())) {
if (targetController.isHuman()) { if (targetController.isHuman()) {
if (targetController.chooseUse(Outcome.Benefit, "This target was already selected from origin spell. Reset to original target?", ability, game)) { if (targetController.chooseUse(Outcome.Benefit, "This target was already selected from origin spell. Reset to original target?", ability, game)) {
@ -240,7 +240,6 @@ public abstract class StackObjImpl implements StackObject {
// valid target was selected, add it to the new target definition // valid target was selected, add it to the new target definition
newTarget.addTarget(tempTarget.getFirstTarget(), target.getTargetAmount(targetId), ability, game, false); newTarget.addTarget(tempTarget.getFirstTarget(), target.getTargetAmount(targetId), ability, game, false);
} }
}
} while (again && targetController.canRespond()); } while (again && targetController.canRespond());
} }
} // keep the target } // keep the target

View file

@ -0,0 +1,97 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game.tournament;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.game.match.Match;
/**
*
* @author spjspj
*/
public class MultiplayerRound {
private final int roundNum;
private final Tournament tournament;
private final int numSeats;
private final List<TournamentPlayer> allPlayers = new ArrayList<>();
private Match match;
private UUID tableId;
public MultiplayerRound(int roundNum, Tournament tournament, int numSeats) {
this.roundNum = roundNum;
this.tournament = tournament;
this.numSeats = numSeats;
}
public List<TournamentPlayer> getAllPlayers () {
return allPlayers;
}
public TournamentPlayer getPlayer (int i) {
if (i >= 0 && i < numSeats && i < allPlayers.size()) {
return allPlayers.get(i);
}
return null;
}
public void addPairing(TournamentPairing match) {
this.allPlayers.add(match.getPlayer1());
this.allPlayers.add(match.getPlayer2());
}
public void addPlayer(TournamentPlayer player) {
this.allPlayers.add(player);
}
public int getRoundNumber() {
return this.roundNum;
}
public void setMatch (Match match) {
this.match = match;
}
public void setTableId (UUID tableId) {
this.tableId = tableId;
}
public boolean isRoundOver() {
boolean roundIsOver = true;
if (this.match != null) {
if (!this.match.hasEnded()) {
roundIsOver = false;
}
}
return roundIsOver;
}
}

View file

@ -262,6 +262,12 @@ public abstract class TournamentImpl implements Tournament {
updateResults(); updateResults();
} }
protected void playMultiplayerRound(MultiplayerRound round) {
playMultiPlayerMatch(round);
updateResults(); // show points from byes
}
protected List<TournamentPlayer> getActivePlayers() { protected List<TournamentPlayer> getActivePlayers() {
List<TournamentPlayer> activePlayers = new ArrayList<>(); List<TournamentPlayer> activePlayers = new ArrayList<>();
for (TournamentPlayer player : players.values()) { for (TournamentPlayer player : players.values()) {
@ -457,6 +463,10 @@ public abstract class TournamentImpl implements Tournament {
tableEventSource.fireTableEvent(EventType.START_MATCH, pair, options.getMatchOptions()); tableEventSource.fireTableEvent(EventType.START_MATCH, pair, options.getMatchOptions());
} }
public void playMultiPlayerMatch(MultiplayerRound round) {
tableEventSource.fireTableEvent(EventType.START_MULTIPLAYER_MATCH, round, options.getMatchOptions());
}
public void end() { public void end() {
endTime = new Date(); endTime = new Date();
tableEventSource.fireTableEvent(EventType.END); tableEventSource.fireTableEvent(EventType.END);

View file

@ -41,15 +41,16 @@ public class TournamentOptions implements Serializable {
protected String name; protected String name;
protected String tournamentType; protected String tournamentType;
protected List<String> playerTypes = new ArrayList<>(); protected List<String> playerTypes = new ArrayList<>();
protected MatchOptions matchOptions = new MatchOptions("", "Two Player Duel"); protected MatchOptions matchOptions;
protected LimitedOptions limitedOptions; protected LimitedOptions limitedOptions;
protected boolean watchingAllowed = true; protected boolean watchingAllowed = true;
protected int numberRounds; protected int numberRounds;
protected String password; protected String password;
protected int quitRatio; protected int quitRatio;
public TournamentOptions(String name) { public TournamentOptions(String name, String matchType, int numSeats) {
this.name = name; this.name = name;
this.matchOptions = new MatchOptions("", matchType, numSeats > 2, numSeats);
} }
public String getName() { public String getName() {

View file

@ -34,8 +34,8 @@ package mage.game.tournament;
*/ */
public class TournamentSealedOptions extends TournamentOptions { public class TournamentSealedOptions extends TournamentOptions {
public TournamentSealedOptions(String name) { public TournamentSealedOptions(String name, String matchType, int numSeats) {
super(name); super(name, matchType, numSeats);
} }
} }

View file

@ -28,6 +28,7 @@
package mage.game.tournament; package mage.game.tournament;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import mage.game.events.TableEvent; import mage.game.events.TableEvent;
@ -50,6 +51,7 @@ public abstract class TournamentSingleElimination extends TournamentImpl {
entry.getValue().setResults("Auto Eliminated"); entry.getValue().setResults("Auto Eliminated");
} }
} }
if (options.matchOptions.getNumSeats() == 2) {
while (this.getActivePlayers().size() > 1) { while (this.getActivePlayers().size() > 1) {
// check if some player got killed / disconnected meanwhile and update their state // check if some player got killed / disconnected meanwhile and update their state
tableEventSource.fireTableEvent(TableEvent.EventType.CHECK_STATE_PLAYERS); tableEventSource.fireTableEvent(TableEvent.EventType.CHECK_STATE_PLAYERS);
@ -57,6 +59,14 @@ public abstract class TournamentSingleElimination extends TournamentImpl {
playRound(round); playRound(round);
eliminatePlayers(round); eliminatePlayers(round);
} }
} else {
MultiplayerRound round = new MultiplayerRound(0, this, options.matchOptions.getNumSeats());
for (TournamentPlayer player : getActivePlayers()) {
round.addPlayer(player);
}
playMultiplayerRound(round);
}
nextStep(); nextStep();
} }

View file

@ -56,6 +56,7 @@ public abstract class TournamentSwiss extends TournamentImpl {
} }
} }
if (options.matchOptions.getNumSeats() == 2) {
while (this.getActivePlayers().size() > 1 && this.getNumberRounds() > this.getRounds().size()) { while (this.getActivePlayers().size() > 1 && this.getNumberRounds() > this.getRounds().size()) {
// check if some player got killed / disconnected meanwhile and update their state // check if some player got killed / disconnected meanwhile and update their state
tableEventSource.fireTableEvent(TableEvent.EventType.CHECK_STATE_PLAYERS); tableEventSource.fireTableEvent(TableEvent.EventType.CHECK_STATE_PLAYERS);
@ -63,6 +64,11 @@ public abstract class TournamentSwiss extends TournamentImpl {
Round round = createRoundSwiss(); Round round = createRoundSwiss();
playRound(round); playRound(round);
} }
} else {
MultiplayerRound round = createMultiplayerRound();
playMultiplayerRound(round);
}
nextStep(); nextStep();
} }
@ -70,6 +76,8 @@ public abstract class TournamentSwiss extends TournamentImpl {
List<TournamentPlayer> roundPlayers = getActivePlayers(); List<TournamentPlayer> roundPlayers = getActivePlayers();
boolean isLastRound = (rounds.size() + 1 == getNumberRounds()); boolean isLastRound = (rounds.size() + 1 == getNumberRounds());
Round round = null;
if (options.matchOptions.getNumSeats() == 2) {
RoundPairings roundPairings; RoundPairings roundPairings;
if (roundPlayers.size() <= 16) { if (roundPlayers.size() <= 16) {
SwissPairingMinimalWeightMatching swissPairing = new SwissPairingMinimalWeightMatching(roundPlayers, rounds, isLastRound); SwissPairingMinimalWeightMatching swissPairing = new SwissPairingMinimalWeightMatching(roundPlayers, rounds, isLastRound);
@ -79,7 +87,7 @@ public abstract class TournamentSwiss extends TournamentImpl {
roundPairings = swissPairing.getRoundPairings(); roundPairings = swissPairing.getRoundPairings();
} }
Round round = new Round(rounds.size() + 1, this); round = new Round(rounds.size() + 1, this);
rounds.add(round); rounds.add(round);
for (TournamentPairing pairing : roundPairings.getPairings()) { for (TournamentPairing pairing : roundPairings.getPairings()) {
round.addPairing(pairing); round.addPairing(pairing);
@ -95,8 +103,33 @@ public abstract class TournamentSwiss extends TournamentImpl {
playerBye.setStateInfo("Round Bye"); playerBye.setStateInfo("Round Bye");
updateResults(); updateResults();
} }
}
return round; return round;
} }
public MultiplayerRound createMultiplayerRound() {
List<TournamentPlayer> roundPlayers = getActivePlayers();
boolean isLastRound = (rounds.size() + 1 == getNumberRounds());
MultiplayerRound round = null;
if (options.matchOptions.getNumSeats() > 2) {
RoundPairings roundPairings;
if (roundPlayers.size() <= 16) {
SwissPairingMinimalWeightMatching swissPairing = new SwissPairingMinimalWeightMatching(roundPlayers, rounds, isLastRound);
roundPairings = swissPairing.getRoundPairings();
} else {
SwissPairingSimple swissPairing = new SwissPairingSimple(roundPlayers, rounds);
roundPairings = swissPairing.getRoundPairings();
}
round = new MultiplayerRound(rounds.size() + 1, this, options.matchOptions.getNumSeats());
for (TournamentPairing pairing : roundPairings.getPairings()) {
round.addPairing(pairing);
}
}
return round;
}
} }

View file

@ -2870,7 +2870,7 @@ public abstract class PlayerImpl implements Player, Serializable {
for (Mode mode : option.getModes().values()) { for (Mode mode : option.getModes().values()) {
Ability newOption = option.copy(); Ability newOption = option.copy();
newOption.getModes().getSelectedModes().clear(); newOption.getModes().getSelectedModes().clear();
newOption.getModes().getSelectedModes().add(mode); newOption.getModes().getSelectedModes().add(mode.getId());
newOption.getModes().setActiveMode(mode); newOption.getModes().setActiveMode(mode);
if (newOption.getTargets().getUnchosen().size() > 0) { if (newOption.getTargets().getUnchosen().size() > 0) {
if (newOption.getManaCosts().getVariableCosts().size() > 0) { if (newOption.getManaCosts().getVariableCosts().size() > 0) {

View file

@ -25,10 +25,13 @@
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.target.common; package mage.target.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
/** /**
@ -55,4 +58,16 @@ public class TargetCreatureOrPlaneswalker extends TargetPermanent {
return new TargetCreatureOrPlaneswalker(this); return new TargetCreatureOrPlaneswalker(this);
} }
@Override
public boolean isLegal(Ability source, Game game) {
for (UUID playerId : targets.keySet()) {
Player targetPlayer = game.getPlayer(playerId);
if (targetPlayer != null) {
// there seems to be no possibility to add more predicates for theplayer so return here true
return true;
}
}
return super.isLegal(source, game); //To change body of generated methods, choose Tools | Templates.
}
} }

View file

@ -70,7 +70,7 @@ public class TargetAddress {
protected Iterator<SpellAbility> spellAbilityIterator; protected Iterator<SpellAbility> spellAbilityIterator;
protected Integer lastSpellAbilityIndex = null; protected Integer lastSpellAbilityIndex = null;
protected Iterator<Mode> modeIterator = null; protected Iterator<UUID> modeIterator = null;
protected Modes modes = null; protected Modes modes = null;
protected UUID lastMode = null; protected UUID lastMode = null;
protected Iterator<Target> targetIterator = null; protected Iterator<Target> targetIterator = null;
@ -127,7 +127,7 @@ public class TargetAddress {
} }
if (modeIterator != null && modeIterator.hasNext()) { if (modeIterator != null && modeIterator.hasNext()) {
lastMode = modeIterator.next().getId(); lastMode = modeIterator.next();
targetIterator = modes.get(lastMode).getTargets().iterator(); targetIterator = modes.get(lastMode).getTargets().iterator();
} else { } else {
lastMode = null; lastMode = null;

View file

@ -102,6 +102,9 @@ git log 79f8617cd3c997d89770094d7a44294b0a48731f..head --diff-filter=A --name-st
since 1.4.15v2 since 1.4.15v2
git log d9c804602ea116d80a74d53eaf07ee7a15cd7d81..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt git log d9c804602ea116d80a74d53eaf07ee7a15cd7d81..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt
since 1.4.15v5
git log 73a2ccda9b36552a09cb2b6a5aef37559866d7fc..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt
3. Copy added_cards.txt to trunk\Utils folder 3. Copy added_cards.txt to trunk\Utils folder
4. Run script: 4. Run script:
> perl extract_in_wiki_format.perl > perl extract_in_wiki_format.perl