mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 03:38:01 +00:00
- 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:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -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/CSubmenuPreferences.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/VSubmenuDownloaders.java -text
|
||||
src/main/java/forge/gui/home/settings/VSubmenuPreferences.java -text
|
||||
|
||||
@@ -1,253 +1,248 @@
|
||||
package forge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import forge.card.spellability.TargetChoices;
|
||||
import forge.game.GameOutcome;
|
||||
import forge.game.event.GameEventAttackersDeclared;
|
||||
import forge.game.event.GameEventBlockersDeclared;
|
||||
import forge.game.event.GameEventCardDamaged;
|
||||
import forge.game.event.GameEventCardDamaged.DamageType;
|
||||
import forge.game.event.GameEventLandPlayed;
|
||||
import forge.game.event.GameEventMulligan;
|
||||
import forge.game.event.GameEventPlayerDamaged;
|
||||
import forge.game.event.GameEventPlayerPoisoned;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTurnBegan;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEvent;
|
||||
import forge.game.event.GameEventTurnPhase;
|
||||
import forge.game.event.GameEventPlayerControl;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerStatistics;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.net.FServer;
|
||||
import forge.util.Lang;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
private final GameLog log;
|
||||
|
||||
public GameLogFormatter(GameLog gameLog) {
|
||||
log = gameLog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventGameOutcome ev) {
|
||||
// add result entries to the game log
|
||||
final LobbyPlayer human = FServer.instance.getLobby().getGuiPlayer();
|
||||
|
||||
// This adds some extra entries to log
|
||||
final List<String> outcomes = new ArrayList<String>();
|
||||
for (Entry<LobbyPlayer, PlayerStatistics> p : ev.result) {
|
||||
String whoHas = p.getKey().equals(human) ? "You have" : p.getKey().getName() + " has";
|
||||
String outcome = String.format("%s %s", whoHas, p.getValue().getOutcome().toString());
|
||||
outcomes.add(outcome);
|
||||
log.add(GameLogEntryType.GAME_OUTCOME, outcome);
|
||||
}
|
||||
|
||||
return generateSummary(ev.history);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventSpellResolved)
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventSpellAbilityCast event) {
|
||||
String who = event.sa.getActivatingPlayer().getName();
|
||||
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(who).append(action).append(what);
|
||||
|
||||
if (event.sa.getTargetRestrictions() != null) {
|
||||
sb.append(" targeting ");
|
||||
for (TargetChoices ch : event.sa.getAllTargetChoices()) {
|
||||
if (null != ch) {
|
||||
sb.append(ch.getTargetedString());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(".");
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.STACK_ADD, sb.toString());
|
||||
}
|
||||
|
||||
private GameLogEntry generateSummary(List<GameOutcome> gamesPlayed) {
|
||||
GameOutcome outcome1 = gamesPlayed.get(0);
|
||||
int[] wins = new int[outcome1.getNumPlayers()];
|
||||
LobbyPlayer[] players = new LobbyPlayer[outcome1.getNumPlayers()];
|
||||
for(int i = 0; i < wins.length; wins[i++] = 0);
|
||||
|
||||
for (GameOutcome go : gamesPlayed) {
|
||||
int i = 0;
|
||||
for(Entry<LobbyPlayer, PlayerStatistics> ps : go) {
|
||||
players[i] = ps.getKey();
|
||||
if( ps.getValue().getOutcome().hasWon() )
|
||||
wins[i]++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i = 0; i < wins.length; i++) {
|
||||
sb.append(players[i].getName()).append(": ").append(wins[i]).append(" ");
|
||||
}
|
||||
return new GameLogEntry(GameLogEntryType.MATCH_RESULTS, sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerControl event) {
|
||||
// TODO Auto-generated method stub
|
||||
LobbyPlayer newController = event.newController;
|
||||
Player p = event.player;
|
||||
|
||||
final String message;
|
||||
if( newController == null )
|
||||
message = p.getName() + " has restored control over themself";
|
||||
else
|
||||
message = String.format("%s is controlled by %s", p.getName(), newController.getName());
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.PLAYER_CONROL, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventTurnPhase ev) {
|
||||
Player p = ev.playerTurn;
|
||||
return new GameLogEntry(GameLogEntryType.PHASE, ev.phaseDesc + Lang.getPossesive(p.getName()) + " " + ev.phase.nameForUi);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventCardDamaged event) {
|
||||
String additionalLog = "";
|
||||
if( event.type == DamageType.Deathtouch ) additionalLog = "(Deathtouch)";
|
||||
if( event.type == DamageType.M1M1Counters ) additionalLog = "(As -1/-1 Counters)";
|
||||
if( event.type == DamageType.LoyaltyLoss ) additionalLog = "(Removing " + Lang.nounWithAmount(event.amount, "loyalty counter") + ")";
|
||||
|
||||
String message = String.format("%s deals %d damage %s to %s.", event.source, event.amount, additionalLog, event.card);
|
||||
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventLandPlayed)
|
||||
*/
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventLandPlayed ev) {
|
||||
String message = String.format("%s played %s", ev.player, ev.land);
|
||||
return new GameLogEntry(GameLogEntryType.LAND, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventTurnBegan event) {
|
||||
String message = String.format( "Turn %d (%s)", event.turnNumber, event.turnOwner);
|
||||
return new GameLogEntry(GameLogEntryType.TURN, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerDamaged ev) {
|
||||
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(GameEventPlayerPoisoned ev) {
|
||||
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(final GameEventAttackersDeclared ev) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Loop through Defenders
|
||||
// Append Defending Player/Planeswalker
|
||||
|
||||
// Not a big fan of the triple nested loop here
|
||||
for (GameEntity k : ev.attackersMap.keySet()) {
|
||||
|
||||
Collection<Card> attackers = ev.attackersMap.get(k);
|
||||
if (attackers == null || attackers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if ( sb.length() > 0 ) sb.append("\n");
|
||||
sb.append(ev.player + " assigned " + Lang.joinHomogenous(attackers));
|
||||
sb.append(" to attack " + k + ".");
|
||||
}
|
||||
if ( sb.length() == 0 )
|
||||
sb.append(ev.player + " didn't attack this turn.");
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(final GameEventBlockersDeclared ev) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Loop through Defenders
|
||||
// Append Defending Player/Planeswalker
|
||||
|
||||
Collection<Card> blockers = null;
|
||||
|
||||
for (Entry<GameEntity, MapOfLists<Card, Card>> kv : ev.blockers.entrySet()) {
|
||||
GameEntity defender = kv.getKey();
|
||||
MapOfLists<Card, Card> attackers = kv.getValue();
|
||||
if (attackers == null || attackers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if ( sb.length() > 0 ) sb.append("\n");
|
||||
|
||||
String controllerName = defender instanceof Card ? ((Card)defender).getController().getName() : defender.getName();
|
||||
boolean firstAttacker = true;
|
||||
for (final Entry<Card, Collection<Card>> att : attackers.entrySet()) {
|
||||
if ( !firstAttacker ) sb.append("\n");
|
||||
|
||||
blockers = att.getValue();
|
||||
if ( blockers.isEmpty() ) {
|
||||
sb.append(controllerName + " didn't block ");
|
||||
} else {
|
||||
sb.append(controllerName + " assigned " + Lang.joinHomogenous(blockers) + " to block ");
|
||||
}
|
||||
|
||||
sb.append(att.getKey()).append(".");
|
||||
firstAttacker = false;
|
||||
}
|
||||
}
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
|
||||
@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());
|
||||
return new GameLogEntry(GameLogEntryType.MULLIGAN, message);
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void recieve(GameEvent ev) {
|
||||
GameLogEntry le = ev.visit(this);
|
||||
if ( le != null )
|
||||
log.add(le);
|
||||
}
|
||||
|
||||
package forge;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import forge.card.spellability.TargetChoices;
|
||||
import forge.game.GameOutcome;
|
||||
import forge.game.event.GameEvent;
|
||||
import forge.game.event.GameEventAttackersDeclared;
|
||||
import forge.game.event.GameEventBlockersDeclared;
|
||||
import forge.game.event.GameEventCardDamaged;
|
||||
import forge.game.event.GameEventCardDamaged.DamageType;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEventLandPlayed;
|
||||
import forge.game.event.GameEventMulligan;
|
||||
import forge.game.event.GameEventPlayerControl;
|
||||
import forge.game.event.GameEventPlayerDamaged;
|
||||
import forge.game.event.GameEventPlayerPoisoned;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTurnBegan;
|
||||
import forge.game.event.GameEventTurnPhase;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
private final GameLog log;
|
||||
|
||||
public GameLogFormatter(GameLog gameLog) {
|
||||
log = gameLog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventGameOutcome ev) {
|
||||
for (Player p : ev.result.getPlayers()) {
|
||||
String outcome = String.format("%s has %s", p.getName(), p.getOutcome().toString());
|
||||
log.add(GameLogEntryType.GAME_OUTCOME, outcome);
|
||||
}
|
||||
return generateSummary(ev.history);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventSpellResolved)
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventSpellAbilityCast event) {
|
||||
String who = event.sa.getActivatingPlayer().getName();
|
||||
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(who).append(action).append(what);
|
||||
|
||||
if (event.sa.getTargetRestrictions() != null) {
|
||||
sb.append(" targeting ");
|
||||
for (TargetChoices ch : event.sa.getAllTargetChoices()) {
|
||||
if (null != ch) {
|
||||
sb.append(ch.getTargetedString());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(".");
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.STACK_ADD, sb.toString());
|
||||
}
|
||||
|
||||
private GameLogEntry generateSummary(List<GameOutcome> gamesPlayed) {
|
||||
|
||||
GameOutcome outcome1 = gamesPlayed.get(0);
|
||||
List<Player> players = outcome1.getPlayers();
|
||||
|
||||
final int[] wins = new int[players.size()];
|
||||
|
||||
// Calculate total games each player has won.
|
||||
for (GameOutcome game : gamesPlayed) {
|
||||
int i = 0;
|
||||
for (Player p : game.getPlayers()) {
|
||||
if (p.getOutcome().hasWon()) {
|
||||
wins[i]++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i = 0; i < wins.length; i++) {
|
||||
Player player = players.get(i);
|
||||
String playerName = player.getName();
|
||||
playerName += " [" + player.getOriginalLobbyPlayer().getType() + "]";
|
||||
sb.append(playerName).append(": ").append(wins[i]).append(" ");
|
||||
}
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.MATCH_RESULTS, sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerControl event) {
|
||||
// TODO Auto-generated method stub
|
||||
LobbyPlayer newController = event.newController;
|
||||
Player p = event.player;
|
||||
|
||||
final String message;
|
||||
if( newController == null )
|
||||
message = p.getName() + " has restored control over themself";
|
||||
else
|
||||
message = String.format("%s is controlled by %s", p.getName(), newController.getName());
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.PLAYER_CONROL, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventTurnPhase ev) {
|
||||
Player p = ev.playerTurn;
|
||||
return new GameLogEntry(GameLogEntryType.PHASE, ev.phaseDesc + Lang.getPossesive(p.getName()) + " " + ev.phase.nameForUi);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventCardDamaged event) {
|
||||
String additionalLog = "";
|
||||
if( event.type == DamageType.Deathtouch ) additionalLog = "(Deathtouch)";
|
||||
if( event.type == DamageType.M1M1Counters ) additionalLog = "(As -1/-1 Counters)";
|
||||
if( event.type == DamageType.LoyaltyLoss ) additionalLog = "(Removing " + Lang.nounWithAmount(event.amount, "loyalty counter") + ")";
|
||||
|
||||
String message = String.format("%s deals %d damage %s to %s.", event.source, event.amount, additionalLog, event.card);
|
||||
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventLandPlayed)
|
||||
*/
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventLandPlayed ev) {
|
||||
String message = String.format("%s played %s", ev.player, ev.land);
|
||||
return new GameLogEntry(GameLogEntryType.LAND, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventTurnBegan event) {
|
||||
String message = String.format( "Turn %d (%s)", event.turnNumber, event.turnOwner);
|
||||
return new GameLogEntry(GameLogEntryType.TURN, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerDamaged ev) {
|
||||
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(GameEventPlayerPoisoned ev) {
|
||||
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(final GameEventAttackersDeclared ev) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Loop through Defenders
|
||||
// Append Defending Player/Planeswalker
|
||||
|
||||
// Not a big fan of the triple nested loop here
|
||||
for (GameEntity k : ev.attackersMap.keySet()) {
|
||||
|
||||
Collection<Card> attackers = ev.attackersMap.get(k);
|
||||
if (attackers == null || attackers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if ( sb.length() > 0 ) sb.append("\n");
|
||||
sb.append(ev.player + " assigned " + Lang.joinHomogenous(attackers));
|
||||
sb.append(" to attack " + k + ".");
|
||||
}
|
||||
if ( sb.length() == 0 )
|
||||
sb.append(ev.player + " didn't attack this turn.");
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(final GameEventBlockersDeclared ev) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Loop through Defenders
|
||||
// Append Defending Player/Planeswalker
|
||||
|
||||
Collection<Card> blockers = null;
|
||||
|
||||
for (Entry<GameEntity, MapOfLists<Card, Card>> kv : ev.blockers.entrySet()) {
|
||||
GameEntity defender = kv.getKey();
|
||||
MapOfLists<Card, Card> attackers = kv.getValue();
|
||||
if (attackers == null || attackers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if ( sb.length() > 0 ) sb.append("\n");
|
||||
|
||||
String controllerName = defender instanceof Card ? ((Card)defender).getController().getName() : defender.getName();
|
||||
boolean firstAttacker = true;
|
||||
for (final Entry<Card, Collection<Card>> att : attackers.entrySet()) {
|
||||
if ( !firstAttacker ) sb.append("\n");
|
||||
|
||||
blockers = att.getValue();
|
||||
if ( blockers.isEmpty() ) {
|
||||
sb.append(controllerName + " didn't block ");
|
||||
} else {
|
||||
sb.append(controllerName + " assigned " + Lang.joinHomogenous(blockers) + " to block ");
|
||||
}
|
||||
|
||||
sb.append(att.getKey()).append(".");
|
||||
firstAttacker = false;
|
||||
}
|
||||
}
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
|
||||
@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());
|
||||
return new GameLogEntry(GameLogEntryType.MULLIGAN, message);
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void recieve(GameEvent ev) {
|
||||
GameLogEntry le = ev.visit(this);
|
||||
if ( le != null )
|
||||
log.add(le);
|
||||
}
|
||||
|
||||
} // end class GameLog
|
||||
@@ -35,6 +35,8 @@ import javax.swing.JLayeredPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Constant.Preferences;
|
||||
import forge.Singletons;
|
||||
@@ -42,7 +44,10 @@ import forge.control.KeyboardShortcuts.Shortcut;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameType;
|
||||
import forge.game.Match;
|
||||
import forge.game.RegisteredPlayer;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.LobbyPlayerAi;
|
||||
import forge.game.player.LobbyPlayerHuman;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.GuiDialog;
|
||||
import forge.gui.SOverlayUtils;
|
||||
@@ -56,6 +61,7 @@ import forge.gui.framework.SOverflowUtil;
|
||||
import forge.gui.framework.SResizingUtil;
|
||||
import forge.gui.home.CHomeUI;
|
||||
import forge.gui.home.VHomeUI;
|
||||
import forge.gui.home.settings.GamePlayerUtil;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.gui.match.VMatchUI;
|
||||
import forge.gui.match.controllers.CDock;
|
||||
@@ -67,6 +73,7 @@ import forge.gui.match.views.VAntes;
|
||||
import forge.gui.menus.ForgeMenu;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.net.FServer;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.properties.NewConstants;
|
||||
import forge.quest.QuestController;
|
||||
@@ -400,7 +407,7 @@ public enum FControl implements KeyEventDispatcher {
|
||||
game.getAction().checkGameOverCondition();
|
||||
else {
|
||||
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();
|
||||
@@ -413,6 +420,7 @@ public enum FControl implements KeyEventDispatcher {
|
||||
|
||||
|
||||
public final void startGameWithUi(Match match) {
|
||||
setPlayerName(match.getPlayers());
|
||||
Game newGame = match.createGame();
|
||||
attachToGame(newGame);
|
||||
match.startGame(newGame, null);
|
||||
@@ -512,5 +520,23 @@ public enum FControl implements KeyEventDispatcher {
|
||||
//Allow the event to be redispatched
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,162 +1,184 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerOutcome;
|
||||
import forge.game.player.PlayerStatistics;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* GameInfo class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @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
|
||||
// only getters) and
|
||||
// GameObserver class - who should be notified of any considerable ingame event
|
||||
public final class GameOutcome implements Iterable<Pair<LobbyPlayer, PlayerStatistics>> {
|
||||
|
||||
|
||||
/** The player got first turn. */
|
||||
// private String playerGotFirstTurn = "Nobody";
|
||||
|
||||
/** The last turn number. */
|
||||
private int lastTurnNumber = 0;
|
||||
|
||||
/** The player rating. */
|
||||
private final List<Pair<LobbyPlayer, PlayerStatistics>> playerRating = new ArrayList<Pair<LobbyPlayer, PlayerStatistics>>(2);
|
||||
|
||||
private GameEndReason winCondition;
|
||||
|
||||
public GameOutcome(GameEndReason reason, final Iterable<Player> list) {
|
||||
winCondition = reason;
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean isWinner(final LobbyPlayer who) {
|
||||
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating)
|
||||
if (pv.getValue().getOutcome().hasWon() && pv.getKey() == who )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the winner.
|
||||
*
|
||||
* @return the winner
|
||||
*/
|
||||
public LobbyPlayer getWinner() {
|
||||
for (Entry<LobbyPlayer, PlayerStatistics> ps : playerRating) {
|
||||
if (ps.getValue().getOutcome().hasWon()) {
|
||||
return ps.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the win condition.
|
||||
*
|
||||
* @return the win condition
|
||||
*/
|
||||
public GameEndReason getWinCondition() {
|
||||
return this.winCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the turn game ended.
|
||||
*
|
||||
* @return the turn game ended
|
||||
*/
|
||||
public int getLastTurnNumber() {
|
||||
return this.lastTurnNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player who got first turn.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* public void setPlayerWhoGotFirstTurn(final String playerName) {
|
||||
* this.playerGotFirstTurn = playerName; }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the win spell effect.
|
||||
*
|
||||
* @return the win spell effect
|
||||
*/
|
||||
public String getWinSpellEffect() {
|
||||
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating) {
|
||||
PlayerOutcome po = pv.getValue().getOutcome();
|
||||
if (po.hasWon()) {
|
||||
return po.altWinSourceName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerOutcome;
|
||||
import forge.game.player.PlayerStatistics;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* GameInfo class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @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
|
||||
// only getters) and
|
||||
// GameObserver class - who should be notified of any considerable ingame event
|
||||
public final class GameOutcome implements Iterable<Pair<LobbyPlayer, PlayerStatistics>> {
|
||||
|
||||
|
||||
/** The player got first turn. */
|
||||
// private String playerGotFirstTurn = "Nobody";
|
||||
|
||||
/** The last turn number. */
|
||||
private int lastTurnNumber = 0;
|
||||
|
||||
/** The player rating. */
|
||||
private final List<Pair<LobbyPlayer, PlayerStatistics>> playerRating = new ArrayList<Pair<LobbyPlayer, PlayerStatistics>>(2);
|
||||
|
||||
private final Iterable<Player> players;
|
||||
|
||||
private GameEndReason winCondition;
|
||||
|
||||
public GameOutcome(GameEndReason reason, final Iterable<Player> list) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean isWinner(final LobbyPlayer who) {
|
||||
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating)
|
||||
if (pv.getValue().getOutcome().hasWon() && pv.getKey() == who )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the winner.
|
||||
*
|
||||
* @return the winner
|
||||
*/
|
||||
public LobbyPlayer getWinningLobbyPlayer() {
|
||||
for (Entry<LobbyPlayer, PlayerStatistics> ps : playerRating) {
|
||||
if (ps.getValue().getOutcome().hasWon()) {
|
||||
return ps.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets winning {@code Player}.
|
||||
* <p>
|
||||
* Alternative to {@link getWinningLobbyPlayer()} which does not
|
||||
* distinguish between human player names (a problem for hotseat games).
|
||||
*/
|
||||
public Player getWinningPlayer() {
|
||||
for (Player p: players) {
|
||||
if (p.getOutcome().hasWon()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the win condition.
|
||||
*
|
||||
* @return the win condition
|
||||
*/
|
||||
public GameEndReason getWinCondition() {
|
||||
return this.winCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the turn game ended.
|
||||
*
|
||||
* @return the turn game ended
|
||||
*/
|
||||
public int getLastTurnNumber() {
|
||||
return this.lastTurnNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player who got first turn.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* public void setPlayerWhoGotFirstTurn(final String playerName) {
|
||||
* this.playerGotFirstTurn = playerName; }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the win spell effect.
|
||||
*
|
||||
* @return the win spell effect
|
||||
*/
|
||||
public String getWinSpellEffect() {
|
||||
for (Pair<LobbyPlayer, PlayerStatistics> pv : playerRating) {
|
||||
PlayerOutcome po = pv.getValue().getOutcome();
|
||||
if (po.hasWon()) {
|
||||
return po.altWinSourceName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,197 +1,197 @@
|
||||
package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.game.event.GameEventAnteCardsSelected;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
|
||||
public class Match {
|
||||
|
||||
private final List<RegisteredPlayer> players;
|
||||
private final GameType gameType;
|
||||
|
||||
private int gamesPerMatch = 3;
|
||||
private int gamesToWinMatch = 2;
|
||||
|
||||
private boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE);
|
||||
|
||||
private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>();
|
||||
private final List<GameOutcome> gamesPlayedRo;
|
||||
|
||||
/**
|
||||
* This should become constructor once.
|
||||
*/
|
||||
public Match(GameType type, List<RegisteredPlayer> players0) {
|
||||
gamesPlayedRo = Collections.unmodifiableList(gamesPlayed);
|
||||
players = Collections.unmodifiableList(Lists.newArrayList(players0));
|
||||
gameType = type;
|
||||
}
|
||||
|
||||
public Match(GameType type, List<RegisteredPlayer> players0, Boolean overrideAnte) {
|
||||
this(type, players0);
|
||||
if( overrideAnte != null )
|
||||
this.useAnte = overrideAnte.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the games played.
|
||||
*
|
||||
* @return the games played
|
||||
*/
|
||||
public final List<GameOutcome> getPlayedGames() {
|
||||
return this.gamesPlayedRo;
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
public int getGamesPerMatch() {
|
||||
return gamesPerMatch;
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
public int getGamesToWinMatch() {
|
||||
return gamesToWinMatch;
|
||||
}
|
||||
|
||||
public void addGamePlayed(Game finished) {
|
||||
if (!finished.isGameOver()) {
|
||||
throw new IllegalStateException("Game is not over yet.");
|
||||
}
|
||||
gamesPlayed.add(finished.getOutcome());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
public Game createGame() {
|
||||
return new Game(players, gameType, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
public void startGame(final Game game, final CountDownLatch latch) {
|
||||
final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed;
|
||||
GameNew.newGame(game, canRandomFoil, this.useAnte);
|
||||
|
||||
// This code could be run run from EDT.
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (useAnte) { // Deciding which cards go to ante
|
||||
List<Pair<Player, Card>> list = GameNew.chooseCardsForAnte(game);
|
||||
GameNew.moveCardsToAnte(list);
|
||||
game.fireEvent(new GameEventAnteCardsSelected(list));
|
||||
}
|
||||
|
||||
GameOutcome lastOutcome = gamesPlayed.isEmpty() ? null : gamesPlayed.get(gamesPlayed.size() - 1);
|
||||
game.getAction().startGame(lastOutcome);
|
||||
|
||||
if( null != latch )
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearGamesPlayed() {
|
||||
gamesPlayed.clear();
|
||||
}
|
||||
|
||||
public void clearLastGame() {
|
||||
gamesPlayed.remove(gamesPlayed.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GameType getGameType() {
|
||||
return gameType;
|
||||
}
|
||||
|
||||
public Iterable<GameOutcome> getOutcomes() {
|
||||
return gamesPlayedRo;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isMatchOver() {
|
||||
int[] victories = new int[players.size()];
|
||||
for (GameOutcome go : gamesPlayed) {
|
||||
LobbyPlayer winner = go.getWinner();
|
||||
int i = 0;
|
||||
for (RegisteredPlayer p : players) {
|
||||
if (p.getPlayer().equals(winner)) {
|
||||
victories[i]++;
|
||||
break; // can't have 2 winners per game
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int score : victories) {
|
||||
if (score >= gamesToWinMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return gamesPlayed.size() >= gamesPerMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param questPlayer
|
||||
* @return
|
||||
*/
|
||||
public int getGamesWonBy(LobbyPlayer questPlayer) {
|
||||
int sum = 0;
|
||||
for (GameOutcome go : gamesPlayed) {
|
||||
if (questPlayer.equals(go.getWinner())) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param questPlayer
|
||||
* @return
|
||||
*/
|
||||
public boolean isWonBy(LobbyPlayer questPlayer) {
|
||||
return getGamesWonBy(questPlayer) >= gamesToWinMatch;
|
||||
}
|
||||
|
||||
public List<RegisteredPlayer> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public static int getPoisonCountersAmountToLose() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
}
|
||||
package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.game.event.GameEventAnteCardsSelected;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
|
||||
public class Match {
|
||||
|
||||
private final List<RegisteredPlayer> players;
|
||||
private final GameType gameType;
|
||||
|
||||
private int gamesPerMatch = 3;
|
||||
private int gamesToWinMatch = 2;
|
||||
|
||||
private boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE);
|
||||
|
||||
private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>();
|
||||
private final List<GameOutcome> gamesPlayedRo;
|
||||
|
||||
/**
|
||||
* This should become constructor once.
|
||||
*/
|
||||
public Match(GameType type, List<RegisteredPlayer> players0) {
|
||||
gamesPlayedRo = Collections.unmodifiableList(gamesPlayed);
|
||||
players = Collections.unmodifiableList(Lists.newArrayList(players0));
|
||||
gameType = type;
|
||||
}
|
||||
|
||||
public Match(GameType type, List<RegisteredPlayer> players0, Boolean overrideAnte) {
|
||||
this(type, players0);
|
||||
if( overrideAnte != null )
|
||||
this.useAnte = overrideAnte.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the games played.
|
||||
*
|
||||
* @return the games played
|
||||
*/
|
||||
public final List<GameOutcome> getPlayedGames() {
|
||||
return this.gamesPlayedRo;
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
public int getGamesPerMatch() {
|
||||
return gamesPerMatch;
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
public int getGamesToWinMatch() {
|
||||
return gamesToWinMatch;
|
||||
}
|
||||
|
||||
public void addGamePlayed(Game finished) {
|
||||
if (!finished.isGameOver()) {
|
||||
throw new IllegalStateException("Game is not over yet.");
|
||||
}
|
||||
gamesPlayed.add(finished.getOutcome());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
public Game createGame() {
|
||||
return new Game(players, gameType, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
public void startGame(final Game game, final CountDownLatch latch) {
|
||||
final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed;
|
||||
GameNew.newGame(game, canRandomFoil, this.useAnte);
|
||||
|
||||
// This code could be run run from EDT.
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (useAnte) { // Deciding which cards go to ante
|
||||
List<Pair<Player, Card>> list = GameNew.chooseCardsForAnte(game);
|
||||
GameNew.moveCardsToAnte(list);
|
||||
game.fireEvent(new GameEventAnteCardsSelected(list));
|
||||
}
|
||||
|
||||
GameOutcome lastOutcome = gamesPlayed.isEmpty() ? null : gamesPlayed.get(gamesPlayed.size() - 1);
|
||||
game.getAction().startGame(lastOutcome);
|
||||
|
||||
if( null != latch )
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearGamesPlayed() {
|
||||
gamesPlayed.clear();
|
||||
}
|
||||
|
||||
public void clearLastGame() {
|
||||
gamesPlayed.remove(gamesPlayed.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GameType getGameType() {
|
||||
return gameType;
|
||||
}
|
||||
|
||||
public Iterable<GameOutcome> getOutcomes() {
|
||||
return gamesPlayedRo;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isMatchOver() {
|
||||
int[] victories = new int[players.size()];
|
||||
for (GameOutcome go : gamesPlayed) {
|
||||
LobbyPlayer winner = go.getWinningLobbyPlayer();
|
||||
int i = 0;
|
||||
for (RegisteredPlayer p : players) {
|
||||
if (p.getPlayer().equals(winner)) {
|
||||
victories[i]++;
|
||||
break; // can't have 2 winners per game
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int score : victories) {
|
||||
if (score >= gamesToWinMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return gamesPlayed.size() >= gamesPerMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param questPlayer
|
||||
* @return
|
||||
*/
|
||||
public int getGamesWonBy(LobbyPlayer questPlayer) {
|
||||
int sum = 0;
|
||||
for (GameOutcome go : gamesPlayed) {
|
||||
if (questPlayer.equals(go.getWinningLobbyPlayer())) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param questPlayer
|
||||
* @return
|
||||
*/
|
||||
public boolean isWonBy(LobbyPlayer questPlayer) {
|
||||
return getGamesWonBy(questPlayer) >= gamesToWinMatch;
|
||||
}
|
||||
|
||||
public List<RegisteredPlayer> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public static int getPoisonCountersAmountToLose() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,16 +52,17 @@ import forge.card.spellability.Ability;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.GameAge;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.RegisteredPlayer;
|
||||
import forge.game.event.GameEventLandPlayed;
|
||||
import forge.game.event.GameEventPlayerLivesChanged;
|
||||
import forge.game.event.GameEventMulligan;
|
||||
import forge.game.event.GameEventPlayerControl;
|
||||
import forge.game.event.GameEventPlayerDamaged;
|
||||
import forge.game.event.GameEventPlayerLivesChanged;
|
||||
import forge.game.event.GameEventPlayerPoisoned;
|
||||
import forge.game.event.GameEventShuffle;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
@@ -72,6 +73,7 @@ import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.GuiDialog;
|
||||
import forge.gui.GuiDisplayUtil;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.Lang;
|
||||
import forge.util.MyRandom;
|
||||
@@ -85,9 +87,9 @@ import forge.util.MyRandom;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
|
||||
private final Map<Card,Integer> commanderDamage = new HashMap<Card,Integer>();
|
||||
|
||||
|
||||
/** The poison counters. */
|
||||
private int poisonCounters = 0;
|
||||
|
||||
@@ -108,7 +110,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
/** The num power surge lands. */
|
||||
private int numPowerSurgeLands;
|
||||
|
||||
|
||||
/** The number of times this player has searched his library. */
|
||||
private int numLibrarySearchedOwn = 0;
|
||||
|
||||
@@ -136,10 +138,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
/** The num drawn this turn. */
|
||||
private int numDrawnThisTurn = 0;
|
||||
private int numDrawnThisDrawStep = 0;
|
||||
|
||||
|
||||
/** The num discarded this turn. */
|
||||
private int numDiscardedThisTurn = 0;
|
||||
|
||||
|
||||
/** A list of tokens not in play, but on their way.
|
||||
* This list is kept in order to not break ETB-replacement
|
||||
* on tokens. */
|
||||
@@ -170,9 +172,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
protected PlayerController controllerCreator = null;
|
||||
|
||||
private int teamNumber = -1;
|
||||
|
||||
|
||||
private Card activeScheme = null;
|
||||
|
||||
|
||||
private Card commander = null;
|
||||
|
||||
/** The Constant ALL_ZONES. */
|
||||
@@ -207,10 +209,19 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
for (final ZoneType z : Player.ALL_ZONES) {
|
||||
final PlayerZone toPut = z == ZoneType.Battlefield
|
||||
? new PlayerZoneBattlefield(z, this)
|
||||
: new PlayerZone(z, this);
|
||||
this.zones.put(z, toPut);
|
||||
: new PlayerZone(z, this);
|
||||
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) {
|
||||
@@ -231,14 +242,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Game getGame() { // I'll probably regret about this
|
||||
public Game getGame() { // I'll probably regret about this
|
||||
return game;
|
||||
}
|
||||
|
||||
|
||||
public final PlayerStatistics getStats() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
public final void setTeam(int iTeam) {
|
||||
teamNumber = iTeam;
|
||||
}
|
||||
@@ -275,7 +286,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
activeScheme = getZone(ZoneType.SchemeDeck).get(0);
|
||||
// gameAction moveTo ?
|
||||
// gameAction moveTo ?
|
||||
getZone(ZoneType.SchemeDeck).remove(activeScheme);
|
||||
this.getZone(ZoneType.Command).add(activeScheme);
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ////////////////////////
|
||||
@@ -469,7 +480,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
runParams.put("Player", this);
|
||||
runParams.put("LifeAmount", lifeGain);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.LifeGained, runParams, false);
|
||||
|
||||
|
||||
game.fireEvent(new GameEventPlayerLivesChanged(this, oldLife, life));
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.assignedDamage.put(source, amount);
|
||||
if (source.hasKeyword("Lifelink")) {
|
||||
source.getController().gainLife(amount, source);
|
||||
@@ -803,7 +814,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
restDamage = restDamage / 2;
|
||||
} else if (c.getName().equals("Benevolent Unicorn")) {
|
||||
if (source.isSpell()) {
|
||||
restDamage -= 1;
|
||||
restDamage -= 1;
|
||||
}
|
||||
} else if (c.getName().equals("Divine Presence")) {
|
||||
if (restDamage > 3) {
|
||||
@@ -942,7 +953,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
if (DEBUGShieldsWithEffects) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -995,8 +1006,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public final Iterable<Card> getAssignedDamageSources() {
|
||||
|
||||
public final Iterable<Card> getAssignedDamageSources() {
|
||||
return assignedDamage.keySet();
|
||||
}
|
||||
|
||||
@@ -1042,7 +1053,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
damageToDo = this.preventDamage(damageToDo, source, true);
|
||||
|
||||
this.addDamageAfterPrevention(damageToDo, source, true); // damage
|
||||
// prevention
|
||||
// prevention
|
||||
// is already
|
||||
// checked
|
||||
|
||||
@@ -1082,7 +1093,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
*
|
||||
* @param num
|
||||
* a int.
|
||||
* @param source
|
||||
* @param source
|
||||
*/
|
||||
public final void setPoisonCounters(final int num, Card source) {
|
||||
int oldPoison = poisonCounters;
|
||||
@@ -1261,8 +1272,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return this.drawCards(1);
|
||||
}
|
||||
|
||||
|
||||
public boolean canMulligan() {
|
||||
|
||||
public boolean canMulligan() {
|
||||
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) {
|
||||
final List<Card> drawn = new ArrayList<Card>();
|
||||
|
||||
|
||||
if (!this.canDraw()) {
|
||||
return drawn;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
||||
|
||||
// TODO: multiple replacements need to be selected by the controller
|
||||
List<Card> dredgers = this.getDredge();
|
||||
if (!dredgers.isEmpty()) {
|
||||
@@ -1299,7 +1310,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drawn.addAll(this.doDraw());
|
||||
}
|
||||
return drawn;
|
||||
@@ -1325,14 +1336,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
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
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
// 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;
|
||||
for(Card c : game.getCardsIn(ZoneType.Battlefield)) {
|
||||
if ( c.getName().equals("Chains of Mephistopheles") ) {
|
||||
@@ -1353,7 +1364,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
AbilityUtils.resolve(saMill);
|
||||
|
||||
return drawn; // Draw is cancelled
|
||||
} else {
|
||||
} else {
|
||||
SpellAbility saDiscard = AbilityFactory.getAbility(c.getSVar("DiscardOne"), c);
|
||||
saDiscard.setActivatingPlayer(c.getController());
|
||||
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()) {
|
||||
|
||||
@@ -1511,7 +1522,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return CardLists.filter(this.getCardsIn(zone), CardPredicates.nameEquals(cardName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<Card> getCardsActivableInExternalZones() {
|
||||
final List<Card> cl = new ArrayList<Card>();
|
||||
|
||||
@@ -1580,7 +1591,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
}
|
||||
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()
|
||||
|
||||
/**
|
||||
@@ -1690,7 +1701,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final int getNumDiscardedThisTurn() {
|
||||
return this.numDiscardedThisTurn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>numDiscardedThisTurn</code>.
|
||||
@@ -1791,7 +1802,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
// Play the shuffle sound
|
||||
game.fireEvent(new GameEventShuffle(this));
|
||||
} // shuffle
|
||||
// //////////////////////////////
|
||||
// //////////////////////////////
|
||||
|
||||
// //////////////////////////////
|
||||
|
||||
@@ -1860,7 +1871,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( land != null && !ignoreZoneAndTiming) {
|
||||
if (land.getOwner() != this && !land.hasKeyword("May be played by your opponent"))
|
||||
return false;
|
||||
@@ -1874,7 +1885,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
// **** Check for land play limit per turn ****
|
||||
// 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;
|
||||
}
|
||||
if (this.isCardInPlay("Fastbond") || this.isCardInCommand("Naya")) {
|
||||
@@ -1979,7 +1990,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
*
|
||||
* @param s
|
||||
* a {@link forge.Card} object.
|
||||
* @return
|
||||
* @return
|
||||
* @return a {@link forge.Card} object.
|
||||
*/
|
||||
public final void setNamedCard(final String s) {
|
||||
@@ -2176,14 +2187,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
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;
|
||||
if (hasNoLife && !this.cantLoseForZeroOrLessLife()) {
|
||||
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
|
||||
// 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) {
|
||||
triedToDrawFromEmptyLibrary = false; // one-shot check
|
||||
return this.loseConditionMet(GameLossReason.Milled, null);
|
||||
@@ -2193,7 +2204,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
if (this.poisonCounters >= 10) {
|
||||
return this.loseConditionMet(GameLossReason.Poisoned, null);
|
||||
}
|
||||
|
||||
|
||||
if(game.getType() == GameType.Commander)
|
||||
{
|
||||
Map<Card,Integer> cmdDmg = getCommanderDamage();
|
||||
@@ -2201,13 +2212,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
{
|
||||
if(cmdDmg.get(c) >= 21)
|
||||
return this.loseConditionMet(GameLossReason.CommanderDamage, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean hasLost() {
|
||||
public final boolean hasLost() {
|
||||
return this.getOutcome() != null && this.getOutcome().lossState != null;
|
||||
}
|
||||
|
||||
@@ -2330,11 +2341,11 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final void resetProwl() {
|
||||
this.prowl = new ArrayList<String>();
|
||||
}
|
||||
|
||||
|
||||
public final void setLibrarySearched(final int l) {
|
||||
this.numLibrarySearchedOwn = l;
|
||||
}
|
||||
|
||||
|
||||
public final int getLibrarySearched() {
|
||||
return this.numLibrarySearchedOwn;
|
||||
}
|
||||
@@ -2378,7 +2389,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
if (incR.length > 1) {
|
||||
final String excR = incR[1];
|
||||
final String[] exR = excR.split("\\+"); // Exclusive Restrictions
|
||||
// are ...
|
||||
// are ...
|
||||
for (int j = 0; j < exR.length; j++) {
|
||||
if (!this.hasProperty(exR[j], sourceController, source)) {
|
||||
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;
|
||||
if (property.substring(7).startsWith("Life") && this.getLife() <= controller.getLife()) {
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
@@ -2624,7 +2635,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final int getLifeGainedThisTurn() {
|
||||
return this.lifeGainedThisTurn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>lifeGainedThisTurn</code>.
|
||||
@@ -2766,11 +2777,11 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final LobbyPlayer getOriginalLobbyPlayer() {
|
||||
return controllerCreator.getLobbyPlayer();
|
||||
}
|
||||
|
||||
|
||||
public final boolean isMindSlaved() {
|
||||
return controller.getLobbyPlayer() != controllerCreator.getLobbyPlayer();
|
||||
}
|
||||
|
||||
|
||||
public final void releaseControl() {
|
||||
if ( controller == controllerCreator )
|
||||
return;
|
||||
@@ -2835,7 +2846,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
public int getCounterDoublersMagnitude(final CounterType type) {
|
||||
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();
|
||||
if (type == CounterType.P1P1) {
|
||||
counterDoublers += getCardsIn(ZoneType.Battlefield, "Corpsejack Menace").size();
|
||||
@@ -2846,9 +2857,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public int getTokenDoublersMagnitude() {
|
||||
final int tokenDoublers = getCardsIn(ZoneType.Battlefield, "Parallel Lives").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();;
|
||||
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() {
|
||||
@@ -2911,7 +2922,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
public final void setFirstController(PlayerController ctrlr) {
|
||||
if( null != controllerCreator ) throw new IllegalStateException("Controller creator already assigned");
|
||||
controllerCreator = ctrlr;
|
||||
controllerCreator = 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.
|
||||
* Then runs triggers.
|
||||
* Then runs triggers.
|
||||
*/
|
||||
public void planeswalk()
|
||||
{
|
||||
planeswalkTo(Arrays.asList(getZone(ZoneType.PlanarDeck).get(0)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Puts the planes in the argument and puts them face up in the command zone.
|
||||
* Then runs triggers.
|
||||
@@ -3003,19 +3014,19 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
getZone(ZoneType.PlanarDeck).remove(c);
|
||||
getZone(ZoneType.Command).add(c);
|
||||
}
|
||||
|
||||
|
||||
//DBG
|
||||
//System.out.println("CurrentPlanes: " + currentPlanes);
|
||||
//System.out.println("ActivePlanes: " + game.getActivePlanes());
|
||||
//System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards());
|
||||
|
||||
|
||||
game.setActivePlanes(currentPlanes);
|
||||
//Run PlaneswalkedTo triggers here.
|
||||
HashMap<String,Object> runParams = new HashMap<String,Object>();
|
||||
runParams.put("Card", currentPlanes);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedTo, runParams,false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 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())
|
||||
{
|
||||
//Run PlaneswalkedFrom triggers here.
|
||||
//Run PlaneswalkedFrom triggers here.
|
||||
HashMap<String,Object> runParams = new HashMap<String,Object>();
|
||||
runParams.put("Card", new ArrayList<Card>(currentPlanes));
|
||||
game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedFrom, runParams,false);
|
||||
|
||||
|
||||
for(Card c : currentPlanes) {
|
||||
game.getZoneOf(c).remove(c);
|
||||
c.clearControllers();
|
||||
@@ -3042,7 +3053,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
//System.out.println("ActivePlanes: " + game.getActivePlanes());
|
||||
//System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Sets up the first plane of a round.
|
||||
@@ -3065,7 +3076,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
game.setActivePlanes(currentPlanes);
|
||||
}
|
||||
|
||||
@@ -3080,7 +3091,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final void resetAttackedThisCombat() {
|
||||
// resets the status of attacked/blocked this phase
|
||||
List<Card> list = CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.CREATURES);
|
||||
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
final Card c = list.get(i);
|
||||
if (c.getDamageHistory().getCreatureAttackedThisCombat()) {
|
||||
@@ -3089,7 +3100,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
if (c.getDamageHistory().getCreatureBlockedThisCombat()) {
|
||||
c.getDamageHistory().setCreatureBlockedThisCombat(false);
|
||||
}
|
||||
|
||||
|
||||
if (c.getDamageHistory().getCreatureGotBlockedThisCombat()) {
|
||||
c.getDamageHistory().setCreatureGotBlockedThisCombat(false);
|
||||
}
|
||||
@@ -3120,41 +3131,41 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
miracleTrigger.setStackDescription(card.getName() + " - Miracle.");
|
||||
miracleTrigger.setActivatingPlayer(card.getOwner());
|
||||
miracleTrigger.setTrigger(true);
|
||||
|
||||
|
||||
game.getStack().add(miracleTrigger);
|
||||
}
|
||||
|
||||
public boolean isSkippingDraw() {
|
||||
|
||||
|
||||
if (hasKeyword("Skip your next draw step.")) {
|
||||
removeKeyword("Skip your next draw step.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (hasKeyword("Skip your draw step.")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void addInboundToken(Card c)
|
||||
{
|
||||
inboundTokens.add(c);
|
||||
}
|
||||
|
||||
|
||||
public void removeInboundToken(Card c)
|
||||
{
|
||||
inboundTokens.remove(c);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
private final class MiracleTrigger extends Ability {
|
||||
private final SpellAbility miracle;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param sourceCard
|
||||
@@ -3165,7 +3176,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
super(sourceCard, manaCost);
|
||||
this.miracle = miracle;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void resolve() {
|
||||
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) {
|
||||
this.isPlayingExtraTrun = b;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3219,4 +3230,15 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public boolean isPlayingExtraTurn() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@@ -53,8 +54,9 @@ import forge.game.player.HumanPlay;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.input.InputSelectCardsFromList;
|
||||
import forge.item.PaperCard;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.PaperCard;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
|
||||
public final class 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("humancardsinexile")) humanCardTexts.put(ZoneType.Exile, categoryValue);
|
||||
else if (categoryName.equals("aicardsinexile")) aiCardTexts.put(ZoneType.Exile, categoryValue);
|
||||
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
final Map<ZoneType, String> aiCardTexts, final String tChangePlayer, final String tChangePhase) {
|
||||
|
||||
|
||||
final Game game = getGame();
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
@@ -148,17 +150,17 @@ public final class GuiDisplayUtil {
|
||||
|
||||
Player newPlayerTurn = tChangePlayer.equals("human") ? newPlayerTurn = human : tChangePlayer.equals("ai") ? newPlayerTurn = ai : null;
|
||||
PhaseType newPhase = tChangePhase.trim().equalsIgnoreCase("none") ? null : PhaseType.smartValueOf(tChangePhase);
|
||||
|
||||
|
||||
game.getPhaseHandler().devModeSet(newPhase, newPlayerTurn);
|
||||
|
||||
|
||||
|
||||
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
|
||||
|
||||
devSetupPlayerState(humanLife, humanCardTexts, human);
|
||||
devSetupPlayerState(computerLife, aiCardTexts, ai);
|
||||
|
||||
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
|
||||
|
||||
game.getAction().checkStaticAbilities();
|
||||
}
|
||||
});
|
||||
@@ -242,7 +244,7 @@ public final class GuiDisplayUtil {
|
||||
final Card c = GuiChoose.oneOrNone("Choose a card", lib);
|
||||
if (null == c)
|
||||
return;
|
||||
|
||||
|
||||
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() {
|
||||
final Game game = getGame();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
@@ -380,7 +382,7 @@ public final class GuiDisplayUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
getGame().getAction().invoke(new Runnable() { @Override public void run() {
|
||||
getGame().getAction().invoke(new Runnable() { @Override public void run() {
|
||||
Card forgeCard = c.toForgeCard(p);
|
||||
getGame().getAction().moveToHand(forgeCard);
|
||||
}});
|
||||
@@ -410,20 +412,20 @@ public final class GuiDisplayUtil {
|
||||
if (c.getRules().getType().isLand()) {
|
||||
forgeCard.setOwner(p);
|
||||
game.getAction().moveToPlay(forgeCard);
|
||||
|
||||
|
||||
} else {
|
||||
final List<SpellAbility> choices = forgeCard.getBasicSpells();
|
||||
if (choices.isEmpty()) {
|
||||
return; // when would it happen?
|
||||
}
|
||||
|
||||
|
||||
final SpellAbility sa = choices.size() == 1 ? choices.get(0) : GuiChoose.oneOrNone("Choose", choices);
|
||||
if (sa == null) {
|
||||
return; // happens if cancelled
|
||||
}
|
||||
|
||||
game.getAction().moveToHand(forgeCard); // this is really needed (for rollbacks at least)
|
||||
// Human player is choosing targets for an ability controlled by chosen player.
|
||||
|
||||
game.getAction().moveToHand(forgeCard); // this is really needed (for rollbacks at least)
|
||||
// Human player is choosing targets for an ability controlled by chosen player.
|
||||
sa.setActivatingPlayer(p);
|
||||
HumanPlay.playSaWithoutPayingManaCost(game, sa, true);
|
||||
}
|
||||
@@ -440,26 +442,26 @@ public final class GuiDisplayUtil {
|
||||
if (null == p) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PlanarDice res = GuiChoose.oneOrNone("Choose result", PlanarDice.values());
|
||||
if(res == null)
|
||||
return;
|
||||
|
||||
|
||||
System.out.println("Rigging planar dice roll: " + res.toString());
|
||||
|
||||
//DBG
|
||||
//System.out.println("ActivePlanes: " + getGame().getActivePlanes());
|
||||
//System.out.println("CommandPlanes: " + getGame().getCardsIn(ZoneType.Command));
|
||||
|
||||
|
||||
PlanarDice.roll(p, res);
|
||||
|
||||
|
||||
getGame().getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
p.getGame().getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void devModePlaneswalkTo() {
|
||||
@@ -496,5 +498,14 @@ public final class GuiDisplayUtil {
|
||||
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
|
||||
|
||||
@@ -3,12 +3,16 @@ package forge.gui.home.settings;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import forge.Command;
|
||||
@@ -21,15 +25,12 @@ import forge.game.ai.AiProfileUtil;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.gui.framework.SLayoutIO;
|
||||
import forge.gui.toolbox.FComboBoxPanel;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.properties.ForgePreferences;
|
||||
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.
|
||||
*
|
||||
* <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 {
|
||||
/** */
|
||||
SINGLETON_INSTANCE;
|
||||
|
||||
|
||||
private VSubmenuPreferences view;
|
||||
private ForgePreferences prefs;
|
||||
|
||||
|
||||
private final List<Pair<JCheckBox, FPref>> lstControls = new ArrayList<Pair<JCheckBox,FPref>>();
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -50,11 +51,11 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
@SuppressWarnings("serial")
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
|
||||
this.view = VSubmenuPreferences.SINGLETON_INSTANCE;
|
||||
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() {
|
||||
@Override
|
||||
public void itemStateChanged(final ItemEvent arg0) {
|
||||
@@ -64,8 +65,8 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
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.getCbManaBurn(), FPref.UI_MANABURN));
|
||||
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.getCbUploadDraft(), FPref.UI_UPLOAD_DRAFT));
|
||||
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.getCbEnableSounds(), FPref.UI_ENABLE_SOUNDS));
|
||||
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.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.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.getCbUseThemedComboBox(), FPref.UI_THEMED_COMBOBOX));
|
||||
lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS));
|
||||
@@ -105,39 +106,41 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
CSubmenuPreferences.this.resetForgeSettingsToDefault();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
view.getBtnDeleteEditorUI().setCommand(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
CSubmenuPreferences.this.resetDeckEditorLayout();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
view.getBtnDeleteMatchUI().setCommand(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
CSubmenuPreferences.this.resetMatchScreenLayout();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
initializeGameLogVerbosityComboBox();
|
||||
initializeAiProfilesComboBox();
|
||||
initializeSkinsComboBox();
|
||||
|
||||
initializeSkinsComboBox();
|
||||
initializePlayerNameButton();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.control.home.IControlSubmenu#update()
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
|
||||
|
||||
this.view = VSubmenuPreferences.SINGLETON_INSTANCE;
|
||||
this.prefs = Singletons.getModel().getPreferences();
|
||||
|
||||
|
||||
setPlayerNameButtonText();
|
||||
view.getCbDevMode().setSelected(prefs.getPrefBoolean(FPref.DEV_MODE_ENABLED));
|
||||
|
||||
|
||||
for(Pair<JCheckBox, FPref> kv: lstControls) {
|
||||
kv.getKey().setSelected(prefs.getPrefBoolean(kv.getValue()));
|
||||
}
|
||||
@@ -147,7 +150,7 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
@Override public void run() { view.getCbRemoveSmall().requestFocusInWindow(); }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
|
||||
*/
|
||||
@@ -155,50 +158,50 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
public Command getCommandOnSelect() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void resetForgeSettingsToDefault() {
|
||||
String userPrompt =
|
||||
String userPrompt =
|
||||
"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);
|
||||
if (reply == JOptionPane.YES_OPTION) {
|
||||
ForgePreferences prefs = Singletons.getModel().getPreferences();
|
||||
prefs.reset();
|
||||
prefs.save();
|
||||
update();
|
||||
RestartUtil.restartApplication(null);
|
||||
}
|
||||
update();
|
||||
RestartUtil.restartApplication(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void resetDeckEditorLayout() {
|
||||
String userPrompt =
|
||||
String userPrompt =
|
||||
"This will reset the Deck Editor screen layout.\n" +
|
||||
"All tabbed views will be restored to their default positions.\n\n" +
|
||||
"Reset layout?";
|
||||
"All tabbed views will be restored to their default positions.\n\n" +
|
||||
"Reset layout?";
|
||||
int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Deck Editor Layout", JOptionPane.YES_NO_OPTION);
|
||||
if (reply == JOptionPane.YES_OPTION) {
|
||||
deleteScreenLayoutFile(Screens.DECK_EDITOR_CONSTRUCTED);
|
||||
JOptionPane.showMessageDialog(null, "Deck Editor layout has been reset.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void resetMatchScreenLayout() {
|
||||
String userPrompt =
|
||||
String userPrompt =
|
||||
"This will reset the layout of the Match screen.\n" +
|
||||
"If you want to save the current layout first, please use " +
|
||||
"the Dock tab -> Save Layout option in the Match screen.\n\n" +
|
||||
"Reset layout?";
|
||||
"If you want to save the current layout first, please use " +
|
||||
"the Dock tab -> Save Layout option in the Match screen.\n\n" +
|
||||
"Reset layout?";
|
||||
int reply = JOptionPane.showConfirmDialog(null, userPrompt, "Reset Match Screen Layout", JOptionPane.YES_NO_OPTION);
|
||||
if (reply == JOptionPane.YES_OPTION) {
|
||||
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) {
|
||||
String fd = SLayoutIO.getFilePreferred(screen);
|
||||
File f = new File(fd);
|
||||
f.delete();
|
||||
f.delete();
|
||||
}
|
||||
|
||||
private void initializeGameLogVerbosityComboBox() {
|
||||
@@ -207,16 +210,16 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
JComboBox<GameLogEntryType> comboBox = createComboBox(GameLogEntryType.values(), userSetting);
|
||||
GameLogEntryType selectedItem = GameLogEntryType.valueOf(this.prefs.getPref(userSetting));
|
||||
panel.setComboBox(comboBox, selectedItem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initializeAiProfilesComboBox() {
|
||||
FPref userSetting = FPref.UI_CURRENT_AI_PROFILE;
|
||||
FPref userSetting = FPref.UI_CURRENT_AI_PROFILE;
|
||||
FComboBoxPanel<String> panel = this.view.getAiProfilesComboBoxPanel();
|
||||
JComboBox<String> comboBox = createComboBox(AiProfileUtil.getProfilesArray(), userSetting);
|
||||
String selectedItem = this.prefs.getPref(userSetting);
|
||||
panel.setComboBox(comboBox, selectedItem);
|
||||
panel.setComboBox(comboBox, selectedItem);
|
||||
}
|
||||
|
||||
|
||||
private void initializeSkinsComboBox() {
|
||||
final FComboBoxPanel<String> panel = this.view.getSkinsComboBoxPanel();
|
||||
String[] installedSkins = FSkin.getSkinNamesArray(true);
|
||||
@@ -242,13 +245,13 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
this.prefs.setPref(FPref.UI_SKIN, "Default");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private <E> JComboBox<E> createComboBox(E[] items, final ForgePreferences.FPref setting) {
|
||||
final JComboBox<E> comboBox = new JComboBox<E>(items);
|
||||
addComboBoxListener(comboBox, setting);
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
|
||||
private <E> void addComboBoxListener(final JComboBox<E> comboBox, final ForgePreferences.FPref setting) {
|
||||
comboBox.addItemListener(new ItemListener() {
|
||||
@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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
70
src/main/java/forge/gui/home/settings/GamePlayerUtil.java
Normal file
70
src/main/java/forge/gui/home/settings/GamePlayerUtil.java
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package forge.gui.home.settings;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
@@ -17,6 +18,7 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -38,7 +40,7 @@ import forge.gui.toolbox.FScrollPane;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Assembles Swing components of preferences submenu singleton.
|
||||
*
|
||||
* <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 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 btnPlayerName = new FLabel.Builder().opaque(true).hoverable(true).text("").build();
|
||||
|
||||
private final JCheckBox cbRemoveSmall = new OptionsCheckBox("Remove Small Creatures");
|
||||
private final JCheckBox cbSingletons = new OptionsCheckBox("Singleton Mode");
|
||||
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>();
|
||||
|
||||
// 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<String> cbpAiProfiles = new FComboBoxPanel<String>("AI Personality:");
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
private VSubmenuPreferences() {
|
||||
|
||||
|
||||
pnlPrefs.setOpaque(false);
|
||||
pnlPrefs.setLayout(new MigLayout("insets 0, gap 0, wrap 2"));
|
||||
|
||||
// Spacing between components is defined here.
|
||||
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";
|
||||
|
||||
|
||||
|
||||
|
||||
// Troubleshooting
|
||||
pnlPrefs.add(new SectionLabel("Troubleshooting"), sectionConstraints);
|
||||
|
||||
|
||||
//pnlPrefs.add(new SectionLabel(" "), sectionConstraints);
|
||||
pnlPrefs.add(btnReset, regularConstraints + ", h 30px!");
|
||||
|
||||
|
||||
final String twoButtonConstraints = "w 38%!, h 30px!, gap 10% 0 0 10px";
|
||||
pnlPrefs.add(btnDeleteMatchUI, twoButtonConstraints);
|
||||
pnlPrefs.add(btnDeleteEditorUI, "w 38%!, h 30px!, gap 0 0 0 10px");
|
||||
// Reset button
|
||||
|
||||
|
||||
|
||||
// General Configuration
|
||||
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(new NoteLabel("Enable for a space efficient sidebar that displays only one menu group at a time (RESTART REQUIRED)."), regularConstraints);
|
||||
|
||||
|
||||
|
||||
|
||||
// Gameplay Options
|
||||
pnlPrefs.add(new SectionLabel("Gameplay"), sectionConstraints + ", gaptop 2%");
|
||||
|
||||
|
||||
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(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(new NoteLabel("Disables artifact cards in generated decks."), regularConstraints);
|
||||
|
||||
|
||||
// Advanced
|
||||
pnlPrefs.add(new SectionLabel("Advanced Settings"), sectionConstraints);
|
||||
|
||||
@@ -174,10 +180,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
pnlPrefs.add(cbUseThemedComboBox, regularConstraints);
|
||||
pnlPrefs.add(new NoteLabel("Turn off if you are having combo-box color clash (RESTART REQUIRED)."), regularConstraints);
|
||||
|
||||
|
||||
|
||||
// Themes
|
||||
pnlPrefs.add(new SectionLabel("Visual Themes"), sectionConstraints + ", gaptop 2%");
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@@ -207,7 +213,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
pnlPrefs.add(cbOverlayCardPower, regularConstraints);
|
||||
pnlPrefs.add(cbOverlayCardManaCost, regularConstraints);
|
||||
|
||||
|
||||
|
||||
// Sound options
|
||||
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(new NoteLabel("Use the alternate sound system (only use in case your have issues with sound not playing or disappearing)"), regularConstraints);
|
||||
|
||||
|
||||
|
||||
|
||||
// Keyboard shortcuts
|
||||
final JLabel lblShortcuts = new SectionLabel("Keyboard Shortcuts");
|
||||
pnlPrefs.add(lblShortcuts, sectionConstraints + ", gaptop 2%");
|
||||
@@ -234,7 +240,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
|
||||
scrContent.setBorder(null);
|
||||
}
|
||||
|
||||
|
||||
public void reloadShortcuts() {
|
||||
for (Map.Entry<FPref, KeyboardShortcutField> e : shortcutFields.entrySet()) {
|
||||
e.getValue().reload(e.getKey());
|
||||
@@ -396,11 +402,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
this.setText(StringUtils.join(displayText, ' '));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public final JCheckBox getCbCompactMainMenu() {
|
||||
return cbCompactMainMenu;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public final JCheckBox getCbRemoveSmall() {
|
||||
@@ -441,7 +447,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
public JCheckBox getCbOverlayCardManaCost() {
|
||||
return cbOverlayCardManaCost;
|
||||
}
|
||||
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public JCheckBox getCbRandomFoil() {
|
||||
return cbRandomFoil;
|
||||
@@ -471,7 +477,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
public JCheckBox getCbDevMode() {
|
||||
return cbDevMode;
|
||||
}
|
||||
|
||||
|
||||
public FComboBoxPanel<String> getAiProfilesComboBoxPanel() {
|
||||
return cbpAiProfiles;
|
||||
}
|
||||
@@ -479,11 +485,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() {
|
||||
return cbpGameLogEntryType;
|
||||
}
|
||||
|
||||
|
||||
public FComboBoxPanel<String> getSkinsComboBoxPanel() {
|
||||
return cbpSkin;
|
||||
}
|
||||
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public JCheckBox getCbEnforceDeckLegality() {
|
||||
return cbEnforceDeckLegality;
|
||||
@@ -506,7 +512,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public JCheckBox getCbAltSoundSystem() {
|
||||
return cbAltSoundSystem;
|
||||
return cbAltSoundSystem;
|
||||
}
|
||||
|
||||
public final JCheckBox getCbUiForTouchScreen() {
|
||||
@@ -517,17 +523,21 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
public FLabel getBtnReset() {
|
||||
return btnReset;
|
||||
}
|
||||
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public JCheckBox getCbShowMatchBackgroundImage() {
|
||||
return cbShowMatchBackgroundImage;
|
||||
}
|
||||
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public JCheckBox getCbUseThemedComboBox() {
|
||||
return cbUseThemedComboBox;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public FLabel getBtnPlayerName() {
|
||||
return btnPlayerName;
|
||||
}
|
||||
|
||||
//========== Overridden from IVDoc
|
||||
|
||||
public final FLabel getBtnDeleteMatchUI() {
|
||||
@@ -577,4 +587,13 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
public DragCell getParentCell() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public class QuestWinLose extends ControlWinLose {
|
||||
|
||||
// Ante returns to owners in a draw
|
||||
if (!outcome.isDraw()) {
|
||||
boolean isHumanWinner = outcome.getWinner().equals(questPlayer);
|
||||
boolean isHumanWinner = outcome.getWinningLobbyPlayer().equals(questPlayer);
|
||||
final List<PaperCard> anteCards = new ArrayList<PaperCard>();
|
||||
for (Player p : lastGame.getRegisteredPlayers()) {
|
||||
if (p.getLobbyPlayer().equals(questPlayer) == isHumanWinner) {
|
||||
|
||||
@@ -1,228 +1,238 @@
|
||||
package forge.gui.match;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import forge.Command;
|
||||
import forge.GameLog;
|
||||
import forge.GameLogEntry;
|
||||
import forge.GameLogEntryType;
|
||||
import forge.Singletons;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameOutcome;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.PlayerStatistics;
|
||||
import forge.gui.toolbox.FButton;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.FOverlay;
|
||||
import forge.gui.toolbox.FScrollPane;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.gui.toolbox.FTextArea;
|
||||
import forge.net.FServer;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class ViewWinLose {
|
||||
private final FButton btnContinue, btnRestart, btnQuit;
|
||||
private final JPanel pnlCustom;
|
||||
|
||||
private final JLabel lblTitle = new JLabel("WinLoseFrame > lblTitle needs updating.");
|
||||
private final JLabel lblStats = new JLabel("WinLoseFrame > lblStats needs updating.");
|
||||
private final JPanel pnlOutcomes = new JPanel(new MigLayout("wrap, align center"));
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public ViewWinLose(final Game game) {
|
||||
final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
|
||||
|
||||
final JPanel pnlLeft = new JPanel();
|
||||
final JPanel pnlRight = new JPanel();
|
||||
final JScrollPane scrCustom = new JScrollPane();
|
||||
pnlCustom = new JPanel();
|
||||
|
||||
btnContinue = new FButton();
|
||||
btnRestart = new FButton();
|
||||
btnQuit = new FButton();
|
||||
|
||||
// Control of the win/lose is handled differently for various game modes.
|
||||
ControlWinLose control = null;
|
||||
switch (game.getType()) {
|
||||
case Quest:
|
||||
control = new QuestWinLose(this, game);
|
||||
break;
|
||||
case Draft:
|
||||
if (!Singletons.getModel().getGauntletMini().isGauntletDraft()) {
|
||||
break;
|
||||
}
|
||||
case Sealed:
|
||||
control = new LimitedWinLose(this, game);
|
||||
break;
|
||||
case Gauntlet:
|
||||
control = new GauntletWinLose(this, game);
|
||||
break;
|
||||
default: // will catch it after switch
|
||||
break;
|
||||
}
|
||||
if (null == control) {
|
||||
control = new ControlWinLose(this, game);
|
||||
}
|
||||
|
||||
|
||||
pnlLeft.setOpaque(false);
|
||||
pnlRight.setOpaque(false);
|
||||
pnlCustom.setOpaque(false);
|
||||
scrCustom.setOpaque(false);
|
||||
scrCustom.setBorder(null);
|
||||
scrCustom.getVerticalScrollBar().setUnitIncrement(16);
|
||||
scrCustom.getViewport().setOpaque(false);
|
||||
scrCustom.getViewport().add(pnlCustom);
|
||||
|
||||
lblTitle.setForeground(Color.white);
|
||||
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
FSkin.get(lblTitle).setFont(FSkin.getBoldFont(30));
|
||||
|
||||
lblStats.setForeground(Color.white);
|
||||
lblStats.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
FSkin.get(lblStats).setFont(FSkin.getFont(26));
|
||||
|
||||
btnContinue.setText("Continue");
|
||||
FSkin.get(btnContinue).setFont(FSkin.getFont(22));
|
||||
btnRestart.setText("Restart");
|
||||
FSkin.get(btnRestart).setFont(FSkin.getFont(22));
|
||||
btnQuit.setText("Quit");
|
||||
FSkin.get(btnQuit).setFont(FSkin.getFont(22));
|
||||
btnContinue.setEnabled(!game.getMatch().isMatchOver());
|
||||
|
||||
// Assemble game log scroller.
|
||||
final FTextArea txtLog = new FTextArea();
|
||||
txtLog.setText(game.getGameLog().getLogText(null));
|
||||
FSkin.get(txtLog).setFont(FSkin.getFont(14));
|
||||
txtLog.setFocusable(true); // allow highlighting and copying of log
|
||||
|
||||
FLabel btnCopyLog = new FLabel.ButtonBuilder().text("Copy to clipboard").build();
|
||||
btnCopyLog.setCommand(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
StringSelection ss = new StringSelection(txtLog.getText());
|
||||
try {
|
||||
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"));
|
||||
pnlRight.setLayout(new MigLayout("insets 0, wrap"));
|
||||
pnlCustom.setLayout(new MigLayout("insets 0, wrap, align center"));
|
||||
|
||||
final boolean customIsPopulated = control.populateCustomPanel();
|
||||
if (customIsPopulated) {
|
||||
overlay.add(pnlLeft, "w 40%!, h 100%!");
|
||||
overlay.add(pnlRight, "w 60%!, h 100%!");
|
||||
pnlRight.add(scrCustom, "w 100%!, h 100%!");
|
||||
}
|
||||
else {
|
||||
overlay.add(pnlLeft, "w 100%!, h 100%!");
|
||||
}
|
||||
|
||||
pnlOutcomes.setOpaque(false);
|
||||
pnlLeft.add(lblTitle, "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"));
|
||||
pnlButtons.setOpaque(false);
|
||||
|
||||
final String constraints = "w 300px!, h 50px!, gap 0 0 20px 0";
|
||||
pnlButtons.add(btnContinue, constraints);
|
||||
pnlButtons.add(btnRestart, constraints);
|
||||
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);
|
||||
scrLog.setBorder(null);
|
||||
pnlLog.setOpaque(false);
|
||||
|
||||
pnlLog.add(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");
|
||||
pnlLeft.add(pnlLog, "w 100%!");
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scrLog.getViewport().setViewPosition(new Point(0, 0));
|
||||
// populateCustomPanel may have changed which buttons are enabled; focus on the 'best' one
|
||||
if (btnContinue.isEnabled()) {
|
||||
btnContinue.requestFocusInWindow();
|
||||
} else {
|
||||
btnQuit.requestFocusInWindow();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
lblTitle.setText(composeTitle(game.getOutcome()));
|
||||
|
||||
GameLog log = game.getGameLog();
|
||||
|
||||
for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.GAME_OUTCOME))
|
||||
pnlOutcomes.add(new FLabel.Builder().text(o.message).fontSize(14).build(), "h 20!");
|
||||
|
||||
for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.MATCH_RESULTS))
|
||||
lblStats.setText(o.message);
|
||||
}
|
||||
|
||||
private String composeTitle(GameOutcome outcome) {
|
||||
LobbyPlayer guiPlayer = FServer.instance.getLobby().getGuiPlayer();
|
||||
int nHumansInGame = 0;
|
||||
for(Pair<LobbyPlayer, PlayerStatistics> pps : outcome) {
|
||||
if( pps.getKey() == guiPlayer )
|
||||
nHumansInGame++;
|
||||
}
|
||||
LobbyPlayer winner = outcome.getWinner();
|
||||
if ( winner == null )
|
||||
return "It's a draw!";
|
||||
|
||||
return nHumansInGame == 1 ? "You " + (winner == guiPlayer ? "won!" : "lost!") : winner.getName() + " Won!";
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.toolbox.FButton} */
|
||||
public FButton getBtnContinue() {
|
||||
return this.btnContinue;
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.toolbox.FButton} */
|
||||
public FButton getBtnRestart() {
|
||||
return this.btnRestart;
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.toolbox.FButton} */
|
||||
public FButton getBtnQuit() {
|
||||
return this.btnQuit;
|
||||
}
|
||||
|
||||
/** @return {@link javax.swing.JPanel} */
|
||||
public JPanel getPnlCustom() {
|
||||
return this.pnlCustom;
|
||||
}
|
||||
}
|
||||
package forge.gui.match;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import forge.Command;
|
||||
import forge.GameLog;
|
||||
import forge.GameLogEntry;
|
||||
import forge.GameLogEntryType;
|
||||
import forge.Singletons;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameOutcome;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.toolbox.FButton;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.FOverlay;
|
||||
import forge.gui.toolbox.FScrollPane;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.gui.toolbox.FTextArea;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class ViewWinLose {
|
||||
private final FButton btnContinue, btnRestart, btnQuit;
|
||||
private final JPanel pnlCustom;
|
||||
|
||||
private final JLabel lblTitle = new JLabel("WinLoseFrame > lblTitle needs updating.");
|
||||
private final JLabel lblStats = new JLabel("WinLoseFrame > lblStats needs updating.");
|
||||
private final JPanel pnlOutcomes = new JPanel(new MigLayout("wrap, align center"));
|
||||
|
||||
private final Game game;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public ViewWinLose(final Game game0) {
|
||||
|
||||
game = game0;
|
||||
|
||||
final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
|
||||
|
||||
final JPanel pnlLeft = new JPanel();
|
||||
final JPanel pnlRight = new JPanel();
|
||||
final JScrollPane scrCustom = new JScrollPane();
|
||||
pnlCustom = new JPanel();
|
||||
|
||||
btnContinue = new FButton();
|
||||
btnRestart = new FButton();
|
||||
btnQuit = new FButton();
|
||||
|
||||
// Control of the win/lose is handled differently for various game
|
||||
// modes.
|
||||
ControlWinLose control = null;
|
||||
switch (game0.getType()) {
|
||||
case Quest:
|
||||
control = new QuestWinLose(this, game0);
|
||||
break;
|
||||
case Draft:
|
||||
if (!Singletons.getModel().getGauntletMini().isGauntletDraft()) {
|
||||
break;
|
||||
}
|
||||
case Sealed:
|
||||
control = new LimitedWinLose(this, game0);
|
||||
break;
|
||||
case Gauntlet:
|
||||
control = new GauntletWinLose(this, game0);
|
||||
break;
|
||||
default: // will catch it after switch
|
||||
break;
|
||||
}
|
||||
if (null == control) {
|
||||
control = new ControlWinLose(this, game0);
|
||||
}
|
||||
|
||||
pnlLeft.setOpaque(false);
|
||||
pnlRight.setOpaque(false);
|
||||
pnlCustom.setOpaque(false);
|
||||
scrCustom.setOpaque(false);
|
||||
scrCustom.setBorder(null);
|
||||
scrCustom.getVerticalScrollBar().setUnitIncrement(16);
|
||||
scrCustom.getViewport().setOpaque(false);
|
||||
scrCustom.getViewport().add(pnlCustom);
|
||||
|
||||
lblTitle.setForeground(Color.white);
|
||||
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
FSkin.get(lblTitle).setFont(FSkin.getBoldFont(30));
|
||||
|
||||
lblStats.setForeground(Color.white);
|
||||
lblStats.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
FSkin.get(lblStats).setFont(FSkin.getFont(26));
|
||||
|
||||
btnContinue.setText("Next Game");
|
||||
FSkin.get(btnContinue).setFont(FSkin.getFont(22));
|
||||
btnRestart.setText("Start New Match");
|
||||
FSkin.get(btnRestart).setFont(FSkin.getFont(22));
|
||||
btnQuit.setText("Quit Match");
|
||||
FSkin.get(btnQuit).setFont(FSkin.getFont(22));
|
||||
btnContinue.setEnabled(!game0.getMatch().isMatchOver());
|
||||
|
||||
// Assemble game log scroller.
|
||||
final FTextArea txtLog = new FTextArea();
|
||||
txtLog.setText(game.getGameLog().getLogText(null).replace("[COMPUTER]", "[AI]"));
|
||||
FSkin.get(txtLog).setFont(FSkin.getFont(14));
|
||||
txtLog.setFocusable(true); // allow highlighting and copying of log
|
||||
|
||||
FLabel btnCopyLog = new FLabel.ButtonBuilder().text("Copy to clipboard").build();
|
||||
btnCopyLog.setCommand(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
StringSelection ss = new StringSelection(txtLog.getText());
|
||||
try {
|
||||
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"));
|
||||
pnlRight.setLayout(new MigLayout("insets 0, wrap"));
|
||||
pnlCustom.setLayout(new MigLayout("insets 0, wrap, align center"));
|
||||
|
||||
final boolean customIsPopulated = control.populateCustomPanel();
|
||||
if (customIsPopulated) {
|
||||
overlay.add(pnlLeft, "w 40%!, h 100%!");
|
||||
overlay.add(pnlRight, "w 60%!, h 100%!");
|
||||
pnlRight.add(scrCustom, "w 100%!, h 100%!");
|
||||
} else {
|
||||
overlay.add(pnlLeft, "w 100%!, h 100%!");
|
||||
}
|
||||
|
||||
pnlOutcomes.setOpaque(false);
|
||||
pnlLeft.add(lblTitle, "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"));
|
||||
pnlButtons.setOpaque(false);
|
||||
|
||||
final String constraints = "w 300px!, h 50px!, gap 0 0 20px 0";
|
||||
pnlButtons.add(btnContinue, constraints);
|
||||
pnlButtons.add(btnRestart, constraints);
|
||||
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);
|
||||
scrLog.setBorder(null);
|
||||
pnlLog.setOpaque(false);
|
||||
|
||||
pnlLog.add(
|
||||
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");
|
||||
pnlLeft.add(pnlLog, "w 100%!");
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scrLog.getViewport().setViewPosition(new Point(0, 0));
|
||||
// populateCustomPanel may have changed which buttons are
|
||||
// enabled; focus on the 'best' one
|
||||
if (btnContinue.isEnabled()) {
|
||||
btnContinue.requestFocusInWindow();
|
||||
} else {
|
||||
btnQuit.requestFocusInWindow();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
lblTitle.setText(composeTitle(game0.getOutcome()));
|
||||
|
||||
showGameOutcomeSummary();
|
||||
showPlayerScores();
|
||||
|
||||
}
|
||||
|
||||
private String composeTitle(GameOutcome outcome) {
|
||||
Player winner = outcome.getWinningPlayer();
|
||||
if (winner == null) {
|
||||
return "It's a draw!";
|
||||
} else {
|
||||
return winner.getName() + " Won!";
|
||||
}
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.toolbox.FButton} */
|
||||
public FButton getBtnContinue() {
|
||||
return this.btnContinue;
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.toolbox.FButton} */
|
||||
public FButton getBtnRestart() {
|
||||
return this.btnRestart;
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.toolbox.FButton} */
|
||||
public FButton getBtnQuit() {
|
||||
return this.btnQuit;
|
||||
}
|
||||
|
||||
/** @return {@link javax.swing.JPanel} */
|
||||
public JPanel getPnlCustom() {
|
||||
return this.pnlCustom;
|
||||
}
|
||||
|
||||
private void showGameOutcomeSummary() {
|
||||
GameLog log = game.getGameLog();
|
||||
for (GameLogEntry o : log.getLogEntriesExact(GameLogEntryType.GAME_OUTCOME))
|
||||
pnlOutcomes.add(new FLabel.Builder().text(o.message).fontSize(14).build(), "h 20!");
|
||||
}
|
||||
|
||||
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("\\[[^\\]]*\\]", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
package forge.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.commons.lang.time.StopWatch;
|
||||
|
||||
import forge.GameLogEntry;
|
||||
import forge.Singletons;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameType;
|
||||
import forge.game.Match;
|
||||
import forge.game.RegisteredPlayer;
|
||||
import forge.util.Lang;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public enum FServer {
|
||||
instance();
|
||||
|
||||
private boolean interactiveMode = true;
|
||||
private Lobby lobby = null;
|
||||
|
||||
public Lobby getLobby() {
|
||||
if (lobby == null) {
|
||||
lobby = new Lobby();
|
||||
}
|
||||
return lobby;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
private final NetServer server = new NetServer();
|
||||
public NetServer getServer() {
|
||||
// TODO Auto-generated method stub
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param args
|
||||
*/
|
||||
public void simulateMatches(String[] args) {
|
||||
interactiveMode = false;
|
||||
System.out.println("Simulation mode");
|
||||
if(args.length < 3 ) {
|
||||
System.out.println("Syntax: forge.exe sim <deck1[.dck]> <deck2[.dck]> [N]");
|
||||
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("\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");
|
||||
return;
|
||||
}
|
||||
Deck d1 = deckFromCommandLineParameter(args[1]);
|
||||
Deck d2 = deckFromCommandLineParameter(args[2]);
|
||||
if(d1 == null || d2 == null) {
|
||||
System.out.println("One of decks could not be loaded, match cannot start");
|
||||
return;
|
||||
}
|
||||
|
||||
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")));
|
||||
|
||||
List<RegisteredPlayer> pp = new ArrayList<RegisteredPlayer>();
|
||||
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())));
|
||||
|
||||
Match mc = new Match(GameType.Constructed, pp);
|
||||
for(int iGame = 0; iGame < nGames; iGame++)
|
||||
simulateSingleMatch(mc, iGame);
|
||||
System.out.flush();
|
||||
}
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param sw
|
||||
* @param pp
|
||||
*/
|
||||
private void simulateSingleMatch(Match mc, int iGame) {
|
||||
StopWatch sw = new StopWatch();
|
||||
sw.start();
|
||||
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
|
||||
Game g1 = mc.createGame();
|
||||
mc.startGame(g1, cdl);
|
||||
try {
|
||||
cdl.await(); // wait until game ends (in other thread)
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
}
|
||||
sw.stop();
|
||||
|
||||
List<GameLogEntry> log = g1.getGameLog().getLogEntries(null);
|
||||
Collections.reverse(log);
|
||||
|
||||
for(GameLogEntry l : log)
|
||||
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()));
|
||||
}
|
||||
|
||||
|
||||
private Deck deckFromCommandLineParameter(String deckname) {
|
||||
int dotpos = deckname.lastIndexOf('.');
|
||||
if(dotpos > 0 && dotpos == deckname.length()-4)
|
||||
return Deck.fromFile(new File(deckname));
|
||||
return Singletons.getModel().getDecks().getConstructed().get(deckname);
|
||||
}
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public boolean isInteractiveMode() {
|
||||
return interactiveMode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package forge.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.commons.lang.time.StopWatch;
|
||||
|
||||
import forge.GameLogEntry;
|
||||
import forge.Singletons;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameType;
|
||||
import forge.game.Match;
|
||||
import forge.game.RegisteredPlayer;
|
||||
import forge.util.Lang;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public enum FServer {
|
||||
instance();
|
||||
|
||||
private boolean interactiveMode = true;
|
||||
private Lobby lobby = null;
|
||||
|
||||
public Lobby getLobby() {
|
||||
if (lobby == null) {
|
||||
lobby = new Lobby();
|
||||
}
|
||||
return lobby;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
private final NetServer server = new NetServer();
|
||||
public NetServer getServer() {
|
||||
// TODO Auto-generated method stub
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param args
|
||||
*/
|
||||
public void simulateMatches(String[] args) {
|
||||
interactiveMode = false;
|
||||
System.out.println("Simulation mode");
|
||||
if(args.length < 3 ) {
|
||||
System.out.println("Syntax: forge.exe sim <deck1[.dck]> <deck2[.dck]> [N]");
|
||||
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("\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");
|
||||
return;
|
||||
}
|
||||
Deck d1 = deckFromCommandLineParameter(args[1]);
|
||||
Deck d2 = deckFromCommandLineParameter(args[2]);
|
||||
if(d1 == null || d2 == null) {
|
||||
System.out.println("One of decks could not be loaded, match cannot start");
|
||||
return;
|
||||
}
|
||||
|
||||
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")));
|
||||
|
||||
List<RegisteredPlayer> pp = new ArrayList<RegisteredPlayer>();
|
||||
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())));
|
||||
|
||||
Match mc = new Match(GameType.Constructed, pp);
|
||||
for(int iGame = 0; iGame < nGames; iGame++)
|
||||
simulateSingleMatch(mc, iGame);
|
||||
System.out.flush();
|
||||
}
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param sw
|
||||
* @param pp
|
||||
*/
|
||||
private void simulateSingleMatch(Match mc, int iGame) {
|
||||
StopWatch sw = new StopWatch();
|
||||
sw.start();
|
||||
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
|
||||
Game g1 = mc.createGame();
|
||||
mc.startGame(g1, cdl);
|
||||
try {
|
||||
cdl.await(); // wait until game ends (in other thread)
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
}
|
||||
sw.stop();
|
||||
|
||||
List<GameLogEntry> log = g1.getGameLog().getLogEntries(null);
|
||||
Collections.reverse(log);
|
||||
|
||||
for(GameLogEntry l : log)
|
||||
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().getWinningLobbyPlayer().getName()));
|
||||
}
|
||||
|
||||
|
||||
private Deck deckFromCommandLineParameter(String deckname) {
|
||||
int dotpos = deckname.lastIndexOf('.');
|
||||
if(dotpos > 0 && dotpos == deckname.length()-4)
|
||||
return Deck.fromFile(new File(deckname));
|
||||
return Singletons.getModel().getDecks().getConstructed().get(deckname);
|
||||
}
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public boolean isInteractiveMode() {
|
||||
return interactiveMode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,128 +1,133 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import forge.control.ChatArea;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.LobbyPlayerAi;
|
||||
import forge.game.player.LobbyPlayerHuman;
|
||||
import forge.game.player.LobbyPlayerRemote;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.net.client.INetClient;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class Lobby {
|
||||
|
||||
|
||||
private final String[] opponentNames = new String[] {
|
||||
"Abigail", "Ada", "Adeline", "Adriana", "Agatha", "Agnes", "Aileen", "Alba", "Alcyon",
|
||||
"Alethea", "Alice", "Alicia", "Alison", "Amanda", "Amelia", "Amy", "Andrea", "Angelina",
|
||||
"Anita", "Ann", "Annabel", "Anne", "Audrey", "Barbara", "Belinda", "Bernice", "Bertha",
|
||||
"Bonnie", "Brenda", "Bridget", "Bunny", "Carmen", "Carol", "Catherine", "Cheryl",
|
||||
"Christine", "Cinderalla", "Claire", "Clarice", "Claudia", "Constance", "Cora",
|
||||
"Corinne", "Cnythia", "Daisy", "Daphne", "Dawn", "Deborah", "Diana", "Dolly", "Dora",
|
||||
"Doreen", "Doris", "Dorothy", "Eileen", "Elaine", "Elizabeth", "Emily", "Emma", "Ethel",
|
||||
"Evelyn", "Fiona", "Florence", "Frances", "Geraldine", "Gertrude", "Gladys", "Gloria",
|
||||
"Grace", "Greta", "Harriet", "Hazel", "Helen", "Hilda", "Ida", "Ingrid", "Irene",
|
||||
"Isabel", "Jacinta", "Jackie", "Jane", "Janet", "Janice", "Jennifer", "Jessie", "Joan",
|
||||
"Jocelyn", "Josephine", "Joyce", "Judith", "Julia", "Juliana", "Karina", "Kathleen",
|
||||
"Laura", "Lilian", "Lily", "Linda", "Lisa", "Lilita", "Lora", "Lorna", "Lucy", "Lydia",
|
||||
"Mabel", "Madeline", "Maggie", "Maria", "Mariam", "Marilyn", "Mary", "Matilda", "Mavis",
|
||||
"Melanie", "Melinda", "Melody", "Michelle", "Mildred", "Molly", "Mona", "Monica",
|
||||
"Nancy", "Nora", "Norma", "Olga", "Pamela", "Patricia", "Paula", "Pauline", "Pearl",
|
||||
"Peggy", "Penny", "Phoebe", "Phyllis", "Polly", "Priscilla", "Rachel", "Rebecca",
|
||||
"Rita", "Rosa", "Rosalind", "Rose", "Rosemary", "Rowena", "Ruby", "Sally", "Samantha",
|
||||
"Sarah", "Selina", "Sharon", "Sheila", "Shirley", "Sonya", "Stella", "Sue", "Susan",
|
||||
"Sylvia", "Tina", "Tracy", "Ursula", "Valentine", "Valerie", "Vanessa", "Veronica",
|
||||
"Victoria", "Violet", "Vivian", "Wendy", "Winnie", "Yvonne", "Aaron", "Abraham", "Adam",
|
||||
"Adrain", "Alain", "Alan", "Alban", "Albert", "Alec", "Alexander", "Alfonso", "Alfred",
|
||||
"Allan", "Allen", "Alonso", "Aloysius", "Alphonso", "Alvin", "Andrew", "Andy", "Amadeus",
|
||||
"Amselm", "Anthony", "Arnold", "Augusta", "Austin", "Barnaby", "Benedict", "Benjamin",
|
||||
"Bertie", "Bertram", "Bill", "Bob", "Boris", "Brady", "Brian", "Bruce", "Burt", "Byron",
|
||||
"Calvin", "Carl", "Carter", "Casey", "Cecil", "Charles", "Christian", "Christopher",
|
||||
"Clarence", "Clement", "Colin", "Conan", "Dalton", "Damian", "Daniel", "David", "Denis",
|
||||
"Derek", "Desmond", "Dick", "Dominic", "Donald", "Douglas", "Duncan", "Edmund",
|
||||
"Edward", "Ellen", "Elton", "Elvis", "Eric", "Eugene", "Felix", "Francis", "Frank",
|
||||
"Frederick", "Gary", "Geoffrey", "George", "Gerald", "Gerry", "Gordon", "Hamish",
|
||||
"Hardy", "Harold", "Harry", "Henry", "Herbert", "Ignatius", "Jack", "James", "Jeffrey",
|
||||
"Jim", "Joe", "John", "Joseph", "Karl", "Keith", "Kenneth", "Kevin", "Larry", "Lawrence",
|
||||
"Leonard", "Lionel", "Louis", "Lucas", "Malcolm", "Mark", "Martin", "Mathew", "Maurice",
|
||||
"Max", "Melvin", "Michael", "Milton", "Morgan", "Morris", "Murphy", "Neville",
|
||||
"Nicholas", "Noel", "Norman", "Oliver", "Oscar", "Patrick", "Paul", "Perkin", "Peter",
|
||||
"Philip", "Ralph", "Randy", "Raymond", "Richard", "Ricky", "Robert", "Robin", "Rodney",
|
||||
"Roger", "Roland", "Ronald", "Roy", "Sam", "Sebastian", "Simon", "Stanley", "Stephen",
|
||||
"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 final LobbyPlayerAi system = new LobbyPlayerAi("System");
|
||||
|
||||
public final LobbyPlayer getGuiPlayer() {
|
||||
return guiPlayer;
|
||||
}
|
||||
|
||||
public final LobbyPlayer getAiPlayer() { return getAiPlayer(getRandomName()); }
|
||||
public final LobbyPlayer getAiPlayer(String name) {
|
||||
LobbyPlayer player = new LobbyPlayerAi(name);
|
||||
if(FSkin.isLoaded())
|
||||
player.setAvatarIndex(MyRandom.getRandom().nextInt(FSkin.getAvatars().size()));
|
||||
return player;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param nextInt
|
||||
* @return
|
||||
*/
|
||||
private String getRandomName() {
|
||||
Random my = MyRandom.getRandom();
|
||||
return opponentNames[my.nextInt(opponentNames.length)];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public LobbyPlayer getQuestPlayer() {
|
||||
return guiPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public synchronized LobbyPlayer findOrCreateRemotePlayer(String name, INetClient client) {
|
||||
if (remotePlayers.containsKey(name))
|
||||
return remotePlayers.get(name);
|
||||
|
||||
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
|
||||
remotePlayers.put(name, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void disconnectPlayer(LobbyPlayer player) {
|
||||
// Should set up a timer here to discard player and all of his games after 20 minutes of being offline
|
||||
}
|
||||
|
||||
|
||||
public void speak(ChatArea room, LobbyPlayer player, String message) {
|
||||
getGuiPlayer().hear(player, message);
|
||||
for(LobbyPlayer remote : remotePlayers.values()) {
|
||||
remote.hear(player, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
package forge.net;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import forge.control.ChatArea;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.LobbyPlayerAi;
|
||||
import forge.game.player.LobbyPlayerHuman;
|
||||
import forge.game.player.LobbyPlayerRemote;
|
||||
import forge.gui.GuiDisplayUtil;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.net.client.INetClient;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class Lobby {
|
||||
|
||||
|
||||
private final String[] opponentNames = new String[] {
|
||||
"Abigail", "Ada", "Adeline", "Adriana", "Agatha", "Agnes", "Aileen", "Alba", "Alcyon",
|
||||
"Alethea", "Alice", "Alicia", "Alison", "Amanda", "Amelia", "Amy", "Andrea", "Angelina",
|
||||
"Anita", "Ann", "Annabel", "Anne", "Audrey", "Barbara", "Belinda", "Bernice", "Bertha",
|
||||
"Bonnie", "Brenda", "Bridget", "Bunny", "Carmen", "Carol", "Catherine", "Cheryl",
|
||||
"Christine", "Cinderalla", "Claire", "Clarice", "Claudia", "Constance", "Cora",
|
||||
"Corinne", "Cnythia", "Daisy", "Daphne", "Dawn", "Deborah", "Diana", "Dolly", "Dora",
|
||||
"Doreen", "Doris", "Dorothy", "Eileen", "Elaine", "Elizabeth", "Emily", "Emma", "Ethel",
|
||||
"Evelyn", "Fiona", "Florence", "Frances", "Geraldine", "Gertrude", "Gladys", "Gloria",
|
||||
"Grace", "Greta", "Harriet", "Hazel", "Helen", "Hilda", "Ida", "Ingrid", "Irene",
|
||||
"Isabel", "Jacinta", "Jackie", "Jane", "Janet", "Janice", "Jennifer", "Jessie", "Joan",
|
||||
"Jocelyn", "Josephine", "Joyce", "Judith", "Julia", "Juliana", "Karina", "Kathleen",
|
||||
"Laura", "Lilian", "Lily", "Linda", "Lisa", "Lilita", "Lora", "Lorna", "Lucy", "Lydia",
|
||||
"Mabel", "Madeline", "Maggie", "Maria", "Mariam", "Marilyn", "Mary", "Matilda", "Mavis",
|
||||
"Melanie", "Melinda", "Melody", "Michelle", "Mildred", "Molly", "Mona", "Monica",
|
||||
"Nancy", "Nora", "Norma", "Olga", "Pamela", "Patricia", "Paula", "Pauline", "Pearl",
|
||||
"Peggy", "Penny", "Phoebe", "Phyllis", "Polly", "Priscilla", "Rachel", "Rebecca",
|
||||
"Rita", "Rosa", "Rosalind", "Rose", "Rosemary", "Rowena", "Ruby", "Sally", "Samantha",
|
||||
"Sarah", "Selina", "Sharon", "Sheila", "Shirley", "Sonya", "Stella", "Sue", "Susan",
|
||||
"Sylvia", "Tina", "Tracy", "Ursula", "Valentine", "Valerie", "Vanessa", "Veronica",
|
||||
"Victoria", "Violet", "Vivian", "Wendy", "Winnie", "Yvonne", "Aaron", "Abraham", "Adam",
|
||||
"Adrain", "Alain", "Alan", "Alban", "Albert", "Alec", "Alexander", "Alfonso", "Alfred",
|
||||
"Allan", "Allen", "Alonso", "Aloysius", "Alphonso", "Alvin", "Andrew", "Andy", "Amadeus",
|
||||
"Amselm", "Anthony", "Arnold", "Augusta", "Austin", "Barnaby", "Benedict", "Benjamin",
|
||||
"Bertie", "Bertram", "Bill", "Bob", "Boris", "Brady", "Brian", "Bruce", "Burt", "Byron",
|
||||
"Calvin", "Carl", "Carter", "Casey", "Cecil", "Charles", "Christian", "Christopher",
|
||||
"Clarence", "Clement", "Colin", "Conan", "Dalton", "Damian", "Daniel", "David", "Denis",
|
||||
"Derek", "Desmond", "Dick", "Dominic", "Donald", "Douglas", "Duncan", "Edmund",
|
||||
"Edward", "Ellen", "Elton", "Elvis", "Eric", "Eugene", "Felix", "Francis", "Frank",
|
||||
"Frederick", "Gary", "Geoffrey", "George", "Gerald", "Gerry", "Gordon", "Hamish",
|
||||
"Hardy", "Harold", "Harry", "Henry", "Herbert", "Ignatius", "Jack", "James", "Jeffrey",
|
||||
"Jim", "Joe", "John", "Joseph", "Karl", "Keith", "Kenneth", "Kevin", "Larry", "Lawrence",
|
||||
"Leonard", "Lionel", "Louis", "Lucas", "Malcolm", "Mark", "Martin", "Mathew", "Maurice",
|
||||
"Max", "Melvin", "Michael", "Milton", "Morgan", "Morris", "Murphy", "Neville",
|
||||
"Nicholas", "Noel", "Norman", "Oliver", "Oscar", "Patrick", "Paul", "Perkin", "Peter",
|
||||
"Philip", "Ralph", "Randy", "Raymond", "Richard", "Ricky", "Robert", "Robin", "Rodney",
|
||||
"Roger", "Roland", "Ronald", "Roy", "Sam", "Sebastian", "Simon", "Stanley", "Stephen",
|
||||
"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 final LobbyPlayerAi system = new LobbyPlayerAi("System");
|
||||
|
||||
public final LobbyPlayer getGuiPlayer() {
|
||||
return guiPlayer;
|
||||
}
|
||||
|
||||
public final LobbyPlayer getAiPlayer() { return getAiPlayer(getRandomName()); }
|
||||
public final LobbyPlayer getAiPlayer(String name) {
|
||||
LobbyPlayer player = new LobbyPlayerAi(name);
|
||||
if(FSkin.isLoaded())
|
||||
player.setAvatarIndex(MyRandom.getRandom().nextInt(FSkin.getAvatars().size()));
|
||||
return player;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param nextInt
|
||||
* @return
|
||||
*/
|
||||
private String getRandomName() {
|
||||
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)];
|
||||
}
|
||||
return aiName;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public LobbyPlayer getQuestPlayer() {
|
||||
return guiPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public synchronized LobbyPlayer findOrCreateRemotePlayer(String name, INetClient client) {
|
||||
if (remotePlayers.containsKey(name))
|
||||
return remotePlayers.get(name);
|
||||
|
||||
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
|
||||
remotePlayers.put(name, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void disconnectPlayer(LobbyPlayer player) {
|
||||
// Should set up a timer here to discard player and all of his games after 20 minutes of being offline
|
||||
}
|
||||
|
||||
|
||||
public void speak(ChatArea room, LobbyPlayer player, String message) {
|
||||
getGuiPlayer().hear(player, message);
|
||||
for(LobbyPlayer remote : remotePlayers.values()) {
|
||||
remote.hear(player, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
||||
* Preference identifiers, and their default values.
|
||||
*/
|
||||
public static enum FPref {
|
||||
PLAYER_NAME (""),
|
||||
CONSTRUCTED_P1_DECK_STATE(""),
|
||||
CONSTRUCTED_P2_DECK_STATE(""),
|
||||
CONSTRUCTED_GAMEPLAYERS(""),
|
||||
|
||||
@@ -1,210 +1,210 @@
|
||||
package forge.sound;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import forge.Card;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.event.GameEventBlockersDeclared;
|
||||
import forge.game.event.GameEventCardChangeZone;
|
||||
import forge.game.event.GameEventCardDamaged;
|
||||
import forge.game.event.GameEventCardDestroyed;
|
||||
import forge.game.event.GameEventCardAttachment;
|
||||
import forge.game.event.GameEventCardRegenerated;
|
||||
import forge.game.event.GameEventCardSacrificed;
|
||||
import forge.game.event.GameEventCardCounters;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEventTurnEnded;
|
||||
import forge.game.event.GameEvent;
|
||||
import forge.game.event.GameEventFlipCoin;
|
||||
import forge.game.event.GameEventLandPlayed;
|
||||
import forge.game.event.GameEventPlayerLivesChanged;
|
||||
import forge.game.event.GameEventPlayerPoisoned;
|
||||
import forge.game.event.GameEventCardTapped;
|
||||
import forge.game.event.GameEventShuffle;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.events.IUiEventVisitor;
|
||||
import forge.gui.events.UiEventAttackerDeclared;
|
||||
import forge.gui.events.UiEventBlockerAssigned;
|
||||
import forge.net.FServer;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
/**
|
||||
* 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 SoundEffectType visit(GameEventCardDamaged event) { return SoundEffectType.Damage; }
|
||||
public SoundEffectType visit(GameEventCardDestroyed event) { return SoundEffectType.Destroy; }
|
||||
public SoundEffectType visit(GameEventCardAttachment event) { return SoundEffectType.Equip; }
|
||||
public SoundEffectType visit(GameEventCardChangeZone event) {
|
||||
ZoneType from = event.from == null ? null : event.from.getZoneType();
|
||||
ZoneType to = event.to.getZoneType();
|
||||
if( from == ZoneType.Library && to == ZoneType.Hand)
|
||||
return SoundEffectType.Draw;
|
||||
if( from == ZoneType.Hand && (to == ZoneType.Graveyard || to == ZoneType.Library) )
|
||||
return SoundEffectType.Discard;
|
||||
|
||||
return to == ZoneType.Exile ? SoundEffectType.Exile : null;
|
||||
}
|
||||
public SoundEffectType visit(GameEventCardRegenerated event) { return SoundEffectType.Regen; }
|
||||
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(GameEventTurnEnded event) { return SoundEffectType.EndOfTurn; }
|
||||
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(GameEventPlayerPoisoned event) { return SoundEffectType.Poison; }
|
||||
public SoundEffectType visit(GameEventShuffle event) { return SoundEffectType.Shuffle; }
|
||||
public SoundEffectType visit(GameEventTokenCreated event) { return SoundEffectType.Token; }
|
||||
public SoundEffectType visit(GameEventBlockersDeclared event) {
|
||||
boolean isLocalHuman = event.defendingPlayer.getLobbyPlayer() == FServer.instance.getLobby().getGuiPlayer();
|
||||
if (isLocalHuman)
|
||||
return null; // already played sounds in interactive mode
|
||||
|
||||
for(MapOfLists<Card, Card> ab : event.blockers.values()) {
|
||||
for(Collection<Card> bb : ab.values()) {
|
||||
if ( !bb.isEmpty() ) {
|
||||
// hasAnyBlocker = true;
|
||||
return SoundEffectType.Block;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the outcome of the duel.
|
||||
*/
|
||||
public SoundEffectType visit(GameEventGameOutcome event) {
|
||||
boolean humanWonTheDuel = event.result.getWinner() == FServer.instance.getLobby().getGuiPlayer();
|
||||
return humanWonTheDuel ? SoundEffectType.WinDuel : SoundEffectType.LoseDuel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the card type/color when the card
|
||||
* ability resolves on the stack.
|
||||
*/
|
||||
public SoundEffectType visit(GameEventSpellResolved evt) {
|
||||
if (evt.spell == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Card source = evt.spell.getSourceCard();
|
||||
if (evt.spell.isSpell()) {
|
||||
// if there's a specific effect for this particular card, play it and
|
||||
// we're done.
|
||||
if (hasSpecificCardEffect(source)) {
|
||||
return SoundEffectType.ScriptedEffect;
|
||||
}
|
||||
|
||||
if (source.isCreature() && source.isArtifact()) {
|
||||
return SoundEffectType.ArtifactCreature;
|
||||
} else if (source.isCreature()) {
|
||||
return SoundEffectType.Creature;
|
||||
} else if (source.isArtifact()) {
|
||||
return SoundEffectType.Artifact;
|
||||
} else if (source.isInstant()) {
|
||||
return SoundEffectType.Instant;
|
||||
} else if (source.isPlaneswalker()) {
|
||||
return SoundEffectType.Planeswalker;
|
||||
} else if (source.isSorcery()) {
|
||||
return SoundEffectType.Sorcery;
|
||||
} else if (source.isEnchantment()) {
|
||||
return SoundEffectType.Enchantment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the change of the card's tapped state
|
||||
* (when a card is tapped or untapped).
|
||||
*
|
||||
* @param tapped_state if true, the "tap" sound is played; otherwise, the
|
||||
* "untap" sound is played
|
||||
* @return the sound effect type
|
||||
*/
|
||||
public SoundEffectType visit(GameEventCardTapped event) {
|
||||
return event.tapped ? SoundEffectType.Tap : SoundEffectType.Untap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the land type when the land is played.
|
||||
*
|
||||
* @param land the land card that was played
|
||||
* @return the sound effect type
|
||||
*/
|
||||
public SoundEffectType visit(GameEventLandPlayed event) {
|
||||
if (event.land == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there's a specific effect for this particular card, play it and
|
||||
// we're done.
|
||||
if (hasSpecificCardEffect(event.land)) {
|
||||
return SoundEffectType.ScriptedEffect;
|
||||
}
|
||||
|
||||
for (SpellAbility sa : event.land.getManaAbility()) {
|
||||
String manaColors = sa.getManaPartRecursive().getOrigProduced();
|
||||
|
||||
if (manaColors.contains("B")) return SoundEffectType.BlackLand;
|
||||
if (manaColors.contains("U")) return SoundEffectType.BlueLand;
|
||||
if (manaColors.contains("G")) return SoundEffectType.GreenLand;
|
||||
if (manaColors.contains("R")) return SoundEffectType.RedLand;
|
||||
if (manaColors.contains("W")) return SoundEffectType.WhiteLand;
|
||||
}
|
||||
|
||||
// play a generic land sound if no other sound corresponded to it.
|
||||
return SoundEffectType.OtherLand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a specific sound effect based on card's name.
|
||||
*
|
||||
* @param c the card to play the sound effect for.
|
||||
* @return the sound effect type
|
||||
*/
|
||||
private static boolean hasSpecificCardEffect(final Card c) {
|
||||
// Implement sound effects for specific cards here, if necessary.
|
||||
String effect = "";
|
||||
if (null != c) {
|
||||
effect = c.getSVar("SoundEffect");
|
||||
}
|
||||
return effect.isEmpty() ? false : true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the SoundEffect SVar of the card that triggered
|
||||
* the event, otherwise returns an empty string.
|
||||
*
|
||||
* @param evt the event which is the source of the sound effect
|
||||
* @return a string containing the SoundEffect SVar, or empty string if
|
||||
* SVar:SoundEffect does not exist.
|
||||
*/
|
||||
public String getScriptedSoundEffectName(GameEvent evt) {
|
||||
Card c = null;
|
||||
|
||||
if (evt instanceof GameEventSpellResolved) {
|
||||
c = ((GameEventSpellResolved) evt).spell.getSourceCard();
|
||||
} else if (evt instanceof GameEventLandPlayed) {
|
||||
c = ((GameEventLandPlayed) evt).land;
|
||||
}
|
||||
|
||||
return c != null ? c.getSVar("SoundEffect") : "";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SoundEffectType visit(UiEventBlockerAssigned event) {
|
||||
return event.attackerBeingBlocked == null ? null : SoundEffectType.Block;
|
||||
}
|
||||
@Override
|
||||
public SoundEffectType visit(UiEventAttackerDeclared event) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package forge.sound;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import forge.Card;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.event.GameEventBlockersDeclared;
|
||||
import forge.game.event.GameEventCardChangeZone;
|
||||
import forge.game.event.GameEventCardDamaged;
|
||||
import forge.game.event.GameEventCardDestroyed;
|
||||
import forge.game.event.GameEventCardAttachment;
|
||||
import forge.game.event.GameEventCardRegenerated;
|
||||
import forge.game.event.GameEventCardSacrificed;
|
||||
import forge.game.event.GameEventCardCounters;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEventTurnEnded;
|
||||
import forge.game.event.GameEvent;
|
||||
import forge.game.event.GameEventFlipCoin;
|
||||
import forge.game.event.GameEventLandPlayed;
|
||||
import forge.game.event.GameEventPlayerLivesChanged;
|
||||
import forge.game.event.GameEventPlayerPoisoned;
|
||||
import forge.game.event.GameEventCardTapped;
|
||||
import forge.game.event.GameEventShuffle;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.events.IUiEventVisitor;
|
||||
import forge.gui.events.UiEventAttackerDeclared;
|
||||
import forge.gui.events.UiEventBlockerAssigned;
|
||||
import forge.net.FServer;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
/**
|
||||
* 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 SoundEffectType visit(GameEventCardDamaged event) { return SoundEffectType.Damage; }
|
||||
public SoundEffectType visit(GameEventCardDestroyed event) { return SoundEffectType.Destroy; }
|
||||
public SoundEffectType visit(GameEventCardAttachment event) { return SoundEffectType.Equip; }
|
||||
public SoundEffectType visit(GameEventCardChangeZone event) {
|
||||
ZoneType from = event.from == null ? null : event.from.getZoneType();
|
||||
ZoneType to = event.to.getZoneType();
|
||||
if( from == ZoneType.Library && to == ZoneType.Hand)
|
||||
return SoundEffectType.Draw;
|
||||
if( from == ZoneType.Hand && (to == ZoneType.Graveyard || to == ZoneType.Library) )
|
||||
return SoundEffectType.Discard;
|
||||
|
||||
return to == ZoneType.Exile ? SoundEffectType.Exile : null;
|
||||
}
|
||||
public SoundEffectType visit(GameEventCardRegenerated event) { return SoundEffectType.Regen; }
|
||||
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(GameEventTurnEnded event) { return SoundEffectType.EndOfTurn; }
|
||||
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(GameEventPlayerPoisoned event) { return SoundEffectType.Poison; }
|
||||
public SoundEffectType visit(GameEventShuffle event) { return SoundEffectType.Shuffle; }
|
||||
public SoundEffectType visit(GameEventTokenCreated event) { return SoundEffectType.Token; }
|
||||
public SoundEffectType visit(GameEventBlockersDeclared event) {
|
||||
boolean isLocalHuman = event.defendingPlayer.getLobbyPlayer() == FServer.instance.getLobby().getGuiPlayer();
|
||||
if (isLocalHuman)
|
||||
return null; // already played sounds in interactive mode
|
||||
|
||||
for(MapOfLists<Card, Card> ab : event.blockers.values()) {
|
||||
for(Collection<Card> bb : ab.values()) {
|
||||
if ( !bb.isEmpty() ) {
|
||||
// hasAnyBlocker = true;
|
||||
return SoundEffectType.Block;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the outcome of the duel.
|
||||
*/
|
||||
public SoundEffectType visit(GameEventGameOutcome event) {
|
||||
boolean humanWonTheDuel = event.result.getWinningLobbyPlayer() == FServer.instance.getLobby().getGuiPlayer();
|
||||
return humanWonTheDuel ? SoundEffectType.WinDuel : SoundEffectType.LoseDuel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the card type/color when the card
|
||||
* ability resolves on the stack.
|
||||
*/
|
||||
public SoundEffectType visit(GameEventSpellResolved evt) {
|
||||
if (evt.spell == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Card source = evt.spell.getSourceCard();
|
||||
if (evt.spell.isSpell()) {
|
||||
// if there's a specific effect for this particular card, play it and
|
||||
// we're done.
|
||||
if (hasSpecificCardEffect(source)) {
|
||||
return SoundEffectType.ScriptedEffect;
|
||||
}
|
||||
|
||||
if (source.isCreature() && source.isArtifact()) {
|
||||
return SoundEffectType.ArtifactCreature;
|
||||
} else if (source.isCreature()) {
|
||||
return SoundEffectType.Creature;
|
||||
} else if (source.isArtifact()) {
|
||||
return SoundEffectType.Artifact;
|
||||
} else if (source.isInstant()) {
|
||||
return SoundEffectType.Instant;
|
||||
} else if (source.isPlaneswalker()) {
|
||||
return SoundEffectType.Planeswalker;
|
||||
} else if (source.isSorcery()) {
|
||||
return SoundEffectType.Sorcery;
|
||||
} else if (source.isEnchantment()) {
|
||||
return SoundEffectType.Enchantment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the change of the card's tapped state
|
||||
* (when a card is tapped or untapped).
|
||||
*
|
||||
* @param tapped_state if true, the "tap" sound is played; otherwise, the
|
||||
* "untap" sound is played
|
||||
* @return the sound effect type
|
||||
*/
|
||||
public SoundEffectType visit(GameEventCardTapped event) {
|
||||
return event.tapped ? SoundEffectType.Tap : SoundEffectType.Untap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound corresponding to the land type when the land is played.
|
||||
*
|
||||
* @param land the land card that was played
|
||||
* @return the sound effect type
|
||||
*/
|
||||
public SoundEffectType visit(GameEventLandPlayed event) {
|
||||
if (event.land == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there's a specific effect for this particular card, play it and
|
||||
// we're done.
|
||||
if (hasSpecificCardEffect(event.land)) {
|
||||
return SoundEffectType.ScriptedEffect;
|
||||
}
|
||||
|
||||
for (SpellAbility sa : event.land.getManaAbility()) {
|
||||
String manaColors = sa.getManaPartRecursive().getOrigProduced();
|
||||
|
||||
if (manaColors.contains("B")) return SoundEffectType.BlackLand;
|
||||
if (manaColors.contains("U")) return SoundEffectType.BlueLand;
|
||||
if (manaColors.contains("G")) return SoundEffectType.GreenLand;
|
||||
if (manaColors.contains("R")) return SoundEffectType.RedLand;
|
||||
if (manaColors.contains("W")) return SoundEffectType.WhiteLand;
|
||||
}
|
||||
|
||||
// play a generic land sound if no other sound corresponded to it.
|
||||
return SoundEffectType.OtherLand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a specific sound effect based on card's name.
|
||||
*
|
||||
* @param c the card to play the sound effect for.
|
||||
* @return the sound effect type
|
||||
*/
|
||||
private static boolean hasSpecificCardEffect(final Card c) {
|
||||
// Implement sound effects for specific cards here, if necessary.
|
||||
String effect = "";
|
||||
if (null != c) {
|
||||
effect = c.getSVar("SoundEffect");
|
||||
}
|
||||
return effect.isEmpty() ? false : true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the SoundEffect SVar of the card that triggered
|
||||
* the event, otherwise returns an empty string.
|
||||
*
|
||||
* @param evt the event which is the source of the sound effect
|
||||
* @return a string containing the SoundEffect SVar, or empty string if
|
||||
* SVar:SoundEffect does not exist.
|
||||
*/
|
||||
public String getScriptedSoundEffectName(GameEvent evt) {
|
||||
Card c = null;
|
||||
|
||||
if (evt instanceof GameEventSpellResolved) {
|
||||
c = ((GameEventSpellResolved) evt).spell.getSourceCard();
|
||||
} else if (evt instanceof GameEventLandPlayed) {
|
||||
c = ((GameEventLandPlayed) evt).land;
|
||||
}
|
||||
|
||||
return c != null ? c.getSVar("SoundEffect") : "";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SoundEffectType visit(UiEventBlockerAssigned event) {
|
||||
return event.attackerBeingBlocked == null ? null : SoundEffectType.Block;
|
||||
}
|
||||
@Override
|
||||
public SoundEffectType visit(UiEventAttackerDeclared event) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user