mirror of
https://github.com/magefree/mage.git
synced 2025-12-29 23:12:10 -08:00
* Added optional rollback current turn and up to 3 previous turns to the battlefield menu. All other players have to agree to the rollback to let it happen.
This commit is contained in:
parent
5736efa103
commit
8acf28eed1
38 changed files with 661 additions and 252 deletions
|
|
@ -39,6 +39,7 @@ public enum PlayerAction {
|
|||
PASS_PRIORITY_UNTIL_NEXT_TURN,
|
||||
PASS_PRIORITY_UNTIL_STACK_RESOLVED,
|
||||
PASS_PRIORITY_CANCEL_ALL_ACTIONS,
|
||||
ROLLBACK_TURNS,
|
||||
UNDO,
|
||||
CONCEDE,
|
||||
MANA_AUTO_PAYMENT_ON,
|
||||
|
|
@ -46,7 +47,10 @@ public enum PlayerAction {
|
|||
RESET_AUTO_SELECT_REPLACEMENT_EFFECTS,
|
||||
REVOKE_PERMISSIONS_TO_SEE_HAND_CARDS,
|
||||
REQUEST_PERMISSION_TO_SEE_HAND_CARDS,
|
||||
REQUEST_PERMISSION_TO_ROLLBACK_TURN,
|
||||
ADD_PERMISSION_TO_SEE_HAND_CARDS,
|
||||
ADD_PERMISSION_TO_ROLLBACK_TURN,
|
||||
DENY_PERMISSON_TO_ROLLBACK_TURN,
|
||||
PERMISSION_REQUESTS_ALLOWED_ON,
|
||||
PERMISSION_REQUESTS_ALLOWED_OFF
|
||||
}
|
||||
|
|
@ -208,9 +208,7 @@ public interface Game extends MageItem, Serializable {
|
|||
*/
|
||||
PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage);
|
||||
|
||||
//game play methods
|
||||
void start(UUID choosingPlayerId);
|
||||
void start(UUID choosingPlayerId, GameOptions options);
|
||||
void resume();
|
||||
void pause();
|
||||
boolean isPaused();
|
||||
|
|
@ -293,5 +291,10 @@ public interface Game extends MageItem, Serializable {
|
|||
int getPriorityTime();
|
||||
void setPriorityTime(int priorityTime);
|
||||
UUID getStartingPlayerId();
|
||||
|
||||
void saveRollBackGameState();
|
||||
boolean canRollbackTurns(int turnsToRollback);
|
||||
void rollbackTurns(int turnsToRollback);
|
||||
boolean executingRollback();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init(UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
//Move commander to command zone
|
||||
for (UUID playerId: state.getPlayerList(startingPlayerId)) {
|
||||
|
|
@ -101,7 +101,7 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
|
||||
}
|
||||
this.getState().addAbility(ability, null);
|
||||
super.init(choosingPlayerId, gameOptions);
|
||||
super.init(choosingPlayerId);
|
||||
if (startingPlayerSkipsDraw) {
|
||||
state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ import mage.players.Players;
|
|||
import mage.target.Target;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.functions.ApplyToPermanent;
|
||||
import mage.watchers.Watchers;
|
||||
import mage.watchers.common.BlockedAttackerWatcher;
|
||||
|
|
@ -129,6 +130,8 @@ import org.apache.log4j.Logger;
|
|||
|
||||
public abstract class GameImpl implements Game, Serializable {
|
||||
|
||||
private static final int ROLLBACK_TURNS_MAX = 4;
|
||||
|
||||
private static final transient Logger logger = Logger.getLogger(GameImpl.class);
|
||||
|
||||
private static final FilterPermanent filterAura = new FilterPermanent();
|
||||
|
|
@ -155,7 +158,8 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
private transient Object customData;
|
||||
protected boolean simulation = false;
|
||||
|
||||
protected final UUID id;
|
||||
protected final UUID id;
|
||||
|
||||
protected boolean ready;
|
||||
protected transient TableEventSource tableEventSource = new TableEventSource();
|
||||
protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource();
|
||||
|
|
@ -170,6 +174,9 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
protected GameState state;
|
||||
private transient Stack<Integer> savedStates = new Stack<>();
|
||||
protected transient GameStates gameStates = new GameStates();
|
||||
// game states to allow player roll back
|
||||
protected transient Map<Integer, GameState> gameStatesRollBack = new HashMap<>();
|
||||
protected boolean executingRollback;
|
||||
|
||||
protected Date startTime;
|
||||
protected Date endTime;
|
||||
|
|
@ -206,7 +213,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
this.attackOption = attackOption;
|
||||
this.state = new GameState();
|
||||
this.startLife = startLife;
|
||||
// this.actions = new LinkedList<MageAction>();
|
||||
this.executingRollback = false;
|
||||
}
|
||||
|
||||
public GameImpl(final GameImpl game) {
|
||||
|
|
@ -232,7 +239,6 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
copyCount++;
|
||||
copyTime += (System.currentTimeMillis() - t1);
|
||||
}
|
||||
// this.actions = new LinkedList<MageAction>();
|
||||
this.stateCheckRequired = game.stateCheckRequired;
|
||||
this.scorePlayer = game.scorePlayer;
|
||||
this.scopeRelevant = game.scopeRelevant;
|
||||
|
|
@ -268,7 +274,10 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
|
||||
@Override
|
||||
public GameOptions getOptions() {
|
||||
return gameOptions;
|
||||
if (gameOptions != null) {
|
||||
return gameOptions;
|
||||
}
|
||||
return new GameOptions(); // happens during the first game updates
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -610,23 +619,17 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(UUID choosingPlayerId) {
|
||||
start(choosingPlayerId, this.gameOptions != null ? gameOptions : GameOptions.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
gameCards.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(UUID choosingPlayerId, GameOptions options) {
|
||||
public void start(UUID choosingPlayerId) {
|
||||
startTime = new Date();
|
||||
this.gameOptions = options;
|
||||
if (state.getPlayers().values().iterator().hasNext()) {
|
||||
scorePlayer = state.getPlayers().values().iterator().next();
|
||||
init(choosingPlayerId, options);
|
||||
init(choosingPlayerId);
|
||||
play(startingPlayerId);
|
||||
}
|
||||
}
|
||||
|
|
@ -731,13 +734,26 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
|
||||
private boolean playTurn(Player player) {
|
||||
this.logStartOfTurn(player);
|
||||
if (checkStopOnTurnOption()) {
|
||||
return false;
|
||||
}
|
||||
state.setActivePlayerId(player.getId());
|
||||
player.becomesActivePlayer();
|
||||
state.getTurn().play(this, player.getId());
|
||||
do {
|
||||
if (executingRollback) {
|
||||
executingRollback = false;
|
||||
player = getPlayer(state.getActivePlayerId());
|
||||
for (Player playerObject: getPlayers().values()) {
|
||||
if (playerObject.isInGame()) {
|
||||
playerObject.abortReset();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state.setActivePlayerId(player.getId());
|
||||
saveRollBackGameState();
|
||||
}
|
||||
this.logStartOfTurn(player);
|
||||
if (checkStopOnTurnOption()) {
|
||||
return false;
|
||||
}
|
||||
state.getTurn().play(this, player);
|
||||
} while (executingRollback);
|
||||
|
||||
if (isPaused() || gameOver(null)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -778,7 +794,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void init(UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
for (Player player: state.getPlayers().values()) {
|
||||
player.beginTurn(this);
|
||||
// init only if match is with timer (>0) and time left was not set yet (== MAX_VALUE).
|
||||
|
|
@ -1151,6 +1167,9 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
// resetPassed should be called if player performs any action
|
||||
if (player.priority(this)) {
|
||||
if(executingRollback()) {
|
||||
return;
|
||||
}
|
||||
applyEffects();
|
||||
}
|
||||
if (isPaused()) {
|
||||
|
|
@ -2566,6 +2585,51 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRollBackGameState() {
|
||||
if (gameOptions.rollbackTurnsAllowed) {
|
||||
int toDelete = getTurnNum()- ROLLBACK_TURNS_MAX;
|
||||
if (toDelete > 0 && gameStatesRollBack.containsKey(toDelete)) {
|
||||
gameStatesRollBack.remove(toDelete);
|
||||
}
|
||||
gameStatesRollBack.put(getTurnNum(), state.copy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRollbackTurns(int turnsToRollback) {
|
||||
int turnToGoTo = getTurnNum() - turnsToRollback;
|
||||
return turnToGoTo > 0 && gameStatesRollBack.containsKey(turnToGoTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void rollbackTurns(int turnsToRollback) {
|
||||
if (gameOptions.rollbackTurnsAllowed) {
|
||||
int turnToGoTo = getTurnNum() - turnsToRollback;
|
||||
if (turnToGoTo < 1 || !gameStatesRollBack.containsKey(turnToGoTo)) {
|
||||
informPlayers(GameLog.getPlayerRequestColoredText("Player request: It's not possible to rollback " + turnsToRollback +" turn(s)"));
|
||||
} else {
|
||||
GameState restore = gameStatesRollBack.get(turnToGoTo);
|
||||
if (restore != null) {
|
||||
informPlayers(GameLog.getPlayerRequestColoredText("Player request: Rolling back to start of turn " + restore.getTurnNum()));
|
||||
for (Player playerObject: getPlayers().values()) {
|
||||
if (playerObject.isHuman() && playerObject.isInGame()) {
|
||||
playerObject.abort();
|
||||
}
|
||||
}
|
||||
state.restore(restore);
|
||||
// because restore uses the objects without copy each copy the state again
|
||||
gameStatesRollBack.put(getTurnNum(), state.copy());
|
||||
executingRollback = true;
|
||||
fireUpdatePlayersEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executingRollback() {
|
||||
return executingRollback;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,4 +37,9 @@ public class GameOptions implements Serializable {
|
|||
* If true, library won't be shuffled at the beginning of the game
|
||||
*/
|
||||
public boolean skipInitShuffling = false;
|
||||
|
||||
/**
|
||||
* If true, players can roll back turn if all players agree
|
||||
*/
|
||||
public boolean rollbackTurnsAllowed = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,19 +77,19 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
|
||||
private final Players players;
|
||||
private final PlayerList playerList;
|
||||
private final Turn turn;
|
||||
private UUID choosingPlayerId; // player that makes a choice at game start
|
||||
|
||||
// revealed cards <Name, <Cards>>, will be reset if all players pass priority
|
||||
private final Revealed revealed;
|
||||
private final Map<UUID, LookedAt> lookedAt = new HashMap<>();
|
||||
private final DelayedTriggeredAbilities delayed;
|
||||
private final SpecialActions specialActions;
|
||||
private final TurnMods turnMods;
|
||||
private final Watchers watchers;
|
||||
|
||||
|
||||
private DelayedTriggeredAbilities delayed;
|
||||
private SpecialActions specialActions;
|
||||
private Watchers watchers;
|
||||
private Turn turn;
|
||||
private TurnMods turnMods;
|
||||
private UUID activePlayerId; // playerId which turn it is
|
||||
private UUID priorityPlayerId; // player that has currently priority
|
||||
private UUID choosingPlayerId; // player that makes a choice at game start
|
||||
private SpellStack stack;
|
||||
private Command command;
|
||||
private Exile exile;
|
||||
|
|
@ -134,21 +134,24 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
public GameState(final GameState state) {
|
||||
this.players = state.players.copy();
|
||||
this.playerList = state.playerList.copy();
|
||||
this.choosingPlayerId = state.choosingPlayerId;
|
||||
this.revealed = state.revealed.copy();
|
||||
this.lookedAt.putAll(state.lookedAt);
|
||||
this.gameOver = state.gameOver;
|
||||
this.paused = state.paused;
|
||||
|
||||
this.activePlayerId = state.activePlayerId;
|
||||
this.priorityPlayerId = state.priorityPlayerId;
|
||||
this.choosingPlayerId = state.choosingPlayerId;
|
||||
this.turn = state.turn.copy();
|
||||
|
||||
this.stack = state.stack.copy();
|
||||
this.command = state.command.copy();
|
||||
this.exile = state.exile.copy();
|
||||
this.revealed = state.revealed.copy();
|
||||
this.lookedAt.putAll(state.lookedAt);
|
||||
this.battlefield = state.battlefield.copy();
|
||||
this.turnNum = state.turnNum;
|
||||
this.stepNum = state.stepNum;
|
||||
this.extraTurn = state.extraTurn;
|
||||
this.legendaryRuleActive = state.legendaryRuleActive;
|
||||
this.gameOver = state.gameOver;
|
||||
this.effects = state.effects.copy();
|
||||
for (TriggeredAbility trigger: state.triggered) {
|
||||
this.triggered.add(trigger.copy());
|
||||
|
|
@ -163,7 +166,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
this.zones.putAll(state.zones);
|
||||
this.paused = state.paused;
|
||||
this.simultaneousEvents.addAll(state.simultaneousEvents);
|
||||
for (Map.Entry<UUID, CardState> entry: state.cardState.entrySet()) {
|
||||
cardState.put(entry.getKey(), entry.getValue().copy());
|
||||
|
|
@ -172,6 +174,40 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.copiedCards.putAll(state.copiedCards);
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
}
|
||||
|
||||
public void restore(GameState state) {
|
||||
this.activePlayerId = state.activePlayerId;
|
||||
this.priorityPlayerId = state.priorityPlayerId;
|
||||
this.turn = state.turn;
|
||||
|
||||
this.stack = state.stack;
|
||||
this.command = state.command;
|
||||
this.exile = state.exile;
|
||||
this.battlefield = state.battlefield;
|
||||
this.turnNum = state.turnNum;
|
||||
this.stepNum = state.stepNum;
|
||||
this.extraTurn = state.extraTurn;
|
||||
this.legendaryRuleActive = state.legendaryRuleActive;
|
||||
this.effects = state.effects;
|
||||
this.triggered = state.triggered;
|
||||
this.triggers = state.triggers;
|
||||
this.delayed = state.delayed;
|
||||
this.specialActions = state.specialActions;
|
||||
this.combat = state.combat;
|
||||
this.turnMods = state.turnMods;
|
||||
this.watchers = state.watchers;
|
||||
this.values = state.values;
|
||||
for (Player copyPlayer: state.players.values()) {
|
||||
Player origPlayer = players.get(copyPlayer.getId());
|
||||
origPlayer.restore(copyPlayer);
|
||||
}
|
||||
this.zones = state.zones;
|
||||
this.simultaneousEvents = state.simultaneousEvents;
|
||||
this.cardState = state.cardState;
|
||||
this.zoneChangeCounter = state.zoneChangeCounter;
|
||||
this.copiedCards = state.copiedCards;
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameState copy() {
|
||||
|
|
@ -558,28 +594,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
zones.put(id, zone);
|
||||
}
|
||||
|
||||
public void restore(GameState state) {
|
||||
this.stack = state.stack;
|
||||
this.command = state.command;
|
||||
this.effects = state.effects;
|
||||
this.triggers = state.triggers;
|
||||
this.triggered = state.triggered;
|
||||
this.combat = state.combat;
|
||||
this.exile = state.exile;
|
||||
this.battlefield = state.battlefield;
|
||||
this.zones = state.zones;
|
||||
this.values = state.values;
|
||||
for (Player copyPlayer: state.players.values()) {
|
||||
Player origPlayer = players.get(copyPlayer.getId());
|
||||
origPlayer.restore(copyPlayer);
|
||||
}
|
||||
this.simultaneousEvents = state.simultaneousEvents;
|
||||
this.cardState = state.cardState;
|
||||
this.zoneChangeCounter = state.zoneChangeCounter;
|
||||
this.copiedCards = state.copiedCards;
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
}
|
||||
|
||||
public void addSimultaneousEvent(GameEvent event, Game game) {
|
||||
simultaneousEvents.add(event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,12 @@ public class GameStates implements Serializable {
|
|||
|
||||
private static final transient Logger logger = Logger.getLogger(GameStates.class);
|
||||
|
||||
// private List<byte[]> states = new LinkedList<byte[]>();
|
||||
private final List<GameState> states = new LinkedList<>();
|
||||
// private final List<byte[]> states;
|
||||
private final List<GameState> states;
|
||||
|
||||
public GameStates() {
|
||||
this.states = new LinkedList<>();
|
||||
}
|
||||
|
||||
public void save(GameState gameState) {
|
||||
// states.add(new Copier<GameState>().copyCompressed(gameState));
|
||||
|
|
@ -60,8 +64,8 @@ public class GameStates implements Serializable {
|
|||
while (states.size() > index + 1) {
|
||||
states.remove(states.size() - 1);
|
||||
}
|
||||
// return new Copier<GameState>().uncompressCopy(states.get(index));
|
||||
logger.trace("Rolling back state: " + index);
|
||||
// return new Copier<GameState>().uncompressCopy(states.get(index));
|
||||
return states.get(index);
|
||||
}
|
||||
return null;
|
||||
|
|
@ -78,7 +82,7 @@ public class GameStates implements Serializable {
|
|||
|
||||
public GameState get(int index) {
|
||||
if (index < states.size()) {
|
||||
// return new Copier<GameState>().uncompressCopy(states.get(index));
|
||||
// return new Copier<GameState>().uncompressCopy(states.get(index));
|
||||
return states.get(index);
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl{
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init(UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
//Move tiny leader to command zone
|
||||
for (UUID playerId: state.getPlayerList(startingPlayerId)) {
|
||||
|
|
@ -101,7 +101,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl{
|
|||
|
||||
}
|
||||
this.getState().addAbility(ability, null);
|
||||
super.init(choosingPlayerId, gameOptions);
|
||||
super.init(choosingPlayerId);
|
||||
if (startingPlayerSkipsDraw) {
|
||||
state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public class MatchOptions implements Serializable {
|
|||
protected List<String> playerTypes = new ArrayList<>();
|
||||
protected String password;
|
||||
protected SkillLevel skillLevel;
|
||||
protected boolean rollbackTurnsAllowed;
|
||||
|
||||
/**
|
||||
* Time each player has during the game to play using his\her priority.
|
||||
|
|
@ -159,4 +160,12 @@ public class MatchOptions implements Serializable {
|
|||
public void setSkillLevel(SkillLevel skillLevel) {
|
||||
this.skillLevel = skillLevel;
|
||||
}
|
||||
|
||||
public boolean isRollbackTurnsAllowed() {
|
||||
return rollbackTurnsAllowed;
|
||||
}
|
||||
|
||||
public void setRollbackTurnsAllowed(boolean rollbackTurnsAllowed) {
|
||||
this.rollbackTurnsAllowed = rollbackTurnsAllowed;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
package mage.game.match;
|
||||
|
||||
import java.io.Serializable;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.players.Player;
|
||||
|
|
@ -36,7 +37,10 @@ import mage.players.Player;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class MatchPlayer {
|
||||
public class MatchPlayer implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 42L;
|
||||
|
||||
private int wins;
|
||||
private boolean matchWinner;
|
||||
|
||||
|
|
@ -45,7 +49,7 @@ public class MatchPlayer {
|
|||
private final String name;
|
||||
|
||||
private boolean quit;
|
||||
private final boolean timerTimeout;
|
||||
//private final boolean timerTimeout;
|
||||
private boolean doneSideboarding;
|
||||
private int priorityTimeLeft;
|
||||
|
||||
|
|
@ -56,7 +60,7 @@ public class MatchPlayer {
|
|||
this.wins = 0;
|
||||
this.doneSideboarding = true;
|
||||
this.quit = false;
|
||||
this.timerTimeout = false;
|
||||
//this.timerTimeout = false;
|
||||
this.name = player.getName();
|
||||
this.matchWinner = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ public abstract class Phase implements Serializable {
|
|||
currentStep = step;
|
||||
if (!game.getState().getTurnMods().skipStep(activePlayerId, getStep().getType())) {
|
||||
playStep(game);
|
||||
if (game.executingRollback()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!game.isSimulation() && checkStopOnStepOption(game)) {
|
||||
return false;
|
||||
|
|
@ -201,6 +204,9 @@ public abstract class Phase implements Serializable {
|
|||
prePriority(game, activePlayerId);
|
||||
if (!game.isPaused() && !game.gameOver(null)) {
|
||||
currentStep.priority(game, activePlayerId, false);
|
||||
if(game.executingRollback()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!game.isPaused() && !game.gameOver(null)) {
|
||||
postPriority(game, activePlayerId);
|
||||
|
|
|
|||
|
|
@ -117,30 +117,34 @@ public class Turn implements Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void play(Game game, UUID activePlayerId) {
|
||||
public void play(Game game, Player activePlayer) {
|
||||
activePlayer.becomesActivePlayer();
|
||||
this.setDeclareAttackersStepStarted(false);
|
||||
if (game.isPaused() || game.gameOver(null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (game.getState().getTurnMods().skipTurn(activePlayerId)) {
|
||||
if (game.getState().getTurnMods().skipTurn(activePlayer.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkTurnIsControlledByOtherPlayer(game, activePlayerId);
|
||||
checkTurnIsControlledByOtherPlayer(game, activePlayer.getId());
|
||||
|
||||
this.activePlayerId = activePlayerId;
|
||||
this.activePlayerId = activePlayer.getId();
|
||||
resetCounts();
|
||||
game.getPlayer(activePlayerId).beginTurn(game);
|
||||
game.getPlayer(activePlayer.getId()).beginTurn(game);
|
||||
for (Phase phase: phases) {
|
||||
if (game.isPaused() || game.gameOver(null)) {
|
||||
return;
|
||||
}
|
||||
if (!isEndTurnRequested() || phase.getType().equals(TurnPhase.END)) {
|
||||
currentPhase = phase;
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayerId, null, activePlayerId));
|
||||
if (!game.getState().getTurnMods().skipPhase(activePlayerId, currentPhase.getType())) {
|
||||
if (phase.play(game, activePlayerId)) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayer.getId(), null, activePlayer.getId()));
|
||||
if (!game.getState().getTurnMods().skipPhase(activePlayer.getId(), currentPhase.getType())) {
|
||||
if (phase.play(game, activePlayer.getId())) {
|
||||
if(game.executingRollback()) {
|
||||
return;
|
||||
}
|
||||
//20091005 - 500.4/703.4n
|
||||
game.emptyManaPools();
|
||||
game.saveState(false);
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
void leave();
|
||||
void concede(Game game);
|
||||
void abort();
|
||||
void abortReset();
|
||||
void skip();
|
||||
|
||||
// priority, undo, ...
|
||||
|
|
|
|||
|
|
@ -369,8 +369,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.canPaySacrificeCost = player.canPaySacrificeCost();
|
||||
this.loseByZeroOrLessLife = player.canLoseByZeroOrLessLife();
|
||||
this.canPlayCardsFromGraveyard = player.canPlayCardsFromGraveyard();
|
||||
this.alternativeSourceCosts.addAll(player.getAlternativeSourceCosts());
|
||||
this.storedBookmark = player.getStoredBookmark();
|
||||
this.alternativeSourceCosts.addAll(player.getAlternativeSourceCosts());
|
||||
|
||||
this.topCardRevealed = player.isTopCardRevealed();
|
||||
this.playersUnderYourControl.clear();
|
||||
|
|
@ -385,7 +384,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.castSourceIdWithAlternateMana = player.getCastSourceIdWithAlternateMana();
|
||||
this.castSourceIdManaCosts = player.getCastSourceIdManaCosts();
|
||||
|
||||
this.usersAllowedToSeeHandCards.addAll(player.getUsersAllowedToSeeHandCards());
|
||||
// Don't restore!
|
||||
// this.storedBookmark
|
||||
// this.usersAllowedToSeeHandCards
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1855,7 +1856,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
passedAllTurns = false;
|
||||
passedUntilEndOfTurn = true;
|
||||
passedUntilStackResolved = false;
|
||||
skippedAtLeastOnce = !game.getTurn().getStepType().equals(PhaseStep.END_TURN);
|
||||
skippedAtLeastOnce = !PhaseStep.END_TURN.equals(game.getTurn().getStepType());
|
||||
this.skip();
|
||||
break;
|
||||
case PASS_PRIORITY_UNTIL_NEXT_TURN: // F4
|
||||
|
|
@ -3126,4 +3127,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return matchPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abortReset() {
|
||||
abort = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import java.util.zip.GZIPOutputStream;
|
|||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @param <T>
|
||||
*/
|
||||
public class Copier<T> {
|
||||
|
||||
|
|
@ -95,8 +96,7 @@ public class Copier<T> {
|
|||
|
||||
public T uncompressCopy(byte[] buffer) {
|
||||
T copy = null;
|
||||
try {
|
||||
ObjectInputStream in = new CopierObjectInputStream(loader, new GZIPInputStream(new ByteArrayInputStream(buffer)));
|
||||
try (ObjectInputStream in = new CopierObjectInputStream(loader, new GZIPInputStream(new ByteArrayInputStream(buffer)))) {
|
||||
copy = (T) in.readObject();
|
||||
}
|
||||
catch(IOException e) {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import mage.ObjectColor;
|
|||
public class GameLog {
|
||||
|
||||
static final String LOG_COLOR_PLAYER = "#20B2AA"; // LightSeaGreen
|
||||
static final String LOG_COLOR_PLAYER_REQUEST = "#D2691E"; // Chocolate
|
||||
static final String LOG_COLOR_GREEN = "#90EE90"; // LightGreen
|
||||
static final String LOG_COLOR_RED = "#FF6347"; // Tomato
|
||||
static final String LOG_COLOR_BLUE = "#87CEFA"; // LightSkyBlue
|
||||
|
|
@ -64,6 +65,10 @@ public class GameLog {
|
|||
public static String getColoredPlayerName(String name) {
|
||||
return "<font color=\'" + LOG_COLOR_PLAYER + "\'>" + name + "</font>";
|
||||
}
|
||||
|
||||
public static String getPlayerRequestColoredText(String name) {
|
||||
return "<font color=\'" + LOG_COLOR_PLAYER_REQUEST + "\'>" + name + "</font>";
|
||||
}
|
||||
|
||||
private static String getColorName(ObjectColor objectColor) {
|
||||
if (objectColor.isMulticolored()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue