mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
Merge remote-tracking branch 'fork/master'
This commit is contained in:
commit
f309717616
131 changed files with 1655 additions and 755 deletions
|
@ -1057,6 +1057,12 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
this.tablesPane.hideTables();
|
||||
}
|
||||
|
||||
public void setTableFilter() {
|
||||
if (this.tablesPane != null) {
|
||||
this.tablesPane.setTableFilter();
|
||||
}
|
||||
}
|
||||
|
||||
public void showGames(boolean setActive) {
|
||||
MagePane topPanebefore = getTopMost(tablesPane);
|
||||
if (!tablesPane.isVisible()) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.client.chat.LocalCommands;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.PlayerAction;
|
||||
import mage.game.match.MatchOptions;
|
||||
|
@ -306,7 +307,11 @@ public class SessionHandler {
|
|||
}
|
||||
|
||||
public static boolean sendChatMessage(UUID chatId, String text) {
|
||||
if (!LocalCommands.handleLocalCommands(chatId, text)) {
|
||||
return session.sendChatMessage(chatId, text);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) {
|
||||
|
|
|
@ -271,8 +271,8 @@ public class ChatPanelBasic extends javax.swing.JPanel {
|
|||
if (color.equals(MessageColor.YELLOW)) {
|
||||
textColor = "Yellow";
|
||||
}
|
||||
if (messageType == MessageType.WHISPER) {
|
||||
if (username.equalsIgnoreCase("Whisper from " + SessionHandler.getUserName())) {
|
||||
if (messageType == MessageType.WHISPER_FROM) {
|
||||
if (username.equalsIgnoreCase(SessionHandler.getUserName())) {
|
||||
if (message.toLowerCase().startsWith("profanity 0")) {
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0");
|
||||
} else if (message.toLowerCase().startsWith("profanity 1")) {
|
||||
|
@ -281,6 +281,10 @@ public class ChatPanelBasic extends javax.swing.JPanel {
|
|||
PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "2");
|
||||
}
|
||||
}
|
||||
username = "Whisper from " + username;
|
||||
}
|
||||
if (messageType == MessageType.WHISPER_TO) {
|
||||
username = "Whisper to " + username;
|
||||
}
|
||||
|
||||
Matcher matchPattern = cardNamePattern.matcher(message);
|
||||
|
|
|
@ -57,7 +57,8 @@ public class ChatPanelSeparated extends ChatPanelBasic {
|
|||
public void receiveMessage(String username, String message, String time, ChatMessage.MessageType messageType, ChatMessage.MessageColor color) {
|
||||
switch (messageType) {
|
||||
case TALK:
|
||||
case WHISPER:
|
||||
case WHISPER_TO:
|
||||
case WHISPER_FROM:
|
||||
case USER_INFO:
|
||||
super.receiveMessage(username, message, time, messageType, color);
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package mage.client.chat;
|
||||
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.util.IgnoreList;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.view.ChatMessage;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LocalCommands {
|
||||
|
||||
private static final DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT);
|
||||
|
||||
/**
|
||||
* Handler for commands that do not require server interaction, i.e settings etc
|
||||
* @param chatId
|
||||
* @param text
|
||||
* @return true if the command was handled locally, else false
|
||||
*/
|
||||
public static boolean handleLocalCommands(UUID chatId, String text) {
|
||||
final StringTokenizer st = new StringTokenizer(text.trim());
|
||||
final int tokens = st.countTokens();
|
||||
if (tokens == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
|
||||
Optional<String> response = Optional.empty();
|
||||
|
||||
switch (st.nextToken()) {
|
||||
case "/ignore":
|
||||
case "\\ignore":
|
||||
final String ignoreTarget = tokens > 1 ? st.nextToken() : "";
|
||||
response = Optional.of(IgnoreList.ignore(serverAddress, ignoreTarget));
|
||||
break;
|
||||
case "/unignore":
|
||||
case "\\unignore":
|
||||
final String unignoreTarget = tokens > 1 ? st.nextToken() : "";
|
||||
response = Optional.of(IgnoreList.unignore(serverAddress, unignoreTarget));
|
||||
break;
|
||||
// TODO: move profanity settings to here
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.isPresent()) {
|
||||
displayLocalCommandResponse(chatId, response.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void displayLocalCommandResponse(UUID chatId, String response) {
|
||||
final String text = new StringBuilder().append("<font color=yellow>").append(response).append("</font>").toString();
|
||||
ClientCallback chatMessage = new ClientCallback("chatMessage", chatId,
|
||||
new ChatMessage("", text, timeFormatter.format(new Date()), ChatMessage.MessageColor.BLUE));
|
||||
MageFrame.getInstance().processCallback(chatMessage);
|
||||
}
|
||||
}
|
|
@ -41,6 +41,7 @@ import mage.client.SessionHandler;
|
|||
import mage.client.components.MageComponents;
|
||||
import mage.client.table.TablePlayerPanel;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.IgnoreList;
|
||||
import mage.client.util.Listener;
|
||||
import mage.constants.MatchTimeLimit;
|
||||
import mage.constants.MultiplayerAttackOption;
|
||||
|
@ -386,6 +387,8 @@ public class NewTableDialog extends MageDialog {
|
|||
options.setPassword(this.txtPassword.getText());
|
||||
options.setQuitRatio((Integer) this.spnQuitRatio.getValue());
|
||||
options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue());
|
||||
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
|
||||
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
|
||||
if (!checkMatchOptions(options)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package mage.client.preference;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import mage.client.MageFrame;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.prefs.BackingStoreException;
|
||||
import java.util.prefs.Preferences;
|
||||
import mage.client.MageFrame;
|
||||
|
||||
// TODO: Move all preference related logic from MageFrame and PreferencesDialog to this class.
|
||||
public class MagePreferences {
|
||||
|
@ -14,6 +17,8 @@ public class MagePreferences {
|
|||
private static final String KEY_EMAIL = "email";
|
||||
private static final String KEY_AUTO_CONNECT = "autoConnect";
|
||||
|
||||
private static final String NODE_KEY_IGNORE_LIST = "ignoreListString";
|
||||
|
||||
private static Preferences prefs() {
|
||||
// TODO: Move MageFrame.prefs to this class.
|
||||
return MageFrame.getPreferences();
|
||||
|
@ -98,4 +103,36 @@ public class MagePreferences {
|
|||
public static void setAutoConnect(boolean autoConnect) {
|
||||
prefs().putBoolean(KEY_AUTO_CONNECT, autoConnect);
|
||||
}
|
||||
|
||||
public static void addIgnoredUser(String serverAddress, String username) {
|
||||
ignoreListNode(serverAddress).putBoolean(username, true);
|
||||
}
|
||||
|
||||
public static boolean removeIgnoredUser(String serverAddress, String username) {
|
||||
Preferences ignoreList = ignoreListNode(serverAddress);
|
||||
boolean exists = ignoreList.getBoolean(username, false);
|
||||
if (exists) {
|
||||
ignoreList.remove(username);
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
public static Set<String> ignoreList(String serverAddress) {
|
||||
try {
|
||||
return Sets.newHashSet(ignoreListNode(serverAddress).keys());
|
||||
} catch (BackingStoreException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Sets.newHashSet();
|
||||
}
|
||||
|
||||
public static void clearIgnoreList(String serverAddress) throws BackingStoreException {
|
||||
ignoreListNode(serverAddress).clear();
|
||||
}
|
||||
|
||||
private static Preferences ignoreListNode(String serverAddress) {
|
||||
return prefs().node(NODE_KEY_IGNORE_LIST).node(serverAddress);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import javax.swing.JOptionPane;
|
|||
import javax.swing.SwingUtilities;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.chat.ChatPanelBasic;
|
||||
import mage.client.constants.Constants.DeckEditorMode;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
|
@ -42,6 +43,7 @@ import mage.client.game.GamePanel;
|
|||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.DeckUtil;
|
||||
import mage.client.util.GameManager;
|
||||
import mage.client.util.IgnoreList;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
import mage.client.util.object.SaveObjectUtil;
|
||||
import mage.interfaces.callback.CallbackClient;
|
||||
|
@ -110,6 +112,15 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
break;
|
||||
case "chatMessage": {
|
||||
ChatMessage message = (ChatMessage) callback.getData();
|
||||
|
||||
// Drop messages from ignored users
|
||||
if (message.getUsername() != null && IgnoreList.IGNORED_MESSAGE_TYPES.contains(message.getMessageType())) {
|
||||
final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
|
||||
if (IgnoreList.userIsIgnored(serverAddress, message.getUsername())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChatPanelBasic panel = MageFrame.getChat(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
// play the sound related to the message
|
||||
|
@ -422,6 +433,7 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" menu to the top right .")
|
||||
.append("<br/>Download icons and symbols by using the \"Symbols\" menu to the top right.")
|
||||
.append("<br/>\\list - Show a list of available chat commands.")
|
||||
.append("<br/>").append(IgnoreList.usage())
|
||||
.append("<br/>Type <font color=green>\\w yourUserName profanity 0 (or 1 or 2)</font> to turn off/on the profanity filter").toString(),
|
||||
null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE);
|
||||
break;
|
||||
|
|
|
@ -140,4 +140,10 @@ public class TablesPane extends MagePane {
|
|||
public void deactivated() {
|
||||
tablesPanel.stopTasks();
|
||||
}
|
||||
|
||||
public void setTableFilter() {
|
||||
if (tablesPanel != null) {
|
||||
tablesPanel.setTableFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -85,6 +86,7 @@ import mage.client.dialog.TableWaitingDialog;
|
|||
import static mage.client.table.TablesPanel.PASSWORDED;
|
||||
import mage.client.util.ButtonColumn;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.IgnoreList;
|
||||
import mage.client.util.MageTableRowSorter;
|
||||
import mage.client.util.gui.GuiDisplayUtil;
|
||||
import mage.client.util.gui.TableUtil;
|
||||
|
@ -550,7 +552,7 @@ public class TablesPanel extends javax.swing.JPanel {
|
|||
return chatPanelMain.getUserChatPanel();
|
||||
}
|
||||
|
||||
private void setTableFilter() {
|
||||
public void setTableFilter() {
|
||||
// state
|
||||
List<RowFilter<Object, Object>> stateFilterList = new ArrayList<>();
|
||||
if (btnStateWaiting.isSelected()) {
|
||||
|
@ -630,6 +632,20 @@ public class TablesPanel extends javax.swing.JPanel {
|
|||
passwordFilterList.add(RowFilter.regexFilter("^\\*\\*\\*$", TableTableModel.COLUMN_PASSWORD));
|
||||
}
|
||||
|
||||
// Hide games of ignored players
|
||||
List<RowFilter<Object, Object>> ignoreListFilterList = new ArrayList<>();
|
||||
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
|
||||
final Set<String> ignoreListCopy = IgnoreList.ignoreList(serverAddress);
|
||||
if (ignoreListCopy.size() > 0) {
|
||||
ignoreListFilterList.add(new RowFilter<Object, Object>() {
|
||||
@Override
|
||||
public boolean include(Entry<? extends Object, ? extends Object> entry) {
|
||||
final String owner = entry.getStringValue(TableTableModel.COLUMN_OWNER);
|
||||
return !ignoreListCopy.contains(owner);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty()
|
||||
|| skillFilterList.isEmpty() || ratingFilterList.isEmpty()
|
||||
|| passwordFilterList.isEmpty()) { // no selection
|
||||
|
@ -673,6 +689,12 @@ public class TablesPanel extends javax.swing.JPanel {
|
|||
filterList.addAll(passwordFilterList);
|
||||
}
|
||||
|
||||
if (ignoreListFilterList.size() > 1) {
|
||||
filterList.add(RowFilter.orFilter(ignoreListFilterList));
|
||||
} else if (ignoreListFilterList.size() == 1) {
|
||||
filterList.addAll(ignoreListFilterList);
|
||||
}
|
||||
|
||||
if (filterList.size() == 1) {
|
||||
activeTablesSorter.setRowFilter(filterList.get(0));
|
||||
} else {
|
||||
|
@ -1177,6 +1199,8 @@ public class TablesPanel extends javax.swing.JPanel {
|
|||
options.setSkillLevel(SkillLevel.CASUAL);
|
||||
options.setRollbackTurnsAllowed(true);
|
||||
options.setQuitRatio(100);
|
||||
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
|
||||
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
|
||||
table = SessionHandler.createTable(roomId, options);
|
||||
|
||||
SessionHandler.joinTable(roomId, table.getTableId(), "Human", "Human", 1, DeckImporterUtil.importDeck("test.dck"), "");
|
||||
|
|
98
Mage.Client/src/main/java/mage/client/util/IgnoreList.java
Normal file
98
Mage.Client/src/main/java/mage/client/util/IgnoreList.java
Normal file
|
@ -0,0 +1,98 @@
|
|||
package mage.client.util;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.preference.MagePreferences;
|
||||
import mage.view.ChatMessage;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
public class IgnoreList {
|
||||
|
||||
private static final String USAGE = "<br/><font color=yellow>\\ignore - shows current ignore list on this server."
|
||||
+ "<br/>\\ignore [username] - add a username to your ignore list on this server."
|
||||
+ "<br/>\\unignore [username] - remove a username from your ignore list on this server.</font>";
|
||||
|
||||
public static final int MAX_IGNORE_LIST_SIZE = 50;
|
||||
public static Set<ChatMessage.MessageType> IGNORED_MESSAGE_TYPES =
|
||||
ImmutableSet.of(ChatMessage.MessageType.TALK,
|
||||
ChatMessage.MessageType.WHISPER_FROM);
|
||||
|
||||
public static String usage() {
|
||||
return USAGE;
|
||||
}
|
||||
|
||||
public static Set<String> ignoreList(String serverAddress) {
|
||||
return MagePreferences.ignoreList(serverAddress);
|
||||
}
|
||||
|
||||
public static String ignoreListString(String serverAddress) {
|
||||
final String[] list = MagePreferences.ignoreList(serverAddress).toArray(new String[0]);
|
||||
Arrays.sort(list);
|
||||
return "<font color=yellow>Current ignore list on " + serverAddress + ": "
|
||||
+ Arrays.toString(list)
|
||||
+ "</font>";
|
||||
}
|
||||
|
||||
public static String ignore(String serverAddress, String user) {
|
||||
if (user == null || user.length() == 0) {
|
||||
return ignoreListString(serverAddress);
|
||||
}
|
||||
|
||||
if (MagePreferences.ignoreList(serverAddress).size() >= MAX_IGNORE_LIST_SIZE) {
|
||||
return "Your ignore list is too big, remove a user to be able to add a new one.";
|
||||
}
|
||||
|
||||
if (userIsIgnored(serverAddress, user)) {
|
||||
return new StringBuilder()
|
||||
.append(user)
|
||||
.append(" is already on your ignore list on ")
|
||||
.append(serverAddress)
|
||||
.toString();
|
||||
}
|
||||
|
||||
MagePreferences.addIgnoredUser(serverAddress, user);
|
||||
updateTablesTable();
|
||||
|
||||
return new StringBuilder()
|
||||
.append("Added ")
|
||||
.append(user)
|
||||
.append(" to your ignore list on ")
|
||||
.append(serverAddress)
|
||||
.toString();
|
||||
}
|
||||
|
||||
private static void updateTablesTable() {
|
||||
MageFrame mageFrame = MageFrame.getInstance();
|
||||
if (mageFrame != null) {
|
||||
mageFrame.setTableFilter();
|
||||
}
|
||||
}
|
||||
|
||||
public static String unignore(String serverAddress, String user) {
|
||||
if (user == null || user.length() == 0) {
|
||||
return usage();
|
||||
}
|
||||
if (MagePreferences.removeIgnoredUser(serverAddress, user)) {
|
||||
updateTablesTable();
|
||||
return new StringBuilder()
|
||||
.append("Removed ")
|
||||
.append(user)
|
||||
.append(" from your ignore list on ")
|
||||
.append(serverAddress)
|
||||
.toString();
|
||||
} else {
|
||||
return new StringBuilder()
|
||||
.append("No such user \"")
|
||||
.append(user)
|
||||
.append("\" on your ignore list on ")
|
||||
.append(serverAddress)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean userIsIgnored(String serverAddress, String username) {
|
||||
return MagePreferences.ignoreList(serverAddress).contains(username);
|
||||
}
|
||||
}
|
|
@ -68,7 +68,7 @@ public class TransformedImageCache {
|
|||
}
|
||||
}
|
||||
|
||||
static final Map<Key, Map<BufferedImage, BufferedImage>> IMAGE_CACHE;
|
||||
private static final Map<Key, Map<BufferedImage, BufferedImage>> IMAGE_CACHE;
|
||||
|
||||
static {
|
||||
// TODO: can we use a single map?
|
||||
|
@ -85,17 +85,17 @@ public class TransformedImageCache {
|
|||
|
||||
private static BufferedImage rotateImage(BufferedImage image, double angle) {
|
||||
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
|
||||
int w = image.getWidth(), h = image.getHeight();
|
||||
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
|
||||
int width = image.getWidth(), height = image.getHeight();
|
||||
int newWidth = (int) Math.floor(width * cos + height * sin), newHeight = (int) Math.floor(height * cos + width * sin);
|
||||
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice gs = ge.getDefaultScreenDevice();
|
||||
GraphicsConfiguration gc = gs.getDefaultConfiguration();
|
||||
|
||||
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
|
||||
BufferedImage result = gc.createCompatibleImage(newWidth, newHeight, Transparency.TRANSLUCENT);
|
||||
Graphics2D g = result.createGraphics();
|
||||
g.translate((neww - w) / 2, (newh - h) / 2);
|
||||
g.rotate(angle, w / 2, h / 2);
|
||||
g.translate((newWidth - width) / 2, (newHeight - height) / 2);
|
||||
g.rotate(angle, width / 2, height / 2);
|
||||
g.drawRenderedImage(image, null);
|
||||
g.dispose();
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package mage.client.preference;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class MagePreferencesTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MagePreferences.ignoreList("test.com.xx").clear();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
MagePreferences.ignoreList("test.com.xx").clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreList() throws Exception {
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(0));
|
||||
assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "test"), is(false));
|
||||
|
||||
MagePreferences.addIgnoredUser("test.com.xx", "test");
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(1));
|
||||
assertThat(MagePreferences.ignoreList("other.com.xx").size(), is(0));
|
||||
|
||||
MagePreferences.addIgnoredUser("test.com.xx", "lul");
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(2));
|
||||
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").contains("test"), is(true));
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").contains("lul"), is(true));
|
||||
|
||||
assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "test"), is(true));
|
||||
assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "test"), is(false));
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(1));
|
||||
|
||||
assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "lul"), is(true));
|
||||
assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "lul"), is(false));
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(0));
|
||||
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").contains("test"), is(false));
|
||||
assertThat(MagePreferences.ignoreList("test.com.xx").contains("lul"), is(false));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package mage.client.util;
|
||||
|
||||
import mage.client.preference.MagePreferences;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
public class IgnoreListTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MagePreferences.clearIgnoreList("test.com.xx");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
MagePreferences.clearIgnoreList("test.com.xx");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreListEmpty() throws Exception {
|
||||
assertThat(IgnoreList.ignoreListString("test.com.xx"), is("<font color=yellow>Current ignore list on test.com.xx: []</font>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreList() throws Exception {
|
||||
final String test = IgnoreList.ignore("test.com.xx", "test");
|
||||
final String kranken = IgnoreList.ignore("test.com.xx", "kranken");
|
||||
assertThat(IgnoreList.ignoreListString("test.com.xx"), is("<font color=yellow>Current ignore list on test.com.xx: [kranken, test]</font>"));
|
||||
assertThat(test, is("Added test to your ignore list on test.com.xx"));
|
||||
assertThat(kranken, is("Added kranken to your ignore list on test.com.xx"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignore() throws Exception {
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false));
|
||||
final String r = IgnoreList.ignore("test.com.xx", "kranken");
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(true));
|
||||
assertEquals(r, "Added kranken to your ignore list on test.com.xx");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreAgain() throws Exception {
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false));
|
||||
IgnoreList.ignore("test.com.xx", "kranken");
|
||||
final String r = IgnoreList.ignore("test.com.xx", "kranken");
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(true));
|
||||
assertEquals(r, "kranken is already on your ignore list on test.com.xx");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreDefaultResponse() throws Exception {
|
||||
final String r1 = IgnoreList.ignore("test.com.xx", "");
|
||||
final String r2 = IgnoreList.ignore("test.com.xx", null);
|
||||
assertThat(IgnoreList.ignoreListString("test.com.xx"), is("<font color=yellow>Current ignore list on test.com.xx: []</font>"));
|
||||
assertEquals(r1, r2);
|
||||
assertEquals(r2, "<font color=yellow>Current ignore list on test.com.xx: []</font>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreMaxSize() throws Exception {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
IgnoreList.ignore("test.com.xx", "" + i);
|
||||
}
|
||||
final String r = IgnoreList.ignore("test.com.xx", "lul");
|
||||
assertEquals(r, "Your ignore list is too big, remove a user to be able to add a new one.");
|
||||
assertThat(IgnoreList.ignoreListString("test.com.xx"), is("<font color=yellow>Current ignore list on test.com.xx: [0, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 4, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 5, 6, 7, 8, 9]</font>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unignore() throws Exception {
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false));
|
||||
IgnoreList.ignore("test.com.xx", "kranken");
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(true));
|
||||
final String r = IgnoreList.unignore("test.com.xx", "kranken");
|
||||
assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false));
|
||||
assertEquals(r, "Removed kranken from your ignore list on test.com.xx");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -244,6 +244,10 @@ public class SessionImpl implements Session {
|
|||
});
|
||||
}
|
||||
|
||||
public Optional<String> getServerHostname() {
|
||||
return isConnected() ? Optional.of(connection.getHost()) : Optional.<String>empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopConnecting() {
|
||||
canceled = true;
|
||||
|
@ -960,6 +964,8 @@ public class SessionImpl implements Session {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean joinGame(UUID gameId) {
|
||||
try {
|
||||
|
|
|
@ -29,6 +29,8 @@ package mage.remote.interfaces;
|
|||
|
||||
import mage.remote.Connection;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
*/
|
||||
|
@ -52,6 +54,8 @@ public interface Connect {
|
|||
|
||||
boolean isConnected();
|
||||
|
||||
Optional<String> getServerHostname();
|
||||
|
||||
boolean disconnectUser(String userSessionId);
|
||||
|
||||
boolean endUserSession(String userSessionId);
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ChatMessage implements Serializable {
|
|||
}
|
||||
|
||||
public enum MessageType {
|
||||
USER_INFO, STATUS, GAME, TALK, WHISPER
|
||||
USER_INFO, STATUS, GAME, TALK, WHISPER_FROM, WHISPER_TO
|
||||
}
|
||||
|
||||
public enum SoundToPlay {
|
||||
|
|
|
@ -133,6 +133,10 @@ public class ChatManager {
|
|||
return;
|
||||
}
|
||||
|
||||
if (message.length() > 500) {
|
||||
message = message.replaceFirst("^(.{500}).*", "$1 (rest of message truncated)");
|
||||
}
|
||||
|
||||
String messageToCheck = message;
|
||||
Matcher matchPattern = cardNamePattern.matcher(message);
|
||||
while (matchPattern.find()) {
|
||||
|
@ -186,7 +190,10 @@ public class ChatManager {
|
|||
+ "<br/>\\me - shows the history of the current player"
|
||||
+ "<br/>\\list or \\l - Show a list of commands"
|
||||
+ "<br/>\\whisper or \\w [player name] [text] - whisper to the player with the given name"
|
||||
+ "<br/>[Card Name] - Show a highlighted card name";
|
||||
+ "<br/>[Card Name] - Show a highlighted card name"
|
||||
+ "<br/>\\ignore - shows current ignore list on this server."
|
||||
+ "<br/>\\ignore [username] - add a username to your ignore list on this server."
|
||||
+ "<br/>\\unignore [username] - remove a username from your ignore list on this server.";
|
||||
|
||||
private boolean performUserCommand(User user, String message, UUID chatId, boolean doError) {
|
||||
String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH);
|
||||
|
|
|
@ -127,10 +127,10 @@ public class ChatSession {
|
|||
public boolean broadcastWhisperToUser(User fromUser, User toUser, String message) {
|
||||
if (clients.containsKey(toUser.getId())) {
|
||||
toUser.fireCallback(new ClientCallback("chatMessage", chatId,
|
||||
new ChatMessage(new StringBuilder("Whisper from ").append(fromUser.getName()).toString(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER, SoundToPlay.PlayerWhispered)));
|
||||
new ChatMessage(fromUser.getName(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER_FROM, SoundToPlay.PlayerWhispered)));
|
||||
if (clients.containsKey(fromUser.getId())) {
|
||||
fromUser.fireCallback(new ClientCallback("chatMessage", chatId,
|
||||
new ChatMessage(new StringBuilder("Whisper to ").append(toUser.getName()).toString(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER, null)));
|
||||
new ChatMessage(toUser.getName(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER_TO, null)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,14 +27,6 @@
|
|||
*/
|
||||
package mage.server;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import mage.MageException;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
|
@ -68,6 +60,15 @@ import mage.server.util.ThreadExecutor;
|
|||
import mage.view.ChatMessage;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -99,7 +100,7 @@ public class TableController {
|
|||
} else {
|
||||
controllerName = "System";
|
||||
}
|
||||
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match);
|
||||
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match, options.getBannedUsers());
|
||||
chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId());
|
||||
init();
|
||||
}
|
||||
|
@ -118,7 +119,7 @@ public class TableController {
|
|||
} else {
|
||||
controllerName = "System";
|
||||
}
|
||||
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament);
|
||||
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament, options.getMatchOptions().getBannedUsers());
|
||||
chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId());
|
||||
}
|
||||
|
||||
|
@ -195,8 +196,9 @@ public class TableController {
|
|||
return false;
|
||||
}
|
||||
|
||||
Player player = createPlayer(name, seat.getPlayerType(), skill);
|
||||
if (player != null) {
|
||||
Optional<Player> playerOptional = createPlayer(name, seat.getPlayerType(), skill);
|
||||
if (playerOptional.isPresent()) {
|
||||
Player player = playerOptional.get();
|
||||
if (!player.canJoinTable(table)) {
|
||||
user.showUserMessage("Join Table", new StringBuilder("A ").append(seat.getPlayerType()).append(" player can't join this table.").toString());
|
||||
return false;
|
||||
|
@ -227,10 +229,11 @@ public class TableController {
|
|||
}
|
||||
|
||||
public synchronized boolean replaceDraftPlayer(Player oldPlayer, String name, String playerType, int skill) {
|
||||
Player newPlayer = createPlayer(name, playerType, skill);
|
||||
if (newPlayer == null || table.getState() != TableState.DRAFTING) {
|
||||
Optional<Player> newPlayerOpt = createPlayer(name, playerType, skill);
|
||||
if (!newPlayerOpt.isPresent() || table.getState() != TableState.DRAFTING) {
|
||||
return false;
|
||||
}
|
||||
Player newPlayer = newPlayerOpt.get();
|
||||
TournamentPlayer oldTournamentPlayer = tournament.getPlayer(oldPlayer.getId());
|
||||
tournament.removePlayer(oldPlayer.getId());
|
||||
tournament.addPlayer(newPlayer, playerType);
|
||||
|
@ -306,13 +309,14 @@ public class TableController {
|
|||
}
|
||||
}
|
||||
|
||||
Player player = createPlayer(name, seat.getPlayerType(), skill);
|
||||
if (player == null) {
|
||||
Optional<Player> playerOpt = createPlayer(name, seat.getPlayerType(), skill);
|
||||
if (!playerOpt.isPresent()) {
|
||||
String message = new StringBuilder("Could not create player ").append(name).append(" of type ").append(seat.getPlayerType()).toString();
|
||||
logger.warn(new StringBuilder("User: ").append(user.getName()).append(" => ").append(message).toString());
|
||||
user.showUserMessage("Join Table", message);
|
||||
return false;
|
||||
}
|
||||
Player player = playerOpt.get();
|
||||
logger.debug("DECK validated: " + table.getValidator().getName() + ' ' + player.getName() + ' ' + deck.getName());
|
||||
if (!player.canJoinTable(table)) {
|
||||
user.showUserMessage("Join Table", new StringBuilder("A ").append(seat.getPlayerType()).append(" player can't join this table.").toString());
|
||||
|
@ -443,17 +447,18 @@ public class TableController {
|
|||
// ReplayManager.getInstance().replayGame(table.getId(), userId);
|
||||
// return true;
|
||||
// }
|
||||
private Player createPlayer(String name, String playerType, int skill) {
|
||||
Player player;
|
||||
private Optional<Player> createPlayer(String name, String playerType, int skill) {
|
||||
Optional<Player> playerOpt;
|
||||
if (options == null) {
|
||||
player = PlayerFactory.getInstance().createPlayer(playerType, name, RangeOfInfluence.ALL, skill);
|
||||
playerOpt = PlayerFactory.getInstance().createPlayer(playerType, name, RangeOfInfluence.ALL, skill);
|
||||
} else {
|
||||
player = PlayerFactory.getInstance().createPlayer(playerType, name, options.getRange(), skill);
|
||||
playerOpt = PlayerFactory.getInstance().createPlayer(playerType, name, options.getRange(), skill);
|
||||
}
|
||||
if (player != null) {
|
||||
if (playerOpt.isPresent()) {
|
||||
Player player = playerOpt.get();
|
||||
logger.trace("Player " + player.getName() + " created id: " + player.getId());
|
||||
}
|
||||
return player;
|
||||
return playerOpt;
|
||||
}
|
||||
|
||||
public void leaveTableAll() {
|
||||
|
|
|
@ -28,14 +28,16 @@
|
|||
|
||||
package mage.server.game;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import mage.constants.RangeOfInfluence;
|
||||
import mage.players.Player;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -53,14 +55,14 @@ public class PlayerFactory {
|
|||
|
||||
private PlayerFactory() {}
|
||||
|
||||
public Player createPlayer(String playerType, String name, RangeOfInfluence range, int skill) {
|
||||
public Optional<Player> createPlayer(String playerType, String name, RangeOfInfluence range, int skill) {
|
||||
try {
|
||||
Class playerTypeClass = playerTypes.get(playerType);
|
||||
if (playerTypeClass != null) {
|
||||
Constructor<?> con = playerTypeClass.getConstructor(String.class, RangeOfInfluence.class, int.class);
|
||||
Player player = (Player) con.newInstance(name, range, skill);
|
||||
logger.trace("Player created: " + name + " - " + player.getId());
|
||||
return player;
|
||||
return Optional.of(player);
|
||||
}
|
||||
else {
|
||||
logger.fatal("Unknown player type: " + playerType);
|
||||
|
@ -68,7 +70,7 @@ public class PlayerFactory {
|
|||
} catch (Exception ex) {
|
||||
logger.fatal("PlayerFactory error ", ex);
|
||||
}
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Set<String> getPlayerTypes() {
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
|
@ -41,6 +40,8 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.game.permanent.token.ServoToken;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
|
@ -62,7 +63,7 @@ public class AetherChaser extends CardImpl {
|
|||
this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2)));
|
||||
|
||||
// Whenever Aether Chaser attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.
|
||||
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false,
|
||||
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), true,
|
||||
"Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token."));
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,10 @@ class AshlingsPrerogativeIncorrectOddityEffect extends PermanentsEnterBattlefiel
|
|||
staticText = "Each creature without converted mana cost of the chosen value enters the battlefield tapped.";
|
||||
}
|
||||
|
||||
public AshlingsPrerogativeIncorrectOddityEffect(final AshlingsPrerogativeIncorrectOddityEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
int incorrectModResult;
|
||||
|
@ -101,6 +105,11 @@ class AshlingsPrerogativeIncorrectOddityEffect extends PermanentsEnterBattlefiel
|
|||
|
||||
return permanent != null && creaturefilter.match(permanent, game) && permanent.getConvertedManaCost() % 2 == incorrectModResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AshlingsPrerogativeIncorrectOddityEffect copy() {
|
||||
return new AshlingsPrerogativeIncorrectOddityEffect(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AshlingsPrerogativeCorrectOddityEffect extends GainAbilityAllEffect {
|
||||
|
@ -112,6 +121,9 @@ class AshlingsPrerogativeCorrectOddityEffect extends GainAbilityAllEffect {
|
|||
super(HasteAbility.getInstance(), Duration.WhileOnBattlefield, creaturefilter);
|
||||
staticText = "Each creature with converted mana cost of the chosen value has haste.";
|
||||
}
|
||||
public AshlingsPrerogativeCorrectOddityEffect(final AshlingsPrerogativeCorrectOddityEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean selectedByRuntimeData(Permanent permanent, Ability source, Game game) {
|
||||
|
@ -124,4 +136,8 @@ class AshlingsPrerogativeCorrectOddityEffect extends GainAbilityAllEffect {
|
|||
return permanent != null && creaturefilter.match(permanent, game) && permanent.getConvertedManaCost() % 2 == correctModResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AshlingsPrerogativeCorrectOddityEffect copy() {
|
||||
return new AshlingsPrerogativeCorrectOddityEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class CanopyCover extends CardImpl {
|
|||
private static final FilterObject filter = new FilterStackObject("spells or abilities your opponents control");
|
||||
|
||||
public CanopyCover(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}");
|
||||
this.subtype.add("Aura");
|
||||
|
||||
// Enchant creature
|
||||
|
@ -70,7 +70,7 @@ public class CanopyCover extends CardImpl {
|
|||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature can't be blocked except by creatures with flying or reach. (!this is a static ability of the enchantment)
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OrchardSpiritEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanopyCoverEffect()));
|
||||
|
||||
// Enchanted creature can't be the target of spells or abilities your opponents control.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedAttachedEffect(filter, Duration.WhileOnBattlefield, AttachmentType.AURA, TargetController.OPPONENT)));
|
||||
|
@ -86,14 +86,14 @@ public class CanopyCover extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class OrchardSpiritEffect extends RestrictionEffect {
|
||||
class CanopyCoverEffect extends RestrictionEffect {
|
||||
|
||||
public OrchardSpiritEffect() {
|
||||
public CanopyCoverEffect() {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
staticText = "Enchanted creature can't be blocked except by creatures with flying or reach";
|
||||
}
|
||||
|
||||
public OrchardSpiritEffect(final OrchardSpiritEffect effect) {
|
||||
public CanopyCoverEffect(final CanopyCoverEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ class OrchardSpiritEffect extends RestrictionEffect {
|
|||
Permanent equipment = game.getPermanent(source.getSourceId());
|
||||
if (equipment != null && equipment.getAttachedTo() != null) {
|
||||
Permanent equipped = game.getPermanent(equipment.getAttachedTo());
|
||||
if (permanent.getId().equals(equipped.getId())) {
|
||||
if (equipped != null && permanent.getId().equals(equipped.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ class OrchardSpiritEffect extends RestrictionEffect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public OrchardSpiritEffect copy() {
|
||||
return new OrchardSpiritEffect(this);
|
||||
public CanopyCoverEffect copy() {
|
||||
return new CanopyCoverEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ package mage.cards.c;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.LoyaltyAbility;
|
||||
|
@ -62,13 +63,12 @@ import mage.target.TargetPlayer;
|
|||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class ChandraPyromaster extends CardImpl {
|
||||
|
||||
public ChandraPyromaster(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{2}{R}{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}");
|
||||
this.subtype.add("Chandra");
|
||||
|
||||
this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4));
|
||||
|
@ -211,10 +211,12 @@ 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);
|
||||
if (!card.getManaCost().isEmpty()) {
|
||||
ContinuousEffect effect = new ChandraPyromasterCastFromExileEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -57,7 +58,6 @@ import mage.target.common.TargetCreatureOrPlayer;
|
|||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public class ChandraTorchOfDefiance extends CardImpl {
|
||||
|
@ -120,6 +120,7 @@ class ChandraTorchOfDefianceEffect extends OneShotEffect {
|
|||
if (card != null) {
|
||||
boolean exiledCardWasCast = false;
|
||||
controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true);
|
||||
if (!card.getManaCost().isEmpty())
|
||||
if (controller.chooseUse(Outcome.Benefit, "Cast the card? (You still pay the costs)", source, game) && !card.getCardType().contains(CardType.LAND)) {
|
||||
// LinkedHashMap<UUID, ActivatedAbility> useableAbilities = controller.getUseableActivatedAbilities(card, Zone.EXILED, game);
|
||||
// for (ActivatedAbility ability : useableAbilities.values()) {
|
||||
|
@ -131,6 +132,7 @@ class ChandraTorchOfDefianceEffect extends OneShotEffect {
|
|||
if (!exiledCardWasCast) {
|
||||
new DamagePlayersEffect(Outcome.Damage, new StaticValue(2), TargetController.OPPONENT).apply(game, source);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
99
Mage.Sets/src/mage/cards/c/CoalhaulerSwine.java
Normal file
99
Mage.Sets/src/mage/cards/c/CoalhaulerSwine.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.cards.c;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealtDamageToSourceTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author vereena42
|
||||
*/
|
||||
public class CoalhaulerSwine extends CardImpl {
|
||||
|
||||
public CoalhaulerSwine(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}");
|
||||
|
||||
this.subtype.add("Boar");
|
||||
this.subtype.add("Beast");
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Whenever Coalhauler Swine is dealt damage, it deals that much damage to each player.
|
||||
this.addAbility(new DealtDamageToSourceTriggeredAbility(Zone.BATTLEFIELD, new CoalhaulerSwineEffect(), false));
|
||||
}
|
||||
|
||||
public CoalhaulerSwine(final CoalhaulerSwine card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoalhaulerSwine copy() {
|
||||
return new CoalhaulerSwine(this);
|
||||
}
|
||||
|
||||
class CoalhaulerSwineEffect extends OneShotEffect {
|
||||
|
||||
public CoalhaulerSwineEffect() {
|
||||
super(Outcome.Damage);
|
||||
staticText = "it deals that much damage to each player";
|
||||
}
|
||||
|
||||
public CoalhaulerSwineEffect(final CoalhaulerSwineEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoalhaulerSwineEffect copy() {
|
||||
return new CoalhaulerSwineEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
for (UUID playerId : game.getPlayers().keySet()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if(player != null) {
|
||||
player.damage((Integer) this.getValue("damage"), source.getSourceId(), game, false, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
112
Mage.Sets/src/mage/cards/d/DeathWatch.java
Normal file
112
Mage.Sets/src/mage/cards/d/DeathWatch.java
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.cards.d;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DiesAttachedTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author vereena42
|
||||
*/
|
||||
public class DeathWatch extends CardImpl {
|
||||
|
||||
public DeathWatch(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}");
|
||||
|
||||
this.subtype.add("Aura");
|
||||
|
||||
// Enchant creature
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
this.getSpellAbility().addTarget(auraTarget);
|
||||
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
this.addAbility(ability);
|
||||
|
||||
// When enchanted creature dies, its controller loses life equal to its power and you gain life equal to its toughness.
|
||||
this.addAbility( new DiesAttachedTriggeredAbility(new DeathWatchEffect(), "enchanted creature"));
|
||||
}
|
||||
|
||||
public DeathWatch(final DeathWatch card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeathWatch copy() {
|
||||
return new DeathWatch(this);
|
||||
}
|
||||
|
||||
class DeathWatchEffect extends OneShotEffect {
|
||||
|
||||
public DeathWatchEffect() {
|
||||
super(Outcome.LoseLife);
|
||||
staticText = "that creature's controller loses life equal to its power and you gain life equal to its toughness.";
|
||||
}
|
||||
|
||||
public DeathWatchEffect(DeathWatchEffect copy) {
|
||||
super(copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeathWatchEffect copy() {
|
||||
return new DeathWatchEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent creature = (Permanent) getValue("attachedTo");
|
||||
if(creature != null){
|
||||
Player opponent = game.getPlayer(creature.getOwnerId());
|
||||
if (opponent != null) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
controller.gainLife(creature.getToughness().getValue(), game);
|
||||
opponent.loseLife(creature.getPower().getValue(), game, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -29,23 +29,28 @@ package mage.cards.d;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CopyEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
import mage.util.functions.ApplyToPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -54,7 +59,7 @@ import mage.target.common.TargetCardInGraveyard;
|
|||
public class DimirDoppelganger extends CardImpl {
|
||||
|
||||
public DimirDoppelganger(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}");
|
||||
this.subtype.add("Shapeshifter");
|
||||
|
||||
this.power = new MageInt(0);
|
||||
|
@ -77,14 +82,14 @@ public class DimirDoppelganger extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class DimirDoppelgangerEffect extends ContinuousEffectImpl {
|
||||
class DimirDoppelgangerEffect extends OneShotEffect {
|
||||
|
||||
public DimirDoppelgangerEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature);
|
||||
DimirDoppelgangerEffect() {
|
||||
super(Outcome.Copy);
|
||||
staticText = "Exile target creature card from a graveyard. {this} becomes a copy of that card and gains this ability";
|
||||
}
|
||||
|
||||
public DimirDoppelgangerEffect(final DimirDoppelgangerEffect effect) {
|
||||
DimirDoppelgangerEffect(final DimirDoppelgangerEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
@ -95,49 +100,48 @@ class DimirDoppelgangerEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getFirstTarget());
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (card == null || permanent == null) {
|
||||
return false;
|
||||
}
|
||||
card.moveToExile(null, "Dimir Doppelganger", source.getSourceId(), game);
|
||||
Card cardToCopy = card.copy();
|
||||
cardToCopy.assignNewId();
|
||||
permanent.setName(cardToCopy.getName());
|
||||
permanent.getPower().setValue(cardToCopy.getPower().getValue());
|
||||
permanent.getToughness().setValue(cardToCopy.getToughness().getValue());
|
||||
permanent.getColor(game).setColor(cardToCopy.getColor(game));
|
||||
permanent.getManaCost().clear();
|
||||
permanent.getManaCost().add(cardToCopy.getManaCost());
|
||||
permanent.getCardType().clear();
|
||||
for (CardType type : cardToCopy.getCardType()) {
|
||||
if (!permanent.getCardType().contains(type)) {
|
||||
permanent.getCardType().add(type);
|
||||
}
|
||||
}
|
||||
permanent.getSubtype(game).clear();
|
||||
for (String type : cardToCopy.getSubtype(game)) {
|
||||
if (!permanent.getSubtype(game).contains(type)) {
|
||||
permanent.getSubtype(game).add(type);
|
||||
}
|
||||
}
|
||||
permanent.getSupertype().clear();
|
||||
for (String type : cardToCopy.getSupertype()) {
|
||||
if (!permanent.getSupertype().contains(type)) {
|
||||
permanent.getSupertype().add(type);
|
||||
}
|
||||
}
|
||||
permanent.removeAllAbilities(source.getSourceId(), game);
|
||||
// gains ability of Dimir Doppelganger
|
||||
Ability dimirDoppelgangerAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DimirDoppelgangerEffect(), new ManaCostsImpl("{1}{U}{B}"));
|
||||
dimirDoppelgangerAbility.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
||||
permanent.addAbility(dimirDoppelgangerAbility, source.getSourceId(), game);
|
||||
|
||||
for (Ability ability : cardToCopy.getAbilities()) {
|
||||
if (!permanent.getAbilities().contains(ability)) {
|
||||
permanent.addAbility(ability, source.getSourceId(), game);
|
||||
}
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent dimirDoppelganger = game.getPermanent(source.getSourceId());
|
||||
Permanent newBluePrint = null;
|
||||
if (controller != null
|
||||
&& dimirDoppelganger != null) {
|
||||
Card copyFromCard = game.getCard(source.getFirstTarget());
|
||||
if (copyFromCard != null) {
|
||||
Cards cardsToExile = new CardsImpl();
|
||||
cardsToExile.add(copyFromCard);
|
||||
controller.moveCards(cardsToExile, Zone.EXILED, source, game);
|
||||
newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game);
|
||||
newBluePrint.assignNewId();
|
||||
ApplyToPermanent applier = new DimirDoppelgangerApplier();
|
||||
applier.apply(game, newBluePrint);
|
||||
CopyEffect copyEffect = new CopyEffect(Duration.Custom, newBluePrint, dimirDoppelganger.getId());
|
||||
copyEffect.newId();
|
||||
copyEffect.setApplier(applier);
|
||||
Ability newAbility = source.copy();
|
||||
copyEffect.init(newAbility, game);
|
||||
game.addEffect(copyEffect, newAbility);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class DimirDoppelgangerApplier extends ApplyToPermanent {
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DimirDoppelgangerEffect(), new ManaCostsImpl("{1}{U}{B}"));
|
||||
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
||||
permanent.getAbilities().add(ability);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, MageObject mageObject) {
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DimirDoppelgangerEffect(), new ManaCostsImpl("{1}{U}{B}"));
|
||||
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
||||
mageObject.getAbilities().add(ability);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ class EssenceFluxEffect extends OneShotEffect {
|
|||
|
||||
EssenceFluxEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "return that card to the battlefield under its owner's control";
|
||||
staticText = "return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it";
|
||||
}
|
||||
|
||||
EssenceFluxEffect(final EssenceFluxEffect effect) {
|
||||
|
|
|
@ -29,24 +29,27 @@ package mage.cards.l;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CopyEffect;
|
||||
import mage.abilities.keyword.HexproofAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.functions.ApplyToPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -67,7 +70,7 @@ public class LazavDimirMastermind extends CardImpl {
|
|||
|
||||
// Whenever a creature card is put into an opponent's graveyard from anywhere, you may have Lazav, Dimir Mastermind become a copy of that card except its name is still Lazav, Dimir Mastermind, it's legendary in addition to its other types, and it gains hexproof and this ability.
|
||||
this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
|
||||
new LazavDimirEffect(), true,
|
||||
new LazavDimirMastermindEffect(), true,
|
||||
new FilterCreatureCard("a creature card"),
|
||||
TargetController.OPPONENT, SetTargetPointer.CARD));
|
||||
}
|
||||
|
@ -82,80 +85,73 @@ public class LazavDimirMastermind extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class LazavDimirEffect extends ContinuousEffectImpl {
|
||||
class LazavDimirMastermindEffect extends OneShotEffect {
|
||||
|
||||
protected Card cardToCopy;
|
||||
|
||||
public LazavDimirEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature);
|
||||
staticText = "have {this} become a copy of that card except its name is still {this}, it's legendary in addition to its other types, and it gains hexproof and this ability";
|
||||
LazavDimirMastermindEffect() {
|
||||
super(Outcome.Copy);
|
||||
staticText = "you may have {this} become a copy of that card except its name is still {this}, it's legendary in addition to its other types, and it gains hexproof and this ability";
|
||||
}
|
||||
|
||||
public LazavDimirEffect(final LazavDimirEffect effect) {
|
||||
LazavDimirMastermindEffect(final LazavDimirMastermindEffect effect) {
|
||||
super(effect);
|
||||
this.cardToCopy = effect.cardToCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazavDimirEffect copy() {
|
||||
return new LazavDimirEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
Card card = game.getCard(((FixedTarget) getTargetPointer()).getTarget());
|
||||
if (card != null) {
|
||||
cardToCopy = card.copy();
|
||||
cardToCopy.assignNewId();
|
||||
} else {
|
||||
discard();
|
||||
}
|
||||
public LazavDimirMastermindEffect copy() {
|
||||
return new LazavDimirMastermindEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent lazavDimirMastermind = game.getPermanent(source.getSourceId());
|
||||
Permanent newBluePrint = null;
|
||||
if (controller != null
|
||||
&& lazavDimirMastermind != null) {
|
||||
Card copyFromCard = game.getCard(((FixedTarget) getTargetPointer()).getTarget());
|
||||
if (copyFromCard != null) {
|
||||
newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game);
|
||||
newBluePrint.assignNewId();
|
||||
ApplyToPermanent applier = new LazavDimirMastermindApplier();
|
||||
applier.apply(game, newBluePrint);
|
||||
CopyEffect copyEffect = new CopyEffect(Duration.Custom, newBluePrint, lazavDimirMastermind.getId());
|
||||
copyEffect.newId();
|
||||
copyEffect.setApplier(applier);
|
||||
Ability newAbility = source.copy();
|
||||
copyEffect.init(newAbility, game);
|
||||
game.addEffect(copyEffect, newAbility);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
permanent.getPower().setValue(cardToCopy.getPower().getValue());
|
||||
permanent.getToughness().setValue(cardToCopy.getToughness().getValue());
|
||||
permanent.getColor(game).setColor(cardToCopy.getColor(game));
|
||||
permanent.getManaCost().clear();
|
||||
permanent.getManaCost().add(cardToCopy.getManaCost());
|
||||
permanent.getCardType().clear();
|
||||
for (CardType type : cardToCopy.getCardType()) {
|
||||
if (!permanent.getCardType().contains(type)) {
|
||||
permanent.getCardType().add(type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
permanent.getSubtype(game).clear();
|
||||
for (String type : cardToCopy.getSubtype(game)) {
|
||||
if (!permanent.getSubtype(game).contains(type)) {
|
||||
permanent.getSubtype(game).add(type);
|
||||
}
|
||||
}
|
||||
permanent.getSupertype().clear();
|
||||
permanent.getSupertype().add("Legendary");
|
||||
for (String type : cardToCopy.getSupertype()) {
|
||||
if (!permanent.getSupertype().contains(type)) {
|
||||
permanent.getSupertype().add(type);
|
||||
}
|
||||
}
|
||||
permanent.removeAllAbilities(source.getSourceId(), game);
|
||||
permanent.addAbility(HexproofAbility.getInstance(), source.getSourceId(), game);
|
||||
permanent.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
|
||||
new LazavDimirEffect(), true,
|
||||
new FilterCreatureCard("a creature card"),
|
||||
TargetController.OPPONENT, SetTargetPointer.CARD), source.getSourceId(), game);
|
||||
}
|
||||
|
||||
for (Ability ability : cardToCopy.getAbilities()) {
|
||||
if (!permanent.getAbilities().contains(ability)) {
|
||||
permanent.addAbility(ability, source.getSourceId(), game);
|
||||
}
|
||||
class LazavDimirMastermindApplier extends ApplyToPermanent {
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
Ability ability = new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
|
||||
new LazavDimirMastermindEffect(), true,
|
||||
new FilterCreatureCard("a creature card"),
|
||||
TargetController.OPPONENT, SetTargetPointer.CARD);
|
||||
permanent.getAbilities().add(ability);
|
||||
permanent.setName("Lazav, Dimir Mastermind");
|
||||
permanent.getSupertype().add("Legendary");
|
||||
permanent.getAbilities().add(HexproofAbility.getInstance());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, MageObject mageObject) {
|
||||
Ability ability = new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
|
||||
new LazavDimirMastermindEffect(), true,
|
||||
new FilterCreatureCard("a creature card"),
|
||||
TargetController.OPPONENT, SetTargetPointer.CARD);
|
||||
mageObject.getAbilities().add(ability);
|
||||
mageObject.setName("Lazav, Dimir Mastermind");
|
||||
mageObject.getSupertype().add("Legendary");
|
||||
mageObject.getAbilities().add(HexproofAbility.getInstance());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
133
Mage.Sets/src/mage/cards/m/MenacingOgre.java
Normal file
133
Mage.Sets/src/mage/cards/m/MenacingOgre.java
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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.cards.m;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class MenacingOgre extends CardImpl {
|
||||
|
||||
public MenacingOgre(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}");
|
||||
|
||||
this.subtype.add("Ogre");
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Trample
|
||||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// Haste
|
||||
this.addAbility(HasteAbility.getInstance());
|
||||
|
||||
// When Menacing Ogre enters the battlefield, each player secretly chooses a number. Then those numbers are revealed. Each player with the highest number loses that much life. If you are one of those players, put two +1/+1 counters on Menacing Ogre.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new MenacingOgreEffect(), false));
|
||||
|
||||
}
|
||||
|
||||
public MenacingOgre(final MenacingOgre card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenacingOgre copy() {
|
||||
return new MenacingOgre(this);
|
||||
}
|
||||
}
|
||||
|
||||
class MenacingOgreEffect extends OneShotEffect {
|
||||
|
||||
public MenacingOgreEffect() {
|
||||
super(Outcome.Detriment);
|
||||
this.staticText = "each player secretly chooses a number. Then those numbers are revealed. Each player with the highest number loses that much life. If you are one of those players, put two +1/+1 counters on {this}";
|
||||
}
|
||||
|
||||
public MenacingOgreEffect(final MenacingOgreEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenacingOgreEffect copy() {
|
||||
return new MenacingOgreEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
int highestNumber = 0;
|
||||
int number = 0;
|
||||
Permanent menacingOgre = game.getPermanent(source.getSourceId());
|
||||
String message = "Choose a number.";
|
||||
HashMap<Player, Integer> numberChosen = new HashMap<>();
|
||||
|
||||
//players choose numbers
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
if (player != null) {
|
||||
number = player.getAmount(0, 1000, message, game);
|
||||
numberChosen.put(player, number);
|
||||
}
|
||||
}
|
||||
//get highest number
|
||||
for (Player player : numberChosen.keySet()) {
|
||||
if (highestNumber < numberChosen.get(player)) {
|
||||
highestNumber = numberChosen.get(player);
|
||||
}
|
||||
}
|
||||
//reveal numbers to players and follow through with effect
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
if (player != null) {
|
||||
game.informPlayers(player.getLogName() + " chose number " + numberChosen.get(player));
|
||||
if (numberChosen.get(player) >= highestNumber) {
|
||||
player.loseLife(highestNumber, game, false);
|
||||
if (player.getId() == source.getControllerId()
|
||||
&& menacingOgre != null) {
|
||||
menacingOgre.addCounters(CounterType.P1P1.createInstance(2), source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
64
Mage.Sets/src/mage/cards/m/MistformUltimus.java
Normal file
64
Mage.Sets/src/mage/cards/m/MistformUltimus.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.cards.m;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author vereena42
|
||||
*/
|
||||
public class MistformUltimus extends CardImpl {
|
||||
|
||||
public MistformUltimus(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
|
||||
|
||||
this.supertype.add("Legendary");
|
||||
this.subtype.add("Illusion");
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Mistform Ultimus is every creature type.
|
||||
this.subtype.add(ChangelingAbility.ALL_CREATURE_TYPE); // "All Creature Type"
|
||||
}
|
||||
|
||||
public MistformUltimus(final MistformUltimus card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MistformUltimus copy() {
|
||||
return new MistformUltimus(this);
|
||||
}
|
||||
}
|
|
@ -31,12 +31,15 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -119,17 +122,11 @@ public class NecroticOoze extends CardImpl {
|
|||
@Override
|
||||
public Set<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer) {
|
||||
// the dependent classes needs to be an enclosed class for dependent check of continuous effects
|
||||
Set<UUID> dependentTo = null;
|
||||
for (ContinuousEffect effect : allEffectsInLayer) {
|
||||
// http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/285211-yixlid-jailer-vs-necrotic-ooze
|
||||
if (YixlidJailer.class.equals(effect.getClass().getEnclosingClass())) {
|
||||
if (dependentTo == null) {
|
||||
dependentTo = new HashSet<>();
|
||||
}
|
||||
dependentTo.add(effect.getId());
|
||||
}
|
||||
}
|
||||
return dependentTo;
|
||||
return allEffectsInLayer.stream()
|
||||
.filter(effect -> YixlidJailer.class.equals(effect.getClass().getEnclosingClass()))
|
||||
.map(Effect::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,19 +25,17 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.cards.o;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.LandfallAbility;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.counters.CounterType;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
|
@ -47,21 +45,23 @@ import mage.target.TargetPlayer;
|
|||
*/
|
||||
public class ObNixilisTheFallen extends CardImpl {
|
||||
|
||||
public ObNixilisTheFallen (UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
|
||||
public ObNixilisTheFallen(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
|
||||
this.supertype.add("Legendary");
|
||||
this.subtype.add("Demon");
|
||||
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Landfall - Whenever a land enters the battlefield under your control, you may have target player lose 3 life.
|
||||
// If you do, put three +1/+1 counters on Ob Nixilis, the Fallen.
|
||||
Ability ability = new LandfallAbility(new LoseLifeTargetEffect(3), true);
|
||||
ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)));
|
||||
ability.addTarget(new TargetPlayer());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public ObNixilisTheFallen (final ObNixilisTheFallen card) {
|
||||
public ObNixilisTheFallen(final ObNixilisTheFallen card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,8 +52,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class PhyrexianTyranny extends CardImpl {
|
||||
|
||||
public PhyrexianTyranny(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}{B}{R}");
|
||||
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{B}{R}");
|
||||
|
||||
// Whenever a player draws a card, that player loses 2 life unless he or she pays {2}.
|
||||
this.addAbility(new PhyrexianTyrannyTriggeredAbility());
|
||||
|
@ -127,7 +126,7 @@ class PhyrexianTyrannyEffect extends OneShotEffect {
|
|||
if (player != null) {
|
||||
Cost cost = new GenericManaCost(2);
|
||||
if (!cost.pay(source, game, player.getId(), player.getId(), false, null)) {
|
||||
player.damage(2, source.getSourceId(), game, false, true);
|
||||
player.loseLife(2, game, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,6 @@ public class Homelands extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Clockwork Gnomes", 127, Rarity.COMMON, mage.cards.c.ClockworkGnomes.class));
|
||||
cards.add(new SetCardInfo("Coral Reef", 29, Rarity.COMMON, mage.cards.c.CoralReef.class));
|
||||
cards.add(new SetCardInfo("Dark Maze", 31, Rarity.COMMON, mage.cards.d.DarkMaze.class, new CardGraphicInfo(null, true)));
|
||||
cards.add(new SetCardInfo("Dark Maze", 31, Rarity.COMMON, mage.cards.d.DarkMaze.class, new CardGraphicInfo(null, true)));
|
||||
cards.add(new SetCardInfo("Death Speakers", 109, Rarity.UNCOMMON, mage.cards.d.DeathSpeakers.class));
|
||||
cards.add(new SetCardInfo("Didgeridoo", 130, Rarity.RARE, mage.cards.d.Didgeridoo.class));
|
||||
cards.add(new SetCardInfo("Drudge Spell", 6, Rarity.UNCOMMON, mage.cards.d.DrudgeSpell.class));
|
||||
|
|
|
@ -127,6 +127,7 @@ public class Legions extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Magma Sliver", 107, Rarity.RARE, mage.cards.m.MagmaSliver.class));
|
||||
cards.add(new SetCardInfo("Merchant of Secrets", 44, Rarity.COMMON, mage.cards.m.MerchantOfSecrets.class));
|
||||
cards.add(new SetCardInfo("Mistform Sliver", 46, Rarity.COMMON, mage.cards.m.MistformSliver.class));
|
||||
cards.add(new SetCardInfo("Mistform Ultimus", 47, Rarity.RARE, mage.cards.m.MistformUltimus.class));
|
||||
cards.add(new SetCardInfo("Nantuko Vigilante", 132, Rarity.COMMON, mage.cards.n.NantukoVigilante.class));
|
||||
cards.add(new SetCardInfo("Needleshot Gourna", 133, Rarity.COMMON, mage.cards.n.NeedleshotGourna.class));
|
||||
cards.add(new SetCardInfo("Noxious Ghoul", 77, Rarity.UNCOMMON, mage.cards.n.NoxiousGhoul.class));
|
||||
|
|
|
@ -216,10 +216,9 @@ public class MastersEditionIV extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Regrowth", 163, Rarity.RARE, mage.cards.r.Regrowth.class));
|
||||
cards.add(new SetCardInfo("Righteous Charge", 23, Rarity.COMMON, mage.cards.r.RighteousCharge.class));
|
||||
cards.add(new SetCardInfo("Ring of Renewal", 224, Rarity.RARE, mage.cards.r.RingOfRenewal.class));
|
||||
cards.add(new SetCardInfo("Rock Hydra", 133, Rarity.RARE, mage.cards.r.RockHydra.class));
|
||||
cards.add(new SetCardInfo("Rockslide Ambush", 134, Rarity.COMMON, mage.cards.r.RockslideAmbush.class));
|
||||
cards.add(new SetCardInfo("Roc of Kher Ridges", 132, Rarity.UNCOMMON, mage.cards.r.RocOfKherRidges.class));
|
||||
cards.add(new SetCardInfo("Rock Hydra", 133, Rarity.RARE, mage.cards.r.RockHydra.class));
|
||||
cards.add(new SetCardInfo("Rockslide Ambush", 134, Rarity.COMMON, mage.cards.r.RockslideAmbush.class));
|
||||
cards.add(new SetCardInfo("Sandstorm", 164, Rarity.COMMON, mage.cards.s.Sandstorm.class));
|
||||
cards.add(new SetCardInfo("Savannah", 250, Rarity.RARE, mage.cards.s.Savannah.class));
|
||||
cards.add(new SetCardInfo("Savannah Lions", 24, Rarity.UNCOMMON, mage.cards.s.SavannahLions.class));
|
||||
|
|
|
@ -55,7 +55,6 @@ public class Onslaught extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Blistering Firecat", 189, Rarity.RARE, mage.cards.b.BlisteringFirecat.class));
|
||||
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
|
||||
cards.add(new SetCardInfo("Bloodstained Mire", 313, Rarity.RARE, mage.cards.b.BloodstainedMire.class, new CardGraphicInfo(new ObjectColor("RB"), null,false)));
|
||||
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
|
||||
cards.add(new SetCardInfo("Boneknitter", 128, Rarity.UNCOMMON, mage.cards.b.Boneknitter.class));
|
||||
cards.add(new SetCardInfo("Brightstone Ritual", 191, Rarity.COMMON, mage.cards.b.BrightstoneRitual.class));
|
||||
cards.add(new SetCardInfo("Broodhatch Nantuko", 250, Rarity.UNCOMMON, mage.cards.b.BroodhatchNantuko.class));
|
||||
|
@ -182,6 +181,7 @@ public class Onslaught extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Lonely Sandbar", 320, Rarity.COMMON, mage.cards.l.LonelySandbar.class));
|
||||
cards.add(new SetCardInfo("Mage's Guile", 91, Rarity.COMMON, mage.cards.m.MagesGuile.class));
|
||||
cards.add(new SetCardInfo("Mana Echoes", 218, Rarity.RARE, mage.cards.m.ManaEchoes.class));
|
||||
cards.add(new SetCardInfo("Menacing Ogre", 219, Rarity.RARE, mage.cards.m.MenacingOgre.class));
|
||||
cards.add(new SetCardInfo("Misery Charm", 158, Rarity.COMMON, mage.cards.m.MiseryCharm.class));
|
||||
cards.add(new SetCardInfo("Mistform Mutant", 95, Rarity.UNCOMMON, mage.cards.m.MistformMutant.class));
|
||||
cards.add(new SetCardInfo("Mobilization", 44, Rarity.RARE, mage.cards.m.Mobilization.class));
|
||||
|
@ -303,18 +303,12 @@ public class Onslaught extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Wheel and Deal", 121, Rarity.RARE, mage.cards.w.WheelAndDeal.class));
|
||||
cards.add(new SetCardInfo("Whipcorder", 60, Rarity.UNCOMMON, mage.cards.w.Whipcorder.class));
|
||||
cards.add(new SetCardInfo("Windswept Heath", 328, Rarity.RARE, mage.cards.w.WindsweptHeath.class, new CardGraphicInfo(new ObjectColor("GW"), null, false)));
|
||||
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
|
||||
cards.add(new SetCardInfo("Trade Secrets", 118, Rarity.RARE, mage.cards.t.TradeSecrets.class));
|
||||
cards.add(new SetCardInfo("Venomspout Brackus", 295, Rarity.UNCOMMON, mage.cards.v.VenomspoutBrackus.class));
|
||||
cards.add(new SetCardInfo("Wirewood Elf", 301, Rarity.COMMON, mage.cards.w.WirewoodElf.class));
|
||||
cards.add(new SetCardInfo("Wirewood Herald", 302, Rarity.COMMON, mage.cards.w.WirewoodHerald.class));
|
||||
cards.add(new SetCardInfo("Wirewood Lodge", 329, Rarity.RARE, mage.cards.w.WirewoodLodge.class));
|
||||
cards.add(new SetCardInfo("Wirewood Pride", 303, Rarity.COMMON, mage.cards.w.WirewoodPride.class));
|
||||
cards.add(new SetCardInfo("Wirewood Savage", 304, Rarity.COMMON, mage.cards.w.WirewoodSavage.class));
|
||||
cards.add(new SetCardInfo("Wooded Foothills", 330, Rarity.RARE, mage.cards.w.WoodedFoothills.class, new CardGraphicInfo(new ObjectColor("RG"), null, false)));
|
||||
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
|
||||
cards.add(new SetCardInfo("Trade Secrets", 118, Rarity.RARE, mage.cards.t.TradeSecrets.class));
|
||||
cards.add(new SetCardInfo("Venomspout Brackus", 295, Rarity.UNCOMMON, mage.cards.v.VenomspoutBrackus.class));
|
||||
cards.add(new SetCardInfo("Words of War", 244, Rarity.RARE, mage.cards.w.WordsOfWar.class));
|
||||
cards.add(new SetCardInfo("Words of Wind", 122, Rarity.RARE, mage.cards.w.WordsOfWind.class));
|
||||
cards.add(new SetCardInfo("Words of Worship", 61, Rarity.RARE, mage.cards.w.WordsOfWorship.class));
|
||||
|
|
|
@ -139,6 +139,7 @@ public class Planechase extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Mage Slayer", 91, Rarity.UNCOMMON, mage.cards.m.MageSlayer.class));
|
||||
cards.add(new SetCardInfo("Mask of Memory", 119, Rarity.UNCOMMON, mage.cards.m.MaskOfMemory.class));
|
||||
cards.add(new SetCardInfo("Master of Etherium", 11, Rarity.RARE, mage.cards.m.MasterOfEtherium.class));
|
||||
cards.add(new SetCardInfo("Menacing Ogre", 59, Rarity.RARE, mage.cards.m.MenacingOgre.class));
|
||||
cards.add(new SetCardInfo("Mountain", 156, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true)));
|
||||
cards.add(new SetCardInfo("Mountain", 157, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true)));
|
||||
cards.add(new SetCardInfo("Mountain", 158, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true)));
|
||||
|
|
|
@ -89,6 +89,7 @@ public class RavnicaCityOfGuilds extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Clinging Darkness", 80, Rarity.COMMON, mage.cards.c.ClingingDarkness.class));
|
||||
cards.add(new SetCardInfo("Cloudstone Curio", 257, Rarity.RARE, mage.cards.c.CloudstoneCurio.class));
|
||||
cards.add(new SetCardInfo("Clutch of the Undercity", 197, Rarity.UNCOMMON, mage.cards.c.ClutchOfTheUndercity.class));
|
||||
cards.add(new SetCardInfo("Coalhauler Swine", 119, Rarity.COMMON, mage.cards.c.CoalhaulerSwine.class));
|
||||
cards.add(new SetCardInfo("Compulsive Research", 40, Rarity.COMMON, mage.cards.c.CompulsiveResearch.class));
|
||||
cards.add(new SetCardInfo("Concerted Effort", 8, Rarity.RARE, mage.cards.c.ConcertedEffort.class));
|
||||
cards.add(new SetCardInfo("Conclave Equenaut", 9, Rarity.COMMON, mage.cards.c.ConclaveEquenaut.class));
|
||||
|
|
|
@ -231,10 +231,9 @@ public class RevisedEdition extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Resurrection", 218, Rarity.UNCOMMON, mage.cards.r.Resurrection.class));
|
||||
cards.add(new SetCardInfo("Reverse Damage", 219, Rarity.RARE, mage.cards.r.ReverseDamage.class));
|
||||
cards.add(new SetCardInfo("Righteousness", 221, Rarity.RARE, mage.cards.r.Righteousness.class));
|
||||
cards.add(new SetCardInfo("Rock Hydra", 172, Rarity.RARE, mage.cards.r.RockHydra.class));
|
||||
cards.add(new SetCardInfo("Rocket Launcher", 272, Rarity.RARE, mage.cards.r.RocketLauncher.class));
|
||||
cards.add(new SetCardInfo("Roc of Kher Ridges", 171, Rarity.RARE, mage.cards.r.RocOfKherRidges.class));
|
||||
cards.add(new SetCardInfo("Rock Hydra", 172, Rarity.RARE, mage.cards.r.RockHydra.class));
|
||||
cards.add(new SetCardInfo("Rocket Launcher", 272, Rarity.RARE, mage.cards.r.RocketLauncher.class));
|
||||
cards.add(new SetCardInfo("Rod of Ruin", 273, Rarity.UNCOMMON, mage.cards.r.RodOfRuin.class));
|
||||
cards.add(new SetCardInfo("Royal Assassin", 33, Rarity.RARE, mage.cards.r.RoyalAssassin.class));
|
||||
cards.add(new SetCardInfo("Sacrifice", 34, Rarity.UNCOMMON, mage.cards.s.Sacrifice.class));
|
||||
|
|
|
@ -105,6 +105,7 @@ public class TimeSpiralTimeshifted extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Merieke Ri Berit", 95, Rarity.SPECIAL, mage.cards.m.MeriekeRiBerit.class));
|
||||
cards.add(new SetCardInfo("Mindless Automaton", 111, Rarity.SPECIAL, mage.cards.m.MindlessAutomaton.class));
|
||||
cards.add(new SetCardInfo("Mirari", 112, Rarity.SPECIAL, mage.cards.m.Mirari.class));
|
||||
cards.add(new SetCardInfo("Mistform Ultimus", 26, Rarity.SPECIAL, mage.cards.m.MistformUltimus.class));
|
||||
cards.add(new SetCardInfo("Moorish Cavalry", 11, Rarity.COMMON, mage.cards.m.MoorishCavalry.class));
|
||||
cards.add(new SetCardInfo("Mystic Enforcer", 96, Rarity.SPECIAL, mage.cards.m.MysticEnforcer.class));
|
||||
cards.add(new SetCardInfo("Mystic Snake", 97, Rarity.COMMON, mage.cards.m.MysticSnake.class));
|
||||
|
|
|
@ -68,6 +68,7 @@ public class Visions extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Creeping Mold", 53, Rarity.UNCOMMON, mage.cards.c.CreepingMold.class));
|
||||
cards.add(new SetCardInfo("Crypt Rats", 5, Rarity.COMMON, mage.cards.c.CryptRats.class));
|
||||
cards.add(new SetCardInfo("Daraja Griffin", 102, Rarity.UNCOMMON, mage.cards.d.DarajaGriffin.class));
|
||||
cards.add(new SetCardInfo("Death Watch", 7, Rarity.COMMON, mage.cards.d.DeathWatch.class));
|
||||
cards.add(new SetCardInfo("Desertion", 30, Rarity.RARE, mage.cards.d.Desertion.class));
|
||||
cards.add(new SetCardInfo("Diamond Kaleidoscope", 143, Rarity.RARE, mage.cards.d.DiamondKaleidoscope.class));
|
||||
cards.add(new SetCardInfo("Dormant Volcano", 161, Rarity.UNCOMMON, mage.cards.d.DormantVolcano.class));
|
||||
|
|
|
@ -92,12 +92,12 @@ public class CrewTest extends CardTestPlayerBase {
|
|||
setChoice(playerA, "Speedway Fanatic");
|
||||
|
||||
// Return all creatures to there owners hands
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Evacuation");
|
||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Evacuation");
|
||||
|
||||
// (Re)Cast Smugglers Copter
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Smuggler's Copter");
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Smuggler's Copter");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
// Only crewed vehicles have card type creature
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.replacement;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class DamageEffectsTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Just encountered another bug. With Wurmcoil Engine out and with a
|
||||
* Gratuitous Violence on the field, I only gained 6 life on blocking rather
|
||||
* than 12 life.
|
||||
*/
|
||||
@Test
|
||||
public void testDamageIsDoubledWithLifelink() {
|
||||
// Landfall - Whenever a land enters the battlefield under your control, you may have target player lose 3 life.
|
||||
// If you do, put three +1/+1 counters on Ob Nixilis, the Fallen.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Ob Nixilis, the Fallen");
|
||||
addCard(Zone.HAND, playerB, "Mountain");
|
||||
|
||||
// Deathtouch, lifelink
|
||||
// When Wurmcoil Engine dies, create a 3/3 colorless Wurm artifact creature token with deathtouch and a 3/3 colorless Wurm artifact creature token with lifelink.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Wurmcoil Engine");
|
||||
// If a creature you control would deal damage to a creature or player, it deals double that damage to that creature or player instead.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Gratuitous Violence");
|
||||
|
||||
playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Mountain");
|
||||
setChoice(playerB, "Yes");
|
||||
addTarget(playerB, playerA);
|
||||
|
||||
attack(2, playerB, "Ob Nixilis, the Fallen");
|
||||
block(2, playerA, "Wurmcoil Engine", "Ob Nixilis, the Fallen");
|
||||
|
||||
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerB, "Ob Nixilis, the Fallen", 1);
|
||||
|
||||
assertGraveyardCount(playerA, "Wurmcoil Engine", 1);
|
||||
assertPermanentCount(playerA, "Wurm", 2);
|
||||
|
||||
assertLife(playerB, 20);
|
||||
assertLife(playerA, 29); // -2 from Ob Nixilis + 12 from double damage with lifelink from Wurmcoil Engine
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDamageToPlayer() {
|
||||
// Deathtouch, lifelink
|
||||
// When Wurmcoil Engine dies, create a 3/3 colorless Wurm artifact creature token with deathtouch and a 3/3 colorless Wurm artifact creature token with lifelink.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Wurmcoil Engine");
|
||||
// If a creature you control would deal damage to a creature or player, it deals double that damage to that creature or player instead.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Gratuitous Violence");
|
||||
|
||||
attack(1, playerA, "Wurmcoil Engine");
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Wurmcoil Engine", 1);
|
||||
|
||||
assertLife(playerB, 8);
|
||||
assertLife(playerA, 32);
|
||||
|
||||
}
|
||||
}
|
|
@ -44,6 +44,29 @@ public class ChandraPyromasterTest extends CardTestPlayerBase {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbility2AncestralVision() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Chandra, Pyromaster");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
|
||||
skipInitShuffling();
|
||||
addCard(Zone.LIBRARY, playerA, "Ancestral Vision");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Exile the top card of your library. You may play it this turn.");
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertPermanentCount(playerA, "Chandra, Pyromaster", 1);
|
||||
assertGraveyardCount(playerA, "Ancestral Vision", 0);
|
||||
|
||||
assertExileCount(playerA, "Ancestral Vision", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbility2CastCardFromExileWithOverlaod() {
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.mage.test.player.TestPlayer;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FilenameFilter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -297,7 +296,8 @@ public abstract class MageTestBase {
|
|||
}
|
||||
|
||||
protected Player createPlayer(String name, String playerType) {
|
||||
return PlayerFactory.getInstance().createPlayer(playerType, name, RangeOfInfluence.ALL, 5);
|
||||
Optional<Player> playerOptional = PlayerFactory.getInstance().createPlayer(playerType, name, RangeOfInfluence.ALL, 5);
|
||||
return playerOptional.orElseThrow(() -> new NullPointerException("PlayerFactory error - player is not created"));
|
||||
}
|
||||
|
||||
protected Player createRandomPlayer(String name) {
|
||||
|
|
|
@ -860,6 +860,25 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
Assert.assertEquals("(Exile) Card counts for player " + owner.getName() + " is not equal.", count, actualCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert card count in player's exile.
|
||||
*
|
||||
* @param owner {@link Player} who's exile should be counted.
|
||||
* @param cardName Name of the cards that should be counted.
|
||||
* @param count Expected count.
|
||||
*/
|
||||
public void assertExileCount(Player owner, String cardName, int count) throws AssertionError {
|
||||
int actualCount = 0;
|
||||
for (ExileZone exile : currentGame.getExile().getExileZones()) {
|
||||
for (Card card : exile.getCards(currentGame)) {
|
||||
if (card.getOwnerId().equals(owner.getId()) && card.getName().equals(cardName)) {
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("(Exile " + owner.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert card count in player's graveyard.
|
||||
*
|
||||
|
|
|
@ -88,11 +88,7 @@ public class AttacksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder("Whenever ");
|
||||
if (attachmentType.equals(AttachmentType.EQUIPMENT)) {
|
||||
sb.append("equipped");
|
||||
} else {
|
||||
sb.append("enchanted");
|
||||
}
|
||||
sb.append(attachmentType.verb().toLowerCase());
|
||||
return sb.append(" creature attacks, ").append(super.getRule()).toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ public class AfterUpkeepStepCondtion implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return !(game.getStep().getType() == PhaseStep.UNTAP
|
||||
|| game.getStep().getType() == PhaseStep.UPKEEP);
|
||||
return game.getStep().getType().isAfter(PhaseStep.UPKEEP);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,10 +26,7 @@ public class BeforeBlockersAreDeclaredCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return !(game.getStep().getType().equals(PhaseStep.DECLARE_BLOCKERS)
|
||||
|| game.getStep().getType().equals(PhaseStep.FIRST_COMBAT_DAMAGE)
|
||||
|| game.getStep().getType().equals(PhaseStep.COMBAT_DAMAGE)
|
||||
|| game.getStep().getType().equals(PhaseStep.END_COMBAT));
|
||||
return game.getStep().getType().isBefore(PhaseStep.DECLARE_BLOCKERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,11 +27,6 @@
|
|||
*/
|
||||
package mage.abilities.costs.mana;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
@ -45,13 +40,15 @@ import mage.players.Player;
|
|||
import mage.target.Targets;
|
||||
import mage.util.ManaUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @param <T>
|
||||
*/
|
||||
public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements ManaCosts<T> {
|
||||
|
||||
protected UUID id;
|
||||
protected final UUID id;
|
||||
protected String text = null;
|
||||
|
||||
private static Map<String, ManaCosts> costs = new HashMap<>();
|
||||
|
@ -323,7 +320,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
if (mana == null || mana.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String[] symbols = mana.split("^\\{|\\}\\{|\\}$");
|
||||
String[] symbols = mana.split("^\\{|}\\{|}$");
|
||||
int modifierForX = 0;
|
||||
for (String symbol : symbols) {
|
||||
if (!symbol.isEmpty()) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities.decorator;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.effects.AsThoughEffect;
|
||||
|
@ -36,7 +37,6 @@ import mage.constants.Duration;
|
|||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class ConditionalAsThoughEffect extends AsThoughEffectImpl {
|
||||
|
@ -59,9 +59,9 @@ public class ConditionalAsThoughEffect extends AsThoughEffectImpl {
|
|||
|
||||
public ConditionalAsThoughEffect(final ConditionalAsThoughEffect effect) {
|
||||
super(effect);
|
||||
this.effect = (AsThoughEffect) effect.effect.copy();
|
||||
this.effect = effect.effect.copy();
|
||||
if (effect.otherwiseEffect != null) {
|
||||
this.otherwiseEffect = (AsThoughEffect) effect.otherwiseEffect.copy();
|
||||
this.otherwiseEffect = effect.otherwiseEffect.copy();
|
||||
}
|
||||
this.condition = effect.condition;
|
||||
this.conditionState = effect.conditionState;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities.effects;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
@ -55,10 +56,10 @@ import mage.target.common.TargetCardInGraveyard;
|
|||
* was not cast (so from Zone != Hand), this effect gets the target to whitch to
|
||||
* attach it and adds the Aura the the battlefield and attachs it to the target.
|
||||
* The "attachTo:" value in game state has to be set therefore.
|
||||
*
|
||||
* <p>
|
||||
* If no "attachTo:" value is defined, the controlling player has to chose the
|
||||
* aura target.
|
||||
*
|
||||
* <p>
|
||||
* This effect is automatically added to ContinuousEffects at the start of a
|
||||
* game
|
||||
*
|
||||
|
@ -204,8 +205,8 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (((ZoneChangeEvent) event).getToZone().equals(Zone.BATTLEFIELD)
|
||||
&& !(((ZoneChangeEvent) event).getFromZone().equals(Zone.STACK))) {
|
||||
if (((ZoneChangeEvent) event).getToZone() == Zone.BATTLEFIELD
|
||||
&& (((ZoneChangeEvent) event).getFromZone() != Zone.STACK)) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && (card.getCardType().contains(CardType.ENCHANTMENT) && card.hasSubtype("Aura", game)
|
||||
|| // in case of transformable enchantments
|
||||
|
|
|
@ -33,6 +33,8 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.MageSingleton;
|
||||
|
@ -51,7 +53,6 @@ import mage.game.Game;
|
|||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class ContinuousEffectImpl extends EffectImpl implements ContinuousEffect {
|
||||
|
@ -171,9 +172,9 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
public void init(Ability source, Game game) {
|
||||
targetPointer.init(game, source);
|
||||
//20100716 - 611.2c
|
||||
if (AbilityType.ACTIVATED.equals(source.getAbilityType())
|
||||
|| AbilityType.SPELL.equals(source.getAbilityType())
|
||||
|| AbilityType.TRIGGERED.equals(source.getAbilityType())) {
|
||||
if (AbilityType.ACTIVATED == source.getAbilityType()
|
||||
|| AbilityType.SPELL == source.getAbilityType()
|
||||
|| AbilityType.TRIGGERED == source.getAbilityType()) {
|
||||
if (layer != null) {
|
||||
switch (layer) {
|
||||
case CopyEffects_1:
|
||||
|
@ -197,7 +198,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
|
||||
@Override
|
||||
public boolean isInactive(Ability source, Game game) {
|
||||
if (duration.equals(Duration.UntilYourNextTurn)) {
|
||||
if (duration == Duration.UntilYourNextTurn) {
|
||||
Player player = game.getPlayer(startingControllerId);
|
||||
if (player != null) {
|
||||
if (player.isInGame()) {
|
||||
|
@ -271,19 +272,13 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
@Override
|
||||
public Set<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer) {
|
||||
if (dependendToType != null) {
|
||||
// the dependent classes needs to be an enclosed class for dependent check of continuous effects
|
||||
Set<UUID> dependentTo = null;
|
||||
for (ContinuousEffect effect : allEffectsInLayer) {
|
||||
if (effect.getDependencyTypes().contains(dependendToType)) {
|
||||
if (dependentTo == null) {
|
||||
dependentTo = new HashSet<>();
|
||||
return allEffectsInLayer.stream()
|
||||
.filter(effect -> effect.getDependencyTypes().contains(dependendToType))
|
||||
.map(Effect::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
}
|
||||
dependentTo.add(effect.getId());
|
||||
}
|
||||
}
|
||||
return dependentTo;
|
||||
}
|
||||
return null;
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,40 +27,12 @@
|
|||
*/
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.keyword.SpliceOntoArcaneAbility;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.CostModificationType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.EffectType;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -77,8 +49,11 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ContinuousEffects implements Serializable {
|
||||
|
@ -218,7 +193,7 @@ public class ContinuousEffects implements Serializable {
|
|||
case WhileOnStack:
|
||||
case WhileInGraveyard:
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
if (abilities != null) {
|
||||
if (!abilities.isEmpty()) {
|
||||
for (Ability ability : abilities) {
|
||||
// If e.g. triggerd abilities (non static) created the effect, the ability must not be in usable zone (e.g. Unearth giving Haste effect)
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) {
|
||||
|
@ -358,7 +333,6 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param event
|
||||
* @param game
|
||||
* @return a list of all {@link ReplacementEffect} that apply to the current
|
||||
|
@ -717,7 +691,8 @@ public class ContinuousEffects implements Serializable {
|
|||
spliceAbilities.remove(selectedAbility);
|
||||
}
|
||||
}
|
||||
} while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game));
|
||||
}
|
||||
while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game));
|
||||
controller.revealCards("Spliced cards", cardsToReveal, game);
|
||||
}
|
||||
}
|
||||
|
@ -777,7 +752,7 @@ public class ContinuousEffects implements Serializable {
|
|||
do {
|
||||
HashMap<ReplacementEffect, HashSet<Ability>> rEffects = getApplicableReplacementEffects(event, game);
|
||||
// Remove all consumed effects (ability dependant)
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) {
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext(); ) {
|
||||
ReplacementEffect entry = it1.next();
|
||||
if (consumed.containsKey(entry.getId())) {
|
||||
HashSet<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
|
||||
|
@ -865,9 +840,8 @@ public class ContinuousEffects implements Serializable {
|
|||
if (consumed.containsKey(rEffect.getId())) {
|
||||
HashSet<UUID> set = consumed.get(rEffect.getId());
|
||||
if (rAbility != null) {
|
||||
if (!set.contains(rAbility.getId())) {
|
||||
set.add(rAbility.getId());
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
HashSet<UUID> set = new HashSet<>();
|
||||
|
@ -936,7 +910,7 @@ public class ContinuousEffects implements Serializable {
|
|||
for (ContinuousEffect effect : layer) {
|
||||
if (activeLayerEffects.contains(effect) && !appliedEffects.contains(effect.getId())) { // Effect does still exist and was not applied yet
|
||||
Set<UUID> dependentTo = effect.isDependentTo(layer);
|
||||
if (dependentTo != null && !appliedEffects.containsAll(dependentTo)) {
|
||||
if (!appliedEffects.containsAll(dependentTo)) {
|
||||
waitingEffects.put(effect, dependentTo);
|
||||
continue;
|
||||
}
|
||||
|
@ -959,7 +933,7 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
if (!waitingEffects.isEmpty()) {
|
||||
// check if waiting effects can be applied now
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) {
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<ContinuousEffect, Set<UUID>> entry = iterator.next();
|
||||
if (appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself
|
||||
appliedAbilities = appliedEffectAbilities.get(entry.getKey());
|
||||
|
@ -1039,7 +1013,7 @@ public class ContinuousEffects implements Serializable {
|
|||
for (ContinuousEffect effect : layer) {
|
||||
if (numberOfEffects > 1) { // If an effect is dependent to not applied effects yet of this layer, so wait to apply this effect
|
||||
Set<UUID> dependentTo = effect.isDependentTo(layer);
|
||||
if (dependentTo != null && !appliedEffects.containsAll(dependentTo)) {
|
||||
if (!appliedEffects.containsAll(dependentTo)) {
|
||||
waitingEffects.put(effect, dependentTo);
|
||||
continue;
|
||||
}
|
||||
|
@ -1162,17 +1136,16 @@ public class ContinuousEffects implements Serializable {
|
|||
private void setControllerForEffect(ContinuousEffectsList<?> effects, UUID sourceId, UUID controllerId) {
|
||||
for (Effect effect : effects) {
|
||||
HashSet<Ability> abilities = effects.getAbility(effect.getId());
|
||||
if (abilities != null) {
|
||||
for (Ability ability : abilities) {
|
||||
if (ability.getSourceId() != null) {
|
||||
if (ability.getSourceId().equals(sourceId)) {
|
||||
ability.setControllerId(controllerId);
|
||||
}
|
||||
} else if (!ability.getZone().equals(Zone.COMMAND)) {
|
||||
} else if (ability.getZone() != Zone.COMMAND) {
|
||||
logger.fatal("Continuous effect for ability with no sourceId Ability: " + ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.constants.Duration;
|
||||
|
@ -41,9 +42,8 @@ import mage.game.Game;
|
|||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @param <T>
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList<T> {
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
|
||||
public void removeEndOfTurnEffects() {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (entry.getDuration() == Duration.EndOfTurn) {
|
||||
i.remove();
|
||||
|
@ -84,7 +84,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
|
||||
public void removeEndOfCombatEffects() {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (entry.getDuration() == Duration.EndOfCombat) {
|
||||
i.remove();
|
||||
|
@ -94,7 +94,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
|
||||
public void removeInactiveEffects(Game game) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (isInactive(entry, game)) {
|
||||
i.remove();
|
||||
|
@ -169,7 +169,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
|
||||
public HashSet<Ability> getAbility(UUID effectId) {
|
||||
return effectAbilityMap.get(effectId);
|
||||
return effectAbilityMap.getOrDefault(effectId, new HashSet<>());
|
||||
}
|
||||
|
||||
public void removeEffects(UUID effectIdToRemove, Set<Ability> abilitiesToRemove) {
|
||||
|
@ -178,7 +178,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
abilities.removeAll(abilitiesToRemove);
|
||||
}
|
||||
if (abilities == null || abilities.isEmpty()) {
|
||||
for (Iterator<T> iterator = this.iterator(); iterator.hasNext();) {
|
||||
for (Iterator<T> iterator = this.iterator(); iterator.hasNext(); ) {
|
||||
ContinuousEffect effect = iterator.next();
|
||||
if (effect.getId().equals(effectIdToRemove)) {
|
||||
iterator.remove();
|
||||
|
|
|
@ -97,13 +97,13 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
switch (enterEventType) {
|
||||
case OTHER:
|
||||
return EventType.ENTERS_THE_BATTLEFIELD.equals(event.getType());
|
||||
return EventType.ENTERS_THE_BATTLEFIELD == event.getType();
|
||||
case SELF:
|
||||
return EventType.ENTERS_THE_BATTLEFIELD_SELF.equals(event.getType());
|
||||
return EventType.ENTERS_THE_BATTLEFIELD_SELF == event.getType();
|
||||
case CONTROL:
|
||||
return EventType.ENTERS_THE_BATTLEFIELD_CONTROL.equals(event.getType());
|
||||
return EventType.ENTERS_THE_BATTLEFIELD_CONTROL == event.getType();
|
||||
case COPY:
|
||||
return EventType.ENTERS_THE_BATTLEFIELD_COPY.equals(event.getType());
|
||||
return EventType.ENTERS_THE_BATTLEFIELD_COPY == event.getType();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import mage.players.Player;
|
|||
*/
|
||||
public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectImpl implements PayCostToAttackBlockEffect {
|
||||
|
||||
public static enum RestrictType {
|
||||
public enum RestrictType {
|
||||
|
||||
ATTACK("attack"),
|
||||
ATTACK_AND_BLOCK("attack or block"),
|
||||
|
@ -111,7 +111,7 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
|
|||
case BLOCK:
|
||||
return event.getType().equals(GameEvent.EventType.DECLARE_BLOCKER);
|
||||
case ATTACK_AND_BLOCK:
|
||||
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER || event.getType().equals(GameEvent.EventType.DECLARE_BLOCKER);
|
||||
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER || event.getType() == EventType.DECLARE_BLOCKER;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ public class AddCombatAndMainPhaseEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// 15.07.2006 If it's somehow not a main phase when Fury of the Horde resolves, all it does is untap all creatures that attacked that turn. No new phases are created.
|
||||
if (TurnPhase.PRECOMBAT_MAIN.equals(game.getTurn().getPhaseType())
|
||||
|| TurnPhase.POSTCOMBAT_MAIN.equals(game.getTurn().getPhaseType())) {
|
||||
if (game.getTurn().getPhaseType() == TurnPhase.PRECOMBAT_MAIN
|
||||
|| game.getTurn().getPhaseType() == TurnPhase.POSTCOMBAT_MAIN) {
|
||||
// we can't add two turn modes at once, will add additional post combat on delayed trigger resolution
|
||||
TurnMod combat = new TurnMod(source.getControllerId(), TurnPhase.COMBAT, TurnPhase.POSTCOMBAT_MAIN, false);
|
||||
game.getState().getTurnMods().add(combat);
|
||||
|
|
|
@ -109,16 +109,12 @@ public class CantBeTargetedAttachedEffect extends ContinuousRuleModifyingEffectI
|
|||
return staticText;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
sb.append("Enchanted creature");
|
||||
} else {
|
||||
sb.append("Equipped creature");
|
||||
}
|
||||
sb.append(attachmentType.verb() + " creature");
|
||||
sb.append(" can't be the target of ");
|
||||
sb.append(filterSource.getMessage());
|
||||
if (!duration.toString().isEmpty()) {
|
||||
sb.append(' ');
|
||||
if (duration.equals(Duration.EndOfTurn)) {
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
sb.append("this turn");
|
||||
} else {
|
||||
sb.append(duration.toString());
|
||||
|
|
|
@ -114,7 +114,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
|
|||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
// the check if a permanent untap pahse is already handled is needed if multiple effects are added to prevent untap in next untap step of controller
|
||||
// if we don't check it for every untap step of a turn only one effect would be consumed instead of all be valid for the next untap step
|
||||
if (GameEvent.EventType.UNTAP_STEP.equals(event.getType())) {
|
||||
if (event.getType() == EventType.UNTAP_STEP) {
|
||||
boolean allHandled = true;
|
||||
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
|
|
|
@ -56,7 +56,7 @@ public class DontUntapInControllersUntapStepEnchantedEffect extends ContinuousRu
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (PhaseStep.UNTAP.equals(game.getTurn().getStepType())) {
|
||||
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
|
||||
Permanent enchantment = game.getPermanent(source.getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null && event.getTargetId().equals(enchantment.getAttachedTo())) {
|
||||
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());
|
||||
|
|
|
@ -81,7 +81,7 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (PhaseStep.UNTAP.equals(game.getTurn().getStepType())) {
|
||||
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
|
||||
for (UUID targetId : targetPointer.getTargets(game, source)) {
|
||||
if (event.getTargetId().equals(targetId)) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
|
|
|
@ -107,7 +107,7 @@ public class DontUntapInOpponentsNextUntapStepAllEffect extends ContinuousRuleMo
|
|||
return false;
|
||||
}
|
||||
// remember the turn of the untap step the effect has to be applied
|
||||
if (GameEvent.EventType.UNTAP_STEP.equals(event.getType())) {
|
||||
if (event.getType() == EventType.UNTAP_STEP) {
|
||||
if (game.getActivePlayerId().equals(getTargetPointer().getFirst(game, source))) {
|
||||
if (validForTurnNum == game.getTurnNum()) { // the turn has a second untap step but the effect is already related to the first untap step
|
||||
discard();
|
||||
|
|
|
@ -190,7 +190,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
|
|||
if (player.choose(Outcome.DrawCard, cards, target, game)) {
|
||||
Cards pickedCards = new CardsImpl(target.getTargets());
|
||||
cards.removeAll(pickedCards);
|
||||
if (targetPickedCards.equals(Zone.LIBRARY) && !putOnTopSelected) {
|
||||
if (targetPickedCards == Zone.LIBRARY && !putOnTopSelected) {
|
||||
player.putCardsOnBottomOfLibrary(pickedCards, game, source, true);
|
||||
} else {
|
||||
player.moveCards(pickedCards.getCards(game), targetPickedCards, source, game);
|
||||
|
|
|
@ -40,7 +40,6 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeff
|
||||
*/
|
||||
public class RegenerateAttachedEffect extends ReplacementEffectImpl {
|
||||
|
@ -102,13 +101,8 @@ public class RegenerateAttachedEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setText() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (attachmentType == AttachmentType.AURA) {
|
||||
sb.append("Regenerate enchanted creature");
|
||||
} else if (attachmentType == AttachmentType.EQUIPMENT) {
|
||||
sb.append("Regenerate equipped creature");
|
||||
}
|
||||
staticText = sb.toString();
|
||||
staticText = "Regenerate " + attachmentType.verb().toLowerCase() + " creature";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,11 +44,7 @@ public class AttacksIfAbleAttachedEffect extends RequirementEffect {
|
|||
|
||||
public AttacksIfAbleAttachedEffect(Duration duration, AttachmentType attachmentType) {
|
||||
super(duration);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature attacks each turn if able";
|
||||
} else {
|
||||
this.staticText = "Equipped creature attacks each turn if able";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature attacks each turn if able";
|
||||
}
|
||||
|
||||
public AttacksIfAbleAttachedEffect(final AttacksIfAbleAttachedEffect effect) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class BlocksIfAbleAllEffect extends RequirementEffect {
|
|||
super(duration);
|
||||
staticText = new StringBuilder(filter.getMessage())
|
||||
.append(" block ")
|
||||
.append(duration.equals(Duration.EndOfTurn) ? "this":"each")
|
||||
.append(duration == Duration.EndOfTurn ? "this":"each")
|
||||
.append(" turn if able").toString();
|
||||
this.filter = filter;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
@ -44,11 +43,7 @@ public class BlocksIfAbleAttachedEffect extends RequirementEffect {
|
|||
|
||||
public BlocksIfAbleAttachedEffect(Duration duration, AttachmentType attachmentType) {
|
||||
super(duration);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature blocks each turn if able";
|
||||
} else {
|
||||
this.staticText = "Equipped creature blocks each turn if able";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature blocks each turn if able";
|
||||
}
|
||||
|
||||
public BlocksIfAbleAttachedEffect(final BlocksIfAbleAttachedEffect effect) {
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
|
@ -38,8 +37,9 @@ import mage.filter.common.FilterCreaturePermanent;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Quercitron
|
||||
*/
|
||||
public class CanAttackAsThoughItDidntHaveDefenderAllEffect extends AsThoughEffectImpl {
|
||||
|
@ -81,7 +81,7 @@ public class CanAttackAsThoughItDidntHaveDefenderAllEffect extends AsThoughEffec
|
|||
StringBuilder sb = new StringBuilder(filter.getMessage());
|
||||
sb.append(" can attack ");
|
||||
if (!duration.toString().isEmpty()) {
|
||||
if(Duration.EndOfTurn.equals(duration)) {
|
||||
if (Duration.EndOfTurn == duration) {
|
||||
sb.append("this turn");
|
||||
} else {
|
||||
sb.append(duration.toString());
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CanAttackAsThoughItDidntHaveDefenderSourceEffect extends AsThoughEf
|
|||
public CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration duration) {
|
||||
super(AsThoughEffectType.ATTACK, duration, Outcome.Benefit);
|
||||
staticText = "{this} can attack "
|
||||
+ (duration.equals(Duration.EndOfTurn) ? "this turn " : "")
|
||||
+ (duration == Duration.EndOfTurn ? "this turn " : "")
|
||||
+ "as though it didn't have defender";
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
@ -45,11 +44,7 @@ public class CanBlockOnlyFlyingAttachedEffect extends RestrictionEffect {
|
|||
|
||||
public CanBlockOnlyFlyingAttachedEffect(AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature can block only creatures with flying";
|
||||
} else {
|
||||
this.staticText = "Equipped creature can block only creatures with flying";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature can block only creatures with flying";
|
||||
}
|
||||
|
||||
public CanBlockOnlyFlyingAttachedEffect(final CanBlockOnlyFlyingAttachedEffect effect) {
|
||||
|
|
|
@ -20,11 +20,7 @@ public class CantAttackAloneAttachedEffect extends RestrictionEffect {
|
|||
|
||||
public CantAttackAloneAttachedEffect(AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature can't attack alone";
|
||||
} else {
|
||||
this.staticText = "Equipped creature can't attack alone";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature can't attack alone";
|
||||
}
|
||||
|
||||
public CantAttackAloneAttachedEffect(final CantAttackAloneAttachedEffect effect) {
|
||||
|
|
|
@ -44,11 +44,7 @@ public class CantAttackAttachedEffect extends RestrictionEffect {
|
|||
|
||||
public CantAttackAttachedEffect(AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature can't attack";
|
||||
} else {
|
||||
this.staticText = "Equipped creature can't attack";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature can't attack";
|
||||
}
|
||||
|
||||
public CantAttackAttachedEffect(final CantAttackAttachedEffect effect) {
|
||||
|
|
|
@ -48,7 +48,7 @@ public class CantAttackBlockAllEffect extends RestrictionEffect {
|
|||
StringBuilder sb = new StringBuilder(filter.getMessage()).append(" can't attack or block");
|
||||
if (!duration.toString().isEmpty()) {
|
||||
sb.append(' ');
|
||||
if (duration.equals(Duration.EndOfTurn)) {
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
sb.append(" this turn");
|
||||
} else {
|
||||
sb.append(' ').append(duration.toString());
|
||||
|
|
|
@ -35,18 +35,13 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CantAttackBlockAttachedEffect extends RestrictionEffect {
|
||||
|
||||
public CantAttackBlockAttachedEffect(AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature can't attack or block";
|
||||
} else {
|
||||
this.staticText = "Equipped creature can't attack or block";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature can't attack or block";
|
||||
}
|
||||
|
||||
public CantAttackBlockAttachedEffect(final CantAttackBlockAttachedEffect effect) {
|
||||
|
|
|
@ -46,8 +46,8 @@ public class CantAttackBlockUnlessPaysAttachedEffect extends PayCostToAttackBloc
|
|||
|
||||
public CantAttackBlockUnlessPaysAttachedEffect(ManaCosts manaCosts, AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, manaCosts);
|
||||
staticText = (attachmentType.equals(AttachmentType.AURA) ? "Enchanted " : "Equipped ")
|
||||
+ "creature can't attack or block unless its controller pays "
|
||||
staticText = attachmentType.verb()
|
||||
+ " creature can't attack or block unless its controller pays "
|
||||
+ (manaCosts == null ? "" : manaCosts.getText());
|
||||
}
|
||||
|
||||
|
@ -59,10 +59,10 @@ public class CantAttackBlockUnlessPaysAttachedEffect extends PayCostToAttackBloc
|
|||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Permanent enchantment = game.getPermanent(source.getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
if (event.getType().equals(EventType.DECLARE_ATTACKER)) {
|
||||
if (event.getType() == EventType.DECLARE_ATTACKER) {
|
||||
return event.getSourceId().equals(enchantment.getAttachedTo());
|
||||
}
|
||||
if (event.getType().equals(EventType.DECLARE_BLOCKER)) {
|
||||
if (event.getType() == EventType.DECLARE_BLOCKER) {
|
||||
return event.getSourceId().equals(enchantment.getAttachedTo());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class CantAttackBlockUnlessPaysSourceEffect extends PayCostToAttackBlockE
|
|||
super(Duration.WhileOnBattlefield, Outcome.Detriment, restrictType, cost);
|
||||
staticText = "{this} can't " + restrictType.toString() + " unless you "
|
||||
+ cost == null ? "" : cost.getText()
|
||||
+ (restrictType.equals(RestrictType.ATTACK) ? " <i>(This cost is paid as attackers are declared.)</i>" : "");
|
||||
+ (restrictType == RestrictType.ATTACK ? " <i>(This cost is paid as attackers are declared.)</i>" : "");
|
||||
}
|
||||
|
||||
public CantAttackBlockUnlessPaysSourceEffect(ManaCosts manaCosts, RestrictType restrictType) {
|
||||
|
@ -62,10 +62,10 @@ public class CantAttackBlockUnlessPaysSourceEffect extends PayCostToAttackBlockE
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (!restrictType.equals(RestrictType.BLOCK) && event.getType().equals(EventType.DECLARE_ATTACKER)) {
|
||||
if (!(restrictType == RestrictType.BLOCK) && event.getType() == EventType.DECLARE_ATTACKER) {
|
||||
return event.getSourceId().equals(source.getSourceId());
|
||||
}
|
||||
if (!restrictType.equals(RestrictType.ATTACK) && event.getType().equals(EventType.DECLARE_BLOCKER)) {
|
||||
if (!(restrictType == RestrictType.ATTACK) && event.getType() == EventType.DECLARE_BLOCKER) {
|
||||
return event.getSourceId().equals(source.getSourceId());
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -46,11 +46,7 @@ public class CantAttackControllerAttachedEffect extends RestrictionEffect {
|
|||
|
||||
public CantAttackControllerAttachedEffect(AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature can't attack you or a planeswalker you control";
|
||||
} else {
|
||||
this.staticText = "Equipped creature can't attack you or a planeswalker you control";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature can't attack you or a planeswalker you control";
|
||||
}
|
||||
|
||||
public CantAttackControllerAttachedEffect(final CantAttackControllerAttachedEffect effect) {
|
||||
|
|
|
@ -46,8 +46,8 @@ public class CantAttackUnlessPaysAttachedEffect extends PayCostToAttackBlockEffe
|
|||
|
||||
public CantAttackUnlessPaysAttachedEffect(ManaCosts manaCosts, AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK, manaCosts);
|
||||
staticText = (attachmentType.equals(AttachmentType.AURA) ? "Enchanted " : "Equipped ")
|
||||
+ "creature can't attack unless its controller pays "
|
||||
staticText = attachmentType.verb()
|
||||
+ " creature can't attack unless its controller pays "
|
||||
+ (manaCosts == null ? "" : manaCosts.getText());
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ public class CantAttackUnlessPaysAttachedEffect extends PayCostToAttackBlockEffe
|
|||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Permanent enchantment = game.getPermanent(source.getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
if (event.getType().equals(EventType.DECLARE_ATTACKER)) {
|
||||
if (event.getType() == EventType.DECLARE_ATTACKER) {
|
||||
return event.getSourceId().equals(enchantment.getAttachedTo());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class CantAttackYouAllEffect extends RestrictionEffect {
|
|||
this.alsoPlaneswalker = alsoPlaneswalker;
|
||||
staticText = filterAttacker.getMessage() + " can't attack you"
|
||||
+ (alsoPlaneswalker ? " or a planeswalker you control" : "")
|
||||
+ (duration.equals(Duration.UntilYourNextTurn) ? " until your next turn" : "");
|
||||
+ (duration == Duration.UntilYourNextTurn ? " until your next turn" : "");
|
||||
}
|
||||
|
||||
CantAttackYouAllEffect(final CantAttackYouAllEffect effect) {
|
||||
|
|
|
@ -47,7 +47,7 @@ public class CantBeBlockedAllEffect extends RestrictionEffect {
|
|||
this.filter = filter;
|
||||
|
||||
this.staticText = filter.getMessage() + " can't be blocked";
|
||||
if (duration.equals(Duration.EndOfTurn)) {
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
this.staticText += " this turn";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,11 +42,7 @@ public class CantBeBlockedAttachedEffect extends RestrictionEffect {
|
|||
|
||||
public CantBeBlockedAttachedEffect(AttachmentType attachmentType) {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
this.staticText = "Enchanted creature can't be blocked";
|
||||
} else {
|
||||
this.staticText = "Equipped creature can't be blocked";
|
||||
}
|
||||
this.staticText = attachmentType.verb() + " creature can't be blocked";
|
||||
}
|
||||
|
||||
public CantBeBlockedAttachedEffect(CantBeBlockedAttachedEffect effect) {
|
||||
|
|
|
@ -36,7 +36,6 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CantBeBlockedByCreaturesAttachedEffect extends RestrictionEffect {
|
||||
|
@ -47,13 +46,9 @@ public class CantBeBlockedByCreaturesAttachedEffect extends RestrictionEffect {
|
|||
super(duration);
|
||||
this.filter = filter;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
sb.append("Enchanted ");
|
||||
} else {
|
||||
sb.append("Equipped ");
|
||||
}
|
||||
staticText = sb.append("creature can't be blocked ")
|
||||
.append(filter.getMessage().startsWith("except by") ? "":"by ").append(filter.getMessage()).toString();
|
||||
sb.append(attachmentType.verb());
|
||||
staticText = sb.append(" creature can't be blocked ")
|
||||
.append(filter.getMessage().startsWith("except by") ? "" : "by ").append(filter.getMessage()).toString();
|
||||
}
|
||||
|
||||
public CantBeBlockedByCreaturesAttachedEffect(final CantBeBlockedByCreaturesAttachedEffect effect) {
|
||||
|
|
|
@ -56,7 +56,7 @@ public class CantBeBlockedByOneAllEffect extends ContinuousEffectImpl {
|
|||
this.amount = amount;
|
||||
this.filter = filter;
|
||||
StringBuilder sb = new StringBuilder("each ").append(filter.getMessage()).append(" can't be blocked ");
|
||||
if (duration.equals(Duration.EndOfTurn)) {
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
sb.append("this turn ");
|
||||
}
|
||||
sb.append("except by ").append(CardUtil.numberToText(amount)).append(" or more creatures");
|
||||
|
|
|
@ -54,7 +54,7 @@ public class CantBeBlockedByOneAttachedEffect extends ContinuousEffectImpl {
|
|||
super(duration, Outcome.Benefit);
|
||||
this.amount = amount;
|
||||
this.attachmentType = attachmentType;
|
||||
staticText = (attachmentType.equals(AttachmentType.AURA) ? "Enchanted" : "Equipped") + " creature can't be blocked except by " + amount + " or more creatures";
|
||||
staticText = attachmentType.verb() + " creature can't be blocked except by " + amount + " or more creatures";
|
||||
}
|
||||
|
||||
public CantBeBlockedByOneAttachedEffect(final CantBeBlockedByOneAttachedEffect effect) {
|
||||
|
|
|
@ -93,7 +93,7 @@ public class CantBeBlockedByTargetSourceEffect extends RestrictionEffect {
|
|||
sb.append("Target ");
|
||||
}
|
||||
sb.append(target.getTargetName()).append(" can't block {this}");
|
||||
if (duration.equals(Duration.EndOfTurn)) {
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
sb.append(" this turn");
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ public class CantBeBlockedSourceEffect extends RestrictionEffect {
|
|||
public CantBeBlockedSourceEffect(Duration duration) {
|
||||
super(duration);
|
||||
this.staticText = "{this} can't be blocked";
|
||||
if (Duration.EndOfTurn.equals(this.duration)) {
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
this.staticText += " this turn";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class CantBlockAllEffect extends RestrictionEffect {
|
|||
public String getText(Mode mode) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(filter.getMessage()).append(" can't block");
|
||||
if (Duration.EndOfTurn.equals(this.duration)) {
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
sb.append(" this turn");
|
||||
}
|
||||
return sb.toString();
|
||||
|
|
|
@ -56,11 +56,8 @@ public class CantBlockAttachedEffect extends RestrictionEffect {
|
|||
super(duration);
|
||||
this.filter = filter;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||
sb.append("Enchanted creature can't block");
|
||||
} else {
|
||||
sb.append("Equipped creature can't block");
|
||||
}
|
||||
sb.append(attachmentType.verb());
|
||||
sb.append(" creature can't block");
|
||||
if (!filter.getMessage().equals("creature")) {
|
||||
sb.append(' ').append(filter.getMessage());
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public class CantBlockSourceEffect extends RestrictionEffect {
|
|||
public CantBlockSourceEffect(Duration duration) {
|
||||
super(duration);
|
||||
this.staticText = "{this} can't block";
|
||||
if (duration.equals(Duration.EndOfTurn)) {
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
this.staticText += " this turn";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ public class CantBlockTargetEffect extends RestrictionEffect {
|
|||
}
|
||||
|
||||
sb.append(" can't block");
|
||||
if (Duration.EndOfTurn.equals(this.duration)) {
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
sb.append(" this turn");
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.Duration;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -37,7 +38,6 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class MustBeBlockedByAllAttachedEffect extends RequirementEffect {
|
||||
|
@ -51,7 +51,7 @@ public class MustBeBlockedByAllAttachedEffect extends RequirementEffect {
|
|||
public MustBeBlockedByAllAttachedEffect(Duration duration, AttachmentType attachmentType) {
|
||||
super(duration);
|
||||
this.attachmentType = attachmentType;
|
||||
staticText = "All creatures able to block " + (attachmentType.equals(AttachmentType.AURA) ? "enchanted":"equipped") + " creature do so";
|
||||
staticText = "All creatures able to block " + attachmentType.verb().toLowerCase() + " creature do so";
|
||||
}
|
||||
|
||||
public MustBeBlockedByAllAttachedEffect(final MustBeBlockedByAllAttachedEffect effect) {
|
||||
|
@ -84,7 +84,7 @@ public class MustBeBlockedByAllAttachedEffect extends RequirementEffect {
|
|||
public UUID mustBlockAttacker(Ability source, Game game) {
|
||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
||||
if (attachment != null && attachment.getAttachedTo() != null) {
|
||||
return attachment.getAttachedTo() ;
|
||||
return attachment.getAttachedTo();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class MustBeBlockedByAllTargetEffect extends RequirementEffect {
|
|||
public MustBeBlockedByAllTargetEffect(Duration duration) {
|
||||
super(duration);
|
||||
staticText = new StringBuilder("All creatures able to block target creature ")
|
||||
.append(this.getDuration().equals(Duration.EndOfTurn) ? "this turn ":"")
|
||||
.append(this.getDuration() == Duration.EndOfTurn ? "this turn ":"")
|
||||
.append("do so").toString();
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ public class MustBeBlockedByAllTargetEffect extends RequirementEffect {
|
|||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
Permanent attackingCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||
if (attackingCreature != null && attackingCreature.isAttacking()) {
|
||||
if (!source.getAbilityType().equals(AbilityType.STATIC)) {
|
||||
if (source.getAbilityType() != AbilityType.STATIC) {
|
||||
BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get("BlockedAttackerWatcher");
|
||||
if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attackingCreature, permanent, game)) {
|
||||
// has already blocked this turn, so no need to do again
|
||||
|
|
|
@ -84,11 +84,7 @@ public class AddCardColorAttachedEffect extends ContinuousEffectImpl {
|
|||
|
||||
private void setText() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (attachmentType == AttachmentType.AURA)
|
||||
sb.append("Enchanted");
|
||||
else if (attachmentType == AttachmentType.EQUIPMENT)
|
||||
sb.append("Equipped");
|
||||
|
||||
sb.append(attachmentType.verb());
|
||||
sb.append(" creature is a ").append(addedColor.getDescription()).append(" in addition to its colors");
|
||||
staticText = sb.toString();
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public class AddCardSubTypeTargetEffect extends ContinuousEffectImpl {
|
|||
target.getSubtype(game).add(addedSubType);
|
||||
}
|
||||
} else {
|
||||
if (Duration.Custom.equals(duration)) {
|
||||
if (duration == Duration.Custom) {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,11 +72,8 @@ public class AddCardSubtypeAttachedEffect extends ContinuousEffectImpl {
|
|||
|
||||
private void setText() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (attachmentType == AttachmentType.AURA)
|
||||
sb.append("Enchanted");
|
||||
else if (attachmentType == AttachmentType.EQUIPMENT)
|
||||
sb.append("Equipped");
|
||||
|
||||
sb.append(attachmentType.verb());
|
||||
sb.append(" creature becomes ").append(addedSubtype).append(" in addition to its other types"); //TODO add attacked card type detection
|
||||
staticText = sb.toString();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue