Merge branch 'master' into scryfall-improvements

This commit is contained in:
Rafael Damasceno 2019-05-28 15:43:03 +01:00
commit 6dbaa9f7cc
84 changed files with 2366 additions and 359 deletions

View file

@ -668,6 +668,12 @@ public class NewTableDialog extends MageDialog {
return false;
}
break;
case "Variant Magic - Oathbreaker":
if (!options.getGameType().startsWith("Oathbreaker")) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Oathbreaker needs also a Oathbreaker game type", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
break;
}
// game => deck
@ -704,6 +710,13 @@ public class NewTableDialog extends MageDialog {
return false;
}
break;
case "Oathbreaker Two Player Duel":
case "Oathbreaker Free For All":
if (!options.getDeckType().equals("Variant Magic - Oathbreaker")) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Oathbreaker needs also a Oathbreaker game type", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
break;
}
return true;
}

View file

@ -1,42 +1,27 @@
package mage.client.game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.Field;
import java.util.UUID;
import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.MenuSelectionManager;
import javax.swing.event.ChangeListener;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.cards.BigCard;
import mage.client.dialog.PreferencesDialog;
import static mage.client.dialog.PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS;
import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT;
import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE;
import static mage.client.dialog.PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY;
import mage.client.util.GUISizeHelper;
import mage.constants.PlayerAction;
import mage.view.PlayerView;
import mage.view.UserRequestMessage;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.Field;
import java.util.UUID;
import static mage.client.dialog.PreferencesDialog.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class PlayAreaPanel extends javax.swing.JPanel {
@ -77,7 +62,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
popupMenu = new JPopupMenu();
if (options.isPlayer) {
addPopupMenuPlayer(player.getUserData().isAllowRequestShowHandCards());
addPopupMenuPlayer(player.getUserData().isAllowRequestHandToAll());
} else {
addPopupMenuWatcher();
}
@ -331,12 +316,12 @@ public class PlayAreaPanel extends javax.swing.JPanel {
// Request to see hand cards
menuItem.addActionListener(e -> SessionHandler.sendPlayerAction(PlayerAction.REQUEST_PERMISSION_TO_SEE_HAND_CARDS, gameId, playerId));
} else {
allowViewHandCardsMenuItem = new JCheckBoxMenuItem("Allow requests to show from other users", allowRequestToShowHandCards);
allowViewHandCardsMenuItem = new JCheckBoxMenuItem("Allow hand requests from other users", allowRequestToShowHandCards);
allowViewHandCardsMenuItem.setMnemonic(KeyEvent.VK_A);
allowViewHandCardsMenuItem.setToolTipText("If activated watchers or other players can request to see your hand cards. If you grant this to a user, it's valid for the complete match.");
allowViewHandCardsMenuItem.setToolTipText("Watchers or other players can request your hand cards once per game. Re-activate it to allow new requests.");
handCardsMenu.add(allowViewHandCardsMenuItem);
// Requests allowed
// requests allowed (disable -> enable to reset requested list)
allowViewHandCardsMenuItem.addActionListener(e -> {
boolean requestsAllowed = ((JCheckBoxMenuItem) e.getSource()).getState();
PreferencesDialog.setPrefValue(KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, requestsAllowed);
@ -451,13 +436,13 @@ public class PlayAreaPanel extends javax.swing.JPanel {
}
});
popupMenu.addSeparator();
menuItem = new JMenuItem("<html>View current deck");
menuItem.setMnemonic(KeyEvent.VK_V);
popupMenu.add(menuItem);
// View limited deck
menuItem.addActionListener(e -> {
SessionHandler.sendPlayerAction(PlayerAction.VIEW_LIMITED_DECK, gameId, null);
@ -522,7 +507,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
this.playerPanel.update(player);
this.battlefieldPanel.update(player.getBattlefield());
if (this.allowViewHandCardsMenuItem != null) {
this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestShowHandCards());
this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestHandToAll());
}
}
@ -547,14 +532,14 @@ public class PlayAreaPanel extends javax.swing.JPanel {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(battlefieldPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(battlefieldPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(Alignment.LEADING)
.addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(battlefieldPanel, GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE)
.addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(battlefieldPanel, GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE)
);
this.setLayout(layout);
}

View file

@ -47,7 +47,7 @@
<Component id="btnQuickStartDuel" min="-2" max="-2" attributes="0"/>
<Component id="btnQuickStartCommander" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="734" max="32767" attributes="0"/>
<EmptySpace pref="667" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -290,7 +290,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRatedbtnFilterActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnUnrated">
@ -307,7 +307,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnUnratedbtnFilterActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
</SubComponents>
@ -396,7 +396,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFormatVintageActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatPremodern">
@ -412,7 +412,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFormatPremodernActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator3">
@ -433,6 +433,22 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatOathbreaker">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Oathbreaker"/>
<Property name="toolTipText" type="java.lang.String" value="Oathbreaker format."/>
<Property name="focusPainted" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatTinyLeader">
<Properties>
<Property name="selected" type="boolean" value="true"/>

View file

@ -329,11 +329,11 @@ public class TablesPanel extends javax.swing.JPanel {
chatPanelMain.getUserChatPanel().setBorder(null);
chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES);
// 4. BUTTONS
// 4. BUTTONS (add new buttons to the end of the list -- if not then users lost their filter settings)
filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished,
btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited,
btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatPremodern, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther,
btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword};
btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword, btnFormatOathbreaker};
JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables};
for (JComponent component : components) {
@ -817,6 +817,9 @@ public class TablesPanel extends javax.swing.JPanel {
if (btnFormatTinyLeader.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatOathbreaker.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Oathbreaker", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatLimited.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE));
}
@ -967,6 +970,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnFormatPremodern = new javax.swing.JToggleButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
btnFormatCommander = new javax.swing.JToggleButton();
btnFormatOathbreaker = new javax.swing.JToggleButton();
btnFormatTinyLeader = new javax.swing.JToggleButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
btnFormatLimited = new javax.swing.JToggleButton();
@ -1180,7 +1184,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnRated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnRated.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRatedbtnFilterActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar1.add(btnRated);
@ -1197,7 +1201,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnUnrated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnUnrated.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnUnratedbtnFilterActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar1.add(btnUnrated);
@ -1279,7 +1283,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnFormatVintage.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnFormatVintage.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFormatVintageActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatVintage);
@ -1295,7 +1299,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnFormatPremodern.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnFormatPremodern.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFormatPremodernActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatPremodern);
@ -1317,6 +1321,22 @@ public class TablesPanel extends javax.swing.JPanel {
});
filterBar2.add(btnFormatCommander);
btnFormatOathbreaker.setSelected(true);
btnFormatOathbreaker.setText("Oathbreaker");
btnFormatOathbreaker.setToolTipText("Oathbreaker format.");
btnFormatOathbreaker.setFocusPainted(false);
btnFormatOathbreaker.setFocusable(false);
btnFormatOathbreaker.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
btnFormatOathbreaker.setRequestFocusEnabled(false);
btnFormatOathbreaker.setVerifyInputWhenFocusTarget(false);
btnFormatOathbreaker.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnFormatOathbreaker.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatOathbreaker);
btnFormatTinyLeader.setSelected(true);
btnFormatTinyLeader.setText("Tiny Leader");
btnFormatTinyLeader.setToolTipText("Tiny Leader format.");
@ -1432,7 +1452,7 @@ public class TablesPanel extends javax.swing.JPanel {
.addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnQuickStartDuel)
.addComponent(btnQuickStartCommander))
.addContainerGap(734, Short.MAX_VALUE))
.addContainerGap(667, Short.MAX_VALUE))
);
jPanelTopLayout.setVerticalGroup(
jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -1631,22 +1651,6 @@ public class TablesPanel extends javax.swing.JPanel {
this.startUpdateTasks(true);
}//GEN-LAST:event_btnStateFinishedActionPerformed
private void btnRatedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRatedbtnFilterActionPerformed
setTableFilter();
}//GEN-LAST:event_btnRatedbtnFilterActionPerformed
private void btnUnratedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUnratedbtnFilterActionPerformed
setTableFilter();
}//GEN-LAST:event_btnUnratedbtnFilterActionPerformed
private void btnFormatPremodernActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatPremodernActionPerformed
setTableFilter();
}//GEN-LAST:event_btnFormatPremodernActionPerformed
private void btnFormatVintageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatVintageActionPerformed
setTableFilter();
}//GEN-LAST:event_btnFormatVintageActionPerformed
private void buttonWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonWhatsNewActionPerformed
MageFrame.getInstance().showWhatsNewDialog(true);
}//GEN-LAST:event_buttonWhatsNewActionPerformed
@ -1666,6 +1670,7 @@ public class TablesPanel extends javax.swing.JPanel {
private javax.swing.JToggleButton btnFormatLegacy;
private javax.swing.JToggleButton btnFormatLimited;
private javax.swing.JToggleButton btnFormatModern;
private javax.swing.JToggleButton btnFormatOathbreaker;
private javax.swing.JToggleButton btnFormatOther;
private javax.swing.JToggleButton btnFormatPremodern;
private javax.swing.JToggleButton btnFormatStandard;

View file

@ -1,9 +1,10 @@
package mage.view;
import java.io.Serializable;
import mage.players.net.UserData;
import mage.players.net.UserSkipPrioritySteps;
import java.io.Serializable;
/**
* Transfer object for {@link mage.players.net.UserData}
*
@ -14,7 +15,6 @@ public class UserDataView implements Serializable {
protected int avatarId;
protected int userGroup;
protected boolean showAbilityPickerForced;
protected boolean allowRequestShowHandCards;
protected boolean confirmEmptyManaPool;
protected UserSkipPrioritySteps userSkipPrioritySteps;
String flagName;
@ -29,10 +29,9 @@ public class UserDataView implements Serializable {
}
public UserDataView(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards,
boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) {
boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) {
this.avatarId = avatarId;
this.showAbilityPickerForced = showAbilityPickerForced;
this.allowRequestShowHandCards = allowRequestShowHandCards;
this.userSkipPrioritySteps = userSkipPrioritySteps;
this.confirmEmptyManaPool = confirmEmptyManaPool;
this.flagName = flagName;
@ -43,7 +42,6 @@ public class UserDataView implements Serializable {
public UserDataView(UserData userData) {
this.avatarId = userData.getAvatarId();
this.userGroup = userData.getGroupId();
this.allowRequestShowHandCards = userData.isAllowRequestShowHandCards();
this.showAbilityPickerForced = userData.isShowAbilityPickerForced();
this.userSkipPrioritySteps = userData.getUserSkipPrioritySteps();
this.confirmEmptyManaPool = userData.confirmEmptyManaPool();
@ -59,10 +57,6 @@ public class UserDataView implements Serializable {
return showAbilityPickerForced;
}
public boolean allowRequestShowHandCards() {
return allowRequestShowHandCards;
}
public UserSkipPrioritySteps getUserSkipPrioritySteps() {
return userSkipPrioritySteps;
}

View file

@ -166,6 +166,12 @@ public class Commander extends Constructed {
}
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');

View file

@ -67,8 +67,6 @@ public class FreeformCommander extends Constructed {
}
}
generateFreeformHash();
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
invalid.put("Commander", "Sideboard must contain only the commander(s)");
valid = false;
@ -116,6 +114,11 @@ public class FreeformCommander extends Constructed {
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');
@ -142,8 +145,4 @@ public class FreeformCommander extends Constructed {
|| cardColor.isRed() && !commander.isRed()
|| cardColor.isWhite() && !commander.isWhite());
}
public void generateFreeformHash() {
return;
}
}

View file

@ -0,0 +1,215 @@
package mage.deck;
import mage.abilities.Ability;
import mage.abilities.keyword.PartnerAbility;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.filter.FilterMana;
import java.util.*;
/**
* @author JayDi85
*/
public class Oathbreaker extends Vintage {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
public Oathbreaker() {
super();
this.name = "Oathbreaker";
// banned = vintage + oathbreaker's list: https://weirdcards.org/oathbreaker-ban-list
// last updated 4/4/19 - High Tide banned
banned.add("Ad Nauseam");
banned.add("Ancestral Recall");
banned.add("Balance");
banned.add("Biorhythm");
banned.add("Black Lotus");
banned.add("Channel");
banned.add("Doomsday");
banned.add("Emrakul, the Aeons Torn");
banned.add("Expropriate");
banned.add("Fastbond");
banned.add("Gifts Ungiven");
banned.add("Griselbrand");
banned.add("High Tide");
banned.add("Library of Alexandria");
banned.add("Limited Resources");
banned.add("Lion's Eye Diamond");
banned.add("Mana Crypt");
banned.add("Mana Geyser");
banned.add("Mana Vault");
banned.add("Mox Emerald");
banned.add("Mox Jet");
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Natural Order");
banned.add("Painter's Servant");
banned.add("Panoptic Mirror");
banned.add("Primal Surge");
banned.add("Primeval Titan");
banned.add("Recurring Nightmare");
banned.add("Saheeli, the Gifted");
banned.add("Sol Ring");
banned.add("Sundering Titan");
banned.add("Sway of the Stars");
banned.add("Sylvan Primordial");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Tooth and Nail");
banned.add("Trade Secrets");
banned.add("Upheaval");
banned.add("Worldfire");
banned.add("Yawgmoth's Bargain");
}
@Override
public int getDeckMinSize() {
return 60 - (1 + 2); // spell + 2 x partner oathbreakers
}
@Override
public int getSideboardMinSize() {
return 2; // spell + oathbreaker
}
@Override
public boolean validate(Deck deck) {
boolean valid = true;
FilterMana colorIdentity = new FilterMana();
if (deck.getCards().size() + deck.getSideboard().size() != 60) {
invalid.put("Deck", "Must contain " + 60 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
}
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
Set<String> commanderNames = new HashSet<>();
String signatureSpell = null;
if (deck.getSideboard().size() < 2 || deck.getSideboard().size() > 3) {
invalid.put("Oathbreaker", "Sideboard must contain only the oathbreaker(s) with signature spell");
valid = false;
} else {
for (Card commander : deck.getSideboard()) {
if (commander.isInstantOrSorcery()) {
if (signatureSpell == null) {
signatureSpell = commander.getName();
} else {
invalid.put("Signature spell", "Only one signature spell allows, but found: " + signatureSpell + " and " + commander.getName());
valid = false;
}
} else {
if (commander.isPlaneswalker()) {
commanderNames.add(commander.getName());
} else {
invalid.put("Oathbreaker", "Only planeswalker can be Oathbreaker, not " + commander.getName());
valid = false;
}
}
}
for (Card commander : deck.getSideboard()) {
if (commanderNames.contains(commander.getName())) {
// partner checks
if (commanderNames.size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) {
boolean partnersWith = false;
for (Ability ability : commander.getAbilities()) {
if (ability instanceof PartnerWithAbility && commanderNames.contains(((PartnerWithAbility) ability).getPartnerName())) {
partnersWith = true;
break;
}
}
if (!partnersWith) {
invalid.put("Oathbreaker", "Oathbreaker without Partner (" + commander.getName() + ')');
valid = false;
}
}
// color identity from commanders only, not spell
FilterMana commanderColor = commander.getColorIdentity();
if (commanderColor.isWhite()) {
colorIdentity.setWhite(true);
}
if (commanderColor.isBlue()) {
colorIdentity.setBlue(true);
}
if (commanderColor.isBlack()) {
colorIdentity.setBlack(true);
}
if (commanderColor.isRed()) {
colorIdentity.setRed(true);
}
if (commanderColor.isGreen()) {
colorIdentity.setGreen(true);
}
}
}
if (commanderNames.size() == 0) {
invalid.put("Sideboard", "Can't find any oathbreaker");
valid = false;
}
if (signatureSpell == null) {
invalid.put("Sideboard", "Can't find signature spell");
valid = false;
}
}
// signature spell color
for (Card card : deck.getSideboard()) {
if (card.getName().equals(signatureSpell) && !cardHasValidColor(colorIdentity, card)) {
invalid.put(card.getName(), "Invalid color for signature spell (" + colorIdentity.toString() + ')');
valid = false;
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
invalid.put(card.getName(), "Not allowed Set: " + card.getExpansionSetCode());
valid = false;
}
}
}
return valid;
}
public boolean cardHasValidColor(FilterMana commander, Card card) {
FilterMana cardColor = card.getColorIdentity();
return !(cardColor.isBlack() && !commander.isBlack()
|| cardColor.isBlue() && !commander.isBlue()
|| cardColor.isGreen() && !commander.isGreen()
|| cardColor.isRed() && !commander.isRed()
|| cardColor.isWhite() && !commander.isWhite());
}
}

View file

@ -124,6 +124,12 @@ public class PennyDreadfulCommander extends Constructed {
}
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');

View file

@ -0,0 +1,55 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.35</version>
</parent>
<artifactId>mage-game-oathbreakerduel</artifactId>
<packaging>jar</packaging>
<name>Mage Game Oathbreaker Two Player</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.mage</groupId>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
<version>1.4.35</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<finalName>mage-game-oathbreakerduel</finalName>
</build>
<properties/>
</project>

View file

@ -0,0 +1,36 @@
package mage.game;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
/**
* @author JayDi85
*/
public class OathbreakerDuel extends OathbreakerFreeForAll {
public OathbreakerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife);
}
public OathbreakerDuel(final OathbreakerDuel game) {
super(game);
}
@Override
public MatchType getGameType() {
return new OathbreakerDuelType();
}
@Override
public int getNumPlayers() {
return 2;
}
@Override
public OathbreakerDuel copy() {
return new OathbreakerDuel(this);
}
}

View file

@ -0,0 +1,29 @@
package mage.game;
import mage.game.match.MatchImpl;
import mage.game.match.MatchOptions;
import mage.game.mulligan.Mulligan;
/**
* @author JayDi85
*/
public class OathbreakerDuelMatch extends MatchImpl {
public OathbreakerDuelMatch(MatchOptions options) {
super(options);
}
@Override
public void startGame() throws GameException {
int startLife = 20;
boolean alsoHand = true;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
OathbreakerDuel game = new OathbreakerDuel(options.getAttackOption(), options.getRange(), mulligan, startLife);
game.setCheckCommanderDamage(false);
game.setStartMessage(this.createGameStartMessage());
game.setAlsoHand(alsoHand);
game.setAlsoLibrary(true);
initGame(game);
games.add(game);
}
}

View file

