- Added option to replace default "Human" with custom name during gameplay. (http://www.slightlymagic.net/forum/viewtopic.php?f=52&t=11553).

This commit is contained in:
spr
2013-10-07 19:56:00 +00:00
parent a8cf682f71
commit db9a451e32
16 changed files with 1708 additions and 1498 deletions

1
.gitattributes vendored
View File

@@ -15187,6 +15187,7 @@ src/main/java/forge/gui/home/settings/CSubmenuAvatars.java -text
src/main/java/forge/gui/home/settings/CSubmenuDownloaders.java -text src/main/java/forge/gui/home/settings/CSubmenuDownloaders.java -text
src/main/java/forge/gui/home/settings/CSubmenuPreferences.java -text src/main/java/forge/gui/home/settings/CSubmenuPreferences.java -text
src/main/java/forge/gui/home/settings/CSubmenuReleaseNotes.java -text src/main/java/forge/gui/home/settings/CSubmenuReleaseNotes.java -text
src/main/java/forge/gui/home/settings/GamePlayerUtil.java -text
src/main/java/forge/gui/home/settings/VSubmenuAvatars.java -text src/main/java/forge/gui/home/settings/VSubmenuAvatars.java -text
src/main/java/forge/gui/home/settings/VSubmenuDownloaders.java -text src/main/java/forge/gui/home/settings/VSubmenuDownloaders.java -text
src/main/java/forge/gui/home/settings/VSubmenuPreferences.java -text src/main/java/forge/gui/home/settings/VSubmenuPreferences.java -text

View File

@@ -1,253 +1,248 @@
package forge; package forge;
import java.util.ArrayList; import java.util.Collection;
import java.util.Collection; import java.util.List;
import java.util.List; import java.util.Map.Entry;
import java.util.Map.Entry;
import com.google.common.eventbus.Subscribe;
import com.google.common.eventbus.Subscribe;
import forge.card.spellability.TargetChoices;
import forge.card.spellability.TargetChoices; import forge.game.GameOutcome;
import forge.game.GameOutcome; import forge.game.event.GameEvent;
import forge.game.event.GameEventAttackersDeclared; import forge.game.event.GameEventAttackersDeclared;
import forge.game.event.GameEventBlockersDeclared; import forge.game.event.GameEventBlockersDeclared;
import forge.game.event.GameEventCardDamaged; import forge.game.event.GameEventCardDamaged;
import forge.game.event.GameEventCardDamaged.DamageType; import forge.game.event.GameEventCardDamaged.DamageType;
import forge.game.event.GameEventLandPlayed; import forge.game.event.GameEventGameOutcome;
import forge.game.event.GameEventMulligan; import forge.game.event.GameEventLandPlayed;
import forge.game.event.GameEventPlayerDamaged; import forge.game.event.GameEventMulligan;
import forge.game.event.GameEventPlayerPoisoned; import forge.game.event.GameEventPlayerControl;
import forge.game.event.GameEventSpellAbilityCast; import forge.game.event.GameEventPlayerDamaged;
import forge.game.event.GameEventSpellResolved; import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.GameEventTurnBegan; import forge.game.event.GameEventSpellAbilityCast;
import forge.game.event.IGameEventVisitor; import forge.game.event.GameEventSpellResolved;
import forge.game.event.GameEventGameOutcome; import forge.game.event.GameEventTurnBegan;
import forge.game.event.GameEvent; import forge.game.event.GameEventTurnPhase;
import forge.game.event.GameEventTurnPhase; import forge.game.event.IGameEventVisitor;
import forge.game.event.GameEventPlayerControl; import forge.game.player.LobbyPlayer;
import forge.game.player.LobbyPlayer; import forge.game.player.Player;
import forge.game.player.Player; import forge.game.zone.ZoneType;
import forge.game.player.PlayerStatistics; import forge.util.Lang;
import forge.game.zone.ZoneType; import forge.util.maps.MapOfLists;
import forge.net.FServer;
import forge.util.Lang; public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
import forge.util.maps.MapOfLists; private final GameLog log;
public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> { public GameLogFormatter(GameLog gameLog) {
private final GameLog log; log = gameLog;
}
public GameLogFormatter(GameLog gameLog) {
log = gameLog; @Override
} public GameLogEntry visit(GameEventGameOutcome ev) {
for (Player p : ev.result.getPlayers()) {
@Override String outcome = String.format("%s has %s", p.getName(), p.getOutcome().toString());
public GameLogEntry visit(GameEventGameOutcome ev) { log.add(GameLogEntryType.GAME_OUTCOME, outcome);
// add result entries to the game log }
final LobbyPlayer human = FServer.instance.getLobby().getGuiPlayer(); return generateSummary(ev.history);
}
// This adds some extra entries to log
final List<String> outcomes = new ArrayList<String>();
for (Entry<LobbyPlayer, PlayerStatistics> p : ev.result) { /* (non-Javadoc)
String whoHas = p.getKey().equals(human) ? "You have" : p.getKey().getName() + " has"; * @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventSpellResolved)
String outcome = String.format("%s %s", whoHas, p.getValue().getOutcome().toString()); */
outcomes.add(outcome); @Override
log.add(GameLogEntryType.GAME_OUTCOME, outcome); public GameLogEntry visit(GameEventSpellResolved ev) {
} String messageForLog = ev.hasFizzled ? ev.spell.getSourceCard().getName() + " ability fizzles." : ev.spell.getStackDescription();
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, messageForLog);
return generateSummary(ev.history); }
}
@Override
/* (non-Javadoc) public GameLogEntry visit(GameEventSpellAbilityCast event) {
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventSpellResolved) String who = event.sa.getActivatingPlayer().getName();
*/ String action = event.sa.isSpell() ? " cast " : " activated ";
@Override String what = event.sa.getStackDescription().startsWith("Morph ") ? "Morph" : event.sa.getSourceCard().toString();
public GameLogEntry visit(GameEventSpellResolved ev) {
String messageForLog = ev.hasFizzled ? ev.spell.getSourceCard().getName() + " ability fizzles." : ev.spell.getStackDescription(); StringBuilder sb = new StringBuilder();
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, messageForLog); sb.append(who).append(action).append(what);
}
if (event.sa.getTargetRestrictions() != null) {
sb.append(" targeting ");
@Override for (TargetChoices ch : event.sa.getAllTargetChoices()) {
public GameLogEntry visit(GameEventSpellAbilityCast event) { if (null != ch) {
String who = event.sa.getActivatingPlayer().getName(); sb.append(ch.getTargetedString());
String action = event.sa.isSpell() ? " cast " : " activated "; }
String what = event.sa.getStackDescription().startsWith("Morph ") ? "Morph" : event.sa.getSourceCard().toString(); }
}
StringBuilder sb = new StringBuilder(); sb.append(".");
sb.append(who).append(action).append(what);
return new GameLogEntry(GameLogEntryType.STACK_ADD, sb.toString());
if (event.sa.getTargetRestrictions() != null) { }
sb.append(" targeting ");
for (TargetChoices ch : event.sa.getAllTargetChoices()) { private GameLogEntry generateSummary(List<GameOutcome> gamesPlayed) {
if (null != ch) {
sb.append(ch.getTargetedString()); GameOutcome outcome1 = gamesPlayed.get(0);
} List<Player> players = outcome1.getPlayers();
}
} final int[] wins = new int[players.size()];
sb.append(".");
// Calculate total games each player has won.
return new GameLogEntry(GameLogEntryType.STACK_ADD, sb.toString()); for (GameOutcome game : gamesPlayed) {
} int i = 0;
for (Player p : game.getPlayers()) {
private GameLogEntry generateSummary(List<GameOutcome> gamesPlayed) { if (p.getOutcome().hasWon()) {
GameOutcome outcome1 = gamesPlayed.get(0); wins[i]++;
int[] wins = new int[outcome1.getNumPlayers()]; }
LobbyPlayer[] players = new LobbyPlayer[outcome1.getNumPlayers()]; i++;
for(int i = 0; i < wins.length; wins[i++] = 0); }
}
for (GameOutcome go : gamesPlayed) {
int i = 0; StringBuilder sb = new StringBuilder();
for(Entry<LobbyPlayer, PlayerStatistics> ps : go) { for(int i = 0; i < wins.length; i++) {
players[i] = ps.getKey(); Player player = players.get(i);
if( ps.getValue().getOutcome().hasWon() ) String playerName = player.getName();
wins[i]++; playerName += " [" + player.getOriginalLobbyPlayer().getType() + "]";
i++; sb.append(playerName).append(": ").append(wins[i]).append(" ");
} }
}
return new GameLogEntry(GameLogEntryType.MATCH_RESULTS, sb.toString());
StringBuilder sb = new StringBuilder(); }
for(int i = 0; i < wins.length; i++) {
sb.append(players[i].getName()).append(": ").append(wins[i]).append(" "); @Override
} public GameLogEntry visit(GameEventPlayerControl event) {
return new GameLogEntry(GameLogEntryType.MATCH_RESULTS, sb.toString()); // TODO Auto-generated method stub
} LobbyPlayer newController = event.newController;
Player p = event.player;
@Override
public GameLogEntry visit(GameEventPlayerControl event) { final String message;
// TODO Auto-generated method stub if( newController == null )
LobbyPlayer newController = event.newController; message = p.getName() + " has restored control over themself";
Player p = event.player; else
message = String.format("%s is controlled by %s", p.getName(), newController.getName());
final String message;
if( newController == null ) return new GameLogEntry(GameLogEntryType.PLAYER_CONROL, message);
message = p.getName() + " has restored control over themself"; }
else
message = String.format("%s is controlled by %s", p.getName(), newController.getName()); @Override
public GameLogEntry visit(GameEventTurnPhase ev) {
return new GameLogEntry(GameLogEntryType.PLAYER_CONROL, message); Player p = ev.playerTurn;
} return new GameLogEntry(GameLogEntryType.PHASE, ev.phaseDesc + Lang.getPossesive(p.getName()) + " " + ev.phase.nameForUi);
}
@Override
public GameLogEntry visit(GameEventTurnPhase ev) {
Player p = ev.playerTurn; @Override
return new GameLogEntry(GameLogEntryType.PHASE, ev.phaseDesc + Lang.getPossesive(p.getName()) + " " + ev.phase.nameForUi); public GameLogEntry visit(GameEventCardDamaged event) {
} String additionalLog = "";
if( event.type == DamageType.Deathtouch ) additionalLog = "(Deathtouch)";
if( event.type == DamageType.M1M1Counters ) additionalLog = "(As -1/-1 Counters)";
@Override if( event.type == DamageType.LoyaltyLoss ) additionalLog = "(Removing " + Lang.nounWithAmount(event.amount, "loyalty counter") + ")";
public GameLogEntry visit(GameEventCardDamaged event) {
String additionalLog = ""; String message = String.format("%s deals %d damage %s to %s.", event.source, event.amount, additionalLog, event.card);
if( event.type == DamageType.Deathtouch ) additionalLog = "(Deathtouch)"; return new GameLogEntry(GameLogEntryType.DAMAGE, message);
if( event.type == DamageType.M1M1Counters ) additionalLog = "(As -1/-1 Counters)"; }
if( event.type == DamageType.LoyaltyLoss ) additionalLog = "(Removing " + Lang.nounWithAmount(event.amount, "loyalty counter") + ")";
/* (non-Javadoc)
String message = String.format("%s deals %d damage %s to %s.", event.source, event.amount, additionalLog, event.card); * @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventLandPlayed)
return new GameLogEntry(GameLogEntryType.DAMAGE, message); */
} @Override
public GameLogEntry visit(GameEventLandPlayed ev) {
/* (non-Javadoc) String message = String.format("%s played %s", ev.player, ev.land);
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventLandPlayed) return new GameLogEntry(GameLogEntryType.LAND, message);
*/ }
@Override
public GameLogEntry visit(GameEventLandPlayed ev) { @Override
String message = String.format("%s played %s", ev.player, ev.land); public GameLogEntry visit(GameEventTurnBegan event) {
return new GameLogEntry(GameLogEntryType.LAND, message); String message = String.format( "Turn %d (%s)", event.turnNumber, event.turnOwner);
} return new GameLogEntry(GameLogEntryType.TURN, message);
}
@Override
public GameLogEntry visit(GameEventTurnBegan event) { @Override
String message = String.format( "Turn %d (%s)", event.turnNumber, event.turnOwner); public GameLogEntry visit(GameEventPlayerDamaged ev) {
return new GameLogEntry(GameLogEntryType.TURN, message); String extra = ev.infect ? " (as poison counters)" : "";
} String message = String.format("%s deals %d %s damage to %s%s.", ev.source, ev.amount, ev.combat ? "combat" : "non-combat", ev.target, extra );
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
@Override }
public GameLogEntry visit(GameEventPlayerDamaged ev) {
String extra = ev.infect ? " (as poison counters)" : ""; @Override
String message = String.format("%s deals %d %s damage to %s%s.", ev.source, ev.amount, ev.combat ? "combat" : "non-combat", ev.target, extra ); public GameLogEntry visit(GameEventPlayerPoisoned ev) {
return new GameLogEntry(GameLogEntryType.DAMAGE, message); String message = String.format("%s receives %s from %s", ev.receiver, Lang.nounWithAmount(ev.amount, "posion counter"), ev.source);
} return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@Override
public GameLogEntry visit(GameEventPlayerPoisoned ev) { @Override
String message = String.format("%s receives %s from %s", ev.receiver, Lang.nounWithAmount(ev.amount, "posion counter"), ev.source); public GameLogEntry visit(final GameEventAttackersDeclared ev) {
return new GameLogEntry(GameLogEntryType.DAMAGE, message); final StringBuilder sb = new StringBuilder();
}
// Loop through Defenders
@Override // Append Defending Player/Planeswalker
public GameLogEntry visit(final GameEventAttackersDeclared ev) {
final StringBuilder sb = new StringBuilder(); // Not a big fan of the triple nested loop here
for (GameEntity k : ev.attackersMap.keySet()) {
// Loop through Defenders
// Append Defending Player/Planeswalker Collection<Card> attackers = ev.attackersMap.get(k);
if (attackers == null || attackers.isEmpty()) {
// Not a big fan of the triple nested loop here continue;
for (GameEntity k : ev.attackersMap.keySet()) { }
if ( sb.length() > 0 ) sb.append("\n");
Collection<Card> attackers = ev.attackersMap.get(k); sb.append(ev.player + " assigned " + Lang.joinHomogenous(attackers));
if (attackers == null || attackers.isEmpty()) { sb.append(" to attack " + k + ".");
continue; }
} if ( sb.length() == 0 )
if ( sb.length() > 0 ) sb.append("\n"); sb.append(ev.player + " didn't attack this turn.");
sb.append(ev.player + " assigned " + Lang.joinHomogenous(attackers));
sb.append(" to attack " + k + "."); return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
} }
if ( sb.length() == 0 )
sb.append(ev.player + " didn't attack this turn.");
@Override
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString()); public GameLogEntry visit(final GameEventBlockersDeclared ev) {
} final StringBuilder sb = new StringBuilder();
// Loop through Defenders
@Override // Append Defending Player/Planeswalker
public GameLogEntry visit(final GameEventBlockersDeclared ev) {
final StringBuilder sb = new StringBuilder(); Collection<Card> blockers = null;
// Loop through Defenders for (Entry<GameEntity, MapOfLists<Card, Card>> kv : ev.blockers.entrySet()) {
// Append Defending Player/Planeswalker GameEntity defender = kv.getKey();
MapOfLists<Card, Card> attackers = kv.getValue();
Collection<Card> blockers = null; if (attackers == null || attackers.isEmpty()) {
continue;
for (Entry<GameEntity, MapOfLists<Card, Card>> kv : ev.blockers.entrySet()) { }
GameEntity defender = kv.getKey(); if ( sb.length() > 0 ) sb.append("\n");
MapOfLists<Card, Card> attackers = kv.getValue();
if (attackers == null || attackers.isEmpty()) { String controllerName = defender instanceof Card ? ((Card)defender).getController().getName() : defender.getName();
continue; boolean firstAttacker = true;
} for (final Entry<Card, Collection<Card>> att : attackers.entrySet()) {
if ( sb.length() > 0 ) sb.append("\n"); if ( !firstAttacker ) sb.append("\n");
String controllerName = defender instanceof Card ? ((Card)defender).getController().getName() : defender.getName(); blockers = att.getValue();
boolean firstAttacker = true; if ( blockers.isEmpty() ) {
for (final Entry<Card, Collection<Card>> att : attackers.entrySet()) { sb.append(controllerName + " didn't block ");
if ( !firstAttacker ) sb.append("\n"); } else {
sb.append(controllerName + " assigned " + Lang.joinHomogenous(blockers) + " to block ");
blockers = att.getValue(); }
if ( blockers.isEmpty() ) {
sb.append(controllerName + " didn't block "); sb.append(att.getKey()).append(".");
} else { firstAttacker = false;
sb.append(controllerName + " assigned " + Lang.joinHomogenous(blockers) + " to block "); }
} }
sb.append(att.getKey()).append("."); return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
firstAttacker = false; }
}
} @Override
public GameLogEntry visit(GameEventMulligan ev) {
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString()); String message = String.format( "%s has mulliganed down to %d cards.", ev.player, ev.player.getZone(ZoneType.Hand).size());
} return new GameLogEntry(GameLogEntryType.MULLIGAN, message);
}
@Override
public GameLogEntry visit(GameEventMulligan ev) {
String message = String.format( "%s has mulliganed down to %d cards.", ev.player, ev.player.getZone(ZoneType.Hand).size()); @Subscribe
return new GameLogEntry(GameLogEntryType.MULLIGAN, message); public void recieve(GameEvent ev) {
} GameLogEntry le = ev.visit(this);
if ( le != null )
log.add(le);
@Subscribe }
public void recieve(GameEvent ev) {
GameLogEntry le = ev.visit(this);
if ( le != null )
log.add(le);
}
} // end class GameLog } // end class GameLog

View File

@@ -35,6 +35,8 @@ import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.WindowConstants; import javax.swing.WindowConstants;
import org.apache.commons.lang.StringUtils;
import forge.Card; import forge.Card;
import forge.Constant.Preferences; import forge.Constant.Preferences;
import forge.Singletons; import forge.Singletons;
@@ -42,7 +44,10 @@ import forge.control.KeyboardShortcuts.Shortcut;
import forge.game.Game; import forge.game.Game;
import forge.game.GameType; import forge.game.GameType;
import forge.game.Match; import forge.game.Match;
import forge.game.RegisteredPlayer;
import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayer;
import forge.game.player.LobbyPlayerAi;
import forge.game.player.LobbyPlayerHuman;
import forge.game.player.Player; import forge.game.player.Player;
import forge.gui.GuiDialog; import forge.gui.GuiDialog;
import forge.gui.SOverlayUtils; import forge.gui.SOverlayUtils;
@@ -56,6 +61,7 @@ import forge.gui.framework.SOverflowUtil;
import forge.gui.framework.SResizingUtil; import forge.gui.framework.SResizingUtil;
import forge.gui.home.CHomeUI; import forge.gui.home.CHomeUI;
import forge.gui.home.VHomeUI; import forge.gui.home.VHomeUI;
import forge.gui.home.settings.GamePlayerUtil;
import forge.gui.match.CMatchUI; import forge.gui.match.CMatchUI;
import forge.gui.match.VMatchUI; import forge.gui.match.VMatchUI;
import forge.gui.match.controllers.CDock; import forge.gui.match.controllers.CDock;
@@ -67,6 +73,7 @@ import forge.gui.match.views.VAntes;
import forge.gui.menus.ForgeMenu; import forge.gui.menus.ForgeMenu;
import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin;
import forge.net.FServer; import forge.net.FServer;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
import forge.properties.NewConstants; import forge.properties.NewConstants;
import forge.quest.QuestController; import forge.quest.QuestController;
@@ -400,7 +407,7 @@ public enum FControl implements KeyEventDispatcher {
game.getAction().checkGameOverCondition(); game.getAction().checkGameOverCondition();
else { else {
game.isGameOver(); // this is synchronized method - it's used to make Game-0 thread see changes made here game.isGameOver(); // this is synchronized method - it's used to make Game-0 thread see changes made here
inputQueue.onGameOver(false); // release any waiting input, effectively passing priority inputQueue.onGameOver(false); // release any waiting input, effectively passing priority
} }
playbackControl.onGameStopRequested(); playbackControl.onGameStopRequested();
@@ -413,6 +420,7 @@ public enum FControl implements KeyEventDispatcher {
public final void startGameWithUi(Match match) { public final void startGameWithUi(Match match) {
setPlayerName(match.getPlayers());
Game newGame = match.createGame(); Game newGame = match.createGame();
attachToGame(newGame); attachToGame(newGame);
match.startGame(newGame, null); match.startGame(newGame, null);
@@ -512,5 +520,23 @@ public enum FControl implements KeyEventDispatcher {
//Allow the event to be redispatched //Allow the event to be redispatched
return false; return false;
} }
/**
* Prompts user for a name that will be used instead of "Human" during gameplay.
* <p>
* This is a one time only event that is triggered when starting a game and the
* PLAYER_NAME setting is blank. Does not apply to a hotseat game.
*/
private void setPlayerName(List<RegisteredPlayer> players) {
final ForgePreferences prefs = Singletons.getModel().getPreferences();
if (StringUtils.isBlank(prefs.getPref(FPref.PLAYER_NAME))) {
boolean isPlayerOneHuman = players.get(0).getPlayer() instanceof LobbyPlayerHuman;
boolean isPlayerTwoComputer = players.get(1).getPlayer() instanceof LobbyPlayerAi;
if (isPlayerOneHuman && isPlayerTwoComputer) {
GamePlayerUtil.setPlayerName();
}
}
}
} }

View File

@@ -1,162 +1,184 @@
/* /*
* Forge: Play Magic: the Gathering. * Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team * Copyright (C) 2011 Forge Team
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package forge.game; package forge.game;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayer;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerOutcome; import forge.game.player.PlayerOutcome;
import forge.game.player.PlayerStatistics; import forge.game.player.PlayerStatistics;
/** /**
* <p> * <p>
* GameInfo class. * GameInfo class.
* </p> * </p>
* *
* @author Forge * @author Forge
* @version $Id: GameOutcome.java 17608 2012-10-20 22:27:27Z Max mtg $ * @version $Id: GameOutcome.java 17608 2012-10-20 22:27:27Z Max mtg $
*/ */
// This class might be divided in two parts: the very summary (immutable with // This class might be divided in two parts: the very summary (immutable with
// only getters) and // only getters) and
// GameObserver class - who should be notified of any considerable ingame event // GameObserver class - who should be notified of any considerable ingame event
public final class GameOutcome implements Iterable<Pair<LobbyPlayer, PlayerStatistics>> { public final class GameOutcome implements Iterable<Pair<LobbyPlayer, PlayerStatistics>> {
/** The player got first turn. */ /** The player got first turn. */
// private String playerGotFirstTurn = "Nobody"; // private String playerGotFirstTurn = "Nobody";
/** The last turn number. */ /** The last turn number. */
private int lastTurnNumber = 0; private int lastTurnNumber = 0;
/** The player rating. */ /** The player rating. */
private final List<Pair<LobbyPlayer, PlayerStatistics>> playerRating = new ArrayList<Pair<LobbyPlayer, PlayerStatistics>>(2); private final List<Pair<LobbyPlayer, PlayerStatistics>> playerRating = new ArrayList<Pair<LobbyPlayer, PlayerStatistics>>(2);
private GameEndReason winCondition; private final Iterable<Player> players;
public GameOutcome(GameEndReason reason, final Iterable<Player> list) { private GameEndReason winCondition;
winCondition = reason;
for (final Player n : list) { public GameOutcome(GameEndReason reason, final Iterable<Player> list) {
this.playerRating.add(Pair.of(n.getLobbyPlayer(), n.getStats())); winCondition = reason;
} players = list;
} for (final Player n : list) {
this.playerRating.add(Pair.of(n.getLobbyPlayer(), n.getStats()));
public boolean isDraw() { }
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating) { }
if (pv.getValue().getOutcome().hasWon()) {
return false; public boolean isDraw() {
} for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating) {
} if (pv.getValue().getOutcome().hasWon()) {
return true; return false;
} }
}
return true;
public boolean isWinner(final LobbyPlayer who) { }
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating)
if (pv.getValue().getOutcome().hasWon() && pv.getKey() == who )
return true; public boolean isWinner(final LobbyPlayer who) {
return false; for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating)
} if (pv.getValue().getOutcome().hasWon() && pv.getKey() == who )
return true;
/** return false;
* Gets the winner. }
*
* @return the winner /**
*/ * Gets the winner.
public LobbyPlayer getWinner() { *
for (Entry<LobbyPlayer, PlayerStatistics> ps : playerRating) { * @return the winner
if (ps.getValue().getOutcome().hasWon()) { */
return ps.getKey(); public LobbyPlayer getWinningLobbyPlayer() {
} for (Entry<LobbyPlayer, PlayerStatistics> ps : playerRating) {
} if (ps.getValue().getOutcome().hasWon()) {
return null; return ps.getKey();
} }
}
/** return null;
* Gets the win condition. }
*
* @return the win condition /**
*/ * Gets winning {@code Player}.
public GameEndReason getWinCondition() { * <p>
return this.winCondition; * Alternative to {@link getWinningLobbyPlayer()} which does not
} * distinguish between human player names (a problem for hotseat games).
*/
/** public Player getWinningPlayer() {
* Gets the turn game ended. for (Player p: players) {
* if (p.getOutcome().hasWon()) {
* @return the turn game ended return p;
*/ }
public int getLastTurnNumber() { }
return this.lastTurnNumber; return null;
} }
/** /**
* Sets the player who got first turn. * Gets the win condition.
* *
*/ * @return the win condition
/* */
* public void setPlayerWhoGotFirstTurn(final String playerName) { public GameEndReason getWinCondition() {
* this.playerGotFirstTurn = playerName; } return this.winCondition;
*/ }
/** /**
* Gets the win spell effect. * Gets the turn game ended.
* *
* @return the win spell effect * @return the turn game ended
*/ */
public String getWinSpellEffect() { public int getLastTurnNumber() {
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating) { return this.lastTurnNumber;
PlayerOutcome po = pv.getValue().getOutcome(); }
if (po.hasWon()) {
return po.altWinSourceName; /**
} * Sets the player who got first turn.
} *
return null; */
} /*
* public void setPlayerWhoGotFirstTurn(final String playerName) {
/* (non-Javadoc) * this.playerGotFirstTurn = playerName; }
* @see java.lang.Iterable#iterator() */
*/
@Override /**
public Iterator<Pair<LobbyPlayer, PlayerStatistics>> iterator() { * Gets the win spell effect.
return playerRating.iterator(); *
} * @return the win spell effect
*/
/** public String getWinSpellEffect() {
* TODO: Write javadoc for this method. for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating) {
* @param turnNumber PlayerOutcome po = pv.getValue().getOutcome();
*/ if (po.hasWon()) {
public void setTurnsPlayed(int turnNumber) { return po.altWinSourceName;
lastTurnNumber = turnNumber; }
} }
return null;
/** }
* TODO: Write javadoc for this method.
* @return /* (non-Javadoc)
*/ * @see java.lang.Iterable#iterator()
public int getNumPlayers() { */
return playerRating.size(); @Override
} public Iterator<Pair<LobbyPlayer, PlayerStatistics>> iterator() {
return playerRating.iterator();
} }
/**
* TODO: Write javadoc for this method.
* @param turnNumber
*/
public void setTurnsPlayed(int turnNumber) {
lastTurnNumber = turnNumber;
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public int getNumPlayers() {
return playerRating.size();
}
public List<Player> getPlayers() {
return (List<Player>)players;
}
}

View File

