mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Refactor lobby and add network support.
- Lobby code has been revised completely to support network lobbies; code has been separated into model and view parts. - Added preliminary network game support; most of it should be working but hasn't been tested thoroughly. - Fixed issue where controlling another player wouldn't be recognised by the GUI. - Fixed issue where hand panels wouldn't display anymore. - Minor fixes/cleanup.
This commit is contained in:
23
.gitattributes
vendored
23
.gitattributes
vendored
@@ -164,6 +164,7 @@ forge-core/.settings/org.eclipse.jdt.core.prefs -text
|
||||
forge-core/.settings/org.eclipse.m2e.core.prefs -text
|
||||
forge-core/pom.xml -text
|
||||
forge-core/pom.xml.releaseBackup -text
|
||||
forge-core/src/main/java/forge/AIOption.java -text
|
||||
forge-core/src/main/java/forge/CardStorageReader.java -text
|
||||
forge-core/src/main/java/forge/FTrace.java -text
|
||||
forge-core/src/main/java/forge/ImageKeys.java -text
|
||||
@@ -17399,10 +17400,12 @@ forge-gui/src/main/java/forge/interfaces/IGuiBase.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IGuiGame.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IGuiTimer.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/ILobby.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/ILobbyListener.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IMayViewCards.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IPlayerChangeListener.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IProgressBar.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/ITextField.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IUpdateable.java -text
|
||||
forge-gui/src/main/java/forge/interfaces/IWinLoseView.java -text
|
||||
forge-gui/src/main/java/forge/itemmanager/BooleanExpression.java -text
|
||||
forge-gui/src/main/java/forge/itemmanager/ColumnDef.java -text
|
||||
@@ -17436,9 +17439,12 @@ forge-gui/src/main/java/forge/limited/WinstonDraft.java -text
|
||||
forge-gui/src/main/java/forge/limited/WinstonDraftAI.java -text
|
||||
forge-gui/src/main/java/forge/limited/package-info.java svneol=native#text/plain
|
||||
forge-gui/src/main/java/forge/match/AbstractGuiGame.java -text
|
||||
forge-gui/src/main/java/forge/match/GameLobby.java -text
|
||||
forge-gui/src/main/java/forge/match/HostedMatch.java -text
|
||||
forge-gui/src/main/java/forge/match/LobbySlot.java -text
|
||||
forge-gui/src/main/java/forge/match/LocalLobby.java -text
|
||||
forge-gui/src/main/java/forge/match/MatchButtonType.java -text
|
||||
forge-gui/src/main/java/forge/match/MatchConstants.java -text
|
||||
forge-gui/src/main/java/forge/match/NetGuiGame.java -text
|
||||
forge-gui/src/main/java/forge/match/NextGameDecision.java -text
|
||||
forge-gui/src/main/java/forge/match/input/Input.java -text
|
||||
forge-gui/src/main/java/forge/match/input/InputAttack.java -text
|
||||
@@ -17470,9 +17476,13 @@ forge-gui/src/main/java/forge/model/MetaSet.java -text
|
||||
forge-gui/src/main/java/forge/model/MultipleForgeJarsFoundError.java -text
|
||||
forge-gui/src/main/java/forge/model/UnOpenedMeta.java -text
|
||||
forge-gui/src/main/java/forge/model/package-info.java svneol=native#text/plain
|
||||
forge-gui/src/main/java/forge/net/ClientGameLobby.java -text
|
||||
forge-gui/src/main/java/forge/net/FGameClient.java -text
|
||||
forge-gui/src/main/java/forge/net/FServerManager.java -text
|
||||
forge-gui/src/main/java/forge/net/NetGame.java -text
|
||||
forge-gui/src/main/java/forge/net/LobbyUpdateEvent.java -text
|
||||
forge-gui/src/main/java/forge/net/NetGameController.java -text
|
||||
forge-gui/src/main/java/forge/net/NetGuiGame.java -text
|
||||
forge-gui/src/main/java/forge/net/ServerGameLobby.java -text
|
||||
forge-gui/src/main/java/forge/net/package-info.java -text
|
||||
forge-gui/src/main/java/forge/planarconquest/ConquestAction.java -text
|
||||
forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java -text
|
||||
@@ -17491,7 +17501,6 @@ forge-gui/src/main/java/forge/player/HumanCostDecision.java -text
|
||||
forge-gui/src/main/java/forge/player/HumanPlay.java -text
|
||||
forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java -text
|
||||
forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java -text
|
||||
forge-gui/src/main/java/forge/player/NetGameController.java -text
|
||||
forge-gui/src/main/java/forge/player/PlayerControllerHuman.java -text
|
||||
forge-gui/src/main/java/forge/player/TargetSelection.java -text
|
||||
forge-gui/src/main/java/forge/player/package-info.java -text
|
||||
@@ -17606,6 +17615,7 @@ forge-net/src/main/java/forge/net/IConnectionObserver.java -text
|
||||
forge-net/src/main/java/forge/net/Lobby.java -text
|
||||
forge-net/src/main/java/forge/net/LobbyPlayerRemote.java -text
|
||||
forge-net/src/main/java/forge/net/NetServer.java -text
|
||||
forge-net/src/main/java/forge/net/ReplyPool.java -text
|
||||
forge-net/src/main/java/forge/net/client/GameServlet.java -text
|
||||
forge-net/src/main/java/forge/net/client/INetClient.java -text
|
||||
forge-net/src/main/java/forge/net/client/InvalidFieldInPacketException.java -text
|
||||
@@ -17618,15 +17628,14 @@ forge-net/src/main/java/forge/net/client/state/UnauthorizedClientState.java -tex
|
||||
forge-net/src/main/java/forge/net/client/state/package-info.java -text
|
||||
forge-net/src/main/java/forge/net/game/GuiGameEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/IRemote.java -text
|
||||
forge-net/src/main/java/forge/net/game/IdentifiableNetEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/LobbySlotType.java -text
|
||||
forge-net/src/main/java/forge/net/game/LobbyState.java -text
|
||||
forge-net/src/main/java/forge/net/game/LobbyUpdateEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/LoginEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/LogoutEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/MessageEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/NetEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/RegisterDeckEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/client/ILobbyListener.java -text
|
||||
forge-net/src/main/java/forge/net/game/ReplyEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/UpdateLobbyPlayerEvent.java -text
|
||||
forge-net/src/main/java/forge/net/game/client/IToServer.java -text
|
||||
forge-net/src/main/java/forge/net/game/client/package-info.java -text
|
||||
forge-net/src/main/java/forge/net/game/package-info.java -text
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package forge.ai;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.game.Game;
|
||||
import forge.game.player.IGameEntitiesFactory;
|
||||
@@ -15,9 +16,9 @@ public class LobbyPlayerAi extends LobbyPlayer implements IGameEntitiesFactory {
|
||||
private boolean allowCheatShuffle;
|
||||
private boolean useSimulation;
|
||||
|
||||
public LobbyPlayerAi(String name, Map<String, String> options) {
|
||||
public LobbyPlayerAi(String name, Set<AIOption> options) {
|
||||
super(name);
|
||||
if (options != null && "True".equals(options.get("UseSimulation"))) {
|
||||
if (options != null && options.contains(AIOption.USE_SIMULATION)) {
|
||||
this.useSimulation = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.*;
|
||||
import forge.game.trigger.Trigger;
|
||||
@@ -141,7 +142,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
@Override
|
||||
public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
ApiType api = sa.getApi();
|
||||
if (null == api) {
|
||||
@@ -240,6 +241,11 @@ public class PlayerControllerAi extends PlayerController {
|
||||
// We don't know how to reveal cards to AI
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal(Collection<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) {
|
||||
// We don't know how to reveal cards to AI
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutablePair<CardCollection, CardCollection> arrangeForScry(CardCollection topN) {
|
||||
CardCollection toBottom = new CardCollection();
|
||||
@@ -850,7 +856,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
String selectPrompt, boolean isOptional, Player decider) {
|
||||
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider);
|
||||
}
|
||||
|
||||
5
forge-core/src/main/java/forge/AIOption.java
Normal file
5
forge-core/src/main/java/forge/AIOption.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package forge;
|
||||
|
||||
public enum AIOption {
|
||||
USE_SIMULATION;
|
||||
}
|
||||
@@ -41,6 +41,8 @@ import java.util.Set;
|
||||
* @version $Id: java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
private static final long serialVersionUID = 7612877255541109847L;
|
||||
|
||||
public static final CardTypeView EMPTY = new CardType();
|
||||
|
||||
public enum CoreType {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.card;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -8,7 +9,7 @@ import forge.card.CardType.CoreType;
|
||||
import forge.card.CardType.Supertype;
|
||||
|
||||
//Interface to expose only the desired functions of CardType without allowing modification
|
||||
public interface CardTypeView extends Iterable<String> {
|
||||
public interface CardTypeView extends Iterable<String>, Serializable {
|
||||
boolean isEmpty();
|
||||
Iterable<CoreType> getCoreTypes();
|
||||
Iterable<Supertype> getSupertypes();
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.util.BinaryUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@@ -34,7 +36,8 @@ import java.util.NoSuchElementException;
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte> {
|
||||
public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Serializable {
|
||||
private static final long serialVersionUID = 794691267379929080L;
|
||||
|
||||
private final byte myColor;
|
||||
private final float orderWeight;
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.card.mana;
|
||||
|
||||
import forge.card.MagicColor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@@ -35,7 +36,9 @@ import org.apache.commons.lang3.StringUtils;
|
||||
* @version $Id: CardManaCost.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
|
||||
public final class ManaCost implements Comparable<ManaCost>, Iterable<ManaCostShard> {
|
||||
public final class ManaCost implements Comparable<ManaCost>, Iterable<ManaCostShard>, Serializable {
|
||||
private static final long serialVersionUID = -2477430496624149226L;
|
||||
|
||||
private static final char DELIM = (char)6;
|
||||
|
||||
private List<ManaCostShard> shards;
|
||||
|
||||
@@ -17,6 +17,15 @@
|
||||
*/
|
||||
package forge.deck;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.StaticData;
|
||||
@@ -26,17 +35,9 @@ import forge.util.ItemPool;
|
||||
import forge.util.ItemPoolSorter;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
public class CardPool extends ItemPool<PaperCard> {
|
||||
private static final long serialVersionUID = -5379091255613968393L;
|
||||
|
||||
public CardPool() {
|
||||
super(PaperCard.class);
|
||||
|
||||
@@ -17,13 +17,17 @@
|
||||
*/
|
||||
package forge.item;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
|
||||
|
||||
/**
|
||||
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
|
||||
* <br><br>
|
||||
@@ -31,9 +35,11 @@ import forge.card.CardRules;
|
||||
*
|
||||
* @author Forge
|
||||
*/
|
||||
public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard {
|
||||
public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard, Serializable {
|
||||
private static final long serialVersionUID = 2942081982620691205L;
|
||||
|
||||
// Reference to rules
|
||||
private final transient CardRules rules;
|
||||
private transient CardRules rules;
|
||||
|
||||
// These fields are kinda PK for PrintedCard
|
||||
private final String name;
|
||||
@@ -43,7 +49,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
private Boolean hasImage;
|
||||
|
||||
// Calculated fields are below:
|
||||
private final transient CardRarity rarity; // rarity is given in ctor when set is assigned
|
||||
private transient CardRarity rarity; // rarity is given in ctor when set is assigned
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -199,4 +205,13 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
|
||||
return Integer.compare(artIndex, o.getArtIndex());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
// default deserialization
|
||||
ois.defaultReadObject();
|
||||
|
||||
final IPaperCard pc = StaticData.instance().getCommonCards().getCard(name, edition, artIndex);
|
||||
this.rules = pc.getRules();
|
||||
this.rarity = pc.getRarity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.common.base.Predicate;
|
||||
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -34,7 +35,8 @@ import java.util.Map.Entry;
|
||||
* @param <T>
|
||||
* an Object
|
||||
*/
|
||||
public class ItemPool<T extends InventoryItem> implements Iterable<Entry<T, Integer>> {
|
||||
public class ItemPool<T extends InventoryItem> implements Iterable<Entry<T, Integer>>, Serializable {
|
||||
private static final long serialVersionUID = 6572047177527559797L;
|
||||
|
||||
/** The fn to printed. */
|
||||
public final transient Function<Entry<T, Integer>, T> FN_GET_KEY = new Function<Entry<T, Integer>, T>() {
|
||||
|
||||
@@ -56,8 +56,10 @@ import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.spellability.Ability;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.MagicStack;
|
||||
@@ -105,20 +107,20 @@ public class Game {
|
||||
private final GameView view;
|
||||
private final Tracker tracker = new Tracker();
|
||||
|
||||
private GameEntityCache<Player, PlayerView> playerCache = new GameEntityCache<>();
|
||||
private final GameEntityCache<Player, PlayerView> playerCache = new GameEntityCache<>();
|
||||
public Player getPlayer(PlayerView playerView) {
|
||||
return playerCache.get(playerView);
|
||||
}
|
||||
public void addPlayer(Integer id, Player player) {
|
||||
playerCache.put(id, player);
|
||||
public void addPlayer(int id, Player player) {
|
||||
playerCache.put(Integer.valueOf(id), player);
|
||||
}
|
||||
|
||||
public GameEntityCache<Card, CardView> cardCache = new GameEntityCache<>();
|
||||
private final GameEntityCache<Card, CardView> cardCache = new GameEntityCache<>();
|
||||
public Card getCard(CardView cardView) {
|
||||
return cardCache.get(cardView);
|
||||
}
|
||||
public void addCard(Integer id, Card card) {
|
||||
cardCache.put(id, card);
|
||||
public void addCard(int id, Card card) {
|
||||
cardCache.put(Integer.valueOf(id), card);
|
||||
}
|
||||
public CardCollection getCardList(Iterable<CardView> cardViews) {
|
||||
CardCollection list = new CardCollection();
|
||||
@@ -126,10 +128,20 @@ public class Game {
|
||||
return list;
|
||||
}
|
||||
|
||||
private final GameEntityCache<SpellAbility, SpellAbilityView> spabCache = new GameEntityCache<>();
|
||||
public SpellAbility getSpellAbility(final SpellAbilityView view) {
|
||||
return spabCache.get(view);
|
||||
}
|
||||
public void addSpellAbility(int id, SpellAbility spellAbility) {
|
||||
spabCache.put(Integer.valueOf(id), spellAbility);
|
||||
}
|
||||
|
||||
public Game(List<RegisteredPlayer> players0, GameRules rules0, Match match0) { /* no more zones to map here */
|
||||
rules = rules0;
|
||||
match = match0;
|
||||
|
||||
spabCache.put(Ability.PLAY_LAND_SURROGATE.getId(), Ability.PLAY_LAND_SURROGATE);
|
||||
|
||||
int highestTeam = -1;
|
||||
for (RegisteredPlayer psc : players0) {
|
||||
// Track highest team number for auto assigning unassigned teams
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class GameEntityCache<Entity extends GameEntity, View extends GameEntityView> {
|
||||
import forge.trackable.TrackableObject;
|
||||
|
||||
public class GameEntityCache<Entity extends IIdentifiable, View extends TrackableObject> {
|
||||
private HashMap<Integer, Entity> entityCache = new HashMap<Integer, Entity>();
|
||||
|
||||
public void put(Integer id, Entity entity) {
|
||||
|
||||
@@ -7,6 +7,8 @@ import forge.trackable.TrackableProperty;
|
||||
import forge.trackable.Tracker;
|
||||
|
||||
public abstract class GameEntityView extends TrackableObject {
|
||||
private static final long serialVersionUID = -5129089945124455670L;
|
||||
|
||||
public static GameEntityView get(GameEntity e) {
|
||||
return e == null ? null : e.getView();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game;
|
||||
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
@@ -30,10 +31,12 @@ import java.util.Observable;
|
||||
* @author Forge
|
||||
* @version $Id: GameLog.java 12297 2011-11-28 19:56:47Z slapshot5 $
|
||||
*/
|
||||
public class GameLog extends Observable {
|
||||
private List<GameLogEntry> log = new ArrayList<GameLogEntry>();
|
||||
public class GameLog extends Observable implements Serializable {
|
||||
private static final long serialVersionUID = 6465283802022948827L;
|
||||
|
||||
private GameLogFormatter formatter = new GameLogFormatter(this);
|
||||
private final List<GameLogEntry> log = new ArrayList<GameLogEntry>();
|
||||
|
||||
private final transient GameLogFormatter formatter = new GameLogFormatter(this);
|
||||
|
||||
/** Logging level:
|
||||
* 0 - Turn
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package forge.game;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class GameLogEntry implements Serializable {
|
||||
private static final long serialVersionUID = -5322859985172769630L;
|
||||
|
||||
public class GameLogEntry {
|
||||
public final String message;
|
||||
public final GameLogEntryType type;
|
||||
// might add here date and some other fields
|
||||
@@ -13,7 +16,6 @@ public class GameLogEntry {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// TODO Auto-generated method stub
|
||||
return type.getCaption() + ": " + message;
|
||||
}
|
||||
}
|
||||
@@ -111,14 +111,14 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(final GameEventPlayerControl event) {
|
||||
final LobbyPlayer newController = event.newController;
|
||||
final LobbyPlayer newLobbyPlayer = event.newLobbyPlayer;
|
||||
final Player p = event.player;
|
||||
|
||||
final String message;
|
||||
if (newController == null) {
|
||||
if (newLobbyPlayer == null) {
|
||||
message = p.getName() + " has restored control over themself";
|
||||
} else {
|
||||
message = String.format("%s is controlled by %s", p.getName(), newController.getName());
|
||||
message = String.format("%s is controlled by %s", p.getName(), newLobbyPlayer.getName());
|
||||
}
|
||||
return new GameLogEntry(GameLogEntryType.PLAYER_CONROL, message);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import forge.item.PaperCard;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -41,7 +42,9 @@ import java.util.Map.Entry;
|
||||
// only getters) and
|
||||
// GameObserver class - who should be notified of any considerable ingame event
|
||||
public final class GameOutcome implements Iterable<Pair<LobbyPlayer, PlayerStatistics>> {
|
||||
public static class AnteResult {
|
||||
public static class AnteResult implements Serializable {
|
||||
private static final long serialVersionUID = 5087554550408543192L;
|
||||
|
||||
public final List<PaperCard> lostCards;
|
||||
public final List<PaperCard> wonCards;
|
||||
|
||||
@@ -50,8 +53,7 @@ public final class GameOutcome implements Iterable<Pair<LobbyPlayer, PlayerStati
|
||||
if (won) {
|
||||
this.wonCards = cards;
|
||||
this.lostCards = new ArrayList<>();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.lostCards = cards;
|
||||
this.wonCards = new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package forge.game;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.GameOutcome.AnteResult;
|
||||
@@ -22,6 +24,7 @@ import forge.trackable.TrackableProperty;
|
||||
import forge.util.FCollectionView;
|
||||
|
||||
public class GameView extends TrackableObject {
|
||||
private static final long serialVersionUID = 8522884512960961528L;
|
||||
|
||||
/*private final TrackableIndex<CardView> cards = new TrackableIndex<CardView>();
|
||||
private final TrackableIndex<PlayerView> players = new TrackableIndex<PlayerView>();
|
||||
@@ -29,7 +32,7 @@ public class GameView extends TrackableObject {
|
||||
private final TrackableIndex<StackItemView> stackItems = new TrackableIndex<StackItemView>();*/
|
||||
private final TrackableCollection<PlayerView> players;
|
||||
private CombatView combatView;
|
||||
private final Game game; //TODO: Remove this when possible before network support added
|
||||
private final transient Game game; //TODO: Remove this when possible before network support added
|
||||
|
||||
public GameView(final Game game0) {
|
||||
super(-1, game0.getTracker()); //ID not needed
|
||||
@@ -88,10 +91,17 @@ public class GameView extends TrackableObject {
|
||||
set(TrackableProperty.PlayerTurn, PlayerView.get(phaseHandler.getPlayerTurn()));
|
||||
}
|
||||
|
||||
public FCollectionView<StackItemView> getStack() {
|
||||
return get(TrackableProperty.Stack);
|
||||
}
|
||||
public StackItemView peekStack() {
|
||||
return Iterables.getFirst(getStack(), null);
|
||||
}
|
||||
public int getStormCount() {
|
||||
return get(TrackableProperty.StormCount);
|
||||
}
|
||||
void updateStack(MagicStack stack) {
|
||||
void updateStack(final MagicStack stack) {
|
||||
set(TrackableProperty.Stack, StackItemView.getCollection(stack));
|
||||
set(TrackableProperty.StormCount, stack.getSpellsCastThisTurn().size());
|
||||
}
|
||||
|
||||
@@ -166,10 +176,6 @@ public class GameView extends TrackableObject {
|
||||
|
||||
//TODO: Find better ways to make this information available to all GUIs without using the Game class
|
||||
|
||||
public FCollectionView<StackItemView> getStack() {
|
||||
return StackItemView.getCollection(game.getStack());
|
||||
}
|
||||
|
||||
public boolean isMatchWonBy(LobbyPlayer questPlayer) {
|
||||
return game.getMatch().isWonBy(questPlayer);
|
||||
}
|
||||
@@ -182,10 +188,6 @@ public class GameView extends TrackableObject {
|
||||
return game.getOutcome().getWinningLobbyPlayer();
|
||||
}
|
||||
|
||||
public StackItemView peekStack() {
|
||||
return StackItemView.get(game.getStack().peek());
|
||||
}
|
||||
|
||||
public boolean isWinner(LobbyPlayer guiPlayer) {
|
||||
return game.getOutcome().isWinner(guiPlayer);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
@@ -700,10 +701,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
|
||||
CardCollectionView shown = !decider.hasKeyword("LimitSearchLibrary") ? player.getCardsIn(ZoneType.Library) : player.getCardsIn(ZoneType.Library, fetchNum);
|
||||
// Look at whole library before moving onto choosing a card
|
||||
delayedReveal = new DelayedReveal(shown, ZoneType.Library, player, source.getName() + " - Looking at cards in ");
|
||||
delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(player), source.getName() + " - Looking at cards in ");
|
||||
}
|
||||
else if (origin.contains(ZoneType.Hand) && player.isOpponentOf(decider)) {
|
||||
delayedReveal = new DelayedReveal(player.getCardsIn(ZoneType.Hand), ZoneType.Hand, player, source.getName() + " - Looking at cards in ");
|
||||
delayedReveal = new DelayedReveal(player.getCardsIn(ZoneType.Hand), ZoneType.Hand, PlayerView.get(player), source.getName() + " - Looking at cards in ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,10 +768,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
for (final Card card : chosenCards) {
|
||||
|
||||
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.sharesLandTypeWith(card);
|
||||
}
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.sharesLandTypeWith(card);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
@@ -784,7 +785,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
Card c = null;
|
||||
if (sa.hasParam("AtRandom")) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(decider.getController());
|
||||
decider.getController().reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
c = Aggregates.random(fetchList);
|
||||
}
|
||||
@@ -812,7 +813,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
fetchList.remove(c);
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.remove(c);
|
||||
delayedReveal.remove(CardView.get(c));
|
||||
}
|
||||
chosenCards.add(c);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.PlayerZone;
|
||||
@@ -144,7 +145,7 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
}
|
||||
else if (!sa.hasParam("NoLooking")) {
|
||||
// show the user the revealed cards
|
||||
delayedReveal = new DelayedReveal(top, srcZone, p);
|
||||
delayedReveal = new DelayedReveal(top, srcZone, PlayerView.get(p));
|
||||
|
||||
if (noMove) {
|
||||
// Let the activating player see the cards even if they're not moved
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.util.Collection;
|
||||
import forge.util.FCollection;
|
||||
|
||||
public class CardCollection extends FCollection<Card> implements CardCollectionView {
|
||||
private static final long serialVersionUID = -8133537013727100275L;
|
||||
|
||||
public static final CardCollectionView EMPTY = new CardCollection();
|
||||
|
||||
public static boolean hasCard(CardCollection cards) {
|
||||
|
||||
@@ -10,10 +10,10 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.CardType;
|
||||
import forge.card.CardTypeView;
|
||||
import forge.card.ColorSet;
|
||||
@@ -32,6 +32,8 @@ import forge.trackable.Tracker;
|
||||
import forge.util.FCollectionView;
|
||||
|
||||
public class CardView extends GameEntityView {
|
||||
private static final long serialVersionUID = -3624090829028979255L;
|
||||
|
||||
public static CardView get(Card c) {
|
||||
return c == null ? null : c.getView();
|
||||
}
|
||||
@@ -715,6 +717,8 @@ public class CardView extends GameEntityView {
|
||||
}
|
||||
|
||||
public class CardStateView extends TrackableObject {
|
||||
private static final long serialVersionUID = 6673944200513430607L;
|
||||
|
||||
private final CardStateName state;
|
||||
|
||||
public CardStateView(final int id0, final CardStateName state0, final Tracker tracker) {
|
||||
|
||||
@@ -17,6 +17,8 @@ import forge.util.FCollection;
|
||||
|
||||
|
||||
public class CombatView extends TrackableObject {
|
||||
private static final long serialVersionUID = 68085618912864941L;
|
||||
|
||||
public CombatView(final Tracker tracker) {
|
||||
super(-1, tracker); //ID not needed
|
||||
set(TrackableProperty.AttackersWithDefenders, new HashMap<CardView, GameEntityView>());
|
||||
|
||||
@@ -2,20 +2,25 @@ package forge.game.event;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
|
||||
public class GameEventPlayerControl extends GameEvent {
|
||||
public final Player player;
|
||||
public final LobbyPlayer oldController;
|
||||
public final LobbyPlayer newController;
|
||||
public final LobbyPlayer oldLobbyPlayer;
|
||||
public final PlayerController oldController;
|
||||
public final LobbyPlayer newLobbyPlayer;
|
||||
public final PlayerController newController;
|
||||
|
||||
public GameEventPlayerControl(Player p, LobbyPlayer old, LobbyPlayer new1) {
|
||||
player = p;
|
||||
oldController = old;
|
||||
newController = new1;
|
||||
public GameEventPlayerControl(final Player p, final LobbyPlayer oldLobbyPlayer, final PlayerController oldController, final LobbyPlayer newLobbyPlayer, final PlayerController newController) {
|
||||
this.player = p;
|
||||
this.oldLobbyPlayer = oldLobbyPlayer;
|
||||
this.oldController = oldController;
|
||||
this.newLobbyPlayer = newLobbyPlayer;
|
||||
this.newController = newController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
public <T> T visit(final IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.keyword;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
@@ -7,8 +8,10 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class KeywordCollection implements Iterable<String> {
|
||||
private KeywordCollectionView view;
|
||||
public class KeywordCollection implements Iterable<String>, Serializable {
|
||||
private static final long serialVersionUID = -2882986558147844702L;
|
||||
|
||||
private transient KeywordCollectionView view;
|
||||
private final EnumMap<Keyword, List<KeywordInstance<?>>> map = new EnumMap<Keyword, List<KeywordInstance<?>>>(Keyword.class);
|
||||
|
||||
public boolean contains(Keyword keyword) {
|
||||
@@ -134,7 +137,9 @@ public class KeywordCollection implements Iterable<String> {
|
||||
return view;
|
||||
}
|
||||
|
||||
public class KeywordCollectionView implements Iterable<String> {
|
||||
public class KeywordCollectionView implements Iterable<String>, Serializable {
|
||||
private static final long serialVersionUID = 7536969077044188264L;
|
||||
|
||||
protected KeywordCollectionView() {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
package forge.game.player;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
//Stores information to reveal cards after a delay unless those cards can be revealed in the same dialog as cards being selected
|
||||
/**
|
||||
* Stores information to reveal cards after a delay unless those cards can be
|
||||
* revealed in the same dialog as cards being selected
|
||||
*/
|
||||
public class DelayedReveal {
|
||||
private final CardCollection cards;
|
||||
private final Collection<CardView> cards;
|
||||
private final ZoneType zone;
|
||||
private final Player owner;
|
||||
private final PlayerView owner;
|
||||
private final String messagePrefix;
|
||||
private boolean revealed;
|
||||
|
||||
public DelayedReveal(Iterable<Card> cards0, ZoneType zone0, Player owner0) {
|
||||
public DelayedReveal(Iterable<Card> cards0, ZoneType zone0, PlayerView owner0) {
|
||||
this(cards0, zone0, owner0, null);
|
||||
}
|
||||
public DelayedReveal(Iterable<Card> cards0, ZoneType zone0, Player owner0, String messagePrefix0) {
|
||||
cards = new CardCollection(cards0); //create copy of list to allow modification
|
||||
public DelayedReveal(Iterable<Card> cards0, ZoneType zone0, PlayerView owner0, String messagePrefix0) {
|
||||
cards = CardView.getCollection(cards0);
|
||||
zone = zone0;
|
||||
owner = owner0;
|
||||
messagePrefix = messagePrefix0;
|
||||
}
|
||||
|
||||
public Iterable<Card> getCards() {
|
||||
public Collection<CardView> getCards() {
|
||||
return cards;
|
||||
}
|
||||
|
||||
@@ -30,17 +34,16 @@ public class DelayedReveal {
|
||||
return zone;
|
||||
}
|
||||
|
||||
public Player getOwner() {
|
||||
public PlayerView getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void remove(Card card) {
|
||||
public String getMessagePrefix() {
|
||||
return messagePrefix;
|
||||
}
|
||||
|
||||
public void remove(CardView card) {
|
||||
cards.remove(card);
|
||||
}
|
||||
|
||||
public void reveal(PlayerController controller) {
|
||||
if (revealed) { return; } //avoid revealing more than once
|
||||
revealed = true;
|
||||
controller.reveal(cards, zone, owner, messagePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2099,7 +2099,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return mindSlaveMaster;
|
||||
}
|
||||
|
||||
public final void setMindSlaveMaster(Player mindSlaveMaster0) {
|
||||
public final void setMindSlaveMaster(final Player mindSlaveMaster0) {
|
||||
if (mindSlaveMaster == mindSlaveMaster0) {
|
||||
return;
|
||||
}
|
||||
@@ -2107,14 +2107,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
view.updateMindSlaveMaster(this);
|
||||
|
||||
if (mindSlaveMaster != null) {
|
||||
LobbyPlayer oldLobbyPlayer = getLobbyPlayer();
|
||||
IGameEntitiesFactory master = (IGameEntitiesFactory)mindSlaveMaster.getLobbyPlayer();
|
||||
final LobbyPlayer oldLobbyPlayer = getLobbyPlayer();
|
||||
final PlayerController oldController = getController();
|
||||
final IGameEntitiesFactory master = (IGameEntitiesFactory)mindSlaveMaster.getLobbyPlayer();
|
||||
controller = master.createMindSlaveController(mindSlaveMaster, this);
|
||||
game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, getLobbyPlayer()));
|
||||
}
|
||||
else {
|
||||
game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, oldController, getLobbyPlayer(), controller));
|
||||
} else {
|
||||
controller = controllerCreator;
|
||||
game.fireEvent(new GameEventPlayerControl(this, getLobbyPlayer(), null));
|
||||
game.fireEvent(new GameEventPlayerControl(this, getLobbyPlayer(), controller, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardShields;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.cost.Cost;
|
||||
@@ -140,6 +141,8 @@ public abstract class PlayerController {
|
||||
reveal(cards, zone, owner, null);
|
||||
}
|
||||
public abstract void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix);
|
||||
public abstract void reveal(Collection<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix);
|
||||
|
||||
/** Shows message to player to reveal chosen cardName, creatureType, number etc. AI must analyze API to understand what that is */
|
||||
public abstract void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value);
|
||||
public abstract ImmutablePair<CardCollection, CardCollection> arrangeForScry(CardCollection topN);
|
||||
|
||||
@@ -21,8 +21,9 @@ import forge.trackable.TrackableProperty;
|
||||
import forge.trackable.Tracker;
|
||||
import forge.util.FCollectionView;
|
||||
|
||||
|
||||
public class PlayerView extends GameEntityView {
|
||||
private static final long serialVersionUID = 7005892740909549086L;
|
||||
|
||||
public static PlayerView get(Player p) {
|
||||
return p == null ? null : p.getView();
|
||||
}
|
||||
|
||||
@@ -77,9 +77,9 @@ public abstract class Ability extends SpellAbility {
|
||||
}
|
||||
|
||||
public static final Ability PLAY_LAND_SURROGATE = new Ability(null, (Cost)null, null){
|
||||
@Override
|
||||
@Override
|
||||
public boolean canPlay() {
|
||||
return true; //if this ability is added anywhere, it can be assumed that land can be played
|
||||
return true; //if this ability is added anywhere, it can be assumed that land can be played
|
||||
}
|
||||
@Override
|
||||
public void resolve() {
|
||||
|
||||
@@ -147,12 +147,23 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
view0 = new SpellAbilityView(this);
|
||||
}
|
||||
view = view0;
|
||||
if (hostCard != null && hostCard.getGame() != null) {
|
||||
hostCard.getGame().addSpellAbility(id, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return obj instanceof SpellAbility && this.id == ((SpellAbility) obj).id;
|
||||
};
|
||||
|
||||
@Override
|
||||
public void setHostCard(final Card c) {
|
||||
@@ -1247,6 +1258,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
public SpellAbilityView getView() {
|
||||
view.updateHostCard(this);
|
||||
view.updateDescription(this);
|
||||
view.updateCanPlay(this);
|
||||
view.updatePromptIfOnlyPossibleAbility(this);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,9 @@ import forge.trackable.TrackableCollection;
|
||||
import forge.trackable.TrackableObject;
|
||||
import forge.trackable.TrackableProperty;
|
||||
|
||||
|
||||
public class SpellAbilityView extends TrackableObject {
|
||||
private static final long serialVersionUID = 2514234930798754769L;
|
||||
|
||||
public static SpellAbilityView get(SpellAbility spab) {
|
||||
return spab == null ? null : spab.getView();
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ import forge.trackable.TrackableObject;
|
||||
import forge.trackable.TrackableProperty;
|
||||
import forge.util.FCollectionView;
|
||||
|
||||
|
||||
public class StackItemView extends TrackableObject {
|
||||
private static final long serialVersionUID = 6733415646691356052L;
|
||||
|
||||
public static StackItemView get(SpellAbilityStackInstance si) {
|
||||
return si == null ? null : si.getView();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,16 @@
|
||||
*/
|
||||
package forge.game.zone;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -45,14 +55,17 @@ import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.replacement.ReplacementLayer;
|
||||
import forge.game.spellability.*;
|
||||
import forge.game.spellability.Ability;
|
||||
import forge.game.spellability.AbilityStatic;
|
||||
import forge.game.spellability.OptionalCost;
|
||||
import forge.game.spellability.Spell;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.TargetChoices;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerType;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* MagicStack class.
|
||||
@@ -518,6 +531,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
setResolving(false);
|
||||
unfreezeStack();
|
||||
sa.resetOnceResolved();
|
||||
game.updateStackForView();
|
||||
|
||||
//game.getAction().checkStaticAbilities();
|
||||
game.getPhaseHandler().onStackResolved();
|
||||
|
||||
@@ -5,6 +5,8 @@ import java.util.Collection;
|
||||
import forge.util.FCollection;
|
||||
|
||||
public class TrackableCollection<T extends TrackableObject> extends FCollection<T> {
|
||||
private static final long serialVersionUID = 1528674215758232314L;
|
||||
|
||||
public TrackableCollection() {
|
||||
}
|
||||
public TrackableCollection(T e) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.trackable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
@@ -8,7 +9,9 @@ import java.util.Set;
|
||||
import forge.game.IIdentifiable;
|
||||
|
||||
//base class for objects that can be tracked and synced between game server and GUI
|
||||
public abstract class TrackableObject implements IIdentifiable {
|
||||
public abstract class TrackableObject implements IIdentifiable, Serializable {
|
||||
private static final long serialVersionUID = 7386836745378571056L;
|
||||
|
||||
private final int id;
|
||||
protected final transient Tracker tracker;
|
||||
private final Map<TrackableProperty, Object> props;
|
||||
@@ -60,6 +63,30 @@ public abstract class TrackableObject implements IIdentifiable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy to this Trackable object the first object of the provided iterator
|
||||
* whose id matches.
|
||||
*
|
||||
* @see TrackableObject#copy(TrackableObject)
|
||||
*/
|
||||
public final void copy(final Iterable<? extends TrackableObject> others) {
|
||||
for (final TrackableObject other : others) {
|
||||
if (this.equals(other)) {
|
||||
copy(other);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all properties of another Trackable object to this object.
|
||||
*/
|
||||
public final void copy(final TrackableObject other) {
|
||||
for (final TrackableProperty prop : other.props.keySet()) {
|
||||
set(prop, other.get(prop));
|
||||
}
|
||||
}
|
||||
|
||||
//use when updating collection type properties with using set
|
||||
protected final void flagAsChanged(final TrackableProperty key) {
|
||||
changedProps.add(key);
|
||||
|
||||
@@ -142,6 +142,7 @@ public enum TrackableProperty {
|
||||
MatchOver(TrackableTypes.BooleanType),
|
||||
NumGamesInMatch(TrackableTypes.IntegerType),
|
||||
NumPlayedGamesInMatch(TrackableTypes.IntegerType),
|
||||
Stack(TrackableTypes.StackItemViewListType),
|
||||
StormCount(TrackableTypes.IntegerType),
|
||||
GameOver(TrackableTypes.BooleanType),
|
||||
PoisonCountersToLose(TrackableTypes.IntegerType),
|
||||
|
||||
@@ -13,8 +13,8 @@ import forge.card.ColorSet;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.keyword.KeywordCollection.KeywordCollectionView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.StackItemView;
|
||||
@@ -284,6 +284,22 @@ public class TrackableTypes {
|
||||
}
|
||||
}
|
||||
};
|
||||
public static final TrackableType<TrackableCollection<StackItemView>> StackItemViewListType = new TrackableType<TrackableCollection<StackItemView>>() {
|
||||
@Override
|
||||
protected TrackableCollection<StackItemView> getDefaultValue() {
|
||||
return new TrackableCollection<StackItemView>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrackableCollection<StackItemView> deserialize(TrackableDeserializer td, TrackableCollection<StackItemView> oldValue) {
|
||||
return td.readCollection(oldValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serialize(TrackableSerializer ts, TrackableCollection<StackItemView> value) {
|
||||
ts.write(value);
|
||||
}
|
||||
};
|
||||
public static final TrackableType<ManaCost> ManaCostType = new TrackableType<ManaCost>() {
|
||||
@Override
|
||||
public ManaCost getDefaultValue() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -12,7 +13,9 @@ import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
|
||||
//base class for a collection with quick lookup and that maintains order
|
||||
public class FCollection<T> implements List<T>, Set<T>, FCollectionView<T>, Cloneable {
|
||||
public class FCollection<T> implements List<T>, Set<T>, FCollectionView<T>, Cloneable, Serializable {
|
||||
private static final long serialVersionUID = -1664555336364294106L;
|
||||
|
||||
private final HashSet<T> set = new HashSet<T>();
|
||||
private final LinkedList<T> list = new LinkedList<T>();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.GameObject;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class MessageUtil {
|
||||
@@ -17,6 +18,14 @@ public class MessageUtil {
|
||||
return message;
|
||||
}
|
||||
|
||||
public static String formatMessage(String message, PlayerView player, Object related) {
|
||||
if (related instanceof Player && message.indexOf("{player") >= 0) {
|
||||
String noun = mayBeYou(player, related);
|
||||
message = message.replace("{player}", noun).replace("{player's}", Lang.getPossesive(noun));
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
// These are not much related to PlayerController
|
||||
public static String formatNotificationMessage(SpellAbility sa, Player player, GameObject target, String value) {
|
||||
if (sa == null || sa.getApi() == null || sa.getHostCard() == null) {
|
||||
@@ -50,4 +59,7 @@ public class MessageUtil {
|
||||
public static String mayBeYou(Player player, Object what) {
|
||||
return what == null ? "(null)" : what == player ? "you" : what.toString();
|
||||
}
|
||||
public static String mayBeYou(PlayerView player, Object what) {
|
||||
return what == null ? "(null)" : what == player ? "you" : what.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import forge.download.GuiDownloader;
|
||||
import forge.error.BugReportDialog;
|
||||
import forge.gui.BoxedProductCardListViewer;
|
||||
import forge.gui.CardListViewer;
|
||||
import forge.gui.FNetOverlay;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.framework.FScreen;
|
||||
import forge.interfaces.IGuiBase;
|
||||
@@ -280,9 +279,4 @@ public class GuiDesktop implements IGuiBase {
|
||||
return match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void netMessage(final String origin, final String message) {
|
||||
FNetOverlay.SINGLETON_INSTANCE.showUp("");
|
||||
FNetOverlay.SINGLETON_INSTANCE.addMessage(origin, message);
|
||||
}
|
||||
}
|
||||
@@ -135,9 +135,14 @@ public enum FNetOverlay {
|
||||
getPanel().validate();
|
||||
}
|
||||
|
||||
SimpleDateFormat inFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
public void addMessage(String origin, String message) {
|
||||
String toAdd = String.format("%n[%s] %s: %s", inFormat.format(new Date()), origin, message);
|
||||
private final static SimpleDateFormat inFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
public void addMessage(final String origin, final String message) {
|
||||
final String toAdd;
|
||||
if (origin == null) {
|
||||
toAdd = String.format("%n[%s] %s: %s", inFormat.format(new Date()), origin, message);
|
||||
} else {
|
||||
toAdd = String.format("%n[%s] %s", inFormat.format(new Date()), message);
|
||||
}
|
||||
txtLog.append(toAdd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,39 +2,17 @@ package forge.screens.home;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import com.beust.jcommander.internal.Maps;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.deck.DeckType;
|
||||
import forge.deck.DeckgenUtil;
|
||||
import forge.game.GameType;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.gui.GuiDialog;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.model.CardCollections;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.toolbox.FList;
|
||||
import forge.toolbox.FOptionPane;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.storage.IStorage;
|
||||
|
||||
public class CLobby {
|
||||
|
||||
@@ -118,7 +96,6 @@ public class CLobby {
|
||||
}
|
||||
|
||||
// General updates when switching back to this view
|
||||
view.updatePlayersFromPrefs();
|
||||
view.getBtnStart().requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
@@ -134,14 +111,6 @@ public class CLobby {
|
||||
view.getDeckChooser(6).initialize(FPref.CONSTRUCTED_P7_DECK_STATE, DeckType.COLOR_DECK);
|
||||
view.getDeckChooser(7).initialize(FPref.CONSTRUCTED_P8_DECK_STATE, DeckType.COLOR_DECK);
|
||||
|
||||
// Start button event handling
|
||||
view.getBtnStart().addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent arg0) {
|
||||
startGame(view.getAppliedVariants());
|
||||
}
|
||||
});
|
||||
|
||||
final ForgePreferences prefs = FModel.getPreferences();
|
||||
// Checkbox event handling
|
||||
view.getCbSingletons().addActionListener(new ActionListener() {
|
||||
@@ -165,208 +134,4 @@ public class CLobby {
|
||||
view.getCbArtifacts().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_ARTIFACTS));
|
||||
}
|
||||
|
||||
/** Starts a match with the applied variants. */
|
||||
private void startGame(final Set<GameType> variantTypes) {
|
||||
if (!view.isEnoughTeams()) {
|
||||
FOptionPane.showMessageDialog("There are not enough teams! Please adjust team allocations.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (final int i : view.getParticipants()) {
|
||||
if (view.getDeckChooser(i).getPlayer() == null) {
|
||||
FOptionPane.showMessageDialog("Please specify a deck for " + view.getPlayerName(i));
|
||||
return;
|
||||
}
|
||||
} // Is it even possible anymore? I think current implementation assigns decks automatically.
|
||||
|
||||
GameType autoGenerateVariant = null;
|
||||
boolean isCommanderMatch = false;
|
||||
boolean isTinyLeadersMatch = false;
|
||||
if (!variantTypes.isEmpty()) {
|
||||
isTinyLeadersMatch = variantTypes.contains(GameType.TinyLeaders);
|
||||
isCommanderMatch = isTinyLeadersMatch || variantTypes.contains(GameType.Commander);
|
||||
if (!isCommanderMatch) {
|
||||
for (GameType variant : variantTypes) {
|
||||
if (variant.isAutoGenerated()) {
|
||||
autoGenerateVariant = variant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
|
||||
|
||||
//Auto-generated decks don't need to be checked here
|
||||
//Commander deck replaces regular deck and is checked later
|
||||
if (checkLegality && autoGenerateVariant == null && !isCommanderMatch) {
|
||||
for (final int i : view.getParticipants()) {
|
||||
String name = view.getPlayerName(i);
|
||||
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(view.getDeckChooser(i).getPlayer().getDeck());
|
||||
if (null != errMsg) {
|
||||
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>();
|
||||
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
|
||||
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
|
||||
for (final int i : view.getParticipants()) {
|
||||
final String name = view.getPlayerName(i);
|
||||
final boolean isAI = view.isPlayerAI(i);
|
||||
final LobbyPlayer lobbyPlayer = isAI
|
||||
? GamePlayerUtil.createAiPlayer(name, view.getPlayerAvatar(i), view.getAiOptions(i))
|
||||
: GamePlayerUtil.getGuiPlayer(name, i);
|
||||
RegisteredPlayer rp = view.getDeckChooser(i).getPlayer();
|
||||
|
||||
if (variantTypes.isEmpty()) {
|
||||
rp.setTeamNumber(view.getTeam(i));
|
||||
players.add(rp.setPlayer(lobbyPlayer));
|
||||
} else {
|
||||
Deck deck = null;
|
||||
PaperCard vanguardAvatar = null;
|
||||
if (isCommanderMatch) {
|
||||
final Object selected = view.getCommanderDeckLists().get(i).getSelectedValue();
|
||||
if (selected instanceof String) {
|
||||
final String sel = (String) selected;
|
||||
final IStorage<Deck> comDecks = FModel.getDecks().getCommander();
|
||||
if (sel.equals("Random") && comDecks.size() > 0) {
|
||||
deck = Aggregates.random(comDecks);
|
||||
}
|
||||
} else {
|
||||
deck = (Deck) selected;
|
||||
}
|
||||
GameType commanderGameType = isTinyLeadersMatch ? GameType.TinyLeaders : GameType.Commander;
|
||||
if (deck == null) { //Can be null if player deselects the list selection or chose Generate
|
||||
deck = DeckgenUtil.generateCommanderDeck(isAI, commanderGameType);
|
||||
}
|
||||
if (checkLegality) {
|
||||
String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck);
|
||||
if (null != errMsg) {
|
||||
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid " + commanderGameType + " Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (autoGenerateVariant != null) {
|
||||
deck = autoGenerateVariant.autoGenerateDeck(rp);
|
||||
CardPool avatarPool = deck.get(DeckSection.Avatar);
|
||||
if (avatarPool != null) {
|
||||
vanguardAvatar = avatarPool.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise variables for other variants
|
||||
deck = deck == null ? rp.getDeck() : deck;
|
||||
Iterable<PaperCard> schemes = null;
|
||||
final boolean playerIsArchenemy = view.isPlayerArchenemy(i);
|
||||
Iterable<PaperCard> planes = null;
|
||||
|
||||
//Archenemy
|
||||
if (variantTypes.contains(GameType.ArchenemyRumble)
|
||||
|| (variantTypes.contains(GameType.Archenemy) && playerIsArchenemy)) {
|
||||
Object selected = view.getSchemeDeckLists().get(i).getSelectedValue();
|
||||
CardPool schemePool = null;
|
||||
if (selected instanceof String) {
|
||||
String sel = (String) selected;
|
||||
if (sel.contains("Use deck's scheme section")) {
|
||||
if (deck.has(DeckSection.Schemes)) {
|
||||
schemePool = deck.get(DeckSection.Schemes);
|
||||
} else {
|
||||
sel = "Random";
|
||||
}
|
||||
}
|
||||
IStorage<Deck> sDecks = FModel.getDecks().getScheme();
|
||||
if (sel.equals("Random") && sDecks.size() != 0) {
|
||||
schemePool = Aggregates.random(sDecks).get(DeckSection.Schemes);
|
||||
}
|
||||
} else {
|
||||
schemePool = ((Deck) selected).get(DeckSection.Schemes);
|
||||
}
|
||||
if (schemePool == null) { //Can be null if player deselects the list selection or chose Generate
|
||||
schemePool = DeckgenUtil.generateSchemePool();
|
||||
}
|
||||
if (checkLegality) {
|
||||
String errMsg = DeckFormat.getSchemeSectionConformanceProblem(schemePool);
|
||||
if (null != errMsg) {
|
||||
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Scheme Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
schemes = schemePool.toFlatList();
|
||||
}
|
||||
|
||||
//Planechase
|
||||
if (variantTypes.contains(GameType.Planechase)) {
|
||||
Object selected = view.getPlanarDeckLists().get(i).getSelectedValue();
|
||||
CardPool planePool = null;
|
||||
if (selected instanceof String) {
|
||||
String sel = (String) selected;
|
||||
if (sel.contains("Use deck's planes section")) {
|
||||
if (deck.has(DeckSection.Planes)) {
|
||||
planePool = deck.get(DeckSection.Planes);
|
||||
} else {
|
||||
sel = "Random";
|
||||
}
|
||||
}
|
||||
IStorage<Deck> pDecks = FModel.getDecks().getPlane();
|
||||
if (sel.equals("Random") && pDecks.size() != 0) {
|
||||
planePool = Aggregates.random(pDecks).get(DeckSection.Planes);
|
||||
}
|
||||
} else {
|
||||
planePool = ((Deck) selected).get(DeckSection.Planes);
|
||||
}
|
||||
if (planePool == null) { //Can be null if player deselects the list selection or chose Generate
|
||||
planePool = DeckgenUtil.generatePlanarPool();
|
||||
}
|
||||
if (checkLegality) {
|
||||
String errMsg = DeckFormat.getPlaneSectionConformanceProblem(planePool);
|
||||
if (null != errMsg) {
|
||||
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Planar Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
planes = planePool.toFlatList();
|
||||
}
|
||||
|
||||
//Vanguard
|
||||
if (variantTypes.contains(GameType.Vanguard)) {
|
||||
Object selected = view.getVanguardLists().get(i).getSelectedValue();
|
||||
if (selected instanceof String) {
|
||||
String sel = (String) selected;
|
||||
if (sel.contains("Use deck's default avatar") && deck.has(DeckSection.Avatar)) {
|
||||
vanguardAvatar = deck.get(DeckSection.Avatar).get(0);
|
||||
} else { //Only other string is "Random"
|
||||
if (isAI) { //AI
|
||||
vanguardAvatar = Aggregates.random(view.getNonRandomAiAvatars());
|
||||
} else { //Human
|
||||
vanguardAvatar = Aggregates.random(view.getNonRandomHumanAvatars());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vanguardAvatar = (PaperCard)selected;
|
||||
}
|
||||
if (vanguardAvatar == null) { //ERROR! null if avatar deselected on list
|
||||
GuiDialog.message("No Vanguard avatar selected for " + name
|
||||
+ ". Please choose one or disable the Vanguard variant");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rp = RegisteredPlayer.forVariants(variantTypes, deck, schemes, playerIsArchenemy, planes, vanguardAvatar);
|
||||
rp.setTeamNumber(view.getTeam(i));
|
||||
players.add(rp.setPlayer(lobbyPlayer));
|
||||
}
|
||||
|
||||
if (!isAI) {
|
||||
guis.put(rp, gui);
|
||||
}
|
||||
view.getDeckChooser(i).saveState();
|
||||
}
|
||||
|
||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.startMatch(GameType.Constructed, variantTypes, players, guis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
@@ -17,7 +19,9 @@ import net.miginfocom.swing.MigLayout;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.Singletons;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
@@ -25,6 +29,7 @@ import forge.deck.DeckSection;
|
||||
import forge.game.GameType;
|
||||
import forge.gui.framework.FScreen;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.LobbySlot;
|
||||
import forge.model.FModel;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.properties.ForgePreferences;
|
||||
@@ -32,7 +37,6 @@ import forge.properties.ForgePreferences.FPref;
|
||||
import forge.screens.deckeditor.CDeckEditorUI;
|
||||
import forge.screens.deckeditor.controllers.CEditorCommander;
|
||||
import forge.screens.deckeditor.controllers.CEditorVariant;
|
||||
import forge.screens.home.VLobby.LobbyType;
|
||||
import forge.screens.home.sanctioned.AvatarSelector;
|
||||
import forge.toolbox.FComboBox;
|
||||
import forge.toolbox.FComboBoxWrapper;
|
||||
@@ -53,17 +57,16 @@ public class PlayerPanel extends FPanel {
|
||||
private final static ForgePreferences prefs = FModel.getPreferences();
|
||||
private static final SkinColor unfocusedPlayerOverlay = FSkin.getColor(FSkin.Colors.CLR_OVERLAY).alphaColor(120);
|
||||
|
||||
private LobbySlotType type;
|
||||
private final int index;
|
||||
private final LobbyType lobbyType;
|
||||
|
||||
private LobbySlotType type = LobbySlotType.LOCAL;
|
||||
private boolean editableForClient;
|
||||
private String playerName = StringUtils.EMPTY;
|
||||
private boolean mayEdit, mayControl, mayRemove;
|
||||
|
||||
private final FLabel nameRandomiser;
|
||||
private final FLabel avatarLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build();
|
||||
private int avatarIndex;
|
||||
|
||||
private final FTextField txtPlayerName = new FTextField.Builder().text("Player name").build();
|
||||
private final FTextField txtPlayerName = new FTextField.Builder().build();
|
||||
private FRadioButton radioHuman;
|
||||
private FRadioButton radioAi;
|
||||
private JCheckBoxMenuItem radioAiUseSimulation;
|
||||
@@ -78,7 +81,6 @@ public class PlayerPanel extends FPanel {
|
||||
|
||||
private final String variantBtnConstraints = "height 30px, hidemode 3";
|
||||
|
||||
private boolean playerIsArchenemy = false;
|
||||
private final FLabel scmDeckSelectorBtn = new FLabel.ButtonBuilder().text("Select a scheme deck").build();
|
||||
private final FLabel scmDeckEditor = new FLabel.ButtonBuilder().text("Scheme Deck Editor").build();
|
||||
private final FLabel scmLabel;
|
||||
@@ -95,26 +97,25 @@ public class PlayerPanel extends FPanel {
|
||||
private final FLabel vgdLabel;
|
||||
|
||||
private final VLobby lobby;
|
||||
public PlayerPanel(final VLobby lobby, final int index, final LobbyType lobbyType) {
|
||||
public PlayerPanel(final VLobby lobby, final boolean allowNetworking, final int index, final LobbySlot slot, final boolean mayEdit, final boolean mayControl) {
|
||||
super();
|
||||
|
||||
this.lobby = lobby;
|
||||
this.index = index;
|
||||
this.mayEdit = mayEdit;
|
||||
this.mayControl = mayControl;
|
||||
|
||||
this.deckLabel = lobby.newLabel("Deck:");
|
||||
this.scmLabel = lobby.newLabel("Scheme deck:");
|
||||
this.cmdLabel = lobby.newLabel("Commander deck:");
|
||||
this.pchLabel = lobby.newLabel("Planar deck:");
|
||||
this.vgdLabel = lobby.newLabel("Vanguard:");
|
||||
|
||||
this.index = index;
|
||||
this.lobbyType = lobbyType;
|
||||
this.playerIsArchenemy = index == 0;
|
||||
|
||||
setLayout(new MigLayout("insets 10px, gap 5px"));
|
||||
|
||||
// Add a button to players 3+ (or if server) to remove them from the setup
|
||||
closeBtn = createCloseButton();
|
||||
if (index >= 2 || lobbyType == LobbyType.SERVER) {
|
||||
this.add(closeBtn, "w 20, h 20, pos (container.w-20) 0");
|
||||
}
|
||||
this.add(closeBtn, "w 20, h 20, pos (container.w-20) 0");
|
||||
|
||||
createAvatar();
|
||||
this.add(avatarLabel, "spany 2, width 80px, height 80px");
|
||||
@@ -132,12 +133,18 @@ public class PlayerPanel extends FPanel {
|
||||
|
||||
this.add(lobby.newLabel("Team:"), "w 40px, h 30px");
|
||||
populateTeamsComboBoxes();
|
||||
|
||||
// Set these before action listeners are added
|
||||
this.setTeam(slot == null ? index : slot.getTeam());
|
||||
this.setIsArchenemy(slot != null && slot.isArchenemy());
|
||||
|
||||
teamComboBox.addActionListener(teamListener);
|
||||
aeTeamComboBox.addActionListener(teamListener);
|
||||
teamComboBox.addTo(this, variantBtnConstraints + ", pushx, growx, gaptop 5px");
|
||||
aeTeamComboBox.addTo(this, variantBtnConstraints + ", pushx, growx, gaptop 5px");
|
||||
if (lobbyType == LobbyType.SERVER) {
|
||||
this.add(radioOpen, "gapleft 1px");
|
||||
|
||||
if (allowNetworking) {
|
||||
this.add(radioOpen, "cell 4 1, ax left, sx 2, wrap");
|
||||
}
|
||||
|
||||
this.add(deckLabel, variantBtnConstraints + ", cell 0 2, sx 2, ax right");
|
||||
@@ -161,7 +168,6 @@ public class PlayerPanel extends FPanel {
|
||||
this.add(vgdSelectorBtn, variantBtnConstraints + ", cell 2 6, sx 4, growx, wrap");
|
||||
|
||||
addHandlersToVariantsControls();
|
||||
updateVariantControlsVisibility();
|
||||
|
||||
this.addMouseListener(new FMouseAdapter() {
|
||||
@Override public final void onLeftMouseDown(final MouseEvent e) {
|
||||
@@ -169,46 +175,62 @@ public class PlayerPanel extends FPanel {
|
||||
}
|
||||
});
|
||||
|
||||
this.type = slot == null ? LobbySlotType.LOCAL : slot.getType();
|
||||
this.setPlayerName(slot == null ? "" : slot.getName());
|
||||
this.setAvatar(slot == null ? 0 : slot.getAvatarIndex());
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (type != LobbySlotType.REMOTE) {
|
||||
if (radioHuman.isSelected()) {
|
||||
type = LobbySlotType.LOCAL;
|
||||
} else if (radioAi.isSelected()) {
|
||||
type = LobbySlotType.AI;
|
||||
} else if (radioOpen.isSelected()) {
|
||||
type = LobbySlotType.OPEN;
|
||||
}
|
||||
avatarLabel.setEnabled(mayEdit);
|
||||
avatarLabel.setIcon(FSkin.getAvatars().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : avatarIndex)));
|
||||
avatarLabel.repaintSelf();
|
||||
|
||||
txtPlayerName.setEnabled(mayEdit);
|
||||
txtPlayerName.setText(type == LobbySlotType.OPEN ? StringUtils.EMPTY : playerName);
|
||||
nameRandomiser.setEnabled(mayEdit);
|
||||
deckLabel.setVisible(mayEdit);
|
||||
deckBtn.setVisible(mayEdit);
|
||||
|
||||
closeBtn.setVisible(mayRemove);
|
||||
|
||||
if (mayRemove) {
|
||||
radioHuman.setEnabled(mayControl);
|
||||
radioAi.setEnabled(mayControl);
|
||||
radioOpen.setEnabled(mayControl);
|
||||
} else {
|
||||
radioHuman.setVisible(mayControl);
|
||||
radioAi.setVisible(mayControl);
|
||||
radioOpen.setVisible(mayControl);
|
||||
}
|
||||
|
||||
final boolean isEditable = lobbyType == LobbyType.LOCAL || type == LobbySlotType.LOCAL ||
|
||||
(lobbyType == LobbyType.SERVER && (type == LobbySlotType.LOCAL || type == LobbySlotType.AI)) ||
|
||||
(lobbyType == LobbyType.CLIENT && editableForClient);
|
||||
avatarLabel.setEnabled(isEditable);
|
||||
txtPlayerName.setEnabled(isEditable);
|
||||
nameRandomiser.setEnabled(isEditable);
|
||||
deckLabel.setVisible(isEditable);
|
||||
deckBtn.setVisible(isEditable);
|
||||
radioHuman.setSelected(type == LobbySlotType.LOCAL);
|
||||
radioAi.setSelected(type == LobbySlotType.AI);
|
||||
radioOpen.setSelected(type == LobbySlotType.OPEN);
|
||||
|
||||
final boolean hasSlotControls = lobbyType == LobbyType.LOCAL || (lobbyType == LobbyType.SERVER && type != LobbySlotType.REMOTE);
|
||||
closeBtn.setVisible(hasSlotControls);
|
||||
radioAi.setVisible(hasSlotControls);
|
||||
radioHuman.setVisible(hasSlotControls);
|
||||
radioOpen.setVisible(hasSlotControls && lobbyType == LobbyType.SERVER);
|
||||
updateVariantControlsVisibility();
|
||||
}
|
||||
|
||||
private final FMouseAdapter radioMouseAdapter = new FMouseAdapter() {
|
||||
@Override public final void onLeftClick(final MouseEvent e) {
|
||||
avatarLabel.requestFocusInWindow();
|
||||
lobby.updateVanguardList(index);
|
||||
update();
|
||||
}
|
||||
private final FMouseAdapter radioMouseAdapter(final FRadioButton source, final LobbySlotType type) {
|
||||
return new FMouseAdapter() {
|
||||
@Override public final void onLeftClick(final MouseEvent e) {
|
||||
if (!source.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
setType(type);
|
||||
lobby.firePlayerChangeListener(index);
|
||||
avatarLabel.requestFocusInWindow();
|
||||
lobby.updateVanguardList(index);
|
||||
lobby.update();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/** Listens to name text fields and gives the appropriate player focus.
|
||||
* Also saves the name preference when leaving player one's text field. */
|
||||
/**
|
||||
* Listens to name text fields and gives the appropriate player focus. Also
|
||||
* saves the name preference when leaving player one's text field.
|
||||
*/
|
||||
private FocusAdapter nameFocusListener = new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
@@ -226,7 +248,8 @@ public class PlayerPanel extends FPanel {
|
||||
prefs.setPref(FPref.PLAYER_NAME, newName);
|
||||
prefs.save();
|
||||
}
|
||||
lobby.firePlayerChangeListener();
|
||||
lobby.firePlayerChangeListener(index);
|
||||
lobby.update();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -247,10 +270,10 @@ public class PlayerPanel extends FPanel {
|
||||
|
||||
final FLabel avatar = (FLabel)e.getSource();
|
||||
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index);
|
||||
lobby.changePlayerFocus(index);
|
||||
avatar.requestFocusInWindow();
|
||||
|
||||
final AvatarSelector aSel = new AvatarSelector(getPlayerName(), avatarIndex, PlayerPanel.this.lobby.getUsedAvatars());
|
||||
final AvatarSelector aSel = new AvatarSelector(playerName, avatarIndex, lobby.getUsedAvatars());
|
||||
for (final FLabel lbl : aSel.getSelectables()) {
|
||||
lbl.setCommand(new UiCommand() {
|
||||
@Override
|
||||
@@ -265,64 +288,35 @@ public class PlayerPanel extends FPanel {
|
||||
aSel.dispose();
|
||||
|
||||
if (index < 2) {
|
||||
PlayerPanel.this.lobby.updateAvatarPrefs();
|
||||
lobby.updateAvatarPrefs();
|
||||
}
|
||||
|
||||
lobby.firePlayerChangeListener();
|
||||
lobby.firePlayerChangeListener(index);
|
||||
}
|
||||
@Override public final void onRightClick(final MouseEvent e) {
|
||||
if (!avatarLabel.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index);
|
||||
lobby.changePlayerFocus(index);
|
||||
avatarLabel.requestFocusInWindow();
|
||||
|
||||
setRandomAvatar();
|
||||
|
||||
if (index < 2) {
|
||||
PlayerPanel.this.lobby.updateAvatarPrefs();
|
||||
lobby.updateAvatarPrefs();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void updateVariantControlsVisibility() {
|
||||
boolean isCommanderApplied = false;
|
||||
boolean isPlanechaseApplied = false;
|
||||
boolean isVanguardApplied = false;
|
||||
boolean isArchenemyApplied = false;
|
||||
boolean archenemyVisiblity = false;
|
||||
boolean isDeckBuildingAllowed = true;
|
||||
|
||||
for (final GameType variant : lobby.getAppliedVariants()) {
|
||||
switch (variant) {
|
||||
case Archenemy:
|
||||
isArchenemyApplied = true;
|
||||
if (playerIsArchenemy) {
|
||||
archenemyVisiblity = true;
|
||||
}
|
||||
break;
|
||||
case ArchenemyRumble:
|
||||
archenemyVisiblity = true;
|
||||
break;
|
||||
case Commander:
|
||||
case TinyLeaders:
|
||||
isCommanderApplied = true;
|
||||
isDeckBuildingAllowed = false; //Commander deck replaces basic deck, so hide that
|
||||
break;
|
||||
case Planechase:
|
||||
isPlanechaseApplied = true;
|
||||
break;
|
||||
case Vanguard:
|
||||
isVanguardApplied = true;
|
||||
break;
|
||||
default:
|
||||
if (variant.isAutoGenerated()) {
|
||||
isDeckBuildingAllowed = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void updateVariantControlsVisibility() {
|
||||
boolean isCommanderApplied = mayEdit && (lobby.hasVariant(GameType.Commander) || lobby.hasVariant(GameType.TinyLeaders));
|
||||
boolean isPlanechaseApplied = mayEdit && lobby.hasVariant(GameType.Planechase);
|
||||
boolean isVanguardApplied = mayEdit && lobby.hasVariant(GameType.Vanguard);
|
||||
boolean isArchenemyApplied = mayEdit && lobby.hasVariant(GameType.Archenemy);
|
||||
boolean archenemyVisiblity = mayEdit && lobby.hasVariant(GameType.ArchenemyRumble) || (isArchenemyApplied && isArchenemy());
|
||||
// Commander deck building replaces normal one, so hide it
|
||||
boolean isDeckBuildingAllowed = mayEdit && !isCommanderApplied && !lobby.hasVariant(GameType.MomirBasic);
|
||||
|
||||
deckLabel.setVisible(isDeckBuildingAllowed);
|
||||
deckBtn.setVisible(isDeckBuildingAllowed);
|
||||
@@ -336,7 +330,6 @@ public class PlayerPanel extends FPanel {
|
||||
|
||||
teamComboBox.setVisible(!isArchenemyApplied);
|
||||
aeTeamComboBox.setVisible(isArchenemyApplied);
|
||||
aeTeamComboBox.setEnabled(!(isArchenemyApplied && playerIsArchenemy));
|
||||
|
||||
pchDeckSelectorBtn.setVisible(isPlanechaseApplied);
|
||||
pchDeckEditor.setVisible(isPlanechaseApplied);
|
||||
@@ -367,30 +360,53 @@ public class PlayerPanel extends FPanel {
|
||||
return type == LobbySlotType.AI;
|
||||
}
|
||||
|
||||
public boolean isSimulatedAi() {
|
||||
public Set<AIOption> getAiOptions() {
|
||||
return isSimulatedAi()
|
||||
? ImmutableSet.of(AIOption.USE_SIMULATION)
|
||||
: Collections.<AIOption>emptySet();
|
||||
}
|
||||
private boolean isSimulatedAi() {
|
||||
return radioAi.isSelected() && radioAiUseSimulation.isSelected();
|
||||
}
|
||||
public void setUseAiSimulation(final boolean useSimulation) {
|
||||
radioAi.setSelected(useSimulation);
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return type == LobbySlotType.LOCAL;
|
||||
}
|
||||
|
||||
public boolean isArchenemy() {
|
||||
return playerIsArchenemy;
|
||||
return aeTeamComboBox.getSelectedIndex() == 0;
|
||||
}
|
||||
|
||||
public void setRemote(final boolean remote) {
|
||||
if (remote) {
|
||||
type = LobbySlotType.REMOTE;
|
||||
} else {
|
||||
public void setType(final LobbySlotType type) {
|
||||
this.type = type;
|
||||
switch (type) {
|
||||
case LOCAL:
|
||||
radioHuman.setSelected(true);
|
||||
break;
|
||||
case AI:
|
||||
radioAi.setSelected(true);
|
||||
break;
|
||||
case OPEN:
|
||||
radioOpen.setSelected(true);
|
||||
type = LobbySlotType.OPEN;
|
||||
break;
|
||||
case REMOTE:
|
||||
break;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
public void setEditableForClient(final boolean editable) {
|
||||
editableForClient = editable;
|
||||
public void setRemote(final boolean remote) {
|
||||
if (remote) {
|
||||
setType(LobbySlotType.REMOTE);
|
||||
radioHuman.setSelected(false);
|
||||
radioAi.setSelected(false);
|
||||
radioOpen.setSelected(false);
|
||||
} else {
|
||||
setType(LobbySlotType.OPEN);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVanguardButtonText(String text) {
|
||||
@@ -408,77 +424,46 @@ public class PlayerPanel extends FPanel {
|
||||
private void populateTeamsComboBoxes() {
|
||||
aeTeamComboBox.addItem("Archenemy");
|
||||
aeTeamComboBox.addItem("Heroes");
|
||||
aeTeamComboBox.setSelectedIndex(lobby.getArchenemyTeams().get(index) - 1);
|
||||
aeTeamComboBox.setEnabled(playerIsArchenemy);
|
||||
|
||||
for (int i = 1; i <= VLobby.MAX_PLAYERS; i++) {
|
||||
teamComboBox.addItem(i);
|
||||
}
|
||||
teamComboBox.setSelectedIndex(lobby.getTeams().get(index) - 1);
|
||||
teamComboBox.setEnabled(true);
|
||||
}
|
||||
|
||||
private ActionListener teamListener = new ActionListener() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
FComboBox<Object> cb = (FComboBox<Object>)e.getSource();
|
||||
@Override public final void actionPerformed(final ActionEvent e) {
|
||||
final FComboBox<Object> cb = (FComboBox<Object>) e.getSource();
|
||||
cb.requestFocusInWindow();
|
||||
Object selection = cb.getSelectedItem();
|
||||
final Object selection = cb.getSelectedItem();
|
||||
|
||||
if (null == selection) {
|
||||
return;
|
||||
if (null != selection) {
|
||||
lobby.changePlayerFocus(index);
|
||||
lobby.firePlayerChangeListener(index);
|
||||
}
|
||||
if (PlayerPanel.this.lobby.getAppliedVariants().contains(GameType.Archenemy)) {
|
||||
String sel = (String) selection;
|
||||
if (sel.contains("Archenemy")) {
|
||||
PlayerPanel.this.lobby.setLastArchenemy(index);
|
||||
for (PlayerPanel pp : PlayerPanel.this.lobby.getPlayerPanels()) {
|
||||
int i = pp.index;
|
||||
PlayerPanel.this.lobby.getArchenemyTeams().set(i, i == PlayerPanel.this.lobby.getLastArchenemy() ? 1 : 2);
|
||||
pp.aeTeamComboBox.setSelectedIndex(i == PlayerPanel.this.lobby.getLastArchenemy() ? 0 : 1);
|
||||
pp.toggleIsPlayerArchenemy();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Integer sel = (Integer) selection;
|
||||
PlayerPanel.this.lobby.getTeams().set(index, sel);
|
||||
}
|
||||
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index);
|
||||
}
|
||||
};
|
||||
|
||||
public void toggleIsPlayerArchenemy() {
|
||||
if (lobby.getAppliedVariants().contains(GameType.Archenemy)) {
|
||||
playerIsArchenemy = lobby.getLastArchenemy() == index;
|
||||
} else {
|
||||
playerIsArchenemy = lobby.getAppliedVariants().contains(GameType.ArchenemyRumble);
|
||||
}
|
||||
updateVariantControlsVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
*/
|
||||
private void addHandlersToVariantsControls() {
|
||||
// Archenemy buttons
|
||||
// Archenemy buttons
|
||||
scmDeckSelectorBtn.setCommand(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntArchenemy().isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble);
|
||||
@Override public final void run() {
|
||||
lobby.setCurrentGameMode(lobby.getVntArchenemy().isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble);
|
||||
scmDeckSelectorBtn.requestFocusInWindow();
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index, PlayerPanel.this.lobby.getCurrentGameMode());
|
||||
lobby.changePlayerFocus(index);
|
||||
}
|
||||
});
|
||||
|
||||
scmDeckEditor.setCommand(new UiCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntArchenemy().isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble);
|
||||
lobby.setCurrentGameMode(lobby.getVntArchenemy().isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble);
|
||||
Predicate<PaperCard> predSchemes = new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard arg0) {
|
||||
@Override public final boolean apply(final PaperCard arg0) {
|
||||
return arg0.getRules().getType().isScheme();
|
||||
}
|
||||
};
|
||||
@@ -493,16 +478,16 @@ public class PlayerPanel extends FPanel {
|
||||
cmdDeckSelectorBtn.setCommand(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntTinyLeaders().isSelected() ? GameType.TinyLeaders : GameType.Commander);
|
||||
lobby.setCurrentGameMode(lobby.getVntTinyLeaders().isSelected() ? GameType.TinyLeaders : GameType.Commander);
|
||||
cmdDeckSelectorBtn.requestFocusInWindow();
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index, PlayerPanel.this.lobby.getCurrentGameMode());
|
||||
lobby.changePlayerFocus(index);
|
||||
}
|
||||
});
|
||||
|
||||
cmdDeckEditor.setCommand(new UiCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntTinyLeaders().isSelected() ? GameType.TinyLeaders : GameType.Commander);
|
||||
lobby.setCurrentGameMode(lobby.getVntTinyLeaders().isSelected() ? GameType.TinyLeaders : GameType.Commander);
|
||||
Singletons.getControl().setCurrentScreen(FScreen.DECK_EDITOR_COMMANDER);
|
||||
CDeckEditorUI.SINGLETON_INSTANCE.setEditorController(new CEditorCommander(CDeckEditorUI.SINGLETON_INSTANCE.getCDetailPicture()));
|
||||
}
|
||||
@@ -512,16 +497,16 @@ public class PlayerPanel extends FPanel {
|
||||
pchDeckSelectorBtn.setCommand(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Planechase);
|
||||
lobby.setCurrentGameMode(GameType.Planechase);
|
||||
pchDeckSelectorBtn.requestFocusInWindow();
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index, GameType.Planechase);
|
||||
lobby.changePlayerFocus(index, GameType.Planechase);
|
||||
}
|
||||
});
|
||||
|
||||
pchDeckEditor.setCommand(new UiCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Planechase);
|
||||
lobby.setCurrentGameMode(GameType.Planechase);
|
||||
Predicate<PaperCard> predPlanes = new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard arg0) {
|
||||
@@ -539,9 +524,9 @@ public class PlayerPanel extends FPanel {
|
||||
vgdSelectorBtn.setCommand(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Vanguard);
|
||||
lobby.setCurrentGameMode(GameType.Vanguard);
|
||||
vgdSelectorBtn.requestFocusInWindow();
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index, GameType.Vanguard);
|
||||
lobby.changePlayerFocus(index, GameType.Vanguard);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -550,18 +535,22 @@ public class PlayerPanel extends FPanel {
|
||||
* @param index
|
||||
*/
|
||||
private void createPlayerTypeOptions() {
|
||||
final boolean isServer = lobbyType == LobbyType.SERVER;
|
||||
radioHuman = new FRadioButton(isServer ? "Local" : "Human", index == 0);
|
||||
radioAi = new FRadioButton("AI", !isServer && index != 0);
|
||||
radioOpen = new FRadioButton("Open", isServer && index != 0);
|
||||
radioHuman = new FRadioButton("Human");
|
||||
radioAi = new FRadioButton("AI");
|
||||
radioOpen = new FRadioButton("Open");
|
||||
|
||||
final JPopupMenu menu = new JPopupMenu();
|
||||
radioAiUseSimulation = new JCheckBoxMenuItem("Use Simulation");
|
||||
menu.add(radioAiUseSimulation);
|
||||
radioAiUseSimulation.addActionListener(new ActionListener() {
|
||||
@Override public final void actionPerformed(final ActionEvent e) {
|
||||
lobby.firePlayerChangeListener(index);
|
||||
} });
|
||||
radioAi.setComponentPopupMenu(menu);
|
||||
|
||||
radioHuman.addMouseListener(radioMouseAdapter);
|
||||
radioAi.addMouseListener(radioMouseAdapter);
|
||||
radioOpen.addMouseListener(radioMouseAdapter);
|
||||
radioHuman.addMouseListener(radioMouseAdapter(radioHuman, LobbySlotType.LOCAL));
|
||||
radioAi.addMouseListener (radioMouseAdapter(radioAi, LobbySlotType.AI));
|
||||
radioOpen.addMouseListener (radioMouseAdapter(radioOpen, LobbySlotType.OPEN));
|
||||
|
||||
final ButtonGroup tempBtnGroup = new ButtonGroup();
|
||||
tempBtnGroup.add(radioHuman);
|
||||
@@ -576,9 +565,9 @@ public class PlayerPanel extends FPanel {
|
||||
deckBtn.setCommand(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Constructed);
|
||||
lobby.setCurrentGameMode(GameType.Constructed);
|
||||
deckBtn.requestFocusInWindow();
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index, GameType.Constructed);
|
||||
lobby.changePlayerFocus(index, GameType.Constructed);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -594,7 +583,7 @@ public class PlayerPanel extends FPanel {
|
||||
newNameBtn.setCommand(new UiCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
String newName = PlayerPanel.this.lobby.getNewName();
|
||||
String newName = lobby.getNewName();
|
||||
if (null == newName) {
|
||||
return;
|
||||
}
|
||||
@@ -605,7 +594,7 @@ public class PlayerPanel extends FPanel {
|
||||
prefs.save();
|
||||
}
|
||||
txtPlayerName.requestFocus();
|
||||
PlayerPanel.this.lobby.changePlayerFocus(index);
|
||||
lobby.changePlayerFocus(index);
|
||||
}
|
||||
});
|
||||
newNameBtn.addFocusListener(nameFocusListener);
|
||||
@@ -640,10 +629,10 @@ public class PlayerPanel extends FPanel {
|
||||
.icon(FSkin.getIcon(FSkinProp.ICO_CLOSE)).hoverable(true).build();
|
||||
closeBtn.setCommand(new Runnable() {
|
||||
@Override public final void run() {
|
||||
if (type == LobbySlotType.REMOTE && !SOptionPane.showConfirmDialog(String.format("Really kick %s?", getPlayerName()), "Kick", false)) {
|
||||
if (type == LobbySlotType.REMOTE && !SOptionPane.showConfirmDialog(String.format("Really kick %s?", playerName), "Kick", false)) {
|
||||
return;
|
||||
}
|
||||
PlayerPanel.this.lobby.removePlayer(index);
|
||||
lobby.removePlayer(index);
|
||||
}
|
||||
});
|
||||
return closeBtn;
|
||||
@@ -654,9 +643,8 @@ public class PlayerPanel extends FPanel {
|
||||
if (index < currentPrefs.length) {
|
||||
avatarIndex = Integer.parseInt(currentPrefs[index]);
|
||||
avatarLabel.setIcon(FSkin.getAvatars().get(avatarIndex));
|
||||
}
|
||||
else {
|
||||
setRandomAvatar();
|
||||
} else {
|
||||
setRandomAvatar(false);
|
||||
}
|
||||
|
||||
avatarLabel.setToolTipText("L-click: Select avatar. R-click: Randomize avatar.");
|
||||
@@ -664,25 +652,22 @@ public class PlayerPanel extends FPanel {
|
||||
avatarLabel.addMouseListener(avatarMouseListener);
|
||||
}
|
||||
|
||||
/** Applies a random avatar, avoiding avatars already used.
|
||||
* @param playerIndex */
|
||||
public void setRandomAvatar() {
|
||||
/** Applies a random avatar, avoiding avatars already used. */
|
||||
private void setRandomAvatar() {
|
||||
setRandomAvatar(true);
|
||||
}
|
||||
private void setRandomAvatar(final boolean fireListeners) {
|
||||
int random = 0;
|
||||
|
||||
List<Integer> usedAvatars = lobby.getUsedAvatars();
|
||||
final List<Integer> usedAvatars = lobby.getUsedAvatars();
|
||||
do {
|
||||
random = MyRandom.getRandom().nextInt(FSkin.getAvatars().size());
|
||||
} while (usedAvatars.contains(random));
|
||||
setAvatar(random);
|
||||
|
||||
lobby.firePlayerChangeListener();
|
||||
}
|
||||
|
||||
public void setAvatar(int newAvatarIndex) {
|
||||
avatarIndex = newAvatarIndex;
|
||||
SkinImage icon = FSkin.getAvatars().get(newAvatarIndex);
|
||||
avatarLabel.setIcon(icon);
|
||||
avatarLabel.repaintSelf();
|
||||
if (fireListeners) {
|
||||
lobby.firePlayerChangeListener(index);
|
||||
}
|
||||
}
|
||||
|
||||
private final FSkin.LineSkinBorder focusedBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3);
|
||||
@@ -690,18 +675,53 @@ public class PlayerPanel extends FPanel {
|
||||
|
||||
public void setFocused(boolean focused) {
|
||||
avatarLabel.setBorder(focused ? focusedBorder : defaultBorder);
|
||||
avatarLabel.setHoverable(focused);
|
||||
}
|
||||
|
||||
String getPlayerName() {
|
||||
return txtPlayerName.getText();
|
||||
}
|
||||
public void setPlayerName(final String string) {
|
||||
playerName = string;
|
||||
txtPlayerName.setText(string);
|
||||
}
|
||||
|
||||
public int getAvatarIndex() {
|
||||
return avatarIndex;
|
||||
}
|
||||
|
||||
public void setPlayerName(String string) {
|
||||
txtPlayerName.setText(string);
|
||||
public void setAvatar(final int newAvatarIndex) {
|
||||
avatarIndex = newAvatarIndex;
|
||||
final SkinImage icon = FSkin.getAvatars().get(newAvatarIndex);
|
||||
avatarLabel.setIcon(icon);
|
||||
avatarLabel.repaintSelf();
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return txtPlayerName.getText();
|
||||
public int getTeam() {
|
||||
return teamComboBox.getSelectedIndex();
|
||||
}
|
||||
public void setTeam(final int team) {
|
||||
teamComboBox.suppressActionListeners();
|
||||
teamComboBox.setSelectedIndex(team);
|
||||
teamComboBox.unsuppressActionListeners();
|
||||
}
|
||||
|
||||
public int getArchenemyTeam() {
|
||||
return aeTeamComboBox.getSelectedIndex();
|
||||
}
|
||||
public void setIsArchenemy(final boolean isArchenemy) {
|
||||
aeTeamComboBox.suppressActionListeners();
|
||||
aeTeamComboBox.setSelectedIndex(isArchenemy ? 0 : 1);
|
||||
aeTeamComboBox.unsuppressActionListeners();
|
||||
}
|
||||
|
||||
public void setMayEdit(final boolean mayEdit) {
|
||||
this.mayEdit = mayEdit;
|
||||
}
|
||||
|
||||
public void setMayControl(final boolean mayControl) {
|
||||
this.mayControl = mayControl;
|
||||
}
|
||||
|
||||
public void setMayRemove(final boolean mayRemove) {
|
||||
this.mayRemove = mayRemove;
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public enum VHomeUI implements IVTopLevelUI {
|
||||
allSubmenus.add(VSubmenuSealed.SINGLETON_INSTANCE);
|
||||
//allSubmenus.add(VSubmenuWinston.SINGLETON_INSTANCE);
|
||||
|
||||
allSubmenus.add(VSubmenuOnlineLobby.SINGLETON_INSTANCE);
|
||||
//allSubmenus.add(VSubmenuOnlineLobby.SINGLETON_INSTANCE);
|
||||
|
||||
allSubmenus.add(VSubmenuDuels.SINGLETON_INSTANCE);
|
||||
allSubmenus.add(VSubmenuChallenges.SINGLETON_INSTANCE);
|
||||
|
||||
@@ -6,14 +6,9 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.JButton;
|
||||
@@ -24,25 +19,31 @@ import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.UiCommand;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.deck.DeckType;
|
||||
import forge.deck.DeckgenUtil;
|
||||
import forge.deckchooser.DecksComboBoxEvent;
|
||||
import forge.deckchooser.FDeckChooser;
|
||||
import forge.deckchooser.IDecksComboBoxListener;
|
||||
import forge.game.GameType;
|
||||
import forge.game.card.CardView;
|
||||
import forge.gui.CardDetailPanel;
|
||||
import forge.interfaces.ILobby;
|
||||
import forge.interfaces.IPlayerChangeListener;
|
||||
import forge.interfaces.IUpdateable;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.GameLobby;
|
||||
import forge.match.LobbySlot;
|
||||
import forge.model.FModel;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.LobbyState;
|
||||
import forge.net.game.LobbyState.LobbyPlayerData;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.toolbox.FCheckBox;
|
||||
@@ -55,39 +56,34 @@ import forge.toolbox.FScrollPanel;
|
||||
import forge.toolbox.FSkin;
|
||||
import forge.toolbox.FSkin.SkinImage;
|
||||
import forge.toolbox.FTextField;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.storage.IStorage;
|
||||
|
||||
/**
|
||||
* Lobby view. View of a number of players at the deck selection stage.
|
||||
*
|
||||
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
|
||||
*/
|
||||
public class VLobby implements ILobby {
|
||||
public class VLobby implements IUpdateable {
|
||||
|
||||
static final int MAX_PLAYERS = 8;
|
||||
private static final ForgePreferences prefs = FModel.getPreferences();
|
||||
|
||||
public enum LobbyType { LOCAL, SERVER, CLIENT; }
|
||||
|
||||
// General variables
|
||||
private final LobbyType type;
|
||||
private int localPlayer = 0;
|
||||
private final GameLobby lobby;
|
||||
private IPlayerChangeListener playerChangeListener = null;
|
||||
private final LblHeader lblTitle = new LblHeader("Sanctioned Format: Constructed");
|
||||
private int activePlayersNum = 2;
|
||||
private int activePlayersNum = 0;
|
||||
private int playerWithFocus = 0; // index of the player that currently has focus
|
||||
private PlayerPanel playerPanelWithFocus;
|
||||
private GameType currentGameMode = GameType.Constructed;
|
||||
private List<Integer> teams = new ArrayList<Integer>(MAX_PLAYERS);
|
||||
private List<Integer> archenemyTeams = new ArrayList<Integer>(MAX_PLAYERS);
|
||||
|
||||
private final StartButton btnStart = new StartButton();
|
||||
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 2"));
|
||||
private final JPanel constructedFrame = new JPanel(new MigLayout("insets 0, gap 0, wrap 2")); // Main content frame
|
||||
|
||||
// Variants frame and variables
|
||||
private final Set<GameType> appliedVariants = new TreeSet<GameType>();
|
||||
private final FPanel variantsPanel = new FPanel(new MigLayout("insets 10, gapx 10"));
|
||||
private final VariantCheckBox vntVanguard = new VariantCheckBox(GameType.Vanguard);
|
||||
private final VariantCheckBox vntMomirBasic = new VariantCheckBox(GameType.MomirBasic);
|
||||
@@ -96,6 +92,8 @@ public class VLobby implements ILobby {
|
||||
private final VariantCheckBox vntPlanechase = new VariantCheckBox(GameType.Planechase);
|
||||
private final VariantCheckBox vntArchenemy = new VariantCheckBox(GameType.Archenemy);
|
||||
private final VariantCheckBox vntArchenemyRumble = new VariantCheckBox(GameType.ArchenemyRumble);
|
||||
private final ImmutableList<VariantCheckBox> vntBoxes =
|
||||
ImmutableList.of(vntVanguard, vntMomirBasic, vntCommander, vntTinyLeaders, vntPlanechase, vntArchenemy, vntArchenemyRumble);
|
||||
|
||||
// Player frame elements
|
||||
private final JPanel playersFrame = new JPanel(new MigLayout("insets 0, gap 0 5, wrap, hidemode 3"));
|
||||
@@ -109,6 +107,7 @@ public class VLobby implements ILobby {
|
||||
private final List<FDeckChooser> deckChoosers = new ArrayList<FDeckChooser>(8);
|
||||
private final FCheckBox cbSingletons = new FCheckBox("Singleton Mode");
|
||||
private final FCheckBox cbArtifacts = new FCheckBox("Remove Artifacts");
|
||||
private final Deck[] decks = new Deck[MAX_PLAYERS];
|
||||
|
||||
// Variants
|
||||
private final List<FList<Object>> schemeDeckLists = new ArrayList<FList<Object>>();
|
||||
@@ -132,8 +131,8 @@ public class VLobby implements ILobby {
|
||||
private final Vector<Object> aiListData = new Vector<Object>();
|
||||
|
||||
// CTR
|
||||
public VLobby(final LobbyType type) {
|
||||
this.type = type;
|
||||
public VLobby(final GameLobby lobby) {
|
||||
this.lobby = lobby;
|
||||
|
||||
lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
|
||||
@@ -142,55 +141,23 @@ public class VLobby implements ILobby {
|
||||
|
||||
variantsPanel.setOpaque(false);
|
||||
variantsPanel.add(newLabel("Variants:"));
|
||||
variantsPanel.add(vntVanguard);
|
||||
variantsPanel.add(vntMomirBasic);
|
||||
variantsPanel.add(vntCommander);
|
||||
variantsPanel.add(vntTinyLeaders);
|
||||
variantsPanel.add(vntPlanechase);
|
||||
variantsPanel.add(vntArchenemy);
|
||||
variantsPanel.add(vntArchenemyRumble);
|
||||
for (final VariantCheckBox vcb : vntBoxes) {
|
||||
variantsPanel.add(vcb);
|
||||
}
|
||||
|
||||
constructedFrame.add(new FScrollPane(variantsPanel, false, true,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
|
||||
"w 100%, h 45px!, gapbottom 10px, spanx 2, wrap");
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
///////////////////// Player Panel /////////////////////
|
||||
|
||||
// Construct individual player panels
|
||||
String constraints = "pushx, growx, wrap, hidemode 3";
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) {
|
||||
teams.add(i + 1);
|
||||
archenemyTeams.add(i == 0 ? 1 : 2);
|
||||
|
||||
final PlayerPanel player = new PlayerPanel(this, i, type);
|
||||
if (type == LobbyType.CLIENT) {
|
||||
player.setRemote(true);
|
||||
}
|
||||
playerPanels.add(player);
|
||||
|
||||
// Populate players panel
|
||||
player.setVisible(i < activePlayersNum);
|
||||
|
||||
playersScroll.add(player, constraints);
|
||||
|
||||
if (i == 0) {
|
||||
constraints += ", gaptop 5px";
|
||||
}
|
||||
}
|
||||
|
||||
playerPanelWithFocus = playerPanels.get(0);
|
||||
playerPanelWithFocus.setFocused(true);
|
||||
|
||||
playersFrame.setOpaque(false);
|
||||
playersFrame.add(playersScroll, "w 100%, h 100%-35px");
|
||||
|
||||
if (type != LobbyType.CLIENT) {
|
||||
if (lobby.hasControl()) {
|
||||
addPlayerBtn.setFocusable(true);
|
||||
addPlayerBtn.setCommand(new Runnable() {
|
||||
@Override public final void run() {
|
||||
addPlayer();
|
||||
lobby.addSlot();
|
||||
}
|
||||
});
|
||||
playersFrame.add(addPlayerBtn, "height 30px!, growx, pushx");
|
||||
@@ -209,9 +176,16 @@ public class VLobby implements ILobby {
|
||||
decksFrame.setOpaque(false);
|
||||
|
||||
// Start Button
|
||||
if (type != LobbyType.CLIENT) {
|
||||
if (lobby.hasControl()) {
|
||||
pnlStart.setOpaque(false);
|
||||
pnlStart.add(btnStart, "align center");
|
||||
|
||||
// Start button event handling
|
||||
btnStart.addActionListener(new ActionListener() {
|
||||
@Override public final void actionPerformed(final ActionEvent arg0) {
|
||||
lobby.startGame();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,143 +201,95 @@ public class VLobby implements ILobby {
|
||||
}
|
||||
populateDeckPanel(GameType.Constructed);
|
||||
populateVanguardLists();
|
||||
|
||||
}
|
||||
|
||||
private int addPlayerInFreeSlot(final String name) {
|
||||
if (activePlayersNum >= MAX_PLAYERS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (final PlayerPanel pp : getPlayerPanels()) {
|
||||
if (pp.isVisible() && (
|
||||
pp.getType() == LobbySlotType.OPEN || (pp.isLocal() && type == LobbyType.SERVER))) {
|
||||
final int index = pp.getIndex();
|
||||
addPlayer(index);
|
||||
pp.setPlayerName(name);
|
||||
System.out.println("Put player " + name + " in slot " + index);
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private void addPlayer() {
|
||||
if (activePlayersNum >= MAX_PLAYERS) {
|
||||
return;
|
||||
}
|
||||
|
||||
int freeIndex = -1;
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) {
|
||||
if (!playerPanels.get(i).isVisible()) {
|
||||
freeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
addPlayer(freeIndex);
|
||||
}
|
||||
private void addPlayer(final int slot) {
|
||||
playerPanels.get(slot).setVisible(true);
|
||||
|
||||
activePlayersNum++;
|
||||
public void update() {
|
||||
activePlayersNum = lobby.getNumberOfSlots();
|
||||
addPlayerBtn.setEnabled(activePlayersNum < MAX_PLAYERS);
|
||||
|
||||
playerPanels.get(slot).setVisible(true);
|
||||
playerPanels.get(slot).focusOnAvatar();
|
||||
|
||||
firePlayerChangeListener();
|
||||
}
|
||||
|
||||
void removePlayer(final int playerIndex) {
|
||||
if (activePlayersNum <= playerIndex) {
|
||||
return;
|
||||
for (final VariantCheckBox vcb : vntBoxes) {
|
||||
vcb.setSelected(hasVariant(vcb.variant));
|
||||
vcb.setEnabled(lobby.hasControl());
|
||||
}
|
||||
activePlayersNum--;
|
||||
final FPanel player = playerPanels.get(playerIndex);
|
||||
player.setVisible(false);
|
||||
addPlayerBtn.setEnabled(true);
|
||||
|
||||
//find closest player still in game and give focus
|
||||
int min = MAX_PLAYERS;
|
||||
final List<Integer> participants = getParticipants();
|
||||
if (!participants.isEmpty()) {
|
||||
int closest = 2;
|
||||
|
||||
for (final int participantIndex : getParticipants()) {
|
||||
final int diff = Math.abs(playerIndex - participantIndex);
|
||||
|
||||
if (diff < min) {
|
||||
min = diff;
|
||||
closest = participantIndex;
|
||||
final boolean allowNetworking = lobby.isAllowNetworking();
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) {
|
||||
final boolean hasPanel = i < playerPanels.size();
|
||||
if (i < activePlayersNum) {
|
||||
// visible panels
|
||||
final LobbySlot slot = lobby.getSlot(i);
|
||||
final PlayerPanel panel;
|
||||
if (hasPanel) {
|
||||
panel = playerPanels.get(i);
|
||||
panel.setVisible(true);
|
||||
} else {
|
||||
panel = new PlayerPanel(this, allowNetworking, i, slot, lobby.mayEdit(i), lobby.hasControl());
|
||||
playerPanels.add(panel);
|
||||
String constraints = "pushx, growx, wrap, hidemode 3";
|
||||
if (i == 0) {
|
||||
constraints += ", gaptop 5px";
|
||||
playerPanelWithFocus = panel;
|
||||
playerPanelWithFocus.setFocused(true);
|
||||
}
|
||||
playersScroll.add(panel, constraints);
|
||||
}
|
||||
|
||||
panel.setType(slot.getType());
|
||||
panel.setPlayerName(slot.getName());
|
||||
panel.setAvatar(slot.getAvatarIndex());
|
||||
panel.setTeam(slot.getTeam());
|
||||
panel.setIsArchenemy(slot.isArchenemy());
|
||||
panel.setUseAiSimulation(slot.getAiOptions().contains(AIOption.USE_SIMULATION));
|
||||
panel.setMayEdit(lobby.mayEdit(i));
|
||||
panel.setMayControl(lobby.mayControl(i));
|
||||
panel.setMayRemove(lobby.mayRemove(i));
|
||||
panel.update();
|
||||
|
||||
deckChoosers.get(i).setIsAi(slot.getType() == LobbySlotType.AI);
|
||||
} else if (hasPanel) {
|
||||
playerPanels.get(i).setVisible(false);
|
||||
}
|
||||
|
||||
changePlayerFocus(closest);
|
||||
playerPanels.get(closest).focusOnAvatar();
|
||||
}
|
||||
firePlayerChangeListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int login(final RemoteClient client) {
|
||||
return addPlayerInFreeSlot(client.getUsername());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout(final RemoteClient client) {
|
||||
removePlayer(client.getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LobbyState getState() {
|
||||
final LobbyState state = new LobbyState();
|
||||
for (int i = 0; i < activePlayersNum; i++) {
|
||||
state.addPlayer(getData(i));
|
||||
if (playerWithFocus >= activePlayersNum) {
|
||||
playerWithFocus = activePlayersNum - 1;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(final LobbyState state) {
|
||||
setLocalPlayer(state.getLocalPlayer());
|
||||
|
||||
final List<LobbyPlayerData> players = state.getPlayers();
|
||||
final int pSize = players.size();
|
||||
activePlayersNum = pSize;
|
||||
for (int i = 0; i < pSize; i++) {
|
||||
final LobbyPlayerData player = players.get(i);
|
||||
final PlayerPanel panel = playerPanels.get(i);
|
||||
|
||||
if (type == LobbyType.CLIENT) {
|
||||
panel.setRemote(i != localPlayer);
|
||||
panel.setEditableForClient(i == localPlayer);
|
||||
} else {
|
||||
panel.setRemote(player.getType() == LobbySlotType.REMOTE);
|
||||
panel.setEditableForClient(false);
|
||||
}
|
||||
panel.setPlayerName(player.getName());
|
||||
panel.setAvatar(player.getAvatarIndex());
|
||||
panel.setVisible(true);
|
||||
panel.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocalPlayer(final int index) {
|
||||
localPlayer = index;
|
||||
changePlayerFocus(playerWithFocus);
|
||||
refreshPanels(true, true);
|
||||
}
|
||||
|
||||
public void setPlayerChangeListener(final IPlayerChangeListener listener) {
|
||||
this.playerChangeListener = listener;
|
||||
}
|
||||
|
||||
void firePlayerChangeListener() {
|
||||
void firePlayerChangeListener(final int index) {
|
||||
if (playerChangeListener != null) {
|
||||
playerChangeListener.update(getData(localPlayer));
|
||||
playerChangeListener.update(index, getSlot(index));
|
||||
}
|
||||
}
|
||||
void fireDeckChangeListener(final int index, final Deck deck) {
|
||||
decks[index] = deck;
|
||||
if (playerChangeListener != null) {
|
||||
playerChangeListener.update(index, UpdateLobbyPlayerEvent.deckUpdate(deck));
|
||||
}
|
||||
}
|
||||
void fireDeckSectionChangeListener(final int index, final DeckSection section, final CardPool cards) {
|
||||
decks[index].putSection(section, cards);
|
||||
if (playerChangeListener != null) {
|
||||
playerChangeListener.update(index, UpdateLobbyPlayerEvent.deckUpdate(section, cards));
|
||||
}
|
||||
}
|
||||
|
||||
private LobbyPlayerData getData(final int index) {
|
||||
void removePlayer(final int index) {
|
||||
lobby.removeSlot(index);
|
||||
}
|
||||
boolean hasVariant(final GameType variant) {
|
||||
return lobby.hasVariant(variant);
|
||||
}
|
||||
|
||||
private UpdateLobbyPlayerEvent getSlot(final int index) {
|
||||
final PlayerPanel panel = playerPanels.get(index);
|
||||
return new LobbyPlayerData(panel.getPlayerName(), panel.getAvatarIndex(), panel.getType());
|
||||
return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.getAiOptions());
|
||||
}
|
||||
|
||||
/** Builds the actual deck panel layouts for each player.
|
||||
@@ -374,53 +300,142 @@ public class VLobby implements ILobby {
|
||||
String labelConstraints = "gaptop 10px, gapbottom 5px";
|
||||
|
||||
// Main deck
|
||||
final FDeckChooser mainChooser = new FDeckChooser(null, isPlayerAI(playerIndex));
|
||||
final FDeckChooser mainChooser = new FDeckChooser(null, false);
|
||||
mainChooser.initialize();
|
||||
mainChooser.getLstDecks().setSelectCommand(new UiCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
@Override public final void run() {
|
||||
VLobby.this.onDeckClicked(playerIndex, mainChooser.getSelectedDeckType(), mainChooser.getLstDecks().getSelectedItems());
|
||||
}
|
||||
});
|
||||
deckChoosers.add(mainChooser);
|
||||
|
||||
// Scheme deck list
|
||||
FPanel schemeDeckPanel = new FPanel();
|
||||
final FPanel schemeDeckPanel = new FPanel();
|
||||
schemeDeckPanel.setBorderToggle(false);
|
||||
schemeDeckPanel.setLayout(new MigLayout(sectionConstraints));
|
||||
schemeDeckPanel.add(new FLabel.Builder().text("Select Scheme deck:").build(), labelConstraints);
|
||||
FList<Object> schemeDeckList = new FList<Object>();
|
||||
final FList<Object> schemeDeckList = new FList<Object>();
|
||||
schemeDeckList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
schemeDeckList.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override public final void valueChanged(final ListSelectionEvent e) {
|
||||
if (playerIndex >= activePlayersNum) {
|
||||
return;
|
||||
}
|
||||
|
||||
FScrollPane scrSchemes = new FScrollPane(schemeDeckList, true,
|
||||
final Object selected = schemeDeckList.getSelectedValue();
|
||||
final Deck deck = decks[playerIndex];
|
||||
CardPool schemePool = null;
|
||||
if (selected instanceof String) {
|
||||
String sel = (String) selected;
|
||||
if (sel.contains("Use deck's scheme section")) {
|
||||
if (deck.has(DeckSection.Schemes)) {
|
||||
schemePool = deck.get(DeckSection.Schemes);
|
||||
} else {
|
||||
sel = "Random";
|
||||
}
|
||||
}
|
||||
final IStorage<Deck> sDecks = FModel.getDecks().getScheme();
|
||||
if (sel.equals("Random") && sDecks.size() != 0) {
|
||||
schemePool = Aggregates.random(sDecks).get(DeckSection.Schemes);
|
||||
}
|
||||
} else if (selected instanceof Deck) {
|
||||
schemePool = ((Deck) selected).get(DeckSection.Schemes);
|
||||
}
|
||||
if (schemePool == null) { //Can be null if player deselects the list selection or chose Generate
|
||||
schemePool = DeckgenUtil.generateSchemePool();
|
||||
}
|
||||
fireDeckSectionChangeListener(playerIndex, DeckSection.Schemes, schemePool);
|
||||
getDeckChooser(playerIndex).saveState();
|
||||
}
|
||||
});
|
||||
|
||||
final FScrollPane scrSchemes = new FScrollPane(schemeDeckList, true,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
schemeDeckPanel.add(scrSchemes, "grow, push");
|
||||
schemeDeckLists.add(schemeDeckList);
|
||||
schemeDeckPanels.add(schemeDeckPanel);
|
||||
|
||||
// Commander deck list
|
||||
FPanel commanderDeckPanel = new FPanel();
|
||||
final FPanel commanderDeckPanel = new FPanel();
|
||||
commanderDeckPanel.setBorderToggle(false);
|
||||
commanderDeckPanel.setLayout(new MigLayout(sectionConstraints));
|
||||
commanderDeckPanel.add(new FLabel.Builder().text("Select Commander deck:").build(), labelConstraints);
|
||||
FList<Object> commanderDeckList = new FList<Object>();
|
||||
final FList<Object> commanderDeckList = new FList<Object>();
|
||||
commanderDeckList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
commanderDeckList.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override public final void valueChanged(final ListSelectionEvent e) {
|
||||
if (playerIndex >= activePlayersNum) {
|
||||
return;
|
||||
}
|
||||
|
||||
FScrollPane scrCommander = new FScrollPane(commanderDeckList, true,
|
||||
final Object selected = commanderDeckList.getSelectedValue();
|
||||
Deck deck = null;
|
||||
if (selected instanceof String) {
|
||||
final String sel = (String) selected;
|
||||
final IStorage<Deck> comDecks = FModel.getDecks().getCommander();
|
||||
if (sel.equals("Random") && comDecks.size() > 0) {
|
||||
deck = Aggregates.random(comDecks);
|
||||
}
|
||||
} else if (selected instanceof Deck) {
|
||||
deck = (Deck) selected;
|
||||
}
|
||||
final GameType commanderGameType = hasVariant(GameType.TinyLeaders) ? GameType.TinyLeaders : GameType.Commander;
|
||||
if (deck == null) { //Can be null if player deselects the list selection or chose Generate
|
||||
deck = DeckgenUtil.generateCommanderDeck(isPlayerAI(playerIndex), commanderGameType);
|
||||
}
|
||||
fireDeckChangeListener(playerIndex, deck);
|
||||
getDeckChooser(playerIndex).saveState();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
final FScrollPane scrCommander = new FScrollPane(commanderDeckList, true,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
commanderDeckPanel.add(scrCommander, "grow, push");
|
||||
commanderDeckLists.add(commanderDeckList);
|
||||
commanderDeckPanels.add(commanderDeckPanel);
|
||||
|
||||
// Planar deck list
|
||||
FPanel planarDeckPanel = new FPanel();
|
||||
final FPanel planarDeckPanel = new FPanel();
|
||||
planarDeckPanel.setBorderToggle(false);
|
||||
planarDeckPanel.setLayout(new MigLayout(sectionConstraints));
|
||||
planarDeckPanel.add(new FLabel.Builder().text("Select Planar deck:").build(), labelConstraints);
|
||||
FList<Object> planarDeckList = new FList<Object>();
|
||||
final FList<Object> planarDeckList = new FList<Object>();
|
||||
planarDeckList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
planarDeckList.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override public final void valueChanged(final ListSelectionEvent e) {
|
||||
if (playerIndex >= activePlayersNum) {
|
||||
return;
|
||||
}
|
||||
|
||||
FScrollPane scrPlanes = new FScrollPane(planarDeckList, true,
|
||||
final Object selected = planarDeckList.getSelectedValue();
|
||||
final Deck deck = decks[playerIndex];
|
||||
CardPool planePool = null;
|
||||
if (selected instanceof String) {
|
||||
String sel = (String) selected;
|
||||
if (sel.contains("Use deck's planes section")) {
|
||||
if (deck.has(DeckSection.Planes)) {
|
||||
planePool = deck.get(DeckSection.Planes);
|
||||
} else {
|
||||
sel = "Random";
|
||||
}
|
||||
}
|
||||
final IStorage<Deck> pDecks = FModel.getDecks().getPlane();
|
||||
if (sel.equals("Random") && pDecks.size() != 0) {
|
||||
planePool = Aggregates.random(pDecks).get(DeckSection.Planes);
|
||||
}
|
||||
} else if (selected instanceof Deck) {
|
||||
planePool = ((Deck) selected).get(DeckSection.Planes);
|
||||
}
|
||||
if (planePool == null) { //Can be null if player deselects the list selection or chose Generate
|
||||
planePool = DeckgenUtil.generatePlanarPool();
|
||||
}
|
||||
fireDeckSectionChangeListener(playerIndex, DeckSection.Planes, planePool);
|
||||
getDeckChooser(playerIndex).saveState();
|
||||
}
|
||||
});
|
||||
|
||||
final FScrollPane scrPlanes = new FScrollPane(planarDeckList, true,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
planarDeckPanel.add(scrPlanes, "grow, push");
|
||||
planarDeckLists.add(planarDeckList);
|
||||
@@ -430,15 +445,15 @@ public class VLobby implements ILobby {
|
||||
FPanel vgdDeckPanel = new FPanel();
|
||||
vgdDeckPanel.setBorderToggle(false);
|
||||
|
||||
FList<Object> vgdAvatarList = new FList<Object>();
|
||||
final FList<Object> vgdAvatarList = new FList<Object>();
|
||||
vgdAvatarList.setListData(isPlayerAI(playerIndex) ? aiListData : humanListData);
|
||||
vgdAvatarList.setSelectedIndex(0);
|
||||
vgdAvatarList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
vgdAvatarList.addListSelectionListener(vgdLSListener);
|
||||
FScrollPane scrAvatars = new FScrollPane(vgdAvatarList, true,
|
||||
final FScrollPane scrAvatars = new FScrollPane(vgdAvatarList, true,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
CardDetailPanel vgdDetail = new CardDetailPanel();
|
||||
final CardDetailPanel vgdDetail = new CardDetailPanel();
|
||||
vgdAvatarDetails.add(vgdDetail);
|
||||
|
||||
vgdDeckPanel.setLayout(new MigLayout(sectionConstraints));
|
||||
@@ -449,16 +464,19 @@ public class VLobby implements ILobby {
|
||||
vgdPanels.add(vgdDeckPanel);
|
||||
}
|
||||
|
||||
protected void onDeckClicked(int iPlayer, DeckType type, Collection<DeckProxy> selectedDecks) {
|
||||
String text = type.toString() + ": " + Lang.joinHomogenous(selectedDecks, DeckProxy.FN_GET_NAME);
|
||||
playerPanels.get(iPlayer).setDeckSelectorButtonText(text);
|
||||
protected void onDeckClicked(final int iPlayer, final DeckType type, final Collection<DeckProxy> selectedDecks) {
|
||||
if (iPlayer < activePlayersNum && lobby.mayEdit(iPlayer)) {
|
||||
final String text = type.toString() + ": " + Lang.joinHomogenous(selectedDecks, DeckProxy.FN_GET_NAME);
|
||||
playerPanels.get(iPlayer).setDeckSelectorButtonText(text);
|
||||
fireDeckChangeListener(iPlayer, selectedDecks.iterator().next().getDeck());
|
||||
}
|
||||
}
|
||||
|
||||
/** Populates the deck panel with the focused player's deck choices. */
|
||||
private void populateDeckPanel(final GameType forGameType) {
|
||||
decksFrame.removeAll();
|
||||
|
||||
if (playerPanelWithFocus.getType() == LobbySlotType.OPEN || playerPanelWithFocus.getType() == LobbySlotType.REMOTE) {
|
||||
if (!lobby.mayEdit(playerWithFocus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -487,7 +505,7 @@ public class VLobby implements ILobby {
|
||||
}
|
||||
|
||||
/** @return {@link javax.swing.JButton} */
|
||||
public JButton getBtnStart() {
|
||||
JButton getBtnStart() {
|
||||
return this.btnStart;
|
||||
}
|
||||
|
||||
@@ -497,18 +515,18 @@ public class VLobby implements ILobby {
|
||||
public List<FDeckChooser> getDeckChoosers() { return Collections.unmodifiableList(deckChoosers); }
|
||||
|
||||
/** Gets the random deck checkbox for Singletons. */
|
||||
public FCheckBox getCbSingletons() { return cbSingletons; }
|
||||
FCheckBox getCbSingletons() { return cbSingletons; }
|
||||
|
||||
/** Gets the random deck checkbox for Artifacts. */
|
||||
public FCheckBox getCbArtifacts() { return cbArtifacts; }
|
||||
FCheckBox getCbArtifacts() { return cbArtifacts; }
|
||||
|
||||
public FCheckBox getVntArchenemy() { return vntArchenemy; }
|
||||
public FCheckBox getVntArchenemyRumble() { return vntArchenemyRumble; }
|
||||
public FCheckBox getVntCommander() { return vntCommander; }
|
||||
public FCheckBox getVntMomirBasic() { return vntMomirBasic; }
|
||||
public FCheckBox getVntPlanechase() { return vntPlanechase; }
|
||||
public FCheckBox getVntTinyLeaders() { return vntTinyLeaders; }
|
||||
public FCheckBox getVntVanguard() { return vntVanguard; }
|
||||
FCheckBox getVntArchenemy() { return vntArchenemy; }
|
||||
FCheckBox getVntArchenemyRumble() { return vntArchenemyRumble; }
|
||||
FCheckBox getVntCommander() { return vntCommander; }
|
||||
FCheckBox getVntMomirBasic() { return vntMomirBasic; }
|
||||
FCheckBox getVntPlanechase() { return vntPlanechase; }
|
||||
FCheckBox getVntTinyLeaders() { return vntTinyLeaders; }
|
||||
FCheckBox getVntVanguard() { return vntVanguard; }
|
||||
|
||||
public int getLastArchenemy() { return lastArchenemy; }
|
||||
public void setLastArchenemy(final int archenemy) { lastArchenemy = archenemy; }
|
||||
@@ -524,38 +542,22 @@ public class VLobby implements ILobby {
|
||||
return deckChoosers.get(playernum);
|
||||
}
|
||||
|
||||
public List<Integer> getTeams() { return teams; }
|
||||
public List<Integer> getArchenemyTeams() { return archenemyTeams; }
|
||||
public GameType getCurrentGameMode() { return currentGameMode; }
|
||||
public void setCurrentGameMode(final GameType mode) { currentGameMode = mode; }
|
||||
|
||||
public boolean isPlayerAI(int playernum) {
|
||||
return playerPanels.get(playernum).isAi();
|
||||
GameType getCurrentGameMode() {
|
||||
return lobby.getGameType();
|
||||
}
|
||||
void setCurrentGameMode(final GameType mode) {
|
||||
lobby.setGameType(mode);
|
||||
update();
|
||||
}
|
||||
|
||||
public Map<String, String> getAiOptions(int playernum) {
|
||||
if (playerPanels.get(playernum).isSimulatedAi()) {
|
||||
Map<String, String> options = new HashMap<String, String>();
|
||||
options.put("UseSimulation", "True");
|
||||
return options;
|
||||
}
|
||||
return null;
|
||||
public boolean isPlayerAI(final int playernum) {
|
||||
return playernum < activePlayersNum ? playerPanels.get(playernum).isAi() : false;
|
||||
}
|
||||
|
||||
public int getNumPlayers() {
|
||||
return activePlayersNum;
|
||||
}
|
||||
|
||||
public final List<Integer> getParticipants() {
|
||||
final List<Integer> participants = new ArrayList<Integer>(activePlayersNum);
|
||||
for (final PlayerPanel panel : playerPanels) {
|
||||
if (panel.isVisible()) {
|
||||
participants.add(playerPanels.indexOf(panel));
|
||||
}
|
||||
}
|
||||
return participants;
|
||||
}
|
||||
|
||||
/** Revalidates the player and deck sections. Necessary after adding or hiding any panels. */
|
||||
private void refreshPanels(boolean refreshPlayerFrame, boolean refreshDeckFrame) {
|
||||
if (refreshPlayerFrame) {
|
||||
@@ -569,7 +571,7 @@ public class VLobby implements ILobby {
|
||||
}
|
||||
|
||||
public void changePlayerFocus(int newFocusOwner) {
|
||||
changePlayerFocus(newFocusOwner, appliedVariants.contains(currentGameMode) ? currentGameMode : GameType.Constructed);
|
||||
changePlayerFocus(newFocusOwner, lobby.getGameType());
|
||||
}
|
||||
|
||||
void changePlayerFocus(int newFocusOwner, GameType gType) {
|
||||
@@ -593,32 +595,15 @@ public class VLobby implements ILobby {
|
||||
prefs.save();
|
||||
}
|
||||
|
||||
/** Updates the avatars from preferences on update. */
|
||||
public void updatePlayersFromPrefs() {
|
||||
ForgePreferences prefs = FModel.getPreferences();
|
||||
|
||||
// Avatar
|
||||
String[] avatarPrefs = prefs.getPref(FPref.UI_AVATARS).split(",");
|
||||
for (int i = 0; i < avatarPrefs.length; i++) {
|
||||
int avatarIndex = Integer.parseInt(avatarPrefs[i]);
|
||||
playerPanels.get(i).setAvatar(avatarIndex);
|
||||
}
|
||||
|
||||
// Name
|
||||
String prefName = prefs.getPref(FPref.PLAYER_NAME);
|
||||
playerPanels.get(0).setPlayerName(StringUtils.isBlank(prefName) ? "Human" : prefName);
|
||||
}
|
||||
|
||||
/** Adds a pre-styled FLabel component with the specified title. */
|
||||
FLabel newLabel(String title) {
|
||||
return new FLabel.Builder().text(title).fontSize(14).fontStyle(Font.ITALIC).build();
|
||||
}
|
||||
|
||||
List<Integer> getUsedAvatars() {
|
||||
List<Integer> usedAvatars = Arrays.asList(-1,-1,-1,-1,-1,-1,-1,-1);
|
||||
int i = 0;
|
||||
for (PlayerPanel pp : playerPanels) {
|
||||
usedAvatars.set(i++, pp.getAvatarIndex());
|
||||
final List<Integer> usedAvatars = Lists.newArrayListWithCapacity(MAX_PLAYERS);
|
||||
for (final PlayerPanel pp : playerPanels) {
|
||||
usedAvatars.add(pp.getAvatarIndex());
|
||||
}
|
||||
return usedAvatars;
|
||||
}
|
||||
@@ -660,92 +645,30 @@ public class VLobby implements ILobby {
|
||||
return names;
|
||||
}
|
||||
|
||||
public String getPlayerName(int i) {
|
||||
return playerPanels.get(i).getPlayerName();
|
||||
}
|
||||
|
||||
public int getPlayerAvatar(int i) {
|
||||
return playerPanels.get(i).getAvatarIndex();
|
||||
}
|
||||
|
||||
public boolean isEnoughTeams() {
|
||||
int lastTeam = -1;
|
||||
final List<Integer> teamList = appliedVariants.contains(GameType.Archenemy) ? archenemyTeams : teams;
|
||||
|
||||
for (final int i : getParticipants()) {
|
||||
if (lastTeam == -1) {
|
||||
lastTeam = teamList.get(i);
|
||||
} else if (lastTeam != teamList.get(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//========== Various listeners in build order
|
||||
|
||||
@SuppressWarnings("serial") private class VariantCheckBox extends FCheckBox {
|
||||
private final GameType variantType;
|
||||
|
||||
private VariantCheckBox(GameType variantType0) {
|
||||
super(variantType0.toString());
|
||||
|
||||
variantType = variantType0;
|
||||
private final GameType variant;
|
||||
private VariantCheckBox(final GameType variantType) {
|
||||
super(variantType.toString());
|
||||
this.variant = variantType;
|
||||
|
||||
setToolTipText(variantType.getDescription());
|
||||
|
||||
addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
@Override public final void itemStateChanged(final ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
appliedVariants.add(variantType);
|
||||
currentGameMode = variantType;
|
||||
|
||||
//ensure other necessary variants are unchecked
|
||||
switch (variantType) {
|
||||
case Archenemy:
|
||||
vntArchenemyRumble.setSelected(false);
|
||||
break;
|
||||
case ArchenemyRumble:
|
||||
vntArchenemy.setSelected(false);
|
||||
break;
|
||||
case Commander:
|
||||
vntTinyLeaders.setSelected(false);
|
||||
vntMomirBasic.setSelected(false);
|
||||
break;
|
||||
case TinyLeaders:
|
||||
vntCommander.setSelected(false);
|
||||
vntMomirBasic.setSelected(false);
|
||||
break;
|
||||
case Vanguard:
|
||||
vntMomirBasic.setSelected(false);
|
||||
break;
|
||||
case MomirBasic:
|
||||
vntCommander.setSelected(false);
|
||||
vntVanguard.setSelected(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
lobby.applyVariant(variantType);
|
||||
} else {
|
||||
lobby.removeVariant(variantType);
|
||||
}
|
||||
else {
|
||||
appliedVariants.remove(variantType);
|
||||
if (currentGameMode == variantType) {
|
||||
currentGameMode = GameType.Constructed;
|
||||
}
|
||||
}
|
||||
|
||||
for (PlayerPanel pp : playerPanels) {
|
||||
pp.toggleIsPlayerArchenemy();
|
||||
}
|
||||
changePlayerFocus(playerWithFocus, currentGameMode);
|
||||
VLobby.this.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ActionListener nameListener = new ActionListener() {
|
||||
final ActionListener nameListener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
FTextField nField = (FTextField)e.getSource();
|
||||
@@ -756,24 +679,44 @@ public class VLobby implements ILobby {
|
||||
/** This listener will look for a vanguard avatar being selected in the lists
|
||||
/ and update the corresponding detail panel. */
|
||||
private ListSelectionListener vgdLSListener = new ListSelectionListener() {
|
||||
@Override public final void valueChanged(final ListSelectionEvent e) {
|
||||
final int index = vgdAvatarLists.indexOf(e.getSource());
|
||||
if (index >= activePlayersNum) {
|
||||
return;
|
||||
}
|
||||
final Object selected = vgdAvatarLists.get(index).getSelectedValue();
|
||||
final PlayerPanel pp = playerPanels.get(index);
|
||||
final CardDetailPanel cdp = vgdAvatarDetails.get(index);
|
||||
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
int index = vgdAvatarLists.indexOf(e.getSource());
|
||||
Object obj = vgdAvatarLists.get(index).getSelectedValue();
|
||||
PlayerPanel pp = playerPanels.get(index);
|
||||
CardDetailPanel cdp = vgdAvatarDetails.get(index);
|
||||
|
||||
if (obj instanceof PaperCard) {
|
||||
pp.setVanguardButtonText(((PaperCard) obj).getName());
|
||||
cdp.setCard(CardView.getCardForUi((PaperCard) obj));
|
||||
final PaperCard vanguardAvatar;
|
||||
final Deck deck = decks[index];
|
||||
if (selected instanceof PaperCard) {
|
||||
pp.setVanguardButtonText(((PaperCard) selected).getName());
|
||||
cdp.setCard(CardView.getCardForUi((PaperCard) selected));
|
||||
cdp.setVisible(true);
|
||||
refreshPanels(false, true);
|
||||
}
|
||||
else {
|
||||
pp.setVanguardButtonText((String) obj);
|
||||
|
||||
vanguardAvatar = (PaperCard)selected;
|
||||
} else {
|
||||
String sel = (String) selected;
|
||||
pp.setVanguardButtonText(sel);
|
||||
cdp.setVisible(false);
|
||||
|
||||
if (sel.contains("Use deck's default avatar") && deck.has(DeckSection.Avatar)) {
|
||||
vanguardAvatar = deck.get(DeckSection.Avatar).get(0);
|
||||
} else { //Only other string is "Random"
|
||||
if (playerPanels.get(index).isAi()) { //AI
|
||||
vanguardAvatar = Aggregates.random(getNonRandomAiAvatars());
|
||||
} else { //Human
|
||||
vanguardAvatar = Aggregates.random(getNonRandomHumanAvatars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CardPool avatarOnce = new CardPool();
|
||||
avatarOnce.add(vanguardAvatar);
|
||||
fireDeckSectionChangeListener(index, DeckSection.Avatar, avatarOnce);
|
||||
getDeckChooser(index).saveState();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -781,14 +724,6 @@ public class VLobby implements ILobby {
|
||||
/////////////////////////////////////
|
||||
//========== METHODS FOR VARIANTS
|
||||
|
||||
public Set<GameType> getAppliedVariants() {
|
||||
return Collections.unmodifiableSet(appliedVariants);
|
||||
}
|
||||
|
||||
public int getTeam(final int playerIndex) {
|
||||
return appliedVariants.contains(GameType.Archenemy) ? archenemyTeams.get(playerIndex) : teams.get(playerIndex);
|
||||
}
|
||||
|
||||
/** Gets the list of planar deck lists. */
|
||||
public List<FList<Object>> getPlanarDeckLists() {
|
||||
return planarDeckLists;
|
||||
|
||||
@@ -8,74 +8,102 @@ import javax.swing.JMenu;
|
||||
import forge.GuiBase;
|
||||
import forge.Singletons;
|
||||
import forge.UiCommand;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.GameType;
|
||||
import forge.gui.FNetOverlay;
|
||||
import forge.gui.framework.FScreen;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.ILobbyListener;
|
||||
import forge.interfaces.IPlayerChangeListener;
|
||||
import forge.interfaces.IUpdateable;
|
||||
import forge.match.GameLobby.GameLobbyData;
|
||||
import forge.menus.IMenuProvider;
|
||||
import forge.menus.MenuUtil;
|
||||
import forge.model.FModel;
|
||||
import forge.net.ClientGameLobby;
|
||||
import forge.net.FGameClient;
|
||||
import forge.net.FServerManager;
|
||||
import forge.net.game.LobbyState;
|
||||
import forge.net.game.LobbyState.LobbyPlayerData;
|
||||
import forge.net.game.LoginEvent;
|
||||
import forge.net.game.client.ILobbyListener;
|
||||
import forge.net.ServerGameLobby;
|
||||
import forge.net.game.IRemote;
|
||||
import forge.net.game.IdentifiableNetEvent;
|
||||
import forge.net.game.MessageEvent;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.screens.home.VLobby;
|
||||
import forge.screens.home.VLobby.LobbyType;
|
||||
import forge.screens.home.sanctioned.ConstructedGameMenu;
|
||||
|
||||
public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
|
||||
SINGLETON_INSTANCE;
|
||||
|
||||
final void host(final int portNumber) {
|
||||
final VLobby lobby = VOnlineLobby.SINGLETON_INSTANCE.setLobby(LobbyType.SERVER);
|
||||
final FServerManager server = FServerManager.getInstance();
|
||||
final ServerGameLobby lobby = new ServerGameLobby();
|
||||
final VLobby view = VOnlineLobby.SINGLETON_INSTANCE.setLobby(lobby);
|
||||
|
||||
FServerManager.getInstance().startServer(portNumber);
|
||||
FServerManager.getInstance().setLobby(lobby);
|
||||
FServerManager.getInstance().hostGame(new GameRules(GameType.Constructed));
|
||||
server.startServer(portNumber);
|
||||
server.setLobby(lobby);
|
||||
|
||||
FNetOverlay.SINGLETON_INSTANCE.showUp("Hosting game");
|
||||
lobby.setPlayerChangeListener(new IPlayerChangeListener() {
|
||||
@Override public final void update(final LobbyPlayerData data) {
|
||||
FServerManager.getInstance().updateLobbyState();
|
||||
lobby.setListener(new IUpdateable() {
|
||||
@Override public final void update() {
|
||||
view.update();
|
||||
server.updateLobbyState();
|
||||
}
|
||||
});
|
||||
view.setPlayerChangeListener(new IPlayerChangeListener() {
|
||||
@Override public final void update(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
server.updateSlot(index, event);
|
||||
server.updateLobbyState();
|
||||
}
|
||||
});
|
||||
|
||||
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", GuiBase.getInterface().getNewGuiGame());
|
||||
FNetOverlay.SINGLETON_INSTANCE.setGameClient(client);
|
||||
client.addLobbyListener(new ILobbyListener() {
|
||||
@Override public final void update(final LobbyState state) {
|
||||
lobby.setState(state);
|
||||
server.setLobbyListener(new ILobbyListener() {
|
||||
@Override public final void update(final GameLobbyData state, final int slot) {
|
||||
// NO-OP, lobby connected directly
|
||||
}
|
||||
@Override public final void message(final String source, final String message) {
|
||||
FNetOverlay.SINGLETON_INSTANCE.addMessage(source, message);
|
||||
}
|
||||
});
|
||||
client.connect("localhost", portNumber);
|
||||
FNetOverlay.SINGLETON_INSTANCE.setGameClient(new IRemote() {
|
||||
@Override public final void send(final NetEvent event) {
|
||||
if (event instanceof MessageEvent) {
|
||||
final MessageEvent message = (MessageEvent) event;
|
||||
FNetOverlay.SINGLETON_INSTANCE.addMessage(message.getSource(), message.getMessage());
|
||||
server.broadcast(event);
|
||||
}
|
||||
}
|
||||
@Override public final Object sendAndWait(final IdentifiableNetEvent event) {
|
||||
send(event);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
view.update();
|
||||
|
||||
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
|
||||
FNetOverlay.SINGLETON_INSTANCE.showUp(String.format("Hosting on port %d", portNumber));
|
||||
}
|
||||
|
||||
final void join(final String hostname, final int port) {
|
||||
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", GuiBase.getInterface().getNewGuiGame());
|
||||
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
|
||||
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui);
|
||||
FNetOverlay.SINGLETON_INSTANCE.setGameClient(client);
|
||||
final VLobby lobby = VOnlineLobby.SINGLETON_INSTANCE.setLobby(LobbyType.CLIENT);
|
||||
final ClientGameLobby lobby = new ClientGameLobby();
|
||||
final VLobby view = VOnlineLobby.SINGLETON_INSTANCE.setLobby(lobby);
|
||||
lobby.setListener(view);
|
||||
client.addLobbyListener(new ILobbyListener() {
|
||||
@Override public final void update(final LobbyState state) {
|
||||
lobby.setState(state);
|
||||
}
|
||||
@Override public final void message(final String source, final String message) {
|
||||
FNetOverlay.SINGLETON_INSTANCE.addMessage(source, message);
|
||||
}
|
||||
@Override public final void update(final GameLobbyData state, final int slot) {
|
||||
lobby.setLocalPlayer(slot);
|
||||
lobby.setData(state);
|
||||
}
|
||||
});
|
||||
lobby.setPlayerChangeListener(new IPlayerChangeListener() {
|
||||
@Override public final void update(final LobbyPlayerData data) {
|
||||
client.send(new LoginEvent(data.getName()));
|
||||
view.setPlayerChangeListener(new IPlayerChangeListener() {
|
||||
@Override public final void update(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
client.send(event);
|
||||
}
|
||||
});
|
||||
client.connect(hostname, port);
|
||||
|
||||
@@ -12,8 +12,8 @@ import forge.gui.framework.EDocID;
|
||||
import forge.gui.framework.FScreen;
|
||||
import forge.gui.framework.IVDoc;
|
||||
import forge.gui.framework.IVTopLevelUI;
|
||||
import forge.match.GameLobby;
|
||||
import forge.screens.home.VLobby;
|
||||
import forge.screens.home.VLobby.LobbyType;
|
||||
import forge.toolbox.FPanel;
|
||||
import forge.util.gui.SOptionPane;
|
||||
import forge.view.FView;
|
||||
@@ -33,9 +33,9 @@ public enum VOnlineLobby implements IVDoc<COnlineLobby>, IVTopLevelUI {
|
||||
VLobby getLobby() {
|
||||
return lobby;
|
||||
}
|
||||
VLobby setLobby(final LobbyType type) {
|
||||
this.lobby = new VLobby(type);
|
||||
getLayoutControl().setLobby(lobby);
|
||||
VLobby setLobby(final GameLobby lobby) {
|
||||
this.lobby = new VLobby(lobby);
|
||||
getLayoutControl().setLobby(this.lobby);
|
||||
return this.lobby;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,9 @@ public enum VOnlineLobby implements IVDoc<COnlineLobby>, IVTopLevelUI {
|
||||
container.repaint();
|
||||
}
|
||||
|
||||
lobby.changePlayerFocus(0);
|
||||
if (!lobby.getPlayerPanels().isEmpty()) {
|
||||
lobby.changePlayerFocus(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,11 +9,14 @@ import forge.deckchooser.IDecksComboBoxListener;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.framework.DragTab;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.interfaces.IPlayerChangeListener;
|
||||
import forge.match.GameLobby;
|
||||
import forge.match.LocalLobby;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.screens.home.EMenuGroup;
|
||||
import forge.screens.home.IVSubmenu;
|
||||
import forge.screens.home.VLobby;
|
||||
import forge.screens.home.VHomeUI;
|
||||
import forge.screens.home.VLobby.LobbyType;
|
||||
import forge.screens.home.VLobby;
|
||||
|
||||
/**
|
||||
* Assembles Swing components of constructed submenu singleton.
|
||||
@@ -28,12 +31,22 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
|
||||
private DragCell parentCell;
|
||||
private final DragTab tab = new DragTab("Constructed Mode");
|
||||
|
||||
private final VLobby lobby = new VLobby(LobbyType.LOCAL);
|
||||
private final GameLobby lobby = new LocalLobby();
|
||||
private final VLobby vLobby = new VLobby(lobby);
|
||||
private VSubmenuConstructed() {
|
||||
lobby.setListener(vLobby);
|
||||
|
||||
vLobby.setPlayerChangeListener(new IPlayerChangeListener() {
|
||||
@Override public final void update(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
lobby.applyToSlot(index, event);
|
||||
}
|
||||
});
|
||||
|
||||
vLobby.update();
|
||||
}
|
||||
|
||||
public VLobby getLobby() {
|
||||
return lobby;
|
||||
return vLobby;
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
@@ -112,25 +125,27 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
|
||||
|
||||
container.removeAll();
|
||||
container.setLayout(new MigLayout("insets 0, gap 0, wrap 1, ax right"));
|
||||
container.add(lobby.getLblTitle(), "w 80%, h 40px!, gap 0 0 15px 15px, span 2, al right, pushx");
|
||||
container.add(vLobby.getLblTitle(), "w 80%, h 40px!, gap 0 0 15px 15px, span 2, al right, pushx");
|
||||
|
||||
for (final FDeckChooser fdc : lobby.getDeckChoosers()) {
|
||||
for (final FDeckChooser fdc : vLobby.getDeckChoosers()) {
|
||||
fdc.populate();
|
||||
fdc.getDecksComboBox().addListener(new IDecksComboBoxListener() {
|
||||
@Override public final void deckTypeSelected(final DecksComboBoxEvent ev) {
|
||||
lobby.getPlayerPanelWithFocus().focusOnAvatar();
|
||||
vLobby.getPlayerPanelWithFocus().focusOnAvatar();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
container.add(lobby.getConstructedFrame(), "gap 20px 20px 20px 0px, push, grow");
|
||||
container.add(lobby.getPanelStart(), "gap 0 0 3.5%! 3.5%!, ax center");
|
||||
container.add(vLobby.getConstructedFrame(), "gap 20px 20px 20px 0px, push, grow");
|
||||
container.add(vLobby.getPanelStart(), "gap 0 0 3.5%! 3.5%!, ax center");
|
||||
|
||||
if (container.isShowing()) {
|
||||
container.validate();
|
||||
container.repaint();
|
||||
}
|
||||
|
||||
lobby.changePlayerFocus(0);
|
||||
if (!vLobby.getPlayerPanels().isEmpty()) {
|
||||
vLobby.changePlayerFocus(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ import forge.control.KeyboardShortcuts;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deckchooser.FDeckViewer;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
@@ -61,9 +60,8 @@ import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.FNetOverlay;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.GuiDialog;
|
||||
import forge.gui.GuiUtils;
|
||||
@@ -78,9 +76,9 @@ import forge.interfaces.IButton;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.AbstractGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.menus.IMenuProvider;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.screens.match.controllers.CAntes;
|
||||
@@ -103,6 +101,7 @@ import forge.toolbox.FSkin.SkinImage;
|
||||
import forge.toolbox.MouseTriggerEvent;
|
||||
import forge.toolbox.special.PhaseIndicator;
|
||||
import forge.toolbox.special.PhaseLabel;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.gui.SOptionPane;
|
||||
@@ -183,6 +182,21 @@ public final class CMatchUI
|
||||
public void setGameView(final GameView gameView) {
|
||||
super.setGameView(gameView);
|
||||
screen.setTabCaption(gameView.getTitle());
|
||||
if (sortedPlayers != null) {
|
||||
for (final PlayerView pv : sortedPlayers) {
|
||||
pv.copy(gameView.getPlayers());
|
||||
}
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
for (final VField f : getFieldViews()) {
|
||||
f.getTabletop().setupPlayZone();
|
||||
}
|
||||
for (final VHand h : getHandViews()) {
|
||||
h.getLayoutControl().updateHand();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -248,7 +262,7 @@ public final class CMatchUI
|
||||
view.getLblAvatar().getResizeTimer().start();
|
||||
}
|
||||
|
||||
public void initMatch(final FCollectionView<PlayerView> sortedPlayers, final Iterable<PlayerView> myPlayers) {
|
||||
private void initMatch(final FCollectionView<PlayerView> sortedPlayers, final Iterable<PlayerView> myPlayers) {
|
||||
this.sortedPlayers = sortedPlayers;
|
||||
this.setLocalPlayers(myPlayers);
|
||||
allHands = sortedPlayers.size() == getLocalPlayerCount();
|
||||
@@ -356,7 +370,7 @@ public final class CMatchUI
|
||||
@Override
|
||||
public final boolean stopAtPhase(final PlayerView turn, final PhaseType phase) {
|
||||
final VField vf = getFieldViewFor(turn);
|
||||
final PhaseLabel label = vf.getPhaseIndicator() .getLabelFor(phase);
|
||||
final PhaseLabel label = vf.getPhaseIndicator().getLabelFor(phase);
|
||||
return label == null || label.getEnabled();
|
||||
}
|
||||
|
||||
@@ -541,12 +555,6 @@ public final class CMatchUI
|
||||
return panels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resetForNewGame() {
|
||||
FloatingCardArea.closeAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnOK(final PlayerView playerView) {
|
||||
return view.getBtnOK();
|
||||
@@ -558,13 +566,15 @@ public final class CMatchUI
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusButton(final IButton button) {
|
||||
public void focusButton(final MatchButtonType button) {
|
||||
// ensure we don't steal focus from an overlay
|
||||
if (!SOverlayUtils.overlayHasFocus()) {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
((FButton)button).requestFocusInWindow();
|
||||
@Override public final void run() {
|
||||
final FButton btn = button == MatchButtonType.OK
|
||||
? getCPrompt().getView().getBtnOK()
|
||||
: getCPrompt().getView().getBtnCancel();
|
||||
btn.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -579,7 +589,7 @@ public final class CMatchUI
|
||||
public void updatePhase() {
|
||||
final PlayerView p = getGameView().getPlayerTurn();
|
||||
final PhaseType ph = getGameView().getPhase();
|
||||
PhaseLabel lbl = getFieldViewFor(p).getPhaseIndicator().getLabelFor(ph);
|
||||
final PhaseLabel lbl = p == null ? null : getFieldViewFor(p).getPhaseIndicator().getLabelFor(ph);
|
||||
|
||||
resetAllPhaseButtons();
|
||||
if (lbl != null) {
|
||||
@@ -629,7 +639,11 @@ public final class CMatchUI
|
||||
|
||||
@Override
|
||||
public void updateStack() {
|
||||
getCStack().update();
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
getCStack().update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -664,7 +678,7 @@ public final class CMatchUI
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||
public SpellAbilityView getAbilityToPlay(final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||
if (triggerEvent == null) {
|
||||
if (abilities.isEmpty()) {
|
||||
return null;
|
||||
@@ -691,7 +705,7 @@ public final class CMatchUI
|
||||
boolean enabled;
|
||||
boolean hasEnabled = false;
|
||||
int shortcut = KeyEvent.VK_1; //use number keys as shortcuts for abilities 1-9
|
||||
for (final SpellAbility ab : abilities) {
|
||||
for (final SpellAbilityView ab : abilities) {
|
||||
enabled = ab.canPlay();
|
||||
if (enabled) {
|
||||
hasEnabled = true;
|
||||
@@ -763,12 +777,7 @@ public final class CMatchUI
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hear(LobbyPlayer player, String message) {
|
||||
FNetOverlay.SINGLETON_INSTANCE.addMessage(player.getName(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openView(final Iterable<PlayerView> myPlayers) {
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
final GameView gameView = getGameView();
|
||||
gameView.getGameLog().addObserver(getCLog());
|
||||
|
||||
@@ -841,16 +850,14 @@ public final class CMatchUI
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameEntityView chooseSingleEntityForEffect(final String title, final FCollectionView<? extends GameEntity> optionList, final DelayedReveal delayedReveal, final boolean isOptional, final PlayerControllerHuman controller) {
|
||||
public GameEntityView chooseSingleEntityForEffect(final String title, final Collection<? extends GameEntityView> optionList, final DelayedReveal delayedReveal, final boolean isOptional) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(controller); //TODO: Merge this into search dialog
|
||||
reveal(delayedReveal.getMessagePrefix(), delayedReveal.getCards()); //TODO: Merge this into search dialog
|
||||
}
|
||||
controller.tempShow(optionList);
|
||||
final List<GameEntityView> gameEntityViews = GameEntityView.getEntityCollection(optionList);
|
||||
if (isOptional) {
|
||||
return oneOrNone(title, gameEntityViews);
|
||||
return oneOrNone(title, optionList);
|
||||
}
|
||||
return one(title, gameEntityViews);
|
||||
return one(title, optionList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package forge.screens.match;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
@@ -91,21 +92,49 @@ public class VMatchUI implements IVTopLevelUI {
|
||||
}
|
||||
}
|
||||
|
||||
// Add extra hands to existing hand panel.
|
||||
for (int i = 1; i < lstHands.size(); i++) {
|
||||
// If already in layout, no need to add again.
|
||||
if (lstHands.get(i).getParentCell() == null) { // if i == 0, we get NPE in two lines
|
||||
DragCell cellWithHand = lstHands.get(0).getParentCell();
|
||||
cellWithHand.addDoc(lstHands.get(i));
|
||||
// Determine (an) existing hand panel
|
||||
DragCell cellWithHands = null;
|
||||
for (final EDocID handId : EDocID.Hands) {
|
||||
cellWithHands = handId.getDoc().getParentCell();
|
||||
if (cellWithHands != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cellWithHands == null) {
|
||||
// Default to a cell we know exists
|
||||
cellWithHands = EDocID.REPORT_LOG.getDoc().getParentCell();
|
||||
}
|
||||
for (final EDocID handId : EDocID.Hands) {
|
||||
final DragCell parentCell = handId.getDoc().getParentCell();
|
||||
VHand myVHand = null;
|
||||
for (final VHand vHand : lstHands) {
|
||||
if (handId.equals(vHand.getDocumentID())) {
|
||||
myVHand = vHand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any hand panels that aren't needed anymore
|
||||
for (int i = EDocID.Hands.length - 1; i >= lstHands.size(); i--) {
|
||||
DragCell cellWithHand = EDocID.Hands[i].getDoc().getParentCell();
|
||||
if (cellWithHand != null) {
|
||||
cellWithHand.removeDoc(EDocID.Hands[i].getDoc());
|
||||
EDocID.Hands[i].setDoc(new VEmptyDoc(EDocID.Hands[i]));
|
||||
if (myVHand == null) {
|
||||
// Hand not present, remove cell if necessary
|
||||
if (parentCell != null) {
|
||||
parentCell.removeDoc(handId.getDoc());
|
||||
handId.setDoc(new VEmptyDoc(handId));
|
||||
}
|
||||
} else {
|
||||
// Hand present, add it if necessary
|
||||
if (parentCell == null) {
|
||||
final EDocID fieldDoc = EDocID.Fields[Arrays.asList(EDocID.Hands).indexOf(handId)];
|
||||
if (fieldDoc.getDoc().getParentCell() != null) {
|
||||
fieldDoc.getDoc().getParentCell().addDoc(myVHand);
|
||||
continue;
|
||||
}
|
||||
final EDocID commandDoc = EDocID.Commands[Arrays.asList(EDocID.Hands).indexOf(handId)];
|
||||
if (commandDoc.getDoc().getParentCell() != null) {
|
||||
commandDoc.getDoc().getParentCell().addDoc(myVHand);
|
||||
continue;
|
||||
}
|
||||
cellWithHands.addDoc(myVHand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.screens.match.controllers;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.UiCommand;
|
||||
@@ -130,7 +131,8 @@ public class CDock implements ICDoc {
|
||||
public void initialize() {
|
||||
final String temp = FModel.getPreferences()
|
||||
.getPref(FPref.UI_TARGETING_OVERLAY);
|
||||
setArcState(ArcState.values()[Integer.valueOf(temp)]);
|
||||
final Integer arcState = Ints.tryParse(temp);
|
||||
setArcState(ArcState.values()[arcState == null ? 0 : arcState.intValue()]);
|
||||
refreshArcStateDisplay();
|
||||
|
||||
view.getBtnConcede().setCommand(new UiCommand() {
|
||||
|
||||
@@ -32,7 +32,7 @@ import forge.UiCommand;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.gui.framework.SDisplayUtil;
|
||||
import forge.screens.match.CMatchUI;
|
||||
@@ -120,7 +120,7 @@ public class CPrompt implements ICDoc {
|
||||
return matchUI.getGameController().selectCard(cardView, otherCardViewsToSelect, triggerEvent);
|
||||
}
|
||||
|
||||
public void selectAbility(final SpellAbility sa) {
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
matchUI.getGameController().selectAbility(sa);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package forge.toolbox;
|
||||
|
||||
import forge.interfaces.IComboBox;
|
||||
import forge.toolbox.FComboBox.TextAlignment;
|
||||
import forge.toolbox.FSkin.SkinFont;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Container;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.ListCellRenderer;
|
||||
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
|
||||
import forge.interfaces.IComboBox;
|
||||
import forge.toolbox.FComboBox.TextAlignment;
|
||||
import forge.toolbox.FSkin.SkinFont;
|
||||
|
||||
/**
|
||||
* Wrapper for combo box with extra logic (either FComboBoxWrapper or FComboBoxPanel should be used instead of FComboBox so skinning works)
|
||||
*
|
||||
@@ -28,6 +32,7 @@ public class FComboBoxWrapper<E> implements IComboBox<E> {
|
||||
}
|
||||
|
||||
private FComboBox<E> comboBox;
|
||||
private ActionListener[] suppressedActionListeners = null;
|
||||
private Object constraints;
|
||||
|
||||
public FComboBoxWrapper() {
|
||||
@@ -111,6 +116,24 @@ public class FComboBoxWrapper<E> implements IComboBox<E> {
|
||||
comboBox.addItemListener(l);
|
||||
}
|
||||
|
||||
public void suppressActionListeners() {
|
||||
final ActionListener[] listeners = comboBox.getActionListeners();
|
||||
for (final ActionListener al : listeners) {
|
||||
comboBox.removeActionListener(al);
|
||||
}
|
||||
suppressedActionListeners = suppressedActionListeners == null
|
||||
? listeners
|
||||
: ObjectArrays.concat(suppressedActionListeners, listeners, ActionListener.class);
|
||||
}
|
||||
public void unsuppressActionListeners() {
|
||||
if (suppressedActionListeners != null) {
|
||||
for (final ActionListener al : suppressedActionListeners) {
|
||||
comboBox.addActionListener(al);
|
||||
}
|
||||
suppressedActionListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void addKeyListener(KeyListener l) {
|
||||
comboBox.addKeyListener(l);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package forge.toolbox;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.Serializable;
|
||||
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
//MouseEvent wrapper used for passing trigger to input classes
|
||||
public class MouseTriggerEvent implements ITriggerEvent {
|
||||
public class MouseTriggerEvent implements ITriggerEvent, Serializable {
|
||||
private static final long serialVersionUID = -4746127117012991732L;
|
||||
|
||||
private final MouseEvent event;
|
||||
|
||||
public MouseTriggerEvent(MouseEvent event0) {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package forge.gamesimulationtests.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -27,6 +35,7 @@ import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardShields;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
@@ -39,8 +48,13 @@ import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.*;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.Spell;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.TargetChoices;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.WrappedAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -48,18 +62,17 @@ import forge.gamesimulationtests.util.card.CardSpecification;
|
||||
import forge.gamesimulationtests.util.card.CardSpecificationHandler;
|
||||
import forge.gamesimulationtests.util.player.PlayerSpecification;
|
||||
import forge.gamesimulationtests.util.player.PlayerSpecificationHandler;
|
||||
import forge.gamesimulationtests.util.playeractions.*;
|
||||
import forge.player.HumanPlay;
|
||||
import forge.gamesimulationtests.util.playeractions.ActivateAbilityAction;
|
||||
import forge.gamesimulationtests.util.playeractions.CastSpellFromHandAction;
|
||||
import forge.gamesimulationtests.util.playeractions.DeclareAttackersAction;
|
||||
import forge.gamesimulationtests.util.playeractions.DeclareBlockersAction;
|
||||
import forge.gamesimulationtests.util.playeractions.PlayerActions;
|
||||
import forge.item.PaperCard;
|
||||
import forge.player.HumanPlay;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Default harmless implementation for tests.
|
||||
* Test-specific behaviour can easily be added by mocking (parts of) this class.
|
||||
@@ -166,7 +179,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
@Override
|
||||
public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return chooseItem(optionList);
|
||||
}
|
||||
@@ -224,6 +237,11 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
//nothing needs to be done here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal(Collection<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) {
|
||||
//nothing needs to be done here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) {
|
||||
//nothing needs to be done here
|
||||
@@ -628,7 +646,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
String selectPrompt, boolean isOptional, Player decider) {
|
||||
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider);
|
||||
}
|
||||
|
||||
@@ -288,7 +288,4 @@ public class GuiMobile implements IGuiBase {
|
||||
return Forge.hostedMatch = new HostedMatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void netMessage(final String origin, final String message) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import forge.util.Callback;
|
||||
public class GameEntityPicker extends TabPageScreen<GameEntityPicker> {
|
||||
private final FOptionPane optionPane;
|
||||
|
||||
public GameEntityPicker(String title, List<GameEntityView> choiceList, List<CardView> revealList, String revealListCaption, FImage revealListImage, boolean isOptional, final Callback<GameEntityView> callback) {
|
||||
public GameEntityPicker(String title, Collection<? extends GameEntityView> choiceList, Collection<CardView> revealList, String revealListCaption, FImage revealListImage, boolean isOptional, final Callback<GameEntityView> callback) {
|
||||
super(new PickerTab[] {
|
||||
new PickerTab(choiceList, "Choices", FSkinImage.DECKLIST, 1),
|
||||
new PickerTab(revealList, revealListCaption, revealListImage, 0)
|
||||
|
||||
@@ -124,10 +124,6 @@ public class FMenuItem extends FDisplayObject implements IButton {
|
||||
g.drawLine(1, SEPARATOR_COLOR, 0, h, w, h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
@Override
|
||||
public void setText(String text0) {
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ public class ConstructedScreen extends LaunchScreen {
|
||||
PlayerPanel playerPanel = playerPanels.get(i);
|
||||
String name = getPlayerName(i);
|
||||
LobbyPlayer lobbyPlayer = playerPanel.isPlayerAI() ? GamePlayerUtil.createAiPlayer(name,
|
||||
getPlayerAvatar(i)) : GamePlayerUtil.getGuiPlayer(name, i);
|
||||
getPlayerAvatar(i)) : GamePlayerUtil.getGuiPlayer(name, i == 0);
|
||||
RegisteredPlayer rp = playerPanel.deckChooser.getPlayer();
|
||||
|
||||
if (appliedVariants.isEmpty()) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import forge.card.CardRenderer;
|
||||
import forge.card.GameEntityPicker;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.FSideboardDialog;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
@@ -34,17 +33,16 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.AbstractGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.screens.match.views.VAssignDamage;
|
||||
import forge.screens.match.views.VCardDisplayArea.CardAreaPanel;
|
||||
import forge.screens.match.views.VPhaseIndicator;
|
||||
import forge.screens.match.views.VPhaseIndicator.PhaseLabel;
|
||||
import forge.screens.match.views.VPlayerPanel;
|
||||
@@ -53,6 +51,7 @@ import forge.screens.match.views.VPrompt;
|
||||
import forge.screens.match.winlose.ViewWinLose;
|
||||
import forge.toolbox.FDisplayObject;
|
||||
import forge.toolbox.FOptionPane;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.MessageUtil;
|
||||
@@ -102,18 +101,12 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resetForNewGame() {
|
||||
CardAreaPanel.resetForNewGame(); //ensure card panels reset between games
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hotSeatMode() {
|
||||
return FModel.getPreferences().getPrefBoolean(FPref.MATCH_HOT_SEAT_MODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openView(final Iterable<PlayerView> myPlayers) {
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
setLocalPlayers(myPlayers);
|
||||
final boolean noHumans = !hasLocalPlayers();
|
||||
|
||||
@@ -162,7 +155,7 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusButton(final IButton button) {
|
||||
public void focusButton(final MatchButtonType button) {
|
||||
//not needed for mobile game
|
||||
}
|
||||
|
||||
@@ -228,7 +221,7 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||
public SpellAbilityView getAbilityToPlay(List<SpellAbilityView> abilities, ITriggerEvent triggerEvent) {
|
||||
if (abilities.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -324,10 +317,6 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hear(LobbyPlayer player, String message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopAtPhase(PlayerView turn, PhaseType phase) {
|
||||
return view.stopAtPhase(turn, phase);
|
||||
@@ -475,27 +464,23 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameEntityView chooseSingleEntityForEffect(final String title, final FCollectionView<? extends GameEntity> optionList, final DelayedReveal delayedReveal, final boolean isOptional, final PlayerControllerHuman controller) {
|
||||
controller.tempShow(optionList);
|
||||
final List<GameEntityView> choiceList = GameEntityView.getEntityCollection(optionList);
|
||||
|
||||
public GameEntityView chooseSingleEntityForEffect(final String title, final Collection<? extends GameEntityView> optionList, final DelayedReveal delayedReveal, final boolean isOptional) {
|
||||
if (delayedReveal == null || Iterables.isEmpty(delayedReveal.getCards())) {
|
||||
if (isOptional) {
|
||||
return SGuiChoose.oneOrNone(title, choiceList);
|
||||
return SGuiChoose.oneOrNone(title, optionList);
|
||||
}
|
||||
return SGuiChoose.one(title, choiceList);
|
||||
return SGuiChoose.one(title, optionList);
|
||||
}
|
||||
|
||||
controller.tempShow(delayedReveal.getCards());
|
||||
final List<CardView> revealList = CardView.getCollection(delayedReveal.getCards());
|
||||
final String revealListCaption = StringUtils.capitalize(MessageUtil.formatMessage("{player's} " + delayedReveal.getZone().name(), controller.getPlayer(), delayedReveal.getOwner()));
|
||||
final Collection<CardView> revealList = delayedReveal.getCards();
|
||||
final String revealListCaption = StringUtils.capitalize(MessageUtil.formatMessage("{player's} " + delayedReveal.getZone().name(), delayedReveal.getOwner(), delayedReveal.getOwner()));
|
||||
final FImage revealListImage = MatchController.getView().getPlayerPanels().values().iterator().next().getZoneTab(delayedReveal.getZone()).getIcon();
|
||||
|
||||
//use special dialog for choosing card and offering ability to see all revealed cards at the same time
|
||||
return new WaitCallback<GameEntityView>() {
|
||||
@Override
|
||||
public void run() {
|
||||
GameEntityPicker picker = new GameEntityPicker(title, choiceList, revealList, revealListCaption, revealListImage, isOptional, this);
|
||||
GameEntityPicker picker = new GameEntityPicker(title, optionList, revealList, revealListCaption, revealListImage, isOptional, this);
|
||||
picker.show();
|
||||
}
|
||||
}.invokeAndWait();
|
||||
|
||||
@@ -242,6 +242,9 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
if (ev.player.getGame().isGameOver()) {
|
||||
return null;
|
||||
}
|
||||
if (ev.newController instanceof PlayerControllerHuman) {
|
||||
matchController.setGameController(PlayerView.get(ev.player), (PlayerControllerHuman) ev.newController);
|
||||
}
|
||||
needPlayerControlUpdate = true;
|
||||
return processEvent();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import forge.LobbyPlayer;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.input.Input;
|
||||
@@ -90,7 +90,7 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(final SpellAbility sa) {
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,11 +4,8 @@ import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
|
||||
public interface IButton {
|
||||
boolean isEnabled();
|
||||
void setEnabled(boolean b0);
|
||||
boolean isVisible();
|
||||
void setVisible(boolean b0);
|
||||
String getText();
|
||||
void setText(String text0);
|
||||
boolean isSelected();
|
||||
void setSelected(boolean b0);
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.List;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
@@ -33,7 +33,7 @@ public interface IGameController {
|
||||
boolean selectCard(CardView cardView,
|
||||
List<CardView> otherCardViewsToSelect, ITriggerEvent triggerEvent);
|
||||
|
||||
void selectAbility(SpellAbility sa);
|
||||
void selectAbility(SpellAbilityView sa);
|
||||
|
||||
boolean tryUndoLastAction();
|
||||
|
||||
|
||||
@@ -51,5 +51,4 @@ public interface IGuiBase {
|
||||
void showBazaar();
|
||||
IGuiGame getNewGuiGame();
|
||||
HostedMatch hostMatch();
|
||||
void netMessage(String origin, String message);
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import com.google.common.base.Function;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
@@ -19,25 +18,24 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public interface IGuiGame {
|
||||
void setGameView(GameView gameView);
|
||||
void setGameController(PlayerView player, IGameController gameController);
|
||||
boolean resetForNewGame();
|
||||
void openView(Iterable<PlayerView> myPlayers);
|
||||
void openView(TrackableCollection<PlayerView> myPlayers);
|
||||
void afterGameEnd();
|
||||
void showCombat();
|
||||
void showPromptMessage(PlayerView playerView, String message);
|
||||
boolean stopAtPhase(PlayerView playerTurn, PhaseType phase);
|
||||
IButton getBtnOK(PlayerView playerView);
|
||||
IButton getBtnCancel(PlayerView playerView);
|
||||
void focusButton(IButton button);
|
||||
void focusButton(MatchButtonType button);
|
||||
void flashIncorrectAction();
|
||||
void updatePhase();
|
||||
void updateTurn(PlayerView player);
|
||||
@@ -54,8 +52,7 @@ public interface IGuiGame {
|
||||
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
||||
void updateLives(Iterable<PlayerView> livesUpdate);
|
||||
void setPanelSelection(CardView hostCard);
|
||||
void hear(LobbyPlayer player, String message);
|
||||
SpellAbility getAbilityToPlay(List<SpellAbility> abilities,
|
||||
SpellAbilityView getAbilityToPlay(List<SpellAbilityView> abilities,
|
||||
ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignDamage(CardView attacker,
|
||||
List<CardView> blockers, int damage, GameEntityView defender,
|
||||
@@ -161,9 +158,8 @@ public interface IGuiGame {
|
||||
|
||||
List<PaperCard> sideboard(CardPool sideboard, CardPool main);
|
||||
GameEntityView chooseSingleEntityForEffect(String title,
|
||||
FCollectionView<? extends GameEntity> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional,
|
||||
PlayerControllerHuman controller);
|
||||
Collection<? extends GameEntityView> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional);
|
||||
void setCard(CardView card);
|
||||
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
||||
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.net.game.LobbyState;
|
||||
import forge.match.GameLobby;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
|
||||
public interface ILobby {
|
||||
LobbyState getState();
|
||||
GameLobby getState();
|
||||
int login(RemoteClient client);
|
||||
void logout(RemoteClient client);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.match.GameLobby.GameLobbyData;
|
||||
|
||||
public interface ILobbyListener {
|
||||
void message(String source, String message);
|
||||
void update(GameLobbyData state, int slot);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.net.game.LobbyState.LobbyPlayerData;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
|
||||
public interface IPlayerChangeListener {
|
||||
void update(LobbyPlayerData data);
|
||||
void update(int index, UpdateLobbyPlayerEvent event);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package forge.interfaces;
|
||||
|
||||
public interface IUpdateable {
|
||||
void update();
|
||||
}
|
||||
@@ -210,9 +210,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
btnOk.setEnabled(okEnabled);
|
||||
btnCancel.setEnabled(cancelEnabled);
|
||||
if (okEnabled && focusOk) {
|
||||
focusButton(btnOk);
|
||||
focusButton(MatchButtonType.OK);
|
||||
} else if (cancelEnabled) {
|
||||
focusButton(btnCancel);
|
||||
focusButton(MatchButtonType.CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
442
forge-gui/src/main/java/forge/match/GameLobby.java
Normal file
442
forge-gui/src/main/java/forge/match/GameLobby.java
Normal file
@@ -0,0 +1,442 @@
|
||||
package forge.match;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.IUpdateable;
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
public abstract class GameLobby {
|
||||
private final static int MAX_PLAYERS = 8;
|
||||
|
||||
private GameLobbyData data = new GameLobbyData();
|
||||
private int lastArchenemy = 0;
|
||||
|
||||
private IUpdateable listener;
|
||||
|
||||
private final boolean allowNetworking;
|
||||
private HostedMatch hostedMatch;
|
||||
private final Map<LobbySlot, IGameController> gameControllers = Maps.newHashMap();
|
||||
protected GameLobby(final boolean allowNetworking) {
|
||||
this.allowNetworking = allowNetworking;
|
||||
}
|
||||
|
||||
public final boolean isAllowNetworking() {
|
||||
return allowNetworking;
|
||||
}
|
||||
|
||||
public void setListener(final IUpdateable listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public GameLobbyData getData() {
|
||||
return data;
|
||||
}
|
||||
public void setData(final GameLobbyData data) {
|
||||
this.data = data;
|
||||
updateView();
|
||||
}
|
||||
|
||||
public GameType getGameType() {
|
||||
return data.currentGameMode;
|
||||
}
|
||||
public void setGameType(final GameType type) {
|
||||
data.currentGameMode = type;
|
||||
updateView();
|
||||
}
|
||||
|
||||
public boolean hasVariant(final GameType variant) {
|
||||
return data.appliedVariants.contains(variant);
|
||||
}
|
||||
|
||||
public int getNumberOfSlots() {
|
||||
return data.slots.size();
|
||||
}
|
||||
public LobbySlot getSlot(final int index) {
|
||||
if (index < 0 || index >= getNumberOfSlots()) {
|
||||
return null;
|
||||
}
|
||||
return data.slots.get(index);
|
||||
}
|
||||
public void applyToSlot(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
final LobbySlot slot = getSlot(index);
|
||||
if (slot == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
final int nSlots = getNumberOfSlots();
|
||||
final boolean triesToChangeArchenemy = event.getArchenemy() != null;
|
||||
final boolean archenemyRemoved = triesToChangeArchenemy && !event.getArchenemy().booleanValue();
|
||||
final boolean hasArchenemyChanged = triesToChangeArchenemy && slot.isArchenemy() != event.getArchenemy().booleanValue();
|
||||
slot.apply(event);
|
||||
|
||||
// Change archenemy teams
|
||||
if (hasVariant(GameType.Archenemy) && hasArchenemyChanged) {
|
||||
final int newArchenemy = archenemyRemoved ? lastArchenemy : index;
|
||||
if (archenemyRemoved) {
|
||||
lastArchenemy = index;
|
||||
}
|
||||
for (int otherIndex = 0; otherIndex < nSlots; otherIndex++) {
|
||||
final LobbySlot otherSlot = getSlot(otherIndex);
|
||||
final boolean becomesArchenemy = otherIndex == newArchenemy;
|
||||
if (!archenemyRemoved && otherSlot.isArchenemy() && !becomesArchenemy) {
|
||||
lastArchenemy = otherIndex;
|
||||
}
|
||||
otherSlot.setIsArchenemy(becomesArchenemy);
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
|
||||
public IGameController getController(final int index) {
|
||||
return gameControllers.get(getSlot(index));
|
||||
}
|
||||
public GameView getGameView() {
|
||||
return hostedMatch.getGameView();
|
||||
}
|
||||
|
||||
public abstract boolean hasControl();
|
||||
public abstract boolean mayEdit(final int index);
|
||||
public abstract boolean mayControl(final int index);
|
||||
public abstract boolean mayRemove(final int index);
|
||||
public abstract IGuiGame getGui(final int index);
|
||||
|
||||
public void addSlot() {
|
||||
final int newIndex = getNumberOfSlots();
|
||||
addSlot(new LobbySlot(allowNetworking ? LobbySlotType.OPEN : LobbySlotType.LOCAL, null, newIndex, newIndex, false, Collections.<AIOption>emptySet()));
|
||||
}
|
||||
protected final void addSlot(final LobbySlot slot) {
|
||||
if (data.slots.size() >= MAX_PLAYERS) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.slots.add(slot);
|
||||
if (StringUtils.isEmpty(slot.getName())) {
|
||||
slot.setName(randomName());
|
||||
}
|
||||
if (data.slots.size() == 1) {
|
||||
// If first slot, make archenemy
|
||||
slot.setIsArchenemy(true);
|
||||
lastArchenemy = 0;
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
private String randomName() {
|
||||
final List<String> names = Lists.newArrayListWithCapacity(MAX_PLAYERS);
|
||||
for (final LobbySlot slot : data.slots) {
|
||||
names.add(slot.getName());
|
||||
}
|
||||
return NameGenerator.getRandomName("Any", "Any", names);
|
||||
}
|
||||
protected final String localName() {
|
||||
return FModel.getPreferences().getPref(FPref.PLAYER_NAME);
|
||||
}
|
||||
protected final int[] localAvatarIndices() {
|
||||
final String[] sAvatars = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
final int[] result = new int[sAvatars.length];
|
||||
for (int i = 0; i < sAvatars.length; i++) {
|
||||
final Integer val = Ints.tryParse(sAvatars[i]);
|
||||
result[i] = val == null ? -1 : val.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void removeSlot(final int index) {
|
||||
if (index < 0 || index >= data.slots.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getSlot(index).isArchenemy()) {
|
||||
getSlot(lastArchenemy).setIsArchenemy(true);
|
||||
// Should actually be a stack here, but that's rather involved for
|
||||
// such a nonimportant feature
|
||||
lastArchenemy = 0;
|
||||
} else if (lastArchenemy == index) {
|
||||
lastArchenemy = 0;
|
||||
} else {
|
||||
lastArchenemy--;
|
||||
}
|
||||
data.slots.remove(index);
|
||||
updateView();
|
||||
}
|
||||
|
||||
public void applyVariant(final GameType variant) {
|
||||
data.currentGameMode = variant;
|
||||
data.appliedVariants.add(variant);
|
||||
|
||||
//ensure other necessary variants are unchecked
|
||||
switch (variant) {
|
||||
case Archenemy:
|
||||
data.appliedVariants.remove(GameType.ArchenemyRumble);
|
||||
break;
|
||||
case ArchenemyRumble:
|
||||
data.appliedVariants.remove(GameType.Archenemy);
|
||||
break;
|
||||
case Commander:
|
||||
data.appliedVariants.remove(GameType.TinyLeaders);
|
||||
data.appliedVariants.remove(GameType.MomirBasic);
|
||||
break;
|
||||
case TinyLeaders:
|
||||
data.appliedVariants.remove(GameType.Commander);
|
||||
data.appliedVariants.remove(GameType.MomirBasic);
|
||||
break;
|
||||
case Vanguard:
|
||||
data.appliedVariants.remove(GameType.MomirBasic);
|
||||
break;
|
||||
case MomirBasic:
|
||||
data.appliedVariants.remove(GameType.Commander);
|
||||
data.appliedVariants.remove(GameType.Vanguard);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
|
||||
public void removeVariant(final GameType variant) {
|
||||
data.appliedVariants.remove(variant);
|
||||
if (data.appliedVariants.isEmpty()) {
|
||||
data.appliedVariants.add(GameType.Constructed);
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
|
||||
private boolean isEnoughTeams() {
|
||||
int lastTeam = -1;
|
||||
final boolean useArchenemyTeams = data.appliedVariants.contains(GameType.Archenemy);
|
||||
for (final LobbySlot slot : data.slots) {
|
||||
final int team = useArchenemyTeams ? (slot.isArchenemy() ? 0 : 1) : slot.getTeam();
|
||||
if (lastTeam == -1) {
|
||||
lastTeam = team;
|
||||
} else if (lastTeam != team) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected final void updateView() {
|
||||
if (listener != null) {
|
||||
listener.update();
|
||||
}
|
||||
}
|
||||
|
||||
/** Starts a match with the applied variants. */
|
||||
public void startGame() {
|
||||
if (!isEnoughTeams()) {
|
||||
SOptionPane.showMessageDialog("There are not enough teams! Please adjust team allocations.");
|
||||
return;
|
||||
}
|
||||
|
||||
final List<LobbySlot> activeSlots = Lists.newArrayListWithCapacity(getNumberOfSlots());
|
||||
for (final LobbySlot slot : data.getSlots()) {
|
||||
if (slot.getType() != LobbySlotType.OPEN) {
|
||||
activeSlots.add(slot);
|
||||
}
|
||||
}
|
||||
|
||||
for (final LobbySlot slot : activeSlots) {
|
||||
if (slot.getDeck() == null) {
|
||||
SOptionPane.showMessageDialog(String.format("Please specify a deck for %s", slot.getName()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Set<GameType> variantTypes = data.appliedVariants;
|
||||
|
||||
GameType autoGenerateVariant = null;
|
||||
boolean isCommanderMatch = false;
|
||||
boolean isTinyLeadersMatch = false;
|
||||
if (!variantTypes.isEmpty()) {
|
||||
isTinyLeadersMatch = variantTypes.contains(GameType.TinyLeaders);
|
||||
isCommanderMatch = isTinyLeadersMatch || variantTypes.contains(GameType.Commander);
|
||||
if (!isCommanderMatch) {
|
||||
for (final GameType variant : variantTypes) {
|
||||
if (variant.isAutoGenerated()) {
|
||||
autoGenerateVariant = variant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
|
||||
|
||||
//Auto-generated decks don't need to be checked here
|
||||
//Commander deck replaces regular deck and is checked later
|
||||
if (checkLegality && autoGenerateVariant == null && !isCommanderMatch) {
|
||||
for (final LobbySlot slot : activeSlots) {
|
||||
final String name = slot.getName();
|
||||
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(slot.getDeck());
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>();
|
||||
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
|
||||
final Map<RegisteredPlayer, LobbySlot> playerToSlot = Maps.newHashMap();
|
||||
boolean hasNameBeenSet = false;
|
||||
for (final LobbySlot slot : activeSlots) {
|
||||
final IGuiGame gui = getGui(data.slots.indexOf(slot));
|
||||
final String name = slot.getName();
|
||||
final int avatar = slot.getAvatarIndex();
|
||||
final int team = slot.getTeam();
|
||||
final boolean isArchenemy = slot.isArchenemy();
|
||||
final Set<AIOption> aiOptions = slot.getAiOptions();
|
||||
|
||||
final boolean isAI = slot.getType() == LobbySlotType.AI;
|
||||
final LobbyPlayer lobbyPlayer;
|
||||
if (isAI) {
|
||||
lobbyPlayer = GamePlayerUtil.createAiPlayer(name, avatar, aiOptions);
|
||||
} else {
|
||||
boolean setNameNow = false;
|
||||
if (!hasNameBeenSet && slot.getType() == LobbySlotType.LOCAL) {
|
||||
setNameNow = true;
|
||||
hasNameBeenSet = true;
|
||||
}
|
||||
lobbyPlayer = GamePlayerUtil.getGuiPlayer(name, setNameNow);
|
||||
}
|
||||
|
||||
Deck deck = slot.getDeck();
|
||||
RegisteredPlayer rp = new RegisteredPlayer(deck);
|
||||
|
||||
if (variantTypes.isEmpty()) {
|
||||
rp.setTeamNumber(team);
|
||||
players.add(rp.setPlayer(lobbyPlayer));
|
||||
} else {
|
||||
PaperCard vanguardAvatar = null;
|
||||
if (isCommanderMatch) {
|
||||
final GameType commanderGameType = isTinyLeadersMatch ? GameType.TinyLeaders : GameType.Commander;
|
||||
if (checkLegality) {
|
||||
String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck);
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid " + commanderGameType + " Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (autoGenerateVariant != null) {
|
||||
deck = autoGenerateVariant.autoGenerateDeck(rp);
|
||||
final CardPool avatarPool = deck.get(DeckSection.Avatar);
|
||||
if (avatarPool != null) {
|
||||
vanguardAvatar = avatarPool.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise variables for other variants
|
||||
deck = deck == null ? rp.getDeck() : deck;
|
||||
Iterable<PaperCard> schemes = null;
|
||||
Iterable<PaperCard> planes = null;
|
||||
|
||||
//Archenemy
|
||||
if (variantTypes.contains(GameType.ArchenemyRumble)
|
||||
|| (variantTypes.contains(GameType.Archenemy) && isArchenemy)) {
|
||||
final CardPool schemePool = deck.get(DeckSection.Schemes);
|
||||
if (checkLegality) {
|
||||
String errMsg = DeckFormat.getSchemeSectionConformanceProblem(schemePool);
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Scheme Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
schemes = schemePool.toFlatList();
|
||||
}
|
||||
|
||||
//Planechase
|
||||
if (variantTypes.contains(GameType.Planechase)) {
|
||||
final CardPool planePool = deck.get(DeckSection.Planes);
|
||||
if (checkLegality) {
|
||||
String errMsg = DeckFormat.getPlaneSectionConformanceProblem(planePool);
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Planar Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
planes = planePool.toFlatList();
|
||||
}
|
||||
|
||||
//Vanguard
|
||||
if (variantTypes.contains(GameType.Vanguard)) {
|
||||
if (vanguardAvatar == null) { //ERROR! null if avatar deselected on list
|
||||
SOptionPane.showMessageDialog("No Vanguard avatar selected for " + name
|
||||
+ ". Please choose one or disable the Vanguard variant");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rp = RegisteredPlayer.forVariants(variantTypes, deck, schemes, isArchenemy, planes, vanguardAvatar);
|
||||
rp.setTeamNumber(team);
|
||||
players.add(rp.setPlayer(lobbyPlayer));
|
||||
}
|
||||
|
||||
if (!isAI) {
|
||||
guis.put(rp, gui);
|
||||
}
|
||||
playerToSlot.put(rp, slot);
|
||||
}
|
||||
|
||||
hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.startMatch(GameType.Constructed, variantTypes, players, guis);
|
||||
|
||||
for (final Player p : hostedMatch.getGame().getPlayers()) {
|
||||
final LobbySlot slot = playerToSlot.get(p.getRegisteredPlayer());
|
||||
if (p.getController() instanceof IGameController) {
|
||||
gameControllers.put(slot, (IGameController) p.getController());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final static class GameLobbyData implements Serializable {
|
||||
private static final long serialVersionUID = -9038854736144187540L;
|
||||
|
||||
private transient GameType currentGameMode = GameType.Constructed;
|
||||
private final Set<GameType> appliedVariants = EnumSet.of(GameType.Constructed);
|
||||
private final List<LobbySlot> slots = Lists.newArrayList();
|
||||
|
||||
public GameType getCurrentGameMode() {
|
||||
return currentGameMode;
|
||||
}
|
||||
public void setCurrentGameMode(GameType currentGameMode) {
|
||||
this.currentGameMode = currentGameMode;
|
||||
}
|
||||
public Set<GameType> getAppliedVariants() {
|
||||
return Collections.unmodifiableSet(appliedVariants);
|
||||
}
|
||||
public List<LobbySlot> getSlots() {
|
||||
return Collections.unmodifiableList(slots);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,8 @@ import forge.properties.ForgePreferences.FPref;
|
||||
import forge.quest.QuestController;
|
||||
import forge.sound.MusicPlaylist;
|
||||
import forge.sound.SoundSystem;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.CollectionSuppliers;
|
||||
import forge.util.FCollection;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.maps.HashMapOfLists;
|
||||
@@ -137,8 +137,6 @@ public class HostedMatch {
|
||||
game.subscribeToEvents(SoundSystem.instance);
|
||||
game.subscribeToEvents(visitor);
|
||||
|
||||
final String[] indices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
|
||||
// Instantiate all required field slots (user at 0)
|
||||
final List<Player> sortedPlayers = Lists.newArrayList(game.getRegisteredPlayers());
|
||||
Collections.sort(sortedPlayers, new Comparator<Player>() {
|
||||
@@ -150,18 +148,23 @@ public class HostedMatch {
|
||||
}
|
||||
});
|
||||
|
||||
final String[] avatarIndices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
final GameView gameView = getGameView();
|
||||
|
||||
int i = 0;
|
||||
int avatarIndex = 0;
|
||||
humanCount = 0;
|
||||
final MapOfLists<IGuiGame, PlayerView> playersPerGui = new HashMapOfLists<IGuiGame, PlayerView>(CollectionSuppliers.<PlayerView>arrayLists());
|
||||
for (final Player p : sortedPlayers) {
|
||||
if (i < indices.length) {
|
||||
avatarIndex = Integer.parseInt(indices[i]);
|
||||
i++;
|
||||
for (int iPlayer = 0; iPlayer < sortedPlayers.size(); iPlayer++) {
|
||||
final RegisteredPlayer rp = match.getPlayers().get(iPlayer);
|
||||
final Player p = sortedPlayers.get(iPlayer);
|
||||
|
||||
p.getLobbyPlayer().setAvatarIndex(rp.getPlayer().getAvatarIndex());
|
||||
if (p.getLobbyPlayer().getAvatarIndex() == -1) {
|
||||
if (iPlayer < avatarIndices.length) {
|
||||
p.getLobbyPlayer().setAvatarIndex(Integer.parseInt(avatarIndices[iPlayer]));
|
||||
} else {
|
||||
p.getLobbyPlayer().setAvatarIndex(0);
|
||||
}
|
||||
}
|
||||
p.getLobbyPlayer().setAvatarIndex(avatarIndex);
|
||||
p.updateAvatar();
|
||||
|
||||
if (p.getController() instanceof PlayerControllerHuman) {
|
||||
@@ -177,8 +180,9 @@ public class HostedMatch {
|
||||
humanCount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (final Entry<IGuiGame, Collection<PlayerView>> e : playersPerGui.entrySet()) {
|
||||
e.getKey().openView(new FCollection<PlayerView>(e.getValue()));
|
||||
e.getKey().openView(new TrackableCollection<PlayerView>(e.getValue()));
|
||||
}
|
||||
|
||||
if (humanCount == 0) { //watch game but do not participate
|
||||
|
||||
109
forge-gui/src/main/java/forge/match/LobbySlot.java
Normal file
109
forge-gui/src/main/java/forge/match/LobbySlot.java
Normal file
@@ -0,0 +1,109 @@
|
||||
package forge.match;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.deck.Deck;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
|
||||
public final class LobbySlot implements Serializable {
|
||||
private static final long serialVersionUID = 6918205436608794289L;
|
||||
|
||||
private LobbySlotType type;
|
||||
private String name;
|
||||
private int avatarIndex;
|
||||
private int team;
|
||||
private boolean isArchenemy;
|
||||
private Deck deck;
|
||||
private ImmutableSet<AIOption> aiOptions;
|
||||
|
||||
public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final Set<AIOption> aiOptions) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.avatarIndex = avatarIndex;
|
||||
this.team = team;
|
||||
this.isArchenemy = isArchenemy;
|
||||
this.setAiOptions(aiOptions);
|
||||
}
|
||||
|
||||
void apply(final UpdateLobbyPlayerEvent data) {
|
||||
if (data.getType() != null) {
|
||||
setType(data.getType());
|
||||
}
|
||||
if (data.getName() != null) {
|
||||
setName(data.getName());
|
||||
}
|
||||
if (data.getAvatarIndex() != -1) {
|
||||
setAvatarIndex(data.getAvatarIndex());
|
||||
}
|
||||
if (data.getTeam() != -1) {
|
||||
setTeam(data.getTeam());
|
||||
}
|
||||
if (data.getArchenemy() != null) {
|
||||
setIsArchenemy(data.getArchenemy().booleanValue());
|
||||
}
|
||||
if (data.getAiOptions() != null) {
|
||||
setAiOptions(data.getAiOptions());
|
||||
}
|
||||
if (data.getDeck() != null) {
|
||||
setDeck(data.getDeck());
|
||||
} else if (getDeck() != null && data.getSection() != null && data.getCards() != null) {
|
||||
getDeck().putSection(data.getSection(), data.getCards());
|
||||
}
|
||||
}
|
||||
|
||||
public LobbySlotType getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(final LobbySlotType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getAvatarIndex() {
|
||||
return avatarIndex;
|
||||
}
|
||||
public void setAvatarIndex(final int avatarIndex) {
|
||||
this.avatarIndex = avatarIndex;
|
||||
}
|
||||
|
||||
public int getTeam() {
|
||||
return team;
|
||||
}
|
||||
public void setTeam(final int team) {
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
public boolean isArchenemy() {
|
||||
return isArchenemy;
|
||||
}
|
||||
public void setIsArchenemy(final boolean isArchenemy) {
|
||||
this.isArchenemy = isArchenemy;
|
||||
}
|
||||
|
||||
public Deck getDeck() {
|
||||
return deck;
|
||||
}
|
||||
public void setDeck(final Deck deck) {
|
||||
this.deck = deck;
|
||||
}
|
||||
|
||||
public ImmutableSet<AIOption> getAiOptions() {
|
||||
return aiOptions;
|
||||
}
|
||||
|
||||
public void setAiOptions(final Set<AIOption> aiOptions) {
|
||||
this.aiOptions = aiOptions == null ? ImmutableSet.<AIOption>of() : ImmutableSet.copyOf(aiOptions);
|
||||
}
|
||||
|
||||
}
|
||||
44
forge-gui/src/main/java/forge/match/LocalLobby.java
Normal file
44
forge-gui/src/main/java/forge/match/LocalLobby.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.GuiBase;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.net.game.LobbySlotType;
|
||||
|
||||
public final class LocalLobby extends GameLobby {
|
||||
|
||||
public LocalLobby() {
|
||||
super(false);
|
||||
|
||||
final String humanName = localName();
|
||||
final int[] avatarIndices = localAvatarIndices();
|
||||
|
||||
final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], 0, true, Collections.<AIOption>emptySet());
|
||||
addSlot(slot0);
|
||||
|
||||
final LobbySlot slot1 = new LobbySlot(LobbySlotType.AI, null, avatarIndices[1], 1, false, Collections.<AIOption>emptySet());
|
||||
addSlot(slot1);
|
||||
}
|
||||
|
||||
@Override public boolean hasControl() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayEdit(final int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayControl(final int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayRemove(final int index) {
|
||||
return index >= 2;
|
||||
}
|
||||
|
||||
@Override public IGuiGame getGui(final int index) {
|
||||
return GuiBase.getInterface().getNewGuiGame();
|
||||
}
|
||||
}
|
||||
6
forge-gui/src/main/java/forge/match/MatchButtonType.java
Normal file
6
forge-gui/src/main/java/forge/match/MatchButtonType.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package forge.match;
|
||||
|
||||
public enum MatchButtonType {
|
||||
OK,
|
||||
CANCEL;
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.PaperCard;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.server.IToClient;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.trackable.TrackableObject;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGuiGame extends AbstractGuiGame {
|
||||
|
||||
private final IToClient client;
|
||||
public NetGuiGame(final IToClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
private void send(final String method) {
|
||||
send(method, Collections.<TrackableObject>emptySet());
|
||||
}
|
||||
private void send(final String method, final TrackableObject object) {
|
||||
send(method, Collections.singleton(object));
|
||||
}
|
||||
private void send(final String method, final Iterable<? extends TrackableObject> objects) {
|
||||
client.send(new GuiGameEvent(method, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameView(final GameView gameView) {
|
||||
super.setGameView(gameView);
|
||||
send("setGameView", gameView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resetForNewGame() {
|
||||
send("resetForNewGame");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openView(final Iterable<PlayerView> myPlayers) {
|
||||
send("openView", myPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterGameEnd() {
|
||||
send("afterGameEnd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCombat() {
|
||||
send("showCombat");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptMessage(PlayerView playerView, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopAtPhase(PlayerView playerTurn, PhaseType phase) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnOK(final PlayerView playerView) {
|
||||
return new NetButton(playerView, "OK");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnCancel(final PlayerView playerView) {
|
||||
return new NetButton(playerView, "Cancel");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusButton(IButton button) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flashIncorrectAction() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePhase() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTurn(PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlayerControl() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableOverlay() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableOverlay() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishGame() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object showManaPool(PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideManaPool(PlayerView player, Object zoneToRestore) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStack() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateZones(List<Pair<PlayerView, ZoneType>> zonesToUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSingleCard(CardView card) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManaPool(Iterable<PlayerView> manaPoolUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLives(Iterable<PlayerView> livesUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPanelSelection(CardView hostCard) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hear(LobbyPlayer player, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities,
|
||||
ITriggerEvent triggerEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CardView, Integer> assignDamage(CardView attacker,
|
||||
List<CardView> blockers, int damage, GameEntityView defender,
|
||||
boolean overrideOrder) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(String message, String title) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(String message, String title) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(String message, String title,
|
||||
String yesButtonText, String noButtonText, boolean defaultYes) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showOptionDialog(String message, String title, FSkinProp icon,
|
||||
String[] options, int defaultOption) {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showCardOptionDialog(CardView card, String message,
|
||||
String title, FSkinProp icon, String[] options, int defaultOption) {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showInputDialog(String message, String title, FSkinProp icon,
|
||||
String initialInput, String[] inputOptions) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirm(CardView c, String question, boolean defaultIsYes,
|
||||
String[] options) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(String message, int min, int max,
|
||||
Collection<T> choices, T selected, Function<T, String> display) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> order(String title, String top, int remainingObjectsMin,
|
||||
int remainingObjectsMax, List<T> sourceChoices,
|
||||
List<T> destChoices, CardView referenceCard,
|
||||
boolean sideboardingMode) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> sideboard(CardPool sideboard, CardPool main) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameEntityView chooseSingleEntityForEffect(String title,
|
||||
FCollectionView<? extends GameEntity> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional,
|
||||
PlayerControllerHuman controller) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCard(CardView card) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean openZones(Collection<ZoneType> zones,
|
||||
Map<PlayerView, Object> players) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreOldZones(Map<PlayerView, Object> playersToRestoreZonesFor) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiSetToSkipPhase(PlayerView playerTurn, PhaseType phase) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentPlayer(PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
private final static class NetButton implements IButton {
|
||||
|
||||
private final PlayerView playerView;
|
||||
private final String button;
|
||||
private NetButton(final PlayerView playerView, final String button) {
|
||||
this.playerView = playerView;
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean b0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String text0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(boolean b0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestFocusInWindow() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCommand(UiCommand command0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(FSkinProp color) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(int r, int g, int b) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,11 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
showMessage(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final boolean allowAwaitNextInput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final void onOk() {
|
||||
|
||||
@@ -125,13 +125,13 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
@Override
|
||||
protected boolean onCardSelected(final Card card, final List<Card> otherCardsToSelect, final ITriggerEvent triggerEvent) {
|
||||
//remove unplayable unless triggerEvent specified, in which case unplayable may be shown as disabled options
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(getController().getPlayer(), triggerEvent == null);
|
||||
if (abilities.isEmpty()) {
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(getController().getPlayer(), triggerEvent == null);
|
||||
if (abilities.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final SpellAbility ability = getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
if (ability != null) {
|
||||
if (ability != null) {
|
||||
chosenSa = new ArrayList<SpellAbility>();
|
||||
chosenSa.add(ability);
|
||||
if (otherCardsToSelect != null && ability.isManaAbility()) {
|
||||
|
||||
@@ -149,7 +149,7 @@ public class InputProxy implements Observer {
|
||||
}
|
||||
|
||||
public final void selectAbility(final SpellAbility sa) {
|
||||
final Input inp = getInput();
|
||||
final Input inp = getInput();
|
||||
if (inp != null) {
|
||||
if (sa != null) {
|
||||
inp.selectAbility(sa);
|
||||
|
||||
36
forge-gui/src/main/java/forge/net/ClientGameLobby.java
Normal file
36
forge-gui/src/main/java/forge/net/ClientGameLobby.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package forge.net;
|
||||
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.GameLobby;
|
||||
|
||||
public final class ClientGameLobby extends GameLobby {
|
||||
private int localPlayer = -1;
|
||||
|
||||
public ClientGameLobby() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
public void setLocalPlayer(final int index) {
|
||||
this.localPlayer = index;
|
||||
}
|
||||
|
||||
@Override public boolean hasControl() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean mayEdit(final int index) {
|
||||
return index == localPlayer;
|
||||
}
|
||||
|
||||
@Override public boolean mayControl(final int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean mayRemove(final int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public IGuiGame getGui(final int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -15,22 +15,44 @@ import io.netty.handler.codec.serialization.ClassResolvers;
|
||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||
import io.netty.handler.codec.serialization.ObjectEncoder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.ILobbyListener;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.model.FModel;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.LobbyUpdateEvent;
|
||||
import forge.net.game.IdentifiableNetEvent;
|
||||
import forge.net.game.LoginEvent;
|
||||
import forge.net.game.MessageEvent;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.client.ILobbyListener;
|
||||
import forge.net.game.ReplyEvent;
|
||||
import forge.net.game.client.IToServer;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class FGameClient implements IToServer {
|
||||
private final IGuiGame clientGui;
|
||||
@@ -39,6 +61,7 @@ public class FGameClient implements IToServer {
|
||||
}
|
||||
|
||||
private final List<ILobbyListener> lobbyListeners = Lists.newArrayList();
|
||||
private final ReplyPool replies = new ReplyPool();
|
||||
|
||||
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
|
||||
|
||||
@@ -81,14 +104,32 @@ public class FGameClient implements IToServer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(final NetEvent event) {
|
||||
System.out.println("Client sent " + event);
|
||||
channel.writeAndFlush(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object sendAndWait(final IdentifiableNetEvent event) throws TimeoutException {
|
||||
replies.initialize(event.getId());
|
||||
|
||||
send(event);
|
||||
|
||||
// Wait for reply
|
||||
return replies.get(event.getId());
|
||||
}
|
||||
|
||||
public void addLobbyListener(final ILobbyListener listener) {
|
||||
lobbyListeners.add(listener);
|
||||
}
|
||||
|
||||
private void setGameControllers(final Iterable<PlayerView> myPlayers) {
|
||||
for (final PlayerView p : myPlayers) {
|
||||
clientGui.setGameController(p, new NetGameController(this));
|
||||
}
|
||||
}
|
||||
|
||||
private class GameClientHandler extends ChannelInboundHandlerAdapter {
|
||||
/**
|
||||
* Creates a client-side handler.
|
||||
@@ -98,24 +139,214 @@ public class FGameClient implements IToServer {
|
||||
|
||||
@Override
|
||||
public void channelActive(final ChannelHandlerContext ctx) {
|
||||
// Don't use send here, as this.channel is not yet set!
|
||||
ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME)));
|
||||
// Don't use send() here, as this.channel is not yet set!
|
||||
ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0])));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
|
||||
System.out.println("Client received: " + msg);
|
||||
if (msg instanceof GuiGameEvent) {
|
||||
if (msg instanceof ReplyEvent) {
|
||||
final ReplyEvent event = (ReplyEvent) msg;
|
||||
replies.complete(event.getIndex(), event.getReply());
|
||||
} else if (msg instanceof GuiGameEvent) {
|
||||
final GuiGameEvent event = (GuiGameEvent) msg;
|
||||
final Object[] args = event.getObjects();
|
||||
Serializable reply = null;
|
||||
boolean doReply = false;
|
||||
|
||||
final IButton btn;
|
||||
if (args.length >= 2 && args[0] instanceof PlayerView && args[1] instanceof MatchButtonType) {
|
||||
btn = args[1] == MatchButtonType.OK ? clientGui.getBtnOK((PlayerView) args[0]) : clientGui.getBtnCancel((PlayerView) args[0]);
|
||||
} else {
|
||||
btn = null;
|
||||
}
|
||||
|
||||
switch (event.getMethod()) {
|
||||
case "setGameView":
|
||||
clientGui.setGameView((GameView) event.getObject());
|
||||
clientGui.setGameView((GameView) args[0]);
|
||||
break;
|
||||
case "openView":
|
||||
clientGui.openView((Iterable<PlayerView>) event.getObjects());
|
||||
default:
|
||||
final TrackableCollection<PlayerView> myPlayers = (TrackableCollection<PlayerView>) args[0];
|
||||
setGameControllers(myPlayers);
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
//clientGui.setGameView(new NetGameView(FGameClient.this));
|
||||
clientGui.openView(myPlayers);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "afterGameEnd":
|
||||
clientGui.afterGameEnd();
|
||||
break;
|
||||
case "showCombat":
|
||||
clientGui.showCombat();
|
||||
break;
|
||||
case "showPromptMessage":
|
||||
clientGui.showPromptMessage((PlayerView) args[0], (String) args[1]);
|
||||
break;
|
||||
case "stopAtPhase":
|
||||
reply = clientGui.stopAtPhase((PlayerView) args[0], (PhaseType) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "focusButton":
|
||||
clientGui.focusButton((MatchButtonType) args[0]);
|
||||
break;
|
||||
case "flashIncorrectAction":
|
||||
clientGui.flashIncorrectAction();
|
||||
break;
|
||||
case "updatePhase":
|
||||
clientGui.updatePhase();
|
||||
break;
|
||||
case "updateTurn":
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
clientGui.updateTurn((PlayerView) args[0]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "udpdatePlayerControl":
|
||||
clientGui.updatePlayerControl();
|
||||
break;
|
||||
case "enableOverlay":
|
||||
clientGui.enableOverlay();
|
||||
break;
|
||||
case "disbleOverlay":
|
||||
clientGui.disableOverlay();
|
||||
break;
|
||||
case "finishGame":
|
||||
clientGui.finishGame();
|
||||
break;
|
||||
case "showManaPool":
|
||||
clientGui.showManaPool((PlayerView) args[0]);
|
||||
break;
|
||||
case "hideManaPool":
|
||||
clientGui.hideManaPool((PlayerView) args[0], args[1]);
|
||||
break;
|
||||
case "updateStack":
|
||||
clientGui.updateStack();
|
||||
break;
|
||||
case "updateZones":
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
clientGui.updateZones((List<Pair<PlayerView, ZoneType>>) args[0]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "updateSingleCard":
|
||||
clientGui.updateSingleCard((CardView) args[0]);
|
||||
break;
|
||||
case "updateManaPool":
|
||||
clientGui.updateManaPool((Iterable<PlayerView>) args[0]);
|
||||
break;
|
||||
case "updateLives":
|
||||
clientGui.updateLives((Iterable<PlayerView>) args[0]);
|
||||
break;
|
||||
case "setPanelSelection":
|
||||
clientGui.setPanelSelection((CardView) args[0]);
|
||||
break;
|
||||
case "getAbilityToPlay":
|
||||
reply = clientGui.getAbilityToPlay((List<SpellAbilityView>) args[0], (ITriggerEvent) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "assignDamage":
|
||||
reply = (Serializable) clientGui.assignDamage((CardView) args[0], (List<CardView>) args[1], (int) args[2], (GameEntityView) args[3], (boolean) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "message":
|
||||
clientGui.message((String) args[0], (String) args[1]);
|
||||
break;
|
||||
case "showErrorDialog":
|
||||
clientGui.showErrorDialog((String) args[0], (String) args[1]);
|
||||
break;
|
||||
case "showConfirmDialog":
|
||||
reply = clientGui.showConfirmDialog((String) args[0], (String) args[1], (String) args[2], (String) args[3], (boolean) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "showOptionDialog":
|
||||
reply = clientGui.showOptionDialog((String) args[0], (String) args[1], (FSkinProp) args[2], (String[]) args[3], (int) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "showCardOptionDialog":
|
||||
reply = clientGui.showCardOptionDialog((CardView) args[0], (String) args[1], (String) args[2], (FSkinProp) args[3], (String[]) args[4], (int) args[5]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "showInputDialog":
|
||||
reply = clientGui.showInputDialog((String) args[0], (String) args[1], (FSkinProp) args[2], (String) args[3], (String[]) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "confirm":
|
||||
reply = clientGui.confirm((CardView) args[0], (String) args[1], (boolean) args[2], (String[]) args[3]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "getChoices":
|
||||
reply = (Serializable) clientGui.getChoices((String) args[0], (int) args[1], (int) args[2], (Collection<Object>) args[3], args[4], (Function<Object, String>) args[5]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "order":
|
||||
reply = (Serializable) clientGui.order((String) args[0], (String) args[1], (int) args[2], (int) args[3], (List<Object>) args[4], (List<Object>) args[5], (CardView) args[6], (boolean) args[7]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "sideboard":
|
||||
reply = (Serializable) clientGui.sideboard((CardPool) args[0], (CardPool) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "chooseSingleEntityForEffect":
|
||||
reply = clientGui.chooseSingleEntityForEffect((String) args[0], (TrackableCollection<GameEntityView>) args[1], (DelayedReveal) args[2], (boolean) args[3]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "setCard":
|
||||
clientGui.setCard((CardView) args[0]);
|
||||
break;
|
||||
// TODO case "setPlayerAvatar":
|
||||
case "openZones":
|
||||
reply = clientGui.openZones((Collection<ZoneType>) args[0], (Map<PlayerView, Object>) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "restoreOldZones":
|
||||
clientGui.restoreOldZones((Map<PlayerView, Object>) args[0]);
|
||||
break;
|
||||
case "isUiSetToSkipPhase":
|
||||
reply = clientGui.isUiSetToSkipPhase((PlayerView) args[0], (PhaseType) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
// BUTTONS
|
||||
case "btn_setEnabled":
|
||||
btn.setEnabled((boolean) args[2]);
|
||||
break;
|
||||
case "btn_setVisible":
|
||||
btn.setVisible((boolean) args[2]);
|
||||
break;
|
||||
case "btn_setText":
|
||||
btn.setText((String) args[2]);
|
||||
break;
|
||||
case "btn_isSelected":
|
||||
reply = btn.isSelected();
|
||||
doReply = true;
|
||||
break;
|
||||
case "btn_setSelected":
|
||||
btn.setSelected((boolean) args[2]);
|
||||
break;
|
||||
case "btn_requestFocusInWindows":
|
||||
reply = btn.requestFocusInWindow();
|
||||
doReply = true;
|
||||
break;
|
||||
case "btn_setCommand":
|
||||
btn.setCommand((UiCommand) args[2]);
|
||||
break;
|
||||
case "btn_setTextColor":
|
||||
if (args.length == 3) {
|
||||
btn.setTextColor((FSkinProp) args[2]);
|
||||
} else {
|
||||
btn.setTextColor((int) args[2], (int) args[3], (int) args[4]);
|
||||
}
|
||||
default:
|
||||
System.err.println("Unsupported game event " + event.getMethod());
|
||||
break;
|
||||
}
|
||||
if (doReply) {
|
||||
send(new ReplyEvent(event.getId(), reply));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +376,8 @@ public class FGameClient implements IToServer {
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
if (msg instanceof LobbyUpdateEvent) {
|
||||
for (final ILobbyListener listener : lobbyListeners) {
|
||||
listener.update(((LobbyUpdateEvent) msg).getState());
|
||||
final LobbyUpdateEvent event = (LobbyUpdateEvent) msg;
|
||||
listener.update(event.getState(), event.getSlot());
|
||||
}
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
package forge.net;
|
||||
|
||||
import forge.game.GameRules;
|
||||
import forge.interfaces.ILobby;
|
||||
import forge.net.game.LobbyState;
|
||||
import forge.net.game.LobbyUpdateEvent;
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.ILobbyListener;
|
||||
import forge.match.LobbySlot;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.LoginEvent;
|
||||
import forge.net.game.LogoutEvent;
|
||||
import forge.net.game.MessageEvent;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.RegisterDeckEvent;
|
||||
import forge.net.game.ReplyEvent;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
import forge.util.ITriggerEvent;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
@@ -27,8 +39,14 @@ import io.netty.handler.codec.serialization.ObjectEncoder;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public final class FServerManager {
|
||||
@@ -36,18 +54,13 @@ public final class FServerManager {
|
||||
|
||||
private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
private final Map<Integer, NetGame> games = Maps.newTreeMap();
|
||||
private int id = 0;
|
||||
private final Map<Channel, RemoteClient> clients = Maps.newTreeMap();
|
||||
private ILobby localLobby;
|
||||
private ServerGameLobby localLobby;
|
||||
private ILobbyListener lobbyListener;
|
||||
|
||||
private FServerManager() {
|
||||
}
|
||||
|
||||
private int nextId() {
|
||||
return id++;
|
||||
}
|
||||
|
||||
public static FServerManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FServerManager();
|
||||
@@ -62,15 +75,14 @@ public final class FServerManager {
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
@Override public final void initChannel(final SocketChannel ch) {
|
||||
final ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(
|
||||
new ObjectEncoder(),
|
||||
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
|
||||
new MessageHandler(),
|
||||
new RegisterClientHandler(),
|
||||
new ToLobbyListenersHandler(),
|
||||
new LobbyInputHandler(),
|
||||
new DeregisterClientHandler(),
|
||||
new GameServerHandler());
|
||||
}
|
||||
@@ -101,29 +113,53 @@ public final class FServerManager {
|
||||
}
|
||||
|
||||
public void broadcast(final NetEvent event) {
|
||||
for (final RemoteClient client : clients.values()) {
|
||||
broadcastTo(event, clients.values());
|
||||
}
|
||||
public void broadcastExcept(final NetEvent event, final RemoteClient notTo) {
|
||||
broadcastExcept(event, Collections.singleton(notTo));
|
||||
}
|
||||
public void broadcastExcept(final NetEvent event, final Collection<RemoteClient> notTo) {
|
||||
broadcastTo(event, Iterables.filter(clients.values(), Predicates.not(Predicates.in(notTo))));
|
||||
}
|
||||
private void broadcastTo(final NetEvent event, final Iterable<RemoteClient> to) {
|
||||
for (final RemoteClient client : to) {
|
||||
event.updateForClient(client);
|
||||
client.send(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLobby(final ILobby lobby) {
|
||||
public void setLobby(final ServerGameLobby lobby) {
|
||||
this.localLobby = lobby;
|
||||
}
|
||||
|
||||
public NetGame hostGame(final GameRules rules) {
|
||||
final int id = nextId();
|
||||
final NetGame game = new NetGame(rules);
|
||||
games.put(id, game);
|
||||
return game;
|
||||
public void setLobbyListener(final ILobbyListener listener) {
|
||||
this.lobbyListener = listener;
|
||||
}
|
||||
|
||||
public void updateLobbyState() {
|
||||
final LobbyState state = localLobby.getState();
|
||||
final LobbyUpdateEvent event = new LobbyUpdateEvent(state);
|
||||
final LobbyUpdateEvent event = new LobbyUpdateEvent(localLobby.getData());
|
||||
broadcast(event);
|
||||
}
|
||||
|
||||
public void updateSlot(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
localLobby.applyToSlot(index, event);
|
||||
}
|
||||
|
||||
public IGuiGame getGui(final int index) {
|
||||
final LobbySlot slot = localLobby.getSlot(index);
|
||||
final LobbySlotType type = slot.getType();
|
||||
if (type == LobbySlotType.LOCAL) {
|
||||
return GuiBase.getInterface().getNewGuiGame();
|
||||
} else if (type == LobbySlotType.REMOTE) {
|
||||
for (final RemoteClient client : clients.values()) {
|
||||
if (client.getIndex() == index) {
|
||||
return new NetGuiGame(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
@@ -141,9 +177,187 @@ public final class FServerManager {
|
||||
}
|
||||
|
||||
private class GameServerHandler extends ChannelInboundHandlerAdapter {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
|
||||
System.out.println("Server received: " + msg);
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
if (msg instanceof ReplyEvent) {
|
||||
client.setReply(((ReplyEvent) msg).getIndex(), ((ReplyEvent) msg).getReply());
|
||||
} else if (msg instanceof GuiGameEvent) {
|
||||
final GuiGameEvent event = (GuiGameEvent) msg;
|
||||
final GameView gameView = localLobby.getGameView();
|
||||
final IGameController controller = localLobby.getController(client.getIndex());
|
||||
final Object[] args = event.getObjects();
|
||||
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override public final void run() {
|
||||
Serializable reply = null;
|
||||
boolean doReply = false;
|
||||
|
||||
switch (event.getMethod()) {
|
||||
// From GameController
|
||||
case "useMana":
|
||||
controller.useMana((byte) args[0]);
|
||||
break;
|
||||
case "tryUndoLastAction":
|
||||
reply = controller.tryUndoLastAction();
|
||||
doReply = true;
|
||||
break;
|
||||
case "selectPlayer":
|
||||
controller.selectPlayer((PlayerView) args[0], (ITriggerEvent) args[1]);
|
||||
break;
|
||||
case "selectCard":
|
||||
reply = controller.selectCard((CardView) args[0], (List<CardView>) args[1], (ITriggerEvent) args[2]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "selectButtonOk":
|
||||
controller.selectButtonOk();
|
||||
break;
|
||||
case "selectButtonCancel":
|
||||
controller.selectButtonCancel();
|
||||
break;
|
||||
case "selectAbility":
|
||||
controller.selectAbility((SpellAbilityView) args[0]);
|
||||
break;
|
||||
case "passPriorityUntilEndOfTurn":
|
||||
reply = controller.passPriorityUntilEndOfTurn();
|
||||
doReply = true;
|
||||
break;
|
||||
case "passPriority":
|
||||
reply = controller.passPriority();
|
||||
doReply = true;
|
||||
break;
|
||||
case "nextGameDecision":
|
||||
controller.nextGameDecision((NextGameDecision) args[0]);
|
||||
break;
|
||||
case "mayLookAtAllCards":
|
||||
reply = controller.mayLookAtAllCards();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getActivateDescription":
|
||||
reply = controller.getActivateDescription((CardView) args[0]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "concede":
|
||||
controller.concede();
|
||||
break;
|
||||
case "alphaStrike":
|
||||
controller.alphaStrike();
|
||||
break;
|
||||
// From GameView
|
||||
case "getPlayers":
|
||||
reply = (Serializable) gameView.getPlayers();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getTitle":
|
||||
reply = gameView.getTitle();
|
||||
doReply = true;
|
||||
break;
|
||||
case "isCommander":
|
||||
reply = gameView.isCommander();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getGameType":
|
||||
reply = gameView.getGameType();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getPoisonCountersToLose":
|
||||
reply = gameView.getPoisonCountersToLose();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getNumGamesInMatch":
|
||||
reply = gameView.getNumGamesInMatch();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getTurn":
|
||||
reply = gameView.getTurn();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getPhase":
|
||||
reply = gameView.getPhase();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getPlayerTurn":
|
||||
reply = gameView.getPlayerTurn();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getStack":
|
||||
reply = (Serializable) gameView.getStack();
|
||||
doReply = true;
|
||||
break;
|
||||
case "peekStack":
|
||||
reply = gameView.peekStack();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getStormCount":
|
||||
reply = gameView.getStormCount();
|
||||
doReply = true;
|
||||
break;
|
||||
case "isFirstGameInMatch":
|
||||
reply = gameView.isFirstGameInMatch();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getNumPlayedGamesInMatch":
|
||||
reply = gameView.getNumPlayedGamesInMatch();
|
||||
doReply = true;
|
||||
break;
|
||||
case "isGameOver":
|
||||
reply = gameView.isGameOver();
|
||||
doReply = true;
|
||||
break;
|
||||
case "isMatchOver":
|
||||
reply = gameView.isMatchOver();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getWinningTeam":
|
||||
reply = gameView.getWinningTeam();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getGameLog":
|
||||
reply = gameView.getGameLog();
|
||||
doReply = true;
|
||||
break;
|
||||
case "getCombat":
|
||||
reply = gameView.getCombat();
|
||||
doReply = true;
|
||||
break;
|
||||
case "isMatchWonBy":
|
||||
reply = gameView.isMatchWonBy((LobbyPlayer) args[0]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "getOutcomesOfMatch":
|
||||
reply = (Serializable) gameView.getOutcomesOfMatch();
|
||||
doReply = true;
|
||||
break;
|
||||
// TODO case "getWinningPlayer":
|
||||
case "isWinner":
|
||||
reply = gameView.isWinner((LobbyPlayer) args[0]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "getGamesWonBy":
|
||||
reply = gameView.getGamesWonBy((LobbyPlayer) args[0]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "getDeck":
|
||||
reply = gameView.getDeck((String) args[0]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "getAnteResult":
|
||||
reply = gameView.getAnteResult((PlayerView) args[0]);
|
||||
doReply = true;
|
||||
break;
|
||||
default:
|
||||
System.err.println(String.format("Unknown incoming client command %s", event.getMethod()));
|
||||
break;
|
||||
}
|
||||
|
||||
if (doReply) {
|
||||
client.send(new ReplyEvent(event.getId(), reply));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,8 +372,7 @@ public final class FServerManager {
|
||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||
final RemoteClient client = new RemoteClient(ctx.channel());
|
||||
clients.put(ctx.channel(), client);
|
||||
games.get(0).addClient(client);
|
||||
System.out.println("User connected to server at " + ctx.channel().remoteAddress());
|
||||
System.out.println("Client connected to server at " + ctx.channel().remoteAddress());
|
||||
updateLobbyState();
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
@@ -168,47 +381,45 @@ public final class FServerManager {
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
if (msg instanceof LoginEvent) {
|
||||
client.setUsername(((LoginEvent) msg).getUsername());
|
||||
final String username = ((LoginEvent) msg).getUsername();
|
||||
client.setUsername(username);
|
||||
broadcast(new MessageEvent(null, String.format("%s joined the room", username)));
|
||||
updateLobbyState();
|
||||
} else if (msg instanceof RegisterDeckEvent) {
|
||||
games.get(0).registerDeck(client, ((RegisterDeckEvent) msg).getDeck());
|
||||
} else if (msg instanceof UpdateLobbyPlayerEvent) {
|
||||
localLobby.applyToSlot(client.getIndex(), (UpdateLobbyPlayerEvent) msg);
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private class ToLobbyListenersHandler extends ChannelInboundHandlerAdapter {
|
||||
private class LobbyInputHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
if (msg instanceof LoginEvent) {
|
||||
final LoginEvent event = (LoginEvent) msg;
|
||||
final int index = localLobby.login(client);
|
||||
final int index = localLobby.connectPlayer(event.getUsername(), event.getAvatarIndex());
|
||||
if (index == -1) {
|
||||
ctx.close();
|
||||
} else {
|
||||
client.setIndex(index);
|
||||
broadcast(event);
|
||||
updateLobbyState();
|
||||
}
|
||||
} else if (msg instanceof UpdateLobbyPlayerEvent) {
|
||||
updateSlot(client.getIndex(), (UpdateLobbyPlayerEvent) msg);
|
||||
} else if (msg instanceof MessageEvent) {
|
||||
final MessageEvent event = (MessageEvent) msg;
|
||||
broadcast(event);
|
||||
lobbyListener.message(event.getSource(), event.getMessage());
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
|
||||
@Override public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
localLobby.logout(client);
|
||||
updateLobbyState();
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeregisterClientHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
final RemoteClient client = clients.remove(ctx.channel());
|
||||
// TODO remove client from games
|
||||
localLobby.disconnectPlayer(client.getIndex());
|
||||
broadcast(new LogoutEvent(client.getUsername()));
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
28
forge-gui/src/main/java/forge/net/LobbyUpdateEvent.java
Normal file
28
forge-gui/src/main/java/forge/net/LobbyUpdateEvent.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package forge.net;
|
||||
|
||||
import forge.match.GameLobby.GameLobbyData;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
|
||||
public class LobbyUpdateEvent implements NetEvent {
|
||||
private static final long serialVersionUID = 7114918637727047985L;
|
||||
|
||||
private final GameLobbyData state;
|
||||
private int slot;
|
||||
public LobbyUpdateEvent(final GameLobbyData state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateForClient(final RemoteClient client) {
|
||||
this.slot = client.getIndex();
|
||||
}
|
||||
|
||||
public GameLobbyData getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.ai.LobbyPlayerAi;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.match.NetGuiGame;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
import forge.player.LobbyPlayerHuman;
|
||||
|
||||
public final class NetGame {
|
||||
|
||||
private final Map<RemoteClient, NetPlayer> clients = Maps.newHashMap();
|
||||
private final GameRules rules;
|
||||
private final HostedMatch match = new HostedMatch();
|
||||
public NetGame(final GameRules rules) {
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
public void addClient(final RemoteClient client) {
|
||||
clients.put(client, new NetPlayer(client, new NetGuiGame(client)));
|
||||
}
|
||||
|
||||
public void startMatch() {
|
||||
final List<RegisteredPlayer> registeredPlayers = Lists.newArrayListWithCapacity(clients.size());
|
||||
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
|
||||
for (final NetPlayer np : clients.values()) {
|
||||
if (np.player == null) {
|
||||
System.err.println("No deck registered for player " + np.client.getUsername());
|
||||
return;
|
||||
}
|
||||
registeredPlayers.add(np.player);
|
||||
guis.put(np.player, np.gui);
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
if (registeredPlayers.size() == 1) {
|
||||
RegisteredPlayer r = new RegisteredPlayer(new Deck());
|
||||
registeredPlayers.add(r);
|
||||
r.setPlayer(new LobbyPlayerAi("AI", new HashMap<String, String>()));
|
||||
}
|
||||
match.startMatch(rules, null, registeredPlayers, guis);
|
||||
}
|
||||
|
||||
public void registerDeck(final RemoteClient client, final Deck deck) {
|
||||
final RegisteredPlayer r = new RegisteredPlayer(deck);
|
||||
clients.get(client).player = r;
|
||||
r.setPlayer(new LobbyPlayerHuman(client.getUsername()));
|
||||
}
|
||||
|
||||
private static final class NetPlayer {
|
||||
private final RemoteClient client;
|
||||
private RegisteredPlayer player = null;
|
||||
private final IGuiGame gui;
|
||||
private NetPlayer(final RemoteClient client, final IGuiGame gui) {
|
||||
this.client = client;
|
||||
this.gui = gui;
|
||||
}
|
||||
}
|
||||
}
|
||||
129
forge-gui/src/main/java/forge/net/NetGameController.java
Normal file
129
forge-gui/src/main/java/forge/net/NetGameController.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.client.IToServer;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGameController implements IGameController {
|
||||
|
||||
private final IToServer server;
|
||||
public NetGameController(final IToServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
private String methodName() {
|
||||
boolean passedFirst = false;
|
||||
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
|
||||
if (ste.getClassName() == getClass().getName()) {
|
||||
if (passedFirst) {
|
||||
return ste.getMethodName();
|
||||
}
|
||||
passedFirst = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void send(final String method, final Object... args) {
|
||||
server.send(new GuiGameEvent(method, args));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T sendAndWait(final String method, final Object... args) {
|
||||
try {
|
||||
return (T) server.sendAndWait(new GuiGameEvent(method, args));
|
||||
} catch (final TimeoutException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useMana(final byte color) {
|
||||
return sendAndWait(methodName(), color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryUndoLastAction() {
|
||||
return sendAndWait(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||
send(methodName(), playerView, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
|
||||
return sendAndWait(methodName(), cardView, otherCardViewsToSelect, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOk() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
send(methodName(), sa);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
return sendAndWait(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriority() {
|
||||
return sendAndWait(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextGameDecision(final NextGameDecision decision) {
|
||||
send(methodName(), decision);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayLookAtAllCards() {
|
||||
// Don't do this over network
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getActivateDescription(final CardView card) {
|
||||
return sendAndWait(methodName(), card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void concede() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDevModeCheats cheat() {
|
||||
return IDevModeCheats.NO_CHEAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alphaStrike() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
}
|
||||
380
forge-gui/src/main/java/forge/net/NetGuiGame.java
Normal file
380
forge-gui/src/main/java/forge/net/NetGuiGame.java
Normal file
@@ -0,0 +1,380 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.AbstractGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.server.IToClient;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGuiGame extends AbstractGuiGame {
|
||||
|
||||
private final IToClient client;
|
||||
private final Map<MatchButtonType, Map<PlayerView, NetButton>> btns = new EnumMap<MatchButtonType, Map<PlayerView,NetButton>>(MatchButtonType.class);
|
||||
public NetGuiGame(final IToClient client) {
|
||||
this.client = client;
|
||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
||||
btns.put(type, Maps.<PlayerView, NetButton>newHashMap());
|
||||
}
|
||||
}
|
||||
|
||||
private String methodName() {
|
||||
boolean passedFirst = false;
|
||||
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
|
||||
if (ste.getClassName() == getClass().getName()) {
|
||||
if (passedFirst) {
|
||||
return ste.getMethodName();
|
||||
}
|
||||
passedFirst = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void send(final String method, final Object... args) {
|
||||
client.send(new GuiGameEvent(method, args));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T sendAndWait(final String method, final Object... args) {
|
||||
try {
|
||||
return (T) client.sendAndWait(new GuiGameEvent(method, args));
|
||||
} catch (final TimeoutException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateGameView() {
|
||||
send("setGameView", getGameView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameView(final GameView gameView) {
|
||||
super.setGameView(gameView);
|
||||
updateGameView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
||||
btns.get(type).clear();
|
||||
for (final PlayerView player : myPlayers) {
|
||||
btns.get(type).put(player, new NetButton(player, type));
|
||||
}
|
||||
}
|
||||
send(methodName(), myPlayers);
|
||||
updateGameView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterGameEnd() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCombat() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptMessage(final PlayerView playerView, final String message) {
|
||||
updateGameView();
|
||||
send(methodName(), playerView, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopAtPhase(final PlayerView playerTurn, final PhaseType phase) {
|
||||
return sendAndWait(methodName(), playerTurn, phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnOK(final PlayerView playerView) {
|
||||
return btns.get(MatchButtonType.OK).get(playerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnCancel(final PlayerView playerView) {
|
||||
return btns.get(MatchButtonType.CANCEL).get(playerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusButton(final MatchButtonType button) {
|
||||
send(methodName(), button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flashIncorrectAction() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePhase() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTurn(final PlayerView player) {
|
||||
updateGameView();
|
||||
send(methodName(), player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlayerControl() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableOverlay() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableOverlay() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishGame() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object showManaPool(final PlayerView player) {
|
||||
send(methodName(), player);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideManaPool(final PlayerView player, final Object zoneToRestore) {
|
||||
send(methodName(), player, zoneToRestore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStack() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateZones(final List<Pair<PlayerView, ZoneType>> zonesToUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), zonesToUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSingleCard(final CardView card) {
|
||||
updateGameView();
|
||||
send(methodName(), card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), manaPoolUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLives(final Iterable<PlayerView> livesUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), livesUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPanelSelection(final CardView hostCard) {
|
||||
updateGameView();
|
||||
send(methodName(), hostCard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbilityView getAbilityToPlay(final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||
return sendAndWait(methodName(), abilities, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CardView, Integer> assignDamage(final CardView attacker, final List<CardView> blockers, final int damage, final GameEntityView defender, final boolean overrideOrder) {
|
||||
return sendAndWait(methodName(), attacker, blockers, damage, defender, overrideOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(final String message, final String title) {
|
||||
send(methodName(), message, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(final String message, final String title) {
|
||||
send(methodName(), message, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(final String message, final String title, final String yesButtonText, final String noButtonText, final boolean defaultYes) {
|
||||
return sendAndWait(methodName(), message, title, yesButtonText, noButtonText, defaultYes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showOptionDialog(final String message, final String title, final FSkinProp icon, final String[] options, final int defaultOption) {
|
||||
return sendAndWait(methodName(), message, title, icon, options, defaultOption);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showCardOptionDialog(final CardView card, final String message, final String title, final FSkinProp icon, final String[] options, final int defaultOption) {
|
||||
return sendAndWait(methodName(), card, message, title, icon, options, defaultOption);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showInputDialog(final String message, final String title, final FSkinProp icon, final String initialInput, final String[] inputOptions) {
|
||||
return sendAndWait(methodName(), message, title, icon, initialInput, inputOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirm(final CardView c, final String question, final boolean defaultIsYes, final String[] options) {
|
||||
return sendAndWait(methodName(), c, question, defaultIsYes, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
return sendAndWait(methodName(), message, min, max, choices, selected, display);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax, final List<T> sourceChoices, final List<T> destChoices, final CardView referenceCard, final boolean sideboardingMode) {
|
||||
return sendAndWait(methodName(), title, top, remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices, referenceCard, sideboardingMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> sideboard(final CardPool sideboard, final CardPool main) {
|
||||
return sendAndWait(methodName(), sideboard, main);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameEntityView chooseSingleEntityForEffect(final String title, final Collection<? extends GameEntityView> optionList, final DelayedReveal delayedReveal, final boolean isOptional) {
|
||||
return sendAndWait(methodName(), title, optionList, delayedReveal, isOptional);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCard(final CardView card) {
|
||||
updateGameView();
|
||||
send(methodName(), card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean openZones(final Collection<ZoneType> zones, final Map<PlayerView, Object> players) {
|
||||
updateGameView();
|
||||
return sendAndWait(methodName(), zones, players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreOldZones(final Map<PlayerView, Object> playersToRestoreZonesFor) {
|
||||
send(methodName(), playersToRestoreZonesFor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiSetToSkipPhase(final PlayerView playerTurn, final PhaseType phase) {
|
||||
return sendAndWait(methodName(), playerTurn, phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentPlayer(final PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
private final class NetButton implements IButton {
|
||||
|
||||
private String methodName() {
|
||||
boolean passedFirst = false;
|
||||
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
|
||||
if (ste.getClassName() == getClass().getName()) {
|
||||
if (passedFirst) {
|
||||
return ste.getMethodName();
|
||||
}
|
||||
passedFirst = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final PlayerView playerView;
|
||||
private final MatchButtonType type;
|
||||
private NetButton(final PlayerView playerView, final MatchButtonType type) {
|
||||
this.playerView = playerView;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(final boolean b0) {
|
||||
send("btn_" + methodName(), playerView, type, b0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(final boolean b0) {
|
||||
send("btn_" + methodName(), playerView, type, b0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(final String text0) {
|
||||
send("btn_" + methodName(), playerView, type, text0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected() {
|
||||
return sendAndWait("btn_" + methodName(), playerView, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(final boolean b0) {
|
||||
send("btn_" + methodName(), playerView, type, b0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestFocusInWindow() {
|
||||
return sendAndWait("btn_" + methodName(), playerView, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCommand(final UiCommand command0) {
|
||||
send("btn_" + methodName(), playerView, type, command0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(final FSkinProp color) {
|
||||
send("btn_" + methodName(), playerView, type, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(final int r, final int g, final int b) {
|
||||
send("btn_" + methodName(), playerView, type, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
forge-gui/src/main/java/forge/net/ServerGameLobby.java
Normal file
65
forge-gui/src/main/java/forge/net/ServerGameLobby.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.GameLobby;
|
||||
import forge.match.LobbySlot;
|
||||
import forge.net.game.LobbySlotType;
|
||||
|
||||
public final class ServerGameLobby extends GameLobby {
|
||||
|
||||
public ServerGameLobby() {
|
||||
super(true);
|
||||
addSlot(new LobbySlot(LobbySlotType.LOCAL, localName(), localAvatarIndices()[0], 0, true, Collections.<AIOption>emptySet()));
|
||||
addSlot(new LobbySlot(LobbySlotType.OPEN, null, -1, 1, false, Collections.<AIOption>emptySet()));
|
||||
}
|
||||
|
||||
public int connectPlayer(final String name, final int avatarIndex) {
|
||||
final int nSlots = getNumberOfSlots();
|
||||
for (int index = 0; index < nSlots; index++) {
|
||||
final LobbySlot slot = getSlot(index);
|
||||
if (slot.getType() == LobbySlotType.OPEN) {
|
||||
connectPlayer(name, avatarIndex, slot);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private void connectPlayer(final String name, final int avatarIndex, final LobbySlot slot) {
|
||||
slot.setType(LobbySlotType.REMOTE);
|
||||
slot.setName(name);
|
||||
slot.setAvatarIndex(avatarIndex);
|
||||
updateView();
|
||||
}
|
||||
public void disconnectPlayer(final int index) {
|
||||
final LobbySlot slot = getSlot(index);
|
||||
slot.setType(LobbySlotType.OPEN);
|
||||
slot.setName(StringUtils.EMPTY);
|
||||
updateView();
|
||||
}
|
||||
|
||||
@Override public boolean hasControl() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayEdit(final int index) {
|
||||
final LobbySlotType type = getSlot(index).getType();
|
||||
return type != LobbySlotType.REMOTE && type != LobbySlotType.OPEN;
|
||||
}
|
||||
|
||||
@Override public boolean mayControl(final int index) {
|
||||
return getSlot(index).getType() != LobbySlotType.REMOTE;
|
||||
}
|
||||
|
||||
@Override public boolean mayRemove(final int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public IGuiGame getGui(final int index) {
|
||||
return FServerManager.getInstance().getGui(index);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package forge.player;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.ai.AiProfileUtil;
|
||||
@@ -13,8 +16,6 @@ import forge.util.GuiDisplayUtil;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public final class GamePlayerUtil {
|
||||
private GamePlayerUtil() { };
|
||||
|
||||
@@ -22,8 +23,8 @@ public final class GamePlayerUtil {
|
||||
public static final LobbyPlayer getGuiPlayer() {
|
||||
return guiPlayer;
|
||||
}
|
||||
public static final LobbyPlayer getGuiPlayer(String name, int index) {
|
||||
if (index == 0) {
|
||||
public static final LobbyPlayer getGuiPlayer(final String name, final boolean writePref) {
|
||||
if (writePref) {
|
||||
if (!name.equals(guiPlayer.getName())) {
|
||||
guiPlayer.setName(name);
|
||||
FModel.getPreferences().setPref(FPref.PLAYER_NAME, name);
|
||||
@@ -49,7 +50,7 @@ public final class GamePlayerUtil {
|
||||
public final static LobbyPlayer createAiPlayer(String name, int avatarIndex) {
|
||||
return createAiPlayer(name, avatarIndex, null);
|
||||
}
|
||||
public final static LobbyPlayer createAiPlayer(String name, int avatarIndex, Map<String, String> options) {
|
||||
public final static LobbyPlayer createAiPlayer(String name, int avatarIndex, Set<AIOption> options) {
|
||||
LobbyPlayerAi player = new LobbyPlayerAi(name, options);
|
||||
|
||||
// TODO: implement specific AI profiles for quest mode.
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
package forge.player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.game.client.IToServer;
|
||||
import forge.trackable.TrackableObject;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGameController implements IGameController {
|
||||
|
||||
private final IToServer server;
|
||||
public NetGameController(final IToServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
private void send(final String method) {
|
||||
send(method, Collections.<TrackableObject>emptySet());
|
||||
}
|
||||
private void send(final String method, final TrackableObject object) {
|
||||
send(method, Collections.singleton(object));
|
||||
}
|
||||
private void send(final String method, final Iterable<? extends TrackableObject> objects) {
|
||||
//server.send(new (method, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayLookAtAllCards() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void concede() {
|
||||
send("concede");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alphaStrike() {
|
||||
send("alphaStrike");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useMana(byte color) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOk() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriority() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectPlayer(PlayerView playerView, ITriggerEvent triggerEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectCard(CardView cardView,
|
||||
List<CardView> otherCardViewsToSelect, ITriggerEvent triggerEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(SpellAbility sa) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryUndoLastAction() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDevModeCheats cheat() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextGameDecision(NextGameDecision decision) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivateDescription(CardView card) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -74,6 +75,7 @@ import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.spellability.TargetChoices;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.WrappedAbility;
|
||||
@@ -217,8 +219,8 @@ public class PlayerControllerHuman
|
||||
* Uses GUI to learn which spell the player (human in our case) would like to play
|
||||
*/
|
||||
public SpellAbility getAbilityToPlay(final List<SpellAbility> abilities, final ITriggerEvent triggerEvent) {
|
||||
return getGui().getAbilityToPlay(abilities, triggerEvent);
|
||||
//return HostedMatch.getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
final SpellAbilityView resultView = getGui().getAbilityToPlay(SpellAbilityView.getCollection(abilities), triggerEvent);
|
||||
return getGame().getSpellAbility(resultView);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -389,13 +391,13 @@ public class PlayerControllerHuman
|
||||
// Human is supposed to read the message and understand from it what to choose
|
||||
if (optionList.isEmpty()) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!isOptional && optionList.size() == 1) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return Iterables.getFirst(optionList, null);
|
||||
}
|
||||
@@ -416,7 +418,7 @@ public class PlayerControllerHuman
|
||||
|
||||
if (canUseSelectCardsInput) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, isOptional ? 0 : 1, 1, optionList);
|
||||
input.setCancelAllowed(isOptional);
|
||||
@@ -425,8 +427,10 @@ public class PlayerControllerHuman
|
||||
return Iterables.getFirst(input.getSelected(), null);
|
||||
}
|
||||
|
||||
final GameEntityView result = getGui().chooseSingleEntityForEffect(title, optionList, delayedReveal, isOptional, this);
|
||||
endTempShowCards(); //assume tempShow called by GuiBase.getInterface().chooseSingleEntityForEffect
|
||||
tempShow(optionList);
|
||||
final GameEntityView result = getGui().chooseSingleEntityForEffect(title, GameEntityView.getEntityCollection(optionList), delayedReveal, isOptional);
|
||||
endTempShowCards();
|
||||
|
||||
if (result instanceof CardView) {
|
||||
return (T) game.getCard((CardView)result);
|
||||
}
|
||||
@@ -438,9 +442,9 @@ public class PlayerControllerHuman
|
||||
|
||||
@Override
|
||||
public int chooseNumber(SpellAbility sa, String title, int min, int max) {
|
||||
if (min >= max) {
|
||||
return min;
|
||||
}
|
||||
if (min >= max) {
|
||||
return min;
|
||||
}
|
||||
final Integer[] choices = new Integer[max + 1 - min];
|
||||
for (int i = 0; i <= max - min; i++) {
|
||||
choices[i] = Integer.valueOf(i + min);
|
||||
@@ -563,19 +567,22 @@ public class PlayerControllerHuman
|
||||
|
||||
@Override
|
||||
public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String message) {
|
||||
reveal(CardView.getCollection(cards), zone, PlayerView.get(owner), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal(Collection<CardView> cards, ZoneType zone, PlayerView owner, String message) {
|
||||
if (StringUtils.isBlank(message)) {
|
||||
message = "Looking at cards in {player's} " + zone.name().toLowerCase();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
message += "{player's} " + zone.name().toLowerCase();
|
||||
}
|
||||
String fm = MessageUtil.formatMessage(message, player, owner);
|
||||
if (!cards.isEmpty()) {
|
||||
tempShowCards(cards);
|
||||
getGui().reveal(fm, CardView.getCollection(cards));
|
||||
tempShowCards(game.getCardList(cards));
|
||||
getGui().reveal(fm, cards);
|
||||
endTempShowCards();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
getGui().message(MessageUtil.formatMessage("There are no cards in {player's} " +
|
||||
zone.name().toLowerCase(), player, owner), fm);
|
||||
}
|
||||
@@ -993,17 +1000,18 @@ public class PlayerControllerHuman
|
||||
return Iterables.getFirst(allTargets, null);
|
||||
}
|
||||
|
||||
final Function<Pair<SpellAbilityStackInstance, GameObject>, String> fnToString = new Function<Pair<SpellAbilityStackInstance, GameObject>, String>() {
|
||||
@Override
|
||||
public String apply(Pair<SpellAbilityStackInstance, GameObject> targ) {
|
||||
return targ.getRight().toString() + " - " + targ.getLeft().getStackDescription();
|
||||
}
|
||||
};
|
||||
|
||||
List<Pair<SpellAbilityStackInstance, GameObject>> chosen = getGui().getChoices(saSpellskite.getHostCard().getName(), 1, 1, allTargets, null, fnToString);
|
||||
final List<Pair<SpellAbilityStackInstance, GameObject>> chosen = getGui().getChoices(saSpellskite.getHostCard().getName(), 1, 1, allTargets, null, new FnTargetToString());
|
||||
return Iterables.getFirst(chosen, null);
|
||||
}
|
||||
|
||||
private final static class FnTargetToString implements Function<Pair<SpellAbilityStackInstance, GameObject>, String>, Serializable {
|
||||
private static final long serialVersionUID = -4779137632302777802L;
|
||||
|
||||
@Override public String apply(final Pair<SpellAbilityStackInstance, GameObject> targ) {
|
||||
return targ.getRight().toString() + " - " + targ.getLeft().getStackDescription();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyOfValue(SpellAbility sa, GameObject realtedTarget, String value) {
|
||||
String message = MessageUtil.formatNotificationMessage(sa, player, realtedTarget, value);
|
||||
@@ -1352,8 +1360,8 @@ public class PlayerControllerHuman
|
||||
return inputProxy.selectCard(cardView, otherCardViewsToSelect, triggerEvent);
|
||||
}
|
||||
|
||||
public void selectAbility(final SpellAbility sa) {
|
||||
inputProxy.selectAbility(sa);
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
inputProxy.selectAbility(getGame().getSpellAbility(sa));
|
||||
}
|
||||
|
||||
public void alphaStrike() {
|
||||
|
||||
41
forge-net/src/main/java/forge/net/ReplyPool.java
Normal file
41
forge-net/src/main/java/forge/net/ReplyPool.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class ReplyPool {
|
||||
|
||||
private final Map<Integer, CompletableFuture<Object>> pool = Maps.newHashMap();
|
||||
|
||||
public ReplyPool() {
|
||||
}
|
||||
|
||||
public void initialize(final int index) {
|
||||
synchronized (pool) {
|
||||
pool.put(Integer.valueOf(index), new CompletableFuture<Object>());
|
||||
}
|
||||
}
|
||||
|
||||
public void complete(final int index, final Object value) {
|
||||
synchronized (pool) {
|
||||
pool.get(Integer.valueOf(index)).complete(value);
|
||||
}
|
||||
}
|
||||
|
||||
public Object get(final int index) throws TimeoutException {
|
||||
final CompletableFuture<Object> future;
|
||||
synchronized (pool) {
|
||||
future = pool.get(Integer.valueOf(index));
|
||||
}
|
||||
try {
|
||||
return future.get(1, TimeUnit.MINUTES);
|
||||
} catch (final InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,40 @@
|
||||
package forge.net.game;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.net.game.server.RemoteClient;
|
||||
import forge.trackable.TrackableObject;
|
||||
|
||||
public final class GuiGameEvent implements NetEvent {
|
||||
public final class GuiGameEvent implements IdentifiableNetEvent {
|
||||
private static final long serialVersionUID = 6223690008522514574L;
|
||||
private static int staticId = 0;
|
||||
|
||||
private final int id;
|
||||
private final String method;
|
||||
private final Iterable<? extends TrackableObject> objects;
|
||||
private final Object[] objects;
|
||||
|
||||
public GuiGameEvent(final String method, final Iterable<? extends TrackableObject> objects) {
|
||||
public GuiGameEvent(final String method, final Object ... objects) {
|
||||
this.id = staticId++;
|
||||
this.method = method;
|
||||
this.objects = objects == null ? ImmutableSet.<TrackableObject>of() : objects;
|
||||
this.objects = objects == null ? new Object[0] : objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("GuiGameEvent %d: %s (%d args)", id, method, objects.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateForClient(final RemoteClient client) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public TrackableObject getObject() {
|
||||
return Iterables.getFirst(objects, null);
|
||||
}
|
||||
|
||||
public Iterable<? extends TrackableObject> getObjects() {
|
||||
public Object[] getObjects() {
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package forge.net.game;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public interface IRemote {
|
||||
void send(NetEvent event);
|
||||
Object sendAndWait(IdentifiableNetEvent event) throws TimeoutException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package forge.net.game;
|
||||
|
||||
import forge.game.IIdentifiable;
|
||||
|
||||
public interface IdentifiableNetEvent extends NetEvent, IIdentifiable {
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package forge.net.game;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class LobbyState implements Serializable {
|
||||
private static final long serialVersionUID = 3899410700896996173L;
|
||||
|
||||
private final List<LobbyPlayerData> players = Lists.newArrayList();
|
||||
private int localPlayer = -1;
|
||||
public int getLocalPlayer() {
|
||||
return localPlayer;
|
||||
}
|
||||
public void setLocalPlayer(final int localPlayer) {
|
||||
this.localPlayer = localPlayer;
|
||||
}
|
||||
|
||||
public void addPlayer(final LobbyPlayerData data) {
|
||||
players.add(data);
|
||||
}
|
||||
public List<LobbyPlayerData> getPlayers() {
|
||||
return Collections.unmodifiableList(players);
|
||||
}
|
||||
|
||||
public final static class LobbyPlayerData implements Serializable {
|
||||
private static final long serialVersionUID = 8642923786206592216L;
|
||||
|
||||
private final String name;
|
||||
private final int avatarIndex;
|
||||
private final LobbySlotType type;
|
||||
public LobbyPlayerData(final String name, final int avatarIndex, final LobbySlotType type) {
|
||||
this.name = name;
|
||||
this.avatarIndex = avatarIndex;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public int getAvatarIndex() {
|
||||
return avatarIndex;
|
||||
}
|
||||
public LobbySlotType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package forge.net.game;
|
||||
|
||||
import forge.net.game.server.RemoteClient;
|
||||
|
||||
public class LobbyUpdateEvent implements NetEvent {
|
||||
private static final long serialVersionUID = -3176971304173703949L;
|
||||
|
||||
private final LobbyState state;
|
||||
public LobbyUpdateEvent(final LobbyState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateForClient(final RemoteClient client) {
|
||||
state.setLocalPlayer(client.getIndex());
|
||||
}
|
||||
|
||||
public LobbyState getState() {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ public class LoginEvent implements NetEvent {
|
||||
private static final long serialVersionUID = -8865183377417377938L;
|
||||
|
||||
private final String username;
|
||||
public LoginEvent(final String username) {
|
||||
private final int avatarIndex;
|
||||
public LoginEvent(final String username, final int avatarIndex) {
|
||||
this.username = username;
|
||||
this.avatarIndex = avatarIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -17,4 +19,8 @@ public class LoginEvent implements NetEvent {
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public int getAvatarIndex() {
|
||||
return avatarIndex;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user