@ -0,0 +1,29 @@
package mage.game;
import mage.game.match.MatchType;
/**
* @author JayDi85
*/
public class OathbreakerDuelType extends MatchType {
public OathbreakerDuelType() {
this.name = "Oathbreaker Two Player Duel";
this.maxPlayers = 2;
this.minPlayers = 2;
this.numTeams = 0;
this.useAttackOption = false;
this.useRange = false;
this.sideboardingAllowed = false;
}
protected OathbreakerDuelType(final OathbreakerDuelType matchType) {
super(matchType);
}
@Override
public OathbreakerDuelType copy() {
return new OathbreakerDuelType(this);
}
}

View file

@ -0,0 +1,50 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.35</version>
</parent>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
<packaging>jar</packaging>
<name>Mage Game Oathbreaker Free For All</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<finalName>mage-game-freeforall</finalName>
</build>
<properties/>
</project>

View file

@ -0,0 +1,143 @@
package mage.game;
import mage.abilities.Ability;
import mage.abilities.common.SignatureSpellCastOnlyWithOathbreakerEffect;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.OathbreakerOnBattlefieldCondition;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.hint.ConditionHint;
import mage.cards.Card;
import mage.constants.CommanderCardType;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
import mage.players.Player;
import mage.watchers.common.CommanderInfoWatcher;
import java.util.*;
/**
* @author JayDi85
*/
public class OathbreakerFreeForAll extends GameCommanderImpl {
private int numPlayers;
private Map<UUID, UUID> playerSignatureSpell = new HashMap<>();
private Map<UUID, List<UUID>> playerCommanders = new HashMap<>();
public OathbreakerFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
super(attackOption, range, mulligan, startLife);
}
public OathbreakerFreeForAll(final OathbreakerFreeForAll game) {
super(game);
this.numPlayers = game.numPlayers;
this.playerSignatureSpell.putAll(game.playerSignatureSpell);
game.playerCommanders.forEach((key, value) -> this.playerCommanders.put(key, new ArrayList<>(value)));
}
@Override
protected void init(UUID choosingPlayerId) {
// init base commander game
startingPlayerSkipsDraw = false;
super.init(choosingPlayerId);
}
@Override
public CommanderInfoWatcher initCommanderWatcher(Card commander, boolean checkCommanderDamage) {
String commanderType;
if (commander.isInstantOrSorcery()) {
commanderType = "Signature Spell";
} else {
commanderType = "Oathbreaker";
}
return new CommanderInfoWatcher(commanderType, commander.getId(), checkCommanderDamage);
}
@Override
public void initCommanderEffects(Card commander, Player player, Ability commanderAbility) {
// all commander effects must be independent from sourceId or controllerId
super.initCommanderEffects(commander, player, commanderAbility);
// signature spell restrict (spell can be casted on player's commander on battlefield)
if (commander.getId().equals(this.playerSignatureSpell.getOrDefault(player.getId(), null))) {
Condition condition = new OathbreakerOnBattlefieldCondition(player.getId(), this.playerCommanders.getOrDefault(player.getId(), null));
commanderAbility.addEffect(new SignatureSpellCastOnlyWithOathbreakerEffect(condition, commander.getId()));
// hint must be added to card, not global ability
Ability ability = new SimpleStaticAbility(new InfoEffect("Signature spell hint"));
ability.addHint(new ConditionHint(condition, "Oathbreaker on battlefield"));
ability.setRuleVisible(false);
commander.addAbility(ability);
}
}
@Override
public void addCommander(Card card, Player player) {
super.addCommander(card, player);
// prepare signature and commanders info
if (card.isInstantOrSorcery()) {
this.playerSignatureSpell.put(player.getId(), card.getId());
} else {
List<UUID> list = this.playerCommanders.getOrDefault(player.getId(), null);
if (list == null) {
list = new ArrayList<>();
this.playerCommanders.put(player.getId(), list);
}
if (!list.contains(card.getId())) {
list.add(card.getId());
}
}
}
@Override
public MatchType getGameType() {
return new OathbreakerFreeForAllType();
}
@Override
public int getNumPlayers() {
return numPlayers;
}
public void setNumPlayers(int numPlayers) {
this.numPlayers = numPlayers;
}
@Override
public OathbreakerFreeForAll copy() {
return new OathbreakerFreeForAll(this);
}
@Override
public Set<UUID> getCommandersIds(Player player, CommanderCardType commanderCardType) {
Set<UUID> res = new HashSet<>();
if (player != null) {
List<UUID> commanders = this.playerCommanders.getOrDefault(player.getId(), new ArrayList<>());
UUID spell = this.playerSignatureSpell.getOrDefault(player.getId(), null);
for (UUID id : player.getCommandersIds()) {
switch (commanderCardType) {
case ANY:
res.add(id);
break;
case COMMANDER_OR_OATHBREAKER:
if (commanders.contains(id)) {
res.add(id);
}
break;
case SIGNATURE_SPELL:
if (id.equals(spell)) {
res.add(id);
}
break;
default:
throw new IllegalStateException("Unknown commander type " + commanderCardType);
}
}
}
return res;
}
}

View file

@ -0,0 +1,30 @@
package mage.game;
import mage.game.match.MatchImpl;
import mage.game.match.MatchOptions;
import mage.game.mulligan.Mulligan;
/**
* @author JayDi85
*/
public class OathbreakerFreeForAllMatch extends MatchImpl {
public OathbreakerFreeForAllMatch(MatchOptions options) {
super(options);
}
@Override
public void startGame() throws GameException {
int startLife = 20;
boolean alsoHand = true;
Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans());
OathbreakerFreeForAll game = new OathbreakerFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife);
game.setCheckCommanderDamage(false);
game.setStartMessage(this.createGameStartMessage());
game.setAlsoHand(alsoHand);
game.setAlsoLibrary(true);
initGame(game);
games.add(game);
}
}

View file

@ -0,0 +1,29 @@
package mage.game;
import mage.game.match.MatchType;
/**
* @author JayDi85
*/
public class OathbreakerFreeForAllType extends MatchType {
public OathbreakerFreeForAllType() {
this.name = "Oathbreaker Free For All";
this.maxPlayers = 10;
this.minPlayers = 3;
this.numTeams = 0;
this.useAttackOption = true;
this.useRange = true;
this.sideboardingAllowed = false;
}
protected OathbreakerFreeForAllType(final OathbreakerFreeForAllType matchType) {
super(matchType);
}
@Override
public OathbreakerFreeForAllType copy() {
return new OathbreakerFreeForAllType(this);
}
}

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
@ -26,19 +27,21 @@
<module>Mage.Game.CanadianHighlanderDuel</module>
<module>Mage.Game.PennyDreadfulCommanderFreeForAll</module>
<module>Mage.Game.FreeformCommanderDuel</module>
<module>Mage.Game.FreeformCommanderFreeForAll</module>
<module>Mage.Game.BrawlDuel</module>
<module>Mage.Game.FreeformCommanderFreeForAll</module>
<module>Mage.Game.BrawlDuel</module>
<module>Mage.Game.BrawlFreeForAll</module>
<module>Mage.Game.OathbreakerDuel</module>
<module>Mage.Game.OathbreakerFreeForAll</module>
<module>Mage.Game.TwoPlayerDuel</module>
<module>Mage.Player.AI</module>
<module>Mage.Player.AIMinimax</module>
<module>Mage.Player.AI.MA</module>
<module>Mage.Player.AIMCTS</module>
<module>Mage.Player.AI.DraftBot</module>
<module>Mage.Player.AI.DraftBot</module>
<module>Mage.Player.Human</module>
<module>Mage.Tournament.BoosterDraft</module>
<module>Mage.Tournament.Constructed</module>
<module>Mage.Tournament.Sealed</module>
<module>Mage.Tournament.Sealed</module>
</modules>
</project>

View file

@ -81,6 +81,8 @@
<gameType name="Penny Dreadful Commander Free For All" jar="mage-game-pennydreadfulcommanderfreeforall.jar" className="mage.game.PennyDreadfulCommanderFreeForAllMatch" typeName="mage.game.PennyDreadfulCommanderFreeForAllType"/>
<gameType name="Freeform Commander Two Player Duel" jar="mage-game-freeformcommanderduel.jar" className="mage.game.FreeformCommanderDuelMatch" typeName="mage.game.FreeformCommanderDuelType"/>
<gameType name="Freeform Commander Free For All" jar="mage-game-freeformcommanderfreeforall.jar" className="mage.game.FreeformCommanderFreeForAllMatch" typeName="mage.game.FreeformCommanderFreeForAllType"/>
<gameType name="Oathbreaker Two Player Duel" jar="mage-game-oathbreakerduel.jar" className="mage.game.OathbreakerDuelMatch" typeName="mage.game.OathbreakerDuelType"/>
<gameType name="Oathbreaker Free For All" jar="mage-game-oathbreakerfreeforall.jar" className="mage.game.OathbreakerFreeForAllMatch" typeName="mage.game.OathbreakerFreeForAllType"/>
<gameType name="Brawl Two Player Duel" jar="mage-game-brawlduel.jar" className="mage.game.BrawlDuelMatch" typeName="mage.game.BrawlDuelType"/>
<gameType name="Brawl Free For All" jar="mage-game-brawlfreeforall.jar" className="mage.game.BrawlFreeForAllMatch" typeName="mage.game.BrawlFreeForAllType"/>
<gameType name="Momir Basic Two Player Duel" jar="mage-game-momirduel.jar" className="mage.game.MomirDuelMatch" typeName="mage.game.MomirDuelType"/>
@ -160,7 +162,7 @@
<deckType name="Constructed - Old School 93/94 - Channel Fireball Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394CFB"/>
<deckType name="Constructed - Old School 93/94 - EudoGames Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394EG"/>
<deckType name="Constructed - Old School 93/94 - EC Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394EC"/>
<deckType name="Constructed - Premodern" jar="mage-deck-constructed.jar" className="mage.deck.Premodern"/>
<deckType name="Constructed - Premodern" jar="mage-deck-constructed.jar" className="mage.deck.Premodern"/>
<deckType name="Constructed - Freeform" jar="mage-deck-constructed.jar" className="mage.deck.Freeform"/>
<deckType name="Variant Magic - Commander" jar="mage-deck-constructed.jar" className="mage.deck.Commander"/>
<deckType name="Variant Magic - Duel Commander" jar="mage-deck-constructed.jar" className="mage.deck.DuelCommander"/>
@ -170,6 +172,7 @@
<deckType name="Variant Magic - Penny Dreadful Commander" jar="mage-deck-constructed.jar" className="mage.deck.PennyDreadfulCommander"/>
<deckType name="Variant Magic - Freeform Commander" jar="mage-deck-constructed.jar" className="mage.deck.FreeformCommander"/>
<deckType name="Variant Magic - Brawl" jar="mage-deck-constructed.jar" className="mage.deck.Brawl"/>
<deckType name="Variant Magic - Oathbreaker" jar="mage-deck-constructed.jar" className="mage.deck.Oathbreaker"/>
<deckType name="Block Constructed - Amonkhet" jar="mage-deck-constructed.jar" className="mage.deck.AmonkhetBlock"/>
<deckType name="Block Constructed - Battle for Zendikar" jar="mage-deck-constructed.jar" className="mage.deck.BattleForZendikarBlock"/>
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed.jar" className="mage.deck.InnistradBlock"/>
@ -188,4 +191,4 @@
<deckType name="Block Constructed Custom - Star Wars" jar="mage-deck-constructed.jar" className="mage.deck.StarWarsBlock"/>
<deckType name="Limited" jar="mage-deck-limited.jar" className="mage.deck.Limited"/>
</deckTypes>
</config>
</config>

View file

@ -178,6 +178,7 @@
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
@ -191,6 +192,19 @@
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-game-oathbreakerduel</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-game-momirduel</artifactId>

View file

@ -75,6 +75,8 @@
<gameType name="Penny Dreadful Commander Free For All" jar="mage-game-pennydreadfulcommanderfreeforall-${project.version}.jar" className="mage.game.PennyDreadfulCommanderFreeForAllMatch" typeName="mage.game.PennyDreadfulCommanderFreeForAllType"/>
<gameType name="Freeform Commander Two Player Duel" jar="mage-game-freeformcommanderduel-${project.version}.jar" className="mage.game.FreeformCommanderDuelMatch" typeName="mage.game.FreeformCommanderDuelType"/>
<gameType name="Freeform Commander Free For All" jar="mage-game-freeformcommanderfreeforall-${project.version}.jar" className="mage.game.FreeformCommanderFreeForAllMatch" typeName="mage.game.FreeformCommanderFreeForAllType"/>
<gameType name="Oathbreaker Two Player Duel" jar="mage-game-oathbreakerduel-${project.version}.jar" className="mage.game.OathbreakerDuelMatch" typeName="mage.game.OathbreakerDuelType"/>
<gameType name="Oathbreaker Free For All" jar="mage-game-oathbreakerfreeforall-${project.version}.jar" className="mage.game.OathbreakerFreeForAllMatch" typeName="mage.game.OathbreakerFreeForAllType"/>
<gameType name="Brawl Two Player Duel" jar="mage-game-brawlduel-${project.version}.jar" className="mage.game.BrawlDuelMatch" typeName="mage.game.BrawlDuelType"/>
<gameType name="Brawl Free For All" jar="mage-game-brawlfreeforall-${project.version}.jar" className="mage.game.BrawlFreeForAllMatch" typeName="mage.game.BrawlFreeForAllType"/>
<gameType name="Momir Basic Two Player Duel" jar="mage-game-momirduel-${project.version}.jar" className="mage.game.MomirDuelMatch" typeName="mage.game.MomirDuelType"/>
@ -154,8 +156,8 @@
<deckType name="Constructed - Old School 93/94 - Channel Fireball Rules" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.OldSchool9394CFB"/>
<deckType name="Constructed - Old School 93/94 - EudoGames Rules" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.OldSchool9394EG"/>
<deckType name="Constructed - Old School 93/94 - EC Rules" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.OldSchool9394EC"/>
<deckType name="Constructed - Premodern" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Premodern"/>
<deckType name="Constructed - Freeform" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Freeform"/>
<deckType name="Constructed - Premodern" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Premodern"/>
<deckType name="Constructed - Freeform" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Freeform"/>
<deckType name="Variant Magic - Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Commander"/>
<deckType name="Variant Magic - Duel Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.DuelCommander"/>
<deckType name="Variant Magic - MTGO 1v1 Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.MTGO1v1Commander"/>
@ -164,6 +166,7 @@
<deckType name="Variant Magic - Penny Dreadful Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.PennyDreadfulCommander"/>
<deckType name="Variant Magic - Freeform Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.FreeformCommander"/>
<deckType name="Variant Magic - Brawl" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Brawl"/>
<deckType name="Variant Magic - Oathbreaker" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Oathbreaker"/>
<deckType name="Block Constructed - Amonkhet" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.AmonkhetBlock"/>
<deckType name="Block Constructed - Battle for Zendikar" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.BattleForZendikarBlock"/>
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.InnistradBlock"/>

View file

@ -596,7 +596,9 @@ public class GameController implements GameCallback {
if (gameSession != null) {
UUID requestingPlayerId = getPlayerId(userIdRequester);
if (requestingPlayerId == null || !requestingPlayerId.equals(grantingPlayer.getId())) { // don't allow request for your own cards
if (grantingPlayer.isRequestToShowHandCardsAllowed()) {
if (grantingPlayer.isPlayerAllowedToRequestHand(game.getId(), requestingPlayerId)) {
// one time request per user restrict, enable request will reset users list and allows again
grantingPlayer.addPlayerToRequestedHandList(game.getId(), requestingPlayerId);
gameSession.requestPermissionToSeeHandCards(userIdRequester);
} else {
// player does not allow the request

View file

@ -522,10 +522,8 @@ public final class SystemUtil {
// as commander (only commander games, look at init code in GameCommanderImpl)
if (game instanceof GameCommanderImpl) {
GameCommanderImpl gameCommander = (GameCommanderImpl) game;
for (Card card : cardsToLoad) {
player.addCommanderId(card.getId());
gameCommander.initCommander(card, player);
}
cardsToLoad.forEach(card -> gameCommander.addCommander(card, player));
cardsToLoad.forEach(card -> gameCommander.initCommander(card, player));
} else {
logger.fatal("Commander card can be used in commander game only: " + command.cardName);
}

View file

@ -93,7 +93,7 @@ class ConspyEffect extends ContinuousEffectImpl {
}
}
// commander in command zone
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller)) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId);
if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) {

View file

@ -0,0 +1,50 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SuperType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ArcumsAstrolabe extends CardImpl {
public ArcumsAstrolabe(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{S}");
this.addSuperType(SuperType.SNOW);
// ({S} can be paid with one mana from a snow permanent.)
this.addAbility(new SimpleStaticAbility(
new InfoEffect("<i>({S} can be paid with one mana from a snow permanent.)</i>")
));
// When Arcum's Astrolabe enters the battlefield, draw a card.
this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)));
// {1}, {T}: Add one mana of any color.
Ability ability = new AnyColorManaAbility(new GenericManaCost(1));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
private ArcumsAstrolabe(final ArcumsAstrolabe card) {
super(card);
}
@Override
public ArcumsAstrolabe copy() {
return new ArcumsAstrolabe(this);
}
}

View file

@ -0,0 +1,57 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.HellbentCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.target.common.TargetPlayerOrPlaneswalker;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class BladebackSliver extends CardImpl {
public BladebackSliver(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}");
this.subtype.add(SubType.SLIVER);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Hellbent As long as you have no cards in hand, Sliver creatures you control have "{T}: This creature deals 1 damage to target player or planeswalker."
Ability ability = new SimpleActivatedAbility(
new DamageTargetEffect(1, "this creature"), new TapSourceCost()
);
ability.addTarget(new TargetPlayerOrPlaneswalker());
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityControlledEffect(
ability, Duration.WhileOnBattlefield,
StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS
), HellbentCondition.instance, "<i>Hellbent</i> &mdash; " +
"As long as you have no cards in hand, Sliver creatures you control have " +
"\"{T}: This creature deals 1 damage to target player or planeswalker.\""
)));
}
private BladebackSliver(final BladebackSliver card) {
super(card);
}
@Override
public BladebackSliver copy() {
return new BladebackSliver(this);
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.condition.LockedInCondition;
import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
@ -12,26 +10,30 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author Loki
*/
public final class BreakOfDay extends CardImpl {
public BreakOfDay(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
// Creatures you control get +1/+1 until end of turn.
this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn));
// Fateful hour - If you have 5 or less life, those creatures also are indestructible this turn.
this.getSpellAbility().addEffect(new ConditionalContinuousEffect(
new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control"), false),
new LockedInCondition(FatefulHourCondition.instance),
"If you have 5 or less life, those creatures also are indestructible this turn"));
new GainAbilityAllEffect(
IndestructibleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURES, false
), new LockedInCondition(FatefulHourCondition.instance),
"<br><i>Fateful hour</i> &mdash; If you have 5 or less life, " +
"those creatures also are indestructible this turn"
));
}
public BreakOfDay(final BreakOfDay card) {

View file

@ -1,9 +1,5 @@
package mage.cards.c;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
@ -21,21 +17,25 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTargets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
*
* @author BetaSteward
*/
public final class ClingingMists extends CardImpl {
public ClingingMists(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}");
// Prevent all combat damage that would be dealt this turn.
this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(null, Duration.EndOfTurn, true));
// Fateful hour - If you have 5 or less life, tap all attacking creatures. Those creatures don't untap during their controller's next untap step.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new ClingingMistsEffect(),
FatefulHourCondition.instance, "If you have 5 or less life, tap all attacking creatures. Those creatures don't untap during their controller's next untap step."));
FatefulHourCondition.instance, "<br><i>Fateful hour</i> &mdash; If you have 5 or less life, " +
"tap all attacking creatures. Those creatures don't untap during their controller's next untap step."));
}

