diff --git a/.gitignore b/.gitignore
index c8e97c13349..227cae92d1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,6 +82,7 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target
*.classpath
*.iml
+hs_err*.log
/submitted
/Mage.Server/config/ai.please.cast.this.txt
diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml
index cb841e6e280..52ff1498269 100644
--- a/Mage.Client/pom.xml
+++ b/Mage.Client/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
org.mage
diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt
index db223b403ff..a4379a04bbd 100644
--- a/Mage.Client/serverlist.txt
+++ b/Mage.Client/serverlist.txt
@@ -1,6 +1,6 @@
XMage.de 1 (Europe/Germany) fast :xmage.de:17171
woogerworks (North America/USA) :xmage.woogerworks.info:17171
-XMage.info 1 (Europe/France) new network code -> see forum :176.31.186.181:17171
+XMage Testserver (Europe/France) 1.4.8v0 :176.31.186.181:17171
XMage BR (South America/Brazil) :ec2-54-233-67-0.sa-east-1.compute.amazonaws.com:17171
Seedds Server (Asia) :115.29.203.80:17171
localhost -> connect to your local server (must be started):localhost:17171
diff --git a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java
index 9840c82582b..2f307ea2f78 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java
@@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com.
*/
-/*
+ /*
* TableWaitingDialog.java
*
* Created on Dec 16, 2009, 10:27:44 AM
@@ -68,7 +68,7 @@ public class TableWaitingDialog extends MageDialog {
private Session session;
private final TableWaitModel tableWaitModel;
private UpdateSeatsTask updateTask;
- private static final int[] defaultColumnsWidth = {20, 50, 100, 100};
+ private static final int[] defaultColumnsWidth = {20, 50, 100, 100, 100};
/**
* Creates new form TableWaitingDialog
@@ -268,10 +268,8 @@ public class TableWaitingDialog extends MageDialog {
if (session.startMatch(roomId, tableId)) {
closeDialog();
}
- } else {
- if (session.startTournament(roomId, tableId)) {
- closeDialog();
- }
+ } else if (session.startTournament(roomId, tableId)) {
+ closeDialog();
}
}//GEN-LAST:event_btnStartActionPerformed
@@ -319,7 +317,7 @@ public class TableWaitingDialog extends MageDialog {
class TableWaitModel extends AbstractTableModel {
- private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type"};
+ private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type", "History"};
private SeatView[] seats = new SeatView[0];
public void loadData(TableView table) {
@@ -353,6 +351,8 @@ class TableWaitModel extends AbstractTableModel {
return seats[arg0].getPlayerName();
case 3:
return seats[arg0].getPlayerType();
+ case 4:
+ return seats[arg0].getHistory();
}
}
return "";
diff --git a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java
index c94ed0dfa14..01e872dc5a7 100644
--- a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java
+++ b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java
@@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com.
*/
-/*
+ /*
* PlayerPanel.java
*
* Created on Nov 18, 2009, 3:01:31 PM
@@ -288,7 +288,8 @@ public class PlayerPanelExt extends javax.swing.JPanel {
basicTooltipText = "Name: " + player.getName()
+ "
Country: " + countryname
+ "
Deck hash code: " + player.getDeckHashCode()
- + "
Wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)";
+ + "
This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)"
+ + (player.getUserData() == null ? "" : "
History: " + player.getUserData().getHistory());
}
// Extend tooltip
StringBuilder tooltipText = new StringBuilder(basicTooltipText);
diff --git a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java
index 0aa6e20af9c..795a8618cdf 100644
--- a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java
+++ b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java
@@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com.
*/
-/*
+ /*
* ChatPanel.java
*
* Created on 15-Dec-2009, 11:04:31 PM
@@ -61,7 +61,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
private final List players = new ArrayList<>();
private final UserTableModel userTableModel;
- private static final int[] defaultColumnsWidth = {20, 100, 100, 100, 80, 80};
+ private static final int[] DEFAULT_COLUMNS_WIDTH = {20, 100, 100, 80, 80};
/*
@@ -78,7 +78,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
jTablePlayers.setForeground(Color.white);
jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel));
- TableUtil.setColumnWidthAndOrder(jTablePlayers, defaultColumnsWidth, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER);
+ TableUtil.setColumnWidthAndOrder(jTablePlayers, DEFAULT_COLUMNS_WIDTH, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER);
jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer());
jScrollPaneTalk.setSystemMessagesPane(colorPaneSystem);
@@ -118,7 +118,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
class UserTableModel extends AbstractTableModel {
- private final String[] columnNames = new String[]{"Loc", "Players", "History", "Info", "Games", "Connection"};
+ private final String[] columnNames = new String[]{"Loc", "Players", "History", "Games", "Connection"};
private UsersView[] players = new UsersView[0];
public void loadData(Collection roomUserInfoList) throws MageRemoteException {
@@ -128,7 +128,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
TableColumnModel tcm = th.getColumnModel();
tcm.getColumn(jTablePlayers.convertColumnIndexToView(1)).setHeaderValue("Players (" + this.players.length + ")");
- tcm.getColumn(jTablePlayers.convertColumnIndexToView(4)).setHeaderValue(
+ tcm.getColumn(jTablePlayers.convertColumnIndexToView(3)).setHeaderValue(
"Games " + roomUserInfo.getNumberActiveGames()
+ (roomUserInfo.getNumberActiveGames() != roomUserInfo.getNumberGameThreads() ? " (T:" + roomUserInfo.getNumberGameThreads() : " (")
+ " limit: " + roomUserInfo.getNumberMaxGames() + ")");
@@ -156,10 +156,8 @@ public class PlayersChatPanel extends javax.swing.JPanel {
case 2:
return players[arg0].getHistory();
case 3:
- return players[arg0].getInfoState();
- case 4:
return players[arg0].getInfoGames();
- case 5:
+ case 4:
return players[arg0].getInfoPing();
}
return "";
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java
index 42b67cf7a57..32462dfa601 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java
@@ -1,12 +1,10 @@
/**
* DownloadJob.java
- *
+ *
* Created on 25.08.2010
*/
-
package org.mage.plugins.card.dl;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -21,25 +19,26 @@ import org.mage.plugins.card.dl.beans.properties.Property;
import org.mage.plugins.card.dl.lm.AbstractLaternaBean;
import org.mage.plugins.card.utils.CardImageUtils;
-
/**
* The class DownloadJob.
- *
+ *
* @version V0.0 25.08.2010
* @author Clemens Koza
*/
public class DownloadJob extends AbstractLaternaBean {
+
public static enum State {
+
NEW, WORKING, FINISHED, ABORTED;
}
- private final String name;
- private final Source source;
- private final Destination destination;
- private final Property state = properties.property("state", State.NEW);
- private final Property message = properties.property("message");
- private final Property error = properties.property("error");
- private final BoundedRangeModel progress = new DefaultBoundedRangeModel();
+ private final String name;
+ private final Source source;
+ private final Destination destination;
+ private final Property state = properties.property("state", State.NEW);
+ private final Property message = properties.property("message");
+ private final Property error = properties.property("error");
+ private final BoundedRangeModel progress = new DefaultBoundedRangeModel();
public DownloadJob(String name, Source source, Destination destination) {
this.name = name;
@@ -48,7 +47,9 @@ public class DownloadJob extends AbstractLaternaBean {
}
/**
- * Sets the job's state. If the state is {@link State#ABORTED}, it instead sets the error to "ABORTED"
+ * Sets the job's state. If the state is {@link State#ABORTED}, it instead
+ * sets the error to "ABORTED"
+ *
* @param state
*/
public void setState(State state) {
@@ -60,8 +61,9 @@ public class DownloadJob extends AbstractLaternaBean {
}
/**
- * Sets the job's state to {@link State#ABORTED} and the error message to the given message. Logs a warning
- * with the given message.
+ * Sets the job's state to {@link State#ABORTED} and the error message to
+ * the given message. Logs a warning with the given message.
+ *
* @param message
*/
public void setError(String message) {
@@ -69,8 +71,9 @@ public class DownloadJob extends AbstractLaternaBean {
}
/**
- * Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the
- * given exception.
+ * Sets the job's state to {@link State#ABORTED} and the error to the given
+ * exception. Logs a warning with the given exception.
+ *
* @param error
*/
public void setError(Exception error) {
@@ -78,14 +81,15 @@ public class DownloadJob extends AbstractLaternaBean {
}
/**
- * Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the
- * given message and exception.
+ * Sets the job's state to {@link State#ABORTED} and the error to the given
+ * exception. Logs a warning with the given message and exception.
+ *
* @param message
* @param error
*/
public void setError(String message, Exception error) {
if (message == null) {
-
+
message = "Download of " + this.getName() + "from " + this.getSource().toString() + " caused error: " + error.toString();
}
// log.warn(message, error);
@@ -97,6 +101,7 @@ public class DownloadJob extends AbstractLaternaBean {
/**
* Sets the job's message.
+ *
* @param message
*/
public void setMessage(String message) {
@@ -119,7 +124,6 @@ public class DownloadJob extends AbstractLaternaBean {
return message.getValue();
}
-
public String getName() {
return name;
}
@@ -163,9 +167,9 @@ public class DownloadJob extends AbstractLaternaBean {
@Override
public String toString() {
- return proxy != null ? proxy.type().toString()+" " :"" + url;
+ return proxy != null ? proxy.type().toString() + " " : "" + url;
}
-
+
};
}
@@ -189,11 +193,11 @@ public class DownloadJob extends AbstractLaternaBean {
public int length() throws IOException {
return getConnection().getContentLength();
}
-
+
@Override
public String toString() {
- return proxy != null ? proxy.type().toString()+" " :"" + url;
- }
+ return proxy != null ? proxy.type().toString() + " " : "" + url;
+ }
};
}
@@ -213,6 +217,14 @@ public class DownloadJob extends AbstractLaternaBean {
return new FileOutputStream(file);
}
+ @Override
+ public boolean isValid() throws IOException {
+ if (file.isFile()) {
+ return file.length() > 0;
+ }
+ return false;
+ }
+
@Override
public boolean exists() {
return file.isFile();
@@ -228,16 +240,20 @@ public class DownloadJob extends AbstractLaternaBean {
}
public interface Source {
+
InputStream open() throws IOException;
int length() throws IOException;
}
public interface Destination {
+
OutputStream open() throws IOException;
boolean exists() throws IOException;
+ boolean isValid() throws IOException;
+
void delete() throws IOException;
}
}
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java
index 1ff78368e1f..ca5160a71db 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java
@@ -1,9 +1,8 @@
/**
* Downloader.java
- *
+ *
* Created on 25.08.2010
*/
-
package org.mage.plugins.card.dl;
import java.io.BufferedInputStream;
@@ -29,10 +28,9 @@ import org.mage.plugins.card.dl.DownloadJob.Source;
import org.mage.plugins.card.dl.DownloadJob.State;
import org.mage.plugins.card.dl.lm.AbstractLaternaBean;
-
/**
* The class Downloader.
- *
+ *
* @version V0.0 25.08.2010
* @author Clemens Koza
*/
@@ -40,16 +38,16 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
private static final Logger logger = Logger.getLogger(Downloader.class);
- private final List jobs = properties.list("jobs");
+ private final List jobs = properties.list("jobs");
private final Channel channel = new MemoryChannel<>();
- private final ExecutorService pool = Executors.newCachedThreadPool();
- private final List fibers = new ArrayList<>();
+ private final ExecutorService pool = Executors.newCachedThreadPool();
+ private final List fibers = new ArrayList<>();
public Downloader() {
PoolFiberFactory f = new PoolFiberFactory(pool);
//subscribe multiple fibers for parallel execution
- for(int i = 0, numThreads = 10; i < numThreads; i++) {
+ for (int i = 0, numThreads = 10; i < numThreads; i++) {
Fiber fiber = f.create();
fiber.start();
fibers.add(fiber);
@@ -59,15 +57,15 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
@Override
public void dispose() {
- for(DownloadJob j:getJobs()) {
- switch(j.getState()) {
+ for (DownloadJob j : getJobs()) {
+ switch (j.getState()) {
case NEW:
case WORKING:
j.setState(State.ABORTED);
}
}
- for(Fiber f:fibers) {
+ for (Fiber f : fibers) {
f.dispose();
}
pool.shutdown();
@@ -84,10 +82,10 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
}
public void add(DownloadJob job) {
- if(job.getState() == State.WORKING) {
+ if (job.getState() == State.WORKING) {
throw new IllegalArgumentException("Job already running");
}
- if(job.getState() == State.FINISHED) {
+ if (job.getState() == State.FINISHED) {
throw new IllegalArgumentException("Job already finished");
}
job.setState(State.NEW);
@@ -100,15 +98,17 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
}
/**
- * Performs the download job: Transfers data from {@link Source} to {@link Destination} and updates the
- * download job's state to reflect the progress.
+ * Performs the download job: Transfers data from {@link Source} to
+ * {@link Destination} and updates the download job's state to reflect the
+ * progress.
*/
private class DownloadCallback implements Callback {
+
@Override
public void onMessage(DownloadJob job) {
//the job won't be processed by multiple threads
- synchronized(job) {
- if(job.getState() != State.NEW) {
+ synchronized (job) {
+ if (job.getState() != State.NEW) {
return;
}
job.setState(State.WORKING);
@@ -118,10 +118,17 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
Destination dst = job.getDestination();
BoundedRangeModel progress = job.getProgress();
- if(dst.exists()) {
+ if (dst.isValid()) {
progress.setMaximum(1);
progress.setValue(1);
} else {
+ if (dst.exists()) {
+ try {
+ dst.delete();
+ } catch (IOException ex1) {
+ logger.warn("While deleting not valid file", ex1);
+ }
+ }
progress.setMaximum(src.length());
InputStream is = new BufferedInputStream(src.open());
try {
@@ -129,45 +136,45 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
try {
byte[] buf = new byte[8 * 1024];
int total = 0;
- for(int len; (len = is.read(buf)) != -1;) {
- if(job.getState() == State.ABORTED) {
+ for (int len; (len = is.read(buf)) != -1;) {
+ if (job.getState() == State.ABORTED) {
throw new IOException("Job was aborted");
}
progress.setValue(total += len);
os.write(buf, 0, len);
}
- } catch(IOException ex) {
+ } catch (IOException ex) {
try {
dst.delete();
- } catch(IOException ex1) {
+ } catch (IOException ex1) {
logger.warn("While deleting", ex1);
}
throw ex;
} finally {
try {
os.close();
- } catch(IOException ex) {
+ } catch (IOException ex) {
logger.warn("While closing", ex);
}
}
} finally {
try {
is.close();
- } catch(IOException ex) {
+ } catch (IOException ex) {
logger.warn("While closing", ex);
}
}
}
job.setState(State.FINISHED);
- } catch(ConnectException ex) {
+ } catch (ConnectException ex) {
String message;
if (ex.getMessage() != null) {
message = ex.getMessage();
} else {
message = "Unknown error";
}
- logger.warn("Error resource download " + job.getName() +" from "+ job.getSource().toString() + ": " + message);
- } catch(IOException ex) {
+ logger.warn("Error resource download " + job.getName() + " from " + job.getSource().toString() + ": " + message);
+ } catch (IOException ex) {
job.setError(ex);
}
}
diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml
index fa29a8edbf5..bacf94c9a8c 100644
--- a/Mage.Common/pom.xml
+++ b/Mage.Common/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
mage-common
diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java
index c409c179799..e5acc0701b2 100644
--- a/Mage.Common/src/mage/utils/MageVersion.java
+++ b/Mage.Common/src/mage/utils/MageVersion.java
@@ -40,8 +40,8 @@ public class MageVersion implements Serializable, Comparable {
*/
public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4;
- public final static int MAGE_VERSION_PATCH = 7;
- public final static String MAGE_VERSION_MINOR_PATCH = "v1";
+ public final static int MAGE_VERSION_PATCH = 8;
+ public final static String MAGE_VERSION_MINOR_PATCH = "v0";
public final static String MAGE_VERSION_INFO = "";
private final int major;
diff --git a/Mage.Common/src/mage/view/SeatView.java b/Mage.Common/src/mage/view/SeatView.java
index d812dadebd6..49d53db0917 100644
--- a/Mage.Common/src/mage/view/SeatView.java
+++ b/Mage.Common/src/mage/view/SeatView.java
@@ -44,6 +44,7 @@ public class SeatView implements Serializable {
private UUID playerId;
private final String playerName;
private final String playerType;
+ private final String history;
public SeatView(Seat seat) {
if (seat.getPlayer() != null) {
@@ -51,13 +52,16 @@ public class SeatView implements Serializable {
this.playerName = seat.getPlayer().getName();
if (seat.getPlayer().getUserData() == null) {
this.flagName = UserData.getDefaultFlagName();
+ this.history = "";
} else {
this.flagName = seat.getPlayer().getUserData().getFlagName();
+ this.history = seat.getPlayer().getUserData().getHistory();
}
} else {
// Empty seat
this.playerName = "";
this.flagName = "";
+ this.history = "";
}
this.playerType = seat.getPlayerType();
}
@@ -78,4 +82,8 @@ public class SeatView implements Serializable {
return flagName;
}
+ public String getHistory() {
+ return history;
+ }
+
}
diff --git a/Mage.Common/src/mage/view/UsersView.java b/Mage.Common/src/mage/view/UsersView.java
index 6e9d649461b..40a39fc41e8 100644
--- a/Mage.Common/src/mage/view/UsersView.java
+++ b/Mage.Common/src/mage/view/UsersView.java
@@ -24,7 +24,7 @@
* 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.view;
import java.io.Serializable;
@@ -40,15 +40,13 @@ public class UsersView implements Serializable {
private final String flagName;
private final String userName;
private final String history;
- private final String infoState;
private final String infoGames;
private final String infoPing;
- public UsersView(String flagName, String userName, String history, String infoState, String infoGames, String infoPing) {
+ public UsersView(String flagName, String userName, String history, String infoGames, String infoPing) {
this.flagName = flagName;
this.history = history;
this.userName = userName;
- this.infoState = infoState;
this.infoGames = infoGames;
this.infoPing = infoPing;
}
@@ -65,10 +63,6 @@ public class UsersView implements Serializable {
return history;
}
- public String getInfoState() {
- return infoState;
- }
-
public String getInfoGames() {
return infoGames;
}
diff --git a/Mage.Plugins/Mage.Counter.Plugin/pom.xml b/Mage.Plugins/Mage.Counter.Plugin/pom.xml
index 79cf14afd4b..3f49e74f486 100644
--- a/Mage.Plugins/Mage.Counter.Plugin/pom.xml
+++ b/Mage.Plugins/Mage.Counter.Plugin/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-plugins
- 1.4.7
+ 1.4.8
mage-counter-plugin
diff --git a/Mage.Plugins/pom.xml b/Mage.Plugins/pom.xml
index a840fe9b784..7e08821960b 100644
--- a/Mage.Plugins/pom.xml
+++ b/Mage.Plugins/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
mage-plugins
diff --git a/Mage.Server.Console/pom.xml b/Mage.Server.Console/pom.xml
index 68d434ffc0d..38af4642cfd 100644
--- a/Mage.Server.Console/pom.xml
+++ b/Mage.Server.Console/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
org.mage
diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml
index d153187b1a7..a115b6be9f8 100644
--- a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml
+++ b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-deck-constructed
diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml
index dda300f0f17..d750b4d3853 100644
--- a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml
+++ b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-deck-limited
diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml
index 7c6895b1879..7d9a8e7549d 100644
--- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml
+++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-game-commanderduel
diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml
index 35f9bb38f06..35ca14148ac 100644
--- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml
+++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-game-commanderfreeforall
diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml
index 620ef0c2c1b..48a762df5d8 100644
--- a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml
+++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-game-freeforall
diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml
index f7227cb7084..60d8c59dd06 100644
--- a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml
+++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-game-momirduel
diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml
index 01be0a566b7..45fd9cc0cd9 100644
--- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml
+++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-game-tinyleadersduel
diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml
index b8c5c5a6693..f0fef0763f8 100644
--- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml
+++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-game-twoplayerduel
diff --git a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml
index 3fa32de395f..3f199c86b60 100644
--- a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml
+++ b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-player-ai-draftbot
diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml
index 4a2601cde07..33ed3edb207 100644
--- a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml
+++ b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-player-ai-ma
diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml
index 84682eb0381..ef1eec05151 100644
--- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml
+++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-player-ai
diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml
index e4a3c7bd26b..d6b9f5c2391 100644
--- a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml
+++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-player-ai-mcts
diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml
index ba11e38a376..94f05621aad 100644
--- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml
+++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-player-aiminimax
diff --git a/Mage.Server.Plugins/Mage.Player.Human/pom.xml b/Mage.Server.Plugins/Mage.Player.Human/pom.xml
index c7e3d8b2eae..e26cbefa9ce 100644
--- a/Mage.Server.Plugins/Mage.Player.Human/pom.xml
+++ b/Mage.Server.Plugins/Mage.Player.Human/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-player-human
diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java
index 48895f9e727..9dc9d7ff025 100644
--- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java
+++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java
@@ -358,15 +358,13 @@ public class HumanPlayer extends PlayerImpl {
}
}
}
- } else {
- if (target.canTarget(response.getUUID(), game)) {
- if (target.getTargets().contains(response.getUUID())) { // if already included remove it with
- target.remove(response.getUUID());
- } else {
- target.addTarget(response.getUUID(), null, game);
- if (target.doneChosing()) {
- return true;
- }
+ } else if (target.canTarget(response.getUUID(), game)) {
+ if (target.getTargets().contains(response.getUUID())) { // if already included remove it with
+ target.remove(response.getUUID());
+ } else {
+ target.addTarget(response.getUUID(), null, game);
+ if (target.doneChosing()) {
+ return true;
}
}
}
@@ -530,12 +528,10 @@ public class HumanPlayer extends PlayerImpl {
if (response.getUUID() != null) {
if (target.getTargets().contains(response.getUUID())) { // if already included remove it
target.remove(response.getUUID());
- } else {
- if (target.canTarget(response.getUUID(), cards, game)) {
- target.addTarget(response.getUUID(), source, game);
- if (target.doneChosing()) {
- return true;
- }
+ } else if (target.canTarget(response.getUUID(), cards, game)) {
+ target.addTarget(response.getUUID(), source, game);
+ if (target.doneChosing()) {
+ return true;
}
}
} else {
@@ -1065,10 +1061,8 @@ public class HumanPlayer extends PlayerImpl {
// does not block yet and can block or can block more attackers
if (filter.match(blocker, null, playerId, game)) {
selectCombatGroup(defendingPlayerId, blocker.getId(), game);
- } else {
- if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) {
- removeBlocker = true;
- }
+ } else if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) {
+ removeBlocker = true;
}
if (removeBlocker) {
@@ -1546,4 +1540,9 @@ public class HumanPlayer extends PlayerImpl {
pass(game);
return true;
}
+
+ @Override
+ public String getHistory() {
+ return "no available";
+ }
}
diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml
index ce3e964160c..8c2ffcdb398 100644
--- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml
+++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-tournament-boosterdraft
diff --git a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml
index 350b1794bea..351a99f9712 100644
--- a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml
+++ b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-tournament-constructed
diff --git a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml
index c7fa4c17de6..a722cc73ee8 100644
--- a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml
+++ b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-server-plugins
- 1.4.7
+ 1.4.8
mage-tournament-sealed
diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml
index 878b46fda1a..d72e100c2ff 100644
--- a/Mage.Server.Plugins/pom.xml
+++ b/Mage.Server.Plugins/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
mage-server-plugins
diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml
index 4d22d719179..18c0364e689 100644
--- a/Mage.Server/config/config.xml
+++ b/Mage.Server/config/config.xml
@@ -19,6 +19,17 @@
userNamePattern - pattern for user name validity check
maxAiOpponents - number of allowed AI opponents on the server
saveGameActivated - allow game save and replay options (not working correctly yet)
+ authenticationActivated - "true" = user have to register to signon "false" = user need not to register
+ * mail configs only needed if authentication is activated:
+ * if mailUser = "" mailgun is used otherwise nativ mail server on the system
+ googleAccount - not supported currently
+ mailgunApiKey - key from the mailgun domain e.g. = "key-12121111..."
+ mailgunDomain - domain for the mailgun message sending
+ mailSmtpHost - hostname to send the mail
+ mailSmtpPort - port to send the mail
+ mailUser - username used to send the mail
+ mailPassword - passworf of the used user to send the mail
+ mailFromAddress - sender address
-->
diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml
index e3151182514..67862424c03 100644
--- a/Mage.Server/pom.xml
+++ b/Mage.Server/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
mage-server
diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml
index cb90395505a..f69d7f28afb 100644
--- a/Mage.Server/release/config/config.xml
+++ b/Mage.Server/release/config/config.xml
@@ -1,6 +1,36 @@
+
diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java
index ce1b6f5e091..8fbc80dd99c 100644
--- a/Mage.Server/src/main/java/mage/server/ChatManager.java
+++ b/Mage.Server/src/main/java/mage/server/ChatManager.java
@@ -24,8 +24,7 @@
* 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.server;
import java.util.ArrayList;
@@ -44,14 +43,15 @@ import org.apache.log4j.Logger;
public class ChatManager {
private static final Logger logger = Logger.getLogger(ChatManager.class);
-
+
private static final ChatManager INSTANCE = new ChatManager();
public static ChatManager getInstance() {
return INSTANCE;
}
- private ChatManager() {}
+ private ChatManager() {
+ }
private final ConcurrentHashMap chatSessions = new ConcurrentHashMap<>();
@@ -66,16 +66,16 @@ public class ChatManager {
if (chatSession != null) {
chatSession.join(userId);
} else {
- logger.trace("Chat to join not found - chatId: " + chatId +" userId: " + userId);
- }
-
+ logger.trace("Chat to join not found - chatId: " + chatId + " userId: " + userId);
+ }
+
}
public void leaveChat(UUID chatId, UUID userId) {
ChatSession chatSession = chatSessions.get(chatId);
if (chatSession != null && chatSession.hasUser(userId)) {
chatSession.kill(userId, DisconnectReason.CleaningUp);
- }
+ }
}
public void destroyChatSession(UUID chatId) {
@@ -88,7 +88,7 @@ public class ChatManager {
logger.trace("Chat removed - chatId: " + chatId);
} else {
logger.trace("Chat to destroy does not exist - chatId: " + chatId);
- }
+ }
}
}
}
@@ -119,63 +119,56 @@ public class ChatManager {
}
}
-
private boolean performUserCommand(User user, String message, UUID chatId) {
String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH);
- if (command.equals("I") || command.equals("INFO")) {
- user.setInfo("");
- chatSessions.get(chatId).broadcastInfoToUser(user,message);
- return true;
- }
- if (command.startsWith("I ") || command.startsWith("INFO ")) {
- user.setInfo(message.substring(command.startsWith("I ") ? 3 : 6));
- chatSessions.get(chatId).broadcastInfoToUser(user,message);
+ if (command.startsWith("H ") || command.startsWith("HISTORY ")) {
+ message = UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
+ chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
if (command.startsWith("W ") || command.startsWith("WHISPER ")) {
- String rest = message.substring(command.startsWith("W ")? 3 : 9);
+ String rest = message.substring(command.startsWith("W ") ? 3 : 9);
int first = rest.indexOf(" ");
if (first > 1) {
- String userToName = rest.substring(0,first);
+ String userToName = rest.substring(0, first);
rest = rest.substring(first + 1).trim();
User userTo = UserManager.getInstance().getUserByName(userToName);
if (userTo != null) {
if (!chatSessions.get(chatId).broadcastWhisperToUser(user, userTo, rest)) {
message += new StringBuilder("
User ").append(userToName).append(" not found").toString();
- chatSessions.get(chatId).broadcastInfoToUser(user,message);
+ chatSessions.get(chatId).broadcastInfoToUser(user, message);
}
} else {
message += new StringBuilder("
User ").append(userToName).append(" not found").toString();
- chatSessions.get(chatId).broadcastInfoToUser(user,message);
+ chatSessions.get(chatId).broadcastInfoToUser(user, message);
}
return true;
}
}
if (command.equals("L") || command.equals("LIST")) {
message += new StringBuilder("
List of commands:")
- .append("
\\info [text] - set a info text to your player")
- .append("
\\list - Show a list of commands")
- .append("
\\whisper [player name] [text] - whisper to the player with the given name").toString();
- chatSessions.get(chatId).broadcastInfoToUser(user,message);
+ .append("
\\history or \\h [username] - shows the history of a player")
+ .append("
\\list or \\l - Show a list of commands")
+ .append("
\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString();
+ chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
return false;
}
-
-
/**
- *
- * use mainly for announcing that a user connection was lost or that a user has reconnected
- *
+ *
+ * use mainly for announcing that a user connection was lost or that a user
+ * has reconnected
+ *
* @param userId
* @param message
- * @param color
+ * @param color
*/
public void broadcast(UUID userId, String message, MessageColor color) {
User user = UserManager.getInstance().getUser(userId);
if (user != null) {
- for (ChatSession chat: chatSessions.values()) {
+ for (ChatSession chat : chatSessions.values()) {
if (chat.hasUser(userId)) {
chat.broadcast(user.getName(), message, color);
}
@@ -186,16 +179,16 @@ public class ChatManager {
public void sendReconnectMessage(UUID userId) {
User user = UserManager.getInstance().getUser(userId);
if (user != null) {
- for (ChatSession chat: chatSessions.values()) {
+ for (ChatSession chat : chatSessions.values()) {
if (chat.hasUser(userId)) {
chat.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS);
- }
- }
+ }
+ }
}
}
-
+
public void removeUser(UUID userId, DisconnectReason reason) {
- for (ChatSession chatSession: chatSessions.values()) {
+ for (ChatSession chatSession : chatSessions.values()) {
if (chatSession.hasUser(userId)) {
chatSession.kill(userId, reason);
}
diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java
index b2a7553eb91..6489473a794 100644
--- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java
+++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java
@@ -99,7 +99,7 @@ public class MageServerImpl implements MageServer {
private static final Logger logger = Logger.getLogger(MageServerImpl.class);
private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor();
private static final SecureRandom RANDOM = new SecureRandom();
-
+
private final String adminPassword;
private final boolean testMode;
private final LinkedHashMap activeAuthTokens = new LinkedHashMap() {
@@ -140,9 +140,16 @@ public class MageServerImpl implements MageServer {
}
String authToken = generateAuthToken();
activeAuthTokens.put(email, authToken);
- if (!MailgunClient.sendMessage(email, "XMage Password Reset Auth Token",
- "Use this auth token to reset your password: " + authToken + "\n" +
- "It's valid until the next server restart.")) {
+ String subject = "XMage Password Reset Auth Token";
+ String text = "Use this auth token to reset your password: " + authToken + "\n"
+ + "It's valid until the next server restart.";
+ boolean success;
+ if (!ConfigSettings.getInstance().getMailUser().isEmpty()) {
+ success = MailClient.sendMessage(email, subject, text);
+ } else {
+ success = MailgunClient.sendMessage(email, subject, text);
+ }
+ if (!success) {
sendErrorMessageToClient(sessionId, "There was an error inside the server while emailing an auth token");
return false;
}
diff --git a/Mage.Server/src/main/java/mage/server/MailClient.java b/Mage.Server/src/main/java/mage/server/MailClient.java
new file mode 100644
index 00000000000..9c7ef614589
--- /dev/null
+++ b/Mage.Server/src/main/java/mage/server/MailClient.java
@@ -0,0 +1,53 @@
+package mage.server;
+
+import java.util.Properties;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import mage.server.util.ConfigSettings;
+import org.apache.log4j.Logger;
+
+public class MailClient {
+
+ private static final Logger logger = Logger.getLogger(Main.class);
+
+ public static boolean sendMessage(String email, String subject, String text) {
+ if (email.length() == 0) {
+ logger.info("Email is not sent because the address is empty");
+ return false;
+ }
+ ConfigSettings config = ConfigSettings.getInstance();
+
+ Properties properties = System.getProperties();
+ properties.setProperty("mail.smtps.host", config.getMailSmtpHost());
+ properties.setProperty("mail.smtps.port", config.getMailSmtpPort());
+ properties.setProperty("mail.smtps.auth", "true");
+ properties.setProperty("mail.user", config.getMailUser());
+ properties.setProperty("mail.password", config.getMailPassword());
+
+ Session session = Session.getDefaultInstance(properties);
+
+ try{
+ MimeMessage message = new MimeMessage(session);
+ message.setFrom(new InternetAddress(config.getMailFromAddress()));
+ message.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
+ message.setSubject(subject);
+ message.setText(text);
+
+ Transport trnsport;
+ trnsport = session.getTransport("smtps");
+ trnsport.connect(null, properties.getProperty("mail.password"));
+ message.saveChanges();
+ trnsport.sendMessage(message, message.getAllRecipients());
+ trnsport.close();
+
+ return true;
+ }catch (MessagingException ex) {
+ logger.error("Error sending message to " + email, ex);
+ }
+ return false;
+ }
+}
diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java
index 34a8d29a1fd..54c2a2b477c 100644
--- a/Mage.Server/src/main/java/mage/server/Main.java
+++ b/Mage.Server/src/main/java/mage/server/Main.java
@@ -32,20 +32,10 @@ import java.io.FilenameFilter;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
import javax.management.MBeanServer;
import mage.cards.repository.CardScanner;
import mage.game.match.MatchType;
-import mage.game.result.ResultProtos.MatchPlayerProto;
-import mage.game.result.ResultProtos.MatchProto;
-import mage.game.result.ResultProtos.TableProto;
-import mage.game.result.ResultProtos.TourneyPlayerProto;
-import mage.game.result.ResultProtos.TourneyProto;
-import mage.game.result.ResultProtos.UserStatsProto;
import mage.game.tournament.TournamentType;
import mage.interfaces.MageServer;
import mage.remote.Connection;
@@ -53,9 +43,6 @@ import mage.server.draft.CubeFactory;
import mage.server.game.DeckValidatorFactory;
import mage.server.game.GameFactory;
import mage.server.game.PlayerFactory;
-import mage.server.record.TableRecord;
-import mage.server.record.TableRecordRepository;
-import mage.server.record.UserStats;
import mage.server.record.UserStatsRepository;
import mage.server.tournament.TournamentFactory;
import mage.server.util.ConfigSettings;
@@ -102,8 +89,6 @@ public class Main {
protected static boolean testMode;
protected static boolean fastDbMode;
- private static final ScheduledExecutorService updateUserStatsTaskExecutor = Executors.newSingleThreadScheduledExecutor();
-
/**
* @param args the command line arguments
*/
@@ -132,6 +117,10 @@ public class Main {
}
logger.info("Done.");
+ logger.info("Updating user stats DB...");
+ UserStatsRepository.instance.updateUserStats();
+ logger.info("Done.");
+
deleteSavedGames();
ConfigSettings config = ConfigSettings.getInstance();
for (GamePlugin plugin : config.getGameTypes()) {
@@ -167,7 +156,12 @@ public class Main {
logger.info("Config - auth. activated : " + (config.isAuthenticationActivated() ? "true" : "false"));
logger.info("Config - mailgun api key : " + config.getMailgunApiKey());
logger.info("Config - mailgun domain : " + config.getMailgunDomain());
- //logger.info("Config - google account : " + config.getGoogleAccount());
+ logger.info("Config - mail smtp Host : " + config.getMailSmtpHost());
+ logger.info("Config - mail smtpPort : " + config.getMailSmtpPort());
+ logger.info("Config - mail user : " + config.getMailUser());
+ logger.info("Config - mail passw. len.: " + config.getMailPassword().length());
+ logger.info("Config - mail from addre.: " + config.getMailFromAddress());
+ logger.info("Config - google account : " + config.getGoogleAccount());
Connection connection = new Connection("&maxPoolSize=" + config.getMaxPoolSize());
connection.setHost(config.getServerAddress());
@@ -190,13 +184,6 @@ public class Main {
} catch (Exception ex) {
logger.fatal("Failed to start server - " + connection.toString(), ex);
}
-
- updateUserStatsTaskExecutor.scheduleAtFixedRate(new Runnable() {
- @Override
- public void run() {
- updateUserStats();
- }
- }, 60, 60, TimeUnit.SECONDS);
}
static void initStatistics() {
@@ -391,78 +378,4 @@ public class Main {
public static boolean isTestMode() {
return testMode;
}
-
- private static void updateUserStats() {
- long latestEndTimeMs = UserStatsRepository.instance.getLatestEndTimeMs();
- List records = TableRecordRepository.instance.getAfter(latestEndTimeMs);
- for (TableRecord record : records) {
- TableProto table = record.getProto();
- if (table.getControllerName().equals("System")) {
- // This is a sub table within a tournament, so it's already handled by the main
- // tournament table.
- continue;
- }
- if (table.hasMatch()) {
- MatchProto match = table.getMatch();
- for (MatchPlayerProto player : match.getPlayersList()) {
- UserStats userStats = UserStatsRepository.instance.getUser(player.getName());
- UserStatsProto proto = userStats != null ? userStats.getProto() :
- UserStatsProto.newBuilder().setName(player.getName()).build();
- UserStatsProto.Builder builder = UserStatsProto.newBuilder(proto)
- .setMatches(proto.getMatches() + 1);
- switch (player.getQuit()) {
- case IDLE_TIMEOUT:
- builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1);
- break;
- case TIMER_TIMEOUT:
- builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1);
- break;
- case QUIT:
- builder.setMatchesQuit(proto.getMatchesQuit() + 1);
- break;
- }
- if (userStats == null) {
- UserStatsRepository.instance.add(new UserStats(builder.build(), table.getEndTimeMs()));
- } else {
- UserStatsRepository.instance.update(new UserStats(builder.build(), table.getEndTimeMs()));
- }
- // UserStats for this player is updated, so refresh it.
- User user = UserManager.getInstance().getUserByName(player.getName());
- if (user != null) {
- user.resetUserStats();
- }
- }
- } else if (table.hasTourney()) {
- TourneyProto tourney = table.getTourney();
- for (TourneyPlayerProto player : tourney.getPlayersList()) {
- UserStats userStats = UserStatsRepository.instance.getUser(player.getName());
- UserStatsProto proto = userStats != null ? userStats.getProto() :
- UserStatsProto.newBuilder().setName(player.getName()).build();
- UserStatsProto.Builder builder = UserStatsProto.newBuilder(proto)
- .setTourneys(proto.getTourneys() + 1);
- switch (player.getQuit()) {
- case DURING_ROUND:
- builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1);
- break;
- case DURING_DRAFTING:
- builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1);
- break;
- case DURING_CONSTRUCTION:
- builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1);
- break;
- }
- if (userStats == null) {
- UserStatsRepository.instance.add(new UserStats(builder.build(), table.getEndTimeMs()));
- } else {
- UserStatsRepository.instance.update(new UserStats(builder.build(), table.getEndTimeMs()));
- }
- // UserStats for this player is updated, so refresh it.
- User user = UserManager.getInstance().getUserByName(player.getName());
- if (user != null) {
- user.resetUserStats();
- }
- }
- }
- }
- }
}
diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java
index 69c8ad42fa0..88dccf49126 100644
--- a/Mage.Server/src/main/java/mage/server/Session.java
+++ b/Mage.Server/src/main/java/mage/server/Session.java
@@ -99,8 +99,15 @@ public class Session {
return returnMessage;
}
AuthorizedUserRepository.instance.add(userName, password, email);
- if (MailgunClient.sendMessage(email, "XMage Registration Completed",
- "You are successfully registered as " + userName + ".")) {
+ String subject = "XMage Registration Completed";
+ String text = "You are successfully registered as " + userName + ".";
+ boolean success;
+ if (!ConfigSettings.getInstance().getMailUser().isEmpty()) {
+ success = MailClient.sendMessage(email, subject, text);
+ } else {
+ success = MailgunClient.sendMessage(email, subject, text);
+ }
+ if (success) {
logger.info("Sent a registration confirmation email to " + email + " for " + userName);
} else {
logger.error("Failed sending a registration confirmation email to " + email + " for " + userName);
diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java
index d8ef96b5c37..b6dad40c541 100644
--- a/Mage.Server/src/main/java/mage/server/User.java
+++ b/Mage.Server/src/main/java/mage/server/User.java
@@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit;
import mage.cards.decks.Deck;
import mage.constants.ManaType;
import mage.game.Table;
+import mage.game.result.ResultProtos;
import mage.game.tournament.TournamentPlayer;
import mage.interfaces.callback.ClientCallback;
import mage.players.net.UserData;
@@ -61,7 +62,7 @@ import org.apache.log4j.Logger;
*/
public class User {
- private static final Logger logger = Logger.getLogger(User.class);
+ private static final Logger LOGGER = Logger.getLogger(User.class);
public enum UserState {
@@ -81,7 +82,6 @@ public class User {
private final Map sideboarding;
private final List watchedGames;
private String sessionId;
- private String info = "";
private String pingInfo = "";
private Date lastActivity;
private UserState userState;
@@ -106,6 +106,7 @@ public class User {
this.watchedGames = new ArrayList<>();
this.tablesToDelete = new ArrayList<>();
this.sessionId = "";
+ this.userStats = null;
}
public String getName() {
@@ -129,15 +130,15 @@ public class User {
if (sessionId.isEmpty()) {
userState = UserState.Disconnected;
lostConnection();
- logger.trace("USER - lost connection: " + userName + " id: " + userId);
+ LOGGER.trace("USER - lost connection: " + userName + " id: " + userId);
} else if (userState == UserState.Created) {
userState = UserState.Connected;
- logger.trace("USER - created: " + userName + " id: " + userId);
+ LOGGER.trace("USER - created: " + userName + " id: " + userId);
} else {
userState = UserState.Reconnected;
reconnect();
- logger.trace("USER - reconnected: " + userName + " id: " + userId);
+ LOGGER.trace("USER - reconnected: " + userName + " id: " + userId);
}
}
@@ -273,12 +274,13 @@ public class User {
public boolean isExpired(Date expired) {
if (lastActivity.before(expired)) {
- logger.trace(userName + " is expired!");
+ LOGGER.trace(userName + " is expired!");
userState = UserState.Expired;
return true;
}
- logger.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString());
- return false; /*userState == UserState.Disconnected && */
+ LOGGER.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString());
+ return false;
+ /*userState == UserState.Disconnected && */
}
@@ -360,35 +362,35 @@ public class User {
}
public void remove(DisconnectReason reason) {
- logger.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size());
+ LOGGER.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size());
for (DraftSession draftSession : draftSessions.values()) {
draftSession.setKilled();
}
draftSessions.clear();
- logger.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size());
+ LOGGER.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size());
for (UUID tournamentId : userTournaments.values()) {
TournamentManager.getInstance().quit(tournamentId, getId());
}
userTournaments.clear();
- logger.trace("REMOVE " + getName() + " Tables " + tables.size());
+ LOGGER.trace("REMOVE " + getName() + " Tables " + tables.size());
for (Entry entry : tables.entrySet()) {
- logger.debug("-- leave tableId: " + entry.getValue().getId());
+ LOGGER.debug("-- leave tableId: " + entry.getValue().getId());
TableManager.getInstance().leaveTable(userId, entry.getValue().getId());
}
tables.clear();
- logger.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size());
+ LOGGER.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size());
for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) {
- logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId());
+ LOGGER.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId());
GameManager.getInstance().quitMatch(gameSessionPlayer.getGameId(), userId);
gameSessionPlayer.quitGame();
}
gameSessions.clear();
- logger.trace("REMOVE " + getName() + " watched Games " + watchedGames.size());
+ LOGGER.trace("REMOVE " + getName() + " watched Games " + watchedGames.size());
for (UUID gameId : watchedGames) {
GameManager.getInstance().stopWatching(gameId, userId);
}
watchedGames.clear();
- logger.trace("REMOVE " + getName() + " Chats ");
+ LOGGER.trace("REMOVE " + getName() + " Chats ");
ChatManager.getInstance().removeUser(userId, reason);
}
@@ -397,6 +399,12 @@ public class User {
this.userData.update(userData);
} else {
this.userData = userData;
+ this.userStats = UserStatsRepository.instance.getUser(this.userName);
+ if (userStats != null) {
+ this.userData.setHistory(userStatsToString(userStats.getProto()));
+ } else {
+ this.userData.setHistory("");
+ }
}
}
@@ -446,11 +454,11 @@ public class User {
}
} else {
// can happen if tournamet has just ended
- logger.debug(getName() + " tournament player missing - tableId:" + table.getId(), null);
+ LOGGER.debug(getName() + " tournament player missing - tableId:" + table.getId(), null);
tablesToDelete.add(tableEntry.getKey());
}
} else {
- logger.error(getName() + " tournament key missing - tableId: " + table.getId(), null);
+ LOGGER.error(getName() + " tournament key missing - tableId: " + table.getId(), null);
}
} else {
switch (table.getState()) {
@@ -500,14 +508,6 @@ public class User {
return sb.toString();
}
- public String getInfo() {
- return info;
- }
-
- public void setInfo(String Info) {
- this.info = Info;
- }
-
public void addGameWatchInfo(UUID gameId) {
watchedGames.add(gameId);
}
@@ -540,5 +540,84 @@ public class User {
// resetUserStats loads UserStats from DB.
public void resetUserStats() {
this.userStats = UserStatsRepository.instance.getUser(this.userName);
+ if (userData != null) {
+ userData.setHistory(userStatsToString(userStats.getProto()));
+ }
}
+
+ public String getHistory() {
+ if (userData != null) {
+ return userData.getHistory();
+ }
+ return "";
+ }
+
+ public static String userStatsToString(ResultProtos.UserStatsProto proto) {
+ List builders = new ArrayList<>();
+ if (proto.getMatches() > 0) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Matches:");
+ builder.append(proto.getMatches());
+ List quit = new ArrayList<>();
+ if (proto.getMatchesIdleTimeout() > 0) {
+ quit.add("I:" + Integer.toString(proto.getMatchesIdleTimeout()));
+ }
+ if (proto.getMatchesTimerTimeout() > 0) {
+ quit.add("T:" + Integer.toString(proto.getMatchesTimerTimeout()));
+ }
+ if (proto.getMatchesQuit() > 0) {
+ quit.add("Q:" + Integer.toString(proto.getMatchesQuit()));
+ }
+ if (quit.size() > 0) {
+ builder.append(" (");
+ joinStrings(builder, quit, " ");
+ builder.append(")");
+ }
+ builders.add(builder);
+ }
+ if (proto.getTourneys() > 0) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Tourneys:");
+ builder.append(proto.getTourneys());
+ List quit = new ArrayList<>();
+ if (proto.getTourneysQuitDuringDrafting() > 0) {
+ quit.add("D:" + Integer.toString(proto.getTourneysQuitDuringDrafting()));
+ }
+ if (proto.getTourneysQuitDuringConstruction() > 0) {
+ quit.add("C:" + Integer.toString(proto.getTourneysQuitDuringConstruction()));
+ }
+ if (proto.getTourneysQuitDuringRound() > 0) {
+ quit.add("R:" + Integer.toString(proto.getTourneysQuitDuringRound()));
+ }
+ if (quit.size() > 0) {
+ builder.append(" (");
+ joinStrings(builder, quit, " ");
+ builder.append(")");
+ }
+ builders.add(builder);
+ }
+ return joinBuilders(builders);
+ }
+
+ private static String joinBuilders(List builders) {
+ if (builders.isEmpty()) {
+ return null;
+ }
+ StringBuilder builder = builders.get(0);
+ for (int i = 1; i < builders.size(); ++i) {
+ builder.append(" ");
+ builder.append(builders.get(i));
+ }
+ return builder.toString();
+ }
+
+ private static void joinStrings(StringBuilder joined, List strings, String separator) {
+ for (int i = 0; i < strings.size(); ++i) {
+ if (i > 0) {
+ joined.append(separator);
+ }
+ joined.append(strings.get(i));
+ }
+ }
+
}
diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java
index 3306a6ddba1..7b1b875869d 100644
--- a/Mage.Server/src/main/java/mage/server/UserManager.java
+++ b/Mage.Server/src/main/java/mage/server/UserManager.java
@@ -1,16 +1,16 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@@ -20,7 +20,7 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ *
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
@@ -38,6 +38,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import mage.server.User.UserState;
+import mage.server.record.UserStats;
+import mage.server.record.UserStatsRepository;
import mage.server.util.ThreadExecutor;
import org.apache.log4j.Logger;
@@ -45,7 +47,7 @@ import org.apache.log4j.Logger;
*
* manages users - if a user is disconnected and 10 minutes have passed with no
* activity the user is removed
- *
+ *
* @author BetaSteward_at_googlemail.com
*/
public class UserManager {
@@ -56,7 +58,7 @@ public class UserManager {
private final ConcurrentHashMap users = new ConcurrentHashMap<>();
private final ConcurrentHashMap usersByName = new ConcurrentHashMap<>();
-
+
private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor();
private static final UserManager INSTANCE = new UserManager();
@@ -64,8 +66,8 @@ public class UserManager {
public static UserManager getInstance() {
return INSTANCE;
}
-
- private UserManager() {
+
+ private UserManager() {
expireExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
@@ -113,7 +115,7 @@ public class UserManager {
public void disconnect(UUID userId, DisconnectReason reason) {
if (userId != null) {
User user = users.get(userId);
- if (user != null) {
+ if (user != null) {
user.setSessionId(""); // Session will be set again with new id if user reconnects
}
ChatManager.getInstance().removeUser(userId, reason);
@@ -123,44 +125,44 @@ public class UserManager {
public boolean isAdmin(UUID userId) {
if (userId != null) {
User user = users.get(userId);
- if (user != null) {
+ if (user != null) {
return user.getName().equals("Admin");
}
}
return false;
}
- public void removeUser(final UUID userId, final DisconnectReason reason) {
+ public void removeUser(final UUID userId, final DisconnectReason reason) {
if (userId != null) {
final User user = users.get(userId);
if (user != null) {
callExecutor.execute(
- new Runnable() {
- @Override
- public void run() {
- try {
- logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId);
- user.remove(reason);
- logger.debug("USER REMOVE END - " + user.getName());
- } catch (Exception ex) {
- handleException(ex);
- } finally {
- users.remove(userId);
- usersByName.remove(user.getName());
- }
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId);
+ user.remove(reason);
+ logger.debug("USER REMOVE END - " + user.getName());
+ } catch (Exception ex) {
+ handleException(ex);
+ } finally {
+ users.remove(userId);
+ usersByName.remove(user.getName());
}
}
+ }
);
} else {
logger.warn("Trying to remove userId: " + userId + " - but it does not exist.");
}
- }
+ }
}
public boolean extendUserSession(UUID userId, String pingInfo) {
if (userId != null) {
User user = users.get(userId);
- if (user != null) {
+ if (user != null) {
user.updateLastActivity(pingInfo);
return true;
}
@@ -169,7 +171,8 @@ public class UserManager {
}
/**
- * Is the connection lost for more than 3 minutes, the user will be removed (within 3 minutes the user can reconnect)
+ * Is the connection lost for more than 3 minutes, the user will be removed
+ * (within 3 minutes the user can reconnect)
*/
private void checkExpired() {
Calendar calendar = Calendar.getInstance();
@@ -185,13 +188,39 @@ public class UserManager {
public void handleException(Exception ex) {
if (ex != null) {
- logger.fatal("User manager exception " + (ex.getMessage() == null ? "null":ex.getMessage()));
+ logger.fatal("User manager exception " + (ex.getMessage() == null ? "null" : ex.getMessage()));
if (ex.getCause() != null) {
- logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null":ex.getCause().getMessage()));
+ logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null" : ex.getCause().getMessage()));
}
ex.printStackTrace();
- }else {
+ } else {
logger.fatal("User manager exception - null");
}
}
+
+ public String getUserHistory(String userName) {
+ User user = getUserByName(userName);
+ if (user == null) {
+ UserStats userStats = UserStatsRepository.instance.getUser(userName);
+ if (userStats == null) {
+ return "User " + userName + " not found";
+ }
+ return User.userStatsToString(userStats.getProto());
+ }
+ return "History of user " + userName + ": " + user.getUserData().getHistory();
+ }
+
+ public void updateUserHistory() {
+ callExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ for (String updatedUser : UserStatsRepository.instance.updateUserStats()) {
+ User user = getUserByName(updatedUser);
+ if (user != null) {
+ user.resetUserStats();
+ }
+ }
+ }
+ });
+ }
}
diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java
index 27d0888704a..30b005e19c2 100644
--- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java
+++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java
@@ -43,13 +43,11 @@ import mage.constants.TableState;
import mage.game.GameException;
import mage.game.Table;
import mage.game.match.MatchOptions;
-import mage.game.result.ResultProtos.UserStatsProto;
import mage.game.tournament.TournamentOptions;
import mage.server.RoomImpl;
import mage.server.TableManager;
import mage.server.User;
import mage.server.UserManager;
-import mage.server.record.UserStats;
import mage.server.tournament.TournamentManager;
import mage.server.util.ConfigSettings;
import mage.server.util.ThreadExecutor;
@@ -93,74 +91,6 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
return tableView;
}
- private static void joinStrings(StringBuilder joined, List strings, String separator) {
- for (int i = 0; i < strings.size(); ++i) {
- if (i > 0) {
- joined.append(separator);
- }
- joined.append(strings.get(i));
- }
- }
-
- private static String joinBuilders(List builders) {
- if (builders.isEmpty()) {
- return null;
- }
- StringBuilder builder = builders.get(0);
- for (int i = 1; i < builders.size(); ++i) {
- builder.append(" ");
- builder.append(builders.get(i));
- }
- return builder.toString();
- }
-
- private static String userStatsToString(UserStatsProto proto) {
- List builders = new ArrayList<>();
- if (proto.getMatches() > 0) {
- StringBuilder builder = new StringBuilder();
- builder.append("Matches:");
- builder.append(proto.getMatches());
- List quit = new ArrayList<>();
- if (proto.getMatchesIdleTimeout() > 0) {
- quit.add("I:" + Integer.toString(proto.getMatchesIdleTimeout()));
- }
- if (proto.getMatchesTimerTimeout() > 0) {
- quit.add("T:" + Integer.toString(proto.getMatchesTimerTimeout()));
- }
- if (proto.getMatchesQuit() > 0) {
- quit.add("Q:" + Integer.toString(proto.getMatchesQuit()));
- }
- if (quit.size() > 0) {
- builder.append(" (");
- joinStrings(builder, quit, " ");
- builder.append(")");
- }
- builders.add(builder);
- }
- if (proto.getTourneys() > 0) {
- StringBuilder builder = new StringBuilder();
- builder.append("Tourneys:");
- builder.append(proto.getTourneys());
- List quit = new ArrayList<>();
- if (proto.getTourneysQuitDuringDrafting() > 0) {
- quit.add("D:" + Integer.toString(proto.getTourneysQuitDuringDrafting()));
- }
- if (proto.getTourneysQuitDuringConstruction() > 0) {
- quit.add("C:" + Integer.toString(proto.getTourneysQuitDuringConstruction()));
- }
- if (proto.getTourneysQuitDuringRound() > 0) {
- quit.add("R:" + Integer.toString(proto.getTourneysQuitDuringRound()));
- }
- if (quit.size() > 0) {
- builder.append(" (");
- joinStrings(builder, quit, " ");
- builder.append(")");
- }
- builders.add(builder);
- }
- return joinBuilders(builders);
- }
-
private void update() {
ArrayList tableList = new ArrayList<>();
ArrayList matchList = new ArrayList<>();
@@ -183,20 +113,14 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
matchView = matchList;
List users = new ArrayList<>();
for (User user : UserManager.getInstance().getUsers()) {
- String history = null;
- UserStats stats = user.getUserStats();
- if (stats != null) {
- history = userStatsToString(stats.getProto());
- }
try {
- users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), history, user.getInfo(), user.getGameInfo(), user.getPingInfo()));
+ users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getHistory(), user.getGameInfo(), user.getPingInfo()));
} catch (Exception ex) {
logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex);
users.add(new UsersView(
(user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world",
user.getName() != null ? user.getName() : "",
- history != null ? history : "",
- user.getInfo() != null ? user.getInfo() : "",
+ user.getHistory() != null ? user.getHistory() : "",
"[exception]",
user.getPingInfo() != null ? user.getPingInfo() : ""));
}
diff --git a/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java b/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java
index b4d16688edf..2bafdff9c1c 100644
--- a/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java
+++ b/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java
@@ -3,6 +3,7 @@ package mage.server.record;
import mage.game.Table;
import mage.game.Table.TableRecorder;
import mage.game.result.ResultProtos.TableProto;
+import mage.server.UserManager;
import org.apache.log4j.Logger;
public class TableRecorderImpl implements TableRecorder {
@@ -17,5 +18,6 @@ public class TableRecorderImpl implements TableRecorder {
public void record(Table table) {
TableProto proto = table.toProto();
TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs()));
+ UserManager.getInstance().updateUserHistory();
}
}
diff --git a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java
index de43a7c76bc..26348de66a3 100644
--- a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java
+++ b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java
@@ -9,8 +9,11 @@ import com.j256.ormlite.support.DatabaseConnection;
import com.j256.ormlite.table.TableUtils;
import java.io.File;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import mage.cards.repository.RepositoryUtil;
+import mage.game.result.ResultProtos;
import org.apache.log4j.Logger;
public enum UserStatsRepository {
@@ -98,6 +101,79 @@ public enum UserStatsRepository {
return 0;
}
+ // updateUserStats reads tables finished after the last DB update and reflects it to the DB.
+ // It returns the list of user names that are upated.
+ public List updateUserStats() {
+ HashSet updatedUsers = new HashSet();
+ // Lock the DB so that no other updateUserStats runs at the same time.
+ synchronized(this) {
+ long latestEndTimeMs = this.getLatestEndTimeMs();
+ List records = TableRecordRepository.instance.getAfter(latestEndTimeMs);
+ for (TableRecord record : records) {
+ ResultProtos.TableProto table = record.getProto();
+ if (table.getControllerName().equals("System")) {
+ // This is a sub table within a tournament, so it's already handled by the main
+ // tournament table.
+ continue;
+ }
+ if (table.hasMatch()) {
+ ResultProtos.MatchProto match = table.getMatch();
+ for (ResultProtos.MatchPlayerProto player : match.getPlayersList()) {
+ UserStats userStats = this.getUser(player.getName());
+ ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto()
+ : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build();
+ ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto)
+ .setMatches(proto.getMatches() + 1);
+ switch (player.getQuit()) {
+ case IDLE_TIMEOUT:
+ builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1);
+ break;
+ case TIMER_TIMEOUT:
+ builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1);
+ break;
+ case QUIT:
+ builder.setMatchesQuit(proto.getMatchesQuit() + 1);
+ break;
+ }
+ if (userStats == null) {
+ this.add(new UserStats(builder.build(), table.getEndTimeMs()));
+ } else {
+ this.update(new UserStats(builder.build(), table.getEndTimeMs()));
+ }
+ updatedUsers.add(player.getName());
+ }
+ } else if (table.hasTourney()) {
+ ResultProtos.TourneyProto tourney = table.getTourney();
+ for (ResultProtos.TourneyPlayerProto player : tourney.getPlayersList()) {
+ UserStats userStats = this.getUser(player.getName());
+ ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto()
+ : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build();
+ ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto)
+ .setTourneys(proto.getTourneys() + 1);
+ switch (player.getQuit()) {
+ case DURING_ROUND:
+ builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1);
+ break;
+ case DURING_DRAFTING:
+ builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1);
+ break;
+ case DURING_CONSTRUCTION:
+ builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1);
+ break;
+ }
+ if (userStats == null) {
+ this.add(new UserStats(builder.build(), table.getEndTimeMs()));
+ } else {
+ this.update(new UserStats(builder.build(), table.getEndTimeMs()));
+ }
+ updatedUsers.add(player.getName());
+ }
+ }
+ }
+ }
+ return new ArrayList(updatedUsers);
+ }
+
public void closeDB() {
try {
if (dao != null && dao.getConnectionSource() != null) {
diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java
index 4cda0d91958..d472b0a8cea 100644
--- a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java
+++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java
@@ -147,6 +147,26 @@ public class ConfigSettings {
return config.getServer().getMailgunDomain();
}
+ public String getMailSmtpHost() {
+ return config.getServer().getMailSmtpHost();
+ }
+
+ public String getMailSmtpPort() {
+ return config.getServer().getMailSmtpPort();
+ }
+
+ public String getMailUser() {
+ return config.getServer().getMailUser();
+ }
+
+ public String getMailPassword() {
+ return config.getServer().getMailPassword();
+ }
+
+ public String getMailFromAddress() {
+ return config.getServer().getMailFromAddress();
+ }
+
public List getPlayerTypes() {
return config.getPlayerTypes().getPlayerType();
}
diff --git a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd
index 1c25007dd23..0a82ec9bae5 100644
--- a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd
+++ b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd
@@ -38,6 +38,11 @@
+
+
+
+
+
diff --git a/Mage.Sets/pom.xml b/Mage.Sets/pom.xml
index 95b969006f5..4050b0efede 100644
--- a/Mage.Sets/pom.xml
+++ b/Mage.Sets/pom.xml
@@ -7,7 +7,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
org.mage
diff --git a/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java b/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java
index 9c3a352436b..c583f19ca4c 100644
--- a/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java
+++ b/Mage.Sets/src/mage/sets/apocalypse/ConsumeStrength.java
@@ -37,6 +37,8 @@ import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.SubLayer;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
@@ -54,8 +56,17 @@ public class ConsumeStrength extends CardImpl {
// Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn.
this.getSpellAbility().addEffect(new ConsumeStrengthEffect());
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(2));
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature to get +2/+2");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature to get -2/-2");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
}
public ConsumeStrength(final ConsumeStrength card) {
@@ -91,7 +102,7 @@ class ConsumeStrengthEffect extends ContinuousEffectImpl {
permanent.addPower(2);
permanent.addToughness(2);
}
- permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1));
+ permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent != null) {
permanent.addPower(-2);
permanent.addToughness(-2);
diff --git a/Mage.Sets/src/mage/sets/eventide/DreamFracture.java b/Mage.Sets/src/mage/sets/eventide/DreamFracture.java
index 2b4de1ba5eb..2641de664bb 100644
--- a/Mage.Sets/src/mage/sets/eventide/DreamFracture.java
+++ b/Mage.Sets/src/mage/sets/eventide/DreamFracture.java
@@ -49,7 +49,6 @@ public class DreamFracture extends CardImpl {
super(ownerId, 19, "Dream Fracture", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{U}{U}");
this.expansionSetCode = "EVE";
-
// Counter target spell. Its controller draws a card.
this.getSpellAbility().addEffect(new DreamFractureEffect());
this.getSpellAbility().addTarget(new TargetSpell());
@@ -73,7 +72,7 @@ class DreamFractureEffect extends OneShotEffect {
public DreamFractureEffect() {
super(Outcome.Neutral);
- this.staticText = "Counter target spell. Its controller draws a card";
+ this.staticText = "Counter target spell. Its controller draws a card";
}
public DreamFractureEffect(final DreamFractureEffect effect) {
@@ -102,4 +101,4 @@ class DreamFractureEffect extends OneShotEffect {
}
return countered;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/sets/fifthedition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/fifthedition/LibraryOfLeng.java
new file mode 100644
index 00000000000..a6dc94c1875
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/fifthedition/LibraryOfLeng.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.fifthedition;
+
+import java.util.UUID;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId);
+ this.cardNumber = 387;
+ this.expansionSetCode = "5ED";
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/fourthedition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/fourthedition/LibraryOfLeng.java
new file mode 100644
index 00000000000..5cd8b91f3b2
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/fourthedition/LibraryOfLeng.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.fourthedition;
+
+import java.util.UUID;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId);
+ this.cardNumber = 351;
+ this.expansionSetCode = "4ED";
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java b/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java
index 9bed435422f..bef3060278d 100644
--- a/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java
+++ b/Mage.Sets/src/mage/sets/gatecrash/Bioshift.java
@@ -56,7 +56,7 @@ public class Bioshift extends CardImpl {
// Move any number of +1/+1 counters from target creature onto another target creature with the same controller.
getSpellAbility().addEffect(new MoveCounterFromTargetToTargetEffect());
getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (you take counters from)")));
- getSpellAbility().addTarget(new BioshiftSecondTargetPermanent());
+ getSpellAbility().addTarget(new BioshiftSecondTargetCreaturePermanent());
}
@@ -113,14 +113,15 @@ class MoveCounterFromTargetToTargetEffect extends OneShotEffect {
}
}
-class BioshiftSecondTargetPermanent extends TargetPermanent {
+class BioshiftSecondTargetCreaturePermanent extends TargetCreaturePermanent {
- BioshiftSecondTargetPermanent() {
- super();
- this.filter = new FilterCreaturePermanent("another target creature with the same controller (counters go to)");
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature with the same controller (counters go to)");
+
+ BioshiftSecondTargetCreaturePermanent() {
+ super(filter);
}
- BioshiftSecondTargetPermanent(final BioshiftSecondTargetPermanent target) {
+ BioshiftSecondTargetCreaturePermanent(final BioshiftSecondTargetCreaturePermanent target) {
super(target);
}
@@ -137,7 +138,7 @@ class BioshiftSecondTargetPermanent extends TargetPermanent {
}
@Override
- public BioshiftSecondTargetPermanent copy() {
- return new BioshiftSecondTargetPermanent(this);
+ public BioshiftSecondTargetCreaturePermanent copy() {
+ return new BioshiftSecondTargetCreaturePermanent(this);
}
}
diff --git a/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java b/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java
index 4a1b7ac9ecb..ab92114de1d 100644
--- a/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java
+++ b/Mage.Sets/src/mage/sets/guildpact/Schismotivate.java
@@ -37,6 +37,8 @@ import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.SubLayer;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
@@ -53,7 +55,17 @@ public class Schismotivate extends CardImpl {
// Target creature gets +4/+0 until end of turn. Another target creature gets -4/-0 until end of turn.
this.getSpellAbility().addEffect(new SchismotivateEffect());
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(2));
+
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets +4/+0 until end of turn)");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets -4/-0 until end of turn)");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
}
public Schismotivate(final Schismotivate card) {
@@ -88,7 +100,7 @@ class SchismotivateEffect extends ContinuousEffectImpl {
if (permanent != null) {
permanent.addPower(4);
}
- permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1));
+ permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent != null) {
permanent.addPower(-4);
}
diff --git a/Mage.Sets/src/mage/sets/legions/ElvishSoultiller.java b/Mage.Sets/src/mage/sets/legions/ElvishSoultiller.java
new file mode 100644
index 00000000000..014632be1d1
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/legions/ElvishSoultiller.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.legions;
+
+import java.util.UUID;
+import mage.MageInt;
+import mage.MageObject;
+import mage.abilities.Ability;
+import mage.abilities.common.DiesTriggeredAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.cards.CardImpl;
+import mage.cards.Cards;
+import mage.cards.CardsImpl;
+import mage.cards.repository.CardRepository;
+import mage.choices.Choice;
+import mage.choices.ChoiceImpl;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.constants.Rarity;
+import mage.filter.common.FilterCreatureCard;
+import mage.filter.predicate.mageobject.SubtypePredicate;
+import mage.game.Game;
+import mage.players.Player;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class ElvishSoultiller extends CardImpl {
+
+ public ElvishSoultiller(UUID ownerId) {
+ super(ownerId, 124, "Elvish Soultiller", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}{G}");
+ this.expansionSetCode = "LGN";
+ this.subtype.add("Elf");
+ this.subtype.add("Mutant");
+ this.power = new MageInt(5);
+ this.toughness = new MageInt(4);
+
+ // When Elvish Soultiller dies, choose a creature type. Shuffle all creature cards of that type from your graveyard into your library.
+ addAbility(new DiesTriggeredAbility(new ElvishSoultillerEffect()));
+
+ }
+
+ public ElvishSoultiller(final ElvishSoultiller card) {
+ super(card);
+ }
+
+ @Override
+ public ElvishSoultiller copy() {
+ return new ElvishSoultiller(this);
+ }
+}
+
+class ElvishSoultillerEffect extends OneShotEffect {
+
+ public ElvishSoultillerEffect() {
+ super(Outcome.Benefit);
+ this.staticText = "choose a creature type. Shuffle all creature cards of that type from your graveyard into your library";
+ }
+
+ public ElvishSoultillerEffect(final ElvishSoultillerEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public ElvishSoultillerEffect copy() {
+ return new ElvishSoultillerEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player controller = game.getPlayer(source.getControllerId());
+ MageObject mageObject = game.getObject(source.getSourceId());
+ if (controller != null && mageObject != null) {
+ Choice typeChoice = new ChoiceImpl(true);
+ typeChoice.setMessage("Choose creature type");
+ typeChoice.setChoices(CardRepository.instance.getCreatureTypes());
+ while (!controller.choose(outcome, typeChoice, game)) {
+ if (!controller.canRespond()) {
+ return false;
+ }
+ }
+ if (!game.isSimulation()) {
+ game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice());
+ }
+ Cards cardsToLibrary = new CardsImpl();
+ FilterCreatureCard filter = new FilterCreatureCard();
+ filter.add(new SubtypePredicate(typeChoice.getChoice()));
+ cardsToLibrary.addAll(controller.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game));
+ controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false);
+ controller.shuffleLibrary(game);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/limitedalpha/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/limitedalpha/LibraryOfLeng.java
new file mode 100644
index 00000000000..c929823f598
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/limitedalpha/LibraryOfLeng.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.limitedalpha;
+
+import java.util.UUID;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId);
+ this.cardNumber = 257;
+ this.expansionSetCode = "LEA";
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/limitedbeta/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/limitedbeta/LibraryOfLeng.java
new file mode 100644
index 00000000000..fc1b1df94a3
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/limitedbeta/LibraryOfLeng.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.limitedbeta;
+
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.Cards;
+import mage.cards.CardsImpl;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.constants.Rarity;
+import mage.constants.Zone;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.events.GameEvent.EventType;
+import mage.game.events.ZoneChangeEvent;
+import mage.players.Player;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends CardImpl {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId, 259, "Library of Leng", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{1}");
+ this.expansionSetCode = "LEB";
+
+ // You have no maximum hand size.
+ Effect effect = new MaximumHandSizeControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET);
+ addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
+
+ // If an effect causes you to discard a card, discard it, but you may put it on top of your library instead of into your graveyard.
+ addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LibraryOfLengEffect()));
+
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
+
+class LibraryOfLengEffect extends ReplacementEffectImpl {
+
+ private UUID cardId;
+ private int zoneChangeCounter;
+
+ public LibraryOfLengEffect() {
+ super(Duration.WhileOnBattlefield, Outcome.Benefit);
+ staticText = "If an effect causes you to discard a card, discard it, but you may put it on top of your library instead of into your graveyard";
+ }
+
+ public LibraryOfLengEffect(final LibraryOfLengEffect effect) {
+ super(effect);
+ this.cardId = effect.cardId;
+ this.zoneChangeCounter = effect.zoneChangeCounter;
+ }
+
+ @Override
+ public LibraryOfLengEffect copy() {
+ return new LibraryOfLengEffect(this);
+ }
+
+ @Override
+ public boolean checksEventType(GameEvent event, Game game) {
+ return event.getType().equals(EventType.DISCARD_CARD)
+ || event.getType().equals(EventType.ZONE_CHANGE);
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ if (event.getType().equals(EventType.DISCARD_CARD)) {
+ return event.getPlayerId().equals(source.getControllerId());
+ }
+ if (event.getType().equals(EventType.ZONE_CHANGE)) {
+ if (event.getTargetId().equals(cardId) && game.getState().getZoneChangeCounter(event.getTargetId()) == zoneChangeCounter) {
+ if (((ZoneChangeEvent) event).getFromZone().equals(Zone.HAND) && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean replaceEvent(GameEvent event, Ability source, Game game) {
+ if (event.getType().equals(EventType.DISCARD_CARD)) {
+ // only save card info
+ Card card = game.getCard(event.getTargetId());
+ if (card != null) {
+ cardId = card.getId();
+ zoneChangeCounter = game.getState().getZoneChangeCounter(cardId);
+ }
+ return false;
+ }
+ if (event.getType().equals(EventType.ZONE_CHANGE)) {
+ Player controller = game.getPlayer(source.getControllerId());
+ Card card = game.getCard(event.getTargetId());
+ if (controller != null && card != null) {
+ cardId = null;
+ zoneChangeCounter = 0;
+ if (controller.chooseUse(outcome, "Put " + card.getIdName() + " on top of your library instead?", source, game)) {
+ Cards cardsToLibrary = new CardsImpl(card);
+ controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java b/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java
index d6af2a5a2ab..9d646d73863 100644
--- a/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java
+++ b/Mage.Sets/src/mage/sets/magic2012/AdaptiveAutomaton.java
@@ -50,7 +50,6 @@ import mage.filter.predicate.permanent.AnotherPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
-import mage.players.Player;
/**
* @author nantuko
@@ -87,8 +86,8 @@ public class AdaptiveAutomaton extends CardImpl {
}
}
-
class AdaptiveAutomatonAddSubtypeEffect extends ContinuousEffectImpl {
+
public AdaptiveAutomatonAddSubtypeEffect() {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
staticText = "{this} is the chosen type in addition to its other types";
diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/masterseditioniv/LibraryOfLeng.java
new file mode 100644
index 00000000000..32b45b5106c
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/masterseditioniv/LibraryOfLeng.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.masterseditioniv;
+
+import java.util.UUID;
+import mage.constants.Rarity;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId);
+ this.cardNumber = 211;
+ this.expansionSetCode = "ME4";
+ this.rarity = Rarity.COMMON;
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java b/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java
index 3eccc7bed57..0f9c606abad 100644
--- a/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java
+++ b/Mage.Sets/src/mage/sets/modernmasters/IncrementalGrowth.java
@@ -35,6 +35,8 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.counters.CounterType;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
@@ -53,8 +55,23 @@ public class IncrementalGrowth extends CardImpl {
// Put a +1/+1 counter on target creature, two +1/+1 counters on another target creature, and three +1/+1 counters on a third target creature.
this.getSpellAbility().addEffect(new IncrementalGrowthEffect());
- Target target = new TargetCreaturePermanent(3,3);
- this.getSpellAbility().addTarget(target);
+
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets a +1/+1 counter)");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets two +1/+1 counter)");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
+
+ FilterCreaturePermanent filter3 = new FilterCreaturePermanent("another creature (gets three +1/+1 counters)");
+ filter3.add(new AnotherTargetPredicate(3));
+ TargetCreaturePermanent target3 = new TargetCreaturePermanent(filter3);
+ target3.setTargetTag(3);
+ this.getSpellAbility().addTarget(target3);
}
public IncrementalGrowth(final IncrementalGrowth card) {
@@ -86,9 +103,9 @@ class IncrementalGrowthEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
int i = 0;
- for (UUID targetId : getTargetPointer().getTargets(game, source)) {
+ for (Target target : source.getTargets()) {
i++;
- Permanent creature = game.getPermanent(targetId);
+ Permanent creature = game.getPermanent(target.getFirstTarget());
if (creature != null) {
creature.addCounters(CounterType.P1P1.createInstance(i), game);
}
diff --git a/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java b/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java
index 54869297d22..eb760b652e1 100644
--- a/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java
+++ b/Mage.Sets/src/mage/sets/newphyrexia/LeechingBite.java
@@ -28,15 +28,20 @@
package mage.sets.newphyrexia;
import java.util.UUID;
-import mage.abilities.effects.Effect;
-import mage.abilities.effects.common.continuous.BoostTargetEffect;
+import mage.abilities.Ability;
+import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
+import mage.constants.Layer;
+import mage.constants.Outcome;
import mage.constants.Rarity;
+import mage.constants.SubLayer;
import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetpointer.SecondTargetPointer;
/**
*
@@ -48,16 +53,20 @@ public class LeechingBite extends CardImpl {
super(ownerId, 113, "Leeching Bite", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}");
this.expansionSetCode = "NPH";
+
// Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn.
- Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn);
- effect.setText("Target creature gets +1/+1 until end of turn");
- this.getSpellAbility().addEffect(effect);
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (getting the +1/+1 counter)")));
- effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn);
- effect.setText("Another target creature gets -1/-1 until end of turn");
- effect.setTargetPointer(new SecondTargetPointer());
- this.getSpellAbility().addEffect(effect);
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (getting the -1/-1 counter)")));
+ this.getSpellAbility().addEffect(new LeechingBiteEffect());
+
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature to get +1/+1");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature to get -1/-1");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
}
public LeechingBite(final LeechingBite card) {
@@ -69,3 +78,35 @@ public class LeechingBite extends CardImpl {
return new LeechingBite(this);
}
}
+
+class LeechingBiteEffect extends ContinuousEffectImpl {
+
+ public LeechingBiteEffect() {
+ super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature);
+ this.staticText = "Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn";
+ }
+
+ public LeechingBiteEffect(final LeechingBiteEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public LeechingBiteEffect copy() {
+ return new LeechingBiteEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Permanent permanent = game.getPermanent(source.getFirstTarget());
+ if (permanent != null) {
+ permanent.addPower(1);
+ permanent.addToughness(1);
+ }
+ permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
+ if (permanent != null) {
+ permanent.addPower(-1);
+ permanent.addToughness(-1);
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/planarchaos/DismalFailure.java b/Mage.Sets/src/mage/sets/planarchaos/DismalFailure.java
new file mode 100644
index 00000000000..a6a9a3ab524
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/planarchaos/DismalFailure.java
@@ -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.sets.planarchaos;
+
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.effects.OneShotEffect;
+import mage.cards.CardImpl;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.constants.Rarity;
+import mage.game.Game;
+import mage.players.Player;
+import mage.target.TargetSpell;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class DismalFailure extends CardImpl {
+
+ public DismalFailure(UUID ownerId) {
+ super(ownerId, 39, "Dismal Failure", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{U}{U}");
+ this.expansionSetCode = "PLC";
+
+ // Counter target spell. Its controller discards a card.
+ this.getSpellAbility().addEffect(new DismalFailureEffect());
+ this.getSpellAbility().addTarget(new TargetSpell());
+ }
+
+ public DismalFailure(final DismalFailure card) {
+ super(card);
+ }
+
+ @Override
+ public DismalFailure copy() {
+ return new DismalFailure(this);
+ }
+}
+
+class DismalFailureEffect extends OneShotEffect {
+
+ public DismalFailureEffect() {
+ super(Outcome.Neutral);
+ this.staticText = "Counter target spell. Its controller discards a card";
+ }
+
+ public DismalFailureEffect(final DismalFailureEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public DismalFailureEffect copy() {
+ return new DismalFailureEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ UUID targetId = source.getFirstTarget();
+ Player controller = null;
+ boolean countered = false;
+ if (targetId != null) {
+ controller = game.getPlayer(game.getControllerId(targetId));
+ }
+ if (targetId != null
+ && game.getStack().counter(targetId, source.getSourceId(), game)) {
+ countered = true;
+ }
+ if (controller != null) {
+ controller.discard(1, false, source, game);
+ }
+ return countered;
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/prophecy/StealStrength.java b/Mage.Sets/src/mage/sets/prophecy/StealStrength.java
index c0dc42b53d9..514b0001b8c 100644
--- a/Mage.Sets/src/mage/sets/prophecy/StealStrength.java
+++ b/Mage.Sets/src/mage/sets/prophecy/StealStrength.java
@@ -37,6 +37,8 @@ import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.SubLayer;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
@@ -53,7 +55,17 @@ public class StealStrength extends CardImpl {
// Target creature gets +1/+1 until end of turn. Another target creature gets -1/-1 until end of turn.
this.getSpellAbility().addEffect(new StealStrengthEffect());
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(2));
+
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets +1/+1 until end of turn)");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets -1/-1 until end of turn)");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
}
public StealStrength(final StealStrength card) {
@@ -89,7 +101,7 @@ class StealStrengthEffect extends ContinuousEffectImpl {
permanent.addPower(1);
permanent.addToughness(1);
}
- permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1));
+ permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent != null) {
permanent.addPower(-1);
permanent.addToughness(-1);
diff --git a/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java b/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java
index b51d0f6adc1..07494f51551 100644
--- a/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java
+++ b/Mage.Sets/src/mage/sets/returntoravnica/RitesOfReaping.java
@@ -37,6 +37,8 @@ import mage.constants.SubLayer;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
@@ -54,7 +56,17 @@ public class RitesOfReaping extends CardImpl {
// Target creature gets +3/+3 until end of turn. Another target creature gets -3/-3 until end of turn.
this.getSpellAbility().addEffect(new RitesOfReapingEffect());
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(2));
+
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets +3/+3 until end of turn)");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets -3/-3 until end of turn)");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
}
public RitesOfReaping(final RitesOfReaping card) {
@@ -90,7 +102,7 @@ class RitesOfReapingEffect extends ContinuousEffectImpl {
permanent.addPower(3);
permanent.addToughness(3);
}
- permanent = game.getPermanent(source.getTargets().get(0).getTargets().get(1));
+ permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent != null) {
permanent.addPower(-3);
permanent.addToughness(-3);
diff --git a/Mage.Sets/src/mage/sets/revisededition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/revisededition/LibraryOfLeng.java
new file mode 100644
index 00000000000..ea198f03c13
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/revisededition/LibraryOfLeng.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.revisededition;
+
+import java.util.UUID;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId);
+ this.cardNumber = 261;
+ this.expansionSetCode = "3ED";
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java b/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java
index 1a18f370549..7cadbaed388 100644
--- a/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java
+++ b/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java
@@ -31,9 +31,7 @@ import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
-import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.constants.CardType;
@@ -42,7 +40,6 @@ import mage.constants.Rarity;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
-import mage.target.targetpointer.FixedTarget;
/**
*
@@ -94,14 +91,17 @@ class CragganwickCrematorEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- Player you = game.getPlayer(source.getControllerId());
- Player targetedPlayer = game.getPlayer(source.getFirstTarget());
- if (you != null && targetedPlayer != null) {
- Card discardedCard = targetedPlayer.discardOne(true, source, game);
+ Player controller = game.getPlayer(source.getControllerId());
+
+ if (controller != null) {
+ Card discardedCard = controller.discardOne(true, source, game);
if (discardedCard != null
&& discardedCard.getCardType().contains(CardType.CREATURE)) {
- int damage = discardedCard.getPower().getValue();
- targetedPlayer.damage(damage, source.getSourceId(), game, false, true);
+ Player targetedPlayer = game.getPlayer(source.getFirstTarget());
+ if (targetedPlayer != null) {
+ int damage = discardedCard.getPower().getValue();
+ targetedPlayer.damage(damage, source.getSourceId(), game, false, true);
+ }
}
return true;
}
diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java b/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java
index 811237a3b48..6cc21583286 100644
--- a/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java
+++ b/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java
@@ -36,6 +36,7 @@ import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.counters.Counter;
import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
@@ -47,7 +48,7 @@ import mage.target.common.TargetCreaturePermanent;
public class FateTransfer extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature to move all counters from");
- private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("target creature to move all counters to");
+ private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target creature to move all counters to");
public FateTransfer(UUID ownerId) {
super(ownerId, 161, "Fate Transfer", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U/B}");
@@ -55,8 +56,15 @@ public class FateTransfer extends CardImpl {
// Move all counters from target creature onto another target creature.
this.getSpellAbility().addEffect(new FateTransferEffect());
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
- this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter2));
+
+ TargetCreaturePermanent fromTarget = new TargetCreaturePermanent(filter);
+ fromTarget.setTargetTag(1);
+ this.getSpellAbility().addTarget(fromTarget);
+
+ TargetCreaturePermanent toTarget = new TargetCreaturePermanent(filter2);
+ filter2.add(new AnotherTargetPredicate(2));
+ toTarget.setTargetTag(2);
+ this.getSpellAbility().addTarget(toTarget);
}
diff --git a/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java b/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java
index 52e1c7100a8..b2641294305 100644
--- a/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java
+++ b/Mage.Sets/src/mage/sets/shadowmoor/IncrementalBlight.java
@@ -35,6 +35,8 @@ import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.counters.CounterType;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
@@ -53,8 +55,23 @@ public class IncrementalBlight extends CardImpl {
// Put a -1/-1 counter on target creature, two -1/-1 counters on another target creature, and three -1/-1 counters on a third target creature.
this.getSpellAbility().addEffect(new IncrementalBlightEffect());
- Target target = new TargetCreaturePermanent(3,3);
- this.getSpellAbility().addTarget(target);
+
+ FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature (gets a -1/-1 counter)");
+ TargetCreaturePermanent target1 = new TargetCreaturePermanent(filter1);
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
+ FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another creature (gets two -1/-1 counters)");
+ filter2.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
+
+ FilterCreaturePermanent filter3 = new FilterCreaturePermanent("another creature (gets three -1/-1 counters)");
+ filter3.add(new AnotherTargetPredicate(3));
+ TargetCreaturePermanent target3 = new TargetCreaturePermanent(filter3);
+ target3.setTargetTag(3);
+ this.getSpellAbility().addTarget(target3);
}
public IncrementalBlight(final IncrementalBlight card) {
@@ -85,9 +102,9 @@ class IncrementalBlightEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
int i = 0;
- for (UUID targetId : getTargetPointer().getTargets(game, source)) {
+ for (Target target : source.getTargets()) {
i++;
- Permanent creature = game.getPermanent(targetId);
+ Permanent creature = game.getPermanent(target.getFirstTarget());
if (creature != null) {
creature.addCounters(CounterType.M1M1.createInstance(i), game);
}
diff --git a/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java b/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java
index 0f7291ab53e..7119873a085 100644
--- a/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java
+++ b/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java
@@ -124,7 +124,7 @@ class RealmRazerEffect extends OneShotEffect {
if (controller != null) {
ExileZone exZone = game.getExile().getExileZone(source.getSourceId());
if (exZone != null) {
- return controller.moveCards(exZone.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null);
+ return controller.moveCards(exZone.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null);
}
return true;
}
diff --git a/Mage.Sets/src/mage/sets/unlimitededition/LibraryOfLeng.java b/Mage.Sets/src/mage/sets/unlimitededition/LibraryOfLeng.java
new file mode 100644
index 00000000000..0db34db7436
--- /dev/null
+++ b/Mage.Sets/src/mage/sets/unlimitededition/LibraryOfLeng.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.sets.unlimitededition;
+
+import java.util.UUID;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class LibraryOfLeng extends mage.sets.limitedbeta.LibraryOfLeng {
+
+ public LibraryOfLeng(UUID ownerId) {
+ super(ownerId);
+ this.cardNumber = 258;
+ this.expansionSetCode = "2ED";
+ }
+
+ public LibraryOfLeng(final LibraryOfLeng card) {
+ super(card);
+ }
+
+ @Override
+ public LibraryOfLeng copy() {
+ return new LibraryOfLeng(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/worldwake/FeralContest.java b/Mage.Sets/src/mage/sets/worldwake/FeralContest.java
index b519cab6c9c..2ff3ec2b193 100644
--- a/Mage.Sets/src/mage/sets/worldwake/FeralContest.java
+++ b/Mage.Sets/src/mage/sets/worldwake/FeralContest.java
@@ -37,6 +37,8 @@ import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.constants.Duration;
import mage.counters.CounterType;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledCreaturePermanent;
@@ -54,10 +56,18 @@ public class FeralContest extends CardImpl {
// Put a +1/+1 counter on target creature you control.
this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
- this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
+
+ TargetControlledCreaturePermanent target1 = new TargetControlledCreaturePermanent();
+ target1.setTargetTag(1);
+ this.getSpellAbility().addTarget(target1);
+
// Another target creature blocks it this turn if able.
this.getSpellAbility().addEffect(new FeralContestEffect());
- this.getSpellAbility().addTarget(new TargetCreaturePermanent());
+ FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature (must block this turn)");
+ filter.add(new AnotherTargetPredicate(2));
+ TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter);
+ target2.setTargetTag(2);
+ this.getSpellAbility().addTarget(target2);
}
public FeralContest(final FeralContest card) {
diff --git a/Mage.Stats/pom.xml b/Mage.Stats/pom.xml
index 63c9fa979b0..8393d25c828 100644
--- a/Mage.Stats/pom.xml
+++ b/Mage.Stats/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
org.mage
diff --git a/Mage.Tests/pom.xml b/Mage.Tests/pom.xml
index 6714da9223a..279c225f293 100644
--- a/Mage.Tests/pom.xml
+++ b/Mage.Tests/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
mage-tests
diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
index 280c227ac81..a4e73e15331 100644
--- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
+++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
@@ -2077,4 +2077,8 @@ public class TestPlayer implements Player {
return AIPlayer;
}
+ public String getHistory() {
+ return computerPlayer.getHistory();
+ }
+
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java
index bcfa18d0f54..ecc5c3df051 100644
--- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java
+++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java
@@ -1,9 +1,19 @@
package org.mage.test.serverside.base;
-import mage.constants.PhaseStep;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import mage.cards.Card;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
+import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.game.Game;
@@ -25,19 +35,13 @@ import org.junit.BeforeClass;
import org.mage.test.player.RandomPlayer;
import org.mage.test.player.TestPlayer;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FilenameFilter;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
/**
* Base class for all tests.
*
* @author ayratn
*/
public abstract class MageTestBase {
+
protected static Logger logger = Logger.getLogger(MageTestBase.class);
public static PluginClassLoader classLoader = new PluginClassLoader();
@@ -46,17 +50,17 @@ public abstract class MageTestBase {
protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)(:\\{tapped\\})?");
- protected List handCardsA = new ArrayList();
- protected List handCardsB = new ArrayList();
- protected List battlefieldCardsA = new ArrayList();
- protected List battlefieldCardsB = new ArrayList();
- protected List graveyardCardsA = new ArrayList();
- protected List graveyardCardsB = new ArrayList();
- protected List libraryCardsA = new ArrayList();
- protected List libraryCardsB = new ArrayList();
+ protected List handCardsA = new ArrayList<>();
+ protected List handCardsB = new ArrayList<>();
+ protected List battlefieldCardsA = new ArrayList<>();
+ protected List battlefieldCardsB = new ArrayList<>();
+ protected List graveyardCardsA = new ArrayList<>();
+ protected List graveyardCardsB = new ArrayList<>();
+ protected List libraryCardsA = new ArrayList<>();
+ protected List libraryCardsB = new ArrayList<>();
- protected Map commandsA = new HashMap();
- protected Map commandsB = new HashMap();
+ protected Map commandsA = new HashMap<>();
+ protected Map commandsB = new HashMap<>();
protected TestPlayer playerA;
protected TestPlayer playerB;
@@ -67,8 +71,7 @@ public abstract class MageTestBase {
protected static Game currentGame = null;
/**
- * Player thats starts the game first.
- * By default, it is ComputerA.
+ * Player thats starts the game first. By default, it is ComputerA.
*/
protected static Player activePlayer = null;
@@ -77,6 +80,7 @@ public abstract class MageTestBase {
protected PhaseStep stopAtStep = PhaseStep.UNTAP;
protected enum ParserState {
+
INIT,
OPTIONS,
EXPECTED
@@ -85,18 +89,13 @@ public abstract class MageTestBase {
protected ParserState parserState;
/**
- * Expected results of the test.
- * Read from test case in {@link String} based format:
+ * Expected results of the test. Read from test case in {@link String} based
+ * format:
*
- * Example:
- * turn:1
- * result:won:ComputerA
- * life:ComputerA:20
- * life:ComputerB:0
- * battlefield:ComputerB:Tine Shrike:0
- * graveyard:ComputerB:Tine Shrike:1
+ * Example: turn:1 result:won:ComputerA life:ComputerA:20 life:ComputerB:0
+ * battlefield:ComputerB:Tine Shrike:0 graveyard:ComputerB:Tine Shrike:1
*/
- protected List expectedResults = new ArrayList();
+ protected List expectedResults = new ArrayList<>();
protected static final String TESTS_PATH = "tests" + File.separator;
@@ -163,8 +162,9 @@ public abstract class MageTestBase {
private static void deleteSavedGames() {
File directory = new File("saved/");
- if (!directory.exists())
+ if (!directory.exists()) {
directory.mkdirs();
+ }
File[] files = directory.listFiles(
new FilenameFilter() {
@Override
@@ -185,7 +185,9 @@ public abstract class MageTestBase {
try {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
- if (line == null || line.isEmpty() || line.startsWith("#")) continue;
+ if (line == null || line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
if (line.startsWith("$include")) {
includeFrom(line);
continue;
diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java
index d076ed3265c..18288af786a 100644
--- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java
+++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java
@@ -1237,4 +1237,10 @@ public class PlayerStub implements Player {
public boolean addTargets(Ability ability, Game game) {
return false;
}
+
+ @Override
+ public String getHistory() {
+ return "";
+ }
+
}
diff --git a/Mage.Updater/pom.xml b/Mage.Updater/pom.xml
index 2e452c1d49f..cc2e47e1b97 100644
--- a/Mage.Updater/pom.xml
+++ b/Mage.Updater/pom.xml
@@ -5,7 +5,7 @@
mage-root
org.mage
- 1.4.7
+ 1.4.8
4.0.0
diff --git a/Mage/pom.xml b/Mage/pom.xml
index d81c9655d9b..30c0b461c1e 100644
--- a/Mage/pom.xml
+++ b/Mage/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
mage
diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java
index 855a16527ef..cc140503ba2 100644
--- a/Mage/src/main/java/mage/cards/repository/CardRepository.java
+++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java
@@ -63,7 +63,7 @@ public enum CardRepository {
// raise this if db structure was changed
private static final long CARD_DB_VERSION = 43;
// raise this if new cards were added to the server
- private static final long CARD_CONTENT_VERSION = 44;
+ private static final long CARD_CONTENT_VERSION = 45;
private final Random random = new Random();
private Dao cardDao;
diff --git a/Mage/src/main/java/mage/game/Seat.java b/Mage/src/main/java/mage/game/Seat.java
index 751a18d3932..f9a3325ac23 100644
--- a/Mage/src/main/java/mage/game/Seat.java
+++ b/Mage/src/main/java/mage/game/Seat.java
@@ -24,8 +24,7 @@
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
-*/
-
+ */
package mage.game;
import java.io.Serializable;
@@ -38,7 +37,6 @@ import mage.players.Player;
public class Seat implements Serializable {
// private static final Logger logger = Logger.getLogger(Seat.class);
-
private String playerType;
private Player player;
diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java
index 95b1a318e67..46cce3480e9 100644
--- a/Mage/src/main/java/mage/game/events/GameEvent.java
+++ b/Mage/src/main/java/mage/game/events/GameEvent.java
@@ -91,6 +91,7 @@ public class GameEvent implements Serializable {
DRAW_CARD, DREW_CARD,
MIRACLE_CARD_REVEALED,
MADNESS_CARD_EXILED,
+ DISCARD_CARD,
DISCARDED_CARD,
CYCLE_CARD, CYCLED_CARD,
CLASH, CLASHED,
diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java
index 654f503e0c8..9bad10ada90 100644
--- a/Mage/src/main/java/mage/players/Player.java
+++ b/Mage/src/main/java/mage/players/Player.java
@@ -824,4 +824,6 @@ public interface Player extends MageItem, Copyable {
* @return
*/
boolean addTargets(Ability ability, Game game);
+
+ String getHistory();
}
diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java
index 07ac9fb6e8f..301900b70cf 100644
--- a/Mage/src/main/java/mage/players/PlayerImpl.java
+++ b/Mage/src/main/java/mage/players/PlayerImpl.java
@@ -92,6 +92,14 @@ import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.PlayerAction;
+import static mage.constants.PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS;
+import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN;
+import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE;
+import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN;
+import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED;
+import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP;
+import static mage.constants.PlayerAction.PERMISSION_REQUESTS_ALLOWED_OFF;
+import static mage.constants.PlayerAction.PERMISSION_REQUESTS_ALLOWED_ON;
import mage.constants.RangeOfInfluence;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
@@ -516,31 +524,29 @@ public abstract class PlayerImpl implements Player, Serializable {
inRange.add(player.getId());
}
}
+ } else if ((range.getRange() * 2) + 1 >= game.getPlayers().size()) {
+ for (Player player : game.getPlayers().values()) {
+ if (!player.hasLeft()) {
+ inRange.add(player.getId());
+ }
+ }
} else {
- if ((range.getRange() * 2) + 1 >= game.getPlayers().size()) {
- for (Player player : game.getPlayers().values()) {
- if (!player.hasLeft()) {
- inRange.add(player.getId());
- }
+ inRange.add(playerId);
+ PlayerList players = game.getState().getPlayerList(playerId);
+ for (int i = 0; i < range.getRange(); i++) {
+ Player player = players.getNext(game);
+ while (player.hasLeft()) {
+ player = players.getNext(game);
}
- } else {
- inRange.add(playerId);
- PlayerList players = game.getState().getPlayerList(playerId);
- for (int i = 0; i < range.getRange(); i++) {
- Player player = players.getNext(game);
- while (player.hasLeft()) {
- player = players.getNext(game);
- }
- inRange.add(player.getId());
- }
- players = game.getState().getPlayerList(playerId);
- for (int i = 0; i < range.getRange(); i++) {
- Player player = players.getPrevious(game);
- while (player.hasLeft()) {
- player = players.getPrevious(game);
- }
- inRange.add(player.getId());
+ inRange.add(player.getId());
+ }
+ players = game.getState().getPlayerList(playerId);
+ for (int i = 0; i < range.getRange(); i++) {
+ Player player = players.getPrevious(game);
+ while (player.hasLeft()) {
+ player = players.getPrevious(game);
}
+ inRange.add(player.getId());
}
}
}
@@ -760,7 +766,8 @@ public abstract class PlayerImpl implements Player, Serializable {
about the discarded card, that cost payment is illegal; the game returns to
the moment before the cost was paid (see rule 717, "Handling Illegal Actions").
*/
- if (card != null) {
+ if (card != null
+ && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD, card.getId(), source == null ? null : source.getSourceId(), playerId), source)) {
// write info to game log first so game log infos from triggered or replacement effects follow in the game log
if (!game.isSimulation()) {
game.informPlayers(getLogName() + " discards " + card.getLogName());
@@ -2089,7 +2096,8 @@ public abstract class PlayerImpl implements Player, Serializable {
break;
}
}
- if (!opponentInGame || // if no more opponent is in game the wins event may no longer be replaced
+ if (!opponentInGame
+ || // if no more opponent is in game the wins event may no longer be replaced
!game.replaceEvent(new GameEvent(GameEvent.EventType.WINS, null, null, playerId))) {
logger.debug("player won -> start: " + this.getName());
if (!this.loses) {
@@ -2169,10 +2177,8 @@ public abstract class PlayerImpl implements Player, Serializable {
if (blocker != null && group != null && group.canBlock(blocker, game)) {
group.addBlocker(blockerId, playerId, game);
game.getCombat().addBlockingGroup(blockerId, attackerId, playerId, game);
- } else {
- if (this.isHuman() && !game.isSimulation()) {
- game.informPlayer(this, "You can't block this creature.");
- }
+ } else if (this.isHuman() && !game.isSimulation()) {
+ game.informPlayer(this, "You can't block this creature.");
}
}
@@ -2793,14 +2799,12 @@ public abstract class PlayerImpl implements Player, Serializable {
}
if (targetNum < option.getTargets().size() - 2) {
addTargetOptions(options, newOption, targetNum + 1, game);
+ } else if (option.getChoices().size() > 0) {
+ addChoiceOptions(options, newOption, 0, game);
+ } else if (option.getCosts().getTargets().size() > 0) {
+ addCostTargetOptions(options, newOption, 0, game);
} else {
- if (option.getChoices().size() > 0) {
- addChoiceOptions(options, newOption, 0, game);
- } else if (option.getCosts().getTargets().size() > 0) {
- addCostTargetOptions(options, newOption, 0, game);
- } else {
- options.add(newOption);
- }
+ options.add(newOption);
}
}
}
@@ -2811,12 +2815,10 @@ public abstract class PlayerImpl implements Player, Serializable {
newOption.getChoices().get(choiceNum).setChoice(choice);
if (choiceNum < option.getChoices().size() - 1) {
addChoiceOptions(options, newOption, choiceNum + 1, game);
+ } else if (option.getCosts().getTargets().size() > 0) {
+ addCostTargetOptions(options, newOption, 0, game);
} else {
- if (option.getCosts().getTargets().size() > 0) {
- addCostTargetOptions(options, newOption, 0, game);
- } else {
- options.add(newOption);
- }
+ options.add(newOption);
}
}
}
@@ -3503,4 +3505,9 @@ public abstract class PlayerImpl implements Player, Serializable {
return true;
}
+ @Override
+ public String getHistory() {
+ return "no available";
+ }
+
}
diff --git a/Mage/src/main/java/mage/players/net/UserData.java b/Mage/src/main/java/mage/players/net/UserData.java
index c2c3b2a3bb4..bca9f231700 100644
--- a/Mage/src/main/java/mage/players/net/UserData.java
+++ b/Mage/src/main/java/mage/players/net/UserData.java
@@ -23,6 +23,8 @@ public class UserData implements Serializable {
protected boolean passPriorityActivation;
protected boolean autoOrderTrigger;
+ protected String history;
+
public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced,
boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps,
String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted,
@@ -40,6 +42,7 @@ public class UserData implements Serializable {
this.passPriorityCast = passPriorityCast;
this.passPriorityActivation = passPriorityActivation;
this.autoOrderTrigger = autoOrderTrigger;
+ this.history = "";
}
public void update(UserData userData) {
@@ -166,7 +169,16 @@ public class UserData implements Serializable {
this.autoOrderTrigger = autoOrderTrigger;
}
+ public void setHistory(String history) {
+ this.history = history;
+ }
+
+ public String getHistory() {
+ return history;
+ }
+
public static String getDefaultFlagName() {
return "world.png";
}
+
}
diff --git a/Utils/release/getting_implemented_cards.txt b/Utils/release/getting_implemented_cards.txt
index 8a4b8ad0f8e..06cf52b409a 100644
--- a/Utils/release/getting_implemented_cards.txt
+++ b/Utils/release/getting_implemented_cards.txt
@@ -54,6 +54,9 @@ git log 2ad15bbd48d5ae34b0cb5d709895d406b977d104..head --diff-filter=A --name-st
since 1.4.7v0
git log 8b37d0b989ba19f0dfccc81db66f5a21cc71fb94..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt
+since 1.4.8v0
+git log 804f9e7fc2b481f7f784943409f558a671088372..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt
+
3. Copy added_cards.txt to trunk\Utils folder
4. Run script:
> perl extract_in_wiki_format.perl
diff --git a/hs_err_pid4700.log b/hs_err_pid4700.log
deleted file mode 100644
index e8d083da24a..00000000000
--- a/hs_err_pid4700.log
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# There is insufficient memory for the Java Runtime Environment to continue.
-# Native memory allocation (malloc) failed to allocate 1048576 bytes for AllocateHeap
-# Possible reasons:
-# The system is out of physical RAM or swap space
-# In 32 bit mode, the process size limit was hit
-# Possible solutions:
-# Reduce memory load on the system
-# Increase physical memory or swap space
-# Check if swap backing store is full
-# Use 64 bit Java on a 64 bit OS
-# Decrease Java heap size (-Xmx/-Xms)
-# Decrease number of Java threads
-# Decrease Java thread stack sizes (-Xss)
-# Set larger code cache with -XX:ReservedCodeCacheSize=
-# This output file may be truncated or incomplete.
-#
-# Out of Memory Error (memory/allocation.inline.hpp:61), pid=4700, tid=4912
-#
-# JRE version: (7.0_71-b14) (build )
-# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.71-b01 mixed mode windows-amd64 compressed oops)
-# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
-#
-
---------------- T H R E A D ---------------
-
-Current thread (0x000000000223f000): JavaThread "Unknown thread" [_thread_in_vm, id=4912, stack(0x00000000025b0000,0x00000000026b0000)]
-
-Stack: [0x00000000025b0000,0x00000000026b0000]
-[error occurred during error reporting (printing stack bounds), id 0xc0000005]
-
-
---------------- P R O C E S S ---------------
-
-Java Threads: ( => current thread )
-
-Other Threads:
-
-=>0x000000000223f000 (exited) JavaThread "Unknown thread" [_thread_in_vm, id=4912, stack(0x00000000025b0000,0x00000000026b0000)]
-
-VM state:not at safepoint (normal execution)
-
-VM Mutex/Monitor currently owned by a thread: None
-
-Heap
- PSYoungGen total 612352K, used 10506K [0x00000007d5500000, 0x0000000800000000, 0x0000000800000000)
- eden space 525312K, 2% used [0x00000007d5500000,0x00000007d5f42948,0x00000007f5600000)
- from space 87040K, 0% used [0x00000007fab00000,0x00000007fab00000,0x0000000800000000)
- to space 87040K, 0% used [0x00000007f5600000,0x00000007f5600000,0x00000007fab00000)
- ParOldGen total 1398272K, used 0K [0x000000077ff80000, 0x00000007d5500000, 0x00000007d5500000)
- object space 1398272K, 0% used [0x000000077ff80000,0x000000077ff80000,0x00000007d5500000)
- PSPermGen total 21504K, used 694K [0x000000077ad80000, 0x000000077c280000, 0x000000077ff80000)
- object space 21504K, 3% used [0x000000077ad80000,0x000000077ae2d9f8,0x000000077c280000)
-
-Card table byte_map: [0x00000000056b0000,0x0000000005ae0000] byte_map_base: 0x0000000001ad9400
-
-Polling page: 0x0000000000240000
-
-Code Cache [0x00000000026b0000, 0x0000000002920000, 0x00000000056b0000)
- total_blobs=37 nmethods=0 adapters=20 free_code_cache=48890Kb largest_free_block=50063104
-
-Compilation events (0 events):
-No events
-
-GC Heap History (0 events):
-No events
-
-Deoptimization events (0 events):
-No events
-
-Internal exceptions (0 events):
-No events
-
-Events (10 events):
-Event: 0.029 loading class 0x00000000022bed40
-Event: 0.029 loading class 0x00000000022bed40 done
-Event: 0.029 loading class 0x00000000022bed90
-Event: 0.029 loading class 0x00000000022bed90 done
-Event: 0.029 loading class 0x00000000022bede0
-Event: 0.029 loading class 0x00000000022bede0 done
-Event: 0.030 loading class 0x00000000022bfb40
-Event: 0.030 loading class 0x00000000022bfb40 done
-Event: 0.030 loading class 0x00000000022bf760
-Event: 0.030 loading class 0x00000000022bf760 done
-
-
-Dynamic libraries:
-0x000000013f320000 - 0x000000013f353000 C:\Program Files\Java\jdk1.7.0_71\bin\java.exe
-0x00000000770c0000 - 0x0000000077269000 C:\Windows\SYSTEM32\ntdll.dll
-0x0000000076ea0000 - 0x0000000076fbf000 C:\Windows\system32\kernel32.dll
-0x000007fefd170000 - 0x000007fefd1dc000 C:\Windows\system32\KERNELBASE.dll
-0x000007fefd7c0000 - 0x000007fefd89b000 C:\Windows\system32\ADVAPI32.dll
-0x000007feff300000 - 0x000007feff39f000 C:\Windows\system32\msvcrt.dll
-0x000007fefe7e0000 - 0x000007fefe7ff000 C:\Windows\SYSTEM32\sechost.dll
-0x000007fefd8a0000 - 0x000007fefd9cd000 C:\Windows\system32\RPCRT4.dll
-0x0000000076fc0000 - 0x00000000770ba000 C:\Windows\system32\USER32.dll
-0x000007fefd230000 - 0x000007fefd297000 C:\Windows\system32\GDI32.dll
-0x000007fefef50000 - 0x000007fefef5e000 C:\Windows\system32\LPK.dll
-0x000007feff230000 - 0x000007feff2f9000 C:\Windows\system32\USP10.dll
-0x000007fefb490000 - 0x000007fefb684000 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.18837_none_fa3b1e3d17594757\COMCTL32.dll
-0x000007fefe760000 - 0x000007fefe7d1000 C:\Windows\system32\SHLWAPI.dll
-0x000007feff3a0000 - 0x000007feff3ce000 C:\Windows\system32\IMM32.DLL
-0x000007fefe9f0000 - 0x000007fefeaf9000 C:\Windows\system32\MSCTF.dll
-0x000000006ab40000 - 0x000000006ac12000 C:\Program Files\Java\jdk1.7.0_71\jre\bin\msvcr100.dll
-0x0000000067b10000 - 0x00000000682e3000 C:\Program Files\Java\jdk1.7.0_71\jre\bin\server\jvm.dll
-0x000007fefa970000 - 0x000007fefa979000 C:\Windows\system32\WSOCK32.dll
-0x000007fefd690000 - 0x000007fefd6dd000 C:\Windows\system32\WS2_32.dll
-0x000007fefe9e0000 - 0x000007fefe9e8000 C:\Windows\system32\NSI.dll
-0x000007fefaf60000 - 0x000007fefaf9b000 C:\Windows\system32\WINMM.dll
-0x0000000077290000 - 0x0000000077297000 C:\Windows\system32\PSAPI.DLL
-0x000000006f510000 - 0x000000006f51f000 C:\Program Files\Java\jdk1.7.0_71\jre\bin\verify.dll
-0x000000006c820000 - 0x000000006c848000 C:\Program Files\Java\jdk1.7.0_71\jre\bin\java.dll
-0x000000006c860000 - 0x000000006c875000 C:\Program Files\Java\jdk1.7.0_71\jre\bin\zip.dll
-
-VM Arguments:
-jvm_args: -Xms2048m -Xmx2048m -Dclassworlds.conf=C:\Program Files\NetBeans 8.0.2\java\maven\bin\m2.conf -Dmaven.home=C:\Program Files\NetBeans 8.0.2\java\maven
-java_command: org.codehaus.plexus.classworlds.launcher.Launcher -Dmaven.ext.class.path=C:\Users\fireshoes\AppData\Roaming\NetBeans\8.0.2\maven-nblib\netbeans-eventspy.jar -Dfile.encoding=UTF-8 clean install
-Launcher Type: SUN_STANDARD
-
-Environment Variables:
-JAVA_HOME=C:\Program Files\Java\jdk1.7.0_71
-PATH=c:\Program FIles\Apache Software Foundation\apache-maven-3.2.3\bin;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\AMD APP\bin\x86_64;C:\Program Files (x86)\AMD APP\bin\x86;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Program FIles\Java\jdk1.7.0_71\bin;C:\Strawberry\c\bin;C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;C:\Program Files (x86)\Git\cmd;C:\apache-maven-3.3.9-src\apache-maven-3.3.9\apache-maven\src
-USERNAME=fireshoes
-OS=Windows_NT
-PROCESSOR_IDENTIFIER=AMD64 Family 18 Model 1 Stepping 0, AuthenticAMD
-
-
-
---------------- S Y S T E M ---------------
-
-OS: Windows 7 , 64 bit Build 7601 Service Pack 1
-
-CPU:total 4 (4 cores per cpu, 1 threads per core) family 18 model 1 stepping 0, cmov, cx8, fxsr, mmx, sse, sse2, sse3, popcnt, mmxext, 3dnowpref, lzcnt, sse4a, tsc, tscinvbit, tscinv
-
-Memory: 4k page, physical 3559120k(796500k free), swap 7967852k(857396k free)
-
-vm_info: Java HotSpot(TM) 64-Bit Server VM (24.71-b01) for windows-amd64 JRE (1.7.0_71-b14), built on Sep 26 2014 16:16:12 by "java_re" with unknown MS VC++:1600
-
-time: Wed Jan 20 09:21:37 2016
-elapsed time: 0 seconds
-
diff --git a/pom.xml b/pom.xml
index a42d4eac758..5dbc875485c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.mage
mage-root
- 1.4.7
+ 1.4.8
pom
Mage Root
Mage Root POM
@@ -83,7 +83,7 @@
- 1.4.7
+ 1.4.8
UTF-8