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