View file

@ -0,0 +1,69 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.RestrictionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CollectorOuphe extends CardImpl {
public CollectorOuphe(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
this.subtype.add(SubType.OUPHE);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Activated abilities of artifacts can't be activated.
this.addAbility(new SimpleStaticAbility(new CollectorOupheEffect()));
}
private CollectorOuphe(final CollectorOuphe card) {
super(card);
}
@Override
public CollectorOuphe copy() {
return new CollectorOuphe(this);
}
}
class CollectorOupheEffect extends RestrictionEffect {
CollectorOupheEffect() {
super(Duration.WhileOnBattlefield);
staticText = "Activated abilities of artifacts can't be activated";
}
private CollectorOupheEffect(final CollectorOupheEffect effect) {
super(effect);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return permanent.isArtifact();
}
@Override
public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) {
return false;
}
@Override
public CollectorOupheEffect copy() {
return new CollectorOupheEffect(this);
}
}

View file

@ -1,9 +1,5 @@
package mage.cards.c;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
@ -14,19 +10,23 @@ import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.CommanderCardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
*
* @author emerald000
*/
public final class CommandBeacon extends CardImpl {
public CommandBeacon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
@ -67,7 +67,7 @@ class CommandBeaconEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<Card> commandersInCommandZone = new ArrayList<>(1);
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) {
Card commander = game.getCard(commanderId);
if (commander != null && game.getState().getZone(commander.getId()) == Zone.COMMAND) {
commandersInCommandZone.add(commander);
@ -75,14 +75,12 @@ class CommandBeaconEffect extends OneShotEffect {
}
if (commandersInCommandZone.size() == 1) {
controller.moveCards(commandersInCommandZone.get(0), Zone.HAND, source, game);
}
else if (commandersInCommandZone.size() == 2) {
} else if (commandersInCommandZone.size() == 2) {
Card firstCommander = commandersInCommandZone.get(0);
Card secondCommander = commandersInCommandZone.get(1);
if (controller.chooseUse(Outcome.ReturnToHand, "Return which commander to hand?", null, firstCommander.getName(), secondCommander.getName(), source, game)) {
controller.moveCards(firstCommander, Zone.HAND, source, game);
}
else {
} else {
controller.moveCards(secondCommander, Zone.HAND, source, game);
}
}

View file

@ -95,7 +95,7 @@ class ConspiracyEffect extends ContinuousEffectImpl {
}
}
// commander in command zone
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller)) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId);
if (card != null && card.isCreature()) {

View file

@ -0,0 +1,37 @@
package mage.cards.c;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.SuspendAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.permanent.token.RhinoToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CrashingFootfalls extends CardImpl {
public CrashingFootfalls(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "");
this.color.setGreen(true);
// Suspend 4{G}
this.addAbility(new SuspendAbility(4, new ManaCostsImpl("{G}"), this));
// Create two 4/4 green Rhino creature tokens with trample.
this.getSpellAbility().addEffect(new CreateTokenEffect(new RhinoToken(), 2));
}
private CrashingFootfalls(final CrashingFootfalls card) {
super(card);
}
@Override
public CrashingFootfalls copy() {
return new CrashingFootfalls(this);
}
}

View file

@ -0,0 +1,47 @@
package mage.cards.e;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.OutlastAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class EnduringSliver extends CardImpl {
public EnduringSliver(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.subtype.add(SubType.SLIVER);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Outlast {2}
this.addAbility(new OutlastAbility(new ManaCostsImpl("{2}")));
// Other sliver creatures you control have outlast {2}.
this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(
new OutlastAbility(new ManaCostsImpl("{2}")), Duration.WhileOnBattlefield,
StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, true
).setText("Other sliver creatures you control have outlast {2}.")));
}
private EnduringSliver(final EnduringSliver card) {
super(card);
}
@Override
public EnduringSliver copy() {
return new EnduringSliver(this);
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.g;
import java.util.UUID;
import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
@ -10,20 +8,20 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.permanent.token.HumanToken;
import java.util.UUID;
/**
*
* @author anonymous
*/
public final class GatherTheTownsfolk extends CardImpl {
public GatherTheTownsfolk(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}");
// Create two 1/1 white Human creature tokens.
// Fateful hour - If you have 5 or less life, create five of those tokens instead.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new CreateTokenEffect(new HumanToken(), 5), new CreateTokenEffect(new HumanToken(), 2),
FatefulHourCondition.instance, "Create two 1/1 white Human creature tokens. If you have 5 or less life, create five of those tokens instead"));
FatefulHourCondition.instance, "Create two 1/1 white Human creature tokens. <br><i>Fateful hour</i> &mdash; If you have 5 or less life, create five of those tokens instead"));
}
public GatherTheTownsfolk(final GatherTheTownsfolk card) {

View file

@ -1,7 +1,5 @@
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.FatefulHourCondition;
@ -10,19 +8,19 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
/**
*
* @author Loki
import java.util.UUID;
/**
* @author Loki
*/
public final class GavonyIronwright extends CardImpl {
public GavonyIronwright(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SOLDIER);
@ -31,7 +29,7 @@ public final class GavonyIronwright extends CardImpl {
// Fateful hour - As long as you have 5 or less life, other creatures you control get +1/+4.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostControlledEffect(1, 4, Duration.WhileOnBattlefield, false),
FatefulHourCondition.instance, "As long as you have 5 or less life, other creatures you control get +1/+4")));
FatefulHourCondition.instance, "<br><i>Fateful hour</i> &mdash; As long as you have 5 or less life, other creatures you control get +1/+4")));
}
public GavonyIronwright(final GavonyIronwright card) {

View file

@ -3,26 +3,28 @@ package mage.cards.g;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.watchers.common.CommanderPlaysCountWatcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author spjspj
* @author spjspj, JayDi85
*/
public final class GeodeGolem extends CardImpl {
@ -65,36 +67,53 @@ class GeodeGolemEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (UUID commanderId : controller.getCommandersIds()) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card commander = game.getCard(commanderId);
if (commander != null && game.getState().getZone(commanderId) == Zone.COMMAND) {
SpellAbility ability = commander.getSpellAbility();
SpellAbility newAbility = commander.getSpellAbility().copy();
newAbility.getCosts().clear();
UUID selectedCommanderId = null;
Set<UUID> possibleCommanders = new HashSet<>();
for (UUID id : game.getCommandersIds(controller)) {
if (game.getState().getZone(id) == Zone.COMMAND) {
possibleCommanders.add(id);
}
}
Integer castCount = (Integer) game.getState().getValue(commander.getId() + "_castCount");
Cost cost = null;
if (castCount > 0) {
cost = new GenericManaCost(castCount * 2);
}
if (possibleCommanders.size() == 0) {
return false;
}
if ((castCount == 0 || castCount > 0 && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null))
&& controller.cast(newAbility, game, true, new MageObjectReference(source.getSourceObject(game), game))) {
// save amount of times commander was cast
if (castCount == null) {
castCount = 1;
} else {
castCount++;
}
game.getState().setValue(commander.getId() + "_castCount", castCount);
return true;
}
// select from commanders
if (possibleCommanders.size() == 1) {
selectedCommanderId = possibleCommanders.iterator().next();
} else {
TargetCard target = new TargetCard(Zone.COMMAND, new FilterCard("commander to cast without mana cost"));
Cards cards = new CardsImpl(possibleCommanders);
target.setNotTarget(true);
if (controller.canRespond() && controller.choose(Outcome.Benefit, cards, target, game)) {
if (target.getFirstTarget() != null) {
selectedCommanderId = target.getFirstTarget();
}
}
}
return true;
Card commander = game.getCard(selectedCommanderId);
if (commander == null) {
return false;
}
// PAY
ManaCost cost = null;
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
int castCount = watcher.getPlaysCount(commander.getId());
if (castCount > 0) {
cost = new GenericManaCost(castCount * 2);
}
// CAST: as spell or as land
if (cost == null || cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) {
if (commander.getSpellAbility() != null) {
return controller.cast(commander.getSpellAbility().copy(), game, true, new MageObjectReference(source.getSourceObject(game), game));
} else {
return controller.playLand(commander, game, true);
}
}
}
return false;
}

View file

@ -0,0 +1,41 @@
package mage.cards.g;
import mage.MageInt;
import mage.abilities.keyword.ExaltedAbility;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class GoblinChampion extends CardImpl {
public GoblinChampion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}");
this.subtype.add(SubType.GOBLIN);
this.subtype.add(SubType.WARRIOR);
this.power = new MageInt(0);
this.toughness = new MageInt(1);
// Haste
this.addAbility(HasteAbility.getInstance());
// Exalted
this.addAbility(new ExaltedAbility());
}
private GoblinChampion(final GoblinChampion card) {
super(card);
}
@Override
public GoblinChampion copy() {
return new GoblinChampion(this);
}
}

View file

@ -0,0 +1,36 @@
package mage.cards.g;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class GoblinOriflamme extends CardImpl {
public GoblinOriflamme(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}");
// Attacking creatures you control get +1/+0.
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(
1, 0, Duration.EndOfTurn,
StaticFilters.FILTER_ATTACKING_CREATURES
)));
}
private GoblinOriflamme(final GoblinOriflamme card) {
super(card);
}
@Override
public GoblinOriflamme copy() {
return new GoblinOriflamme(this);
}
}

View file

@ -0,0 +1,52 @@
package mage.cards.i;
import mage.MageInt;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.NinjutsuAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class IngeniousInfiltrator extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledCreaturePermanent(SubType.NINJA, "a Ninja you control");
public IngeniousInfiltrator(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}");
this.subtype.add(SubType.VEDALKEN);
this.subtype.add(SubType.NINJA);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Ninjutsu {U}{B}
this.addAbility(new NinjutsuAbility(new ManaCostsImpl("{1}{U}")));
// Whenever a Ninja you control deals combat damage to a player, draw a card.
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
new DrawCardSourceControllerEffect(1), filter,
false, SetTargetPointer.NONE, true
));
}
private IngeniousInfiltrator(final IngeniousInfiltrator card) {
super(card);
}
@Override
public IngeniousInfiltrator copy() {
return new IngeniousInfiltrator(this);
}
}

View file

@ -109,8 +109,9 @@ class KarnLiberatedEffect extends OneShotEffect {
if (card.isOwnedBy(player.getId()) && !card.isCopy() // no copies
&& !player.getSideboard().contains(card.getId())
&& !cards.contains(card)) { // not the exiled cards
if (player.getCommandersIds().contains(card.getId())) {
game.addCommander(new Commander(card));
if (game.getCommandersIds(player).contains(card.getId())) {
game.addCommander(new Commander(card)); // TODO: check restart and init
// no needs in initCommander call -- it's uses on game startup (init)
game.setZone(card.getId(), Zone.COMMAND);
} else {
player.getLibrary().putOnTop(card, game);

View file

@ -0,0 +1,59 @@
package mage.cards.k;
import mage.abilities.Mode;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.SacrificeOpponentsEffect;
import mage.abilities.keyword.EntwineAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.filter.StaticFilters;
import mage.game.permanent.token.WhiteBlackSpiritToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class KayasGuile extends CardImpl {
public KayasGuile(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{B}");
// Choose two
this.getSpellAbility().getModes().setMinModes(2);
this.getSpellAbility().getModes().setMaxModes(2);
// Each opponent sacrifices a creature.
this.getSpellAbility().addEffect(new SacrificeOpponentsEffect(
StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT
));
// Exile all cards from each opponent's graveyard.
this.getSpellAbility().addMode(new Mode(new ExileGraveyardAllPlayersEffect(
StaticFilters.FILTER_CARD_CARDS, TargetController.OPPONENT
)));
// Create a 1/1 white and black Spirit creature token with flying.
this.getSpellAbility().addMode(new Mode(new CreateTokenEffect(new WhiteBlackSpiritToken())));
// You gain 4 life.
this.getSpellAbility().addMode(new Mode(new GainLifeEffect(4)));
// Entwine {3}
this.addAbility(new EntwineAbility(new ManaCostsImpl("{3}"), "Choose all if you pay the entwine cost."));
}
private KayasGuile(final KayasGuile card) {
super(card);
}
@Override
public KayasGuile copy() {
return new KayasGuile(this);
}
}

View file

@ -95,7 +95,7 @@ class MythUnboundCostReductionEffect extends CostModificationEffectImpl {
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof PlayLandAbility) {
if (abilityToModify.isControlledBy(source.getControllerId())) {
return player.getCommandersIds().contains(abilityToModify.getSourceId());
return game.getCommandersIds(player).contains(abilityToModify.getSourceId());
}
}
return false;

View file

@ -93,7 +93,7 @@ class OpalPalaceWatcher extends Watcher {
for (UUID playerId : game.getPlayerList()) {
Player player = game.getPlayer(playerId);
if (player != null) {
if (player.getCommandersIds().contains(card.getId())) {
if (game.getCommandersIds(player).contains(card.getId())) {
commanderId.add(card.getId());
break;
}

View file

@ -1,7 +1,5 @@
package mage.cards.p;
import java.util.Iterator;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
@ -22,8 +20,11 @@ import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class PathOfAncestry extends CardImpl {
@ -88,9 +89,10 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && spell.isCreature()) {
Player controller = game.getPlayer(getControllerId());
if (controller != null && controller.getCommandersIds() != null && !controller.getCommandersIds().isEmpty()) {
Set<UUID> commanders = game.getCommandersIds(controller);
if (controller != null && commanders != null && !commanders.isEmpty()) {
if (spell.getAbilities().contains(ChangelingAbility.getInstance())) {
for (UUID cmdr : controller.getCommandersIds()) {
for (UUID cmdr : commanders) {
MageObject commander = game.getObject(cmdr);
if (commander != null) {
if (commander.getAbilities().contains(ChangelingAbility.getInstance())) {
@ -110,7 +112,7 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl {
while (spellSubs.hasNext()) {
SubType sType = spellSubs.next();
if (sType.getSubTypeSet() == SubTypeSet.CreatureType) {
for (UUID cmdr : controller.getCommandersIds()) {
for (UUID cmdr : commanders) {
MageObject commander = game.getObject(cmdr);
if (commander != null && (commander.hasSubtype(sType, game) || commander.getAbilities().contains(ChangelingAbility.getInstance()))) {
return true;

View file

@ -0,0 +1,40 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SegovianAngel extends CardImpl {
public SegovianAngel(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
this.subtype.add(SubType.ANGEL);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
}
private SegovianAngel(final SegovianAngel card) {
super(card);
}
@Override
public SegovianAngel copy() {
return new SegovianAngel(this);
}
}

View file

@ -0,0 +1,41 @@
package mage.cards.s;
import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.target.TargetSpell;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SpellSnuff extends CardImpl {
public SpellSnuff(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}");
// Counter target spell.
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addTarget(new TargetSpell());
// Fateful hour If you have 5 or less life, draw a card.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new DrawCardSourceControllerEffect(1), FatefulHourCondition.instance,
"<br><i>Fateful hour</i> &mdash; If you have 5 or less life, draw a card."
));
}
private SpellSnuff(final SpellSnuff card) {
super(card);
}
@Override
public SpellSnuff copy() {
return new SpellSnuff(this);
}
}

View file

@ -0,0 +1,88 @@
package mage.cards.s;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class StringOfDisappearances extends CardImpl {
public StringOfDisappearances(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
this.getSpellAbility().addEffect(new StringOfDisappearancesEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
private StringOfDisappearances(final StringOfDisappearances card) {
super(card);
}
@Override
public StringOfDisappearances copy() {
return new StringOfDisappearances(this);
}
}
class StringOfDisappearancesEffect extends OneShotEffect {
StringOfDisappearancesEffect() {
super(Outcome.Damage);
this.staticText = "Return target creature to its owner's hand. " +
"Then that creature's controller may pay {U}{U}. " +
"If the player does, they may copy this spell " +
"and may choose a new target for that copy.";
}
private StringOfDisappearancesEffect(final StringOfDisappearancesEffect effect) {
super(effect);
}
@Override
public StringOfDisappearancesEffect copy() {
return new StringOfDisappearancesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent == null) {
return false;
}
Player affectedPlayer = game.getPlayer(permanent.getControllerId());
new ReturnToHandTargetEffect().apply(game, source);
if (affectedPlayer == null) {
return false;
}
if (!affectedPlayer.chooseUse(Outcome.Copy, "Pay {U}{U} to copy the spell?", source, game)) {
return true;
}
Cost cost = new ManaCostsImpl("{U}{U}");
if (!cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false, null)) {
return true;
}
Spell spell = game.getStack().getSpell(source.getSourceId());
if (spell == null) {
return true;
}
spell.createCopyOnStack(game, source, affectedPlayer.getId(), true);
game.informPlayers(affectedPlayer.getLogName() + " copies " + spell.getName() + '.');
return true;
}
}

View file

@ -0,0 +1,42 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.RedManaAbility;
import mage.abilities.mana.WhiteManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TalismanOfConviction extends CardImpl {
public TalismanOfConviction(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {T}: Add {R} or {W}. Talisman of Conviction deals 1 damage to you.
Ability ability = new RedManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
ability = new WhiteManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
}
private TalismanOfConviction(final TalismanOfConviction card) {
super(card);
}
@Override
public TalismanOfConviction copy() {
return new TalismanOfConviction(this);
}
}

View file

@ -0,0 +1,42 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.RedManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TalismanOfCreativity extends CardImpl {
public TalismanOfCreativity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {T}: Add {U} or {R}. Talisman of Creativity deals 1 damage to you.
Ability ability = new BlueManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
ability = new RedManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
}
private TalismanOfCreativity(final TalismanOfCreativity card) {
super(card);
}
@Override
public TalismanOfCreativity copy() {
return new TalismanOfCreativity(this);
}
}

View file

@ -0,0 +1,42 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.GreenManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TalismanOfCuriosity extends CardImpl {
public TalismanOfCuriosity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {T}: Add {G} or {U}. Talisman of Curiosity deals 1 damage to you.
Ability ability = new GreenManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
ability = new BlueManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
}
private TalismanOfCuriosity(final TalismanOfCuriosity card) {
super(card);
}
@Override
public TalismanOfCuriosity copy() {
return new TalismanOfCuriosity(this);
}
}

View file

@ -0,0 +1,42 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.BlackManaAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.WhiteManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TalismanOfHierarchy extends CardImpl {
public TalismanOfHierarchy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {T}: Add {W} or {B}. Talisman of Hierarchy deals 1 damage to you.
Ability ability = new WhiteManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
ability = new BlackManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
}
private TalismanOfHierarchy(final TalismanOfHierarchy card) {
super(card);
}
@Override
public TalismanOfHierarchy copy() {
return new TalismanOfHierarchy(this);
}
}

View file

@ -0,0 +1,42 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.BlackManaAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.GreenManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TalismanOfResilience extends CardImpl {
public TalismanOfResilience(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {T}: Add {B} or {G}. Talisman of Resilience deals 1 damage to you.
Ability ability = new BlackManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
ability = new GreenManaAbility();
ability.addEffect(new DamageControllerEffect(1));
this.addAbility(ability);
}
private TalismanOfResilience(final TalismanOfResilience card) {
super(card);
}
@Override
public TalismanOfResilience copy() {
return new TalismanOfResilience(this);
}
}

View file

@ -99,7 +99,7 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
}
}
// commander in command zone
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller)) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId);
if (card != null && card.isCreature()) {

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -13,19 +11,20 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.permanent.token.HumanToken;
import java.util.UUID;
/**
*
* @author anonymous
*/
public final class ThrabenDoomsayer extends CardImpl {
public ThrabenDoomsayer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC);
@ -36,7 +35,7 @@ public final class ThrabenDoomsayer extends CardImpl {
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new HumanToken()), new TapSourceCost()));
// Fateful hour - As long as you have 5 or less life, other creatures you control get +2/+2.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, true),
FatefulHourCondition.instance, "As long as you have 5 or less life, other creatures you control get +2/+2")));
FatefulHourCondition.instance, "<br><i>Fateful hour</i> &mdash; As long as you have 5 or less life, other creatures you control get +2/+2")));
}
public ThrabenDoomsayer(final ThrabenDoomsayer card) {

View file

@ -0,0 +1,101 @@
package mage.cards.v;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.ChangelingAbility;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ValiantChangeling extends CardImpl {
public ValiantChangeling(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}");
this.subtype.add(SubType.SHAPESHIFTER);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// This spell costs {1} less to cast for each creature type among creatures you control. This effect can't reduce the amount of mana this spell costs by more than {5}.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new ValiantChangelingCostReductionEffect()));
// Changeling
this.addAbility(ChangelingAbility.getInstance());
// Double strike
this.addAbility(DoubleStrikeAbility.getInstance());
}
private ValiantChangeling(final ValiantChangeling card) {
super(card);
}
@Override
public ValiantChangeling copy() {
return new ValiantChangeling(this);
}
}
class ValiantChangelingCostReductionEffect extends CostModificationEffectImpl {
ValiantChangelingCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each creature type among creatures you control. " +
"This effect can't reduce the amount of mana this spell costs by more than {5}.";
}
private ValiantChangelingCostReductionEffect(ValiantChangelingCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
Set<SubType> subTypes = new HashSet();
int reductionAmount = 0;
for (Permanent permanent : game.getBattlefield().getActivePermanents(
StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game
)) {
if (permanent.getAbilities().contains(ChangelingAbility.getInstance())
|| permanent.isAllCreatureTypes()) {
reductionAmount = 5;
break;
}
subTypes.addAll(permanent.getSubtype(game));
reductionAmount = subTypes.size();
if (reductionAmount > 4) {
break;
}
}
CardUtil.reduceCost(abilityToModify, Math.max(reductionAmount, 5));
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if ((abilityToModify instanceof SpellAbility)
&& abilityToModify.getSourceId().equals(source.getSourceId())) {
return game.getCard(abilityToModify.getSourceId()) != null;
}
return false;
}
@Override
public ValiantChangelingCostReductionEffect copy() {
return new ValiantChangelingCostReductionEffect(this);
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.v;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.FatefulHourCondition;
@ -11,13 +9,14 @@ import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author Loki
*/
public final class VillageSurvivors extends CardImpl {
@ -34,7 +33,7 @@ public final class VillageSurvivors extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, true),
FatefulHourCondition.instance,
"Fateful hour - As long as you have 5 or less life, other creatures you control have vigilance")));
"<br><i>Fateful hour</i> &mdash; As long as you have 5 or less life, other creatures you control have vigilance")));
}
public VillageSurvivors(final VillageSurvivors card) {

View file

@ -0,0 +1,34 @@
package mage.cards.w;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.StormAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class WeatherTheStorm extends CardImpl {
public WeatherTheStorm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}");
// You gain 3 life.
this.getSpellAbility().addEffect(new GainLifeEffect(3));
// Storm
this.addAbility(new StormAbility());
}
private WeatherTheStorm(final WeatherTheStorm card) {
super(card);
}
@Override
public WeatherTheStorm copy() {
return new WeatherTheStorm(this);
}
}

