diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDev.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDev.java index 9582dd6d610..8d65f9db1d0 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDev.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDev.java @@ -61,6 +61,16 @@ public enum CDev implements ICDoc { public void setupGameState() { MatchUtil.getHumanController().cheat().setupGameState(); } + + private final MouseListener madDump = new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + dumpGameState(); + } + }; + public void dumpGameState() { + MatchUtil.getHumanController().cheat().dumpGameState(); + } private final MouseListener madTutor = new MouseAdapter() { @Override @@ -181,6 +191,7 @@ public enum CDev implements ICDoc { VDev.SINGLETON_INSTANCE.getLblViewAll().addMouseListener(madViewAll); VDev.SINGLETON_INSTANCE.getLblGenerateMana().addMouseListener(madMana); VDev.SINGLETON_INSTANCE.getLblSetupGame().addMouseListener(madSetup); + VDev.SINGLETON_INSTANCE.getLblDumpGame().addMouseListener(madDump); VDev.SINGLETON_INSTANCE.getLblTutor().addMouseListener(madTutor); VDev.SINGLETON_INSTANCE.getLblCardToHand().addMouseListener(madCardToHand); VDev.SINGLETON_INSTANCE.getLblCounterPermanent().addMouseListener(madCounter); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/views/VDev.java b/forge-gui-desktop/src/main/java/forge/screens/match/views/VDev.java index 0667d349dda..51a9890ca11 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/views/VDev.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/views/VDev.java @@ -60,6 +60,7 @@ public enum VDev implements IVDoc { private final DevLabel lblViewAll = new DevLabel("View All Cards"); private final DevLabel lblGenerateMana = new DevLabel("Generate Mana"); private final DevLabel lblSetupGame = new DevLabel("Setup Game State"); + private final DevLabel lblDumpGame = new DevLabel("Dump Game State"); private final DevLabel lblTutor = new DevLabel("Tutor for Card"); private final DevLabel lblCounterPermanent = new DevLabel("Add Counters to Permanent"); private final DevLabel lblTapPermanent = new DevLabel("Tap Permanents"); @@ -86,6 +87,7 @@ public enum VDev implements IVDoc { viewport.add(this.lblSetLife, halfConstraintsLeft); viewport.add(this.lblWinGame, halfConstraints); viewport.add(this.lblSetupGame, constraints); + viewport.add(this.lblDumpGame, constraints); viewport.add(this.lblUnlimitedLands, constraints); viewport.add(this.lblCounterPermanent, constraints); viewport.add(this.lblTapPermanent, halfConstraintsLeft); @@ -157,6 +159,11 @@ public enum VDev implements IVDoc { return this.lblSetupGame; } + /** @return {@link forge.screens.match.views.VDev.DevLabel} */ + public DevLabel getLblDumpGame() { + return this.lblDumpGame; + } + /** @return {@link forge.screens.match.views.VDev.DevLabel} */ public DevLabel getLblTutor() { return this.lblTutor; diff --git a/forge-gui/src/main/java/forge/player/GameState.java b/forge-gui/src/main/java/forge/player/GameState.java index bd6d0a93cfa..d6a4d56fe7b 100644 --- a/forge-gui/src/main/java/forge/player/GameState.java +++ b/forge-gui/src/main/java/forge/player/GameState.java @@ -4,6 +4,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -18,8 +19,18 @@ import forge.game.player.Player; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.model.FModel; +import forge.util.FCollectionView; public class GameState { + private static final Map ZONES = new HashMap(); + static { + ZONES.put(ZoneType.Battlefield, "play"); + ZONES.put(ZoneType.Hand, "hand"); + ZONES.put(ZoneType.Graveyard, "graveyard"); + ZONES.put(ZoneType.Library, "library"); + ZONES.put(ZoneType.Exile, "exile"); + } + private int humanLife = -1; private int computerLife = -1; private final Map humanCardTexts = new EnumMap(ZoneType.class); @@ -30,6 +41,85 @@ public class GameState { public GameState() { } + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("humanlife=%d\n", humanLife)); + sb.append(String.format("ailife=%d\n", computerLife)); + sb.append(String.format("activeplayer=%s\n", tChangePlayer)); + sb.append(String.format("activephase=%s\n", tChangePhase)); + appendCards(humanCardTexts, "human", sb); + appendCards(aiCardTexts, "ai", sb); + return sb.toString(); + } + + private void appendCards(Map cardTexts, String categoryPrefix, StringBuilder sb) { + for (Entry kv : cardTexts.entrySet()) { + sb.append(String.format("%scardsin%s=%s\n", categoryPrefix, ZONES.get(kv.getKey()), kv.getValue())); + } + } + + public void initFromGame(Game game) throws Exception { + FCollectionView players = game.getPlayers(); + // Can only serialized a two player game with one AI and one human. + if (players.size() != 2) { + throw new Exception("Game not supported"); + } + final Player human = game.getPlayers().get(0); + final Player ai = game.getPlayers().get(1); + if (!human.getController().isGuiPlayer() || !ai.getController().isAI()) { + throw new Exception("Game not supported"); + } + humanLife = human.getLife(); + computerLife = ai.getLife(); + tChangePlayer = game.getPhaseHandler().getPlayerTurn() == ai ? "ai" : "human"; + tChangePhase = game.getPhaseHandler().getPhase().toString(); + aiCardTexts.clear(); + humanCardTexts.clear(); + for (ZoneType zone : ZONES.keySet()) { + for (Card card : game.getCardsIn(zone)) { + addCard(zone, card.getOwner() == ai ? aiCardTexts : humanCardTexts, card); + } + } + } + + private void addCard(ZoneType zoneType, Map cardTexts, Card c) { + String value = cardTexts.get(zoneType); + String newText = c.getName(); + if (zoneType == ZoneType.Battlefield) { + if (c.isTapped()) { + newText += "|Tapped:True"; + } + if (c.isSick()) { + newText += "|SummonSick:True"; + } + if (c.isFaceDown()) { + newText += "|FaceDown:True"; + } + Map counters = c.getCounters(); + if (!counters.isEmpty()) { + newText += "|Counters:"; + boolean start = true; + for(Entry kv : counters.entrySet()) { + String str = kv.getKey().toString(); + int count = kv.getValue(); + for (int i = 0; i < count; i++) { + if (!start) { + newText += ","; + } + newText += str; + start = false; + } + } + } + } + if (value == null) { + value = newText; + } else { + value += ";" + newText; + } + cardTexts.put(zoneType, value); + } + public void parse(InputStream in) throws Exception { final BufferedReader br = new BufferedReader(new InputStreamReader(in)); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 2d437ec2cb5..0a1f2e8eee0 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -1,8 +1,10 @@ package forge.player; +import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -1416,6 +1418,22 @@ public class PlayerControllerHuman extends PlayerController { }); } + public void dumpGameState() { + final GameState state = new GameState(); + try { + state.initFromGame(game); + File f = GuiBase.getInterface().getSaveFile(new File(ForgeConstants.USER_GAMES_DIR, "state.txt")); + if (f != null) { + final BufferedWriter bw = new BufferedWriter(new FileWriter(f)); + bw.write(state.toString()); + bw.close(); + } + } catch (Exception e) { + SOptionPane.showErrorDialog(e.getMessage()); + e.printStackTrace(); + } + } + public void setupGameState() { File gamesDir = new File(ForgeConstants.USER_GAMES_DIR); if (!gamesDir.exists()) { // if the directory does not exist, try to create it