diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index 4cfb6dfd91a..ef1464e2c56 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -1153,7 +1153,7 @@ public class PhaseHandler implements java.io.Serializable { } turn = cturn; - game.fireEvent(new GameEventTurnPhase(playerTurn, phase, "")); + game.fireEvent(new GameEventTurnPhase(playerTurn, phase, "dev")); if (endCombat) { endCombat(); // not-null can be created only when declare attackers phase begins } diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index d5c952cb15f..5d88f0ce3ea 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -51,6 +51,7 @@ import forge.ImageCache; import forge.LobbyPlayer; import forge.Singletons; import forge.StaticData; +import forge.ai.GameState; import forge.assets.FSkinProp; import forge.card.CardStateName; import forge.control.KeyboardShortcuts; @@ -620,6 +621,11 @@ public final class CMatchUI }); } + @Override + public GameState getGamestate() { + return null; + } + @Override public List getMenus() { return menus.getMenus(); @@ -771,7 +777,7 @@ public final class CMatchUI } @Override - public void updatePhase() { + public void updatePhase(boolean saveState) { final PlayerView p = getGameView().getPlayerTurn(); final PhaseType ph = getGameView().getPhase(); // this should never happen, but I've seen it periodically... so, need to get to the bottom of it diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 51c1ffafe75..6c81849be07 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -7,7 +7,9 @@ import java.util.List; import java.util.Map; import forge.FThreads; +import forge.ai.GameState; import forge.assets.FSkinImage; +import forge.item.IPaperCard; import forge.util.Localizer; import org.apache.commons.lang3.StringUtils; @@ -71,6 +73,11 @@ public class MatchController extends AbstractGuiGame { private static HostedMatch hostedMatch; private static MatchScreen view; + private static GameState phaseGameState; + + private GameState getPhaseGameState() { + return phaseGameState; + } private final Map zonesToRestore = Maps.newHashMap(); @@ -122,6 +129,11 @@ public class MatchController extends AbstractGuiGame { refreshCardDetails(null); } + @Override + public GameState getGamestate() { + return getPhaseGameState(); + } + public boolean hotSeatMode() { return FModel.getPreferences().getPrefBoolean(FPref.MATCH_HOT_SEAT_MODE); } @@ -199,7 +211,7 @@ public class MatchController extends AbstractGuiGame { } @Override - public void updatePhase() { + public void updatePhase(boolean saveState) { final PlayerView p = getGameView().getPlayerTurn(); final PhaseType ph = getGameView().getPhase(); @@ -217,6 +229,20 @@ public class MatchController extends AbstractGuiGame { } if(GuiBase.isNetworkplay()) checkStack(); + + if (saveState) { + phaseGameState = new GameState() { + @Override //todo get specific card edition for this function? + public IPaperCard getPaperCard(final String cardName) { + return FModel.getMagicDb().getCommonCards().getCard(cardName); + } + }; + try { + phaseGameState.initFromGame(getGameView().getGame()); + } catch (Exception e) { + System.out.println(phaseGameState); + } + } } diff --git a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java index 903b796ed80..548dbbb8ac7 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java @@ -378,6 +378,9 @@ public class MatchScreen extends FScreen { devMenu.setEnabled(true); else devMenu.setEnabled(false); + + //rollbackphase enable -- todo limit by gametype? + devMenu.getChildAt(2).setEnabled(game.getPlayers().size() == 2 && game.getStack().size() == 0 && !GuiBase.isNetworkplay()); } } diff --git a/forge-gui-mobile/src/forge/screens/match/views/VDevMenu.java b/forge-gui-mobile/src/forge/screens/match/views/VDevMenu.java index 4bc24b8ceda..524875812b4 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VDevMenu.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VDevMenu.java @@ -34,6 +34,17 @@ public class VDevMenu extends FDropDownMenu { }); } })); + addItem(new FMenuItem(Localizer.getInstance().getMessage("lblRollbackPhase"), new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + ThreadUtil.invokeInGameThread(new Runnable() { //must invoke all these in game thread since they may require synchronous user input + @Override + public void run() { + MatchController.instance.getGameController().cheat().rollbackPhase(); + } + }); + } + })); addItem(new FMenuItem(Localizer.getInstance().getMessage("lblCastSpellOrPlayLand"), new FEventHandler() { @Override public void handleEvent(FEvent e) { diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 3a2b59192e3..972ee275ac8 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -1947,6 +1947,7 @@ lblViewAll=Zeige alle Karten lblSetupGame=Spielstand erstellen lblDumpGame=Spielstand sichern lblTutor=Suche nach Karte +lblRollbackPhase=Rollback Phase lblAddCounterPermanent=Marken zu Karte hinzufügen lblSubCounterPermanent=Marken von Karte entfernen lblTapPermanent=Bleibende Karte tappen diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 5e5798bc1fe..3fa7c3ca427 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1947,6 +1947,7 @@ lblViewAll=View All Cards lblSetupGame=Setup Game State lblDumpGame=Dump Game State lblTutor=Tutor for Card +lblRollbackPhase=Rollback Phase lblAddCounterPermanent=Add Counters to Card lblSubCounterPermanent=Sub Counters from Card lblTapPermanent=Tap Permanents diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 93bb5643c6a..6e1251e6b62 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -1947,6 +1947,7 @@ lblViewAll=Ver todas las cartas lblSetupGame=Configurar el estado del juego lblDumpGame=Volcar el estado del juego lblTutor=Tutor para la carta +lblRollbackPhase=Rollback Phase lblAddCounterPermanent=Añadir contadores a la carta lblSubCounterPermanent=Quitar contadores a la carta lblTapPermanent=Girar permanentes diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index ef1e3094fa3..ee19babe5d3 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -1947,6 +1947,7 @@ lblViewAll=View All Cards lblSetupGame=Setup Game State lblDumpGame=Dump Game State lblTutor=Tutor for Card +lblRollbackPhase=Rollback Phase lblAddCounterPermanent=Add Counters to Card lblSubCounterPermanent=Sub Counters from Card lblTapPermanent=Tap Permanents diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index c3c0e34f5d5..eff98ff542b 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -1947,6 +1947,7 @@ lblViewAll=View All Cards lblSetupGame=Setup Game State lblDumpGame=Dump Game State lblTutor=Tutor for Card +lblRollbackPhase=Rollback Phase lblAddCounterPermanent=Add Counters to Card lblSubCounterPermanent=Sub Counters from Card lblTapPermanent=Tap Permanents diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index d425253b20d..de317e0ed67 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -1947,6 +1947,7 @@ lblViewAll=查看所有牌 lblSetupGame=设定游戏状态 lblDumpGame=转储游戏状态 lblTutor=导师牌 +lblRollbackPhase=Rollback Phase lblAddCounterPermanent=向牌添加指示物 lblSubCounterPermanent=从牌减少指示物 lblTapPermanent=横置永久物 diff --git a/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java b/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java index d07e5a7c9b7..a93b5bf1f9b 100644 --- a/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java +++ b/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java @@ -39,6 +39,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { private boolean processEventsQueued, needPhaseUpdate, needCombatUpdate, needStackUpdate, needPlayerControlUpdate, refreshFieldUpdate; private boolean gameOver, gameFinished; + private boolean needSaveState = false; private PlayerView turnUpdate; public FControlGameEventHandler(final PlayerControllerHuman humanController0) { @@ -81,7 +82,12 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { } if (needPhaseUpdate) { needPhaseUpdate = false; - matchController.updatePhase(); + if (needSaveState) { + needSaveState = false; + matchController.updatePhase(true); + } else { + matchController.updatePhase(false); + } } if (needCombatUpdate) { needCombatUpdate = false; @@ -173,6 +179,10 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { @Override public Void visit(final GameEventTurnPhase ev) { needPhaseUpdate = true; + if (ev.phaseDesc == "dev") + needSaveState = false; + else + needSaveState = true; return processEvent(); } diff --git a/forge-gui/src/main/java/forge/interfaces/IDevModeCheats.java b/forge-gui/src/main/java/forge/interfaces/IDevModeCheats.java index dd62238991e..b296696c5fa 100644 --- a/forge-gui/src/main/java/forge/interfaces/IDevModeCheats.java +++ b/forge-gui/src/main/java/forge/interfaces/IDevModeCheats.java @@ -8,6 +8,8 @@ public interface IDevModeCheats { void generateMana(); + void rollbackPhase(); + void dumpGameState(); void setupGameState(); @@ -95,6 +97,11 @@ public interface IDevModeCheats { @Override public void generateMana() { } + + @Override + public void rollbackPhase() { + } + @Override public void dumpGameState() { } diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java index ded3b8b5963..743af6b8307 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java @@ -7,6 +7,7 @@ import java.util.Map; import com.google.common.base.Function; import forge.LobbyPlayer; +import forge.ai.GameState; import forge.assets.FSkinProp; import forge.deck.CardPool; import forge.game.GameEntityView; @@ -42,7 +43,7 @@ public interface IGuiGame { void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1); void flashIncorrectAction(); void alertUser(); - void updatePhase(); + void updatePhase(boolean saveState); void updateTurn(PlayerView player); void updatePlayerControl(); void enableOverlay(); @@ -61,6 +62,7 @@ public interface IGuiGame { void updateCards(Iterable cards); void refreshCardDetails(Iterable cards); void refreshField(); + GameState getGamestate(); void updateManaPool(Iterable manaPoolUpdate); void updateLives(Iterable livesUpdate); void setPanelSelection(CardView hostCard); diff --git a/forge-gui/src/main/java/forge/match/HostedMatch.java b/forge-gui/src/main/java/forge/match/HostedMatch.java index ba2bd1f9c10..bc2dd2db781 100644 --- a/forge-gui/src/main/java/forge/match/HostedMatch.java +++ b/forge-gui/src/main/java/forge/match/HostedMatch.java @@ -418,7 +418,7 @@ public class HostedMatch { gui.openView(new TrackableCollection<>(p.getView())); gui.setGameView(null); gui.setGameView(gameView); - gui.updatePhase(); + gui.updatePhase(true); gui.message(event.message); } } diff --git a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java index 902ec236091..7c7c2deb927 100644 --- a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java @@ -2,6 +2,7 @@ package forge.net.server; import com.google.common.base.Function; import forge.LobbyPlayer; +import forge.ai.GameState; import forge.assets.FSkinProp; import forge.deck.CardPool; import forge.game.GameEntityView; @@ -93,7 +94,7 @@ public class NetGuiGame extends AbstractGuiGame { public void alertUser() { send(ProtocolMethod.alertUser); } @Override - public void updatePhase() { + public void updatePhase(boolean saveState) { updateGameView(); send(ProtocolMethod.updatePhase); } @@ -189,6 +190,11 @@ public class NetGuiGame extends AbstractGuiGame { send(ProtocolMethod.refreshField); } + @Override + public GameState getGamestate() { + return null; + } + @Override public SpellAbilityView getAbilityToPlay(final CardView hostCard, final List abilities, final ITriggerEvent triggerEvent) { return sendAndWait(ProtocolMethod.getAbilityToPlay, hostCard, abilities, null/*triggerEvent*/); //someplatform don't have mousetriggerevent class or it will not allow them to click/tap diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index e8444f0bacb..e98487f821f 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -2140,6 +2140,17 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont }); } + @Override + public void rollbackPhase() { + final Player pPriority = getGame().getPhaseHandler().getPriorityPlayer(); + if (pPriority == null) { + getGui().message(localizer.getMessage("lblNoPlayerPriorityGameStateCannotBeSetup")); + return; + } + if (getGui().getGamestate() != null) + getGui().getGamestate().applyToGame(getGame()); + } + private GameState createGameStateObject() { return new GameState() { @Override