diff --git a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
index 50b06f8383..ea00608dda 100644
--- a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
+++ b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
@@ -43,7 +43,6 @@ import mage.client.util.gui.ArrowBuilder;
import mage.remote.Session;
import org.apache.log4j.Logger;
-import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.Serializable;
@@ -117,6 +116,7 @@ public class FeedbackPanel extends javax.swing.JPanel {
this.btnRight.setVisible(true);
this.btnRight.setText("Cancel");
this.helper.setState("", false, "Cancel", true);
+ this.helper.setUndoEnabled(false);
break;
case SELECT:
this.btnLeft.setVisible(false);
@@ -149,7 +149,7 @@ public class FeedbackPanel extends javax.swing.JPanel {
this.revalidate();
this.repaint();
- this.helper.setLinks(btnLeft, btnRight, btnSpecial);
+ this.helper.setLinks(btnLeft, btnRight, btnSpecial, btnUndo);
this.helper.setVisible(true);
}
@@ -205,7 +205,6 @@ public class FeedbackPanel extends javax.swing.JPanel {
}
public void clear() {
-// stopModal();
this.btnLeft.setVisible(false);
this.btnRight.setVisible(false);
this.btnSpecial.setVisible(false);
@@ -213,138 +212,14 @@ public class FeedbackPanel extends javax.swing.JPanel {
logger.debug("feedback - clear");
}
-// public void clear0() {
-// stopModal();
-// }
-
-// private synchronized void startModal() {
-//
-// try {
-// if (SwingUtilities.isEventDispatchThread()) {
-// EventQueue theQueue = getToolkit().getSystemEventQueue();
-// while (!selected) {
-// AWTEvent event = theQueue.getNextEvent();
-// Object source = event.getSource();
-// boolean dispatch = true;
-//
-// if (event instanceof MouseEvent) {
-// MouseEvent e = (MouseEvent) event;
-// MouseEvent m = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this);
-// if (!this.contains(m.getPoint()) && e.getID() != MouseEvent.MOUSE_DRAGGED) {
-// dispatch = false;
-// }
-// }
-//
-// if (dispatch) {
-// if (event instanceof ActiveEvent) {
-// ((ActiveEvent) event).dispatch();
-// } else if (source instanceof Component) {
-// ((Component) source).dispatchEvent(event);
-// } else if (source instanceof MenuComponent) {
-// ((MenuComponent) source).dispatchEvent(event);
-// } else {
-// logger.warn("Unable to dispatch: " + event);
-// }
-// }
-// }
-// } else {
-// while (!selected) {
-// wait();
-// }
-// }
-// } catch (InterruptedException ignored) {
-// }
-//
-// }
-//
-// private synchronized void stopModal() {
-// notifyAll();
-// }
-
- /** This method is called from within the constructor to
- * initialize the form.
- * WARNING: Do NOT modify this code. The content of this method is
- * always regenerated by the Form Editor.
- */
- @SuppressWarnings("unchecked")
- // //GEN-BEGIN:initComponents
- private void initComponents() {
-
- btnRight = new javax.swing.JButton();
- btnLeft = new javax.swing.JButton();
- jScrollPane1 = new javax.swing.JScrollPane();
- //lblMessage = new javax.swing.JTextArea();
- lblMessage = new MageTextArea();
- btnSpecial = new javax.swing.JButton();
-
- setBackground(new java.awt.Color(255,255,255,200));
-
- btnRight.setText("Cancel");
- btnRight.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- btnRightActionPerformed(evt);
- }
- });
-
- btnLeft.setText("OK");
- btnLeft.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- btnLeftActionPerformed(evt);
- }
- });
-
- jScrollPane1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
- jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
-
- //lblMessage.setBackground(new java.awt.Color(204, 204, 204));
- /*lblMessage.setColumns(20);
- lblMessage.setEditable(false);
- lblMessage.setLineWrap(true);
- lblMessage.setRows(2);
- lblMessage.setWrapStyleWord(true);*/
-
- lblMessage.setBorder(null);
- jScrollPane1.setViewportView(lblMessage);
- jScrollPane1.setBorder(null);
-
- btnSpecial.setText("Special");
- btnSpecial.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- btnSpecialActionPerformed(evt);
- }
- });
-
- javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
- this.setLayout(layout);
- layout.setHorizontalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(btnSpecial)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 31, Short.MAX_VALUE)
- .addComponent(btnLeft)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(btnRight))
- .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 224, Short.MAX_VALUE)
- );
- layout.setVerticalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(btnRight)
- .addComponent(btnLeft)
- .addComponent(btnSpecial)))
- );
- }// //GEN-END:initComponents
-
public void customInitComponents() {
btnRight = new javax.swing.JButton();
btnLeft = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
lblMessage = new MageTextArea();
btnSpecial = new javax.swing.JButton();
+ btnUndo = new javax.swing.JButton();
+ btnUndo.setVisible(true);
setBackground(new java.awt.Color(0,0,0,80));
@@ -379,26 +254,18 @@ public class FeedbackPanel extends javax.swing.JPanel {
}
});
- JLabel jlabel = new JLabel();
- jlabel.setLayout(new BorderLayout());
- jlabel.add(jScrollPane1, BorderLayout.CENTER);
+ btnUndo.setText("Undo");
+ btnUndo.addActionListener(new java.awt.event.ActionListener() {
+ @Override
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnUndoActionPerformed(evt);
+ }
+ });
- setLayout(new BorderLayout());
-
- JLabel jlabel2 = new JLabel();
- jlabel2.setLayout(new FlowLayout());
- jlabel2.add(btnSpecial);
- jlabel2.add(btnLeft);
- jlabel2.add(btnRight);
- jlabel2.setPreferredSize(new Dimension(0, 35));
-
- add(jlabel, BorderLayout.CENTER);
- add(jlabel2, BorderLayout.PAGE_END);
}
private void btnRightActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRightActionPerformed
this.selected = true;
-// clear0();
if (connectedDialog != null) {
connectedDialog.hideDialog();
}
@@ -414,7 +281,6 @@ public class FeedbackPanel extends javax.swing.JPanel {
private void btnLeftActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLeftActionPerformed
this.selected = true;
-// clear0();
session.sendPlayerBoolean(gameId, true);
AudioManager.playButtonCancel();
}//GEN-LAST:event_btnLeftActionPerformed
@@ -423,6 +289,10 @@ public class FeedbackPanel extends javax.swing.JPanel {
session.sendPlayerString(gameId, "special");
}//GEN-LAST:event_btnSpecialActionPerformed
+ private void btnUndoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSpecialActionPerformed
+ session.undo(gameId);
+ }
+
public void setHelperPanel(HelperPanel helper) {
this.helper = helper;
}
@@ -443,9 +313,18 @@ public class FeedbackPanel extends javax.swing.JPanel {
}
}
+ public void allowUndo(int bookmark) {
+ this.helper.setUndoEnabled(true);
+ }
+
+ public void disableUndo() {
+ this.helper.setUndoEnabled(false);
+ }
+
private javax.swing.JButton btnLeft;
private javax.swing.JButton btnRight;
private javax.swing.JButton btnSpecial;
+ private javax.swing.JButton btnUndo;
private javax.swing.JScrollPane jScrollPane1;
//private javax.swing.JTextArea lblMessage;
private MageTextArea lblMessage;
diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java
index 09c32a6cbb..a8df0075e0 100644
--- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java
+++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java
@@ -490,6 +490,14 @@ public final class GamePanel extends javax.swing.JPanel {
} else {
CombatManager.getInstance().hideCombat(gameId);
}
+
+ System.out.println("Size: " + game.getStatesSavedSize());
+ if (game.getStatesSavedSize() > 0) {
+ feedbackPanel.allowUndo(game.getStatesSavedSize());
+ } else {
+ feedbackPanel.disableUndo();
+ }
+
this.revalidate();
this.repaint();
}
diff --git a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java
index 9ec04c0020..8aa258a234 100644
--- a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java
+++ b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java
@@ -29,10 +29,11 @@
package mage.client.game;
-import java.awt.*;
-import javax.swing.*;
import mage.client.components.MageTextArea;
+import javax.swing.*;
+import java.awt.*;
+
/**
* Panel with buttons that copy the state of feedback panel.
*
@@ -43,6 +44,7 @@ public class HelperPanel extends JPanel {
private javax.swing.JButton btnLeft;
private javax.swing.JButton btnRight;
private javax.swing.JButton btnSpecial;
+ private javax.swing.JButton btnUndo;
//private javax.swing.JButton btnEndTurn;
//private javax.swing.JButton btnStopTimer;
@@ -52,6 +54,7 @@ public class HelperPanel extends JPanel {
private javax.swing.JButton linkLeft;
private javax.swing.JButton linkRight;
private javax.swing.JButton linkSpecial;
+ private javax.swing.JButton linkUndo;
public HelperPanel() {
initComponents();
@@ -89,6 +92,9 @@ public class HelperPanel extends JPanel {
btnRight = new JButton("Cancel");
btnRight.setVisible(false);
container.add(btnRight);
+ btnUndo = new JButton("Undo");
+ btnUndo.setVisible(false);
+ container.add(btnUndo);
btnLeft.addActionListener(new java.awt.event.ActionListener() {
@Override
@@ -122,6 +128,15 @@ public class HelperPanel extends JPanel {
}}
}
});
+
+ btnUndo.addActionListener(new java.awt.event.ActionListener() {
+ @Override
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ if (linkUndo != null) {{
+ linkUndo.doClick();
+ }}
+ }
+ });
}
public void setState(String txtLeft, boolean leftVisible, String txtRight, boolean rightVisible) {
@@ -140,6 +155,10 @@ public class HelperPanel extends JPanel {
this.btnSpecial.setText(txtSpecial);
}
+ public void setUndoEnabled(boolean enabled) {
+ this.btnUndo.setVisible(enabled);
+ }
+
public void setRight(String txtRight, boolean rightVisible) {
this.btnRight.setVisible(rightVisible);
if (!txtRight.isEmpty()) {
@@ -147,10 +166,11 @@ public class HelperPanel extends JPanel {
}
}
- public void setLinks(JButton left, JButton right, JButton special) {
+ public void setLinks(JButton left, JButton right, JButton special, JButton undo) {
this.linkLeft = left;
this.linkRight = right;
this.linkSpecial = special;
+ this.linkUndo = undo;
}
public void setMessage(String message) {
diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/mage/interfaces/MageServer.java
index b9806744be..3944a38167 100644
--- a/Mage.Common/src/mage/interfaces/MageServer.java
+++ b/Mage.Common/src/mage/interfaces/MageServer.java
@@ -100,6 +100,7 @@ public interface MageServer {
void sendPlayerBoolean(UUID gameId, String sessionId, Boolean data) throws MageException;
void sendPlayerInteger(UUID gameId, String sessionId, Integer data) throws MageException;
void concedeGame(UUID gameId, String sessionId) throws MageException;
+ void undo(UUID gameId, String sessionId) throws MageException;
GameView getGameView(UUID gameId, String sessionId, UUID playerId) throws MageException;
//priority methods
diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java
index 11cfce49e1..1af8d1faf5 100644
--- a/Mage.Common/src/mage/remote/SessionImpl.java
+++ b/Mage.Common/src/mage/remote/SessionImpl.java
@@ -929,6 +929,21 @@ public class SessionImpl implements Session {
return false;
}
+ @Override
+ public boolean undo(UUID gameId) {
+ try {
+ if (isConnected()) {
+ server.undo(gameId, sessionId);
+ return true;
+ }
+ } catch (MageException ex) {
+ handleMageException(ex);
+ } catch (Throwable t) {
+ handleThrowable(t);
+ }
+ return false;
+ }
+
@Override
public boolean passPriorityUntilNextYourTurn(UUID gameId) {
try {
diff --git a/Mage.Common/src/mage/remote/interfaces/GamePlay.java b/Mage.Common/src/mage/remote/interfaces/GamePlay.java
index 0773c95283..3387d792e3 100644
--- a/Mage.Common/src/mage/remote/interfaces/GamePlay.java
+++ b/Mage.Common/src/mage/remote/interfaces/GamePlay.java
@@ -59,6 +59,8 @@ public interface GamePlay {
DraftPickView sendCardPick(UUID draftId, UUID cardId);
+ boolean undo(UUID gameId);
+
/*** Separate methods for priority handling ***/
/**
* magenoxx:
diff --git a/Mage.Common/src/mage/view/GameView.java b/Mage.Common/src/mage/view/GameView.java
index fb6438775e..a3b641dce8 100644
--- a/Mage.Common/src/mage/view/GameView.java
+++ b/Mage.Common/src/mage/view/GameView.java
@@ -74,10 +74,17 @@ public class GameView implements Serializable {
private String priorityPlayerName = "";
private int turn;
private boolean special = false;
+ private int statesSavedSize;
public GameView(GameState state, Game game) {
for (Player player: state.getPlayers().values()) {
players.add(new PlayerView(player, state, game));
+ if (player.getStoredBookmark() > 0) {
+ if (this.statesSavedSize > 0) {
+ throw new IllegalStateException("This shouldn't happen");
+ }
+ this.statesSavedSize = player.getStoredBookmark();
+ }
}
for (StackObject stackObject: state.getStack()) {
if (stackObject instanceof StackAbility) {
@@ -254,7 +261,7 @@ public class GameView implements Serializable {
return special;
}
- /*public List getStackOrder() {
- return stackOrder;
- }*/
+ public int getStatesSavedSize() {
+ return statesSavedSize;
+ }
}
diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java
index 5fb8c89a1d..25be5b66c1 100644
--- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java
+++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java
@@ -27,9 +27,6 @@
*/
package mage.player.ai;
-import java.io.File;
-import java.util.*;
-import java.util.concurrent.*;
import mage.Constants.Outcome;
import mage.Constants.PhaseStep;
import mage.Constants.RangeOfInfluence;
@@ -62,6 +59,10 @@ import mage.target.Target;
import mage.target.TargetCard;
import mage.target.Targets;
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.*;
+
/**
*
@@ -132,7 +133,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements
switch (game.getTurn().getStepType()) {
case UPKEEP:
case DRAW:
- pass();
+ pass(game);
return false;
case PRECOMBAT_MAIN:
case POSTCOMBAT_MAIN:
@@ -146,36 +147,36 @@ public class ComputerPlayer6 extends ComputerPlayer implements
act(game);
return true;
} else {
- pass();
+ pass(game);
}
return false;
case BEGIN_COMBAT:
case FIRST_COMBAT_DAMAGE:
case COMBAT_DAMAGE:
case END_COMBAT:
- pass();
+ pass(game);
return false;
case DECLARE_ATTACKERS:
if (game.getActivePlayerId().equals(playerId)) {
//declareAttackers(game, playerId);
- pass();
+ pass(game);
} else {
- pass();
+ pass(game);
}
return false;
case DECLARE_BLOCKERS:
if (!game.getActivePlayerId().equals(playerId)) {
declareBlockers(game, playerId);
- pass();
+ pass(game);
} else {
- pass();
+ pass(game);
}
return false;
case END_TURN:
- pass();
+ pass(game);
return false;
case CLEANUP:
- pass();
+ pass(game);
return false;
}
return false;
@@ -222,7 +223,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements
protected void act(Game game) {
if (actions == null || actions.size() == 0) {
- pass();
+ pass(game);
} else {
boolean usedStack = false;
while (actions.peek() != null) {
@@ -257,7 +258,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements
}
}
if (usedStack) {
- pass();
+ pass(game);
}
}
}
@@ -536,7 +537,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements
}
if (!sim.isGameOver() && action.isUsesStack()) {
// only pass if the last action uses the stack
- sim.getPlayer(currentPlayer.getId()).pass();
+ sim.getPlayer(currentPlayer.getId()).pass(game);
sim.getPlayerList().getNext();
}
SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId());
diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java
index 7b4c4eb8ac..aaf726cdc0 100644
--- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java
+++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java
@@ -28,7 +28,6 @@
package mage.player.ai;
-import java.util.*;
import mage.Constants;
import mage.Constants.RangeOfInfluence;
import mage.abilities.Ability;
@@ -40,6 +39,10 @@ import mage.game.turn.*;
import mage.players.Player;
import org.apache.log4j.Logger;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
/**
*
@@ -77,7 +80,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
switch (game.getTurn().getStepType()) {
case UPKEEP:
case DRAW:
- pass();
+ pass(game);
return false;
case PRECOMBAT_MAIN:
if (game.getActivePlayerId().equals(playerId)) {
@@ -89,11 +92,11 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
return true;
}
else {
- pass();
+ pass(game);
}
return false;
case BEGIN_COMBAT:
- pass();
+ pass(game);
return false;
case DECLARE_ATTACKERS:
if (!game.getActivePlayerId().equals(playerId)) {
@@ -105,14 +108,14 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
return true;
}
else {
- pass();
+ pass(game);
}
return false;
case DECLARE_BLOCKERS:
case FIRST_COMBAT_DAMAGE:
case COMBAT_DAMAGE:
case END_COMBAT:
- pass();
+ pass(game);
return false;
case POSTCOMBAT_MAIN:
// if (game.getActivePlayerId().equals(playerId)) {
@@ -124,13 +127,13 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
return true;
// }
// else {
-// pass();
+// pass(game);
// }
// return false;
case END_TURN:
case CLEANUP:
actionCache.clear();
- pass();
+ pass(game);
return false;
}
return false;
diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java
index bae61e1c33..59754c112b 100644
--- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java
+++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java
@@ -721,7 +721,7 @@ public class ComputerPlayer> extends PlayerImpl i
break;
}
}
- pass();
+ pass(game);
return true;
}
diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java
index c9bbf7aa25..e79cae270e 100644
--- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java
+++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java
@@ -106,7 +106,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements
switch (game.getTurn().getStepType()) {
case UPKEEP:
case DRAW:
- pass();
+ pass(game);
return false;
case PRECOMBAT_MAIN:
case BEGIN_COMBAT:
@@ -123,7 +123,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements
return true;
case END_TURN:
case CLEANUP:
- pass();
+ pass(game);
return false;
}
return false;
@@ -131,7 +131,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements
protected void act(Game game) {
if (actions == null || actions.size() == 0)
- pass();
+ pass(game);
else {
boolean usedStack = false;
while (actions.peek() != null) {
@@ -143,7 +143,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements
usedStack = true;
}
if (usedStack)
- pass();
+ pass(game);
}
logger.info("Turn " + game.getTurnNum() + " Step " + game.getStep().toString() + " Player " + name + " Life " + life);
}
@@ -405,7 +405,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements
}
if (!sim.isGameOver() && action.isUsesStack()) {
// only pass if the last action uses the stack
- sim.getPlayer(currentPlayer.getId()).pass();
+ sim.getPlayer(currentPlayer.getId()).pass(game);
sim.getPlayerList().getNext();
}
SimulationNode newNode = new SimulationNode(node, sim, action, currentPlayer.getId());
diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java
index c151a8d4f9..1aa4d27b6f 100644
--- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java
+++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java
@@ -74,7 +74,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
switch (game.getTurn().getStepType()) {
case UPKEEP:
case DRAW:
- pass();
+ pass(game);
return false;
case PRECOMBAT_MAIN:
if (game.getActivePlayerId().equals(playerId)) {
@@ -85,10 +85,10 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
return true;
}
else
- pass();
+ pass(game);
return false;
case BEGIN_COMBAT:
- pass();
+ pass(game);
return false;
case DECLARE_ATTACKERS:
if (!game.getActivePlayerId().equals(playerId)) {
@@ -99,13 +99,13 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
return true;
}
else
- pass();
+ pass(game);
return false;
case DECLARE_BLOCKERS:
case FIRST_COMBAT_DAMAGE:
case COMBAT_DAMAGE:
case END_COMBAT:
- pass();
+ pass(game);
return false;
case POSTCOMBAT_MAIN:
if (game.getActivePlayerId().equals(playerId)) {
@@ -116,11 +116,11 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
return true;
}
else
- pass();
+ pass(game);
return false;
case END_TURN:
case CLEANUP:
- pass();
+ pass(game);
return false;
}
return false;
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 d968ec52ad..785efbe361 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
@@ -391,24 +391,24 @@ public class HumanPlayer extends PlayerImpl {
passed = false;
if (!abort) {
if (passedAllTurns) {
- pass();
+ pass(game);
return false;
}
if (passedTurn && game.getStack().isEmpty()) {
- pass();
+ pass(game);
return false;
}
updateGameStatePriority("priority", game);
game.firePriorityEvent(playerId);
waitForResponse();
if (response.getBoolean() != null) {
- pass();
+ pass(game);
return false;
} else if (response.getInteger() != null) {
/*if (response.getInteger() == -9999) {
passedAllTurns = true;
}*/
- pass();
+ pass(game);
//passedTurn = true;
return false;
} else if (response.getString() != null && response.getString().equals("special")) {
diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java
index 039984c00b..2b28dc211f 100644
--- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java
+++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java
@@ -570,6 +570,17 @@ public class MageServerImpl implements MageServer {
});
}
+ @Override
+ public void undo(final UUID gameId, final String sessionId) throws MageException {
+ execute("undo", sessionId, new Action() {
+ @Override
+ public void execute() {
+ UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId();
+ GameManager.getInstance().undo(gameId, userId);
+ }
+ });
+ }
+
@Override
public void passPriorityUntilNextYourTurn(final UUID gameId, final String sessionId) throws MageException {
execute("passPriorityUntilNextYourTurn", sessionId, new Action() {
diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java
index bd15915f65..9304e8ab02 100644
--- a/Mage.Server/src/main/java/mage/server/game/GameController.java
+++ b/Mage.Server/src/main/java/mage/server/game/GameController.java
@@ -255,6 +255,10 @@ public class GameController implements GameCallback {
game.concede(getPlayerId(userId));
}
+ public void undo(UUID userId) {
+ game.undo(getPlayerId(userId));
+ }
+
public void passPriorityUntilNextYourTurn(UUID userId) {
game.passPriorityUntilNextYourTurn(getPlayerId(userId));
}
diff --git a/Mage.Server/src/main/java/mage/server/game/GameManager.java b/Mage.Server/src/main/java/mage/server/game/GameManager.java
index 69e208ce0d..8389a73508 100644
--- a/Mage.Server/src/main/java/mage/server/game/GameManager.java
+++ b/Mage.Server/src/main/java/mage/server/game/GameManager.java
@@ -96,6 +96,11 @@ public class GameManager {
gameControllers.get(gameId).concede(userId);
}
+ public void undo(UUID gameId, UUID userId) {
+ if (gameControllers.containsKey(gameId))
+ gameControllers.get(gameId).undo(userId);
+ }
+
public void passPriorityUntilNextYourTurn(UUID gameId, UUID userId) {
if (gameControllers.containsKey(gameId))
gameControllers.get(gameId).passPriorityUntilNextYourTurn(userId);
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 0f8b6315d7..b10c8d683b 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
@@ -45,6 +45,7 @@ import mage.player.ai.ComputerPlayer;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
+import mage.target.common.TargetCreaturePermanentAmount;
import org.junit.Ignore;
import java.io.Serializable;
@@ -52,7 +53,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import mage.target.common.TargetCreaturePermanentAmount;
/**
*
@@ -124,7 +124,7 @@ public class TestPlayer extends ComputerPlayer {
}
}
}
- pass();
+ pass(game);
return false;
}
diff --git a/Mage/src/mage/abilities/effects/common/PassEffect.java b/Mage/src/mage/abilities/effects/common/PassEffect.java
index 4b4b671d91..54fad6a24f 100644
--- a/Mage/src/mage/abilities/effects/common/PassEffect.java
+++ b/Mage/src/mage/abilities/effects/common/PassEffect.java
@@ -51,7 +51,7 @@ public class PassEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
- player.pass();
+ player.pass(game);
return true;
}
diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java
index 917267ef75..1b711253db 100644
--- a/Mage/src/mage/game/Game.java
+++ b/Mage/src/mage/game/Game.java
@@ -164,6 +164,7 @@ public interface Game extends MageItem, Serializable {
void mulligan(UUID playerId);
void quit(UUID playerId);
void concede(UUID playerId);
+ void undo(UUID playerId);
void emptyManaPools();
void addEffect(ContinuousEffect continuousEffect, Ability source);
void addEmblem(Emblem emblem, Ability source);
@@ -200,6 +201,7 @@ public interface Game extends MageItem, Serializable {
int bookmarkState();
void restoreState(int bookmark);
void removeBookmark(int bookmark);
+ int getSavedStateSize();
// game options
void setGameOptions(GameOptions options);
diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java
index cdd829ba25..75c220052a 100644
--- a/Mage/src/mage/game/GameImpl.java
+++ b/Mage/src/mage/game/GameImpl.java
@@ -420,7 +420,7 @@ public abstract class GameImpl> implements Game, Serializa
savedStates.push(gameStates.getSize() - 1);
return savedStates.size();
}
- return 0;
+ return savedStates.size();
}
@Override
@@ -444,10 +444,31 @@ public abstract class GameImpl> implements Game, Serializa
while (savedStates.size() > bookmark) {
savedStates.pop();
}
+ gameStates.remove(bookmark);
}
}
}
+ private void clearAllBookmarks() {
+ if (!simulation) {
+ while (!savedStates.isEmpty()) {
+ savedStates.pop();
+ }
+ gameStates.remove(0);
+ for (Player player : getPlayers().values()) {
+ player.setStoredBookmark(-1);
+ }
+ }
+ }
+
+ @Override
+ public int getSavedStateSize() {
+ if (!simulation) {
+ return savedStates.size();
+ }
+ return 0;
+ }
+
@Override
public void start(UUID choosingPlayerId) {
start(choosingPlayerId, this.gameOptions != null ? gameOptions : GameOptions.getDefault());
@@ -721,6 +742,19 @@ public abstract class GameImpl> implements Game, Serializa
}
}
+ @Override
+ public synchronized void undo(UUID playerId) {
+ Player player = state.getPlayer(playerId);
+ if (player != null) {
+ int bookmark = player.getStoredBookmark();
+ if (bookmark != -1) {
+ restoreState(bookmark);
+ player.setStoredBookmark(-1);
+ fireUpdatePlayersEvent();
+ }
+ }
+ }
+
@Override
public synchronized void passPriorityUntilNextYourTurn(UUID playerId) {
Player player = state.getPlayer(playerId);
@@ -748,6 +782,7 @@ public abstract class GameImpl> implements Game, Serializa
@Override
public void playPriority(UUID activePlayerId, boolean resuming) {
int bookmark = 0;
+ clearAllBookmarks();
try {
while (!isPaused() && !isGameOver()) {
if (!resuming) {
diff --git a/Mage/src/mage/game/GameStates.java b/Mage/src/mage/game/GameStates.java
index 0fda26e4fc..8c6e8bd049 100644
--- a/Mage/src/mage/game/GameStates.java
+++ b/Mage/src/mage/game/GameStates.java
@@ -28,10 +28,11 @@
package mage.game;
+import org.apache.log4j.Logger;
+
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
-import org.apache.log4j.Logger;
/**
*
@@ -66,6 +67,15 @@ public class GameStates implements Serializable {
return null;
}
+ public int remove(int index) {
+ if (states.size() > 0 && index < states.size()) {
+ while (states.size() > index && states.size() > 0) {
+ states.remove(states.size() - 1);
+ }
+ }
+ return states.size();
+ }
+
public GameState get(int index) {
if (index < states.size())
// return new Copier().uncompressCopy(states.get(index));
diff --git a/Mage/src/mage/game/turn/Turn.java b/Mage/src/mage/game/turn/Turn.java
index 67c498d883..55d39d083a 100644
--- a/Mage/src/mage/game/turn/Turn.java
+++ b/Mage/src/mage/game/turn/Turn.java
@@ -28,17 +28,18 @@
package mage.game.turn;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.UUID;
import mage.Constants.PhaseStep;
import mage.Constants.TurnPhase;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
+
/**
*
@@ -161,7 +162,7 @@ public class Turn implements Serializable {
if (phase.resumePlay(game, stepType, wasPaused)) {
//20091005 - 500.4/703.4n
game.emptyManaPools();
- game.saveState();
+ //game.saveState();
//20091005 - 500.8
playExtraPhases(game, phase.getType());
}
@@ -175,7 +176,7 @@ public class Turn implements Serializable {
if (phase.play(game, activePlayerId)) {
//20091005 - 500.4/703.4n
game.emptyManaPools();
- game.saveState();
+ //game.saveState();
//20091005 - 500.8
playExtraPhases(game, phase.getType());
}
diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java
index 5081dd723f..4a05188217 100644
--- a/Mage/src/mage/players/Player.java
+++ b/Mage/src/mage/players/Player.java
@@ -94,7 +94,7 @@ public interface Player extends MageItem, Copyable {
void setMaxHandSize(int maxHandSize);
boolean isPassed();
boolean isEmptyDraw();
- void pass();
+ void pass(Game game);
void resetPassed();
boolean hasLost();
boolean hasWon();
@@ -202,6 +202,10 @@ public interface Player extends MageItem, Copyable {
void passPriorityUntilNextYourTurn(Game game);
void passTurnPriority(Game game);
void restorePriority(Game game);
+
+ int getStoredBookmark();
+ void setStoredBookmark(int bookmark);
+ void resetStoredBookmark(Game game);
void revealCards(String name, Cards cards, Game game);
void lookAtCards(String name, Cards cards, Game game);
diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java
index 8c50b99be5..fe4df43a02 100644
--- a/Mage/src/mage/players/PlayerImpl.java
+++ b/Mage/src/mage/players/PlayerImpl.java
@@ -101,6 +101,7 @@ public abstract class PlayerImpl> implements Player, Ser
protected boolean passed;
protected boolean passedTurn;
protected int turns;
+ protected int storedBookmark = -1;
/**
* This indicates that player passed all turns until his own turn starts.
@@ -175,6 +176,7 @@ public abstract class PlayerImpl> implements Player, Ser
this.userData = player.userData;
this.canPayLifeCost = player.canPayLifeCost;
this.canPaySacrificeCost = player.canPaySacrificeCost;
+ this.storedBookmark = player.storedBookmark;
}
@Override
@@ -537,6 +539,7 @@ public abstract class PlayerImpl> implements Player, Ser
game.fireEvent(event);
game.fireInformEvent(name + spellAbility.getActivatedMessage(game));
game.removeBookmark(bookmark);
+ resetStoredBookmark(game);
return true;
}
game.restoreState(bookmark);
@@ -556,6 +559,7 @@ public abstract class PlayerImpl> implements Player, Ser
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), playerId));
game.fireInformEvent(name + " plays " + card.getName());
game.removeBookmark(bookmark);
+ resetStoredBookmark(game);
return true;
}
game.restoreState(bookmark);
@@ -568,7 +572,11 @@ public abstract class PlayerImpl> implements Player, Ser
int bookmark = game.bookmarkState();
if (ability.activate(game, false)) {
ability.resolve(game);
- game.removeBookmark(bookmark);
+ // #169
+ if (storedBookmark == -1) {
+ setStoredBookmark(bookmark);
+ }
+ //game.removeBookmark(bookmark);
return true;
}
game.restoreState(bookmark);
@@ -587,6 +595,7 @@ public abstract class PlayerImpl> implements Player, Ser
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, ability.getId(), ability.getSourceId(), playerId));
game.fireInformEvent(name + ability.getActivatedMessage(game));
game.removeBookmark(bookmark);
+ resetStoredBookmark(game);
return true;
}
game.restoreState(bookmark);
@@ -596,6 +605,7 @@ public abstract class PlayerImpl> implements Player, Ser
if (ability.activate(game, false)) {
ability.resolve(game);
game.removeBookmark(bookmark);
+ resetStoredBookmark(game);
return true;
}
game.restoreState(bookmark);
@@ -612,6 +622,7 @@ public abstract class PlayerImpl> implements Player, Ser
game.fireInformEvent(name + action.getActivatedMessage(game));
if (action.resolve(game)) {
game.removeBookmark(bookmark);
+ resetStoredBookmark(game);
return true;
}
}
@@ -628,7 +639,7 @@ public abstract class PlayerImpl> implements Player, Ser
}
if (ability instanceof PassAbility) {
- pass();
+ pass(game);
return true;
}
else if (ability instanceof PlayLandAbility) {
@@ -1055,8 +1066,9 @@ public abstract class PlayerImpl> implements Player, Ser
}
@Override
- public void pass() {
+ public void pass(Game game) {
this.passed = true;
+ resetStoredBookmark(game);
}
@Override
@@ -1598,4 +1610,21 @@ public abstract class PlayerImpl> implements Player, Ser
return turns;
}
+ @Override
+ public int getStoredBookmark() {
+ return storedBookmark;
+ }
+
+ @Override
+ public void setStoredBookmark(int storedBookmark) {
+ this.storedBookmark = storedBookmark;
+ }
+
+ @Override
+ public synchronized void resetStoredBookmark(Game game) {
+ if (this.storedBookmark != -1) {
+ game.removeBookmark(this.storedBookmark);
+ }
+ setStoredBookmark(-1);
+ }
}