Closed #169: Make it possible to untap lands

This commit is contained in:
magenoxx 2013-03-29 20:35:16 +04:00
parent dd9aec6a49
commit 29b84e0d92
24 changed files with 244 additions and 207 deletions

View file

@ -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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//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)))
);
}// </editor-fold>//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;

View file

@ -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();
}

View file

@ -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) {

View file

@ -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

View file

@ -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 {

View file

@ -59,6 +59,8 @@ public interface GamePlay {
DraftPickView sendCardPick(UUID draftId, UUID cardId);
boolean undo(UUID gameId);
/*** Separate methods for priority handling ***/
/**
* magenoxx:

View file

@ -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<UUID> getStackOrder() {
return stackOrder;
}*/
public int getStatesSavedSize() {
return statesSavedSize;
}
}

View file

@ -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<ComputerPlayer6> 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<ComputerPlayer6> 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<ComputerPlayer6> 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<ComputerPlayer6> implements
}
}
if (usedStack) {
pass();
pass(game);
}
}
}
@ -536,7 +537,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> 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());

View file

@ -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;

View file

@ -721,7 +721,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
break;
}
}
pass();
pass(game);
return true;
}

View file

@ -106,7 +106,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> 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<ComputerPlayer2> implements
return true;
case END_TURN:
case CLEANUP:
pass();
pass(game);
return false;
}
return false;
@ -131,7 +131,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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());

View file

@ -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;

View file

@ -391,24 +391,24 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> {
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")) {

View file

@ -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() {

View file

@ -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));
}

View file

@ -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);

View file

@ -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<TestPlayer> {
}
}
}
pass();
pass(game);
return false;
}

View file

@ -51,7 +51,7 @@ public class PassEffect extends OneShotEffect<PassEffect> {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
player.pass();
player.pass(game);
return true;
}

View file

@ -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);

View file

@ -420,7 +420,7 @@ public abstract class GameImpl<T extends GameImpl<T>> 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<T extends GameImpl<T>> 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<T extends GameImpl<T>> 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<T extends GameImpl<T>> implements Game, Serializa
@Override
public void playPriority(UUID activePlayerId, boolean resuming) {
int bookmark = 0;
clearAllBookmarks();
try {
while (!isPaused() && !isGameOver()) {
if (!resuming) {

View file

@ -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<GameState>().uncompressCopy(states.get(index));

View file

@ -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());
}

View file

@ -94,7 +94,7 @@ public interface Player extends MageItem, Copyable<Player> {
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<Player> {
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);

View file

@ -101,6 +101,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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<T extends PlayerImpl<T>> 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);
}
}