View file

@ -0,0 +1,54 @@
package mage.cards.w;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CardsInControllerGraveCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.ChangelingAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class WebweaverChangeling extends CardImpl {
public WebweaverChangeling(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}");
this.subtype.add(SubType.SHAPESHIFTER);
this.power = new MageInt(3);
this.toughness = new MageInt(5);
// Changeling
this.addAbility(ChangelingAbility.getInstance());
// Reach
this.addAbility(ReachAbility.getInstance());
// When Webweaver Changeling enters the battlefield, if there are three or more creature cards in your graveyard, you gain 5 life.
this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(
new GainLifeEffect(5),
new CardsInControllerGraveCondition(
3, StaticFilters.FILTER_CARD_CREATURE
), "When {this} enters the battlefield, if there are three or more " +
"creature cards in your graveyard, you gain 5 life."
)));
}
private WebweaverChangeling(final WebweaverChangeling card) {
super(card);
}
@Override
public WebweaverChangeling copy() {
return new WebweaverChangeling(this);
}
}

View file

@ -0,0 +1,72 @@
package mage.cards.y;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.effects.common.counter.ProliferateEffect;
import mage.abilities.keyword.ProtectionAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class YawgmothThranPhysician extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.HUMAN, "Humans");
public YawgmothThranPhysician(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(2);
this.toughness = new MageInt(4);
// Protection from Humans.
this.addAbility(new ProtectionAbility(filter));
// Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card.
Ability ability = new SimpleActivatedAbility(
new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new PayLifeCost(1)
);
ability.addCost(new SacrificeTargetCost(
new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)
));
ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and"));
ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability);
// {B}{B}, Discard a card: Proliferate.
ability = new SimpleActivatedAbility(new ProliferateEffect(), new ManaCostsImpl("{B}{B}"));
ability.addCost(new DiscardCardCost());
this.addAbility(ability);
}
private YawgmothThranPhysician(final YawgmothThranPhysician card) {
super(card);
}
@Override
public YawgmothThranPhysician copy() {
return new YawgmothThranPhysician(this);
}
}

View file

@ -1,4 +1,3 @@
package mage.sets;
import mage.cards.ExpansionSet;
@ -36,6 +35,7 @@ public final class BattleForZendikar extends ExpansionSet {
this.ratioBoosterMythic = 8;
this.numBoosterSpecial = 0;
this.ratioBoosterSpecialLand = 144;
cards.add(new SetCardInfo("Adverse Conditions", 54, Rarity.UNCOMMON, mage.cards.a.AdverseConditions.class));
cards.add(new SetCardInfo("Akoum Firebird", 138, Rarity.MYTHIC, mage.cards.a.AkoumFirebird.class));
cards.add(new SetCardInfo("Akoum Hellkite", 139, Rarity.RARE, mage.cards.a.AkoumHellkite.class));
@ -43,21 +43,21 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Aligned Hedron Network", 222, Rarity.RARE, mage.cards.a.AlignedHedronNetwork.class));
cards.add(new SetCardInfo("Ally Encampment", 228, Rarity.RARE, mage.cards.a.AllyEncampment.class));
cards.add(new SetCardInfo("Altar's Reap", 103, Rarity.COMMON, mage.cards.a.AltarsReap.class));
cards.add(new SetCardInfo("Angel of Renewal", 18, Rarity.UNCOMMON, mage.cards.a.AngelOfRenewal.class));
cards.add(new SetCardInfo("Angelic Captain", 208, Rarity.RARE, mage.cards.a.AngelicCaptain.class));
cards.add(new SetCardInfo("Angelic Gift", 19, Rarity.COMMON, mage.cards.a.AngelicGift.class));
cards.add(new SetCardInfo("Angel of Renewal", 18, Rarity.UNCOMMON, mage.cards.a.AngelOfRenewal.class));
cards.add(new SetCardInfo("Anticipate", 69, Rarity.COMMON, mage.cards.a.Anticipate.class));
cards.add(new SetCardInfo("Bane of Bala Ged", 1, Rarity.UNCOMMON, mage.cards.b.BaneOfBalaGed.class));
cards.add(new SetCardInfo("Barrage Tyrant", 127, Rarity.RARE, mage.cards.b.BarrageTyrant.class));
cards.add(new SetCardInfo("Beastcaller Savant", 170, Rarity.RARE, mage.cards.b.BeastcallerSavant.class));
cards.add(new SetCardInfo("Belligerent Whiptail", 141, Rarity.COMMON, mage.cards.b.BelligerentWhiptail.class));
cards.add(new SetCardInfo("Benthic Infiltrator", 55, Rarity.COMMON, mage.cards.b.BenthicInfiltrator.class));
cards.add(new SetCardInfo("Blight Herder", 2, Rarity.RARE, mage.cards.b.BlightHerder.class));
cards.add(new SetCardInfo("Blighted Cataract", 229, Rarity.UNCOMMON, mage.cards.b.BlightedCataract.class));
cards.add(new SetCardInfo("Blighted Fen", 230, Rarity.UNCOMMON, mage.cards.b.BlightedFen.class));
cards.add(new SetCardInfo("Blighted Gorge", 231, Rarity.UNCOMMON, mage.cards.b.BlightedGorge.class));
cards.add(new SetCardInfo("Blighted Steppe", 232, Rarity.UNCOMMON, mage.cards.b.BlightedSteppe.class));
cards.add(new SetCardInfo("Blighted Woodland", 233, Rarity.UNCOMMON, mage.cards.b.BlightedWoodland.class));
cards.add(new SetCardInfo("Blight Herder", 2, Rarity.RARE, mage.cards.b.BlightHerder.class));
cards.add(new SetCardInfo("Blisterpod", 163, Rarity.COMMON, mage.cards.b.Blisterpod.class));
cards.add(new SetCardInfo("Bloodbond Vampire", 104, Rarity.UNCOMMON, mage.cards.b.BloodbondVampire.class));
cards.add(new SetCardInfo("Boiling Earth", 142, Rarity.COMMON, mage.cards.b.BoilingEarth.class));
@ -66,8 +66,8 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Brilliant Spectrum", 70, Rarity.COMMON, mage.cards.b.BrilliantSpectrum.class));
cards.add(new SetCardInfo("Bring to Light", 209, Rarity.RARE, mage.cards.b.BringToLight.class));
cards.add(new SetCardInfo("Brood Butcher", 199, Rarity.RARE, mage.cards.b.BroodButcher.class));
cards.add(new SetCardInfo("Broodhunter Wurm", 171, Rarity.COMMON, mage.cards.b.BroodhunterWurm.class));
cards.add(new SetCardInfo("Brood Monitor", 164, Rarity.UNCOMMON, mage.cards.b.BroodMonitor.class));
cards.add(new SetCardInfo("Broodhunter Wurm", 171, Rarity.COMMON, mage.cards.b.BroodhunterWurm.class));
cards.add(new SetCardInfo("Brutal Expulsion", 200, Rarity.RARE, mage.cards.b.BrutalExpulsion.class));
cards.add(new SetCardInfo("Call the Scions", 165, Rarity.COMMON, mage.cards.c.CallTheScions.class));
cards.add(new SetCardInfo("Canopy Vista", 234, Rarity.RARE, mage.cards.c.CanopyVista.class));
@ -94,8 +94,8 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Dispel", 76, Rarity.COMMON, mage.cards.d.Dispel.class));
cards.add(new SetCardInfo("Dominator Drone", 92, Rarity.COMMON, mage.cards.d.DominatorDrone.class));
cards.add(new SetCardInfo("Dragonmaster Outcast", 144, Rarity.MYTHIC, mage.cards.d.DragonmasterOutcast.class));
cards.add(new SetCardInfo("Drana, Liberator of Malakir", 109, Rarity.MYTHIC, mage.cards.d.DranaLiberatorOfMalakir.class));
cards.add(new SetCardInfo("Drana's Emissary", 210, Rarity.UNCOMMON, mage.cards.d.DranasEmissary.class));
cards.add(new SetCardInfo("Drana, Liberator of Malakir", 109, Rarity.MYTHIC, mage.cards.d.DranaLiberatorOfMalakir.class));
cards.add(new SetCardInfo("Drowner of Hope", 57, Rarity.RARE, mage.cards.d.DrownerOfHope.class));
cards.add(new SetCardInfo("Dust Stalker", 202, Rarity.RARE, mage.cards.d.DustStalker.class));
cards.add(new SetCardInfo("Dutiful Return", 110, Rarity.COMMON, mage.cards.d.DutifulReturn.class));
@ -116,22 +116,22 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Firemantle Mage", 145, Rarity.UNCOMMON, mage.cards.f.FiremantleMage.class));
cards.add(new SetCardInfo("Forerunner of Slaughter", 204, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfSlaughter.class));
cards.add(new SetCardInfo("Forest", "270a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "274b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", "271a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "272a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "273a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "274a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "270b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", "271b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", "272b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", "273b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 270, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 271, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 272, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 273, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 274, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Fortified Rampart", 27, Rarity.COMMON, mage.cards.f.FortifiedRampart.class));
cards.add(new SetCardInfo("From Beyond", 167, Rarity.RARE, mage.cards.f.FromBeyond.class));
cards.add(new SetCardInfo("Geyserfield Stalker", 111, Rarity.COMMON, mage.cards.g.GeyserfieldStalker.class));
cards.add(new SetCardInfo("Ghostly Sentinel", 28, Rarity.COMMON, mage.cards.g.GhostlySentinel.class));
cards.add(new SetCardInfo("Giant Mantis", 173, Rarity.COMMON, mage.cards.g.GiantMantis.class));
cards.add(new SetCardInfo("Gideon, Ally of Zendikar", 29, Rarity.MYTHIC, mage.cards.g.GideonAllyOfZendikar.class));
cards.add(new SetCardInfo("Gideon's Reproach", 30, Rarity.COMMON, mage.cards.g.GideonsReproach.class));
cards.add(new SetCardInfo("Gideon, Ally of Zendikar", 29, Rarity.MYTHIC, mage.cards.g.GideonAllyOfZendikar.class));
cards.add(new SetCardInfo("Goblin War Paint", 146, Rarity.COMMON, mage.cards.g.GoblinWarPaint.class));
cards.add(new SetCardInfo("Grave Birthing", 93, Rarity.COMMON, mage.cards.g.GraveBirthing.class));
cards.add(new SetCardInfo("Greenwarden of Murasa", 174, Rarity.MYTHIC, mage.cards.g.GreenwardenOfMurasa.class));
@ -152,15 +152,15 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Infuse with the Elements", 175, Rarity.UNCOMMON, mage.cards.i.InfuseWithTheElements.class));
cards.add(new SetCardInfo("Inspired Charge", 32, Rarity.COMMON, mage.cards.i.InspiredCharge.class));
cards.add(new SetCardInfo("Island", "255a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "259b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", "256a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "257a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "258a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "259a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "255b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", "256b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", "257b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", "258b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", 256, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", 257, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", 258, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", 259, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Jaddi Offshoot", 176, Rarity.UNCOMMON, mage.cards.j.JaddiOffshoot.class));
cards.add(new SetCardInfo("Kalastria Healer", 114, Rarity.COMMON, mage.cards.k.KalastriaHealer.class));
cards.add(new SetCardInfo("Kalastria Nightwatch", 115, Rarity.COMMON, mage.cards.k.KalastriaNightwatch.class));
@ -187,16 +187,15 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Molten Nursery", 130, Rarity.UNCOMMON, mage.cards.m.MoltenNursery.class));
cards.add(new SetCardInfo("Mortuary Mire", 240, Rarity.COMMON, mage.cards.m.MortuaryMire.class));
cards.add(new SetCardInfo("Mountain", "265a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "269b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", "266a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "267a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "268a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "269a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "265b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", "266b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", "267b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", "268b", Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 266, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 267, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 268, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 269, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Munda, Ambush Leader", 215, Rarity.RARE, mage.cards.m.MundaAmbushLeader.class));
cards.add(new SetCardInfo("Murasa Ranger", 178, Rarity.UNCOMMON, mage.cards.m.MurasaRanger.class));
cards.add(new SetCardInfo("Murk Strider", 62, Rarity.COMMON, mage.cards.m.MurkStrider.class));
@ -205,8 +204,8 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Nirkana Assassin", 118, Rarity.COMMON, mage.cards.n.NirkanaAssassin.class));
cards.add(new SetCardInfo("Nissa's Renewal", 180, Rarity.RARE, mage.cards.n.NissasRenewal.class));
cards.add(new SetCardInfo("Noyan Dar, Roil Shaper", 216, Rarity.RARE, mage.cards.n.NoyanDarRoilShaper.class));
cards.add(new SetCardInfo("Oblivion Sower", 11, Rarity.MYTHIC, mage.cards.o.OblivionSower.class));
cards.add(new SetCardInfo("Ob Nixilis Reignited", 119, Rarity.MYTHIC, mage.cards.o.ObNixilisReignited.class));
cards.add(new SetCardInfo("Oblivion Sower", 11, Rarity.MYTHIC, mage.cards.o.OblivionSower.class));
cards.add(new SetCardInfo("Omnath, Locus of Rage", 217, Rarity.MYTHIC, mage.cards.o.OmnathLocusOfRage.class));
cards.add(new SetCardInfo("Ondu Champion", 149, Rarity.COMMON, mage.cards.o.OnduChampion.class));
cards.add(new SetCardInfo("Ondu Greathorn", 40, Rarity.COMMON, mage.cards.o.OnduGreathorn.class));
@ -220,15 +219,15 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Pathway Arrows", 225, Rarity.UNCOMMON, mage.cards.p.PathwayArrows.class));
cards.add(new SetCardInfo("Pilgrim's Eye", 226, Rarity.UNCOMMON, mage.cards.p.PilgrimsEye.class));
cards.add(new SetCardInfo("Plains", "250a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "254b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", "251a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "252a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "253a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "254a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "250b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", "251b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", "252b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", "253b", Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", 252, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", 253, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", 254, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Planar Outburst", 42, Rarity.RARE, mage.cards.p.PlanarOutburst.class));
cards.add(new SetCardInfo("Plated Crusher", 183, Rarity.UNCOMMON, mage.cards.p.PlatedCrusher.class));
cards.add(new SetCardInfo("Plummet", 184, Rarity.COMMON, mage.cards.p.Plummet.class));
@ -246,14 +245,14 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Retreat to Kazandu", 186, Rarity.UNCOMMON, mage.cards.r.RetreatToKazandu.class));
cards.add(new SetCardInfo("Retreat to Valakut", 153, Rarity.UNCOMMON, mage.cards.r.RetreatToValakut.class));
cards.add(new SetCardInfo("Rising Miasma", 122, Rarity.UNCOMMON, mage.cards.r.RisingMiasma.class));
cards.add(new SetCardInfo("Roilmage's Trick", 83, Rarity.COMMON, mage.cards.r.RoilmagesTrick.class));
cards.add(new SetCardInfo("Roil Spout", 219, Rarity.UNCOMMON, mage.cards.r.RoilSpout.class));
cards.add(new SetCardInfo("Roil's Retribution", 45, Rarity.UNCOMMON, mage.cards.r.RoilsRetribution.class));
cards.add(new SetCardInfo("Roilmage's Trick", 83, Rarity.COMMON, mage.cards.r.RoilmagesTrick.class));
cards.add(new SetCardInfo("Rolling Thunder", 154, Rarity.UNCOMMON, mage.cards.r.RollingThunder.class));
cards.add(new SetCardInfo("Rot Shambler", 187, Rarity.UNCOMMON, mage.cards.r.RotShambler.class));
cards.add(new SetCardInfo("Ruin Processor", 12, Rarity.COMMON, mage.cards.r.RuinProcessor.class));
cards.add(new SetCardInfo("Ruination Guide", 64, Rarity.UNCOMMON, mage.cards.r.RuinationGuide.class));
cards.add(new SetCardInfo("Ruinous Path", 123, Rarity.RARE, mage.cards.r.RuinousPath.class));
cards.add(new SetCardInfo("Ruin Processor", 12, Rarity.COMMON, mage.cards.r.RuinProcessor.class));
cards.add(new SetCardInfo("Rush of Ice", 84, Rarity.COMMON, mage.cards.r.RushOfIce.class));
cards.add(new SetCardInfo("Salvage Drone", 65, Rarity.COMMON, mage.cards.s.SalvageDrone.class));
cards.add(new SetCardInfo("Sanctum of Ugin", 242, Rarity.RARE, mage.cards.s.SanctumOfUgin.class));
@ -283,20 +282,20 @@ public final class BattleForZendikar extends ExpansionSet {
cards.add(new SetCardInfo("Spawning Bed", 248, Rarity.UNCOMMON, mage.cards.s.SpawningBed.class));
cards.add(new SetCardInfo("Spell Shrivel", 66, Rarity.COMMON, mage.cards.s.SpellShrivel.class));
cards.add(new SetCardInfo("Stasis Snare", 50, Rarity.UNCOMMON, mage.cards.s.StasisSnare.class));
cards.add(new SetCardInfo("Stonefury", 156, Rarity.COMMON, mage.cards.s.Stonefury.class));
cards.add(new SetCardInfo("Stone Haven Medic", 51, Rarity.COMMON, mage.cards.s.StoneHavenMedic.class));
cards.add(new SetCardInfo("Stonefury", 156, Rarity.COMMON, mage.cards.s.Stonefury.class));
cards.add(new SetCardInfo("Sunken Hollow", 249, Rarity.RARE, mage.cards.s.SunkenHollow.class));
cards.add(new SetCardInfo("Sure Strike", 157, Rarity.COMMON, mage.cards.s.SureStrike.class));
cards.add(new SetCardInfo("Swamp", "260a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "264b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", "261a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "262a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "263a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "264a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "260b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", "261b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", "262b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", "263b", Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", 260, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", 262, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", 263, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", 264, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swarm Surge", 100, Rarity.COMMON, mage.cards.s.SwarmSurge.class));
cards.add(new SetCardInfo("Swell of Growth", 191, Rarity.COMMON, mage.cards.s.SwellOfGrowth.class));
cards.add(new SetCardInfo("Sylvan Scrying", 192, Rarity.UNCOMMON, mage.cards.s.SylvanScrying.class));

View file

@ -29,24 +29,30 @@ public final class ModernHorizons extends ExpansionSet {
cards.add(new SetCardInfo("Abominable Treefolk", 194, Rarity.UNCOMMON, mage.cards.a.AbominableTreefolk.class));
cards.add(new SetCardInfo("Altar of Dementia", 218, Rarity.RARE, mage.cards.a.AltarOfDementia.class));
cards.add(new SetCardInfo("Archmage's Charm", 40, Rarity.RARE, mage.cards.a.ArchmagesCharm.class));
cards.add(new SetCardInfo("Arcum's Astrolabe", 220, Rarity.COMMON, mage.cards.a.ArcumsAstrolabe.class));
cards.add(new SetCardInfo("Aria of Flame", 118, Rarity.RARE, mage.cards.a.AriaOfFlame.class));
cards.add(new SetCardInfo("Astral Drift", 3, Rarity.RARE, mage.cards.a.AstralDrift.class));
cards.add(new SetCardInfo("Ayula's Influence", 156, Rarity.RARE, mage.cards.a.AyulasInfluence.class));
cards.add(new SetCardInfo("Ayula, Queen Among Bears", 155, Rarity.RARE, mage.cards.a.AyulaQueenAmongBears.class));
cards.add(new SetCardInfo("Battle Screech", 4, Rarity.UNCOMMON, mage.cards.b.BattleScreech.class));
cards.add(new SetCardInfo("Bazaar Trademage", 41, Rarity.RARE, mage.cards.b.BazaarTrademage.class));
cards.add(new SetCardInfo("Bladeback Sliver", 119, Rarity.COMMON, mage.cards.b.BladebackSliver.class));
cards.add(new SetCardInfo("Cabal Therapist", 80, Rarity.RARE, mage.cards.c.CabalTherapist.class));
cards.add(new SetCardInfo("Changeling Outcast", 82, Rarity.COMMON, mage.cards.c.ChangelingOutcast.class));
cards.add(new SetCardInfo("Chillerpillar", 43, Rarity.COMMON, mage.cards.c.Chillerpillar.class));
cards.add(new SetCardInfo("Choking Tethers", 44, Rarity.COMMON, mage.cards.c.ChokingTethers.class));
cards.add(new SetCardInfo("Cloudshredder Sliver", 195, Rarity.RARE, mage.cards.c.CloudshredderSliver.class));
cards.add(new SetCardInfo("Collected Conjuring", 196, Rarity.RARE, mage.cards.c.CollectedConjuring.class));
cards.add(new SetCardInfo("Collector Ouphe", 158, Rarity.RARE, mage.cards.c.CollectorOuphe.class));
cards.add(new SetCardInfo("Crashing Footfalls", 160, Rarity.RARE, mage.cards.c.CrashingFootfalls.class));
cards.add(new SetCardInfo("Crypt Rats", 84, Rarity.UNCOMMON, mage.cards.c.CryptRats.class));
cards.add(new SetCardInfo("Deep Forest Hermit", 161, Rarity.RARE, mage.cards.d.DeepForestHermit.class));
cards.add(new SetCardInfo("Diabolic Edict", 87, Rarity.COMMON, mage.cards.d.DiabolicEdict.class));
cards.add(new SetCardInfo("Dismantling Blow", 5, Rarity.UNCOMMON, mage.cards.d.DismantlingBlow.class));
cards.add(new SetCardInfo("Dregscape Sliver", 88, Rarity.UNCOMMON, mage.cards.d.DregscapeSliver.class));
cards.add(new SetCardInfo("Eladamri's Call", 197, Rarity.RARE, mage.cards.e.EladamrisCall.class));
cards.add(new SetCardInfo("Elvish Fury", 162, Rarity.COMMON, mage.cards.e.ElvishFury.class));
cards.add(new SetCardInfo("Enduring Sliver", 8, Rarity.COMMON, mage.cards.e.EnduringSliver.class));
cards.add(new SetCardInfo("Etchings of the Chosen", 198, Rarity.UNCOMMON, mage.cards.e.EtchingsOfTheChosen.class));
cards.add(new SetCardInfo("Exclude", 48, Rarity.UNCOMMON, mage.cards.e.Exclude.class));
cards.add(new SetCardInfo("Fact or Fiction", 50, Rarity.UNCOMMON, mage.cards.f.FactOrFiction.class));
@ -68,8 +74,10 @@ public final class ModernHorizons extends ExpansionSet {
cards.add(new SetCardInfo("Giver of Runes", 13, Rarity.RARE, mage.cards.g.GiverOfRunes.class));
cards.add(new SetCardInfo("Glacial Revelation", 167, Rarity.UNCOMMON, mage.cards.g.GlacialRevelation.class));
cards.add(new SetCardInfo("Goatnap", 126, Rarity.COMMON, mage.cards.g.Goatnap.class));
cards.add(new SetCardInfo("Goblin Champion", 127, Rarity.COMMON, mage.cards.g.GoblinChampion.class));
cards.add(new SetCardInfo("Goblin Engineer", 128, Rarity.RARE, mage.cards.g.GoblinEngineer.class));
cards.add(new SetCardInfo("Goblin Matron", 129, Rarity.UNCOMMON, mage.cards.g.GoblinMatron.class));
cards.add(new SetCardInfo("Goblin Oriflamme", 130, Rarity.UNCOMMON, mage.cards.g.GoblinOriflamme.class));
cards.add(new SetCardInfo("Goblin War Party", 131, Rarity.COMMON, mage.cards.g.GoblinWarParty.class));
cards.add(new SetCardInfo("Good-Fortune Unicorn", 201, Rarity.UNCOMMON, mage.cards.g.GoodFortuneUnicorn.class));
cards.add(new SetCardInfo("Headless Specter", 95, Rarity.COMMON, mage.cards.h.HeadlessSpecter.class));
@ -77,6 +85,9 @@ public final class ModernHorizons extends ExpansionSet {
cards.add(new SetCardInfo("Hollowhead Sliver", 132, Rarity.UNCOMMON, mage.cards.h.HollowheadSliver.class));
cards.add(new SetCardInfo("Ice-Fang Coatl", 203, Rarity.RARE, mage.cards.i.IceFangCoatl.class));
cards.add(new SetCardInfo("Impostor of the Sixth Pride", 14, Rarity.COMMON, mage.cards.i.ImpostorOfTheSixthPride.class));
cards.add(new SetCardInfo("Ingenious Infiltrator", 204, Rarity.UNCOMMON, mage.cards.i.IngeniousInfiltrator.class));
cards.add(new SetCardInfo("Kaya's Guile", 205, Rarity.RARE, mage.cards.k.KayasGuile.class));
cards.add(new SetCardInfo("Kess, Dissident Mage", 206, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class));
cards.add(new SetCardInfo("King of the Pride", 16, Rarity.UNCOMMON, mage.cards.k.KingOfThePride.class));
cards.add(new SetCardInfo("Lava Dart", 134, Rarity.COMMON, mage.cards.l.LavaDart.class));
cards.add(new SetCardInfo("Lavabelly Sliver", 207, Rarity.UNCOMMON, mage.cards.l.LavabellySliver.class));
@ -88,6 +99,7 @@ public final class ModernHorizons extends ExpansionSet {
cards.add(new SetCardInfo("Mother Bear", 171, Rarity.COMMON, mage.cards.m.MotherBear.class));
cards.add(new SetCardInfo("Mox Tantalite", 226, Rarity.MYTHIC, mage.cards.m.MoxTantalite.class));
cards.add(new SetCardInfo("Munitions Expert", 209, Rarity.UNCOMMON, mage.cards.m.MunitionsExpert.class));
cards.add(new SetCardInfo("Nantuko Cultivator", 173, Rarity.UNCOMMON, mage.cards.n.NantukoCultivator.class));
cards.add(new SetCardInfo("Nature's Chant", 210, Rarity.COMMON, mage.cards.n.NaturesChant.class));
cards.add(new SetCardInfo("Nimble Mongoose", 174, Rarity.COMMON, mage.cards.n.NimbleMongoose.class));
cards.add(new SetCardInfo("Nurturing Peatland", 243, Rarity.RARE, mage.cards.n.NurturingPeatland.class));
@ -108,6 +120,7 @@ public final class ModernHorizons extends ExpansionSet {
cards.add(new SetCardInfo("Scrapyard Recombiner", 227, Rarity.RARE, mage.cards.s.ScrapyardRecombiner.class));
cards.add(new SetCardInfo("Scuttling Sliver", 68, Rarity.UNCOMMON, mage.cards.s.ScuttlingSliver.class));
cards.add(new SetCardInfo("Seasoned Pyromancer", 145, Rarity.MYTHIC, mage.cards.s.SeasonedPyromancer.class));
cards.add(new SetCardInfo("Segovian Angel", 25, Rarity.COMMON, mage.cards.s.SegovianAngel.class));
cards.add(new SetCardInfo("Serra the Benevolent", 26, Rarity.MYTHIC, mage.cards.s.SerraTheBenevolent.class));
cards.add(new SetCardInfo("Silent Clearing", 246, Rarity.RARE, mage.cards.s.SilentClearing.class));
cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 29, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class));
@ -117,26 +130,37 @@ public final class ModernHorizons extends ExpansionSet {
cards.add(new SetCardInfo("Snow-Covered Mountain", 253, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Snow-Covered Plains", 250, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Snow-Covered Swamp", 252, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Spell Snuff", 70, Rarity.COMMON, mage.cards.s.SpellSnuff.class));
cards.add(new SetCardInfo("Splicer's Skill", 31, Rarity.UNCOMMON, mage.cards.s.SplicersSkill.class));
cards.add(new SetCardInfo("Spore Frog", 180, Rarity.COMMON, mage.cards.s.SporeFrog.class));
cards.add(new SetCardInfo("Springbloom Druid", 181, Rarity.COMMON, mage.cards.s.SpringbloomDruid.class));
cards.add(new SetCardInfo("Squirrel Nest", 182, Rarity.UNCOMMON, mage.cards.s.SquirrelNest.class));
cards.add(new SetCardInfo("Stream of Thought", 71, Rarity.COMMON, mage.cards.s.StreamOfThought.class));
cards.add(new SetCardInfo("String of Disappearances", 72, Rarity.COMMON, mage.cards.s.StringOfDisappearances.class));
cards.add(new SetCardInfo("Sunbaked Canyon", 247, Rarity.RARE, mage.cards.s.SunbakedCanyon.class));
cards.add(new SetCardInfo("Sword of Sinew and Steel", 228, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class));
cards.add(new SetCardInfo("Sword of Truth and Justice", 229, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class));
cards.add(new SetCardInfo("Talisman of Conviction", 230, Rarity.UNCOMMON, mage.cards.t.TalismanOfConviction.class));
cards.add(new SetCardInfo("Talisman of Creativity", 231, Rarity.UNCOMMON, mage.cards.t.TalismanOfCreativity.class));
cards.add(new SetCardInfo("Talisman of Curiosity", 232, Rarity.UNCOMMON, mage.cards.t.TalismanOfCuriosity.class));
cards.add(new SetCardInfo("Talisman of Hierarchy", 233, Rarity.UNCOMMON, mage.cards.t.TalismanOfHierarchy.class));
cards.add(new SetCardInfo("Talisman of Resilience", 234, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class));
cards.add(new SetCardInfo("Tempered Sliver", 183, Rarity.UNCOMMON, mage.cards.t.TemperedSliver.class));
cards.add(new SetCardInfo("The First Sliver", 200, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class));
cards.add(new SetCardInfo("Thundering Djinn", 215, Rarity.UNCOMMON, mage.cards.t.ThunderingDjinn.class));
cards.add(new SetCardInfo("Umezawa's Charm", 111, Rarity.COMMON, mage.cards.u.UmezawasCharm.class));
cards.add(new SetCardInfo("Undead Augur", 112, Rarity.UNCOMMON, mage.cards.u.UndeadAugur.class));
cards.add(new SetCardInfo("Urza, Lord High Artificer", 75, Rarity.MYTHIC, mage.cards.u.UrzaLordHighArtificer.class));
cards.add(new SetCardInfo("Valiant Changeling", 34, Rarity.UNCOMMON, mage.cards.v.ValiantChangeling.class));
cards.add(new SetCardInfo("Venomous Changeling", 114, Rarity.COMMON, mage.cards.v.VenomousChangeling.class));
cards.add(new SetCardInfo("Wall of One Thousand Cuts", 36, Rarity.COMMON, mage.cards.w.WallOfOneThousandCuts.class));
cards.add(new SetCardInfo("Waterlogged Grove", 249, Rarity.RARE, mage.cards.w.WaterloggedGrove.class));
cards.add(new SetCardInfo("Weather the Storm", 191, Rarity.COMMON, mage.cards.w.WeatherTheStorm.class));
cards.add(new SetCardInfo("Webweaver Changeling", 192, Rarity.UNCOMMON, mage.cards.w.WebweaverChangeling.class));
cards.add(new SetCardInfo("Winds of Abandon", 37, Rarity.RARE, mage.cards.w.WindsOfAbandon.class));
cards.add(new SetCardInfo("Wing Shards", 38, Rarity.UNCOMMON, mage.cards.w.WingShards.class));
cards.add(new SetCardInfo("Wrenn and Six", 217, Rarity.MYTHIC, mage.cards.w.WrennAndSix.class));
cards.add(new SetCardInfo("Yawgmoth, Thran Physician", 116, Rarity.MYTHIC, mage.cards.y.YawgmothThranPhysician.class));
cards.add(new SetCardInfo("Zhalfirin Decoy", 39, Rarity.UNCOMMON, mage.cards.z.ZhalfirinDecoy.class));
}
}

View file

@ -1,15 +1,12 @@
package mage.sets;
import mage.ObjectColor;
import mage.cards.CardGraphicInfo;
import mage.cards.ExpansionSet;
import mage.cards.FrameStyle;
import mage.constants.Rarity;
import mage.constants.SetType;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public final class Zendikar extends ExpansionSet {
@ -29,6 +26,7 @@ public final class Zendikar extends ExpansionSet {
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
cards.add(new SetCardInfo("Adventuring Gear", 195, Rarity.COMMON, mage.cards.a.AdventuringGear.class));
cards.add(new SetCardInfo("Aether Figment", 40, Rarity.UNCOMMON, mage.cards.a.AetherFigment.class));
cards.add(new SetCardInfo("Akoum Refuge", 210, Rarity.UNCOMMON, mage.cards.a.AkoumRefuge.class));
@ -45,10 +43,10 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Blade of the Bloodchief", 196, Rarity.RARE, mage.cards.b.BladeOfTheBloodchief.class));
cards.add(new SetCardInfo("Bladetusk Boar", 118, Rarity.COMMON, mage.cards.b.BladetuskBoar.class));
cards.add(new SetCardInfo("Blazing Torch", 197, Rarity.UNCOMMON, mage.cards.b.BlazingTorch.class));
cards.add(new SetCardInfo("Bloodchief Ascension", 82, Rarity.RARE, mage.cards.b.BloodchiefAscension.class));
cards.add(new SetCardInfo("Bloodghast", 83, Rarity.RARE, mage.cards.b.Bloodghast.class));
cards.add(new SetCardInfo("Blood Seeker", 80, Rarity.COMMON, mage.cards.b.BloodSeeker.class));
cards.add(new SetCardInfo("Blood Tribute", 81, Rarity.RARE, mage.cards.b.BloodTribute.class));
cards.add(new SetCardInfo("Bloodchief Ascension", 82, Rarity.RARE, mage.cards.b.BloodchiefAscension.class));
cards.add(new SetCardInfo("Bloodghast", 83, Rarity.RARE, mage.cards.b.Bloodghast.class));
cards.add(new SetCardInfo("Bog Tatters", 84, Rarity.COMMON, mage.cards.b.BogTatters.class));
cards.add(new SetCardInfo("Bold Defense", 3, Rarity.COMMON, mage.cards.b.BoldDefense.class));
cards.add(new SetCardInfo("Brave the Elements", 4, Rarity.UNCOMMON, mage.cards.b.BraveTheElements.class));
@ -80,14 +78,14 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Explorer's Scope", 202, Rarity.COMMON, mage.cards.e.ExplorersScope.class));
cards.add(new SetCardInfo("Feast of Blood", 88, Rarity.UNCOMMON, mage.cards.f.FeastOfBlood.class));
cards.add(new SetCardInfo("Felidar Sovereign", 12, Rarity.MYTHIC, mage.cards.f.FelidarSovereign.class));
cards.add(new SetCardInfo("Forest", 246, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Forest", 247, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Forest", 248, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Forest", 249, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Forest", 266, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 267, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 268, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 269, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "246a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "247a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "248a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", "249a", Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 246, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Forest", 247, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Forest", 248, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Forest", 249, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Frontier Guide", 161, Rarity.UNCOMMON, mage.cards.f.FrontierGuide.class));
cards.add(new SetCardInfo("Gatekeeper of Malakir", 89, Rarity.UNCOMMON, mage.cards.g.GatekeeperOfMalakir.class));
cards.add(new SetCardInfo("Geyser Glider", 124, Rarity.UNCOMMON, mage.cards.g.GeyserGlider.class));
@ -121,14 +119,14 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Into the Roil", 48, Rarity.COMMON, mage.cards.i.IntoTheRoil.class));
cards.add(new SetCardInfo("Iona, Shield of Emeria", 13, Rarity.MYTHIC, mage.cards.i.IonaShieldOfEmeria.class));
cards.add(new SetCardInfo("Ior Ruin Expedition", 49, Rarity.COMMON, mage.cards.i.IorRuinExpedition.class));
cards.add(new SetCardInfo("Island", 234, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Island", 235, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Island", 236, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Island", 237, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Island", 254, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 256, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 257, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "234a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "235a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "236a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", "237a", Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 234, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Island", 235, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Island", 236, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Island", 237, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Joraga Bard", 166, Rarity.COMMON, mage.cards.j.JoragaBard.class));
cards.add(new SetCardInfo("Journey to Nowhere", 14, Rarity.COMMON, mage.cards.j.JourneyToNowhere.class));
cards.add(new SetCardInfo("Jwar Isle Refuge", 215, Rarity.UNCOMMON, mage.cards.j.JwarIsleRefuge.class));
@ -165,22 +163,21 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Marsh Flats", 219, Rarity.RARE, mage.cards.m.MarshFlats.class, new CardGraphicInfo(new ObjectColor("WB"), null, false)));
cards.add(new SetCardInfo("Merfolk Seastalkers", 55, Rarity.UNCOMMON, mage.cards.m.MerfolkSeastalkers.class));
cards.add(new SetCardInfo("Merfolk Wayfinder", 56, Rarity.UNCOMMON, mage.cards.m.MerfolkWayfinder.class));
cards.add(new SetCardInfo("Mind Sludge", 102, Rarity.UNCOMMON, mage.cards.m.MindSludge.class));
cards.add(new SetCardInfo("Mindbreak Trap", 57, Rarity.MYTHIC, mage.cards.m.MindbreakTrap.class));
cards.add(new SetCardInfo("Mindless Null", 103, Rarity.COMMON, mage.cards.m.MindlessNull.class));
cards.add(new SetCardInfo("Mind Sludge", 102, Rarity.UNCOMMON, mage.cards.m.MindSludge.class));
cards.add(new SetCardInfo("Mire Blight", 104, Rarity.COMMON, mage.cards.m.MireBlight.class));
cards.add(new SetCardInfo("Misty Rainforest", 220, Rarity.RARE, mage.cards.m.MistyRainforest.class, new CardGraphicInfo(new ObjectColor("UG"), null,
false)));
cards.add(new SetCardInfo("Misty Rainforest", 220, Rarity.RARE, mage.cards.m.MistyRainforest.class, new CardGraphicInfo(new ObjectColor("UG"), null, false)));
cards.add(new SetCardInfo("Mold Shambler", 169, Rarity.COMMON, mage.cards.m.MoldShambler.class));
cards.add(new SetCardInfo("Molten Ravager", 138, Rarity.COMMON, mage.cards.m.MoltenRavager.class));
cards.add(new SetCardInfo("Mountain", 242, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Mountain", 243, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Mountain", 244, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Mountain", 245, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Mountain", 262, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 263, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 264, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "242a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "243a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "244a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", "245a", Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 242, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Mountain", 243, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Mountain", 244, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Mountain", 245, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Murasa Pyromancer", 139, Rarity.UNCOMMON, mage.cards.m.MurasaPyromancer.class));
cards.add(new SetCardInfo("Narrow Escape", 27, Rarity.COMMON, mage.cards.n.NarrowEscape.class));
cards.add(new SetCardInfo("Needlebite Trap", 105, Rarity.UNCOMMON, mage.cards.n.NeedlebiteTrap.class));
@ -200,14 +197,14 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Pillarfield Ox", 31, Rarity.COMMON, mage.cards.p.PillarfieldOx.class));
cards.add(new SetCardInfo("Piranha Marsh", 222, Rarity.COMMON, mage.cards.p.PiranhaMarsh.class));
cards.add(new SetCardInfo("Pitfall Trap", 32, Rarity.UNCOMMON, mage.cards.p.PitfallTrap.class));
cards.add(new SetCardInfo("Plains", 230, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Plains", 231, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Plains", 232, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Plains", 233, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 252, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 253, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "230a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "231a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "232a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", "233a", Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 230, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Plains", 231, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Plains", 232, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Plains", 233, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Plated Geopede", 141, Rarity.COMMON, mage.cards.p.PlatedGeopede.class));
cards.add(new SetCardInfo("Predatory Urge", 175, Rarity.RARE, mage.cards.p.PredatoryUrge.class));
cards.add(new SetCardInfo("Primal Bellow", 176, Rarity.UNCOMMON, mage.cards.p.PrimalBellow.class));
@ -257,14 +254,14 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Summoning Trap", 184, Rarity.RARE, mage.cards.s.SummoningTrap.class));
cards.add(new SetCardInfo("Sunspring Expedition", 37, Rarity.COMMON, mage.cards.s.SunspringExpedition.class));
cards.add(new SetCardInfo("Surrakar Marauder", 113, Rarity.COMMON, mage.cards.s.SurrakarMarauder.class));
cards.add(new SetCardInfo("Swamp", 238, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Swamp", 239, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Swamp", 240, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Swamp", 241, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true)));
cards.add(new SetCardInfo("Swamp", 258, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 259, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 260, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "238a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "239a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "240a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", "241a", Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 238, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Swamp", 239, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Swamp", 240, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Swamp", 241, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS));
cards.add(new SetCardInfo("Tajuru Archer", 185, Rarity.UNCOMMON, mage.cards.t.TajuruArcher.class));
cards.add(new SetCardInfo("Tanglesap", 186, Rarity.COMMON, mage.cards.t.Tanglesap.class));
cards.add(new SetCardInfo("Teetering Peaks", 226, Rarity.COMMON, mage.cards.t.TeeteringPeaks.class));
@ -289,8 +286,7 @@ public final class Zendikar extends ExpansionSet {
cards.add(new SetCardInfo("Vampire Nighthawk", 116, Rarity.UNCOMMON, mage.cards.v.VampireNighthawk.class));
cards.add(new SetCardInfo("Vampire's Bite", 117, Rarity.COMMON, mage.cards.v.VampiresBite.class));
cards.add(new SetCardInfo("Vastwood Gorger", 192, Rarity.COMMON, mage.cards.v.VastwoodGorger.class));
cards.add(new SetCardInfo("Verdant Catacombs", 229, Rarity.RARE, mage.cards.v.VerdantCatacombs.class, new CardGraphicInfo(new ObjectColor("BG"), null,
false)));
cards.add(new SetCardInfo("Verdant Catacombs", 229, Rarity.RARE, mage.cards.v.VerdantCatacombs.class, new CardGraphicInfo(new ObjectColor("BG"), null, false)));
cards.add(new SetCardInfo("Vines of Vastwood", 193, Rarity.COMMON, mage.cards.v.VinesOfVastwood.class));
cards.add(new SetCardInfo("Warren Instigator", 154, Rarity.MYTHIC, mage.cards.w.WarrenInstigator.class));
cards.add(new SetCardInfo("Welkin Tern", 76, Rarity.COMMON, mage.cards.w.WelkinTern.class));

View file

@ -750,7 +750,7 @@ public class TestPlayer implements Player {
// show command
if (params[0].equals(SHOW_COMMAND_COMMAND) && params.length == 1) {
printStart(action.getActionName());
CardsImpl cards = new CardsImpl(computerPlayer.getCommandersIds());
CardsImpl cards = new CardsImpl(game.getCommandersIds(computerPlayer));
printCards(cards.getCards(game));
printEnd();
actions.remove(action);
@ -3077,8 +3077,13 @@ public class TestPlayer implements Player {
}
@Override
public boolean isRequestToShowHandCardsAllowed() {
return computerPlayer.isRequestToShowHandCardsAllowed();
public boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId) {
return computerPlayer.isPlayerAllowedToRequestHand(gameId, requesterPlayerId);
}
@Override
public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) {
computerPlayer.addPlayerToRequestedHandList(gameId, requesterPlayerId);
}
@Override

View file

@ -1242,10 +1242,15 @@ public class PlayerStub implements Player {
}
@Override
public boolean isRequestToShowHandCardsAllowed() {
public boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId) {
return false;
}
@Override
public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) {
//
}
@Override
public Set<UUID> getUsersAllowedToSeeHandCards() {
return null;

View file

@ -0,0 +1,61 @@
package mage.abilities.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
import java.util.UUID;
/**
* For oathbreaker game mode
*
* @author JayDi85
*/
public class SignatureSpellCastOnlyWithOathbreakerEffect extends ContinuousRuleModifyingEffectImpl {
private final Condition condition;
private final UUID signatureSpell;
public SignatureSpellCastOnlyWithOathbreakerEffect(Condition condition, UUID signatureSpell) {
super(Duration.EndOfGame, Outcome.Detriment);
this.condition = condition;
this.signatureSpell = signatureSpell;
staticText = setText();
}
private SignatureSpellCastOnlyWithOathbreakerEffect(final SignatureSpellCastOnlyWithOathbreakerEffect effect) {
super(effect);
this.condition = effect.condition;
this.signatureSpell = effect.signatureSpell;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getSourceId().equals(signatureSpell)) {
return condition != null && !condition.apply(game, source);
}
return false; // cast not prevented by this effect
}
@Override
public SignatureSpellCastOnlyWithOathbreakerEffect copy() {
return new SignatureSpellCastOnlyWithOathbreakerEffect(this);
}
private String setText() {
StringBuilder sb = new StringBuilder("cast this spell only ");
if (condition != null) {
sb.append(' ').append(condition.toString());
}
return sb.toString();
}
}

View file

@ -1,8 +1,8 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.constants.CommanderCardType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -22,7 +22,7 @@ public enum CommanderInPlayCondition implements Condition {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) {
Permanent commander = game.getPermanent(commanderId);
if (commander != null && commander.isControlledBy(source.getControllerId())) {
return true;

View file

@ -0,0 +1,51 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.Game;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* For Oathbreaker game mode
*
* @author JayDi85
*/
public class OathbreakerOnBattlefieldCondition implements Condition {
private UUID playerId;
private FilterControlledPermanent filter;
public OathbreakerOnBattlefieldCondition(UUID playerId, List<UUID> oathbreakersToSearch) {
this.playerId = playerId;
this.filter = new FilterControlledPermanent("oathbreaker on battlefield");
if (oathbreakersToSearch != null && !oathbreakersToSearch.isEmpty()) {
// any commander on battlefield
List<PermanentIdPredicate> idsList = new ArrayList<>();
for (UUID id : oathbreakersToSearch) {
idsList.add(new PermanentIdPredicate(id));
}
this.filter.add(Predicates.or(idsList));
} else {
// random id to disable condition
this.filter.add(new PermanentIdPredicate(UUID.randomUUID()));
}
}
@Override
public boolean apply(Game game, Ability source) {
// source.getSourceId() is null for commander's effects
int permanentsOnBattlefield = game.getBattlefield().count(this.filter, source.getSourceId(), playerId, game);
return permanentsOnBattlefield > 0;
}
@Override
public String toString() {
return filter.getMessage();
}
}

View file

@ -5,6 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.constants.CommanderCardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
@ -83,7 +84,7 @@ class CommanderStormEffect extends OneShotEffect {
if (player == null) {
return false;
}
stormCount = player.getCommandersIds().stream()
stormCount = game.getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER).stream()
.map((commanderId) -> game.getState().getWatcher(CommanderPlaysCountWatcher.class).getPlaysCount(commanderId))
.reduce(stormCount, Integer::sum);
if (stormCount == 0) {

View file

@ -1,30 +1,27 @@
package mage.abilities.keyword;
import java.util.Iterator;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.StaticAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.costs.OptionalAdditionalCostImpl;
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
import mage.abilities.costs.*;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import java.util.Iterator;
/**
* 702.40. Entwine
*
* <p>
* 702.40a Entwine is a static ability of modal spells (see rule 700.2) that
* functions while the spell is on the stack. "Entwine [cost]" means "You may
* choose all modes of this spell instead of just one. If you do, you pay an
* additional [cost]." Using the entwine ability follows the rules for choosing
* modes and paying additional costs in rules 601.2b and 601.2e-g.
*
* <p>
* 702.40b If the entwine cost was paid, follow the text of each of the modes in
* the order written on the card when the spell resolves.
*
@ -33,15 +30,18 @@ import mage.players.Player;
public class EntwineAbility extends StaticAbility implements OptionalAdditionalModeSourceCosts {
private static final String keywordText = "Entwine";
private static final String reminderText = "Choose both if you pay the entwine cost.";
protected OptionalAdditionalCost additionalCost;
public EntwineAbility(String manaString) {
super(Zone.STACK, null);
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString));
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "Choose both if you pay the entwine cost.", new ManaCostsImpl(manaString));
}
public EntwineAbility(Cost cost) {
this(cost, "Choose both if you pay the entwine cost.");
}
public EntwineAbility(Cost cost, String reminderText) {
super(Zone.STACK, null);
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost);
setRuleAtTheTop(true);
@ -80,28 +80,32 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
@Override
public void changeModes(Ability ability, Game game) {
if (ability instanceof SpellAbility) {
Player player = game.getPlayer(controllerId);
if (player != null) {
this.resetCosts();
if (additionalCost != null) {
if (additionalCost.canPay(ability, ability.getSourceId(), ability.getControllerId(), game)
&& player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) {
if (!(ability instanceof SpellAbility)) {
return;
}
Player player = game.getPlayer(controllerId);
if (player == null) {
return;
}
this.resetCosts();
if (additionalCost == null) {
return;
}
if (additionalCost.canPay(ability, ability.getSourceId(), ability.getControllerId(), game)
&& player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) {
additionalCost.activate();
ability.getModes().setAdditionalCost(this);
ability.getModes().setMinModes(2);
ability.getModes().setMaxModes(2);
}
}
}
additionalCost.activate();
int modeCount = ability.getModes().size();
ability.getModes().setAdditionalCost(this);
ability.getModes().setMinModes(modeCount);
ability.getModes().setMaxModes(modeCount);
}
}
@Override
public void addOptionalAdditionalModeCosts(Ability ability, Game game) {
if (additionalCost.isActivated()) {
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) {
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) {
Cost cost = (Cost) it.next();
if (cost instanceof ManaCostsImpl) {
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());

View file

@ -1,6 +1,5 @@
package mage.abilities.keyword;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost;
@ -21,24 +20,25 @@ import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetControlledPermanent;
import java.util.UUID;
/**
* 702.47. Ninjutsu
*
* <p>
* 702.47a Ninjutsu is an activated ability that functions only while the card
* with ninjutsu is in a player's hand. "Ninjutsu [cost]" means "[Cost], Reveal
* this card from your hand, Return an unblocked attacking creature you control
* to its owner's hand: Put this card onto the battlefield from your hand tapped
* and attacking."
*
* <p>
* 702.47b The card with ninjutsu remains revealed from the time the ability is
* announced until the ability leaves the stack.
*
* <p>
* 702.47c A ninjutsu ability may be activated only while a creature on the
* battlefield is unblocked (see rule 509.1h). The creature with ninjutsu is put
* onto the battlefield unblocked. It will be attacking the same player or
* planeswalker as the creature that was returned to its owner's hand.
*
*
* @author LevelX2
*/
public class NinjutsuAbility extends ActivatedAbilityImpl {
@ -51,7 +51,6 @@ public class NinjutsuAbility extends ActivatedAbilityImpl {
}
/**
*
* @param manaCost ninjutsu mana cost
*/
public NinjutsuAbility(ManaCost manaCost) {
@ -195,7 +194,7 @@ class RevealNinjutsuCardCost extends CostImpl {
Card card = player.getHand().get(ability.getSourceId(), game);
if (card == null && commander
&& player.getCommandersIds().contains(ability.getSourceId())) {
&& game.getCommandersIds(player).contains(ability.getSourceId())) {
for (CommandObject coj : game.getState().getCommand()) {
if (coj != null && coj.getId().equals(ability.getSourceId())) {
card = game.getCard(ability.getSourceId());

View file

@ -1,8 +1,5 @@
package mage.abilities.mana;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
@ -17,8 +14,11 @@ import mage.filter.FilterMana;
import mage.game.Game;
import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl {
@ -46,7 +46,7 @@ public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl
if (netMana.isEmpty() && game != null) {
Player controller = game.getPlayer(getControllerId());
if (controller != null) {
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller)) {
Card commander = game.getCard(commanderId);
if (commander != null) {
FilterMana commanderMana = commander.getColorIdentity();
@ -114,7 +114,7 @@ class CommanderIdentityManaEffect extends ManaEffect {
if (controller != null) {
Choice choice = new ChoiceImpl();
choice.setMessage("Pick a mana color");
for (UUID commanderId : controller.getCommandersIds()) {
for (UUID commanderId : game.getCommandersIds(controller)) {
Card commander = game.getCard(commanderId);
if (commander != null) {
FilterMana commanderMana = commander.getColorIdentity();

View file

@ -24,7 +24,7 @@ public abstract class ExpansionSet implements Serializable {
private static final Logger logger = Logger.getLogger(ExpansionSet.class);
public static final CardGraphicInfo NON_FULL_USE_VARIOUS = new CardGraphicInfo(null, true);
public static final CardGraphicInfo FULL_ART_BFZ_VARIOUS = new CardGraphicInfo(FrameStyle.BFZ_FULL_ART_BASIC, true);
public static final CardGraphicInfo FULL_ART_ZEN_VARIOUS = new CardGraphicInfo(FrameStyle.ZEN_FULL_ART_BASIC, true);
public class SetCardInfo implements Serializable {

View file

@ -0,0 +1,10 @@
package mage.constants;
/**
* @author JayDi85
*/
public enum CommanderCardType {
ANY,
COMMANDER_OR_OATHBREAKER,
SIGNATURE_SPELL
}

View file

@ -20,7 +20,7 @@ public enum CommanderPredicate implements Predicate<Permanent> {
public boolean apply(Permanent input, Game game) {
Player owner = game.getPlayer(input.getOwnerId());
return owner != null
&& owner.getCommandersIds().contains(input.getId());
&& game.getCommandersIds(owner).contains(input.getId());
}
@Override

View file

@ -476,4 +476,9 @@ public interface Game extends MageItem, Serializable {
Mulligan getMulligan();
Set<UUID> getCommandersIds(Player player, CommanderCardType commanderCardType);
default Set<UUID> getCommandersIds(Player player) {
return getCommandersIds(player, CommanderCardType.ANY);
}
}

View file

@ -41,6 +41,7 @@ public abstract class GameCommanderImpl extends GameImpl {
@Override
protected void init(UUID choosingPlayerId) {
// Karn Liberated calls it to restart game, all data and commanders must be re-initialized
// plays watcher
state.addWatcher(new CommanderPlaysCountWatcher());
@ -49,20 +50,19 @@ public abstract class GameCommanderImpl extends GameImpl {
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
Player player = getPlayer(playerId);
if (player != null) {
if (player.getSideboard().isEmpty()) { // needed for restart game of e.g. Karn Liberated
for (UUID commanderId : player.getCommandersIds()) {
Card commander = this.getCard(commanderId);
if (commander != null) {
initCommander(commander, player);
}
// add new commanders
for (UUID id : player.getSideboard()) {
Card commander = this.getCard(id);
if (commander != null) {
addCommander(commander, player);
}
} else {
while (!player.getSideboard().isEmpty()) {
Card commander = this.getCard(player.getSideboard().iterator().next());
if (commander != null) {
player.addCommanderId(commander.getId());
initCommander(commander, player);
}
}
// init commanders
for (UUID commanderId : this.getCommandersIds(player)) {
Card commander = this.getCard(commanderId);
if (commander != null) {
initCommander(commander, player);
}
}
}
@ -75,17 +75,27 @@ public abstract class GameCommanderImpl extends GameImpl {
}
public void initCommander(Card commander, Player player) {
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
commander.moveToZone(Zone.COMMAND, null, this, true);
commander.getAbilities().setControllerId(player.getId());
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
ability.addEffect(new CommanderCostModification(commander.getId()));
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage);
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
initCommanderEffects(commander, player, ability);
CommanderInfoWatcher watcher = initCommanderWatcher(commander, checkCommanderDamage);
getState().addWatcher(watcher);
watcher.addCardInfoToCommander(this);
this.getState().addAbility(ability, null);
}
public CommanderInfoWatcher initCommanderWatcher(Card commander, boolean checkCommanderDamage) {
return new CommanderInfoWatcher("Commander", commander.getId(), checkCommanderDamage);
}
public void initCommanderEffects(Card commander, Player player, Ability commanderAbility) {
// all commander effects must be independent from sourceId or controllerId
commanderAbility.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
commanderAbility.addEffect(new CommanderCostModification(commander.getId()));
}
//20130711
/*903.8. The Commander variant uses an alternate mulligan rule.
* Each time a player takes a mulligan, rather than shuffling their entire hand of cards into their library, that player exiles any number of cards from their hand face down.
@ -173,7 +183,7 @@ public abstract class GameCommanderImpl extends GameImpl {
@Override
protected boolean checkStateBasedActions() {
for (Player player : getPlayers().values()) {
for (UUID commanderId : player.getCommandersIds()) {
for (UUID commanderId : this.getCommandersIds(player)) {
CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId);
if (damageWatcher == null) {
continue;
@ -207,4 +217,8 @@ public abstract class GameCommanderImpl extends GameImpl {
this.checkCommanderDamage = checkCommanderDamage;
}
public void addCommander(Card card, Player player) {
player.addCommanderId(card.getId());
}
}

View file

@ -2871,7 +2871,7 @@ public abstract class GameImpl implements Game, Serializable {
// as commander (only commander games, look at init code in GameCommanderImpl)
if (this instanceof GameCommanderImpl) {
for (Card card : command) {
player.addCommanderId(card.getId());
((GameCommanderImpl) this).addCommander(card, player);
// no needs in initCommander call -- it's uses on game startup (init)
}
} else if (!command.isEmpty()) {
@ -3193,4 +3193,9 @@ public abstract class GameImpl implements Game, Serializable {
return mulligan;
}
@Override
public Set<UUID> getCommandersIds(Player player, CommanderCardType commanderCardType) {
return player.getCommandersIds();
}
}

View file

@ -62,7 +62,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
ability.addEffect(new CommanderCostModification(commander.getId()));
// Commander rule #4 was removed Jan. 18, 2016
// ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander)));
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), false);
CommanderInfoWatcher watcher = new CommanderInfoWatcher("Commander", commander.getId(), false);
getState().addWatcher(watcher);
watcher.addCardInfoToCommander(this);
this.getState().addAbility(ability, null);

View file

@ -696,9 +696,11 @@ public interface Player extends MageItem, Copyable<Player> {
/**
* Get the commanderIds of the player
* Deprecated, use game.getCommandersIds(xxx) instead
*
* @return
*/
@Deprecated
Set<UUID> getCommandersIds();
/**
@ -853,7 +855,9 @@ public interface Player extends MageItem, Copyable<Player> {
void revokePermissionToSeeHandCards();
boolean isRequestToShowHandCardsAllowed();
boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId);
void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId);
Set<UUID> getUsersAllowedToSeeHandCards();

View file

@ -302,7 +302,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.sideboard = player.getSideboard().copy();
this.hand = player.getHand().copy();
this.graveyard = player.getGraveyard().copy();
this.commandersIds = player.getCommandersIds();
this.commandersIds = new HashSet<>(player.getCommandersIds());
this.abilities = player.getAbilities().copy();
this.counters = player.getCounters().copy();
@ -2284,6 +2284,7 @@ public abstract class PlayerImpl implements Player, Serializable {
break;
case PERMISSION_REQUESTS_ALLOWED_ON:
userData.setAllowRequestShowHandCards(true);
userData.resetRequestedHandPlayersList(game.getId()); // users can send request again
break;
}
logger.trace("PASS Priority: " + playerAction.toString());
@ -3969,8 +3970,13 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean isRequestToShowHandCardsAllowed() {
return userData.isAllowRequestShowHandCards();
public boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId) {
return userData.isAllowRequestHandToPlayer(gameId, requesterPlayerId);
}
@Override
public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) {
userData.addPlayerToRequestedHandList(gameId, requesterPlayerId);
}
@Override

View file

@ -1,6 +1,7 @@
package mage.players.net;
import java.io.Serializable;
import java.util.*;
/**
* User data that is passed during connection to the server.
@ -24,6 +25,7 @@ public class UserData implements Serializable {
protected boolean autoOrderTrigger;
protected boolean useFirstManaAbility = false;
private String userIdStr;
protected Map<UUID, Set<UUID>> requestedHandPlayersList; // game -> players list
protected String matchHistory;
protected int matchQuitRatio;
@ -35,9 +37,9 @@ public class UserData implements Serializable {
private int limitedRating;
public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced,
boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps,
String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted,
boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility, String userIdStr) {
boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps,
String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted,
boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility, String userIdStr) {
this.groupId = userGroup.getGroupId();
this.avatarId = avatarId;
this.showAbilityPickerForced = showAbilityPickerForced;
@ -57,6 +59,7 @@ public class UserData implements Serializable {
this.tourneyHistory = "";
this.tourneyQuitRatio = 0;
this.userIdStr = userIdStr;
this.requestedHandPlayersList = new HashMap<>();
}
public void update(UserData userData) {
@ -106,14 +109,35 @@ public class UserData implements Serializable {
this.showAbilityPickerForced = showAbilityPickerForced;
}
public boolean isAllowRequestShowHandCards() {
public boolean isAllowRequestHandToAll() {
return allowRequestShowHandCards;
}
public boolean isAllowRequestHandToPlayer(UUID gameId, UUID requesterPlayerId) {
// once per game
boolean allowToPlayer = true;
if (requestedHandPlayersList.containsKey(gameId) && requestedHandPlayersList.get(gameId).contains(requesterPlayerId)) {
allowToPlayer = false;
}
return isAllowRequestHandToAll() && allowToPlayer;
}
public void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId) {
if (!requestedHandPlayersList.containsKey(gameId)) {
requestedHandPlayersList.put(gameId, new HashSet<>());
}
Set<UUID> requestedPlayers = requestedHandPlayersList.get(gameId);
requestedPlayers.add(requesterPlayerId);
}
public void setAllowRequestShowHandCards(boolean allowRequestShowHandCards) {
this.allowRequestShowHandCards = allowRequestShowHandCards;
}
public void resetRequestedHandPlayersList(UUID gameId) {
this.requestedHandPlayersList.remove(gameId);
}
public UserSkipPrioritySteps getUserSkipPrioritySteps() {
return userSkipPrioritySteps;
}

View file

@ -26,17 +26,20 @@ public class CommanderInfoWatcher extends Watcher {
private final Map<UUID, Integer> damageToPlayer = new HashMap<>();
private final boolean checkCommanderDamage;
private final String commanderTypeName;
public CommanderInfoWatcher(UUID commander, boolean checkCommanderDamage) {
public CommanderInfoWatcher(String commanderTypeName, UUID commander, boolean checkCommanderDamage) {
super(WatcherScope.CARD);
this.sourceId = commander;
this.checkCommanderDamage = checkCommanderDamage;
this.commanderTypeName = commanderTypeName;
}
public CommanderInfoWatcher(final CommanderInfoWatcher watcher) {
super(watcher);
this.damageToPlayer.putAll(watcher.damageToPlayer);
this.checkCommanderDamage = watcher.checkCommanderDamage;
this.commanderTypeName = watcher.commanderTypeName;
}
@Override
@ -78,7 +81,7 @@ public class CommanderInfoWatcher extends Watcher {
}
if (object != null) {
StringBuilder sb = new StringBuilder();
sb.append("<b>Commander</b>");
sb.append("<b>" + commanderTypeName + "</b>");
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
int playsCount = watcher.getPlaysCount(sourceId);
if (playsCount > 0) {
@ -89,9 +92,9 @@ public class CommanderInfoWatcher extends Watcher {
if (checkCommanderDamage) {
for (Map.Entry<UUID, Integer> entry : damageToPlayer.entrySet()) {
Player damagedPlayer = game.getPlayer(entry.getKey());
sb.append("<b>Commander</b> did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.');
sb.append("<b>" + commanderTypeName + "</b> did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.');
this.addInfo(object, "Commander" + entry.getKey(),
"<b>Commander</b> did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game);
"<b>" + commanderTypeName + "</b> did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game);
}
}
}

View file

@ -43,7 +43,7 @@ public class CommanderPlaysCountWatcher extends Watcher {
UUID possibleCommanderId = event.getSourceId();
boolean isCommanderObject = false;
for (Player player : game.getPlayers().values()) {
if (player.getCommandersIds().contains(possibleCommanderId)) {
if (game.getCommandersIds(player).contains(possibleCommanderId)) {
isCommanderObject = true;
break;
}

View file

@ -35118,6 +35118,7 @@ Morophon, the Boundless|Modern Horizons|1|M|{7}|Legendary Creature - Shapeshifte
Astral Drift|Modern Horizons|3|R|{2}{W}|Enchantment|||Whenever you cycle Astral Drift or cycle another card while Astral Drift is on the battlefield, you may exile target creature. If you do, return that card to the battlefield under its owner's control at the beginning of the next end step.$Cycling {2}{W}|
Battle Screech|Modern Horizons|4|U|{2}{W}{W}|Sorcery|||Create two 1/1 white Bird creature tokens with flying.$Flashback—Tap three untapped white creatures you control.|
Dismantling Blow|Modern Horizons|5|U|{2}{W}|Instant|||Kicker {2}{U}$Destroy target artifact or enchantment. If this spell was kicked, draw two cards.|
Enduring Sliver|Modern Horizons|8|C|{1}{W}|Creature - Sliver|2|2|Outlast {2}$Other sliver creatures you control have outlast {2}.|
Force of Virtue|Modern Horizons|10|R|{2}{W}{W}|Enchantment|||If it's not your turn, you may exile a white card from your hand rather than pay this spell's mana cost.$Flash$Creatures you control get +1/+1.|
Generous Gift|Modern Horizons|11|U|{2}{W}|Instant|||Destroy target permanent. Its controller creates a 3/3 green Elephant creature token.|
Giver of Runes|Modern Horizons|13|R|{W}|Creature - Kor Cleric|1|2|{T}: Another target creature you control gains protection from colorless or from the color of your choice until end of turn.|
@ -35125,9 +35126,11 @@ Impostor of the Sixth Pride|Modern Horizons|14|C|{1}{W}|Creature - Shapeshifter|
King of the Pride|Modern Horizons|16|U|{2}{W}|Creature - Cat|2|1|Other Cats you control get +2/+1.|
Martyr's Soul|Modern Horizons|19|C|{2}{W}|Creature - Spirit Soldier|3|2|Convoke$When Martyr's Soul enters the battlefield, if you control no tapped lands, put two +1/+1 counters on it.|
Ranger-Captain of Eos|Modern Horizons|21|M|{1}{W}{W}|Creature - Human Soldier|3|3|When Ranger-Captain of Eos enters the battlefield, you may search your library for a creature card with converted mana cost 1 or less, reveal it, put it into your hand, then shuffle your library.$Sacrifice Ranger-Captain of Eos: Your opponents can't cast noncreature spells this turn.|
Segovian Angel|Modern Horizons|25|C|{W}|Creature - Angel|1|1|Flying, vigilance|
Serra the Benevolent|Modern Horizons|26|M|{2}{W}{W}|Legendary Planeswalker - Serra|4|+2: Creatures you control with flying get +1/+1 until end of turn.$-3: Create a 4/4 white Angel creature token with flying and vigilance.$-6: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead."|
Sisay, Weatherlight Captain|Modern Horizons|29|R|{2}{W}|Legendary Creature - Human Soldier|2|2|Sisay, Weatherlight Captain gets +1/+1 for each color among other legendary permanents you control.${W}{U}{B}{R}{G}: Search your library for a legendary permanent card with converted mana cost less than Sisay's power, put that card onto the battlefield, then shuffle your library.|
Splicer's Skill|Modern Horizons|31|U|{2}{W}|Sorcery|||Create a 3/3 colorless Golem artifact creature token.$Splice onto instant or sorcery {3}{W}|
Valiant Changeling|Modern Horizons|34|U|{5}{W}{W}|Creature - Shapeshifter|3|3|This spell costs {1} less to cast for each creature type among creatures you control. This effect can't reduce the amount of mana this spell costs by more than {5}.$Changeling$Double strike|
Wall of One Thousand Cuts|Modern Horizons|36|C|{3}{W}{W}|Creature - Wall|3|5|Defender, flying${W}: Wall of One Thousand Cuts can attack this turn as though it didn't have defender.|
Winds of Abandon|Modern Horizons|37|R|{1}{W}|Sorcery|||Exile target creature you don't control. For each creature exiled this way, its controller searches their library for a basic land card. Those players put those cards onto the battlefield tapped, then shuffle their libraries.$Overload {4}{W}{W}|
Wing Shards|Modern Horizons|38|U|{1}{W}{W}|Instant|||Target player sacrifices an attacking creature.$Storm|
@ -35144,7 +35147,9 @@ Pondering Mage|Modern Horizons|63|C|{3}{U}{U}|Creature - Human Wizard|3|4|When P
Prohibit|Modern Horizons|64|C|{1}{U}|Instant|||Kicker {2}$Counter target spell if its converted mana cost is 2 or less. If this spell was kicked, counter that spell if its converted mana cost is 4 or less instead.|
Scour All Possibilities|Modern Horizons|67|C|{1}{U}|Sorcery|||Scry 2, then draw a card.$Flashback {4}{U}|
Scuttling Sliver|Modern Horizons|68|U|{2}{U}|Creature - Sliver Trilobite|2|2|Sliver creatures you control have "{2}: Untap this creature."|
Spell Snuff|Modern Horizons|70|C|{1}{U}{U}|Instant|||Counter target spell.$Fateful hour — If you have 5 or less life, draw a card.|
Stream of Thought|Modern Horizons|71|C|{U}|Sorcery|||Target player puts the top four cards of their library into their graveyard. You shuffle up to four cards from your graveyard into your library.$Replicate {2}{U}{U}|
String of Disappearances|Modern Horizons|72|C|{U}|Instant|||Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy.|
Urza, Lord High Artificer|Modern Horizons|75|M|{2}{U}{U}|Legendary Creature - Human Artificer|1|4|When Urza, Lord High Artificer enters the battlefield, create a 0/0 colorless Construct artifact creature token with "This creature gets +1/+1 for each artifact you control."$Tap an untapped artifact you control: Add {U}.${5}: Shuffle your library, then exile the top card. Until end of turn, you may play that card without paying its mana cost.|
Cabal Therapist|Modern Horizons|80|R|{B}|Creature - Horror|1|1|Menace$At the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.|
Changeling Outcast|Modern Horizons|82|C|{B}|Creature - Shapeshifter|1|1|Changeling$Changeling Outcast can't block and can't be blocked.|
@ -35155,17 +35160,21 @@ Feaster of Fools|Modern Horizons|90|U|{4}{B}{B}|Creature - Demon|3|3|Convoke$Fly
Force of Despair|Modern Horizons|92|R|{1}{B}{B}|Instant|||If it's not your turn, you may exile a black card from your hand rather than pay this spell's mana cost.$Destroy all creatures that entered the battlefield this turn.|
Headless Specter|Modern Horizons|95|C|{1}{B}{B}|Creature - Specter|2|2|Flying$Hellbent — Whenever Headless Specter deals combat damage to a player, if you have no cards in hand, that player discards a card at random.|
Plague Engineer|Modern Horizons|100|R|{2}{B}|Creature - Carrier|2|2|Deathtouch$As Plague Engineer enters the battlefield, choose a creature type.$Creatures of the chosen type your opponents control get -1/-1.|
Sling-Gang Lieutenant|Modern Horizons|108|U|{3}{B}|Creature - Goblin|||When Sling-Gang Lieutenant enters the battlefield, create two 1/1 red Goblin creature tokens.$Sacrifice a Goblin: Target player loses 1 life and you gain 1 life.|
Sling-Gang Lieutenant|Modern Horizons|108|U|{3}{B}|Creature - Goblin|1|1|When Sling-Gang Lieutenant enters the battlefield, create two 1/1 red Goblin creature tokens.$Sacrifice a Goblin: Target player loses 1 life and you gain 1 life.|
Umezawa's Charm|Modern Horizons|111|C|{1}{B}|Instant|||Choose one—$• Target creature gets +2/+2 until end of turn.$• Target creature gets -1/-1 until end of turn.$• You gain 2 life.|
Undead Augur|Modern Horizons|112|U|{B}{B}|Creature - Zombie Wizard|2|2|Whenever Undead Augur or another Zombie you control dies, you draw a card and you lose 1 life.|
Venomous Changeling|Modern Horizons|114|C|{2}{B}|Creature - Shapeshifter|1|3|Changeling$Deathtouch|
Yawgmoth, Thran Physician|Modern Horizons|116|M|{2}{B}{B}|Legendary Creature - Human Cleric|2|4|Protection from Humans$Pay 1 life, Sacrifice another creature: Put a -1/-1 counter on up to one target creature and draw a card.${B}{B}, Discard a card: Proliferate.|
Aria of Flame|Modern Horizons|118|R|{2}{R}|Enchantment|||When Aria of Flame enters the battlefield, each opponent gains 10 life.$Whenever you cast an instant or sorcery spell, put a verse counter on Aria of Flame, then it deals damage equal to the number of verse counters on it to target player or planeswalker.|
Bladeback Sliver|Modern Horizons|119|C|{1}{R}|Creature - Sliver|2|2|Hellbent — As long as you have no cards in hand, Sliver creatures you control have "{T}: This creature deals 1 damage to target player or planeswalker."|
Firebolt|Modern Horizons|122|U|{R}|Sorcery|||Firebolt deals 2 damage to any target.$Flashback {4}{R}|
Fists of Flame|Modern Horizons|123|C|{1}{R}|Instant|||Draw a card. Until end of turn, target creature gains trample and gets +1/+0 for each card you've drawn this turn.|
Force of Rage|Modern Horizons|124|R|{1}{R}{R}|Instant|||If it's not your turn, you may exile a red card from your hand rather than pay this spell's mana cost.$Create two 3/1 red Elemental creature tokens with trample and haste. Sacrifice those tokens at the beginning of your next upkeep.|
Goatnap|Modern Horizons|126|C|{2}{R}|Sorcery|||Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. If that creature is a Goat, it also gets +3/+0 until end of turn.|
Goblin Champion|Modern Horizons|127|C|{R}|Creature - Goblin Warrior|0|1|Haste$Exalted|
Goblin Engineer|Modern Horizons|128|R|{1}{R}|Creature - Goblin Artificer|1|2|When Goblin Engineer enters the battlefield, you may search your library for an artifact card, put it into your graveyard, then shuffle your library.${R}, {T}, Sacrifice an artifact: Return target artifact card with converted mana cost 3 or less from your graveyard to the battlefield.|
Goblin Matron|Modern Horizons|129|U|{2}{R}|Creature - Goblin|1|1|When Goblin Matron enters the battlefield, you may search your library for a Goblin card, reveal that card, and put it into your hand. If you do, shuffle your library.|
Goblin Oriflamme|Modern Horizons|130|U|{1}{R}|Enchantment|||Attacking creatures you control get +1/+0.|
Goblin War Party|Modern Horizons|131|C|{3}{R}|Sorcery|||Choose one —$• Create three 1/1 red Goblin creature tokens.$• Creatures you control get +1/+1 and gain haste until end of turn.$Entwine {2}{R}|
Hollowhead Sliver|Modern Horizons|132|U|{2}{R}|Creature - Sliver|2|2|Sliver creatures you control have "{T}, Discard a card: Draw a card."|
Lava Dart|Modern Horizons|134|C|{R}|Instant|||Lava Dart deals 1 damage to any target.$Flashback—Sacrifice a Mountain.|
@ -35177,6 +35186,8 @@ Ravenous Giant|Modern Horizons|143|U|{2}{R}{R}|Creature - Giant|5|5|At the begin
Seasoned Pyromancer|Modern Horizons|145|M|{1}{R}{R}|Creature - Human Shaman|2|2|When Seasoned Pyromancer enters the battlefield, discard two cards, then draw two cards. For each nonland card discarded this way, create a 1/1 red Elemental creature token.${3}{R}{R}, Exile Seasoned Pyromancer from your graveyard: Create two 1/1 red Elemental creature tokens.|
Ayula, Queen Among Bears|Modern Horizons|155|R|{1}{G}|Legendary Creature - Bear|2|2|Whenever another Bear enters the battlefield under your control, choose one —$• Put two +1/+1 counters on target Bear.$• Target Bear you control fights target creature you don't control.|
Ayula's Influence|Modern Horizons|156|R|{G}{G}{G}|Enchantment|||Discard a land card: Create a 2/2 green Bear creature token.|
Collector Ouphe|Modern Horizons|158|R|{1}{G}|Creature - Ouphe|2|2|Activated abilities of artifacts can't be activated.|
Crashing Footfalls|Modern Horizons|160|R||Sorcery|||Suspend 4—{G}$Create two 4/4 green Rhino creature tokens with trample.|
Deep Forest Hermit|Modern Horizons|161|R|{3}{G}{G}|Creature - Elf Druid|1|1|Vanishing 3$When Deep Forest Hermit enters the battlefield, create four 1/1 green Squirrel creature tokens.$Squirrels you control get +1/+1.|
Elvish Fury|Modern Horizons|162|C|{G}|Instant|||Buyback {4}$Target creature gets +2/+2 until end of turn.|
Force of Vigor|Modern Horizons|164|R|{2}{G}{G}|Instant|||If it's not your turn, you may exile a green card from your hand rather than pay this spell's mana cost.$Destroy up to two target artifacts and/or enchantments.|
@ -35184,6 +35195,7 @@ Genesis|Modern Horizons|166|R|{4}{G}|Creature - Incarnation|4|4|At the beginning
Glacial Revelation|Modern Horizons|167|U|{2}{G}|Sorcery|||Reveal the top six cards of your library. You may put any number of snow permanent cards from among them into your hand. Put the rest into your graveyard.|
Hexdrinker|Modern Horizons|168|M|{G}|Creature - Snake|2|1|Level up {1}$LEVEL 3-7$4/4$Protection from instants$LEVEL 8+$6/6$Protection from everything|
Mother Bear|Modern Horizons|171|C|{1}{G}|Creature - Bear|2|2|{3}{G}{G}, Exile Mother Bear from your graveyard: Create two 2/2 green Bear creature tokens. Activate this ability only any time you could cast a sorcery.|
Nantuko Cultivator|Modern Horizons|173|U|{3}{G}|Creature - Insect Druid|2|2|When Nantuko Cultivator enters the battlefield, you may discard any number of land cards. Put that many +1/+1 counters on Nantuko Cultivator and draw that many cards.|
Nimble Mongoose|Modern Horizons|174|C|{G}|Creature - Mongoose|1|1|Shroud$Threshold — Nimble Mongoose gets +2/+2 as long as seven or more cards are in your graveyard.|
Regrowth|Modern Horizons|175|U|{1}{G}|Sorcery|||Return target card from your graveyard to your hand.|
Savage Swipe|Modern Horizons|178|C|{G}|Sorcery|||Target creature you control gets +2/+2 until end of turn if its power is 2. Then it fights target creature you don't control.|
@ -35193,14 +35205,20 @@ Springbloom Druid|Modern Horizons|181|C|{2}{G}|Creature - Elf Druid|1|1|When Spr
Squirrel Nest|Modern Horizons|182|U|{1}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 1/1 green Squirrel creature token."|
Tempered Sliver|Modern Horizons|183|U|{2}{G}|Creature - Sliver|2|2|Sliver creatures you control have "Whenever this creature deals combat damage to a player, put a +1/+1 counter on it."|
Unbound Flourishing|Modern Horizons|189|M|{2}{G}|Enchantment|||Whenever you cast a permanent spell with a mana cost that contains {X}, double the value of X.$Whenever you cast an instant or sorcery spell or activate an ability, if that spell's mana cost or that ability's activation cost contains {X}, copy that spell or ability. You may choose new targets for the copy.|
Weather the Storm|Modern Horizons|191|C|{1}{G}|Instant|||You gain 3 life.$Storm|
Webweaver Changeling|Modern Horizons|192|U|{3}{G}{G}|Creature - Shapeshifter|3|5|Changeling$Reach$When Webweaver Changeling enters the battlefield, if there are three or more creature cards in your graveyard, you gain 5 life.|
Abominable Treefolk|Modern Horizons|194|U|{2}{G}{U}|Snow Creature - Treefolk|*|*|Trample$Abominable Treefolk's power and toughness are each equal to the number of snow permanents you control.$When Abominable Treefolk enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step.|
Cloudshredder Sliver|Modern Horizons|195|R|{R}{W}|Creature - Sliver|1|1|Sliver creatures you control have flying and haste.|
Collected Conjuring|Modern Horizons|196|R|{2}{U}{R}|Sorcery|||Exile the top six cards of your library. You may cast up to two sorcery cards with converted mana costs 3 or less from among them without paying their mana cost. Put the exiled cards not cast this way on the bottom of your library in a random order.|
Eladamri's Call|Modern Horizons|197|R|{G}{W}|Instant|||Search your library for a creature card, reveal that card, put it into your hand, then shuffle your library.|
Etchings of the Chosen|Modern Horizons|198|U|{1}{W}{B}|Enchantment|||As Etchings of the Chosen enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1.${1}, Sacrifice a creature of the chosen type: Target creature you control gains indestructible until end of turn.|
Fallen Shinobi|Modern Horizons|199|R|{3}{U}{B}|Creature - Zombie Ninja|5|4|Ninjutsu {2}{U}{B}$Whenever Fallen Shinobi deals combat damage to a player, that player exiles the top two cards of their library. Until end of turn, you may play those cards without paying their mana cost.|
The First Sliver|Modern Horizons|200|M|{W}{U}{B}{R}{G}|Legendary Creature - Sliver|7|7|Cascade$Sliver spells you cast have cascade.|
Good-Fortune Unicorn|Modern Horizons|201|U|{1}{G}{W}|Creature - Unicorn|2|2|Whenever another creature enters the battlefield under your control, put a +1/+1 counter on that creature.|
Ice-Fang Coatl|Modern Horizons|203|R|{G}{U}|Snow Creature - Snake|1|1|Flash$Flying$When Ice-Fang Coatl enters the battlefield, draw a card.$Ice-Fang Coatl has deathtouch as long as you control at least three other snow permanents.|
Ingenious Infiltrator|Modern Horizons|204|U|{2}{U}{B}|Creature - Vedalken Ninja|2|3|Ninjutsu {U}{B}$Whenever a Ninja you control deals combat damage to a player, draw a card.|
Kaya's Guile|Modern Horizons|205|R|{1}{W}{B}|Instant|||Choose two —$• Each opponent sacrifices a creature.$• Exile all cards from each opponent's graveyard.$• Create a 1/1 white and black Spirit creature token with flying.$• You gain 4 life.$Entwine {3}|
Kess, Dissident Mage|Modern Horizons|206|M|{1}{U}{B}{R}|Legendary Creature - Human Wizard|3|4|Flying$During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard, exile it instead.|
Lavabelly Sliver|Modern Horizons|207|U|{1}{R}{W}|Creature - Sliver|2|2|Sliver creatures you control have "When this creature enters the battlefield, it deals 1 damage to target player or planeswalker and you gain 1 life."|
Lightning Skelemental|Modern Horizons|208|R|{B}{R}{R}|Creature - Elemental Skeleton|6|1|Trample, haste$Whenever Lightning Skelemental deals combat damage to a player, that player discards two cards.$At the beginning of the end step, sacrifice Lightning Skelemental.|
Munitions Expert|Modern Horizons|209|U|{B}{R}|Creature - Goblin|1|1|Flash$When Munitions Expert enters the battlefield, you may have it deal damage to target creature or planeswalker equal to the number of Goblins you control.|
@ -35208,12 +35226,18 @@ Nature's Chant|Modern Horizons|210|C|{1}{G/W}|Instant|||Destroy target artifact
Thundering Djinn|Modern Horizons|215|U|{3}{U}{R}|Creature - Djinn|3|4|Flying$Whenever Thundering Djinn attacks, it deals damage to any target equal to the number of cards you've drawn this turn.|
Wrenn and Six|Modern Horizons|217|M|{R}{G}|Legendary Planeswalker - Wrenn|3|+1: Return up to one target land card from your graveyard to your hand.$-1: Wrenn and Six deals 1 damage to any target.$-7: You get an emblem with "Instant and sorcery cards in your graveyard have retrace."|
Altar of Dementia|Modern Horizons|218|R|{2}|Artifact|||Sacrifice a creature: Target player puts a number of cards equal to the sacrificed creature's power from the top of their library into their graveyard.|
Arcum's Astrolabe|Modern Horizons|220|C|{S}|Snow Artifact|||({S} can be paid with one mana from a snow permanent.)$When Arcum's Astrolabe enters the battlefield, draw a card.${1}, {T}: Add one mana of any color.|
Farmstead Gleaner|Modern Horizons|222|U|{3}|Artifact Creature - Scarecrow|2|2|Farmstead Gleaner doesn't untap during your untap step.${2}, {Q}: Put a +1/+1 counter on Farmstead Gleaner.|
Lesser Masticore|Modern Horizons|225|U|{2}|Artifact Creature - Masticore|2|2|As an additional cost to cast this spell, discard a card.${4}: Lesser Masticore deals 1 damage to target creature.$Persist|
Mox Tantalite|Modern Horizons|226|M||Artifact|||Suspend 3—{0}${T}: Add one mana of any color.|
Scrapyard Recombiner|Modern Horizons|227|R|{3}|Artifact Creature - Construct|0|0|Modular 2${T}, Sacrifice an artifact: Search your library for a Construct card, reveal it, put it into your hand, then shuffle your library.|
Sword of Sinew and Steel|Modern Horizons|228|M|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has protection from black and from red.$Whenever equipped creature deals combat damage to a player, destroy up to one target planeswalker and up to one target artifact.$Equip {2}|
Sword of Truth and Justice|Modern Horizons|229|M|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has protection from white and from blue.$Whenever equipped creature deals combat damage to a player, put a +1/+1 counter on a creature you control, then proliferate.$Equip {2}|
Talisman of Conviction|Modern Horizons|230|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {R} or {W}. Talisman of Conviction deals 1 damage to you.|
Talisman of Creativity|Modern Horizons|231|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {U} or {R}. Talisman of Creativity deals 1 damage to you.|
Talisman of Curiosity|Modern Horizons|232|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {G} or {U}. Talisman of Curiosity deals 1 damage to you.|
Talisman of Hierarchy|Modern Horizons|233|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {W} or {B}. Talisman of Hierarchy deals 1 damage to you.|
Talisman of Resilience|Modern Horizons|234|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {G}. Talisman of Resilience deals 1 damage to you.|
Fiery Islet|Modern Horizons|238|R||Land|||{T}, Pay 1 life: Add {U} or {R}.${1}, {T}, Sacrifice Fiery Islet: Draw a card.|
Frostwalk Bastion|Modern Horizons|240|U||Snow Land|||{T}: Add {C}.${1}{S}: Until end of turn, Frostwalk Bastion becomes a 2/3 Construct artifact creature. It's still a land.$Whenever Frostwalk Bastion deals combat damage to a creature, tap that creature and it doesn't untap during its controller's next untap step.|
Nurturing Peatland|Modern Horizons|243|R||Land|||{T}, Pay 1 life: Add {B} or {G}.${1}, {T}, Sacrifice Nurturing Peatland: Draw a card.|