mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
Merge branch 'master' of https://github.com/magefree/mage
This commit is contained in:
commit
0ebd773caf
55 changed files with 28614 additions and 28269 deletions
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
|
@ -20,7 +20,7 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
|
@ -31,7 +31,6 @@
|
|||
*
|
||||
* Created on 30-Mar-2010, 9:25:40 PM
|
||||
*/
|
||||
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.Component;
|
||||
|
@ -54,6 +53,7 @@ import mage.client.plugins.impl.Plugins;
|
|||
import mage.client.util.Config;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.Listener;
|
||||
import mage.utils.CardUtil;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CardsView;
|
||||
import org.mage.card.arcane.CardPanel;
|
||||
|
@ -82,7 +82,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
|
||||
public void clear() {
|
||||
for(MouseListener ml: this.getMouseListeners()) {
|
||||
for (MouseListener ml : this.getMouseListeners()) {
|
||||
this.removeMouseListener(ml);
|
||||
}
|
||||
this.clearCardEventListeners();
|
||||
|
@ -101,7 +101,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
this.bigCard = bigCard;
|
||||
this.gameId = gameId;
|
||||
if (merge) {
|
||||
for (CardView card: showCards.values()) {
|
||||
for (CardView card : showCards.values()) {
|
||||
if (!cards.containsKey(card.getId())) {
|
||||
addCard(card, bigCard, gameId, drawImage);
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
} else {
|
||||
this.clearCards();
|
||||
for (CardView card: showCards.values()) {
|
||||
for (CardView card : showCards.values()) {
|
||||
addCard(card, bigCard, gameId, drawImage);
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
int curRow = 0;
|
||||
if (cards.size() > 0) {
|
||||
Rectangle rectangle = new Rectangle(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
List<MageCard> sortedCards = new ArrayList<MageCard>(cards.values());
|
||||
List<MageCard> sortedCards = new ArrayList<>(cards.values());
|
||||
switch (sortSetting.getSortBy()) {
|
||||
case NAME:
|
||||
Collections.sort(sortedCards, new CardNameComparator());
|
||||
|
@ -155,15 +155,16 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
case COLOR:
|
||||
Collections.sort(sortedCards, new CardColorComparator());
|
||||
break;
|
||||
case COLOR_DETAILED:
|
||||
Collections.sort(sortedCards, new CardColorDetailedComparator());
|
||||
case COLOR_IDENTITY:
|
||||
Collections.sort(sortedCards, new CardColorDetailedIdentity());
|
||||
break;
|
||||
case CASTING_COST:
|
||||
Collections.sort(sortedCards, new CardCostComparator());
|
||||
break;
|
||||
|
||||
}
|
||||
MageCard lastCard = null;
|
||||
for (MageCard cardImg: sortedCards) {
|
||||
for (MageCard cardImg : sortedCards) {
|
||||
if (sortSetting.isPilesToggle()) {
|
||||
if (lastCard == null) {
|
||||
lastCard = cardImg;
|
||||
|
@ -187,8 +188,9 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
curRow = 0;
|
||||
}
|
||||
break;
|
||||
case COLOR_DETAILED:
|
||||
if (cardImg.getOriginal().getColor().hashCode() != lastCard.getOriginal().getColor().hashCode()) {
|
||||
case COLOR_IDENTITY:
|
||||
if (CardUtil.getColorIdentitySortValue(cardImg.getOriginal().getManaCost(), cardImg.getOriginal().getColor(), cardImg.getOriginal().getRules())
|
||||
!= CardUtil.getColorIdentitySortValue(lastCard.getOriginal().getManaCost(), lastCard.getOriginal().getColor(), lastCard.getOriginal().getRules())) {
|
||||
curColumn++;
|
||||
curRow = 0;
|
||||
}
|
||||
|
@ -206,8 +208,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
moveToFront(cardImg);
|
||||
curRow++;
|
||||
lastCard = cardImg;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
rectangle.setLocation(curColumn * Config.dimensions.frameWidth, curRow * 20);
|
||||
cardImg.setBounds(rectangle);
|
||||
cardImg.setCardBounds(rectangle.x, rectangle.y, Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
|
@ -221,15 +222,15 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
}
|
||||
resizeArea();
|
||||
revalidate();
|
||||
repaint();
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void clearCards() {
|
||||
// remove possible mouse listeners, preventing gc
|
||||
for (MageCard mageCard: cards.values()) {
|
||||
for (MageCard mageCard : cards.values()) {
|
||||
if (mageCard instanceof CardPanel) {
|
||||
((CardPanel)mageCard).cleanUp();
|
||||
((CardPanel) mageCard).cleanUp();
|
||||
}
|
||||
}
|
||||
this.cards.clear();
|
||||
|
@ -237,7 +238,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
|
||||
private void removeAllCardImg() {
|
||||
for (Component comp: getComponents()) {
|
||||
for (Component comp : getComponents()) {
|
||||
if (comp instanceof Card || comp instanceof MageCard) {
|
||||
remove(comp);
|
||||
}
|
||||
|
@ -245,14 +246,14 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
|
||||
private void removeCardImg(UUID cardId) {
|
||||
for (Component comp: getComponents()) {
|
||||
for (Component comp : getComponents()) {
|
||||
if (comp instanceof Card) {
|
||||
if (((Card)comp).getCardId().equals(cardId)) {
|
||||
if (((Card) comp).getCardId().equals(cardId)) {
|
||||
remove(comp);
|
||||
comp = null;
|
||||
}
|
||||
} else if (comp instanceof MageCard) {
|
||||
if (((MageCard)comp).getOriginal().getId().equals(cardId)) {
|
||||
if (((MageCard) comp).getOriginal().getId().equals(cardId)) {
|
||||
remove(comp);
|
||||
comp = null;
|
||||
}
|
||||
|
@ -275,10 +276,10 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
cardEventSource.clearListeners();
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
|
@ -296,10 +297,8 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2 && !e.isConsumed()) {
|
||||
|
@ -322,22 +321,26 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {}
|
||||
public void mousePressed(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {}
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {}
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
private void resizeArea() {
|
||||
Dimension area = new Dimension(0, 0);
|
||||
Dimension size = getPreferredSize();
|
||||
|
||||
for (Component comp: getComponents()) {
|
||||
for (Component comp : getComponents()) {
|
||||
Rectangle r = comp.getBounds();
|
||||
if (r.x + r.width > area.width) {
|
||||
area.width = r.x + r.width;
|
||||
|
@ -348,13 +351,13 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
}
|
||||
if (size.height != area.height || size.width != area.width) {
|
||||
setPreferredSize(area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
revalidate();
|
||||
repaint();
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -379,8 +382,7 @@ class CardRarityComparator implements Comparator<MageCard> {
|
|||
int val = o1.getOriginal().getRarity().compareTo(o2.getOriginal().getRarity());
|
||||
if (val == 0) {
|
||||
return o1.getOriginal().getName().compareTo(o2.getOriginal().getName());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
@ -394,8 +396,7 @@ class CardCostComparator implements Comparator<MageCard> {
|
|||
int val = Integer.valueOf(o1.getOriginal().getConvertedManaCost()).compareTo(Integer.valueOf(o2.getOriginal().getConvertedManaCost()));
|
||||
if (val == 0) {
|
||||
return o1.getOriginal().getName().compareTo(o2.getOriginal().getName());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
@ -409,23 +410,22 @@ class CardColorComparator implements Comparator<MageCard> {
|
|||
int val = o1.getOriginal().getColor().compareTo(o2.getOriginal().getColor());
|
||||
if (val == 0) {
|
||||
return o1.getOriginal().getName().compareTo(o2.getOriginal().getName());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CardColorDetailedComparator implements Comparator<MageCard> {
|
||||
class CardColorDetailedIdentity implements Comparator<MageCard> {
|
||||
|
||||
@Override
|
||||
public int compare(MageCard o1, MageCard o2) {
|
||||
int val = o1.getOriginal().getColor().hashCode() - o2.getOriginal().getColor().hashCode();
|
||||
int val = CardUtil.getColorIdentitySortValue(o1.getOriginal().getManaCost(), o1.getOriginal().getColor(), o1.getOriginal().getRules())
|
||||
- CardUtil.getColorIdentitySortValue(o2.getOriginal().getManaCost(), o2.getOriginal().getColor(), o2.getOriginal().getRules());
|
||||
if (val == 0) {
|
||||
return o1.getOriginal().getName().compareTo(o2.getOriginal().getName());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CardsList.java
|
||||
*
|
||||
* Created on Dec 18, 2009, 10:40:12 AM
|
||||
*/
|
||||
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.Color;
|
||||
|
@ -59,7 +58,7 @@ import mage.client.constants.Constants.DeckEditorMode;
|
|||
import mage.client.constants.Constants.SortBy;
|
||||
import static mage.client.constants.Constants.SortBy.CASTING_COST;
|
||||
import static mage.client.constants.Constants.SortBy.COLOR;
|
||||
import static mage.client.constants.Constants.SortBy.COLOR_DETAILED;
|
||||
import static mage.client.constants.Constants.SortBy.COLOR_IDENTITY;
|
||||
import static mage.client.constants.Constants.SortBy.RARITY;
|
||||
import mage.client.deckeditor.SortSetting;
|
||||
import mage.client.deckeditor.table.TableModel;
|
||||
|
@ -67,7 +66,7 @@ import mage.client.deckeditor.table.UpdateCountsCallback;
|
|||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.CardViewColorComparator;
|
||||
import mage.client.util.CardViewColorDetailedComparator;
|
||||
import mage.client.util.CardViewColorIdentityComparator;
|
||||
import mage.client.util.CardViewCostComparator;
|
||||
import mage.client.util.CardViewNameComparator;
|
||||
import mage.client.util.CardViewRarityComparator;
|
||||
|
@ -86,7 +85,7 @@ import org.mage.card.arcane.CardPanel;
|
|||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CardsList extends javax.swing.JPanel implements MouseListener, ICardGrid {
|
||||
|
||||
|
||||
protected CardEventSource cardEventSource = new CardEventSource();
|
||||
private Dimension cardDimension;
|
||||
private CardsView cards;
|
||||
|
@ -98,8 +97,10 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
private TableModel mainModel;
|
||||
private JTable mainTable;
|
||||
private ICardGrid currentView;
|
||||
|
||||
/** Creates new form Cards */
|
||||
|
||||
/**
|
||||
* Creates new form Cards
|
||||
*/
|
||||
public CardsList() {
|
||||
initComponents();
|
||||
makeTransparent();
|
||||
|
@ -115,22 +116,22 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
mainModel.removeTableModelListener(mainTable);
|
||||
mainModel.clear();
|
||||
}
|
||||
if(cardArea != null) {
|
||||
for(MouseListener ml: cardArea.getMouseListeners()) {
|
||||
if (cardArea != null) {
|
||||
for (MouseListener ml : cardArea.getMouseListeners()) {
|
||||
cardArea.removeMouseListener(ml);
|
||||
}
|
||||
}
|
||||
if(mainTable != null) {
|
||||
for(MouseListener ml: mainTable.getMouseListeners()) {
|
||||
if (mainTable != null) {
|
||||
for (MouseListener ml : mainTable.getMouseListeners()) {
|
||||
mainTable.removeMouseListener(ml);
|
||||
}
|
||||
}
|
||||
if (currentView != null) {
|
||||
currentView.clearCardEventListeners();
|
||||
}
|
||||
for (Component comp :cardArea.getComponents()) {
|
||||
if (comp instanceof CardPanel) {
|
||||
((CardPanel)comp).cleanUp();
|
||||
for (Component comp : cardArea.getComponents()) {
|
||||
if (comp instanceof CardPanel) {
|
||||
((CardPanel) comp).cleanUp();
|
||||
}
|
||||
}
|
||||
mageCards.clear();
|
||||
|
@ -208,20 +209,20 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
// activate spinner for card number change
|
||||
mainModel.setNumberEditable(true);
|
||||
TableColumnModel tcm = mainTable.getColumnModel();
|
||||
TableColumn tc = tcm.getColumn(0);
|
||||
TableColumn tc = tcm.getColumn(0);
|
||||
tc.setMaxWidth(55);
|
||||
tc.setMinWidth(55);
|
||||
tc.setPreferredWidth(55);
|
||||
tc.setCellEditor(new TableSpinnerEditor(this));
|
||||
tc.setCellEditor(new TableSpinnerEditor(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void handleSetNumber(int number) {
|
||||
if (mainTable.getSelectedRowCount() == 1) {
|
||||
mainModel.setNumber(mainTable.getSelectedRow(), number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void handleDoubleClick() {
|
||||
if (mainTable.getSelectedRowCount() > 0) {
|
||||
int[] n = mainTable.getSelectedRows();
|
||||
|
@ -232,7 +233,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void handleAltDoubleClick() {
|
||||
if (mainTable.getSelectedRowCount() > 0) {
|
||||
int[] n = mainTable.getSelectedRows();
|
||||
|
@ -243,7 +244,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ICardGrid getMainModel() {
|
||||
return mainModel;
|
||||
}
|
||||
|
@ -256,7 +257,6 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
return list;
|
||||
}
|
||||
|
||||
|
||||
public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) {
|
||||
int selectedRow = -1;
|
||||
if (currentView.equals(mainModel)) {
|
||||
|
@ -270,7 +270,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
chkPiles.setSelected(sortSetting.isPilesToggle());
|
||||
currentView.loadCards(showCards, sortSetting, bigCard, gameId);
|
||||
if (selectedRow >= 0) {
|
||||
selectedRow = Math.min(selectedRow, mainTable.getRowCount()-1);
|
||||
selectedRow = Math.min(selectedRow, mainTable.getRowCount() - 1);
|
||||
if (selectedRow >= 0) {
|
||||
mainTable.setRowSelectionInterval(selectedRow, selectedRow);
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
if (cards == null) {
|
||||
cards = new CardsView();
|
||||
}
|
||||
currentView.loadCards(cards, sortSetting, bigCard, gameId);
|
||||
currentView.loadCards(cards, sortSetting, bigCard, gameId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -295,22 +295,21 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
Comparator<CardView> comparator = null;
|
||||
Map<UUID, MageCard> oldMageCards = mageCards;
|
||||
mageCards = new LinkedHashMap<>();
|
||||
|
||||
|
||||
//Find card view
|
||||
for(UUID uuid : cards.keySet()){
|
||||
if(oldMageCards.containsKey(uuid)){
|
||||
for (UUID uuid : cards.keySet()) {
|
||||
if (oldMageCards.containsKey(uuid)) {
|
||||
mageCards.put(uuid, oldMageCards.get(uuid));
|
||||
oldMageCards.remove(uuid);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
mageCards.put(uuid, addCard(cards.get(uuid), bigCard, gameId));
|
||||
}
|
||||
}
|
||||
//Remove unused cards
|
||||
for(MageCard card : oldMageCards.values()){
|
||||
for (MageCard card : oldMageCards.values()) {
|
||||
cardArea.remove(card);
|
||||
}
|
||||
|
||||
|
||||
if (cards != null && cards.size() > 0) {
|
||||
Rectangle rectangle = new Rectangle(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
List<CardView> sortedCards = new ArrayList<>(cards.values());
|
||||
|
@ -324,25 +323,25 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
case COLOR:
|
||||
comparator = new CardViewColorComparator();
|
||||
break;
|
||||
case COLOR_DETAILED:
|
||||
comparator = new CardViewColorDetailedComparator();
|
||||
case COLOR_IDENTITY:
|
||||
comparator = new CardViewColorIdentityComparator();
|
||||
break;
|
||||
case CASTING_COST:
|
||||
comparator = new CardViewCostComparator();
|
||||
break;
|
||||
}
|
||||
if(comparator != null){
|
||||
if (comparator != null) {
|
||||
Collections.sort(sortedCards, new CardViewNameComparator());
|
||||
Collections.sort(sortedCards, comparator);
|
||||
}
|
||||
CardView lastCard = null;
|
||||
for (CardView card: sortedCards) {
|
||||
for (CardView card : sortedCards) {
|
||||
if (sortSetting.isPilesToggle()) {
|
||||
if (lastCard == null) {
|
||||
lastCard = card;
|
||||
}
|
||||
if(comparator != null){
|
||||
if(comparator.compare(card, lastCard) > 0){
|
||||
if (comparator != null) {
|
||||
if (comparator.compare(card, lastCard) > 0) {
|
||||
curColumn++;
|
||||
maxRow = Math.max(maxRow, curRow);
|
||||
curRow = 0;
|
||||
|
@ -350,7 +349,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
}
|
||||
rectangle.setLocation(curColumn * Config.dimensions.frameWidth, curRow * 20);
|
||||
setCardBounds(mageCards.get(card.getId()), rectangle);
|
||||
|
||||
|
||||
curRow++;
|
||||
lastCard = card;
|
||||
} else {
|
||||
|
@ -368,21 +367,21 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
maxRow = Math.max(maxRow, curRow);
|
||||
maxColumn = Math.max(maxColumn, curColumn);
|
||||
updateCounts();
|
||||
cardArea.setPreferredSize(new Dimension((maxColumn+1) * Config.dimensions.frameWidth, Config.dimensions.frameHeight + maxRow*20));
|
||||
cardArea.setPreferredSize(new Dimension((maxColumn + 1) * Config.dimensions.frameWidth, Config.dimensions.frameHeight + maxRow * 20));
|
||||
cardArea.revalidate();
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
this.setVisible(true);
|
||||
}
|
||||
|
||||
private void updateCounts(){
|
||||
|
||||
private void updateCounts() {
|
||||
int landCount = 0;
|
||||
int creatureCount = 0;
|
||||
int sorceryCount = 0;
|
||||
int instantCount = 0;
|
||||
int enchantmentCount = 0;
|
||||
for (CardView card: cards.values()) {
|
||||
if (card.getCardTypes().contains(CardType.LAND)) {
|
||||
for (CardView card : cards.values()) {
|
||||
if (card.getCardTypes().contains(CardType.LAND)) {
|
||||
landCount++;
|
||||
}
|
||||
if (card.getCardTypes().contains(CardType.CREATURE)) {
|
||||
|
@ -398,7 +397,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
enchantmentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int count = cards != null ? cards.size() : 0;
|
||||
this.lblCount.setText(Integer.toString(count));
|
||||
this.lblCreatureCount.setText(Integer.toString(creatureCount));
|
||||
|
@ -418,7 +417,6 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
cardImg.addMouseListener(this);
|
||||
return cardImg;
|
||||
}
|
||||
|
||||
|
||||
private void setCardBounds(MageCard card, Rectangle rectangle) {
|
||||
card.setBounds(rectangle);
|
||||
|
@ -456,10 +454,10 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
mainModel.clearCardEventListeners();
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
|
@ -678,9 +676,9 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
currentView = mainModel;
|
||||
panelCardArea.setViewportView(mainTable);
|
||||
cbSortBy.setEnabled(false);
|
||||
chkPiles.setEnabled(false);
|
||||
chkPiles.setEnabled(false);
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_DRAFT_VIEW, "listView");
|
||||
redrawCards();
|
||||
redrawCards();
|
||||
}//GEN-LAST:event_jToggleListViewActionPerformed
|
||||
|
||||
private void cbSortByActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbSortByActionPerformed
|
||||
|
@ -698,8 +696,8 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
panelCardArea.setViewportView(cardArea);
|
||||
cbSortBy.setEnabled(true);
|
||||
chkPiles.setEnabled(true);
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_DRAFT_VIEW, "cardView");
|
||||
redrawCards();
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_DRAFT_VIEW, "cardView");
|
||||
redrawCards();
|
||||
}//GEN-LAST:event_jToggleCardViewActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
|
@ -725,28 +723,26 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.getClickCount() >= 1 && !e.isConsumed()) {
|
||||
if (e.getClickCount() >= 1 && !e.isConsumed()) {
|
||||
Object obj = e.getSource();
|
||||
if (e.getClickCount() == 2) {
|
||||
e.consume();
|
||||
if (obj instanceof Card) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((Card)obj).getOriginal(), "alt-double-click");
|
||||
}
|
||||
else {
|
||||
cardEventSource.doubleClick(((Card)obj).getOriginal(), "double-click");
|
||||
cardEventSource.altDoubleClick(((Card) obj).getOriginal(), "alt-double-click");
|
||||
} else {
|
||||
cardEventSource.doubleClick(((Card) obj).getOriginal(), "double-click");
|
||||
}
|
||||
} else if (obj instanceof MageCard) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((MageCard)obj).getOriginal(), "alt-double-click");
|
||||
}
|
||||
else {
|
||||
cardEventSource.doubleClick(((MageCard)obj).getOriginal(), "double-click");
|
||||
cardEventSource.altDoubleClick(((MageCard) obj).getOriginal(), "alt-double-click");
|
||||
} else {
|
||||
cardEventSource.doubleClick(((MageCard) obj).getOriginal(), "double-click");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj instanceof MageCard) {
|
||||
checkMenu(e, ((MageCard)obj).getOriginal());
|
||||
checkMenu(e, ((MageCard) obj).getOriginal());
|
||||
} else {
|
||||
checkMenu(e, null);
|
||||
}
|
||||
|
@ -758,14 +754,14 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
if (!e.isConsumed()) {
|
||||
Object obj = e.getSource();
|
||||
if (obj instanceof MageCard) {
|
||||
checkMenu(e, ((MageCard)obj).getOriginal());
|
||||
checkMenu(e, ((MageCard) obj).getOriginal());
|
||||
} else {
|
||||
checkMenu(e, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMenu(MouseEvent Me, SimpleCardView card){
|
||||
private void checkMenu(MouseEvent Me, SimpleCardView card) {
|
||||
if (Me.isPopupTrigger()) {
|
||||
Me.consume();
|
||||
cardEventSource.showPopupMenuEvent(card, Me.getComponent(), Me.getX(), Me.getY(), "show-popup-menu");
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.client.constants;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -37,6 +36,7 @@ import javax.swing.border.Border;
|
|||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
private Constants() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public final class Constants {
|
|||
public static final int POWBOX_TEXT_MAX_LEFT = 212;
|
||||
public static final int DAMAGE_MAX_LEFT = 180;
|
||||
|
||||
public static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2,2,2,2);
|
||||
public static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2);
|
||||
|
||||
public static final double SCALE_FACTOR = 0.5;
|
||||
|
||||
|
@ -80,26 +80,29 @@ public final class Constants {
|
|||
public static final String RESOURCE_PATH_SET = IO.imageBaseDir + "sets" + File.separator;
|
||||
public static final String RESOURCE_PATH_SET_SMALL = RESOURCE_PATH_SET + File.separator + "small" + File.separator;
|
||||
public static final String BASE_SOUND_PATH = "sounds" + File.separator;
|
||||
public static final String BASE_MUSICS_PATH = "music" + File.separator ;
|
||||
|
||||
public static final String BASE_MUSICS_PATH = "music" + File.separator;
|
||||
|
||||
public interface IO {
|
||||
|
||||
String imageBaseDir = "plugins" + File.separator + "images" + File.separator;
|
||||
String IMAGE_PROPERTIES_FILE = "image.url.properties";
|
||||
}
|
||||
|
||||
public enum DeckEditorMode {
|
||||
|
||||
FREE_BUILDING,
|
||||
LIMITED_BUILDING,
|
||||
SIDEBOARDING
|
||||
}
|
||||
|
||||
public enum SortBy {
|
||||
CASTING_COST ("Casting Cost"),
|
||||
RARITY ("Rarity"),
|
||||
COLOR ("Color"),
|
||||
COLOR_DETAILED ("Color Detailed"),
|
||||
NAME ("Name"),
|
||||
UNSORTED ("Unsorted");
|
||||
|
||||
CASTING_COST("Casting Cost"),
|
||||
RARITY("Rarity"),
|
||||
COLOR("Color"),
|
||||
COLOR_IDENTITY("Color Identity"),
|
||||
NAME("Name"),
|
||||
UNSORTED("Unsorted");
|
||||
|
||||
private final String text;
|
||||
|
||||
|
@ -120,8 +123,8 @@ public final class Constants {
|
|||
return RARITY;
|
||||
case "Color":
|
||||
return COLOR;
|
||||
case "Color Detailed":
|
||||
return COLOR_DETAILED;
|
||||
case "Color Identity":
|
||||
return COLOR_IDENTITY;
|
||||
case "Name":
|
||||
return NAME;
|
||||
default:
|
||||
|
|
|
@ -25,21 +25,21 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.client.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
import mage.utils.CardUtil;
|
||||
import mage.view.CardView;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CardViewColorDetailedComparator implements Comparator<CardView> {
|
||||
public class CardViewColorIdentityComparator implements Comparator<CardView> {
|
||||
|
||||
@Override
|
||||
public int compare(CardView o1, CardView o2) {
|
||||
return o1.getColor().hashCode() - o2.getColor().hashCode();
|
||||
return CardUtil.getColorIdentitySortValue(o1.getManaCost(), o1.getColor(), o1.getRules())
|
||||
- CardUtil.getColorIdentitySortValue(o2.getManaCost(), o2.getColor(), o2.getRules());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
|
@ -20,12 +20,11 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.client.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
@ -39,7 +38,7 @@ public class CardViewCostComparator implements Comparator<CardView> {
|
|||
|
||||
@Override
|
||||
public int compare(CardView o1, CardView o2) {
|
||||
return Integer.valueOf(o1.getConvertedManaCost()).compareTo(Integer.valueOf(o2.getConvertedManaCost()));
|
||||
return Integer.valueOf(o1.getConvertedManaCost()).compareTo(o2.getConvertedManaCost());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,7 +36,10 @@ import java.net.Proxy;
|
|||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.prefs.Preferences;
|
||||
import mage.client.MageFrame;
|
||||
import mage.remote.Connection;
|
||||
|
@ -56,6 +59,7 @@ public class MythicspoilerComSource implements CardImageSource {
|
|||
private static CardImageSource instance;
|
||||
private static Map<String, String> setsAliases;
|
||||
private static Map<String, String> cardNameAliases;
|
||||
private static Map<String, Set<String>> cardNameAliasesStart;
|
||||
private final Map<String, Map<String, String>> sets;
|
||||
|
||||
public static CardImageSource getInstance() {
|
||||
|
@ -71,8 +75,9 @@ public class MythicspoilerComSource implements CardImageSource {
|
|||
}
|
||||
|
||||
public MythicspoilerComSource() {
|
||||
sets = new HashMap<>();
|
||||
sets = new LinkedHashMap<>();
|
||||
setsAliases = new HashMap<>();
|
||||
setsAliases.put("exp", "bfz");
|
||||
cardNameAliases = new HashMap<>();
|
||||
// set+wrong name from web side => correct card name
|
||||
cardNameAliases.put("MM2-otherwordlyjourney", "otherworldlyjourney");
|
||||
|
@ -81,12 +86,21 @@ public class MythicspoilerComSource implements CardImageSource {
|
|||
cardNameAliases.put("THS-soldierofpantheon", "soldierofthepantheon");
|
||||
cardNameAliases.put("THS-vulpinegolaith", "vulpinegoliath");
|
||||
cardNameAliases.put("ORI-kothopedhoarderofsouls", "kothophedsoulhoarder");
|
||||
cardNameAliases.put("BFZ-unisonstrike", "tandemtactics");
|
||||
cardNameAliases.put("BFZ-eldrazidevastator", "eldrazidevastator");
|
||||
cardNameAliases.put("BFZ-kozliekschanneler", "kozilekschanneler");
|
||||
|
||||
cardNameAliasesStart = new HashMap<>();
|
||||
HashSet<String> names = new HashSet<>();
|
||||
names.add("eldrazidevastator.jpg");
|
||||
cardNameAliasesStart.put("BFZ", names);
|
||||
}
|
||||
|
||||
private Map<String, String> getSetLinks(String cardSet) {
|
||||
Map<String, String> setLinks = new HashMap<>();
|
||||
try {
|
||||
String setNames = setsAliases.get(cardSet.toLowerCase());
|
||||
Set<String> aliasesStart = cardNameAliasesStart.get(cardSet);
|
||||
if (setNames == null) {
|
||||
setNames = cardSet.toLowerCase();
|
||||
}
|
||||
|
@ -119,33 +133,42 @@ public class MythicspoilerComSource implements CardImageSource {
|
|||
}
|
||||
|
||||
Elements cardsImages = doc.select("img[src^=cards/]"); // starts with cards/
|
||||
if (!aliasesStart.isEmpty()) {
|
||||
for (String text : aliasesStart) {
|
||||
cardsImages.addAll(doc.select("img[src^=" + text + "]"));
|
||||
}
|
||||
}
|
||||
if (cardsImages.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (Element cardsImage : cardsImages) {
|
||||
String cardLink = cardsImage.attr("src");
|
||||
String cardName = null;
|
||||
if (cardLink.startsWith("cards/") && cardLink.endsWith(".jpg")) {
|
||||
String cardName = cardLink.substring(6, cardLink.length() - 4);
|
||||
if (cardName != null && !cardName.isEmpty()) {
|
||||
if (cardNameAliases.containsKey(cardSet + "-" + cardName)) {
|
||||
cardName = cardNameAliases.get(cardSet + "-" + cardName);
|
||||
}
|
||||
if (cardName.endsWith("1") || cardName.endsWith("2") || cardName.endsWith("3") || cardName.endsWith("4") || cardName.endsWith("5")) {
|
||||
if (!cardName.startsWith("forest")
|
||||
&& !cardName.startsWith("swamp")
|
||||
&& !cardName.startsWith("mountain")
|
||||
&& !cardName.startsWith("island")
|
||||
&& !cardName.startsWith("plains")) {
|
||||
cardName = cardName.substring(0, cardName.length() - 1);
|
||||
}
|
||||
}
|
||||
setLinks.put(cardName, baseUrl + cardLink);
|
||||
}
|
||||
cardName = cardLink.substring(6, cardLink.length() - 4);
|
||||
} else if (aliasesStart.contains(cardLink)) {
|
||||
cardName = cardLink.substring(0, cardLink.length() - 4);;
|
||||
}
|
||||
if (cardName != null && !cardName.isEmpty()) {
|
||||
if (cardNameAliases.containsKey(cardSet + "-" + cardName)) {
|
||||
cardName = cardNameAliases.get(cardSet + "-" + cardName);
|
||||
}
|
||||
if (cardName.endsWith("1") || cardName.endsWith("2") || cardName.endsWith("3") || cardName.endsWith("4") || cardName.endsWith("5")) {
|
||||
if (!cardName.startsWith("forest")
|
||||
&& !cardName.startsWith("swamp")
|
||||
&& !cardName.startsWith("mountain")
|
||||
&& !cardName.startsWith("island")
|
||||
&& !cardName.startsWith("plains")) {
|
||||
cardName = cardName.substring(0, cardName.length() - 1);
|
||||
}
|
||||
}
|
||||
setLinks.put(cardName, baseUrl + cardLink);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
System.out.println("Exception when parsing the mythicspoiler page: " + ex.getMessage());
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import org.mage.plugins.card.utils.CardImageUtils;
|
|||
|
||||
/**
|
||||
* This class stores ALL card images in a cache with soft values. this means
|
||||
* that the images may be garbage collected when they are not needed any more, but will
|
||||
* be kept as long as possible.
|
||||
* that the images may be garbage collected when they are not needed any more,
|
||||
* but will be kept as long as possible.
|
||||
*
|
||||
* Key format: "<cardname>#<setname>#<type>#<collectorID>#<param>"
|
||||
*
|
||||
|
@ -46,8 +46,7 @@ public class ImageCache {
|
|||
private static final Map<String, BufferedImage> imageCache;
|
||||
|
||||
/**
|
||||
* Common pattern for keys.
|
||||
* Format: "<cardname>#<setname>#<collectorID>"
|
||||
* Common pattern for keys. Format: "<cardname>#<setname>#<collectorID>"
|
||||
*/
|
||||
private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)");
|
||||
|
||||
|
@ -104,16 +103,16 @@ public class ImageCache {
|
|||
thumbnailFile = new TFile(thumbnailPath);
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
boolean exists =false;
|
||||
boolean exists = false;
|
||||
if (thumbnailFile != null) {
|
||||
try {
|
||||
exists = thumbnailFile.exists();
|
||||
} catch(Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
exists = false;
|
||||
}
|
||||
}
|
||||
if (exists) {
|
||||
log.debug("loading thumbnail for " + key + ", path="+thumbnailPath);
|
||||
log.debug("loading thumbnail for " + key + ", path=" + thumbnailPath);
|
||||
return loadImage(thumbnailFile);
|
||||
} else {
|
||||
BufferedImage image = loadImage(file);
|
||||
|
@ -187,30 +186,15 @@ public class ImageCache {
|
|||
}
|
||||
|
||||
public static BufferedImage getThumbnail(CardView card) {
|
||||
String key = getKey(card) + "#thumb";
|
||||
if (card.getUsesVariousArt()) {
|
||||
key += "#usesVariousArt";
|
||||
}
|
||||
// log.debug("#key: " + key);
|
||||
return getImage(key);
|
||||
return getImage(getKey(card, card.getName(), "#thumb"));
|
||||
}
|
||||
|
||||
public static BufferedImage getImageOriginal(CardView card) {
|
||||
String key = getKey(card);
|
||||
if (card.getUsesVariousArt()) {
|
||||
key += "#usesVariousArt";
|
||||
}
|
||||
// log.warn("#key: " + key);
|
||||
return getImage(key);
|
||||
return getImage(getKey(card, card.getName(), ""));
|
||||
}
|
||||
|
||||
public static BufferedImage getImageOriginalAlternateName(CardView card) {
|
||||
String key = getKeyAlternateName(card, card.getAlternateName());
|
||||
if (card.getUsesVariousArt()) {
|
||||
key += "#usesVariousArt";
|
||||
}
|
||||
// log.warn("#key: " + key);
|
||||
return getImage(key);
|
||||
return getImage(getKey(card, card.getAlternateName(), ""));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,7 +214,7 @@ public class ImageCache {
|
|||
if (ex.getCause() instanceof NullPointerException) {
|
||||
return null;
|
||||
}
|
||||
log.error(ex,ex);
|
||||
log.error(ex, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -238,32 +222,25 @@ public class ImageCache {
|
|||
/**
|
||||
* Returns the map key for a card, without any suffixes for the image size.
|
||||
*/
|
||||
private static String getKey(CardView card) {
|
||||
StringBuilder sb = new StringBuilder(card.getName()).append("#");
|
||||
sb.append(card.getExpansionSetCode()).append("#");
|
||||
sb.append(card.getType()).append("#");
|
||||
sb.append(card.getCardNumber()).append("#");
|
||||
sb.append(card.getTokenSetCode() == null ? "":card.getTokenSetCode());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map key for the flip image of a card, without any suffixes for the image size.
|
||||
*/
|
||||
private static String getKeyAlternateName(CardView card, String alternateName) {
|
||||
StringBuilder sb = new StringBuilder(alternateName).append("#");
|
||||
sb.append(card.getExpansionSetCode()).append("#");
|
||||
sb.append(card.getType()).append("#");
|
||||
sb.append(card.getCardNumber()).append("#");
|
||||
sb.append(card.getTokenSetCode() == null ? "":card.getTokenSetCode());
|
||||
return sb.toString();
|
||||
private static String getKey(CardView card, String name, String suffix) {
|
||||
return name + "#" + card.getExpansionSetCode() + "#" + card.getType() + "#" + card.getCardNumber() + "#"
|
||||
+ (card.getTokenSetCode() == null ? "" : card.getTokenSetCode())
|
||||
+ suffix
|
||||
+ (card.getUsesVariousArt() ? "#usesVariousArt" : "");
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns the map key for the flip image of a card, without any suffixes for the image size.
|
||||
// */
|
||||
// private static String getKeyAlternateName(CardView card, String alternateName) {
|
||||
// return alternateName + "#" + card.getExpansionSetCode() + "#" +card.getType()+ "#" + card.getCardNumber() + "#"
|
||||
// + (card.getTokenSetCode() == null ? "":card.getTokenSetCode());
|
||||
// }
|
||||
/**
|
||||
* Load image from file
|
||||
*
|
||||
* @param file
|
||||
* file to load image from
|
||||
* @param file file to load image from
|
||||
* @return {@link BufferedImage}
|
||||
*/
|
||||
public static BufferedImage loadImage(TFile file) {
|
||||
|
@ -297,7 +274,7 @@ public class ImageCache {
|
|||
ImageIO.write(image, "jpg", outputStream);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(e,e);
|
||||
log.error(e, e);
|
||||
imageFile.delete();
|
||||
}
|
||||
return image;
|
||||
|
@ -305,6 +282,7 @@ public class ImageCache {
|
|||
|
||||
/**
|
||||
* Returns an image scaled to the size given
|
||||
*
|
||||
* @param original
|
||||
* @return
|
||||
*/
|
||||
|
@ -344,6 +322,7 @@ public class ImageCache {
|
|||
/**
|
||||
* Returns an image scaled to the size appropriate for the card picture
|
||||
* panel
|
||||
*
|
||||
* @param original
|
||||
* @param sizeNeed
|
||||
* @return
|
||||
|
@ -356,6 +335,7 @@ public class ImageCache {
|
|||
|
||||
/**
|
||||
* Returns the image appropriate to display the card in the picture panel
|
||||
*
|
||||
* @param card
|
||||
* @param width
|
||||
* @param height
|
||||
|
@ -365,11 +345,7 @@ public class ImageCache {
|
|||
if (Constants.THUMBNAIL_SIZE_FULL.width + 10 > width) {
|
||||
return getThumbnail(card);
|
||||
}
|
||||
String key = getKey(card);
|
||||
if (card.getUsesVariousArt()) {
|
||||
key += "#usesVariousArt";
|
||||
}
|
||||
// log.warn("getImage: " + key);
|
||||
String key = getKey(card, card.getName(), "");
|
||||
BufferedImage original = getImage(key);
|
||||
if (original == null) {
|
||||
log.debug(key + " not found");
|
||||
|
|
|
@ -64,6 +64,6 @@ ddd=gvl
|
|||
unh=uh
|
||||
dde=pvc
|
||||
# Remove setname as soon as the images can be downloaded
|
||||
ignore.urls=TOK,EXP,OGW
|
||||
ignore.urls=TOK, OGW
|
||||
# sets ordered by release time (newest goes first)
|
||||
token.lookup.order=OGW,EXP,DDP,BFZ,FVD,FVE,FVL,FVR,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC
|
|
@ -1,5 +1,7 @@
|
|||
package mage.utils;
|
||||
|
||||
import java.util.List;
|
||||
import mage.ObjectColor;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.MagePermanent;
|
||||
import mage.constants.CardType;
|
||||
|
@ -13,6 +15,12 @@ import mage.view.CardView;
|
|||
*/
|
||||
public class CardUtil {
|
||||
|
||||
private static final String regexBlack = ".*\\x7b.{0,2}B.{0,2}\\x7d.*";
|
||||
private static final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*";
|
||||
private static final String regexRed = ".*\\x7b.{0,2}R.{0,2}\\x7d.*";
|
||||
private static final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*";
|
||||
private static final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*";
|
||||
|
||||
public static boolean isCreature(CardView card) {
|
||||
return is(card, CardType.CREATURE);
|
||||
}
|
||||
|
@ -48,4 +56,34 @@ public class CardUtil {
|
|||
public static boolean isLand(Card card) {
|
||||
return card.getCardType().contains(CardType.LAND);
|
||||
}
|
||||
|
||||
public static int getColorIdentitySortValue(List<String> manaCost, ObjectColor originalColor, List<String> rules) {
|
||||
ObjectColor color = new ObjectColor(originalColor);
|
||||
for (String rule : rules) {
|
||||
rule = rule.replaceAll("(?i)<i.*?</i>", ""); // Ignoring reminder text in italic
|
||||
if (rule.matches(regexBlack)) {
|
||||
color.setBlack(true);
|
||||
}
|
||||
if (rule.matches(regexBlue)) {
|
||||
color.setBlue(true);
|
||||
}
|
||||
if (rule.matches(regexGreen)) {
|
||||
color.setGreen(true);
|
||||
}
|
||||
if (rule.matches(regexRed)) {
|
||||
color.setRed(true);
|
||||
}
|
||||
if (rule.matches(regexWhite)) {
|
||||
color.setWhite(true);
|
||||
}
|
||||
}
|
||||
|
||||
int hash = 3;
|
||||
hash = 23 * hash + (color.isWhite() || manaCost.contains("{W}") ? 1 : 0);
|
||||
hash = 23 * hash + (color.isBlue() || manaCost.contains("{U}") ? 1 : 0);
|
||||
hash = 23 * hash + (color.isBlack() || manaCost.contains("{B}") ? 1 : 0);
|
||||
hash = 23 * hash + (color.isRed() || manaCost.contains("{R}") ? 1 : 0);
|
||||
hash = 23 * hash + (color.isGreen() || manaCost.contains("{G}") ? 1 : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,18 +25,21 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.sets;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.constants.SetType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
|
||||
public class BattleForZendikar extends ExpansionSet {
|
||||
|
||||
private static final BattleForZendikar fINSTANCE = new BattleForZendikar();
|
||||
|
@ -45,16 +48,33 @@ public class BattleForZendikar extends ExpansionSet {
|
|||
return fINSTANCE;
|
||||
}
|
||||
|
||||
List<CardInfo> savedSpecialLand = new ArrayList<>();
|
||||
|
||||
private BattleForZendikar() {
|
||||
super("Battle for Zendikar", "BFZ", "mage.sets.battleforzendikar", new GregorianCalendar(2015, 10, 2).getTime(), SetType.EXPANSION);
|
||||
this.blockName = "Battle for Zendikar";
|
||||
this.hasBoosters = true;
|
||||
this.hasBasicLands = true;
|
||||
this.numBoosterLands = 1;
|
||||
this.ratioBoosterSpecialLand = 20; // Approximately as rare as opening a foil mythic = 8 * 6 = ~every 48th booster includes one
|
||||
// I set it to 20 to get it more often
|
||||
this.numBoosterCommon = 10;
|
||||
this.numBoosterUncommon = 3;
|
||||
this.numBoosterRare = 1;
|
||||
this.ratioBoosterMythic = 8;
|
||||
this.numBoosterSpecial = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CardInfo> getSpecialLand() {
|
||||
List<CardInfo> specialLand = new ArrayList<>();
|
||||
if (savedSpecialLand.isEmpty()) {
|
||||
CardCriteria criteria = new CardCriteria();
|
||||
criteria.setCodes("EXP");
|
||||
specialLand.addAll(CardRepository.instance.findCards(criteria));
|
||||
}
|
||||
|
||||
specialLand.addAll(savedSpecialLand);
|
||||
return specialLand;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,37 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.sets.alarareborn;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
|
@ -44,8 +43,6 @@ public class Terminate extends CardImpl {
|
|||
public Terminate(UUID ownerId) {
|
||||
super(ownerId, 46, "Terminate", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}{R}");
|
||||
this.expansionSetCode = "ARB";
|
||||
|
||||
|
||||
|
||||
// Destroy target creature. It can't be regenerated.
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
|
|
|
@ -27,22 +27,26 @@
|
|||
*/
|
||||
package mage.sets.avacynrestored;
|
||||
|
||||
import mage.constants.*;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.abilities.mana.AnyColorManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetLandPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
*/
|
||||
|
@ -53,7 +57,6 @@ public class AbundantGrowth extends CardImpl {
|
|||
this.expansionSetCode = "AVR";
|
||||
this.subtype.add("Aura");
|
||||
|
||||
|
||||
// Enchant land
|
||||
TargetPermanent auraTarget = new TargetLandPermanent();
|
||||
this.getSpellAbility().addTarget(auraTarget);
|
||||
|
@ -66,7 +69,9 @@ public class AbundantGrowth extends CardImpl {
|
|||
|
||||
// Enchanted land has "{tap}: Add one mana of any color to your mana pool."
|
||||
Ability gainedAbility = new AnyColorManaAbility(new TapSourceCost());
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA)));
|
||||
Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA);
|
||||
effect.setText("Enchanted land has \"{tap}: Add one mana of any color to your mana pool.\"");
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
|
||||
}
|
||||
|
||||
public AbundantGrowth(final AbundantGrowth card) {
|
||||
|
|
|
@ -60,7 +60,7 @@ public class GideonAllyOfZendikar extends CardImpl {
|
|||
super(ownerId, 29, "Gideon, Ally of Zendikar", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{W}{W}");
|
||||
this.expansionSetCode = "BFZ";
|
||||
this.subtype.add("Gideon");
|
||||
|
||||
|
||||
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false));
|
||||
|
||||
// +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn.
|
||||
|
@ -69,7 +69,7 @@ public class GideonAllyOfZendikar extends CardImpl {
|
|||
effect.setText("Prevent all damage that would be dealt to him this turn");
|
||||
ability.addEffect(effect);
|
||||
this.addAbility(ability);
|
||||
|
||||
|
||||
// 0: Put a 2/2 white Knight Ally creature token onto the battlefield.
|
||||
this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new KnightAllyToken()), 0));
|
||||
|
||||
|
@ -94,6 +94,7 @@ class GideonAllyOfZendikarEmblem extends Emblem {
|
|||
BoostControlledEffect effect = new BoostControlledEffect(1, 1, Duration.EndOfGame);
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, effect);
|
||||
this.getAbilities().add(ability);
|
||||
this.setExpansionSetCodeForImage("BFZ");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,8 +108,8 @@ class GideonAllyOfZendikarToken extends Token {
|
|||
subtype.add("Ally");
|
||||
power = new MageInt(5);
|
||||
toughness = new MageInt(5);
|
||||
|
||||
addAbility(IndestructibleAbility.getInstance());
|
||||
|
||||
addAbility(IndestructibleAbility.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,4 +124,4 @@ class KnightAllyToken extends Token {
|
|||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ import mage.MageObject;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DiesTriggeredAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
|
||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
|
@ -44,6 +46,7 @@ import mage.constants.Rarity;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -99,10 +102,15 @@ class GreenwardenOfMurasaEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (controller != null && sourceObject != null) {
|
||||
Card targetCard = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && sourceObject != null && targetCard != null) {
|
||||
if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return card from your graveyard to your hand?", source, game)) {
|
||||
new ExileSourceEffect().apply(game, source);
|
||||
return new ReturnToHandTargetEffect().apply(game, source);
|
||||
// Setting the fixed target prevents to return Greenwarden of Murasa itself (becuase it's exiled meanwhile),
|
||||
// but of course you can target it as the ability triggers I guess
|
||||
Effect effect = new ReturnToHandTargetEffect();
|
||||
effect.setTargetPointer(new FixedTarget(targetCard.getId(), targetCard.getZoneChangeCounter(game)));
|
||||
return effect.apply(game, source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -46,9 +46,8 @@ import mage.target.targetpointer.SecondTargetPointer;
|
|||
public class GripOfDesolation extends CardImpl {
|
||||
|
||||
public GripOfDesolation(UUID ownerId) {
|
||||
super(ownerId, 94, "Grip of Desolation", Rarity.UNCOMMON, new CardType[]{}, "{4}{B}{B}");
|
||||
super(ownerId, 94, "Grip of Desolation", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{4}{B}{B}");
|
||||
this.expansionSetCode = "BFZ";
|
||||
this.supertype.add("Intant");
|
||||
|
||||
// Devoid
|
||||
Ability ability = new DevoidAbility(this.color);
|
||||
|
|
|
@ -53,7 +53,7 @@ public class InfuseWithTheElements extends CardImpl {
|
|||
|
||||
// <i>Converge</i> - Put X +1/+1 counters on target creature, where X is the number of colors of mana spent to cast Infuse with the Elements.
|
||||
this.getSpellAbility().setAbilityWord(AbilityWord.CONVERGE);
|
||||
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), ColorsOfManaSpentToCastCount.getInstance());
|
||||
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(0), ColorsOfManaSpentToCastCount.getInstance());
|
||||
effect.setText("Put X +1/+1 counters on target creature, where X is the number of colors of mana spent to cast {this}");
|
||||
this.getSpellAbility().addEffect(effect);
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
|
|
|
@ -150,17 +150,16 @@ class KioraRevealEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (sourceObject != null && player != null) {
|
||||
Cards cards = new CardsImpl(Zone.PICK);
|
||||
if (sourceObject != null && controller != null) {
|
||||
Cards cards = new CardsImpl(Zone.LIBRARY);
|
||||
cards.addAll(controller.getLibrary().getTopCards(game, 4));
|
||||
boolean creatureCardFound = false;
|
||||
boolean landCardFound = false;
|
||||
int count = Math.min(player.getLibrary().size(), 4);
|
||||
for (int i = 0; i < count; i++) {
|
||||
Card card = player.getLibrary().removeFromTop(game);
|
||||
for (UUID cardId : cards) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
game.setZone(card.getId(), Zone.PICK);
|
||||
cards.add(card);
|
||||
if (card.getCardType().contains(CardType.CREATURE)) {
|
||||
creatureCardFound = true;
|
||||
|
@ -172,30 +171,30 @@ class KioraRevealEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
if (!cards.isEmpty()) {
|
||||
player.revealCards(sourceObject.getName(), cards, game);
|
||||
if ((creatureCardFound || landCardFound)
|
||||
&& player.chooseUse(Outcome.DrawCard,
|
||||
controller.revealCards(sourceObject.getName(), cards, game);
|
||||
if ((creatureCardFound || landCardFound)
|
||||
&& controller.chooseUse(Outcome.DrawCard,
|
||||
"Put a creature card and/or a land card into your hand?", source, game)) {
|
||||
TargetCard target = new TargetCard(Zone.PICK, new FilterCreatureCard("creature card to put into your hand"));
|
||||
if (creatureCardFound && player.choose(Outcome.DrawCard, cards, target, game)) {
|
||||
if (creatureCardFound && controller.chooseTarget(Outcome.DrawCard, cards, target, source, game)) {
|
||||
Card card = cards.get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
card.moveToZone(Zone.HAND, source.getSourceId(), game, false);
|
||||
controller.moveCards(card, null, Zone.HAND, source, game);
|
||||
}
|
||||
}
|
||||
|
||||
target = new TargetCard(Zone.PICK, new FilterLandCard("land card to put into your hand"));
|
||||
if (landCardFound && player.choose(Outcome.DrawCard, cards, target, game)) {
|
||||
target = new TargetCard(Zone.LIBRARY, new FilterLandCard("land card to put into your hand"));
|
||||
if (landCardFound && controller.chooseTarget(Outcome.DrawCard, cards, target, source, game)) {
|
||||
Card card = cards.get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
card.moveToZone(Zone.HAND, source.getSourceId(), game, false);
|
||||
controller.moveCards(card, null, Zone.HAND, source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
player.moveCards(cards, Zone.PICK, Zone.GRAVEYARD, source, game);
|
||||
controller.moveCards(cards, null, Zone.GRAVEYARD, source, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -208,12 +207,13 @@ class KioraMasterOfTheDepthsEmblem extends Emblem {
|
|||
|
||||
public KioraMasterOfTheDepthsEmblem() {
|
||||
this.setName("EMBLEM: Kiora, Master of the Depths");
|
||||
|
||||
|
||||
Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.COMMAND,
|
||||
new KioraFightEffect(), filter, true, SetTargetPointer.PERMANENT,
|
||||
"Whenever a creature enters the battlefield under your control, you may have it fight target creature.");
|
||||
ability.addTarget(new TargetCreaturePermanent());
|
||||
this.getAbilities().add(ability);
|
||||
this.setExpansionSetCodeForImage("BFZ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public class MakindiPatrol extends CardImpl {
|
|||
|
||||
// <i>Rally</i> — Whenever Makindi Patrol or another Ally enters the battlefield under your control, creatures you control gain vigilance until end of turn.
|
||||
this.addAbility(new AllyEntersBattlefieldTriggeredAbility(
|
||||
new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control")), false));
|
||||
new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures")), false));
|
||||
}
|
||||
|
||||
public MakindiPatrol(final MakindiPatrol card) {
|
||||
|
|
|
@ -40,10 +40,12 @@ import mage.cards.CardsImpl;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -79,7 +81,7 @@ public class MundaAmbushLeader extends CardImpl {
|
|||
|
||||
class MundaAmbushLeaderEffect extends OneShotEffect {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("Ally cards");
|
||||
private static final FilterCard filter = new FilterCard("Ally cards to reveal and put on top of your libraray");
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate("Ally"));
|
||||
|
@ -107,12 +109,16 @@ class MundaAmbushLeaderEffect extends OneShotEffect {
|
|||
Cards allCards = new CardsImpl();
|
||||
allCards.addAll(controller.getLibrary().getTopCards(game, 4));
|
||||
controller.lookAtCards(sourceObject.getIdName(), allCards, game);
|
||||
Cards allyCards = new CardsImpl();
|
||||
allyCards.addAll(allCards.getCards(filter, source.getSourceId(), source.getControllerId(), game));
|
||||
if (!allyCards.isEmpty()) {
|
||||
controller.revealCards(sourceObject.getIdName(), allyCards, game, true);
|
||||
allCards.removeAll(allyCards);
|
||||
controller.putCardsOnTopOfLibrary(allyCards, game, source, true);
|
||||
if (!allCards.isEmpty()) {
|
||||
Cards cardsToReveal = new CardsImpl();
|
||||
TargetCard target = new TargetCard(0, Integer.MAX_VALUE, Zone.LIBRARY, new FilterCard("Ally cards to put on top of your libraray"));
|
||||
controller.chooseTarget(outcome, allCards, target, source, game);
|
||||
cardsToReveal.addAll(target.getTargets());
|
||||
if (!cardsToReveal.isEmpty()) {
|
||||
controller.revealCards(sourceObject.getIdName(), cardsToReveal, game, true);
|
||||
allCards.removeAll(cardsToReveal);
|
||||
}
|
||||
controller.putCardsOnTopOfLibrary(cardsToReveal, game, source, true);
|
||||
}
|
||||
if (!allCards.isEmpty()) {
|
||||
controller.putCardsOnBottomOfLibrary(allCards, game, source, true);
|
||||
|
|
|
@ -100,6 +100,7 @@ class ObNixilisReignitedEmblem extends Emblem {
|
|||
setName("EMBLEM: Ob Nixilis Reignited");
|
||||
|
||||
this.getAbilities().add(new ObNixilisEmblemTriggeredAbility(new LoseLifeSourceControllerEffect(2), false));
|
||||
this.setExpansionSetCodeForImage("BFZ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,9 @@ class OblivionSowerEffect extends OneShotEffect {
|
|||
Cards exiledLands = new CardsImpl();
|
||||
exiledLands.addAll(exiledCards.getCards(filter, source.getSourceId(), controller.getId(), game));
|
||||
if (!exiledLands.isEmpty() && controller.chooseUse(outcome, "Put lands into play?", source, game)) {
|
||||
FilterCard filterToPlay = new FilterCard("Lands owned by " + targetPlayer.getName() + " to put into play under your control");
|
||||
FilterCard filterToPlay = new FilterCard("land"
|
||||
+ (exiledLands.size() > 1 ? "s" : "") + " from exile owned by "
|
||||
+ targetPlayer.getName() + " to put into play under your control");
|
||||
TargetCard targetCards = new TargetCard(0, exiledLands.size(), Zone.EXILED, filterToPlay);
|
||||
if (controller.chooseTarget(outcome, exiledLands, targetCards, source, game)) {
|
||||
controller.moveCards(new CardsImpl(targetCards.getTargets()), null, Zone.BATTLEFIELD, source, game);
|
||||
|
|
|
@ -41,7 +41,6 @@ import mage.constants.Duration;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.filter.common.FilterControlledLandPermanent;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
|
||||
/**
|
||||
|
@ -60,7 +59,6 @@ public class SlabHammer extends CardImpl {
|
|||
new DoIfCostPaid(new BoostEquippedEffect(2, 2, Duration.EndOfTurn),
|
||||
new ReturnToHandTargetPermanentCost(new TargetControlledPermanent(new FilterControlledLandPermanent())),
|
||||
"Return a land you control to its owner's hand? (giving +2/+2 to the equipped creature)"));
|
||||
ability.addTarget(new TargetPermanent());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Equip {2}
|
||||
|
|
|
@ -52,7 +52,7 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
*/
|
||||
public class TitansPresence extends CardImpl {
|
||||
|
||||
private static final FilterCreatureCard filter = new FilterCreatureCard("a colorless creature card from your hand to reveal");
|
||||
private static final FilterCreatureCard filter = new FilterCreatureCard("a colorless creature card from your hand");
|
||||
|
||||
static {
|
||||
filter.add(new ColorlessPredicate());
|
||||
|
|
|
@ -40,6 +40,7 @@ import mage.constants.TargetController;
|
|||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -63,7 +64,7 @@ public class FumikoTheLowblood extends CardImpl {
|
|||
// Creatures your opponents control attack each turn if able.
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control");
|
||||
filter.add(new ControllerPredicate(TargetController.OPPONENT));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter)));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter)), new AttackedThisTurnWatcher());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ import mage.target.TargetSpell;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
import mage.constants.Outcome;
|
||||
*
|
||||
* import mage.constants.Outcome;
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class Mindreaver extends CardImpl {
|
||||
|
@ -77,10 +77,10 @@ public class Mindreaver extends CardImpl {
|
|||
Ability ability = new HeroicAbility(new MindreaverExileEffect(), false);
|
||||
ability.addTarget(new TargetPlayer());
|
||||
this.addAbility(ability);
|
||||
|
||||
// {U}{U}, Sacrifice Mindreaver: Counter target spell with the same name as a card exiled with mindreaver.
|
||||
|
||||
// {U}{U}, Sacrifice Mindreaver: Counter target spell with the same name as a card exiled with Mindreaver.
|
||||
ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{U}{U}"));
|
||||
FilterSpell filter = new FilterSpell("spell with the same name as a card exiled with mindreaver");
|
||||
FilterSpell filter = new FilterSpell("spell with the same name as a card exiled with {this}");
|
||||
filter.add(new MindreaverNamePredicate(this.getId()));
|
||||
ability.addTarget(new TargetSpell(filter));
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
|
@ -116,12 +116,13 @@ class MindreaverExileEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
UUID exileId = CardUtil.getCardExileZoneId(game, source);
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source));
|
||||
if (opponent != null) {
|
||||
if (opponent != null && sourceObject != null) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Card card = opponent.getLibrary().getFromTop(game);
|
||||
if (card != null) {
|
||||
card.moveToExile(exileId, "Mindreaver", source.getSourceId(), game);
|
||||
card.moveToExile(exileId, sourceObject.getIdName(), source.getSourceId(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,29 +131,29 @@ class MindreaverExileEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
class MindreaverNamePredicate implements Predicate<MageObject> {
|
||||
|
||||
|
||||
private final UUID sourceId;
|
||||
|
||||
|
||||
public MindreaverNamePredicate(UUID sourceId) {
|
||||
this.sourceId = sourceId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(MageObject input, Game game) {
|
||||
Set<String> cardNames = new HashSet<String>();
|
||||
UUID exileId = CardUtil.getCardExileZoneId(game, sourceId);
|
||||
ExileZone exileZone = game.getExile().getExileZone(exileId);
|
||||
if (exileZone != null) {
|
||||
for(Card card : exileZone.getCards(game)) {
|
||||
for (Card card : exileZone.getCards(game)) {
|
||||
cardNames.add(card.getName());
|
||||
}
|
||||
}
|
||||
// If a player names a card, the player may name either half of a split card, but not both.
|
||||
// If a player names a card, the player may name either half of a split card, but not both.
|
||||
// A split card has the chosen name if one of its two names matches the chosen name.
|
||||
if (input instanceof SplitCard) {
|
||||
return cardNames.contains(((SplitCard)input).getLeftHalfCard().getName()) || cardNames.contains(((SplitCard)input).getRightHalfCard().getName());
|
||||
} else if (input instanceof Spell && ((Spell)input).getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)){
|
||||
SplitCard card = (SplitCard) ((Spell)input).getCard();
|
||||
return cardNames.contains(((SplitCard) input).getLeftHalfCard().getName()) || cardNames.contains(((SplitCard) input).getRightHalfCard().getName());
|
||||
} else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
|
||||
SplitCard card = (SplitCard) ((Spell) input).getCard();
|
||||
return cardNames.contains(card.getLeftHalfCard().getName()) || cardNames.contains(card.getRightHalfCard().getName());
|
||||
} else {
|
||||
return cardNames.contains(input.getName());
|
||||
|
@ -163,4 +164,4 @@ class MindreaverNamePredicate implements Predicate<MageObject> {
|
|||
public String toString() {
|
||||
return "spell with the same name as a card exiled with {source}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import mage.constants.Duration;
|
|||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -62,7 +63,7 @@ public class AvatarOfSlaughter extends CardImpl {
|
|||
effect = new AttacksIfAbleAllEffect(new FilterCreaturePermanent("creatures"));
|
||||
effect.setText("and attack each turn if able");
|
||||
ability.addEffect(effect);
|
||||
this.addAbility(ability);
|
||||
this.addAbility(ability, new AttackedThisTurnWatcher());
|
||||
}
|
||||
|
||||
public AvatarOfSlaughter(final AvatarOfSlaughter card) {
|
||||
|
|
|
@ -38,7 +38,7 @@ import mage.filter.common.FilterEnchantmentPermanent;
|
|||
import mage.target.Target;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetArtifactPermanent;
|
||||
import mage.target.targetpointer.SecondTargetPointer;
|
||||
import mage.target.common.TargetEnchantmentPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -62,12 +62,11 @@ public class HullBreach extends CardImpl {
|
|||
this.getSpellAbility().addMode(mode);
|
||||
// or destroy target artifact and target enchantment.
|
||||
mode = new Mode();
|
||||
Effect effect = new DestroyTargetEffect();
|
||||
effect.setTargetPointer(new SecondTargetPointer());
|
||||
Effect effect = new DestroyTargetEffect(false, true);
|
||||
effect.setText("destroy target artifact and target enchantment");
|
||||
mode.getEffects().add(effect);
|
||||
mode.getTargets().add(new TargetArtifactPermanent());
|
||||
mode.getTargets().add(new TargetPermanent(new FilterEnchantmentPermanent()));
|
||||
mode.getTargets().add(new TargetEnchantmentPermanent());
|
||||
this.getSpellAbility().addMode(mode);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
package mage.sets.commander2013;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
@ -51,7 +53,6 @@ public class TemptWithDiscovery extends CardImpl {
|
|||
super(ownerId, 174, "Tempt with Discovery", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{G}");
|
||||
this.expansionSetCode = "C13";
|
||||
|
||||
|
||||
// Tempting offer - Search your library for a land card and put it onto the battlefield.
|
||||
// Each opponent may search his or her library for a land card and put it onto the battlefield.
|
||||
// For each opponent who searches a library this way, search your library for a land card and put it onto the battlefield.
|
||||
|
@ -89,12 +90,14 @@ class TemptWithDiscoveryEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Set<UUID> playersShuffle = new LinkedHashSet<>();
|
||||
playersShuffle.add(controller.getId());
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard());
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
for (UUID cardId: target.getTargets()) {
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), controller.getId());
|
||||
controller.moveCards(card, null, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,11 +108,12 @@ class TemptWithDiscoveryEffect extends OneShotEffect {
|
|||
if (opponent.chooseUse(outcome, "Search your library for a land card and put it onto the battlefield?", source, game)) {
|
||||
target.clearChosen();
|
||||
opponentsUsedSearch++;
|
||||
playersShuffle.add(playerId);
|
||||
if (opponent.searchLibrary(target, game)) {
|
||||
for (UUID cardId: target.getTargets()) {
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), opponent.getId());
|
||||
opponent.moveCards(card, null, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,17 +123,23 @@ class TemptWithDiscoveryEffect extends OneShotEffect {
|
|||
if (opponentsUsedSearch > 0) {
|
||||
target = new TargetCardInLibrary(0, opponentsUsedSearch, new FilterLandCard());
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
for (UUID cardId: target.getTargets()) {
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), controller.getId());
|
||||
controller.moveCards(card, null, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UUID playerId : playersShuffle) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
player.shuffleLibrary(game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public class WarmongerHellkite extends CardImpl {
|
|||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// All creatures attack each combat if able.
|
||||
Effect effect = new AttacksIfAbleAllEffect(new FilterCreaturePermanent("creatures"));
|
||||
Effect effect = new AttacksIfAbleAllEffect(new FilterCreaturePermanent("creatures"), Duration.WhileOnBattlefield, true);
|
||||
effect.setText("All creatures attack each combat if able");
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
|
@ -20,20 +20,19 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.sets.conflux;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
|
@ -57,6 +56,7 @@ public class CelestialPurge extends CardImpl {
|
|||
super(ownerId, 5, "Celestial Purge", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{W}");
|
||||
this.expansionSetCode = "CON";
|
||||
|
||||
// Exile target black or red permanent.
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||
this.getSpellAbility().addEffect(new ExileTargetEffect());
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ThrabenDoomsayer extends CardImpl {
|
|||
// {tap}: Put a 1/1 white Human creature token onto the battlefield.
|
||||
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, false),
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, true),
|
||||
FatefulHourCondition.getInstance(), "As long as you have 5 or less life, other creatures you control get +2/+2")));
|
||||
}
|
||||
|
||||
|
|
|
@ -44,22 +44,21 @@ import mage.filter.predicate.permanent.ControllerPredicate;
|
|||
* @author LevelX2
|
||||
*/
|
||||
public class DictateOfErebos extends CardImpl {
|
||||
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control");
|
||||
|
||||
|
||||
static {
|
||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
}
|
||||
|
||||
|
||||
public DictateOfErebos(UUID ownerId) {
|
||||
super(ownerId, 65, "Dictate of Erebos", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}");
|
||||
this.expansionSetCode = "JOU";
|
||||
|
||||
|
||||
// Flash
|
||||
this.addAbility(FlashAbility.getInstance());
|
||||
// Whenever a creature you control dies, each opponent sacrifices a creature.
|
||||
this.addAbility(new DiesCreatureTriggeredAbility(new SacrificeOpponentsEffect(new FilterControlledCreaturePermanent("a creature")), false, filter));
|
||||
this.addAbility(new DiesCreatureTriggeredAbility(new SacrificeOpponentsEffect(new FilterControlledCreaturePermanent("a creature")), false, filter));
|
||||
}
|
||||
|
||||
public DictateOfErebos(final DictateOfErebos card) {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
|
@ -20,26 +20,25 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.sets.magic2011;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.RemoveCountersSourceCost;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.target.common.TargetCreatureOrPlayer;
|
||||
|
||||
|
@ -56,7 +55,10 @@ public class Triskelion extends CardImpl {
|
|||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// Triskelion enters the battlefield with three +1/+1 counters on it.
|
||||
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), "with three +1/+1 counters on it"));
|
||||
|
||||
// Remove a +1/+1 counter from Triskelion: Triskelion deals 1 damage to target creature or player.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new RemoveCountersSourceCost(CounterType.P1P1.createInstance()));
|
||||
ability.addTarget(new TargetCreatureOrPlayer());
|
||||
this.addAbility(ability);
|
||||
|
|
|
@ -74,7 +74,6 @@ public class ChandraPyromaster extends CardImpl {
|
|||
this.expansionSetCode = "M14";
|
||||
this.subtype.add("Chandra");
|
||||
|
||||
|
||||
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false));
|
||||
|
||||
// +1: Chandra, Pyromaster deals 1 damage to target player and 1 damage to up to one target creature that player controls. That creature can't block this turn.
|
||||
|
@ -215,7 +214,7 @@ class ChandraPyromasterEffect2 extends OneShotEffect {
|
|||
Card card = library.removeFromTop(game);
|
||||
if (card != null) {
|
||||
controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName() + " <this card may be played the turn it was exiled>", source.getSourceId(), game, Zone.LIBRARY, true);
|
||||
ContinuousEffect effect = new ChandraPyromasterCastFromExileEffect();
|
||||
ContinuousEffect effect = new ChandraPyromasterCastFromExileEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
|
@ -273,36 +272,31 @@ class ChandraPyromasterEffect3 extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player you = game.getPlayer(source.getControllerId());
|
||||
if (you == null) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller == null || sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
Cards cards = new CardsImpl();
|
||||
int max = Math.min(you.getLibrary().size(), 10);
|
||||
for (int i = 0; i < max; i++) {
|
||||
Card card = you.getLibrary().removeFromTop(game);
|
||||
if (card != null) {
|
||||
card.moveToExile(source.getSourceId(), "Chandra Pyromaster", source.getSourceId(), game);
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
cards.addAll(controller.getLibrary().getTopCards(game, 10));
|
||||
controller.moveCardsToExile(cards.getCards(game), source, game, true, source.getSourceId(), sourceObject.getIdName());
|
||||
|
||||
if (cards.getCards(new FilterInstantOrSorceryCard(), game).size() > 0) {
|
||||
TargetCard target = new TargetCard(Zone.EXILED, new FilterInstantOrSorceryCard());
|
||||
if (you.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) {
|
||||
if (controller.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) {
|
||||
Card card = cards.get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
Card copy1 = card.copy();
|
||||
Card copy2 = card.copy();
|
||||
Card copy3 = card.copy();
|
||||
if (copy1 != null && you.chooseUse(outcome, "Do you wish to cast copy 1 of " + card.getName(), source, game)) {
|
||||
you.cast(copy1.getSpellAbility(), game, true);
|
||||
if (controller.chooseUse(outcome, "Do you wish to cast copy 1 of " + card.getName(), source, game)) {
|
||||
Card copy1 = card.copy();
|
||||
controller.cast(copy1.getSpellAbility(), game, true);
|
||||
}
|
||||
if (copy2 != null && you.chooseUse(outcome, "Do you wish to cast copy 2 of " + card.getName(), source, game)) {
|
||||
you.cast(copy2.getSpellAbility(), game, true);
|
||||
if (controller.chooseUse(outcome, "Do you wish to cast copy 2 of " + card.getName(), source, game)) {
|
||||
Card copy2 = card.copy();
|
||||
controller.cast(copy2.getSpellAbility(), game, true);
|
||||
}
|
||||
if (copy3 != null && you.chooseUse(outcome, "Do you wish to cast copy 3 of " + card.getName(), source, game)) {
|
||||
you.cast(copy3.getSpellAbility(), game, true);
|
||||
if (controller.chooseUse(outcome, "Do you wish to cast copy 3 of " + card.getName(), source, game)) {
|
||||
Card copy3 = card.copy();
|
||||
controller.cast(copy3.getSpellAbility(), game, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import mage.filter.predicate.permanent.AnotherPredicate;
|
|||
import mage.filter.predicate.permanent.AttackingPredicate;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -59,15 +60,15 @@ public class GoblinRabblemaster extends CardImpl {
|
|||
|
||||
private static final FilterCreaturePermanent otherGoblinFilter = new FilterCreaturePermanent("Goblin", "Other Goblin creatures you control");
|
||||
private static final FilterCreaturePermanent attackingFilter = new FilterCreaturePermanent("Goblin", "other attacking Goblin");
|
||||
|
||||
|
||||
static {
|
||||
otherGoblinFilter.add(new AnotherPredicate());
|
||||
otherGoblinFilter.add(new ControllerPredicate(TargetController.YOU));
|
||||
|
||||
|
||||
attackingFilter.add(new AttackingPredicate());
|
||||
attackingFilter.add(new AnotherPredicate());
|
||||
}
|
||||
|
||||
|
||||
public GoblinRabblemaster(UUID ownerId) {
|
||||
super(ownerId, 145, "Goblin Rabblemaster", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}");
|
||||
this.expansionSetCode = "M15";
|
||||
|
@ -79,11 +80,11 @@ public class GoblinRabblemaster extends CardImpl {
|
|||
|
||||
// Other Goblin creatures you control attack each turn if able.
|
||||
Effect effect = new AttacksIfAbleAllEffect(otherGoblinFilter);
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
|
||||
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), new AttackedThisTurnWatcher());
|
||||
|
||||
// At the beginning of combat on your turn, put a 1/1 red Goblin creature token with haste onto the battlefield.
|
||||
this.addAbility(new BeginningOfCombatTriggeredAbility(new CreateTokenEffect(new GoblinToken()), TargetController.YOU, false));
|
||||
|
||||
|
||||
// When Goblin Rabblemaster attacks, it gets +1/+0 until end of turn for each other attacking Goblin.
|
||||
this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(new PermanentsOnBattlefieldCount(attackingFilter), new StaticValue(0), Duration.EndOfTurn, true), false));
|
||||
}
|
||||
|
@ -110,5 +111,5 @@ class GoblinToken extends Token {
|
|||
toughness = new MageInt(1);
|
||||
addAbility(HasteAbility.getInstance());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import mage.constants.CardType;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Library;
|
||||
|
@ -60,7 +61,7 @@ public class EvolutionaryLeap extends CardImpl {
|
|||
|
||||
// {G}, Sacrifice a creature: Reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EvolutionaryLeapEffect(), new ManaCostsImpl("{G}"));
|
||||
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent()));
|
||||
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature"))));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ class EvolutionaryLeapEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (controller != null && controller.getLibrary().size() > 0) {
|
||||
if (controller != null && controller.getLibrary().size() > 0) {
|
||||
Cards cards = new CardsImpl();
|
||||
Library library = controller.getLibrary();
|
||||
Card card = null;
|
||||
|
@ -108,22 +109,27 @@ class EvolutionaryLeapEffect extends OneShotEffect {
|
|||
} while (library.size() > 0 && card != null && !filter.match(card, game));
|
||||
// reveal cards
|
||||
if (!cards.isEmpty()) {
|
||||
controller.revealCards(sourceObject.getName(), cards, game);
|
||||
}
|
||||
// put creature card in hand
|
||||
controller.moveCards(card, Zone.LIBRARY, Zone.HAND, source, game);
|
||||
// remove it from revealed card list
|
||||
cards.remove(card);
|
||||
// Put the rest on the bottom of your library in a random order
|
||||
while (cards.size() > 0) {
|
||||
card = cards.getRandom(game);
|
||||
if (card != null) {
|
||||
controller.revealCards(sourceObject.getIdName(), cards, game);
|
||||
if (filter.match(card, game)) {
|
||||
// put creature card in hand
|
||||
controller.moveCards(card, Zone.LIBRARY, Zone.HAND, source, game);
|
||||
// remove it from revealed card list
|
||||
cards.remove(card);
|
||||
controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, false, false);
|
||||
}
|
||||
// Put the rest on the bottom of your library in a random order
|
||||
Cards randomOrder = new CardsImpl();
|
||||
while (cards.size() > 0) {
|
||||
card = cards.getRandom(game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
randomOrder.add(card);
|
||||
controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, false, false);
|
||||
}
|
||||
}
|
||||
controller.putCardsOnBottomOfLibrary(randomOrder, game, source, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,18 +48,19 @@ import mage.filter.predicate.permanent.ControllerPredicate;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public class InciteWar extends CardImpl {
|
||||
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control");
|
||||
|
||||
static {
|
||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
}
|
||||
}
|
||||
|
||||
public InciteWar(UUID ownerId) {
|
||||
super(ownerId, 96, "Incite War", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{R}");
|
||||
|
@ -68,12 +69,13 @@ public class InciteWar extends CardImpl {
|
|||
// Choose one - Creatures target player controls attack this turn if able;
|
||||
this.getSpellAbility().addEffect(new InciteWarMustAttackEffect());
|
||||
this.getSpellAbility().addTarget(new TargetPlayer());
|
||||
|
||||
this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher());
|
||||
|
||||
// or creatures you control gain first strike until end of turn.
|
||||
Mode mode = new Mode();
|
||||
mode.getEffects().add(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter));
|
||||
this.getSpellAbility().getModes().addMode(mode);
|
||||
|
||||
|
||||
// Entwine {2}
|
||||
this.addAbility(new EntwineAbility("{2}"));
|
||||
}
|
||||
|
@ -91,7 +93,7 @@ public class InciteWar extends CardImpl {
|
|||
class InciteWarMustAttackEffect extends OneShotEffect {
|
||||
|
||||
public InciteWarMustAttackEffect() {
|
||||
super(Outcome.Detriment);
|
||||
super(Outcome.Detriment);
|
||||
staticText = "Creatures target player control attack this turn if able";
|
||||
}
|
||||
|
||||
|
@ -116,4 +118,4 @@ class InciteWarMustAttackEffect extends OneShotEffect {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.sets.morningtide;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.TargetController;
|
||||
import mage.game.permanent.token.FaerieRogueToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Loki
|
||||
*/
|
||||
public class Bitterblossom extends CardImpl {
|
||||
|
||||
public Bitterblossom(UUID ownerId) {
|
||||
super(ownerId, 58, "Bitterblossom", Rarity.RARE, new CardType[]{CardType.TRIBAL, CardType.ENCHANTMENT}, "{1}{B}");
|
||||
this.expansionSetCode = "MOR";
|
||||
this.subtype.add("Faerie");
|
||||
|
||||
// At the beginning of your upkeep, you lose 1 life and put a 1/1 black Faerie Rogue creature token with flying onto the battlefield.
|
||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(1), TargetController.YOU, false);
|
||||
ability.addEffect(new CreateTokenEffect(new FaerieRogueToken(), 1));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public Bitterblossom(final Bitterblossom card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitterblossom copy() {
|
||||
return new Bitterblossom(this);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.sets.morningtide;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.TargetController;
|
||||
import mage.game.permanent.token.FaerieRogueToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Loki
|
||||
*/
|
||||
public class Bitterblossom extends CardImpl {
|
||||
|
||||
public Bitterblossom(UUID ownerId) {
|
||||
super(ownerId, 58, "Bitterblossom", Rarity.RARE, new CardType[]{CardType.TRIBAL, CardType.ENCHANTMENT}, "{1}{B}");
|
||||
this.expansionSetCode = "MOR";
|
||||
this.subtype.add("Faerie");
|
||||
|
||||
// At the beginning of your upkeep, you lose 1 life and put a 1/1 black Faerie Rogue creature token with flying onto the battlefield.
|
||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(1), TargetController.YOU, false);
|
||||
ability.addEffect(new CreateTokenEffect(new FaerieRogueToken(), 1));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public Bitterblossom(final Bitterblossom card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitterblossom copy() {
|
||||
return new Bitterblossom(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.util.UUID;
|
|||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SpellCastAllTriggeredAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.SoulshiftAbility;
|
||||
import mage.cards.Card;
|
||||
|
@ -61,7 +61,7 @@ public class ElderPineOfJukai extends CardImpl {
|
|||
this.toughness = new MageInt(1);
|
||||
|
||||
// Whenever you cast a Spirit or Arcane spell, reveal the top three cards of your library. Put all land cards revealed this way into your hand and the rest on the bottom of your library in any order.
|
||||
this.addAbility(new SpellCastAllTriggeredAbility(new ElderPineOfJukaiEffect(), new FilterSpiritOrArcaneCard(), false));
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(new ElderPineOfJukaiEffect(), new FilterSpiritOrArcaneCard(), false));
|
||||
|
||||
// Soulshift 2
|
||||
this.addAbility(new SoulshiftAbility(2));
|
||||
|
|
|
@ -28,22 +28,22 @@
|
|||
package mage.sets.shardsofalara;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.*;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -51,15 +51,21 @@ import mage.game.permanent.token.Token;
|
|||
*/
|
||||
public class GoblinAssault extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblin creatures");
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate("Goblin"));
|
||||
}
|
||||
|
||||
public GoblinAssault(UUID ownerId) {
|
||||
super(ownerId, 101, "Goblin Assault", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
|
||||
this.expansionSetCode = "ALA";
|
||||
|
||||
|
||||
// At the beginning of your upkeep, put a 1/1 red Goblin creature token with haste onto the battlefield.
|
||||
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new GoblinAssaultToken()), TargetController.YOU, false));
|
||||
|
||||
// Goblin creatures attack each turn if able.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GoblinAssaultEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter, Duration.WhileOnBattlefield)), new AttackedThisTurnWatcher());
|
||||
}
|
||||
|
||||
public GoblinAssault(final GoblinAssault card) {
|
||||
|
@ -72,48 +78,6 @@ public class GoblinAssault extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class GoblinAssaultEffect extends RequirementEffect {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblin creatures");
|
||||
static {
|
||||
filter.add(new SubtypePredicate("Goblin"));
|
||||
}
|
||||
|
||||
public GoblinAssaultEffect() {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
staticText = "Goblin creatures attack each turn if able";
|
||||
}
|
||||
|
||||
public GoblinAssaultEffect(final GoblinAssaultEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinAssaultEffect copy() {
|
||||
return new GoblinAssaultEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustAttack(Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustBlock(Game game) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GoblinAssaultToken extends Token {
|
||||
|
||||
public GoblinAssaultToken() {
|
||||
|
|
|
@ -38,70 +38,70 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class SpliceOnArcaneTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Test that it works to cast Through the Breach
|
||||
* by slicing it on an arcane spell
|
||||
* Test that it works to cast Through the Breach by slicing it on an arcane
|
||||
* spell
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testSpliceThroughTheBreach() {
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
// Sorcery - Arcane {R}
|
||||
// Lava Spike deals 3 damage to target player.
|
||||
addCard(Zone.HAND, playerA, "Lava Spike",1);
|
||||
addCard(Zone.HAND, playerA, "Lava Spike", 1);
|
||||
// You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice that creature at the beginning of the next end step.
|
||||
// Splice onto Arcane {2}{R}{R} (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
|
||||
addCard(Zone.HAND, playerA, "Through the Breach",1);
|
||||
addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
|
||||
addCard(Zone.HAND, playerA, "Through the Breach", 1);
|
||||
addCard(Zone.HAND, playerA, "Silvercoat Lion", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB);
|
||||
setChoice(playerA, "Silvercoat Lion");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 17);
|
||||
|
||||
|
||||
assertGraveyardCount(playerA, "Lava Spike", 1);
|
||||
assertHandCount(playerA, "Through the Breach", 1);
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||
assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true);
|
||||
Assert.assertEquals("All available mana has to be used", 0, playerA.getManaAvailable(currentGame).size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSpliceTorrentOfStone() {
|
||||
|
||||
public void testSpliceTorrentOfStone() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
// Sorcery - Arcane {R}
|
||||
// Lava Spike deals 3 damage to target player.
|
||||
addCard(Zone.HAND, playerA, "Lava Spike",1);
|
||||
addCard(Zone.HAND, playerA, "Lava Spike", 1);
|
||||
// Torrent of Stone deals 4 damage to target creature.
|
||||
// Splice onto Arcane-Sacrifice two Mountains. (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
|
||||
addCard(Zone.HAND, playerA, "Torrent of Stone",1);
|
||||
// Splice onto Arcane-Sacrifice two Mountains. (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
|
||||
addCard(Zone.HAND, playerA, "Torrent of Stone", 1);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion",1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB);
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 17);
|
||||
|
||||
|
||||
assertGraveyardCount(playerA, "Lava Spike", 1);
|
||||
assertHandCount(playerA, "Torrent of Stone", 1);
|
||||
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
|
||||
assertPermanentCount(playerA, "Mountain", 0);
|
||||
assertPermanentCount(playerA, "Mountain", 0);
|
||||
Assert.assertEquals("No more mana available", "[]", playerA.getManaAvailable(currentGame).toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nourishing Shoal's interaction with Splicing Through the Breach is
|
||||
* bugged. You should still need to pay 2RR as an additional cost, which is
|
||||
|
@ -111,34 +111,94 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase {
|
|||
* powerful.
|
||||
*/
|
||||
@Test
|
||||
public void testSpliceThroughTheBreach2() {
|
||||
public void testSpliceThroughTheBreach2() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
// You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost.
|
||||
// You gain X life.
|
||||
addCard(Zone.HAND, playerA, "Nourishing Shoal",1);
|
||||
addCard(Zone.HAND, playerA, "Giant Growth",1);
|
||||
addCard(Zone.HAND, playerA, "Nourishing Shoal", 1);
|
||||
addCard(Zone.HAND, playerA, "Giant Growth", 1);
|
||||
// You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice that creature at the beginning of the next end step.
|
||||
// Splice onto Arcane {2}{R}{R} (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
|
||||
addCard(Zone.HAND, playerA, "Through the Breach",1);
|
||||
addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
|
||||
addCard(Zone.HAND, playerA, "Through the Breach", 1);
|
||||
addCard(Zone.HAND, playerA, "Silvercoat Lion", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nourishing Shoal");
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "Silvercoat Lion");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 21);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
|
||||
assertGraveyardCount(playerA, "Nourishing Shoal", 1);
|
||||
assertHandCount(playerA, "Through the Breach", 1);
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||
assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true);
|
||||
|
||||
Assert.assertEquals("All available mana has to be used","[]", playerA.getManaAvailable(currentGame).toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Assert.assertEquals("All available mana has to be used", "[]", playerA.getManaAvailable(currentGame).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cards involved: Nourishing Shoal, Goryo's Vengeance, Griselbrand,
|
||||
* Terminate
|
||||
*
|
||||
* I actually noticed this bug on the 1.4.3 client, but I didn't see it in
|
||||
* the change log for 1.4.4, so I assume it is still unknown. Also, it is a
|
||||
* bit of a rules corner case and I haven't seen anyone else report it, so
|
||||
* the players of this deck may actually not realize it's incorrect.
|
||||
*
|
||||
* The scenario was that I cast a Nourishing Shoal with a Goryo's Vengeance
|
||||
* spliced to it targeting Griselbrand in my graveyard and exiling
|
||||
* Worldspine Wurm. My opponent responded with a Snapcaster Mage, so to
|
||||
* deprive him of his ability to reuse his counterspell, I cast the Goryo's
|
||||
* Vengeance on the Griselbrand. This one resolved. He then used Terminate
|
||||
* on the Griselbrand after I had activated it once. When the Shoal tried to
|
||||
* resolve, it should have been countered due to no legal target. However,
|
||||
* it caused me to gain 11 life. It did not resurrect Griselbrand
|
||||
* (correctly), but it should have done nothing at all.
|
||||
*
|
||||
* I include the info about the Terminate because thinking through, it could
|
||||
* be pertinent. I would guess what is going on here is one of two things.
|
||||
* Either the client doesn't recognize the Shoal with a spliced Vengeance as
|
||||
* a spell with a single target (because Shoal normally doesn't have a
|
||||
* target) or because the Griselbrand ended up back in the graveyard before
|
||||
* the Shoal tried to resolve, the client thought its target was still
|
||||
* valid. I lean toward the former since the Shoal/Vengeance properly failed
|
||||
* to resurrect the now dead again Griselbrand, so I don't think it was
|
||||
* reading that as the target, but I'm not certain. I will try to reproduce
|
||||
* the error against a bot and update this report.
|
||||
*/
|
||||
@Test
|
||||
public void testCounteredBecauseOfNoLegalTarget() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 8);
|
||||
// You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost.
|
||||
// You gain X life.
|
||||
addCard(Zone.HAND, playerA, "Nourishing Shoal", 1); // "{X}{G}{G}"
|
||||
// Return target legendary creature card from your graveyard to the battlefield. That creature gains haste. Exile it at the beginning of the next end step.
|
||||
// Splice onto Arcane {2}{B}
|
||||
addCard(Zone.HAND, playerA, "Goryo's Vengeance", 1); // {1}{B}
|
||||
addCard(Zone.GRAVEYARD, playerA, "Griselbrand", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nourishing Shoal");
|
||||
setChoice(playerA, "X=3");
|
||||
setChoice(playerA, "Yes"); // splice
|
||||
addTarget(playerA, "Griselbrand");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goryo's Vengeance", "Griselbrand", "Nourishing Shoal");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Nourishing Shoal", 1);
|
||||
assertGraveyardCount(playerA, "Goryo's Vengeance", 1);
|
||||
assertPermanentCount(playerA, "Griselbrand", 1);
|
||||
|
||||
assertLife(playerA, 20); // no life gain because Nourishing Shoal has to be countered having no legal targets (from Goryo's V.)
|
||||
assertLife(playerB, 20);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package org.mage.test.cards.abilities.oneshot.exile;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CelestialPurgeTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* I activated Celestial Purge trying to targeting a Bitterblossom but i
|
||||
* couldn't so please fix that bug
|
||||
*/
|
||||
@Test
|
||||
public void testExileWorks() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
// Exile target black or red permanent.
|
||||
addCard(Zone.HAND, playerA, "Celestial Purge");
|
||||
|
||||
// At the beginning of your upkeep, you lose 1 life and put a 1/1 black Faerie Rogue creature token with flying onto the battlefield.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Bitterblossom");
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Celestial Purge", "Bitterblossom");
|
||||
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 19);
|
||||
|
||||
assertGraveyardCount(playerA, "Celestial Purge", 1);
|
||||
|
||||
assertExileCount("Bitterblossom", 1);
|
||||
assertPermanentCount(playerB, "Faerie Rogue", 1);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package org.mage.test.cards.mana;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class HybridManaTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void testCastReaperKingMonoHybrid() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
|
||||
// Other Scarecrow creatures you control get +1/+1.
|
||||
// Whenever another Scarecrow enters the battlefield under your control, destroy target permanent.
|
||||
addCard(Zone.HAND, playerA, "Reaper King", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reaper King");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Reaper King", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -228,30 +228,62 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof ColoredManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof HybridManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mono Hybrid mana costs
|
||||
// First try only to pay colored mana with the pool
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof MonoHybridManaCost) {
|
||||
if (((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.W)) && pool.getWhite() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.B)) && pool.getBlack() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.R)) && pool.getRed() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.G)) && pool.getGreen() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.U)) && pool.getBlue() > 0)) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if colored didn't fit pay colorless with the mana
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof MonoHybridManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof SnowManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof GenericManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
|
|||
if (targetName != null && targetName.length() > 0) {
|
||||
return targetName + " doesn't untap during its controller's next untap step";
|
||||
} else {
|
||||
return "Target " + (mode == null ? "creature" : mode.getTargets().get(0).getTargetName()) + " doesn't untap during its controller's next untap step";
|
||||
return "target " + (mode == null ? "creature" : mode.getTargets().get(0).getTargetName()) + " doesn't untap during its controller's next untap step";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -46,8 +45,7 @@ import mage.target.TargetPermanent;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* All opponents have to sacrifice [amount] permanents
|
||||
* that match the [filter].
|
||||
* All opponents have to sacrifice [amount] permanents that match the [filter].
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
@ -59,6 +57,7 @@ public class SacrificeOpponentsEffect extends OneShotEffect {
|
|||
public SacrificeOpponentsEffect(FilterPermanent filter) {
|
||||
this(1, filter);
|
||||
}
|
||||
|
||||
public SacrificeOpponentsEffect(int amount, FilterPermanent filter) {
|
||||
this(new StaticValue(amount), filter);
|
||||
}
|
||||
|
@ -87,12 +86,14 @@ public class SacrificeOpponentsEffect extends OneShotEffect {
|
|||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
if (player != null) {
|
||||
int numTargets = Math.min(amount.calculate(game, source, this), game.getBattlefield().countAll(filter, player.getId(), game));
|
||||
TargetPermanent target = new TargetPermanent(numTargets, numTargets, filter, true);
|
||||
if (target.canChoose(player.getId(), game)) {
|
||||
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
||||
perms.addAll(target.getTargets());
|
||||
if (numTargets > 0) {
|
||||
TargetPermanent target = new TargetPermanent(numTargets, numTargets, filter, true);
|
||||
if (target.canChoose(player.getId(), game)) {
|
||||
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
||||
perms.addAll(target.getTargets());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
@ -12,6 +11,7 @@ import mage.constants.Duration;
|
|||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -24,19 +24,28 @@ public class AttacksIfAbleAllEffect extends RequirementEffect {
|
|||
public AttacksIfAbleAllEffect(FilterCreaturePermanent filter) {
|
||||
this(filter, Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
||||
|
||||
boolean eachCombat;
|
||||
|
||||
public AttacksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration) {
|
||||
this(filter, duration, false);
|
||||
}
|
||||
|
||||
public AttacksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration, boolean eachCombat) {
|
||||
super(duration);
|
||||
staticText = new StringBuilder(filter.getMessage())
|
||||
.append(" attack ")
|
||||
.append(duration.equals(Duration.EndOfTurn) ? "this":"each")
|
||||
.append(" turn if able").toString();
|
||||
this.filter = filter;
|
||||
this.eachCombat = eachCombat;
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
staticText = filter.getMessage() + " attack " + (eachCombat ? "each combat" : "this turn") + " if able";
|
||||
} else {
|
||||
staticText = filter.getMessage() + " attack each " + (eachCombat ? "combat" : "turn") + " if able";
|
||||
}
|
||||
}
|
||||
|
||||
public AttacksIfAbleAllEffect(final AttacksIfAbleAllEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.eachCombat = effect.eachCombat;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +55,14 @@ public class AttacksIfAbleAllEffect extends RequirementEffect {
|
|||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) {
|
||||
if (eachCombat) {
|
||||
return true;
|
||||
}
|
||||
AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get("AttackedThisTurn");
|
||||
return watcher != null && !watcher.getAttackedThisTurnCreatures().contains(permanent.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,13 +25,12 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.constants.Duration;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
|
@ -56,10 +55,7 @@ public class AttacksIfAbleTargetEffect extends RequirementEffect {
|
|||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (this.getTargetPointer().getTargets(game, source).contains(permanent.getId())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this.getTargetPointer().getTargets(game, source).contains(permanent.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,8 +75,7 @@ public class AttacksIfAbleTargetEffect extends RequirementEffect {
|
|||
}
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
return new StringBuilder("Target ").append(mode.getTargets().get(0).getTargetName()).append(" attacks this turn if able").toString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new StringBuilder("Target ").append(mode.getTargets().get(0).getTargetName()).append(" attacks each turn if able").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,10 @@ public abstract class ExpansionSet implements Serializable {
|
|||
protected String blockName;
|
||||
protected boolean hasBoosters = false;
|
||||
protected int numBoosterSpecial;
|
||||
|
||||
protected int numBoosterLands;
|
||||
protected int ratioBoosterSpecialLand = 0; // if > 0 basic lands are replaced with speical land in the ratio every X land is replaced by special land
|
||||
|
||||
protected int numBoosterCommon;
|
||||
protected int numBoosterUncommon;
|
||||
protected int numBoosterRare;
|
||||
|
@ -150,9 +153,14 @@ public abstract class ExpansionSet implements Serializable {
|
|||
}
|
||||
|
||||
if (numBoosterLands > 0) {
|
||||
List<CardInfo> specialLands = getSpecialLand();
|
||||
List<CardInfo> basicLands = getCardsByRarity(Rarity.LAND);
|
||||
for (int i = 0; i < numBoosterLands; i++) {
|
||||
addToBooster(booster, basicLands);
|
||||
if (ratioBoosterSpecialLand > 0 && rnd.nextInt(ratioBoosterSpecialLand) == 1 && specialLands != null) {
|
||||
addToBooster(booster, specialLands);
|
||||
} else {
|
||||
addToBooster(booster, basicLands);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<CardInfo> commons = getCardsByRarity(Rarity.COMMON);
|
||||
|
@ -320,6 +328,10 @@ public abstract class ExpansionSet implements Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public List<CardInfo> getSpecialLand() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeSavedCards() {
|
||||
savedCards.clear();
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public enum CardRepository {
|
|||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 41;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 37;
|
||||
private static final long CARD_CONTENT_VERSION = 38;
|
||||
|
||||
private final Random random = new Random();
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
|
@ -20,14 +20,14 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import java.util.Random;
|
||||
import mage.MageInt;
|
||||
import mage.Mana;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
|
@ -49,7 +49,24 @@ public class EldraziScionToken extends Token {
|
|||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana, new SacrificeSourceCost()));
|
||||
this.setOriginalExpansionSetCode("BFZ");
|
||||
setOriginalExpansionSetCode("BFZ");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpansionSetCodeForImage(String code) {
|
||||
super.setExpansionSetCodeForImage(code);
|
||||
if (getOriginalExpansionSetCode().equals("BFZ")) {
|
||||
this.setTokenType(new Random().nextInt(3) + 1); // 3 different images
|
||||
}
|
||||
}
|
||||
|
||||
public EldraziScionToken(final EldraziScionToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EldraziScionToken copy() {
|
||||
return new EldraziScionToken(this); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,6 +171,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
int index = 0;
|
||||
result = false;
|
||||
boolean legalParts = false;
|
||||
boolean notTargeted = true;
|
||||
// check for legal parts
|
||||
for (SpellAbility spellAbility : this.spellAbilities) {
|
||||
// if muliple modes are selected, and there are modes with targets, then at least one mode has to have a legal target or
|
||||
|
@ -178,10 +179,15 @@ public class Spell extends StackObjImpl implements Card {
|
|||
// If all targets are illegal when the spell tries to resolve, the spell is countered and none of its effects happen.
|
||||
// If at least one target is still legal at that time, the spell resolves, but an illegal target can't perform any actions
|
||||
// or have any actions performed on it.
|
||||
legalParts |= spellAbilityHasLegalParts(spellAbility, game);
|
||||
// if only a spliced spell has targets and all targets ar illegal, the complete spell is countered
|
||||
if (hasTargets(spellAbility, game)) {
|
||||
notTargeted = false;
|
||||
legalParts |= spellAbilityHasLegalParts(spellAbility, game);
|
||||
}
|
||||
|
||||
}
|
||||
// resolve if legal parts
|
||||
if (legalParts) {
|
||||
if (notTargeted || legalParts) {
|
||||
for (SpellAbility spellAbility : this.spellAbilities) {
|
||||
if (spellAbilityHasLegalParts(spellAbility, game)) {
|
||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
||||
|
@ -262,6 +268,21 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean hasTargets(SpellAbility spellAbility, Game game) {
|
||||
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
||||
spellAbility.getModes().setActiveMode(modeId);
|
||||
if (!spellAbility.getTargets().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return !spellAbility.getTargets().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean spellAbilityHasLegalParts(SpellAbility spellAbility, Game game) {
|
||||
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
||||
boolean targetedMode = false;
|
||||
|
|
|
@ -2927,7 +2927,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Set<Card> cardList = new HashSet<>();
|
||||
for (UUID cardId : cards) {
|
||||
fromZone = game.getState().getZone(cardId);
|
||||
if (fromZone.equals(Zone.BATTLEFIELD)) {
|
||||
if (Zone.BATTLEFIELD.equals(fromZone)) {
|
||||
Permanent permanent = game.getPermanent(cardId);
|
||||
if (permanent != null) {
|
||||
cardList.add(permanent);
|
||||
|
|
|
@ -117,13 +117,15 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
if (permanent != null) {
|
||||
if (source != null) {
|
||||
MageObject targetSource = game.getObject(source.getSourceId());
|
||||
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game)
|
||||
&& filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
} else {
|
||||
return filter.match(permanent, game);
|
||||
}
|
||||
}
|
||||
Spell spell = game.getStack().getSpell(id);
|
||||
if (spell != null) {
|
||||
if (spell != null
|
||||
&& !source.getSourceId().equals(id)) { // 114.4. A spell or ability on the stack is an illegal target for itself.
|
||||
return filter.match(spell, game);
|
||||
}
|
||||
return false;
|
||||
|
@ -151,7 +153,9 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, sourceId, sourceControllerId, game)) {
|
||||
if (spell != null
|
||||
&& !sourceId.equals(spell.getSourceId())
|
||||
&& filter.match(spell, sourceId, sourceControllerId, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -184,7 +188,8 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
int count = 0;
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
if (spell != null
|
||||
&& filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -208,7 +213,9 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
if (spell != null
|
||||
&& !sourceId.equals(spell.getSourceId())
|
||||
&& filter.match(spell, sourceId, sourceControllerId, game)) {
|
||||
possibleTargets.add(spell.getId());
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +232,8 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
if (spell != null
|
||||
&& filter.match(spell, null, sourceControllerId, game)) {
|
||||
possibleTargets.add(spell.getId());
|
||||
}
|
||||
}
|
||||
|
|
55265
Utils/mtg-cards-data.txt
55265
Utils/mtg-cards-data.txt
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue