From 72b954c80360afeaf13a70605502a341c806fd8f Mon Sep 17 00:00:00 2001 From: slapshot5 Date: Sun, 4 Dec 2011 03:32:38 +0000 Subject: [PATCH] Add a Game Log (and tie into New GUI). It currently has the ability to log turns, phases, add to stack, resolve from stack, play land, activate mana ability. However, only stack info and turns will show up in the log by default. (There is a logging level that can eventually be used for customization.) --- .gitattributes | 1 + src/main/java/forge/AllZone.java | 18 ++++ src/main/java/forge/GameAction.java | 2 + src/main/java/forge/GameLog.java | 82 +++++++++++++++++++ src/main/java/forge/MagicStack.java | 26 +++++- src/main/java/forge/Phase.java | 3 + src/main/java/forge/Player.java | 3 + .../forge/control/match/ControlTabber.java | 9 ++ src/main/java/forge/model/FGameState.java | 23 ++++++ .../java/forge/view/match/ViewTabber.java | 42 +++++++++- 10 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 src/main/java/forge/GameLog.java diff --git a/.gitattributes b/.gitattributes index 4e2295115ad..398b37ce1bf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10559,6 +10559,7 @@ src/main/java/forge/FileUtil.java svneol=native#text/plain src/main/java/forge/GameAction.java svneol=native#text/plain src/main/java/forge/GameActionUtil.java svneol=native#text/plain src/main/java/forge/GameEntity.java -text +src/main/java/forge/GameLog.java -text src/main/java/forge/GuiDisplay.java svneol=native#text/plain src/main/java/forge/GuiDisplayUtil.java svneol=native#text/plain src/main/java/forge/GuiDownloadPicturesLQ.java svneol=native#text/plain diff --git a/src/main/java/forge/AllZone.java b/src/main/java/forge/AllZone.java index 65696578647..63fa28dd2b8 100644 --- a/src/main/java/forge/AllZone.java +++ b/src/main/java/forge/AllZone.java @@ -292,6 +292,24 @@ public final class AllZone { return null; } + /** + *

+ * getGameLog. + *

+ * + * @return a {@link forge.GameLog} object; may be null. + * @since 1.2.0 + */ + public static GameLog getGameLog() { + final FGameState gameState = Singletons.getModel().getGameState(); + + if (gameState != null) { + return gameState.getGameLog(); + } + + return null; + } + /** *

* getCardFactory. diff --git a/src/main/java/forge/GameAction.java b/src/main/java/forge/GameAction.java index e6c72b3daeb..5162d0c66a9 100644 --- a/src/main/java/forge/GameAction.java +++ b/src/main/java/forge/GameAction.java @@ -1486,6 +1486,8 @@ public class GameAction { AllZone.getInputControl().setInput(new InputMulligan()); Phase.setGameBegins(1); + + AllZone.getGameLog().add("Turn", "Turn " + AllZone.getPhase().getTurn() + " (" + AllZone.getPhase().getPlayerTurn()+")", 0); } // newGame() // this is where the computer cheats diff --git a/src/main/java/forge/GameLog.java b/src/main/java/forge/GameLog.java new file mode 100644 index 00000000000..f4466d30307 --- /dev/null +++ b/src/main/java/forge/GameLog.java @@ -0,0 +1,82 @@ + +package forge; + +import java.util.ArrayList; + + +/** + *

+ * GameLog class. + *

+ * + * Logging level: + * 0 - Turn + * 2 - Stack items + * 4 - Mana abilities + * 6 - All Phase information + * + * @author Forge + * @version $Id: GameLog.java 12297 2011-11-28 19:56:47Z slapshot5 $ + */ +public class GameLog extends MyObservable { + private ArrayList log = new ArrayList(); + + public GameLog() { + + } + + public void add(final String type, final String message, final int level) { + log.add(new LogEntry(type, message, level)); + this.updateObservers(); + } + + public String getLogText() { + return getLogText(10); + } + + public String getLogText(final int logLevel) { + StringBuilder sb = new StringBuilder(); + for (int i = log.size() - 1; i >= 0; i--) { + LogEntry le = log.get(i); + if (le.getLevel() > logLevel) { + continue; + } + sb.append(le.getType()).append(": ").append(le.getMessage()); + sb.append("\r\n"); + } + return sb.toString(); + } + + public void reset() { + log.clear(); + this.updateObservers(); + } + + public LogEntry getLogEntry(int index) { + return log.get(index); + } + + private class LogEntry { + private String type; + private String message; + private int level; + + LogEntry(final String typeIn, final String messageIn, final int levelIn) { + type = typeIn; + message = messageIn; + level = levelIn; + } + + public String getType() { + return type; + } + + public String getMessage() { + return message; + } + + public int getLevel() { + return level; + } + } +} // end class GameLog diff --git a/src/main/java/forge/MagicStack.java b/src/main/java/forge/MagicStack.java index 8ba69da1b44..906597f4974 100644 --- a/src/main/java/forge/MagicStack.java +++ b/src/main/java/forge/MagicStack.java @@ -375,6 +375,7 @@ public class MagicStack extends MyObservable { if (sp instanceof AbilityMana) { // Mana Abilities go straight through sp.resolve(); sp.resetOnceResolved(); + AllZone.getGameLog().add("Mana", sp.getSourceCard() + " - " + sp.getDescription(), 4); return; } @@ -383,6 +384,28 @@ public class MagicStack extends MyObservable { this.getFrozenStack().push(si); return; } + + //============= GameLog ====================== + StringBuilder sb = new StringBuilder(); + sb.append(sp.getActivatingPlayer()); + if (sp.isSpell()) { + sb.append(" cast "); + } + else if (sp.isAbility()) { + sb.append(" activated "); + } + sb.append(sp.getSourceCard()); + + if (sp.getTarget() != null) { + sb.append(" targeting "); + for (TargetChoices ch : chosenTargets) { + sb.append(ch.getTargetedString()); + } + } + sb.append("."); + + AllZone.getGameLog().add("AddToStack", sb.toString(), 2); + //============= GameLog ====================== // if activating player slips through the cracks, assign activating // Player to the controller here @@ -938,7 +961,8 @@ public class MagicStack extends MyObservable { } } } - + + AllZone.getGameLog().add("ResolveStack", sa.getStackDescription(), 2); } /** diff --git a/src/main/java/forge/Phase.java b/src/main/java/forge/Phase.java index 4e478217072..24e81cd8438 100644 --- a/src/main/java/forge/Phase.java +++ b/src/main/java/forge/Phase.java @@ -526,11 +526,14 @@ public class Phase extends MyObservable implements java.io.Serializable { this.bRepeat = false; } } + + AllZone.getGameLog().add("Phase", getPlayerTurn() + " " + getPhase(), 6); // **** Anything BELOW Here is actually in the next phase. Maybe move // this to handleBeginPhase if (this.getPhase().equals(Constant.Phase.UNTAP)) { this.turn++; + AllZone.getGameLog().add("Turn", "Turn " + turn + " ("+getPlayerTurn()+")", 0); } // Visual indicators diff --git a/src/main/java/forge/Player.java b/src/main/java/forge/Player.java index 04954655d93..b5505702ba8 100644 --- a/src/main/java/forge/Player.java +++ b/src/main/java/forge/Player.java @@ -1680,6 +1680,9 @@ public abstract class Player extends GameEntity { // check state effects for static animate (Living Lands, Conversion, // etc...) AllZone.getGameAction().checkStateEffects(); + + //add to log + AllZone.getGameLog().add("Land", this + " played " + land, 2); // Run triggers final HashMap runParams = new HashMap(); diff --git a/src/main/java/forge/control/match/ControlTabber.java b/src/main/java/forge/control/match/ControlTabber.java index 520ca868421..1ae4d464d62 100644 --- a/src/main/java/forge/control/match/ControlTabber.java +++ b/src/main/java/forge/control/match/ControlTabber.java @@ -73,8 +73,17 @@ public class ControlTabber extends MyObservable { ControlTabber.this.view.updateStack(); } }; + + //Game Log + final Observer o2 = new Observer() { + @Override + public void update(final Observable a, final Object b) { + ControlTabber.this.view.updateConsole(); + } + }; AllZone.getStack().addObserver(o1); + AllZone.getGameLog().addObserver(o2); } /** Adds listeners to various components in tabber. */ diff --git a/src/main/java/forge/model/FGameState.java b/src/main/java/forge/model/FGameState.java index 809c30f0c73..b9cfb93a0bf 100644 --- a/src/main/java/forge/model/FGameState.java +++ b/src/main/java/forge/model/FGameState.java @@ -25,6 +25,7 @@ import forge.DefaultPlayerZone; import forge.EndOfCombat; import forge.EndOfTurn; import forge.GameAction; +import forge.GameLog; import forge.HumanPlayer; import forge.MagicStack; import forge.Phase; @@ -57,6 +58,7 @@ public class FGameState { private StaticEffects staticEffects = new StaticEffects(); private TriggerHandler triggerHandler = new TriggerHandler(); private Combat combat = new Combat(); + private GameLog gameLog = new GameLog(); private PlayerZone stackZone = new DefaultPlayerZone(Constant.Zone.Stack, null); @@ -287,6 +289,25 @@ public class FGameState { this.combat = combat0; } + /** + * Gets the game log. + * + * @return the game log + */ + public final GameLog getGameLog() { + return this.gameLog; + } + + /** + * Sets the game log. + * + * @param combat0 + * the combat to set + */ + public final void setgameLog(final GameLog gl) { + this.gameLog = gl; + } + /** * Gets the stack zone. * @@ -356,6 +377,8 @@ public class FGameState { this.getPhase().reset(); this.getStack().reset(); this.getCombat().reset(); + + this.getGameLog().reset(); for (final Player p : this.getPlayers()) { for (final Zone z : Player.ALL_ZONES) { diff --git a/src/main/java/forge/view/match/ViewTabber.java b/src/main/java/forge/view/match/ViewTabber.java index 37f1e46002e..0faaa23e377 100644 --- a/src/main/java/forge/view/match/ViewTabber.java +++ b/src/main/java/forge/view/match/ViewTabber.java @@ -39,6 +39,7 @@ import javax.swing.border.MatteBorder; import net.miginfocom.swing.MigLayout; import forge.AllZone; import forge.Constant; +import forge.GameLog; import forge.MagicStack; import forge.Player; import forge.card.spellability.SpellAbilityStackInstance; @@ -229,6 +230,36 @@ public class ViewTabber extends FRoundedPanel { this.pnlCombat.add(tar, "w 95%!, gapleft 3%, gaptop 1%, h 95%"); } + /** + * Sets the text for the GameLog + * + * @param s + *   String message + */ + public void updateConsole() { + final GameLog gl = AllZone.getGameLog(); + + this.pnlConsole.removeAll(); + + final Font font = this.skin.getFont1().deriveFont(Font.PLAIN, 14); + final Border border = new MatteBorder(0, 0, 1, 0, this.skin.getClrBorders()); + + //by default, grab everything logging level 2 or less + //TODO - some option to make this configurable is probably desirable + JTextArea tar = new JTextArea(gl.getLogText(2)); + tar.setOpaque(false); + tar.setBorder(border); + tar.setFont(font); + tar.setForeground(this.skin.getClrText()); + + tar.setFocusable(false); + tar.setEditable(false); + tar.setLineWrap(true); + tar.setWrapStyleWord(true); + + this.pnlConsole.add(tar, "w 95%!, gapleft 3%, gaptop 1%"); + } + /** * Updates labels in the "player" panel, which display non-critical details * about each player in the game. @@ -276,6 +307,15 @@ public class ViewTabber extends FRoundedPanel { return this.pnlCombat; } + /** + * Gets the pnl console. + * + * @return FPanel + */ + public FPanel getPnlConsole() { + return this.pnlConsole; + } + /** * Gets the pnl players. * @@ -489,7 +529,7 @@ public class ViewTabber extends FRoundedPanel { log.setFont(this.skin.getFont1().deriveFont(Font.PLAIN, 12)); log.setBorder(new MatteBorder(1, 0, 0, 0, this.skin.getClrBorders())); - log.setText("Not implemented yet. Input codes entered above. " + "Output data recorded below."); + log.setText("No log information yet. Input codes entered above. " + "Output data recorded below."); this.pnlConsole.setLayout(new MigLayout("insets 0, gap 0, wrap 2"));