@@ -1,197 +1,197 @@
package forge.game; package forge.game;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Card; import forge.Card;
import forge.Singletons; import forge.Singletons;
import forge.game.event.GameEventAnteCardsSelected; import forge.game.event.GameEventAnteCardsSelected;
import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayer;
import forge.game.player.Player; import forge.game.player.Player;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
*/ */
public class Match { public class Match {
private final List<RegisteredPlayer> players; private final List<RegisteredPlayer> players;
private final GameType gameType; private final GameType gameType;
private int gamesPerMatch = 3; private int gamesPerMatch = 3;
private int gamesToWinMatch = 2; private int gamesToWinMatch = 2;
private boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE); private boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE);
private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>(); private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>();
private final List<GameOutcome> gamesPlayedRo; private final List<GameOutcome> gamesPlayedRo;
/** /**
* This should become constructor once. * This should become constructor once.
*/ */
public Match(GameType type, List<RegisteredPlayer> players0) { public Match(GameType type, List<RegisteredPlayer> players0) {
gamesPlayedRo = Collections.unmodifiableList(gamesPlayed); gamesPlayedRo = Collections.unmodifiableList(gamesPlayed);
players = Collections.unmodifiableList(Lists.newArrayList(players0)); players = Collections.unmodifiableList(Lists.newArrayList(players0));
gameType = type; gameType = type;
} }
public Match(GameType type, List<RegisteredPlayer> players0, Boolean overrideAnte) { public Match(GameType type, List<RegisteredPlayer> players0, Boolean overrideAnte) {
this(type, players0); this(type, players0);
if( overrideAnte != null ) if( overrideAnte != null )
this.useAnte = overrideAnte.booleanValue(); this.useAnte = overrideAnte.booleanValue();
} }
/** /**
* Gets the games played. * Gets the games played.
* *
* @return the games played * @return the games played
*/ */
public final List<GameOutcome> getPlayedGames() { public final List<GameOutcome> getPlayedGames() {
return this.gamesPlayedRo; return this.gamesPlayedRo;
} }
/** @return int */ /** @return int */
public int getGamesPerMatch() { public int getGamesPerMatch() {
return gamesPerMatch; return gamesPerMatch;
} }
/** @return int */ /** @return int */
public int getGamesToWinMatch() { public int getGamesToWinMatch() {
return gamesToWinMatch; return gamesToWinMatch;
} }
public void addGamePlayed(Game finished) { public void addGamePlayed(Game finished) {
if (!finished.isGameOver()) { if (!finished.isGameOver()) {
throw new IllegalStateException("Game is not over yet."); throw new IllegalStateException("Game is not over yet.");
} }
gamesPlayed.add(finished.getOutcome()); gamesPlayed.add(finished.getOutcome());
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
*/ */
public Game createGame() { public Game createGame() {
return new Game(players, gameType, this); return new Game(players, gameType, this);
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
*/ */
public void startGame(final Game game, final CountDownLatch latch) { public void startGame(final Game game, final CountDownLatch latch) {
final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed; final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed;
GameNew.newGame(game, canRandomFoil, this.useAnte); GameNew.newGame(game, canRandomFoil, this.useAnte);
// This code could be run run from EDT. // This code could be run run from EDT.
game.getAction().invoke(new Runnable() { game.getAction().invoke(new Runnable() {
@Override @Override
public void run() { public void run() {
if (useAnte) { // Deciding which cards go to ante if (useAnte) { // Deciding which cards go to ante
List<Pair<Player, Card>> list = GameNew.chooseCardsForAnte(game); List<Pair<Player, Card>> list = GameNew.chooseCardsForAnte(game);
GameNew.moveCardsToAnte(list); GameNew.moveCardsToAnte(list);
game.fireEvent(new GameEventAnteCardsSelected(list)); game.fireEvent(new GameEventAnteCardsSelected(list));
} }
GameOutcome lastOutcome = gamesPlayed.isEmpty() ? null : gamesPlayed.get(gamesPlayed.size() - 1); GameOutcome lastOutcome = gamesPlayed.isEmpty() ? null : gamesPlayed.get(gamesPlayed.size() - 1);
game.getAction().startGame(lastOutcome); game.getAction().startGame(lastOutcome);
if( null != latch ) if( null != latch )
latch.countDown(); latch.countDown();
} }
}); });
} }
public void clearGamesPlayed() { public void clearGamesPlayed() {
gamesPlayed.clear(); gamesPlayed.clear();
} }
public void clearLastGame() { public void clearLastGame() {
gamesPlayed.remove(gamesPlayed.size() - 1); gamesPlayed.remove(gamesPlayed.size() - 1);
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* *
* @return * @return
*/ */
public GameType getGameType() { public GameType getGameType() {
return gameType; return gameType;
} }
public Iterable<GameOutcome> getOutcomes() { public Iterable<GameOutcome> getOutcomes() {
return gamesPlayedRo; return gamesPlayedRo;
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* *
* @return * @return
*/ */
public boolean isMatchOver() { public boolean isMatchOver() {
int[] victories = new int[players.size()]; int[] victories = new int[players.size()];
for (GameOutcome go : gamesPlayed) { for (GameOutcome go : gamesPlayed) {
LobbyPlayer winner = go.getWinner(); LobbyPlayer winner = go.getWinningLobbyPlayer();
int i = 0; int i = 0;
for (RegisteredPlayer p : players) { for (RegisteredPlayer p : players) {
if (p.getPlayer().equals(winner)) { if (p.getPlayer().equals(winner)) {
victories[i]++; victories[i]++;
break; // can't have 2 winners per game break; // can't have 2 winners per game
} }
i++; i++;
} }
} }
for (int score : victories) { for (int score : victories) {
if (score >= gamesToWinMatch) { if (score >= gamesToWinMatch) {
return true; return true;
} }
} }
return gamesPlayed.size() >= gamesPerMatch; return gamesPlayed.size() >= gamesPerMatch;
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* *
* @param questPlayer * @param questPlayer
* @return * @return
*/ */
public int getGamesWonBy(LobbyPlayer questPlayer) { public int getGamesWonBy(LobbyPlayer questPlayer) {
int sum = 0; int sum = 0;
for (GameOutcome go : gamesPlayed) { for (GameOutcome go : gamesPlayed) {
if (questPlayer.equals(go.getWinner())) { if (questPlayer.equals(go.getWinningLobbyPlayer())) {
sum++; sum++;
} }
} }
return sum; return sum;
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* *
* @param questPlayer * @param questPlayer
* @return * @return
*/ */
public boolean isWonBy(LobbyPlayer questPlayer) { public boolean isWonBy(LobbyPlayer questPlayer) {
return getGamesWonBy(questPlayer) >= gamesToWinMatch; return getGamesWonBy(questPlayer) >= gamesToWinMatch;
} }
public List<RegisteredPlayer> getPlayers() { public List<RegisteredPlayer> getPlayers() {
return players; return players;
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
*/ */
public static int getPoisonCountersAmountToLose() { public static int getPoisonCountersAmountToLose() {
return 10; return 10;
} }
} }

View File

@@ -52,16 +52,17 @@ import forge.card.spellability.Ability;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.staticability.StaticAbility; import forge.card.staticability.StaticAbility;
import forge.card.trigger.TriggerType; import forge.card.trigger.TriggerType;
import forge.game.GameActionUtil;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameAge; import forge.game.GameAge;
import forge.game.GameType; import forge.game.GameType;
import forge.game.GlobalRuleChange; import forge.game.GlobalRuleChange;
import forge.game.RegisteredPlayer;
import forge.game.event.GameEventLandPlayed; import forge.game.event.GameEventLandPlayed;
import forge.game.event.GameEventPlayerLivesChanged;
import forge.game.event.GameEventMulligan; import forge.game.event.GameEventMulligan;
import forge.game.event.GameEventPlayerControl; import forge.game.event.GameEventPlayerControl;
import forge.game.event.GameEventPlayerDamaged; import forge.game.event.GameEventPlayerDamaged;
import forge.game.event.GameEventPlayerLivesChanged;
import forge.game.event.GameEventPlayerPoisoned; import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.GameEventShuffle; import forge.game.event.GameEventShuffle;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
@@ -72,6 +73,7 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.gui.GuiDialog; import forge.gui.GuiDialog;
import forge.gui.GuiDisplayUtil;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
import forge.util.Lang; import forge.util.Lang;
import forge.util.MyRandom; import forge.util.MyRandom;
@@ -85,9 +87,9 @@ import forge.util.MyRandom;
* @version $Id$ * @version $Id$
*/ */
public class Player extends GameEntity implements Comparable<Player> { public class Player extends GameEntity implements Comparable<Player> {
private final Map<Card,Integer> commanderDamage = new HashMap<Card,Integer>(); private final Map<Card,Integer> commanderDamage = new HashMap<Card,Integer>();
/** The poison counters. */ /** The poison counters. */
private int poisonCounters = 0; private int poisonCounters = 0;
@@ -108,7 +110,7 @@ public class Player extends GameEntity implements Comparable<Player> {
/** The num power surge lands. */ /** The num power surge lands. */
private int numPowerSurgeLands; private int numPowerSurgeLands;
/** The number of times this player has searched his library. */ /** The number of times this player has searched his library. */
private int numLibrarySearchedOwn = 0; private int numLibrarySearchedOwn = 0;
@@ -136,10 +138,10 @@ public class Player extends GameEntity implements Comparable<Player> {
/** The num drawn this turn. */ /** The num drawn this turn. */
private int numDrawnThisTurn = 0; private int numDrawnThisTurn = 0;
private int numDrawnThisDrawStep = 0; private int numDrawnThisDrawStep = 0;
/** The num discarded this turn. */ /** The num discarded this turn. */
private int numDiscardedThisTurn = 0; private int numDiscardedThisTurn = 0;
/** A list of tokens not in play, but on their way. /** A list of tokens not in play, but on their way.
* This list is kept in order to not break ETB-replacement * This list is kept in order to not break ETB-replacement
* on tokens. */ * on tokens. */
@@ -170,9 +172,9 @@ public class Player extends GameEntity implements Comparable<Player> {
protected PlayerController controllerCreator = null; protected PlayerController controllerCreator = null;
private int teamNumber = -1; private int teamNumber = -1;
private Card activeScheme = null; private Card activeScheme = null;
private Card commander = null; private Card commander = null;
/** The Constant ALL_ZONES. */ /** The Constant ALL_ZONES. */
@@ -207,10 +209,19 @@ public class Player extends GameEntity implements Comparable<Player> {
for (final ZoneType z : Player.ALL_ZONES) { for (final ZoneType z : Player.ALL_ZONES) {
final PlayerZone toPut = z == ZoneType.Battlefield final PlayerZone toPut = z == ZoneType.Battlefield
? new PlayerZoneBattlefield(z, this) ? new PlayerZoneBattlefield(z, this)
: new PlayerZone(z, this); : new PlayerZone(z, this);
this.zones.put(z, toPut); this.zones.put(z, toPut);
}
if (isHotSeatGame(game)) {
if (game.getPlayers().size() == 1) {
Player player1 = game.getPlayers().get(0);
player1.setName("Player 1");
this.setName("Player 2");
}
} else {
this.setName(chooseName(GuiDisplayUtil.personalizeHuman(name)));
} }
this.setName(chooseName(name));
} }
private String chooseName(String originalName) { private String chooseName(String originalName) {
@@ -231,14 +242,14 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
@Override @Override
public Game getGame() { // I'll probably regret about this public Game getGame() { // I'll probably regret about this
return game; return game;
} }
public final PlayerStatistics getStats() { public final PlayerStatistics getStats() {
return stats; return stats;
} }
public final void setTeam(int iTeam) { public final void setTeam(int iTeam) {
teamNumber = iTeam; teamNumber = iTeam;
} }
@@ -275,7 +286,7 @@ public class Player extends GameEntity implements Comparable<Player> {
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
activeScheme = getZone(ZoneType.SchemeDeck).get(0); activeScheme = getZone(ZoneType.SchemeDeck).get(0);
// gameAction moveTo ? // gameAction moveTo ?
getZone(ZoneType.SchemeDeck).remove(activeScheme); getZone(ZoneType.SchemeDeck).remove(activeScheme);
this.getZone(ZoneType.Command).add(activeScheme); this.getZone(ZoneType.Command).add(activeScheme);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
@@ -361,7 +372,7 @@ public class Player extends GameEntity implements Comparable<Player> {
return other != this && other != null && ( other.teamNumber < 0 || other.teamNumber != this.teamNumber ); return other != this && other != null && ( other.teamNumber < 0 || other.teamNumber != this.teamNumber );
} }
// //////////////////////// // ////////////////////////
@@ -469,7 +480,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Player", this); runParams.put("Player", this);
runParams.put("LifeAmount", lifeGain); runParams.put("LifeAmount", lifeGain);
game.getTriggerHandler().runTrigger(TriggerType.LifeGained, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.LifeGained, runParams, false);
game.fireEvent(new GameEventPlayerLivesChanged(this, oldLife, life)); game.fireEvent(new GameEventPlayerLivesChanged(this, oldLife, life));
} else { } else {
System.out.println("Player - trying to gain negative or 0 life"); System.out.println("Player - trying to gain negative or 0 life");
@@ -645,7 +656,7 @@ public class Player extends GameEntity implements Comparable<Player> {
commanderDamage.put(source,commanderDamage.get(source) + amount); commanderDamage.put(source,commanderDamage.get(source) + amount);
} }
} }
this.assignedDamage.put(source, amount); this.assignedDamage.put(source, amount);
if (source.hasKeyword("Lifelink")) { if (source.hasKeyword("Lifelink")) {
source.getController().gainLife(amount, source); source.getController().gainLife(amount, source);
@@ -803,7 +814,7 @@ public class Player extends GameEntity implements Comparable<Player> {
restDamage = restDamage / 2; restDamage = restDamage / 2;
} else if (c.getName().equals("Benevolent Unicorn")) { } else if (c.getName().equals("Benevolent Unicorn")) {
if (source.isSpell()) { if (source.isSpell()) {
restDamage -= 1; restDamage -= 1;
} }
} else if (c.getName().equals("Divine Presence")) { } else if (c.getName().equals("Divine Presence")) {
if (restDamage > 3) { if (restDamage > 3) {
@@ -942,7 +953,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (DEBUGShieldsWithEffects) { if (DEBUGShieldsWithEffects) {
System.out.println("Remaining shields: " System.out.println("Remaining shields: "
+ (shieldMap.containsKey(shieldSource) ? shieldMap.get(shieldSource).get("ShieldAmount") : "all shields used")); + (shieldMap.containsKey(shieldSource) ? shieldMap.get(shieldSource).get("ShieldAmount") : "all shields used"));
System.out.println("Remaining damage: " + restDamage); System.out.println("Remaining damage: " + restDamage);
} }
} }
@@ -995,8 +1006,8 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
return num; return num;
} }
public final Iterable<Card> getAssignedDamageSources() { public final Iterable<Card> getAssignedDamageSources() {
return assignedDamage.keySet(); return assignedDamage.keySet();
} }
@@ -1042,7 +1053,7 @@ public class Player extends GameEntity implements Comparable<Player> {
damageToDo = this.preventDamage(damageToDo, source, true); damageToDo = this.preventDamage(damageToDo, source, true);
this.addDamageAfterPrevention(damageToDo, source, true); // damage this.addDamageAfterPrevention(damageToDo, source, true); // damage
// prevention // prevention
// is already // is already
// checked // checked
@@ -1082,7 +1093,7 @@ public class Player extends GameEntity implements Comparable<Player> {
* *
* @param num * @param num
* a int. * a int.
* @param source * @param source
*/ */
public final void setPoisonCounters(final int num, Card source) { public final void setPoisonCounters(final int num, Card source) {
int oldPoison = poisonCounters; int oldPoison = poisonCounters;
@@ -1261,8 +1272,8 @@ public class Player extends GameEntity implements Comparable<Player> {
return this.drawCards(1); return this.drawCards(1);
} }
public boolean canMulligan() { public boolean canMulligan() {
return !getZone(ZoneType.Hand).isEmpty(); return !getZone(ZoneType.Hand).isEmpty();
} }
@@ -1277,13 +1288,13 @@ public class Player extends GameEntity implements Comparable<Player> {
*/ */
public final List<Card> drawCards(final int n) { public final List<Card> drawCards(final int n) {
final List<Card> drawn = new ArrayList<Card>(); final List<Card> drawn = new ArrayList<Card>();
if (!this.canDraw()) { if (!this.canDraw()) {
return drawn; return drawn;
} }
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
// TODO: multiple replacements need to be selected by the controller // TODO: multiple replacements need to be selected by the controller
List<Card> dredgers = this.getDredge(); List<Card> dredgers = this.getDredge();
if (!dredgers.isEmpty()) { if (!dredgers.isEmpty()) {
@@ -1299,7 +1310,7 @@ public class Player extends GameEntity implements Comparable<Player> {
continue; continue;
} }
} }
drawn.addAll(this.doDraw()); drawn.addAll(this.doDraw());
} }
return drawn; return drawn;
@@ -1325,14 +1336,14 @@ public class Player extends GameEntity implements Comparable<Player> {
return drawn; return drawn;
} }
// ======== Chains of Mephistopheles hardcode. ========= // ======== Chains of Mephistopheles hardcode. =========
// This card requires player to either discard a card, and then he may proceed drawing, or mill 1 - then no draw will happen // This card requires player to either discard a card, and then he may proceed drawing, or mill 1 - then no draw will happen
// It's oracle-worded as a replacement effect ("If a player would draw a card ... discards a card instead") (rule 419.1a) // It's oracle-worded as a replacement effect ("If a player would draw a card ... discards a card instead") (rule 419.1a)
// Yet, gatherer's rulings read: The effect is cumulative. If there are two of these on the battlefield, each of them will modify each draw // Yet, gatherer's rulings read: The effect is cumulative. If there are two of these on the battlefield, each of them will modify each draw
// That means player isn't supposed to choose one replacement effect out of two (generated by Chains Of Mephistopheles), but both happen. // That means player isn't supposed to choose one replacement effect out of two (generated by Chains Of Mephistopheles), but both happen.
// So it's not a common replacement effect and has to be handled by special code. // So it's not a common replacement effect and has to be handled by special code.
// This is why the code is placed after any other replacement effects could affect the draw event. // This is why the code is placed after any other replacement effects could affect the draw event.
List<Card> chainsList = null; List<Card> chainsList = null;
for(Card c : game.getCardsIn(ZoneType.Battlefield)) { for(Card c : game.getCardsIn(ZoneType.Battlefield)) {
if ( c.getName().equals("Chains of Mephistopheles") ) { if ( c.getName().equals("Chains of Mephistopheles") ) {
@@ -1353,7 +1364,7 @@ public class Player extends GameEntity implements Comparable<Player> {
AbilityUtils.resolve(saMill); AbilityUtils.resolve(saMill);
return drawn; // Draw is cancelled return drawn; // Draw is cancelled
} else { } else {
SpellAbility saDiscard = AbilityFactory.getAbility(c.getSVar("DiscardOne"), c); SpellAbility saDiscard = AbilityFactory.getAbility(c.getSVar("DiscardOne"), c);
saDiscard.setActivatingPlayer(c.getController()); saDiscard.setActivatingPlayer(c.getController());
saDiscard.getTargets().add(this); saDiscard.getTargets().add(this);
@@ -1361,7 +1372,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
} }
} }
// End of = Chains of Mephistopheles hardcode. ========= // End of = Chains of Mephistopheles hardcode. =========
if (!library.isEmpty()) { if (!library.isEmpty()) {
@@ -1511,7 +1522,7 @@ public class Player extends GameEntity implements Comparable<Player> {
return CardLists.filter(this.getCardsIn(zone), CardPredicates.nameEquals(cardName)); return CardLists.filter(this.getCardsIn(zone), CardPredicates.nameEquals(cardName));
} }
public List<Card> getCardsActivableInExternalZones() { public List<Card> getCardsActivableInExternalZones() {
final List<Card> cl = new ArrayList<Card>(); final List<Card> cl = new ArrayList<Card>();
@@ -1580,7 +1591,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
} }
return 0; return 0;
// throw new RuntimeException("Input_Draw : getDredgeNumber() card doesn't have dredge - " + c.getName()); // throw new RuntimeException("Input_Draw : getDredgeNumber() card doesn't have dredge - " + c.getName());
} // getDredgeNumber() } // getDredgeNumber()
/** /**
@@ -1690,7 +1701,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public final int getNumDiscardedThisTurn() { public final int getNumDiscardedThisTurn() {
return this.numDiscardedThisTurn; return this.numDiscardedThisTurn;
} }
/** /**
* <p> * <p>
* Getter for the field <code>numDiscardedThisTurn</code>. * Getter for the field <code>numDiscardedThisTurn</code>.
@@ -1791,7 +1802,7 @@ public class Player extends GameEntity implements Comparable<Player> {
// Play the shuffle sound // Play the shuffle sound
game.fireEvent(new GameEventShuffle(this)); game.fireEvent(new GameEventShuffle(this));
} // shuffle } // shuffle
// ////////////////////////////// // //////////////////////////////
// ////////////////////////////// // //////////////////////////////
@@ -1860,7 +1871,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
} }
} }
if( land != null && !ignoreZoneAndTiming) { if( land != null && !ignoreZoneAndTiming) {
if (land.getOwner() != this && !land.hasKeyword("May be played by your opponent")) if (land.getOwner() != this && !land.hasKeyword("May be played by your opponent"))
return false; return false;
@@ -1874,7 +1885,7 @@ public class Player extends GameEntity implements Comparable<Player> {
// **** Check for land play limit per turn **** // **** Check for land play limit per turn ****
// Dev Mode // Dev Mode
if (this.getLobbyPlayer().getType() == PlayerType.HUMAN && Preferences.DEV_MODE && if (this.getLobbyPlayer().getType() == PlayerType.HUMAN && Preferences.DEV_MODE &&
Singletons.getModel().getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND)) { Singletons.getModel().getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND)) {
return true; return true;
} }
if (this.isCardInPlay("Fastbond") || this.isCardInCommand("Naya")) { if (this.isCardInPlay("Fastbond") || this.isCardInCommand("Naya")) {
@@ -1979,7 +1990,7 @@ public class Player extends GameEntity implements Comparable<Player> {
* *
* @param s * @param s
* a {@link forge.Card} object. * a {@link forge.Card} object.
* @return * @return
* @return a {@link forge.Card} object. * @return a {@link forge.Card} object.
*/ */
public final void setNamedCard(final String s) { public final void setNamedCard(final String s) {
@@ -2176,14 +2187,14 @@ public class Player extends GameEntity implements Comparable<Player> {
return this.getOutcome().lossState != null; return this.getOutcome().lossState != null;
} }
// Rule 704.5a - If a player has 0 or less life, he or she loses the game. // Rule 704.5a - If a player has 0 or less life, he or she loses the game.
final boolean hasNoLife = this.getLife() <= 0; final boolean hasNoLife = this.getLife() <= 0;
if (hasNoLife && !this.cantLoseForZeroOrLessLife()) { if (hasNoLife && !this.cantLoseForZeroOrLessLife()) {
return this.loseConditionMet(GameLossReason.LifeReachedZero, null); return this.loseConditionMet(GameLossReason.LifeReachedZero, null);
} }
// Rule 704.5b - If a player attempted to draw a card from a library with no cards in it // Rule 704.5b - If a player attempted to draw a card from a library with no cards in it
// since the last time state-based actions were checked, he or she loses the game. // since the last time state-based actions were checked, he or she loses the game.
if (triedToDrawFromEmptyLibrary) { if (triedToDrawFromEmptyLibrary) {
triedToDrawFromEmptyLibrary = false; // one-shot check triedToDrawFromEmptyLibrary = false; // one-shot check
return this.loseConditionMet(GameLossReason.Milled, null); return this.loseConditionMet(GameLossReason.Milled, null);
@@ -2193,7 +2204,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (this.poisonCounters >= 10) { if (this.poisonCounters >= 10) {
return this.loseConditionMet(GameLossReason.Poisoned, null); return this.loseConditionMet(GameLossReason.Poisoned, null);
} }
if(game.getType() == GameType.Commander) if(game.getType() == GameType.Commander)
{ {
Map<Card,Integer> cmdDmg = getCommanderDamage(); Map<Card,Integer> cmdDmg = getCommanderDamage();
@@ -2201,13 +2212,13 @@ public class Player extends GameEntity implements Comparable<Player> {
{ {
if(cmdDmg.get(c) >= 21) if(cmdDmg.get(c) >= 21)
return this.loseConditionMet(GameLossReason.CommanderDamage, null); return this.loseConditionMet(GameLossReason.CommanderDamage, null);
} }
} }
return false; return false;
} }
public final boolean hasLost() { public final boolean hasLost() {
return this.getOutcome() != null && this.getOutcome().lossState != null; return this.getOutcome() != null && this.getOutcome().lossState != null;
} }
@@ -2330,11 +2341,11 @@ public class Player extends GameEntity implements Comparable<Player> {
public final void resetProwl() { public final void resetProwl() {
this.prowl = new ArrayList<String>(); this.prowl = new ArrayList<String>();
} }
public final void setLibrarySearched(final int l) { public final void setLibrarySearched(final int l) {
this.numLibrarySearchedOwn = l; this.numLibrarySearchedOwn = l;
} }
public final int getLibrarySearched() { public final int getLibrarySearched() {
return this.numLibrarySearchedOwn; return this.numLibrarySearchedOwn;
} }
@@ -2378,7 +2389,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (incR.length > 1) { if (incR.length > 1) {
final String excR = incR[1]; final String excR = incR[1];
final String[] exR = excR.split("\\+"); // Exclusive Restrictions final String[] exR = excR.split("\\+"); // Exclusive Restrictions
// are ... // are ...
for (int j = 0; j < exR.length; j++) { for (int j = 0; j < exR.length; j++) {
if (!this.hasProperty(exR[j], sourceController, source)) { if (!this.hasProperty(exR[j], sourceController, source)) {
return false; return false;
@@ -2466,7 +2477,7 @@ public class Player extends GameEntity implements Comparable<Player> {
final Player controller = "Active".equals(property.split("Than")[1]) ? game.getPhaseHandler().getPlayerTurn() : sourceController; final Player controller = "Active".equals(property.split("Than")[1]) ? game.getPhaseHandler().getPlayerTurn() : sourceController;
if (property.substring(7).startsWith("Life") && this.getLife() <= controller.getLife()) { if (property.substring(7).startsWith("Life") && this.getLife() <= controller.getLife()) {
return false; return false;
} else if (property.substring(7).startsWith("CardsInHand") } else if (property.substring(7).startsWith("CardsInHand")
&& this.getCardsIn(ZoneType.Hand).size() <= controller.getCardsIn(ZoneType.Hand).size()) { && this.getCardsIn(ZoneType.Hand).size() <= controller.getCardsIn(ZoneType.Hand).size()) {
return false; return false;
} }
@@ -2624,7 +2635,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public final int getLifeGainedThisTurn() { public final int getLifeGainedThisTurn() {
return this.lifeGainedThisTurn; return this.lifeGainedThisTurn;
} }
/** /**
* <p> * <p>
* Setter for the field <code>lifeGainedThisTurn</code>. * Setter for the field <code>lifeGainedThisTurn</code>.
@@ -2766,11 +2777,11 @@ public class Player extends GameEntity implements Comparable<Player> {
public final LobbyPlayer getOriginalLobbyPlayer() { public final LobbyPlayer getOriginalLobbyPlayer() {
return controllerCreator.getLobbyPlayer(); return controllerCreator.getLobbyPlayer();
} }
public final boolean isMindSlaved() { public final boolean isMindSlaved() {
return controller.getLobbyPlayer() != controllerCreator.getLobbyPlayer(); return controller.getLobbyPlayer() != controllerCreator.getLobbyPlayer();
} }
public final void releaseControl() { public final void releaseControl() {
if ( controller == controllerCreator ) if ( controller == controllerCreator )
return; return;
@@ -2835,7 +2846,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public int getCounterDoublersMagnitude(final CounterType type) { public int getCounterDoublersMagnitude(final CounterType type) {
int counterDoublers = getCardsIn(ZoneType.Battlefield, "Doubling Season").size() int counterDoublers = getCardsIn(ZoneType.Battlefield, "Doubling Season").size()
+ CardLists.filter(getGame().getCardsIn(ZoneType.Command), + CardLists.filter(getGame().getCardsIn(ZoneType.Command),
CardPredicates.nameEquals("Selesnya Loft Gardens")).size(); CardPredicates.nameEquals("Selesnya Loft Gardens")).size();
if (type == CounterType.P1P1) { if (type == CounterType.P1P1) {
counterDoublers += getCardsIn(ZoneType.Battlefield, "Corpsejack Menace").size(); counterDoublers += getCardsIn(ZoneType.Battlefield, "Corpsejack Menace").size();
@@ -2846,9 +2857,9 @@ public class Player extends GameEntity implements Comparable<Player> {
public int getTokenDoublersMagnitude() { public int getTokenDoublersMagnitude() {
final int tokenDoublers = getCardsIn(ZoneType.Battlefield, "Parallel Lives").size() final int tokenDoublers = getCardsIn(ZoneType.Battlefield, "Parallel Lives").size()
+ getCardsIn(ZoneType.Battlefield, "Doubling Season").size() + getCardsIn(ZoneType.Battlefield, "Doubling Season").size()
+ CardLists.filter(getGame().getCardsIn(ZoneType.Command), + CardLists.filter(getGame().getCardsIn(ZoneType.Command),
CardPredicates.nameEquals("Selesnya Loft Gardens")).size();; CardPredicates.nameEquals("Selesnya Loft Gardens")).size();;
return 1 << tokenDoublers; // pow(a,0) = 1; pow(a,1) = a return 1 << tokenDoublers; // pow(a,0) = 1; pow(a,1) = a
} }
public void onCleanupPhase() { public void onCleanupPhase() {
@@ -2911,7 +2922,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final void setFirstController(PlayerController ctrlr) { public final void setFirstController(PlayerController ctrlr) {
if( null != controllerCreator ) throw new IllegalStateException("Controller creator already assigned"); if( null != controllerCreator ) throw new IllegalStateException("Controller creator already assigned");
controllerCreator = ctrlr; controllerCreator = ctrlr;
controller = ctrlr; controller = ctrlr;
} }
/** /**
@@ -2981,13 +2992,13 @@ public class Player extends GameEntity implements Comparable<Player> {
/** /**
* *
* Takes the top plane of the planar deck and put it face up in the command zone. * Takes the top plane of the planar deck and put it face up in the command zone.
* Then runs triggers. * Then runs triggers.
*/ */
public void planeswalk() public void planeswalk()
{ {
planeswalkTo(Arrays.asList(getZone(ZoneType.PlanarDeck).get(0))); planeswalkTo(Arrays.asList(getZone(ZoneType.PlanarDeck).get(0)));
} }
/** /**
* Puts the planes in the argument and puts them face up in the command zone. * Puts the planes in the argument and puts them face up in the command zone.
* Then runs triggers. * Then runs triggers.
@@ -3003,19 +3014,19 @@ public class Player extends GameEntity implements Comparable<Player> {
getZone(ZoneType.PlanarDeck).remove(c); getZone(ZoneType.PlanarDeck).remove(c);
getZone(ZoneType.Command).add(c); getZone(ZoneType.Command).add(c);
} }
//DBG //DBG
//System.out.println("CurrentPlanes: " + currentPlanes); //System.out.println("CurrentPlanes: " + currentPlanes);
//System.out.println("ActivePlanes: " + game.getActivePlanes()); //System.out.println("ActivePlanes: " + game.getActivePlanes());
//System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards()); //System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards());
game.setActivePlanes(currentPlanes); game.setActivePlanes(currentPlanes);
//Run PlaneswalkedTo triggers here. //Run PlaneswalkedTo triggers here.
HashMap<String,Object> runParams = new HashMap<String,Object>(); HashMap<String,Object> runParams = new HashMap<String,Object>();
runParams.put("Card", currentPlanes); runParams.put("Card", currentPlanes);
game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedTo, runParams,false); game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedTo, runParams,false);
} }
/** /**
* *
* Puts my currently active planes, if any, at the bottom of my planar deck. * Puts my currently active planes, if any, at the bottom of my planar deck.
@@ -3024,11 +3035,11 @@ public class Player extends GameEntity implements Comparable<Player> {
{ {
if(!currentPlanes.isEmpty()) if(!currentPlanes.isEmpty())
{ {
//Run PlaneswalkedFrom triggers here. //Run PlaneswalkedFrom triggers here.
HashMap<String,Object> runParams = new HashMap<String,Object>(); HashMap<String,Object> runParams = new HashMap<String,Object>();
runParams.put("Card", new ArrayList<Card>(currentPlanes)); runParams.put("Card", new ArrayList<Card>(currentPlanes));
game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedFrom, runParams,false); game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedFrom, runParams,false);
for(Card c : currentPlanes) { for(Card c : currentPlanes) {
game.getZoneOf(c).remove(c); game.getZoneOf(c).remove(c);
c.clearControllers(); c.clearControllers();
@@ -3042,7 +3053,7 @@ public class Player extends GameEntity implements Comparable<Player> {
//System.out.println("ActivePlanes: " + game.getActivePlanes()); //System.out.println("ActivePlanes: " + game.getActivePlanes());
//System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards()); //System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards());
} }
/** /**
* *
* Sets up the first plane of a round. * Sets up the first plane of a round.
@@ -3065,7 +3076,7 @@ public class Player extends GameEntity implements Comparable<Player> {
break; break;
} }
} }
game.setActivePlanes(currentPlanes); game.setActivePlanes(currentPlanes);
} }
@@ -3080,7 +3091,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public final void resetAttackedThisCombat() { public final void resetAttackedThisCombat() {
// resets the status of attacked/blocked this phase // resets the status of attacked/blocked this phase
List<Card> list = CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.CREATURES); List<Card> list = CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.CREATURES);
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
final Card c = list.get(i); final Card c = list.get(i);
if (c.getDamageHistory().getCreatureAttackedThisCombat()) { if (c.getDamageHistory().getCreatureAttackedThisCombat()) {
@@ -3089,7 +3100,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (c.getDamageHistory().getCreatureBlockedThisCombat()) { if (c.getDamageHistory().getCreatureBlockedThisCombat()) {
c.getDamageHistory().setCreatureBlockedThisCombat(false); c.getDamageHistory().setCreatureBlockedThisCombat(false);
} }
if (c.getDamageHistory().getCreatureGotBlockedThisCombat()) { if (c.getDamageHistory().getCreatureGotBlockedThisCombat()) {
c.getDamageHistory().setCreatureGotBlockedThisCombat(false); c.getDamageHistory().setCreatureGotBlockedThisCombat(false);
} }
@@ -3120,41 +3131,41 @@ public class Player extends GameEntity implements Comparable<Player> {
miracleTrigger.setStackDescription(card.getName() + " - Miracle."); miracleTrigger.setStackDescription(card.getName() + " - Miracle.");
miracleTrigger.setActivatingPlayer(card.getOwner()); miracleTrigger.setActivatingPlayer(card.getOwner());
miracleTrigger.setTrigger(true); miracleTrigger.setTrigger(true);
game.getStack().add(miracleTrigger); game.getStack().add(miracleTrigger);
} }
public boolean isSkippingDraw() { public boolean isSkippingDraw() {
if (hasKeyword("Skip your next draw step.")) { if (hasKeyword("Skip your next draw step.")) {
removeKeyword("Skip your next draw step."); removeKeyword("Skip your next draw step.");
return true; return true;
} }
if (hasKeyword("Skip your draw step.")) { if (hasKeyword("Skip your draw step.")) {
return true; return true;
} }
return false; return false;
} }
public void addInboundToken(Card c) public void addInboundToken(Card c)
{ {
inboundTokens.add(c); inboundTokens.add(c);
} }
public void removeInboundToken(Card c) public void removeInboundToken(Card c)
{ {
inboundTokens.remove(c); inboundTokens.remove(c);
} }
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
*/ */
private final class MiracleTrigger extends Ability { private final class MiracleTrigger extends Ability {
private final SpellAbility miracle; private final SpellAbility miracle;
/** /**
* TODO: Write javadoc for Constructor. * TODO: Write javadoc for Constructor.
* @param sourceCard * @param sourceCard
@@ -3165,7 +3176,7 @@ public class Player extends GameEntity implements Comparable<Player> {
super(sourceCard, manaCost); super(sourceCard, manaCost);
this.miracle = miracle; this.miracle = miracle;
} }
@Override @Override
public void resolve() { public void resolve() {
miracle.setActivatingPlayer(getSourceCard().getOwner()); miracle.setActivatingPlayer(getSourceCard().getOwner());
@@ -3206,11 +3217,11 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
/** /**
* @param b isPlayingExtraTurn to set * @param b isPlayingExtraTurn to set
*/ */
public void setExtraTurn(boolean b) { public void setExtraTurn(boolean b) {
this.isPlayingExtraTrun = b; this.isPlayingExtraTrun = b;
} }
/** /**
@@ -3219,4 +3230,15 @@ public class Player extends GameEntity implements Comparable<Player> {
public boolean isPlayingExtraTurn() { public boolean isPlayingExtraTurn() {
return isPlayingExtraTrun; return isPlayingExtraTrun;
} }
private boolean isHotSeatGame(Game game0) {
boolean isHotSeat = false;
List<RegisteredPlayer> players = game0.getMatch().getPlayers();
if (players.size() == 2) {
boolean isPlayer1Human = players.get(0).getPlayer().getType() == PlayerType.HUMAN;
boolean isPlayer2Human = players.get(1).getPlayer().getType() == PlayerType.HUMAN;
isHotSeat = (isPlayer1Human && isPlayer2Human);
}
return isHotSeat;
}
} }

View File

@@ -32,6 +32,7 @@ import java.util.Map.Entry;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -53,8 +54,9 @@ import forge.game.player.HumanPlay;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.input.InputSelectCardsFromList; import forge.gui.input.InputSelectCardsFromList;
import forge.item.PaperCard;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.properties.ForgePreferences.FPref;
public final class GuiDisplayUtil { public final class GuiDisplayUtil {
private GuiDisplayUtil() { private GuiDisplayUtil() {
@@ -122,7 +124,7 @@ public final class GuiDisplayUtil {
else if (categoryName.equals("aicardsinlibrary")) aiCardTexts.put(ZoneType.Library, categoryValue); else if (categoryName.equals("aicardsinlibrary")) aiCardTexts.put(ZoneType.Library, categoryValue);
else if (categoryName.equals("humancardsinexile")) humanCardTexts.put(ZoneType.Exile, categoryValue); else if (categoryName.equals("humancardsinexile")) humanCardTexts.put(ZoneType.Exile, categoryValue);
else if (categoryName.equals("aicardsinexile")) aiCardTexts.put(ZoneType.Exile, categoryValue); else if (categoryName.equals("aicardsinexile")) aiCardTexts.put(ZoneType.Exile, categoryValue);
} }
in.close(); in.close();
@@ -138,7 +140,7 @@ public final class GuiDisplayUtil {
private static void setupGameState(final int humanLife, final int computerLife, final Map<ZoneType, String> humanCardTexts, private static void setupGameState(final int humanLife, final int computerLife, final Map<ZoneType, String> humanCardTexts,
final Map<ZoneType, String> aiCardTexts, final String tChangePlayer, final String tChangePhase) { final Map<ZoneType, String> aiCardTexts, final String tChangePlayer, final String tChangePhase) {
final Game game = getGame(); final Game game = getGame();
game.getAction().invoke(new Runnable() { game.getAction().invoke(new Runnable() {
@Override @Override
@@ -148,17 +150,17 @@ public final class GuiDisplayUtil {
Player newPlayerTurn = tChangePlayer.equals("human") ? newPlayerTurn = human : tChangePlayer.equals("ai") ? newPlayerTurn = ai : null; Player newPlayerTurn = tChangePlayer.equals("human") ? newPlayerTurn = human : tChangePlayer.equals("ai") ? newPlayerTurn = ai : null;
PhaseType newPhase = tChangePhase.trim().equalsIgnoreCase("none") ? null : PhaseType.smartValueOf(tChangePhase); PhaseType newPhase = tChangePhase.trim().equalsIgnoreCase("none") ? null : PhaseType.smartValueOf(tChangePhase);
game.getPhaseHandler().devModeSet(newPhase, newPlayerTurn); game.getPhaseHandler().devModeSet(newPhase, newPlayerTurn);
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
devSetupPlayerState(humanLife, humanCardTexts, human); devSetupPlayerState(humanLife, humanCardTexts, human);
devSetupPlayerState(computerLife, aiCardTexts, ai); devSetupPlayerState(computerLife, aiCardTexts, ai);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
game.getAction().checkStaticAbilities(); game.getAction().checkStaticAbilities();
} }
}); });
@@ -242,7 +244,7 @@ public final class GuiDisplayUtil {
final Card c = GuiChoose.oneOrNone("Choose a card", lib); final Card c = GuiChoose.oneOrNone("Choose a card", lib);
if (null == c) if (null == c)
return; return;
getGame().getAction().invoke(new Runnable() { @Override public void run() { getGame().getAction().moveToHand(c); }}); getGame().getAction().invoke(new Runnable() { @Override public void run() { getGame().getAction().moveToHand(c); }});
} }
@@ -311,8 +313,8 @@ public final class GuiDisplayUtil {
*/ */
public static void devModeUntapPerm() { public static void devModeUntapPerm() {
final Game game = getGame(); final Game game = getGame();
game.getAction().invoke(new Runnable() { game.getAction().invoke(new Runnable() {
@Override @Override
@@ -380,7 +382,7 @@ public final class GuiDisplayUtil {
return; return;
} }
getGame().getAction().invoke(new Runnable() { @Override public void run() { getGame().getAction().invoke(new Runnable() { @Override public void run() {
Card forgeCard = c.toForgeCard(p); Card forgeCard = c.toForgeCard(p);
getGame().getAction().moveToHand(forgeCard); getGame().getAction().moveToHand(forgeCard);
}}); }});
@@ -410,20 +412,20 @@ public final class GuiDisplayUtil {
if (c.getRules().getType().isLand()) { if (c.getRules().getType().isLand()) {
forgeCard.setOwner(p); forgeCard.setOwner(p);
game.getAction().moveToPlay(forgeCard); game.getAction().moveToPlay(forgeCard);
} else { } else {
final List<SpellAbility> choices = forgeCard.getBasicSpells(); final List<SpellAbility> choices = forgeCard.getBasicSpells();
if (choices.isEmpty()) { if (choices.isEmpty()) {
return; // when would it happen? return; // when would it happen?
} }
final SpellAbility sa = choices.size() == 1 ? choices.get(0) : GuiChoose.oneOrNone("Choose", choices); final SpellAbility sa = choices.size() == 1 ? choices.get(0) : GuiChoose.oneOrNone("Choose", choices);
if (sa == null) { if (sa == null) {
return; // happens if cancelled return; // happens if cancelled
} }
game.getAction().moveToHand(forgeCard); // this is really needed (for rollbacks at least) game.getAction().moveToHand(forgeCard); // this is really needed (for rollbacks at least)
// Human player is choosing targets for an ability controlled by chosen player. // Human player is choosing targets for an ability controlled by chosen player.
sa.setActivatingPlayer(p); sa.setActivatingPlayer(p);
HumanPlay.playSaWithoutPayingManaCost(game, sa, true); HumanPlay.playSaWithoutPayingManaCost(game, sa, true);
} }
@@ -440,26 +442,26 @@ public final class GuiDisplayUtil {
if (null == p) { if (null == p) {
return; return;
} }
PlanarDice res = GuiChoose.oneOrNone("Choose result", PlanarDice.values()); PlanarDice res = GuiChoose.oneOrNone("Choose result", PlanarDice.values());
if(res == null) if(res == null)
return; return;
System.out.println("Rigging planar dice roll: " + res.toString()); System.out.println("Rigging planar dice roll: " + res.toString());
//DBG //DBG
//System.out.println("ActivePlanes: " + getGame().getActivePlanes()); //System.out.println("ActivePlanes: " + getGame().getActivePlanes());
//System.out.println("CommandPlanes: " + getGame().getCardsIn(ZoneType.Command)); //System.out.println("CommandPlanes: " + getGame().getCardsIn(ZoneType.Command));
PlanarDice.roll(p, res); PlanarDice.roll(p, res);
getGame().getAction().invoke(new Runnable() { getGame().getAction().invoke(new Runnable() {
@Override @Override
public void run() { public void run() {
p.getGame().getStack().chooseOrderOfSimultaneousStackEntryAll(); p.getGame().getStack().chooseOrderOfSimultaneousStackEntryAll();
} }
}); });
} }
public static void devModePlaneswalkTo() { public static void devModePlaneswalkTo() {
@@ -496,5 +498,14 @@ public final class GuiDisplayUtil {
return Singletons.getControl().getObservedGame(); return Singletons.getControl().getObservedGame();
} }
public static String getPlayerName() {
return Singletons.getModel().getPreferences().getPref(FPref.PLAYER_NAME);
}
public static String personalizeHuman(String text) {
String playerName = Singletons.getModel().getPreferences().getPref(FPref.PLAYER_NAME);
return text.replaceAll("(?i)human", playerName);
}
} // end class GuiDisplayUtil } // end class GuiDisplayUtil

View File

@@ -3,12 +3,16 @@ package forge.gui.home.settings;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import forge.Command; import forge.Command;
@@ -21,15 +25,12 @@ import forge.game.ai.AiProfileUtil;
import forge.gui.framework.ICDoc; import forge.gui.framework.ICDoc;
import forge.gui.framework.SLayoutIO; import forge.gui.framework.SLayoutIO;
import forge.gui.toolbox.FComboBoxPanel; import forge.gui.toolbox.FComboBoxPanel;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin;
import forge.properties.ForgePreferences; import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
import java.util.ArrayList; /**
import java.util.Arrays;
import java.util.List;
/**
* Controls the preferences submenu in the home UI. * Controls the preferences submenu in the home UI.
* *
* <br><br><i>(C at beginning of class name denotes a control class.)</i> * <br><br><i>(C at beginning of class name denotes a control class.)</i>
@@ -38,10 +39,10 @@ import java.util.List;
public enum CSubmenuPreferences implements ICDoc { public enum CSubmenuPreferences implements ICDoc {
/** */ /** */
SINGLETON_INSTANCE; SINGLETON_INSTANCE;
private VSubmenuPreferences view; private VSubmenuPreferences view;
private ForgePreferences prefs; private ForgePreferences prefs;
private final List<Pair<JCheckBox, FPref>> lstControls = new ArrayList<Pair<JCheckBox,FPref>>(); private final List<Pair<JCheckBox, FPref>> lstControls = new ArrayList<Pair<JCheckBox,FPref>>();
/* (non-Javadoc) /* (non-Javadoc)
@@ -50,11 +51,11 @@ public enum CSubmenuPreferences implements ICDoc {
@SuppressWarnings("serial") @SuppressWarnings("serial")
@Override @Override
public void initialize() { public void initialize() {
this.view = VSubmenuPreferences.SINGLETON_INSTANCE; this.view = VSubmenuPreferences.SINGLETON_INSTANCE;
this.prefs = Singletons.getModel().getPreferences(); this.prefs = Singletons.getModel().getPreferences();
// This updates variable right now and is not standard // This updates variable right now and is not standard
view.getCbDevMode().addItemListener(new ItemListener() { view.getCbDevMode().addItemListener(new ItemListener() {
@Override @Override
public void itemStateChanged(final ItemEvent arg0) { public void itemStateChanged(final ItemEvent arg0) {
@@ -64,8 +65,8 @@ public enum CSubmenuPreferences implements ICDoc {
prefs.save(); prefs.save();
} }
}); });
lstControls.clear(); // just in case lstControls.clear(); // just in case
lstControls.add(Pair.of(view.getCbAnte(), FPref.UI_ANTE)); lstControls.add(Pair.of(view.getCbAnte(), FPref.UI_ANTE));
lstControls.add(Pair.of(view.getCbManaBurn(), FPref.UI_MANABURN)); lstControls.add(Pair.of(view.getCbManaBurn(), FPref.UI_MANABURN));
lstControls.add(Pair.of(view.getCbScaleLarger(), FPref.UI_SCALE_LARGER)); lstControls.add(Pair.of(view.getCbScaleLarger(), FPref.UI_SCALE_LARGER));
@@ -76,15 +77,15 @@ public enum CSubmenuPreferences implements ICDoc {
lstControls.add(Pair.of(view.getCbSingletons(), FPref.DECKGEN_SINGLETONS)); lstControls.add(Pair.of(view.getCbSingletons(), FPref.DECKGEN_SINGLETONS));
lstControls.add(Pair.of(view.getCbUploadDraft(), FPref.UI_UPLOAD_DRAFT)); lstControls.add(Pair.of(view.getCbUploadDraft(), FPref.UI_UPLOAD_DRAFT));
lstControls.add(Pair.of(view.getCbStackLand(), FPref.UI_SMOOTH_LAND)); lstControls.add(Pair.of(view.getCbStackLand(), FPref.UI_SMOOTH_LAND));
lstControls.add(Pair.of(view.getCbRandomFoil(), FPref.UI_RANDOM_FOIL)); lstControls.add(Pair.of(view.getCbRandomFoil(), FPref.UI_RANDOM_FOIL));
lstControls.add(Pair.of(view.getCbRandomizeArt(), FPref.UI_RANDOM_CARD_ART)); lstControls.add(Pair.of(view.getCbRandomizeArt(), FPref.UI_RANDOM_CARD_ART));
lstControls.add(Pair.of(view.getCbEnableSounds(), FPref.UI_ENABLE_SOUNDS)); lstControls.add(Pair.of(view.getCbEnableSounds(), FPref.UI_ENABLE_SOUNDS));
lstControls.add(Pair.of(view.getCbAltSoundSystem(), FPref.UI_ALT_SOUND_SYSTEM)); lstControls.add(Pair.of(view.getCbAltSoundSystem(), FPref.UI_ALT_SOUND_SYSTEM));
lstControls.add(Pair.of(view.getCbUiForTouchScreen(), FPref.UI_FOR_TOUCHSCREN)); lstControls.add(Pair.of(view.getCbUiForTouchScreen(), FPref.UI_FOR_TOUCHSCREN));
lstControls.add(Pair.of(view.getCbCompactMainMenu(), FPref.UI_COMPACT_MAIN_MENU)); lstControls.add(Pair.of(view.getCbCompactMainMenu(), FPref.UI_COMPACT_MAIN_MENU));
lstControls.add(Pair.of(view.getCbOverlayCardName(), FPref.UI_OVERLAY_CARD_NAME)); lstControls.add(Pair.of(view.getCbOverlayCardName(), FPref.UI_OVERLAY_CARD_NAME));
lstControls.add(Pair.of(view.getCbOverlayCardPower(), FPref.UI_OVERLAY_CARD_POWER)); lstControls.add(Pair.of(view.getCbOverlayCardPower(), FPref.UI_OVERLAY_CARD_POWER));
lstControls.add(Pair.of(view.getCbOverlayCardManaCost(), FPref.UI_OVERLAY_CARD_MANA_COST)); lstControls.add(Pair.of(view.getCbOverlayCardManaCost(), FPref.UI_OVERLAY_CARD_MANA_COST));
lstControls.add(Pair.of(view.getCbShowMatchBackgroundImage(), FPref.UI_MATCH_IMAGE_VISIBLE)); lstControls.add(Pair.of(view.getCbShowMatchBackgroundImage(), FPref.UI_MATCH_IMAGE_VISIBLE));
lstControls.add(Pair.of(view.getCbUseThemedComboBox(), FPref.UI_THEMED_COMBOBOX)); lstControls.add(Pair.of(view.getCbUseThemedComboBox(), FPref.UI_THEMED_COMBOBOX));
lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS)); lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS));
@@ -105,39 +106,41 @@ public enum CSubmenuPreferences implements ICDoc {
CSubmenuPreferences.this.resetForgeSettingsToDefault(); CSubmenuPreferences.this.resetForgeSettingsToDefault();
} }
}); });
view.getBtnDeleteEditorUI().setCommand(new Command() { view.getBtnDeleteEditorUI().setCommand(new Command() {
@Override @Override
public void run() { public void run() {
CSubmenuPreferences.this.resetDeckEditorLayout(); CSubmenuPreferences.this.resetDeckEditorLayout();
} }
}); });
view.getBtnDeleteMatchUI().setCommand(new Command() { view.getBtnDeleteMatchUI().setCommand(new Command() {
@Override @Override
public void run() { public void run() {
CSubmenuPreferences.this.resetMatchScreenLayout(); CSubmenuPreferences.this.resetMatchScreenLayout();
} }
}); });
initializeGameLogVerbosityComboBox(); initializeGameLogVerbosityComboBox();
initializeAiProfilesComboBox(); initializeAiProfilesComboBox();
initializeSkinsComboBox(); initializeSkinsComboBox();
initializePlayerNameButton();
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.control.home.IControlSubmenu#update() * @see forge.control.home.IControlSubmenu#update()
*/ */
@Override @Override
public void update() { public void update() {
this.view = VSubmenuPreferences.SINGLETON_INSTANCE; this.view = VSubmenuPreferences.SINGLETON_INSTANCE;
this.prefs = Singletons.getModel().getPreferences(); this.prefs = Singletons.getModel().getPreferences();
setPlayerNameButtonText();
view.getCbDevMode().setSelected(prefs.getPrefBoolean(FPref.DEV_MODE_ENABLED)); view.getCbDevMode().setSelected(prefs.getPrefBoolean(FPref.DEV_MODE_ENABLED));
for(Pair<JCheckBox, FPref> kv: lstControls) { for(Pair<JCheckBox, FPref> kv: lstControls) {
kv.getKey().setSelected(prefs.getPrefBoolean(kv.getValue())); kv.getKey().setSelected(prefs.getPrefBoolean(kv.getValue()));
} }
@@ -147,7 +150,7 @@ public enum CSubmenuPreferences implements ICDoc {
@Override public void run() { view.getCbRemoveSmall().requestFocusInWindow(); } @Override public void run() { view.getCbRemoveSmall().requestFocusInWindow(); }
}); });
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect() * @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/ */
@@ -155,50 +158,50 @@ public enum CSubmenuPreferences implements ICDoc {
public Command getCommandOnSelect() { public Command getCommandOnSelect() {
return null; return null;
} }
private void resetForgeSettingsToDefault() { private void resetForgeSettingsToDefault() {
String userPrompt = String userPrompt =
"This will reset all preferences to their defaults and restart Forge.\n\n" + "This will reset all preferences to their defaults and restart Forge.\n\n" +
"Reset and restart Forge?"; "Reset and restart Forge?";
int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Settings", JOptionPane.YES_NO_OPTION); int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Settings", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) { if (reply == JOptionPane.YES_OPTION) {
ForgePreferences prefs = Singletons.getModel().getPreferences(); ForgePreferences prefs = Singletons.getModel().getPreferences();
prefs.reset(); prefs.reset();
prefs.save(); prefs.save();
update(); update();
RestartUtil.restartApplication(null); RestartUtil.restartApplication(null);
} }
} }
private void resetDeckEditorLayout() { private void resetDeckEditorLayout() {
String userPrompt = String userPrompt =
"This will reset the Deck Editor screen layout.\n" + "This will reset the Deck Editor screen layout.\n" +
"All tabbed views will be restored to their default positions.\n\n" + "All tabbed views will be restored to their default positions.\n\n" +
"Reset layout?"; "Reset layout?";
int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Deck Editor Layout", JOptionPane.YES_NO_OPTION); int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Deck Editor Layout", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) { if (reply == JOptionPane.YES_OPTION) {
deleteScreenLayoutFile(Screens.DECK_EDITOR_CONSTRUCTED); deleteScreenLayoutFile(Screens.DECK_EDITOR_CONSTRUCTED);
JOptionPane.showMessageDialog(null, "Deck Editor layout has been reset."); JOptionPane.showMessageDialog(null, "Deck Editor layout has been reset.");
} }
} }
private void resetMatchScreenLayout() { private void resetMatchScreenLayout() {
String userPrompt = String userPrompt =
"This will reset the layout of the Match screen.\n" + "This will reset the layout of the Match screen.\n" +
"If you want to save the current layout first, please use " + "If you want to save the current layout first, please use " +
"the Dock tab -> Save Layout option in the Match screen.\n\n" + "the Dock tab -> Save Layout option in the Match screen.\n\n" +
"Reset layout?"; "Reset layout?";
int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Match Screen Layout", JOptionPane.YES_NO_OPTION); int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Match Screen Layout", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) { if (reply == JOptionPane.YES_OPTION) {
deleteScreenLayoutFile(Screens.MATCH_SCREEN); deleteScreenLayoutFile(Screens.MATCH_SCREEN);
JOptionPane.showMessageDialog(null, "Match Screen layout has been reset."); JOptionPane.showMessageDialog(null, "Match Screen layout has been reset.");
} }
} }
private void deleteScreenLayoutFile(Screens screen) { private void deleteScreenLayoutFile(Screens screen) {
String fd = SLayoutIO.getFilePreferred(screen); String fd = SLayoutIO.getFilePreferred(screen);
File f = new File(fd); File f = new File(fd);
f.delete(); f.delete();
} }
private void initializeGameLogVerbosityComboBox() { private void initializeGameLogVerbosityComboBox() {
@@ -207,16 +210,16 @@ public enum CSubmenuPreferences implements ICDoc {
JComboBox<GameLogEntryType> comboBox = createComboBox(GameLogEntryType.values(), userSetting); JComboBox<GameLogEntryType> comboBox = createComboBox(GameLogEntryType.values(), userSetting);
GameLogEntryType selectedItem = GameLogEntryType.valueOf(this.prefs.getPref(userSetting)); GameLogEntryType selectedItem = GameLogEntryType.valueOf(this.prefs.getPref(userSetting));
panel.setComboBox(comboBox, selectedItem); panel.setComboBox(comboBox, selectedItem);
} }
private void initializeAiProfilesComboBox() { private void initializeAiProfilesComboBox() {
FPref userSetting = FPref.UI_CURRENT_AI_PROFILE; FPref userSetting = FPref.UI_CURRENT_AI_PROFILE;
FComboBoxPanel<String> panel = this.view.getAiProfilesComboBoxPanel(); FComboBoxPanel<String> panel = this.view.getAiProfilesComboBoxPanel();
JComboBox<String> comboBox = createComboBox(AiProfileUtil.getProfilesArray(), userSetting); JComboBox<String> comboBox = createComboBox(AiProfileUtil.getProfilesArray(), userSetting);
String selectedItem = this.prefs.getPref(userSetting); String selectedItem = this.prefs.getPref(userSetting);
panel.setComboBox(comboBox, selectedItem); panel.setComboBox(comboBox, selectedItem);
} }
private void initializeSkinsComboBox() { private void initializeSkinsComboBox() {
final FComboBoxPanel<String> panel = this.view.getSkinsComboBoxPanel(); final FComboBoxPanel<String> panel = this.view.getSkinsComboBoxPanel();
String[] installedSkins = FSkin.getSkinNamesArray(true); String[] installedSkins = FSkin.getSkinNamesArray(true);
@@ -242,13 +245,13 @@ public enum CSubmenuPreferences implements ICDoc {
this.prefs.setPref(FPref.UI_SKIN, "Default"); this.prefs.setPref(FPref.UI_SKIN, "Default");
} }
} }
private <E> JComboBox<E> createComboBox(E[] items, final ForgePreferences.FPref setting) { private <E> JComboBox<E> createComboBox(E[] items, final ForgePreferences.FPref setting) {
final JComboBox<E> comboBox = new JComboBox<E>(items); final JComboBox<E> comboBox = new JComboBox<E>(items);
addComboBoxListener(comboBox, setting); addComboBoxListener(comboBox, setting);
return comboBox; return comboBox;
} }
private <E> void addComboBoxListener(final JComboBox<E> comboBox, final ForgePreferences.FPref setting) { private <E> void addComboBoxListener(final JComboBox<E> comboBox, final ForgePreferences.FPref setting) {
comboBox.addItemListener(new ItemListener() { comboBox.addItemListener(new ItemListener() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -260,4 +263,29 @@ public enum CSubmenuPreferences implements ICDoc {
} }
}); });
} }
private void initializePlayerNameButton() {
FLabel btn = view.getBtnPlayerName();
setPlayerNameButtonText();
btn.setCommand(getPlayerNameButtonCommand());
}
private void setPlayerNameButtonText() {
FLabel btn = view.getBtnPlayerName();
String name = prefs.getPref(FPref.PLAYER_NAME);
btn.setText(StringUtils.isBlank(name) ? "Human" : name);
}
@SuppressWarnings("serial")
private Command getPlayerNameButtonCommand() {
return new Command() {
@Override
public void run() {
GamePlayerUtil.setPlayerName();
setPlayerNameButtonText();
}
};
}
} }

View File

@@ -0,0 +1,70 @@
package forge.gui.home.settings;
import javax.swing.JOptionPane;
import org.apache.commons.lang.StringUtils;
import forge.Singletons;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
public final class GamePlayerUtil {
private GamePlayerUtil() { };
private final static ForgePreferences prefs = Singletons.getModel().getPreferences();
public static void setPlayerName() {
String playerName = prefs.getPref(FPref.PLAYER_NAME);
String newName = null;
if (StringUtils.isBlank(playerName)) {
newName = (String)JOptionPane.showInputDialog(
Singletons.getView().getFrame(),
"By default, Forge will refer to you as the \"Human\" during gameplay.\n" +
"If you would prefer a different name please enter it now.\n",
"Personalize Forge Gameplay",
JOptionPane.QUESTION_MESSAGE,
null, null, null);
} else {
newName = getNewPlayerNameFromInputDialog(playerName);
}
if (newName == null || !StringUtils.isAlphanumericSpace(newName)) {
newName = (StringUtils.isBlank(playerName) ? "Human" : playerName);
} else if (StringUtils.isWhitespace(newName)) {
newName = "Human";
} else {
newName = newName.trim();
}
prefs.setPref(FPref.PLAYER_NAME, newName);
prefs.save();
if (StringUtils.isBlank(playerName) && newName != "Human") {
JOptionPane.showMessageDialog(
Singletons.getView().getFrame(),
"Thank you, " + newName + ". " +
"You will not be prompted again but you can change\nyour name at any time using the \"Player Name\" setting in Preferences.\n\n");
}
}
private static String getNewPlayerNameFromInputDialog(String playerName) {
String newName =
(String)JOptionPane.showInputDialog(
Singletons.getView().getFrame(),
"Please enter a new name (alpha-numeric only)\n",
"Personalize Forge Gameplay",
JOptionPane.PLAIN_MESSAGE,
null, null, playerName);
if (newName == null || !StringUtils.isAlphanumericSpace(newName)) {
return playerName;
} else if (StringUtils.isWhitespace(newName)) {
return "Human";
} else {
return newName.trim();
}
}
}

View File

@@ -1,6 +1,7 @@
package forge.gui.home.settings; package forge.gui.home.settings;
import java.awt.Color; import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusAdapter; import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
@@ -17,6 +18,7 @@ import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants; import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -38,7 +40,7 @@ import forge.gui.toolbox.FScrollPane;
import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
/** /**
* Assembles Swing components of preferences submenu singleton. * Assembles Swing components of preferences submenu singleton.
* *
* <br><br><i>(V at beginning of class name denotes a view class.)</i> * <br><br><i>(V at beginning of class name denotes a view class.)</i>
@@ -59,7 +61,8 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FLabel btnReset = new FLabel.Builder().opaque(true).hoverable(true).text("Reset to Default Settings").build(); private final FLabel btnReset = new FLabel.Builder().opaque(true).hoverable(true).text("Reset to Default Settings").build();
private final FLabel btnDeleteMatchUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Match Layout").build(); private final FLabel btnDeleteMatchUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Match Layout").build();
private final FLabel btnDeleteEditorUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Editor Layout").build(); private final FLabel btnDeleteEditorUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Editor Layout").build();
private final FLabel btnPlayerName = new FLabel.Builder().opaque(true).hoverable(true).text("").build();
private final JCheckBox cbRemoveSmall = new OptionsCheckBox("Remove Small Creatures"); private final JCheckBox cbRemoveSmall = new OptionsCheckBox("Remove Small Creatures");
private final JCheckBox cbSingletons = new OptionsCheckBox("Singleton Mode"); private final JCheckBox cbSingletons = new OptionsCheckBox("Singleton Mode");
private final JCheckBox cbRemoveArtifacts = new OptionsCheckBox("Remove Artifacts"); private final JCheckBox cbRemoveArtifacts = new OptionsCheckBox("Remove Artifacts");
@@ -87,47 +90,50 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final Map<FPref, KeyboardShortcutField> shortcutFields = new HashMap<FPref, KeyboardShortcutField>(); private final Map<FPref, KeyboardShortcutField> shortcutFields = new HashMap<FPref, KeyboardShortcutField>();
// ComboBox items are added in CSubmenuPreferences since this is just the View. // ComboBox items are added in CSubmenuPreferences since this is just the View.
private final FComboBoxPanel<String> cbpSkin = new FComboBoxPanel<String>("Choose Skin:"); private final FComboBoxPanel<String> cbpSkin = new FComboBoxPanel<String>("Choose Skin:");
private final FComboBoxPanel<GameLogEntryType> cbpGameLogEntryType = new FComboBoxPanel<GameLogEntryType>("Game Log Verbosity:"); private final FComboBoxPanel<GameLogEntryType> cbpGameLogEntryType = new FComboBoxPanel<GameLogEntryType>("Game Log Verbosity:");
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<String>("AI Personality:"); private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<String>("AI Personality:");
/** /**
* Constructor. * Constructor.
*/ */
private VSubmenuPreferences() { private VSubmenuPreferences() {
pnlPrefs.setOpaque(false); pnlPrefs.setOpaque(false);
pnlPrefs.setLayout(new MigLayout("insets 0, gap 0, wrap 2")); pnlPrefs.setLayout(new MigLayout("insets 0, gap 0, wrap 2"));
// Spacing between components is defined here. // Spacing between components is defined here.
final String sectionConstraints = "w 80%!, h 42px!, gap 10% 0 10px 10px, span 2 1"; final String sectionConstraints = "w 80%!, h 42px!, gap 10% 0 10px 10px, span 2 1";
final String regularConstraints = "w 80%!, h 22px!, gap 10% 0 0 10px, span 2 1"; final String regularConstraints = "w 80%!, h 22px!, gap 10% 0 0 10px, span 2 1";
// Troubleshooting // Troubleshooting
pnlPrefs.add(new SectionLabel("Troubleshooting"), sectionConstraints); pnlPrefs.add(new SectionLabel("Troubleshooting"), sectionConstraints);
//pnlPrefs.add(new SectionLabel(" "), sectionConstraints); //pnlPrefs.add(new SectionLabel(" "), sectionConstraints);
pnlPrefs.add(btnReset, regularConstraints + ", h 30px!"); pnlPrefs.add(btnReset, regularConstraints + ", h 30px!");
final String twoButtonConstraints = "w 38%!, h 30px!, gap 10% 0 0 10px"; final String twoButtonConstraints = "w 38%!, h 30px!, gap 10% 0 0 10px";
pnlPrefs.add(btnDeleteMatchUI, twoButtonConstraints); pnlPrefs.add(btnDeleteMatchUI, twoButtonConstraints);
pnlPrefs.add(btnDeleteEditorUI, "w 38%!, h 30px!, gap 0 0 0 10px"); pnlPrefs.add(btnDeleteEditorUI, "w 38%!, h 30px!, gap 0 0 0 10px");
// Reset button // Reset button
// General Configuration // General Configuration
pnlPrefs.add(new SectionLabel("General Configuration"), sectionConstraints + ", gaptop 2%"); pnlPrefs.add(new SectionLabel("General Configuration"), sectionConstraints + ", gaptop 2%");
pnlPrefs.add(getPlayerNamePanel(), regularConstraints + ", h 26px!");
pnlPrefs.add(new NoteLabel("Sets the name that you will be referred to by Forge during gameplay."), regularConstraints);
pnlPrefs.add(cbCompactMainMenu, regularConstraints); pnlPrefs.add(cbCompactMainMenu, regularConstraints);
pnlPrefs.add(new NoteLabel("Enable for a space efficient sidebar that displays only one menu group at a time (RESTART REQUIRED)."), regularConstraints); pnlPrefs.add(new NoteLabel("Enable for a space efficient sidebar that displays only one menu group at a time (RESTART REQUIRED)."), regularConstraints);
// Gameplay Options // Gameplay Options
pnlPrefs.add(new SectionLabel("Gameplay"), sectionConstraints + ", gaptop 2%"); pnlPrefs.add(new SectionLabel("Gameplay"), sectionConstraints + ", gaptop 2%");
pnlPrefs.add(cbpAiProfiles, "w 80%!, gap 10% 0 0 10px, span 2 1"); pnlPrefs.add(cbpAiProfiles, "w 80%!, gap 10% 0 0 10px, span 2 1");
pnlPrefs.add(new NoteLabel("Choose your AI opponent."), regularConstraints); pnlPrefs.add(new NoteLabel("Choose your AI opponent."), regularConstraints);
pnlPrefs.add(cbAnte, regularConstraints); pnlPrefs.add(cbAnte, regularConstraints);
pnlPrefs.add(new NoteLabel("Determines whether or not the game is played for ante."), regularConstraints); pnlPrefs.add(new NoteLabel("Determines whether or not the game is played for ante."), regularConstraints);
@@ -161,7 +167,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbRemoveArtifacts, regularConstraints); pnlPrefs.add(cbRemoveArtifacts, regularConstraints);
pnlPrefs.add(new NoteLabel("Disables artifact cards in generated decks."), regularConstraints); pnlPrefs.add(new NoteLabel("Disables artifact cards in generated decks."), regularConstraints);
// Advanced // Advanced
pnlPrefs.add(new SectionLabel("Advanced Settings"), sectionConstraints); pnlPrefs.add(new SectionLabel("Advanced Settings"), sectionConstraints);
@@ -174,10 +180,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbUseThemedComboBox, regularConstraints); pnlPrefs.add(cbUseThemedComboBox, regularConstraints);
pnlPrefs.add(new NoteLabel("Turn off if you are having combo-box color clash (RESTART REQUIRED)."), regularConstraints); pnlPrefs.add(new NoteLabel("Turn off if you are having combo-box color clash (RESTART REQUIRED)."), regularConstraints);
// Themes // Themes
pnlPrefs.add(new SectionLabel("Visual Themes"), sectionConstraints + ", gaptop 2%"); pnlPrefs.add(new SectionLabel("Visual Themes"), sectionConstraints + ", gaptop 2%");
pnlPrefs.add(cbpSkin, "w 80%!, gap 10% 0 0 10px, span 2 1"); pnlPrefs.add(cbpSkin, "w 80%!, gap 10% 0 0 10px, span 2 1");
pnlPrefs.add(new NoteLabel("Change the overall look and feel of Forge (RESTART REQUIRED)."), regularConstraints); pnlPrefs.add(new NoteLabel("Change the overall look and feel of Forge (RESTART REQUIRED)."), regularConstraints);
@@ -207,7 +213,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbOverlayCardPower, regularConstraints); pnlPrefs.add(cbOverlayCardPower, regularConstraints);
pnlPrefs.add(cbOverlayCardManaCost, regularConstraints); pnlPrefs.add(cbOverlayCardManaCost, regularConstraints);
// Sound options // Sound options
pnlPrefs.add(new SectionLabel("Sound Options"), sectionConstraints + ", gaptop 2%"); pnlPrefs.add(new SectionLabel("Sound Options"), sectionConstraints + ", gaptop 2%");
@@ -216,8 +222,8 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbAltSoundSystem, regularConstraints); pnlPrefs.add(cbAltSoundSystem, regularConstraints);
pnlPrefs.add(new NoteLabel("Use the alternate sound system (only use in case your have issues with sound not playing or disappearing)"), regularConstraints); pnlPrefs.add(new NoteLabel("Use the alternate sound system (only use in case your have issues with sound not playing or disappearing)"), regularConstraints);
// Keyboard shortcuts // Keyboard shortcuts
final JLabel lblShortcuts = new SectionLabel("Keyboard Shortcuts"); final JLabel lblShortcuts = new SectionLabel("Keyboard Shortcuts");
pnlPrefs.add(lblShortcuts, sectionConstraints + ", gaptop 2%"); pnlPrefs.add(lblShortcuts, sectionConstraints + ", gaptop 2%");
@@ -234,7 +240,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
scrContent.setBorder(null); scrContent.setBorder(null);
} }
public void reloadShortcuts() { public void reloadShortcuts() {
for (Map.Entry<FPref, KeyboardShortcutField> e : shortcutFields.entrySet()) { for (Map.Entry<FPref, KeyboardShortcutField> e : shortcutFields.entrySet()) {
e.getValue().reload(e.getKey()); e.getValue().reload(e.getKey());
@@ -396,11 +402,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
this.setText(StringUtils.join(displayText, ' ')); this.setText(StringUtils.join(displayText, ' '));
} }
} }
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public final JCheckBox getCbCompactMainMenu() { public final JCheckBox getCbCompactMainMenu() {
return cbCompactMainMenu; return cbCompactMainMenu;
} }
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public final JCheckBox getCbRemoveSmall() { public final JCheckBox getCbRemoveSmall() {
@@ -441,7 +447,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public JCheckBox getCbOverlayCardManaCost() { public JCheckBox getCbOverlayCardManaCost() {
return cbOverlayCardManaCost; return cbOverlayCardManaCost;
} }
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbRandomFoil() { public JCheckBox getCbRandomFoil() {
return cbRandomFoil; return cbRandomFoil;
@@ -471,7 +477,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public JCheckBox getCbDevMode() { public JCheckBox getCbDevMode() {
return cbDevMode; return cbDevMode;
} }
public FComboBoxPanel<String> getAiProfilesComboBoxPanel() { public FComboBoxPanel<String> getAiProfilesComboBoxPanel() {
return cbpAiProfiles; return cbpAiProfiles;
} }
@@ -479,11 +485,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() { public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() {
return cbpGameLogEntryType; return cbpGameLogEntryType;
} }
public FComboBoxPanel<String> getSkinsComboBoxPanel() { public FComboBoxPanel<String> getSkinsComboBoxPanel() {
return cbpSkin; return cbpSkin;
} }
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbEnforceDeckLegality() { public JCheckBox getCbEnforceDeckLegality() {
return cbEnforceDeckLegality; return cbEnforceDeckLegality;
@@ -506,7 +512,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbAltSoundSystem() { public JCheckBox getCbAltSoundSystem() {
return cbAltSoundSystem; return cbAltSoundSystem;
} }
public final JCheckBox getCbUiForTouchScreen() { public final JCheckBox getCbUiForTouchScreen() {
@@ -517,17 +523,21 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public FLabel getBtnReset() { public FLabel getBtnReset() {
return btnReset; return btnReset;
} }
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbShowMatchBackgroundImage() { public JCheckBox getCbShowMatchBackgroundImage() {
return cbShowMatchBackgroundImage; return cbShowMatchBackgroundImage;
} }
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbUseThemedComboBox() { public JCheckBox getCbUseThemedComboBox() {
return cbUseThemedComboBox; return cbUseThemedComboBox;
} }
public FLabel getBtnPlayerName() {
return btnPlayerName;
}
//========== Overridden from IVDoc //========== Overridden from IVDoc
public final FLabel getBtnDeleteMatchUI() { public final FLabel getBtnDeleteMatchUI() {
@@ -577,4 +587,13 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public DragCell getParentCell() { public DragCell getParentCell() {
return parentCell; return parentCell;
} }
private JPanel getPlayerNamePanel() {
JPanel p = new JPanel(new MigLayout("insets 0, gap 0!"));
p.setOpaque(false);
FLabel lbl = new FLabel.Builder().text("Player Name: ").fontSize(12).fontStyle(Font.BOLD).build();
p.add(lbl, "aligny top, h 100%");
p.add(btnPlayerName, "aligny top, h 100%, w 200px!");
return p;
}
} }

View File

@@ -134,7 +134,7 @@ public class QuestWinLose extends ControlWinLose {
// Ante returns to owners in a draw // Ante returns to owners in a draw
if (!outcome.isDraw()) { if (!outcome.isDraw()) {
boolean isHumanWinner = outcome.getWinner().equals(questPlayer); boolean isHumanWinner = outcome.getWinningLobbyPlayer().equals(questPlayer);
final List<PaperCard> anteCards = new ArrayList<PaperCard>(); final List<PaperCard> anteCards = new ArrayList<PaperCard>();
for (Player p : lastGame.getRegisteredPlayers()) { for (Player p : lastGame.getRegisteredPlayers()) {
if (p.getLobbyPlayer().equals(questPlayer) == isHumanWinner) { if (p.getLobbyPlayer().equals(questPlayer) == isHumanWinner) {

View File

@@ -1,228 +1,238 @@
package forge.gui.match; package forge.gui.match;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
import java.awt.Point; import java.awt.Point;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JLabel;
import javax.swing.JScrollPane; import javax.swing.JPanel;
import javax.swing.SwingConstants; import javax.swing.JScrollPane;
import javax.swing.SwingUtilities; import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import org.apache.commons.lang3.tuple.Pair;
import net.miginfocom.swing.MigLayout;
import net.miginfocom.swing.MigLayout; import forge.Command;
import forge.Command; import forge.GameLog;
import forge.GameLog; import forge.GameLogEntry;
import forge.GameLogEntry; import forge.GameLogEntryType;
import forge.GameLogEntryType; import forge.Singletons;
import forge.Singletons; import forge.game.Game;
import forge.game.Game; import forge.game.GameOutcome;
import forge.game.GameOutcome; import forge.game.player.Player;
import forge.game.player.LobbyPlayer; import forge.gui.toolbox.FButton;
import forge.game.player.PlayerStatistics; import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FButton; import forge.gui.toolbox.FOverlay;
import forge.gui.toolbox.FLabel; import forge.gui.toolbox.FScrollPane;
import forge.gui.toolbox.FOverlay; import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.FScrollPane; import forge.gui.toolbox.FTextArea;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.FTextArea; /**
import forge.net.FServer; * TODO: Write javadoc for this type.
*
/** */
* TODO: Write javadoc for this type. public class ViewWinLose {
* private final FButton btnContinue, btnRestart, btnQuit;
*/ private final JPanel pnlCustom;
public class ViewWinLose {
private final FButton btnContinue, btnRestart, btnQuit; private final JLabel lblTitle = new JLabel("WinLoseFrame > lblTitle needs updating.");
private final JPanel pnlCustom; private final JLabel lblStats = new JLabel("WinLoseFrame > lblStats needs updating.");
private final JPanel pnlOutcomes = new JPanel(new MigLayout("wrap, align center"));
private final JLabel lblTitle = new JLabel("WinLoseFrame > lblTitle needs updating.");
private final JLabel lblStats = new JLabel("WinLoseFrame > lblStats needs updating."); private final Game game;
private final JPanel pnlOutcomes = new JPanel(new MigLayout("wrap, align center"));
@SuppressWarnings("serial")
@SuppressWarnings("serial") public ViewWinLose(final Game game0) {
public ViewWinLose(final Game game) {
final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel(); game = game0;
final JPanel pnlLeft = new JPanel(); final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
final JPanel pnlRight = new JPanel();
final JScrollPane scrCustom = new JScrollPane(); final JPanel pnlLeft = new JPanel();
pnlCustom = new JPanel(); final JPanel pnlRight = new JPanel();
final JScrollPane scrCustom = new JScrollPane();
btnContinue = new FButton(); pnlCustom = new JPanel();
btnRestart = new FButton();
btnQuit = new FButton(); btnContinue = new FButton();
btnRestart = new FButton();
// Control of the win/lose is handled differently for various game modes. btnQuit = new FButton();
ControlWinLose control = null;
switch (game.getType()) { // Control of the win/lose is handled differently for various game
case Quest: // modes.
control = new QuestWinLose(this, game); ControlWinLose control = null;
break; switch (game0.getType()) {
case Draft: case Quest:
if (!Singletons.getModel().getGauntletMini().isGauntletDraft()) { control = new QuestWinLose(this, game0);
break; break;
} case Draft:
case Sealed: if (!Singletons.getModel().getGauntletMini().isGauntletDraft()) {
control = new LimitedWinLose(this, game); break;
break; }
case Gauntlet: case Sealed:
control = new GauntletWinLose(this, game); control = new LimitedWinLose(this, game0);
break; break;
default: // will catch it after switch case Gauntlet:
break; control = new GauntletWinLose(this, game0);
} break;
if (null == control) { default: // will catch it after switch
control = new ControlWinLose(this, game); break;
} }
if (null == control) {
control = new ControlWinLose(this, game0);
pnlLeft.setOpaque(false); }
pnlRight.setOpaque(false);
pnlCustom.setOpaque(false); pnlLeft.setOpaque(false);
scrCustom.setOpaque(false); pnlRight.setOpaque(false);
scrCustom.setBorder(null); pnlCustom.setOpaque(false);
scrCustom.getVerticalScrollBar().setUnitIncrement(16); scrCustom.setOpaque(false);
scrCustom.getViewport().setOpaque(false); scrCustom.setBorder(null);
scrCustom.getViewport().add(pnlCustom); scrCustom.getVerticalScrollBar().setUnitIncrement(16);
scrCustom.getViewport().setOpaque(false);
lblTitle.setForeground(Color.white); scrCustom.getViewport().add(pnlCustom);
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
FSkin.get(lblTitle).setFont(FSkin.getBoldFont(30)); lblTitle.setForeground(Color.white);
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
lblStats.setForeground(Color.white); FSkin.get(lblTitle).setFont(FSkin.getBoldFont(30));
lblStats.setHorizontalAlignment(SwingConstants.CENTER);
FSkin.get(lblStats).setFont(FSkin.getFont(26)); lblStats.setForeground(Color.white);
lblStats.setHorizontalAlignment(SwingConstants.CENTER);
btnContinue.setText("Continue"); FSkin.get(lblStats).setFont(FSkin.getFont(26));
FSkin.get(btnContinue).setFont(FSkin.getFont(22));
btnRestart.setText("Restart"); btnContinue.setText("Next Game");
FSkin.get(btnRestart).setFont(FSkin.getFont(22)); FSkin.get(btnContinue).setFont(FSkin.getFont(22));
btnQuit.setText("Quit"); btnRestart.setText("Start New Match");
FSkin.get(btnQuit).setFont(FSkin.getFont(22)); FSkin.get(btnRestart).setFont(FSkin.getFont(22));
btnContinue.setEnabled(!game.getMatch().isMatchOver()); btnQuit.setText("Quit Match");
FSkin.get(btnQuit).setFont(FSkin.getFont(22));
// Assemble game log scroller. btnContinue.setEnabled(!game0.getMatch().isMatchOver());
final FTextArea txtLog = new FTextArea();
txtLog.setText(game.getGameLog().getLogText(null)); // Assemble game log scroller.
FSkin.get(txtLog).setFont(FSkin.getFont(14)); final FTextArea txtLog = new FTextArea();
txtLog.setFocusable(true); // allow highlighting and copying of log txtLog.setText(game.getGameLog().getLogText(null).replace("[COMPUTER]", "[AI]"));
FSkin.get(txtLog).setFont(FSkin.getFont(14));
FLabel btnCopyLog = new FLabel.ButtonBuilder().text("Copy to clipboard").build(); txtLog.setFocusable(true); // allow highlighting and copying of log
btnCopyLog.setCommand(new Command() {
@Override FLabel btnCopyLog = new FLabel.ButtonBuilder().text("Copy to clipboard").build();
public void run() { btnCopyLog.setCommand(new Command() {
StringSelection ss = new StringSelection(txtLog.getText()); @Override
try { public void run() {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null); StringSelection ss = new StringSelection(txtLog.getText());
} catch (IllegalStateException ex) { try {
// ignore; may be unavailable on some platforms Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);
} } catch (IllegalStateException ex) {
} // ignore; may be unavailable on some platforms
}); }
}
// Add all components accordingly. });
overlay.setLayout(new MigLayout("insets 0, w 100%!, h 100%!"));
pnlLeft.setLayout(new MigLayout("insets 0, wrap, align center")); // Add all components accordingly.
pnlRight.setLayout(new MigLayout("insets 0, wrap")); overlay.setLayout(new MigLayout("insets 0, w 100%!, h 100%!"));
pnlCustom.setLayout(new MigLayout("insets 0, wrap, align center")); pnlLeft.setLayout(new MigLayout("insets 0, wrap, align center"));
pnlRight.setLayout(new MigLayout("insets 0, wrap"));
final boolean customIsPopulated = control.populateCustomPanel(); pnlCustom.setLayout(new MigLayout("insets 0, wrap, align center"));
if (customIsPopulated) {
overlay.add(pnlLeft, "w 40%!, h 100%!"); final boolean customIsPopulated = control.populateCustomPanel();
overlay.add(pnlRight, "w 60%!, h 100%!"); if (customIsPopulated) {
pnlRight.add(scrCustom, "w 100%!, h 100%!"); overlay.add(pnlLeft, "w 40%!, h 100%!");
} overlay.add(pnlRight, "w 60%!, h 100%!");
else { pnlRight.add(scrCustom, "w 100%!, h 100%!");
overlay.add(pnlLeft, "w 100%!, h 100%!"); } else {
} overlay.add(pnlLeft, "w 100%!, h 100%!");
}
pnlOutcomes.setOpaque(false);
pnlLeft.add(lblTitle, "h 60px!, center"); pnlOutcomes.setOpaque(false);
pnlLeft.add(pnlOutcomes, "center"); pnlLeft.add(lblTitle, "h 60px!, center");
pnlLeft.add(lblStats, "h 60px!, center"); pnlLeft.add(pnlOutcomes, "center");
pnlLeft.add(lblStats, "h 60px!, center");
// A container must be made to ensure proper centering.
final JPanel pnlButtons = new JPanel(new MigLayout("insets 0, wrap, ax center")); // A container must be made to ensure proper centering.
pnlButtons.setOpaque(false); final JPanel pnlButtons = new JPanel(new MigLayout("insets 0, wrap, ax center"));
pnlButtons.setOpaque(false);
final String constraints = "w 300px!, h 50px!, gap 0 0 20px 0";
pnlButtons.add(btnContinue, constraints); final String constraints = "w 300px!, h 50px!, gap 0 0 20px 0";
pnlButtons.add(btnRestart, constraints); pnlButtons.add(btnContinue, constraints);
pnlButtons.add(btnQuit, constraints); pnlButtons.add(btnRestart, constraints);
pnlLeft.add(pnlButtons, "w 100%!"); pnlButtons.add(btnQuit, constraints);
pnlLeft.add(pnlButtons, "w 100%!");
final JPanel pnlLog = new JPanel(new MigLayout("insets 0, wrap, ax center"));
final FScrollPane scrLog = new FScrollPane(txtLog); final JPanel pnlLog = new JPanel(new MigLayout("insets 0, wrap, ax center"));
scrLog.setBorder(null); final FScrollPane scrLog = new FScrollPane(txtLog);
pnlLog.setOpaque(false); scrLog.setBorder(null);
pnlLog.setOpaque(false);
pnlLog.add(new FLabel.Builder().text("Game Log").fontAlign(SwingConstants.CENTER)
.fontSize(18).fontStyle(Font.BOLD).build(), pnlLog.add(
"w 300px!, h 28px!, gaptop 20px"); new FLabel.Builder().text("Game Log").fontAlign(SwingConstants.CENTER).fontSize(18)
.fontStyle(Font.BOLD).build(), "w 300px!, h 28px!, gaptop 20px");
pnlLog.add(scrLog, "w 300px!, h 100px!, gap 0 0 10 10");
pnlLog.add(btnCopyLog, "center, w pref+16, h pref+8"); pnlLog.add(scrLog, "w 300px!, h 100px!, gap 0 0 10 10");
pnlLeft.add(pnlLog, "w 100%!"); pnlLog.add(btnCopyLog, "center, w pref+16, h pref+8");
pnlLeft.add(pnlLog, "w 100%!");
SwingUtilities.invokeLater(new Runnable() {
@Override SwingUtilities.invokeLater(new Runnable() {
public void run() { @Override
scrLog.getViewport().setViewPosition(new Point(0, 0)); public void run() {
// populateCustomPanel may have changed which buttons are enabled; focus on the 'best' one scrLog.getViewport().setViewPosition(new Point(0, 0));
if (btnContinue.isEnabled()) { // populateCustomPanel may have changed which buttons are
btnContinue.requestFocusInWindow(); // enabled; focus on the 'best' one
} else { if (btnContinue.isEnabled()) {
btnQuit.requestFocusInWindow(); btnContinue.requestFocusInWindow();
} } else {
} btnQuit.requestFocusInWindow();
}); }
}
lblTitle.setText(composeTitle(game.getOutcome())); });
GameLog log = game.getGameLog(); lblTitle.setText(composeTitle(game0.getOutcome()));
for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.GAME_OUTCOME)) showGameOutcomeSummary();
pnlOutcomes.add(new FLabel.Builder().text(o.message).fontSize(14).build(), "h 20!"); showPlayerScores();
for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.MATCH_RESULTS)) }
lblStats.setText(o.message);
} private String composeTitle(GameOutcome outcome) {
Player winner = outcome.getWinningPlayer();
private String composeTitle(GameOutcome outcome) { if (winner == null) {
LobbyPlayer guiPlayer = FServer.instance.getLobby().getGuiPlayer(); return "It's a draw!";
int nHumansInGame = 0; } else {
for(Pair<LobbyPlayer, PlayerStatistics> pps : outcome) { return winner.getName() + " Won!";
if( pps.getKey() == guiPlayer ) }
nHumansInGame++; }
}
LobbyPlayer winner = outcome.getWinner(); /** @return {@link forge.gui.toolbox.FButton} */
if ( winner == null ) public FButton getBtnContinue() {
return "It's a draw!"; return this.btnContinue;
}
return nHumansInGame == 1 ? "You " + (winner == guiPlayer ? "won!" : "lost!") : winner.getName() + " Won!";
} /** @return {@link forge.gui.toolbox.FButton} */
public FButton getBtnRestart() {
/** @return {@link forge.gui.toolbox.FButton} */ return this.btnRestart;
public FButton getBtnContinue() { }
return this.btnContinue;
} /** @return {@link forge.gui.toolbox.FButton} */
public FButton getBtnQuit() {
/** @return {@link forge.gui.toolbox.FButton} */ return this.btnQuit;
public FButton getBtnRestart() { }
return this.btnRestart;
} /** @return {@link javax.swing.JPanel} */
public JPanel getPnlCustom() {
/** @return {@link forge.gui.toolbox.FButton} */ return this.pnlCustom;
public FButton getBtnQuit() { }
return this.btnQuit;
} private void showGameOutcomeSummary() {
GameLog log = game.getGameLog();
/** @return {@link javax.swing.JPanel} */ for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.GAME_OUTCOME))
public JPanel getPnlCustom() { pnlOutcomes.add(new FLabel.Builder().text(o.message).fontSize(14).build(), "h 20!");
return this.pnlCustom; }
}
} private void showPlayerScores() {
GameLog log = game.getGameLog();
for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.MATCH_RESULTS)) {
lblStats.setText(removePlayerTypeFromLogMessage(o.message));
}
}
private String removePlayerTypeFromLogMessage(String message) {
return message.replaceAll("\\[[^\\]]*\\]", "");
}
}

View File

@@ -1,129 +1,129 @@
package forge.net; package forge.net;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.apache.commons.lang.time.StopWatch; import org.apache.commons.lang.time.StopWatch;
import forge.GameLogEntry; import forge.GameLogEntry;
import forge.Singletons; import forge.Singletons;
import forge.deck.Deck; import forge.deck.Deck;
import forge.game.Game; import forge.game.Game;
import forge.game.GameType; import forge.game.GameType;
import forge.game.Match; import forge.game.Match;
import forge.game.RegisteredPlayer; import forge.game.RegisteredPlayer;
import forge.util.Lang; import forge.util.Lang;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
*/ */
public enum FServer { public enum FServer {
instance(); instance();
private boolean interactiveMode = true; private boolean interactiveMode = true;
private Lobby lobby = null; private Lobby lobby = null;
public Lobby getLobby() { public Lobby getLobby() {
if (lobby == null) { if (lobby == null) {
lobby = new Lobby(); lobby = new Lobby();
} }
return lobby; return lobby;
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
*/ */
private final NetServer server = new NetServer(); private final NetServer server = new NetServer();
public NetServer getServer() { public NetServer getServer() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return server; return server;
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @param args * @param args
*/ */
public void simulateMatches(String[] args) { public void simulateMatches(String[] args) {
interactiveMode = false; interactiveMode = false;
System.out.println("Simulation mode"); System.out.println("Simulation mode");
if(args.length < 3 ) { if(args.length < 3 ) {
System.out.println("Syntax: forge.exe sim <deck1[.dck]> <deck2[.dck]> [N]"); System.out.println("Syntax: forge.exe sim <deck1[.dck]> <deck2[.dck]> [N]");
System.out.println("\tsim - stands for simulation mode"); System.out.println("\tsim - stands for simulation mode");
System.out.println("\tdeck1 (or deck2) - constructed deck name or filename (has to be quoted when contains multiple words)"); System.out.println("\tdeck1 (or deck2) - constructed deck name or filename (has to be quoted when contains multiple words)");
System.out.println("\tdeck is treated as file if it ends with a dot followed by three numbers or letters"); System.out.println("\tdeck is treated as file if it ends with a dot followed by three numbers or letters");
System.out.println("\tN - number of games, defaults to 1"); System.out.println("\tN - number of games, defaults to 1");
return; return;
} }
Deck d1 = deckFromCommandLineParameter(args[1]); Deck d1 = deckFromCommandLineParameter(args[1]);
Deck d2 = deckFromCommandLineParameter(args[2]); Deck d2 = deckFromCommandLineParameter(args[2]);
if(d1 == null || d2 == null) { if(d1 == null || d2 == null) {
System.out.println("One of decks could not be loaded, match cannot start"); System.out.println("One of decks could not be loaded, match cannot start");
return; return;
} }
int nGames = args.length >= 4 ? Integer.parseInt(args[3]) : 1; int nGames = args.length >= 4 ? Integer.parseInt(args[3]) : 1;
System.out.println(String.format("Ai-%s vs Ai_%s - %s", d1.getName(), d2.getName(), Lang.nounWithNumeral(nGames, "game"))); System.out.println(String.format("Ai-%s vs Ai_%s - %s", d1.getName(), d2.getName(), Lang.nounWithNumeral(nGames, "game")));
List<RegisteredPlayer> pp = new ArrayList<RegisteredPlayer>(); List<RegisteredPlayer> pp = new ArrayList<RegisteredPlayer>();
pp.add(RegisteredPlayer.fromDeck(d1).setPlayer(FServer.instance.getLobby().getAiPlayer("Ai-" + d1.getName()))); pp.add(RegisteredPlayer.fromDeck(d1).setPlayer(FServer.instance.getLobby().getAiPlayer("Ai-" + d1.getName())));
pp.add(RegisteredPlayer.fromDeck(d2).setPlayer(FServer.instance.getLobby().getAiPlayer("Ai_" + d2.getName()))); pp.add(RegisteredPlayer.fromDeck(d2).setPlayer(FServer.instance.getLobby().getAiPlayer("Ai_" + d2.getName())));
Match mc = new Match(GameType.Constructed, pp); Match mc = new Match(GameType.Constructed, pp);
for(int iGame = 0; iGame < nGames; iGame++) for(int iGame = 0; iGame < nGames; iGame++)
simulateSingleMatch(mc, iGame); simulateSingleMatch(mc, iGame);
System.out.flush(); System.out.flush();
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @param sw * @param sw
* @param pp * @param pp
*/ */
private void simulateSingleMatch(Match mc, int iGame) { private void simulateSingleMatch(Match mc, int iGame) {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
sw.start(); sw.start();
CountDownLatch cdl = new CountDownLatch(1); CountDownLatch cdl = new CountDownLatch(1);
Game g1 = mc.createGame(); Game g1 = mc.createGame();
mc.startGame(g1, cdl); mc.startGame(g1, cdl);
try { try {
cdl.await(); // wait until game ends (in other thread) cdl.await(); // wait until game ends (in other thread)
} catch (InterruptedException e) { } catch (InterruptedException e) {
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log. // TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
e.printStackTrace(); e.printStackTrace();
} }
sw.stop(); sw.stop();
List<GameLogEntry> log = g1.getGameLog().getLogEntries(null); List<GameLogEntry> log = g1.getGameLog().getLogEntries(null);
Collections.reverse(log); Collections.reverse(log);
for(GameLogEntry l : log) for(GameLogEntry l : log)
System.out.println(l); System.out.println(l);
System.out.println(String.format("\nGame %d ended in %d ms. %s has won!\n", 1+iGame, sw.getTime(), g1.getOutcome().getWinner().getName())); System.out.println(String.format("\nGame %d ended in %d ms. %s has won!\n", 1+iGame, sw.getTime(), g1.getOutcome().getWinningLobbyPlayer().getName()));
} }
private Deck deckFromCommandLineParameter(String deckname) { private Deck deckFromCommandLineParameter(String deckname) {
int dotpos = deckname.lastIndexOf('.'); int dotpos = deckname.lastIndexOf('.');
if(dotpos > 0 && dotpos == deckname.length()-4) if(dotpos > 0 && dotpos == deckname.length()-4)
return Deck.fromFile(new File(deckname)); return Deck.fromFile(new File(deckname));
return Singletons.getModel().getDecks().getConstructed().get(deckname); return Singletons.getModel().getDecks().getConstructed().get(deckname);
} }
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
*/ */
public boolean isInteractiveMode() { public boolean isInteractiveMode() {
return interactiveMode; return interactiveMode;
} }
} }

View File

@@ -1,128 +1,133 @@
package forge.net; package forge.net;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import forge.control.ChatArea; import forge.control.ChatArea;
import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayer;
import forge.game.player.LobbyPlayerAi; import forge.game.player.LobbyPlayerAi;
import forge.game.player.LobbyPlayerHuman; import forge.game.player.LobbyPlayerHuman;
import forge.game.player.LobbyPlayerRemote; import forge.game.player.LobbyPlayerRemote;
import forge.gui.toolbox.FSkin; import forge.gui.GuiDisplayUtil;
import forge.net.client.INetClient; import forge.gui.toolbox.FSkin;
import forge.util.MyRandom; import forge.net.client.INetClient;
import forge.util.MyRandom;
/**
* TODO: Write javadoc for this type. /**
* * TODO: Write javadoc for this type.
*/ *
public class Lobby { */
public class Lobby {
private final String[] opponentNames = new String[] {
"Abigail", "Ada", "Adeline", "Adriana", "Agatha", "Agnes", "Aileen", "Alba", "Alcyon", private final String[] opponentNames = new String[] {
"Alethea", "Alice", "Alicia", "Alison", "Amanda", "Amelia", "Amy", "Andrea", "Angelina", "Abigail", "Ada", "Adeline", "Adriana", "Agatha", "Agnes", "Aileen", "Alba", "Alcyon",
"Anita", "Ann", "Annabel", "Anne", "Audrey", "Barbara", "Belinda", "Bernice", "Bertha", "Alethea", "Alice", "Alicia", "Alison", "Amanda", "Amelia", "Amy", "Andrea", "Angelina",
"Bonnie", "Brenda", "Bridget", "Bunny", "Carmen", "Carol", "Catherine", "Cheryl", "Anita", "Ann", "Annabel", "Anne", "Audrey", "Barbara", "Belinda", "Bernice", "Bertha",
"Christine", "Cinderalla", "Claire", "Clarice", "Claudia", "Constance", "Cora", "Bonnie", "Brenda", "Bridget", "Bunny", "Carmen", "Carol", "Catherine", "Cheryl",
"Corinne", "Cnythia", "Daisy", "Daphne", "Dawn", "Deborah", "Diana", "Dolly", "Dora", "Christine", "Cinderalla", "Claire", "Clarice", "Claudia", "Constance", "Cora",
"Doreen", "Doris", "Dorothy", "Eileen", "Elaine", "Elizabeth", "Emily", "Emma", "Ethel", "Corinne", "Cnythia", "Daisy", "Daphne", "Dawn", "Deborah", "Diana", "Dolly", "Dora",
"Evelyn", "Fiona", "Florence", "Frances", "Geraldine", "Gertrude", "Gladys", "Gloria", "Doreen", "Doris", "Dorothy", "Eileen", "Elaine", "Elizabeth", "Emily", "Emma", "Ethel",
"Grace", "Greta", "Harriet", "Hazel", "Helen", "Hilda", "Ida", "Ingrid", "Irene", "Evelyn", "Fiona", "Florence", "Frances", "Geraldine", "Gertrude", "Gladys", "Gloria",
"Isabel", "Jacinta", "Jackie", "Jane", "Janet", "Janice", "Jennifer", "Jessie", "Joan", "Grace", "Greta", "Harriet", "Hazel", "Helen", "Hilda", "Ida", "Ingrid", "Irene",
"Jocelyn", "Josephine", "Joyce", "Judith", "Julia", "Juliana", "Karina", "Kathleen", "Isabel", "Jacinta", "Jackie", "Jane", "Janet", "Janice", "Jennifer", "Jessie", "Joan",
"Laura", "Lilian", "Lily", "Linda", "Lisa", "Lilita", "Lora", "Lorna", "Lucy", "Lydia", "Jocelyn", "Josephine", "Joyce", "Judith", "Julia", "Juliana", "Karina", "Kathleen",
"Mabel", "Madeline", "Maggie", "Maria", "Mariam", "Marilyn", "Mary", "Matilda", "Mavis", "Laura", "Lilian", "Lily", "Linda", "Lisa", "Lilita", "Lora", "Lorna", "Lucy", "Lydia",
"Melanie", "Melinda", "Melody", "Michelle", "Mildred", "Molly", "Mona", "Monica", "Mabel", "Madeline", "Maggie", "Maria", "Mariam", "Marilyn", "Mary", "Matilda", "Mavis",
"Nancy", "Nora", "Norma", "Olga", "Pamela", "Patricia", "Paula", "Pauline", "Pearl", "Melanie", "Melinda", "Melody", "Michelle", "Mildred", "Molly", "Mona", "Monica",
"Peggy", "Penny", "Phoebe", "Phyllis", "Polly", "Priscilla", "Rachel", "Rebecca", "Nancy", "Nora", "Norma", "Olga", "Pamela", "Patricia", "Paula", "Pauline", "Pearl",
"Rita", "Rosa", "Rosalind", "Rose", "Rosemary", "Rowena", "Ruby", "Sally", "Samantha", "Peggy", "Penny", "Phoebe", "Phyllis", "Polly", "Priscilla", "Rachel", "Rebecca",
"Sarah", "Selina", "Sharon", "Sheila", "Shirley", "Sonya", "Stella", "Sue", "Susan", "Rita", "Rosa", "Rosalind", "Rose", "Rosemary", "Rowena", "Ruby", "Sally", "Samantha",
"Sylvia", "Tina", "Tracy", "Ursula", "Valentine", "Valerie", "Vanessa", "Veronica", "Sarah", "Selina", "Sharon", "Sheila", "Shirley", "Sonya", "Stella", "Sue", "Susan",
"Victoria", "Violet", "Vivian", "Wendy", "Winnie", "Yvonne", "Aaron", "Abraham", "Adam", "Sylvia", "Tina", "Tracy", "Ursula", "Valentine", "Valerie", "Vanessa", "Veronica",
"Adrain", "Alain", "Alan", "Alban", "Albert", "Alec", "Alexander", "Alfonso", "Alfred", "Victoria", "Violet", "Vivian", "Wendy", "Winnie", "Yvonne", "Aaron", "Abraham", "Adam",
"Allan", "Allen", "Alonso", "Aloysius", "Alphonso", "Alvin", "Andrew", "Andy", "Amadeus", "Adrain", "Alain", "Alan", "Alban", "Albert", "Alec", "Alexander", "Alfonso", "Alfred",
"Amselm", "Anthony", "Arnold", "Augusta", "Austin", "Barnaby", "Benedict", "Benjamin", "Allan", "Allen", "Alonso", "Aloysius", "Alphonso", "Alvin", "Andrew", "Andy", "Amadeus",
"Bertie", "Bertram", "Bill", "Bob", "Boris", "Brady", "Brian", "Bruce", "Burt", "Byron", "Amselm", "Anthony", "Arnold", "Augusta", "Austin", "Barnaby", "Benedict", "Benjamin",
"Calvin", "Carl", "Carter", "Casey", "Cecil", "Charles", "Christian", "Christopher", "Bertie", "Bertram", "Bill", "Bob", "Boris", "Brady", "Brian", "Bruce", "Burt", "Byron",
"Clarence", "Clement", "Colin", "Conan", "Dalton", "Damian", "Daniel", "David", "Denis", "Calvin", "Carl", "Carter", "Casey", "Cecil", "Charles", "Christian", "Christopher",
"Derek", "Desmond", "Dick", "Dominic", "Donald", "Douglas", "Duncan", "Edmund", "Clarence", "Clement", "Colin", "Conan", "Dalton", "Damian", "Daniel", "David", "Denis",
"Edward", "Ellen", "Elton", "Elvis", "Eric", "Eugene", "Felix", "Francis", "Frank", "Derek", "Desmond", "Dick", "Dominic", "Donald", "Douglas", "Duncan", "Edmund",
"Frederick", "Gary", "Geoffrey", "George", "Gerald", "Gerry", "Gordon", "Hamish", "Edward", "Ellen", "Elton", "Elvis", "Eric", "Eugene", "Felix", "Francis", "Frank",
"Hardy", "Harold", "Harry", "Henry", "Herbert", "Ignatius", "Jack", "James", "Jeffrey", "Frederick", "Gary", "Geoffrey", "George", "Gerald", "Gerry", "Gordon", "Hamish",
"Jim", "Joe", "John", "Joseph", "Karl", "Keith", "Kenneth", "Kevin", "Larry", "Lawrence", "Hardy", "Harold", "Harry", "Henry", "Herbert", "Ignatius", "Jack", "James", "Jeffrey",
"Leonard", "Lionel", "Louis", "Lucas", "Malcolm", "Mark", "Martin", "Mathew", "Maurice", "Jim", "Joe", "John", "Joseph", "Karl", "Keith", "Kenneth", "Kevin", "Larry", "Lawrence",
"Max", "Melvin", "Michael", "Milton", "Morgan", "Morris", "Murphy", "Neville", "Leonard", "Lionel", "Louis", "Lucas", "Malcolm", "Mark", "Martin", "Mathew", "Maurice",
"Nicholas", "Noel", "Norman", "Oliver", "Oscar", "Patrick", "Paul", "Perkin", "Peter", "Max", "Melvin", "Michael", "Milton", "Morgan", "Morris", "Murphy", "Neville",
"Philip", "Ralph", "Randy", "Raymond", "Richard", "Ricky", "Robert", "Robin", "Rodney", "Nicholas", "Noel", "Norman", "Oliver", "Oscar", "Patrick", "Paul", "Perkin", "Peter",
"Roger", "Roland", "Ronald", "Roy", "Sam", "Sebastian", "Simon", "Stanley", "Stephen", "Philip", "Ralph", "Randy", "Raymond", "Richard", "Ricky", "Robert", "Robin", "Rodney",
"Stuart", "Terence", "Thomas", "Tim", "Tom", "Tony", "Victor", "Vincent", "Wallace", "Roger", "Roland", "Ronald", "Roy", "Sam", "Sebastian", "Simon", "Stanley", "Stephen",
"Walter", "Wilfred", "William", "Winston" "Stuart", "Terence", "Thomas", "Tim", "Tom", "Tony", "Victor", "Vincent", "Wallace",
}; "Walter", "Wilfred", "William", "Winston"
};
private Map<String, LobbyPlayerRemote> remotePlayers = new ConcurrentHashMap<String, LobbyPlayerRemote>();
private final LobbyPlayerHuman guiPlayer = new LobbyPlayerHuman("Human"); private Map<String, LobbyPlayerRemote> remotePlayers = new ConcurrentHashMap<String, LobbyPlayerRemote>();
private final LobbyPlayerAi system = new LobbyPlayerAi("System"); private final LobbyPlayerHuman guiPlayer = new LobbyPlayerHuman("Human");
private final LobbyPlayerAi system = new LobbyPlayerAi("System");
public final LobbyPlayer getGuiPlayer() {
return guiPlayer; public final LobbyPlayer getGuiPlayer() {
} return guiPlayer;
}
public final LobbyPlayer getAiPlayer() { return getAiPlayer(getRandomName()); }
public final LobbyPlayer getAiPlayer(String name) { public final LobbyPlayer getAiPlayer() { return getAiPlayer(getRandomName()); }
LobbyPlayer player = new LobbyPlayerAi(name); public final LobbyPlayer getAiPlayer(String name) {
if(FSkin.isLoaded()) LobbyPlayer player = new LobbyPlayerAi(name);
player.setAvatarIndex(MyRandom.getRandom().nextInt(FSkin.getAvatars().size())); if(FSkin.isLoaded())
return player; player.setAvatarIndex(MyRandom.getRandom().nextInt(FSkin.getAvatars().size()));
} return player;
}
/**
* TODO: Write javadoc for this method. /**
* @param nextInt * TODO: Write javadoc for this method.
* @return * @param nextInt
*/ * @return
private String getRandomName() { */
Random my = MyRandom.getRandom(); private String getRandomName() {
return opponentNames[my.nextInt(opponentNames.length)]; Random my = MyRandom.getRandom();
String playerName = GuiDisplayUtil.getPlayerName();
} String aiName = opponentNames[my.nextInt(opponentNames.length)];
while (aiName.equalsIgnoreCase(playerName)) {
/** aiName = opponentNames[my.nextInt(opponentNames.length)];
* TODO: Write javadoc for this method. }
* @return return aiName;
*/ }
public LobbyPlayer getQuestPlayer() {
return guiPlayer; /**
} * TODO: Write javadoc for this method.
* @return
/** */
* TODO: Write javadoc for this method. public LobbyPlayer getQuestPlayer() {
* @param name return guiPlayer;
* @return }
*/
public synchronized LobbyPlayer findOrCreateRemotePlayer(String name, INetClient client) { /**
if (remotePlayers.containsKey(name)) * TODO: Write javadoc for this method.
return remotePlayers.get(name); * @param name
* @return
LobbyPlayerRemote res = new LobbyPlayerRemote(name, client); */
speak(ChatArea.Room, system, res.getName() + " has joined the server."); public synchronized LobbyPlayer findOrCreateRemotePlayer(String name, INetClient client) {
// have to load avatar from remote user's preferences here if (remotePlayers.containsKey(name))
remotePlayers.put(name, res); return remotePlayers.get(name);
return res; LobbyPlayerRemote res = new LobbyPlayerRemote(name, client);
} speak(ChatArea.Room, system, res.getName() + " has joined the server.");
// have to load avatar from remote user's preferences here
public void disconnectPlayer(LobbyPlayer player) { remotePlayers.put(name, res);
// Should set up a timer here to discard player and all of his games after 20 minutes of being offline
} return res;
}
public void speak(ChatArea room, LobbyPlayer player, String message) { public void disconnectPlayer(LobbyPlayer player) {
getGuiPlayer().hear(player, message); // Should set up a timer here to discard player and all of his games after 20 minutes of being offline
for(LobbyPlayer remote : remotePlayers.values()) { }
remote.hear(player, message);
}
} public void speak(ChatArea room, LobbyPlayer player, String message) {
} getGuiPlayer().hear(player, message);
for(LobbyPlayer remote : remotePlayers.values()) {
remote.hear(player, message);
}
}
}

View File

@@ -34,6 +34,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
* Preference identifiers, and their default values. * Preference identifiers, and their default values.
*/ */
public static enum FPref { public static enum FPref {
PLAYER_NAME (""),
CONSTRUCTED_P1_DECK_STATE(""), CONSTRUCTED_P1_DECK_STATE(""),
CONSTRUCTED_P2_DECK_STATE(""), CONSTRUCTED_P2_DECK_STATE(""),
CONSTRUCTED_GAMEPLAYERS(""), CONSTRUCTED_GAMEPLAYERS(""),

View File

@@ -1,210 +1,210 @@
package forge.sound; package forge.sound;
import java.util.Collection; import java.util.Collection;
import forge.Card; import forge.Card;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.game.event.GameEventBlockersDeclared; import forge.game.event.GameEventBlockersDeclared;
import forge.game.event.GameEventCardChangeZone; import forge.game.event.GameEventCardChangeZone;
import forge.game.event.GameEventCardDamaged; import forge.game.event.GameEventCardDamaged;
import forge.game.event.GameEventCardDestroyed; import forge.game.event.GameEventCardDestroyed;
import forge.game.event.GameEventCardAttachment; import forge.game.event.GameEventCardAttachment;
import forge.game.event.GameEventCardRegenerated; import forge.game.event.GameEventCardRegenerated;
import forge.game.event.GameEventCardSacrificed; import forge.game.event.GameEventCardSacrificed;
import forge.game.event.GameEventCardCounters; import forge.game.event.GameEventCardCounters;
import forge.game.event.GameEventGameOutcome; import forge.game.event.GameEventGameOutcome;
import forge.game.event.GameEventTurnEnded; import forge.game.event.GameEventTurnEnded;
import forge.game.event.GameEvent; import forge.game.event.GameEvent;
import forge.game.event.GameEventFlipCoin; import forge.game.event.GameEventFlipCoin;
import forge.game.event.GameEventLandPlayed; import forge.game.event.GameEventLandPlayed;
import forge.game.event.GameEventPlayerLivesChanged; import forge.game.event.GameEventPlayerLivesChanged;
import forge.game.event.GameEventPlayerPoisoned; import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.GameEventCardTapped; import forge.game.event.GameEventCardTapped;
import forge.game.event.GameEventShuffle; import forge.game.event.GameEventShuffle;
import forge.game.event.GameEventSpellResolved; import forge.game.event.GameEventSpellResolved;
import forge.game.event.GameEventTokenCreated; import forge.game.event.GameEventTokenCreated;
import forge.game.event.IGameEventVisitor; import forge.game.event.IGameEventVisitor;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.events.IUiEventVisitor; import forge.gui.events.IUiEventVisitor;
import forge.gui.events.UiEventAttackerDeclared; import forge.gui.events.UiEventAttackerDeclared;
import forge.gui.events.UiEventBlockerAssigned; import forge.gui.events.UiEventBlockerAssigned;
import forge.net.FServer; import forge.net.FServer;
import forge.util.maps.MapOfLists; import forge.util.maps.MapOfLists;
/** /**
* This class is in charge of converting any forge.game.event.Event to a SoundEffectType. * This class is in charge of converting any forge.game.event.Event to a SoundEffectType.
* *
*/ */
public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> implements IUiEventVisitor<SoundEffectType> { public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> implements IUiEventVisitor<SoundEffectType> {
public SoundEffectType visit(GameEventCardDamaged event) { return SoundEffectType.Damage; } public SoundEffectType visit(GameEventCardDamaged event) { return SoundEffectType.Damage; }
public SoundEffectType visit(GameEventCardDestroyed event) { return SoundEffectType.Destroy; } public SoundEffectType visit(GameEventCardDestroyed event) { return SoundEffectType.Destroy; }
public SoundEffectType visit(GameEventCardAttachment event) { return SoundEffectType.Equip; } public SoundEffectType visit(GameEventCardAttachment event) { return SoundEffectType.Equip; }
public SoundEffectType visit(GameEventCardChangeZone event) { public SoundEffectType visit(GameEventCardChangeZone event) {
ZoneType from = event.from == null ? null : event.from.getZoneType(); ZoneType from = event.from == null ? null : event.from.getZoneType();
ZoneType to = event.to.getZoneType(); ZoneType to = event.to.getZoneType();
if( from == ZoneType.Library && to == ZoneType.Hand) if( from == ZoneType.Library && to == ZoneType.Hand)
return SoundEffectType.Draw; return SoundEffectType.Draw;
if( from == ZoneType.Hand && (to == ZoneType.Graveyard || to == ZoneType.Library) ) if( from == ZoneType.Hand && (to == ZoneType.Graveyard || to == ZoneType.Library) )
return SoundEffectType.Discard; return SoundEffectType.Discard;
return to == ZoneType.Exile ? SoundEffectType.Exile : null; return to == ZoneType.Exile ? SoundEffectType.Exile : null;
} }
public SoundEffectType visit(GameEventCardRegenerated event) { return SoundEffectType.Regen; } public SoundEffectType visit(GameEventCardRegenerated event) { return SoundEffectType.Regen; }
public SoundEffectType visit(GameEventCardSacrificed event) { return SoundEffectType.Sacrifice; } public SoundEffectType visit(GameEventCardSacrificed event) { return SoundEffectType.Sacrifice; }
public SoundEffectType visit(GameEventCardCounters event) { return event.newValue > event.oldValue ? SoundEffectType.AddCounter : event.newValue < event.oldValue ? SoundEffectType.RemoveCounter : null; } public SoundEffectType visit(GameEventCardCounters event) { return event.newValue > event.oldValue ? SoundEffectType.AddCounter : event.newValue < event.oldValue ? SoundEffectType.RemoveCounter : null; }
public SoundEffectType visit(GameEventTurnEnded event) { return SoundEffectType.EndOfTurn; } public SoundEffectType visit(GameEventTurnEnded event) { return SoundEffectType.EndOfTurn; }
public SoundEffectType visit(GameEventFlipCoin event) { return SoundEffectType.FlipCoin; } public SoundEffectType visit(GameEventFlipCoin event) { return SoundEffectType.FlipCoin; }
public SoundEffectType visit(GameEventPlayerLivesChanged event) { return event.newLives < event.oldLives ? SoundEffectType.LifeLoss : SoundEffectType.LifeGain; } public SoundEffectType visit(GameEventPlayerLivesChanged event) { return event.newLives < event.oldLives ? SoundEffectType.LifeLoss : SoundEffectType.LifeGain; }
public SoundEffectType visit(GameEventPlayerPoisoned event) { return SoundEffectType.Poison; } public SoundEffectType visit(GameEventPlayerPoisoned event) { return SoundEffectType.Poison; }
public SoundEffectType visit(GameEventShuffle event) { return SoundEffectType.Shuffle; } public SoundEffectType visit(GameEventShuffle event) { return SoundEffectType.Shuffle; }
public SoundEffectType visit(GameEventTokenCreated event) { return SoundEffectType.Token; } public SoundEffectType visit(GameEventTokenCreated event) { return SoundEffectType.Token; }
public SoundEffectType visit(GameEventBlockersDeclared event) { public SoundEffectType visit(GameEventBlockersDeclared event) {
boolean isLocalHuman = event.defendingPlayer.getLobbyPlayer() == FServer.instance.getLobby().getGuiPlayer(); boolean isLocalHuman = event.defendingPlayer.getLobbyPlayer() == FServer.instance.getLobby().getGuiPlayer();
if (isLocalHuman) if (isLocalHuman)
return null; // already played sounds in interactive mode return null; // already played sounds in interactive mode
for(MapOfLists<Card, Card> ab : event.blockers.values()) { for(MapOfLists<Card, Card> ab : event.blockers.values()) {
for(Collection<Card> bb : ab.values()) { for(Collection<Card> bb : ab.values()) {
if ( !bb.isEmpty() ) { if ( !bb.isEmpty() ) {
// hasAnyBlocker = true; // hasAnyBlocker = true;
return SoundEffectType.Block; return SoundEffectType.Block;
} }
} }
} }
return null; return null;
} }
/** /**
* Plays the sound corresponding to the outcome of the duel. * Plays the sound corresponding to the outcome of the duel.
*/ */
public SoundEffectType visit(GameEventGameOutcome event) { public SoundEffectType visit(GameEventGameOutcome event) {
boolean humanWonTheDuel = event.result.getWinner() == FServer.instance.getLobby().getGuiPlayer(); boolean humanWonTheDuel = event.result.getWinningLobbyPlayer() == FServer.instance.getLobby().getGuiPlayer();
return humanWonTheDuel ? SoundEffectType.WinDuel : SoundEffectType.LoseDuel; return humanWonTheDuel ? SoundEffectType.WinDuel : SoundEffectType.LoseDuel;
} }
/** /**
* Plays the sound corresponding to the card type/color when the card * Plays the sound corresponding to the card type/color when the card
* ability resolves on the stack. * ability resolves on the stack.
*/ */
public SoundEffectType visit(GameEventSpellResolved evt) { public SoundEffectType visit(GameEventSpellResolved evt) {
if (evt.spell == null ) { if (evt.spell == null ) {
return null; return null;
} }
Card source = evt.spell.getSourceCard(); Card source = evt.spell.getSourceCard();
if (evt.spell.isSpell()) { if (evt.spell.isSpell()) {
// if there's a specific effect for this particular card, play it and // if there's a specific effect for this particular card, play it and
// we're done. // we're done.
if (hasSpecificCardEffect(source)) { if (hasSpecificCardEffect(source)) {
return SoundEffectType.ScriptedEffect; return SoundEffectType.ScriptedEffect;
} }
if (source.isCreature() && source.isArtifact()) { if (source.isCreature() && source.isArtifact()) {
return SoundEffectType.ArtifactCreature; return SoundEffectType.ArtifactCreature;
} else if (source.isCreature()) { } else if (source.isCreature()) {
return SoundEffectType.Creature; return SoundEffectType.Creature;
} else if (source.isArtifact()) { } else if (source.isArtifact()) {
return SoundEffectType.Artifact; return SoundEffectType.Artifact;
} else if (source.isInstant()) { } else if (source.isInstant()) {
return SoundEffectType.Instant; return SoundEffectType.Instant;
} else if (source.isPlaneswalker()) { } else if (source.isPlaneswalker()) {
return SoundEffectType.Planeswalker; return SoundEffectType.Planeswalker;
} else if (source.isSorcery()) { } else if (source.isSorcery()) {
return SoundEffectType.Sorcery; return SoundEffectType.Sorcery;
} else if (source.isEnchantment()) { } else if (source.isEnchantment()) {
return SoundEffectType.Enchantment; return SoundEffectType.Enchantment;
} }
} }
return null; return null;
} }
/** /**
* Plays the sound corresponding to the change of the card's tapped state * Plays the sound corresponding to the change of the card's tapped state
* (when a card is tapped or untapped). * (when a card is tapped or untapped).
* *
* @param tapped_state if true, the "tap" sound is played; otherwise, the * @param tapped_state if true, the "tap" sound is played; otherwise, the
* "untap" sound is played * "untap" sound is played
* @return the sound effect type * @return the sound effect type
*/ */
public SoundEffectType visit(GameEventCardTapped event) { public SoundEffectType visit(GameEventCardTapped event) {
return event.tapped ? SoundEffectType.Tap : SoundEffectType.Untap; return event.tapped ? SoundEffectType.Tap : SoundEffectType.Untap;
} }
/** /**
* Plays the sound corresponding to the land type when the land is played. * Plays the sound corresponding to the land type when the land is played.
* *
* @param land the land card that was played * @param land the land card that was played
* @return the sound effect type * @return the sound effect type
*/ */
public SoundEffectType visit(GameEventLandPlayed event) { public SoundEffectType visit(GameEventLandPlayed event) {
if (event.land == null) { if (event.land == null) {
return null; return null;
} }
// if there's a specific effect for this particular card, play it and // if there's a specific effect for this particular card, play it and
// we're done. // we're done.
if (hasSpecificCardEffect(event.land)) { if (hasSpecificCardEffect(event.land)) {
return SoundEffectType.ScriptedEffect; return SoundEffectType.ScriptedEffect;
} }
for (SpellAbility sa : event.land.getManaAbility()) { for (SpellAbility sa : event.land.getManaAbility()) {
String manaColors = sa.getManaPartRecursive().getOrigProduced(); String manaColors = sa.getManaPartRecursive().getOrigProduced();
if (manaColors.contains("B")) return SoundEffectType.BlackLand; if (manaColors.contains("B")) return SoundEffectType.BlackLand;
if (manaColors.contains("U")) return SoundEffectType.BlueLand; if (manaColors.contains("U")) return SoundEffectType.BlueLand;
if (manaColors.contains("G")) return SoundEffectType.GreenLand; if (manaColors.contains("G")) return SoundEffectType.GreenLand;
if (manaColors.contains("R")) return SoundEffectType.RedLand; if (manaColors.contains("R")) return SoundEffectType.RedLand;
if (manaColors.contains("W")) return SoundEffectType.WhiteLand; if (manaColors.contains("W")) return SoundEffectType.WhiteLand;
} }
// play a generic land sound if no other sound corresponded to it. // play a generic land sound if no other sound corresponded to it.
return SoundEffectType.OtherLand; return SoundEffectType.OtherLand;
} }
/** /**
* Play a specific sound effect based on card's name. * Play a specific sound effect based on card's name.
* *
* @param c the card to play the sound effect for. * @param c the card to play the sound effect for.
* @return the sound effect type * @return the sound effect type
*/ */
private static boolean hasSpecificCardEffect(final Card c) { private static boolean hasSpecificCardEffect(final Card c) {
// Implement sound effects for specific cards here, if necessary. // Implement sound effects for specific cards here, if necessary.
String effect = ""; String effect = "";
if (null != c) { if (null != c) {
effect = c.getSVar("SoundEffect"); effect = c.getSVar("SoundEffect");
} }
return effect.isEmpty() ? false : true; return effect.isEmpty() ? false : true;
} }
/** /**
* Returns the value of the SoundEffect SVar of the card that triggered * Returns the value of the SoundEffect SVar of the card that triggered
* the event, otherwise returns an empty string. * the event, otherwise returns an empty string.
* *
* @param evt the event which is the source of the sound effect * @param evt the event which is the source of the sound effect
* @return a string containing the SoundEffect SVar, or empty string if * @return a string containing the SoundEffect SVar, or empty string if
* SVar:SoundEffect does not exist. * SVar:SoundEffect does not exist.
*/ */
public String getScriptedSoundEffectName(GameEvent evt) { public String getScriptedSoundEffectName(GameEvent evt) {
Card c = null; Card c = null;
if (evt instanceof GameEventSpellResolved) { if (evt instanceof GameEventSpellResolved) {
c = ((GameEventSpellResolved) evt).spell.getSourceCard(); c = ((GameEventSpellResolved) evt).spell.getSourceCard();
} else if (evt instanceof GameEventLandPlayed) { } else if (evt instanceof GameEventLandPlayed) {
c = ((GameEventLandPlayed) evt).land; c = ((GameEventLandPlayed) evt).land;
} }
return c != null ? c.getSVar("SoundEffect") : ""; return c != null ? c.getSVar("SoundEffect") : "";
} }
@Override @Override
public SoundEffectType visit(UiEventBlockerAssigned event) { public SoundEffectType visit(UiEventBlockerAssigned event) {
return event.attackerBeingBlocked == null ? null : SoundEffectType.Block; return event.attackerBeingBlocked == null ? null : SoundEffectType.Block;
} }
@Override @Override
public SoundEffectType visit(UiEventAttackerDeclared event) { public SoundEffectType visit(UiEventAttackerDeclared event) {
return null; return null;
} }
} }