mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Commit large scale CardView refactoring to support head-to-head better, handle hidden and face down cards better, and reduce flickering of P/T and other attributes
This commit is contained in:
@@ -53,7 +53,7 @@ public class CardDetailUtil {
|
||||
if (card == null) {
|
||||
return getBorderColors(null, false, false, false).iterator().next();
|
||||
}
|
||||
return getBorderColors(card.getColors(), card.isLand(), card.getCard().isUiDisplayable(), false).iterator().next();
|
||||
return getBorderColors(card.getColors(), card.isLand(), card.getCard().mayBeShown(), false).iterator().next();
|
||||
}
|
||||
public static DetailColors getBorderColor(final ColorSet cardColors, final boolean isLand, boolean canShow) {
|
||||
return getBorderColors(cardColors, isLand, canShow, false).get(0);
|
||||
@@ -62,7 +62,7 @@ public class CardDetailUtil {
|
||||
if (card == null) {
|
||||
return getBorderColors(null, false, false, true);
|
||||
}
|
||||
return getBorderColors(card.getColors(), card.isLand(), card.getCard().isUiDisplayable(), true);
|
||||
return getBorderColors(card.getColors(), card.isLand(), card.getCard().mayBeShown(), true);
|
||||
}
|
||||
private static List<DetailColors> getBorderColors(final ColorSet cardColors, final boolean isLand, boolean canShow, boolean supportMultiple) {
|
||||
List<DetailColors> borderColors = new ArrayList<DetailColors>();
|
||||
|
||||
@@ -32,6 +32,7 @@ import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.event.GameEventCombatEnded;
|
||||
import forge.game.event.GameEventGameFinished;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEventGameStarted;
|
||||
import forge.game.event.GameEventManaPool;
|
||||
import forge.game.event.GameEventPlayerControl;
|
||||
import forge.game.event.GameEventPlayerLivesChanged;
|
||||
@@ -74,9 +75,16 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
@Subscribe
|
||||
public void receiveGameEvent(final GameEvent ev) {
|
||||
gameView.updateViews();
|
||||
ev.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventGameStarted event) {
|
||||
gameView.endUpdateDelay(); //allow views to update once game starts
|
||||
return null;
|
||||
}
|
||||
|
||||
private final AtomicBoolean phaseUpdPlanned = new AtomicBoolean(false);
|
||||
@Override
|
||||
public Void visit(final GameEventTurnPhase ev) {
|
||||
@@ -142,7 +150,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
final List<CardView> options = Lists.newArrayList();
|
||||
for (final Entry<Player, Card> kv : ev.cards.entries()) {
|
||||
final CardView fakeCard = new CardView(true); //use fake card so real cards appear with proper formatting
|
||||
final CardView fakeCard = new CardView(-1); //use fake card so real cards appear with proper formatting
|
||||
fakeCard.getOriginal().setName(" -- From " + Lang.getPossesive(kv.getKey().getName()) + " deck --");
|
||||
options.add(fakeCard);
|
||||
options.add(gameView.getCardView(kv.getValue()));
|
||||
@@ -294,8 +302,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (cardsToUpdate) {
|
||||
final Iterable<CardView> newCardsToUpdate = gameView.getRefreshedCardViews(cardsToUpdate);
|
||||
MatchUtil.updateCards(newCardsToUpdate);
|
||||
MatchUtil.updateCards(cardsToUpdate);
|
||||
cardsToUpdate.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.input.InputPlaybackControl;
|
||||
import forge.match.input.InputQueue;
|
||||
import forge.match.input.InputSynchronized;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.player.LobbyPlayerHuman;
|
||||
@@ -71,6 +70,7 @@ import forge.view.WatchLocalGame;
|
||||
public class MatchUtil {
|
||||
private static IMatchController controller;
|
||||
private static Game game;
|
||||
private static Player currentPlayer;
|
||||
private static final List<LocalGameView> gameViews = new ArrayList<LocalGameView>();
|
||||
|
||||
/** Cache of players. */
|
||||
@@ -180,6 +180,10 @@ public class MatchUtil {
|
||||
if (p.getController() instanceof PlayerControllerHuman) {
|
||||
final PlayerControllerHuman controller = (PlayerControllerHuman) p.getController();
|
||||
LocalGameView gameView = controller.getGameView();
|
||||
if (humanCount == 0) {
|
||||
currentPlayer = p;
|
||||
gameView.startUpdateDelay(); //delay updating views until game finishes initializing
|
||||
}
|
||||
game.subscribeToEvents(new FControlGameEventHandler(gameView, humanCount == 0));
|
||||
gameViews.add(gameView);
|
||||
humanCount++;
|
||||
@@ -188,7 +192,9 @@ public class MatchUtil {
|
||||
|
||||
if (humanCount == 0) { //watch game but do not participate
|
||||
LocalGameView gameView = new WatchLocalGame(GuiBase.getInterface(), game);
|
||||
gameView.setLocalPlayer(sortedPlayers.get(0));
|
||||
currentPlayer = sortedPlayers.get(0);
|
||||
gameView.setLocalPlayer(currentPlayer);
|
||||
gameView.startUpdateDelay();
|
||||
game.subscribeToEvents(new FControlGameEventHandler(gameView, true));
|
||||
gameViews.add(gameView);
|
||||
}
|
||||
@@ -235,7 +241,7 @@ public class MatchUtil {
|
||||
}
|
||||
|
||||
public static LocalGameView getGameView() {
|
||||
return getGameView(getCurrentPlayer());
|
||||
return getGameView(currentPlayer);
|
||||
}
|
||||
public static LocalGameView getGameView(Player player) {
|
||||
switch (gameViews.size()) {
|
||||
@@ -244,10 +250,7 @@ public class MatchUtil {
|
||||
case 0:
|
||||
return null;
|
||||
default:
|
||||
if (player != null && player.getController() instanceof PlayerControllerHuman) {
|
||||
return ((PlayerControllerHuman)player.getController()).getGameView();
|
||||
}
|
||||
return gameViews.get(0);
|
||||
return gameViews.get(player.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,23 +283,14 @@ public class MatchUtil {
|
||||
}
|
||||
|
||||
public static Player getCurrentPlayer() {
|
||||
if (game == null) { return null; }
|
||||
|
||||
LobbyPlayer lobbyPlayer = getGuiPlayer();
|
||||
return currentPlayer;
|
||||
}
|
||||
public static void setCurrentPlayer(Player currentPlayer0) {
|
||||
if (currentPlayer == currentPlayer0) { return; }
|
||||
currentPlayer = currentPlayer0;
|
||||
if (gameViews.size() > 1) {
|
||||
//account for if second human player is currently being prompted
|
||||
InputSynchronized activeInput = InputQueue.getActiveInput();
|
||||
if (activeInput != null) {
|
||||
lobbyPlayer = activeInput.getOwner().getLobbyPlayer();
|
||||
}
|
||||
gameViews.get(currentPlayer.getId()).updateViews(); //ensure views updated when current player changes to account for changes in card visibility
|
||||
}
|
||||
|
||||
for (Player p : game.getPlayers()) {
|
||||
if (p.getLobbyPlayer() == lobbyPlayer) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void alphaStrike() {
|
||||
@@ -368,7 +362,7 @@ public class MatchUtil {
|
||||
}
|
||||
|
||||
Player priorityPlayer = game.getPhaseHandler().getPriorityPlayer();
|
||||
boolean humanHasPriority = priorityPlayer == null || priorityPlayer.getLobbyPlayer() == getGuiPlayer();
|
||||
boolean humanHasPriority = priorityPlayer == null || priorityPlayer.getLobbyPlayer() instanceof LobbyPlayerHuman;
|
||||
|
||||
if (humanCount > 0 && humanHasPriority) {
|
||||
game.getAction().checkGameOverCondition();
|
||||
@@ -388,6 +382,7 @@ public class MatchUtil {
|
||||
if (game == null) { return; }
|
||||
|
||||
game = null;
|
||||
currentPlayer = null;
|
||||
gameViews.clear();
|
||||
players.clear();
|
||||
cards.clear();
|
||||
|
||||
@@ -22,6 +22,9 @@ import java.util.Observer;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.interfaces.IGuiBase;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.view.CardView;
|
||||
@@ -97,34 +100,23 @@ public class InputProxy implements Observer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* selectPlayer.
|
||||
* </p>
|
||||
*
|
||||
* @param player
|
||||
* a {@link forge.game.player.Player} object.
|
||||
*/
|
||||
public final void selectPlayer(final PlayerView player, final ITriggerEvent triggerEvent) {
|
||||
public final void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||
final Input inp = getInput();
|
||||
if (inp != null) {
|
||||
inp.selectPlayer(gameView.getPlayer(player), triggerEvent);
|
||||
final Player player = gameView.getPlayer(playerView);
|
||||
if (player != null) {
|
||||
inp.selectPlayer(player, triggerEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* selectCard.
|
||||
* </p>
|
||||
*
|
||||
* @param cardView
|
||||
* a {@link forge.game.card.Card} object.
|
||||
* @param triggerEvent
|
||||
*/
|
||||
public final boolean selectCard(final CardView cardView, final ITriggerEvent triggerEvent) {
|
||||
final Input inp = getInput();
|
||||
if (inp != null) {
|
||||
return inp.selectCard(gameView.getCard(cardView), triggerEvent);
|
||||
final Card card = gameView.getCard(cardView);
|
||||
if (card != null) {
|
||||
return inp.selectCard(card, triggerEvent);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -132,7 +124,10 @@ public class InputProxy implements Observer {
|
||||
public final void selectAbility(final SpellAbilityView ab) {
|
||||
final Input inp = getInput();
|
||||
if (inp != null) {
|
||||
inp.selectAbility(gameView.getSpellAbility(ab));
|
||||
final SpellAbility sa = gameView.getSpellAbility(ab);
|
||||
if (sa != null) {
|
||||
inp.selectAbility(sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.view.IGameView;
|
||||
|
||||
/**
|
||||
@@ -33,12 +34,6 @@ import forge.view.IGameView;
|
||||
* @version $Id: InputQueue.java 24769 2014-02-09 13:56:04Z Hellfish $
|
||||
*/
|
||||
public class InputQueue extends Observable {
|
||||
private static InputSynchronized activeInput;
|
||||
|
||||
public static InputSynchronized getActiveInput() {
|
||||
return activeInput;
|
||||
}
|
||||
|
||||
private final BlockingDeque<InputSynchronized> inputStack = new LinkedBlockingDeque<InputSynchronized>();
|
||||
private final InputLockUI inputLock;
|
||||
|
||||
@@ -62,9 +57,6 @@ public class InputQueue extends Observable {
|
||||
if (topMostInput != inp) {
|
||||
throw new RuntimeException("Cannot remove input " + inp.getClass().getSimpleName() + " because it's not on top of stack. Stack = " + inputStack );
|
||||
}
|
||||
if (inp == activeInput) {
|
||||
activeInput = null;
|
||||
}
|
||||
updateObservers();
|
||||
}
|
||||
|
||||
@@ -89,7 +81,9 @@ public class InputQueue extends Observable {
|
||||
}
|
||||
|
||||
public void setInput(final InputSynchronized input) {
|
||||
activeInput = input;
|
||||
if (MatchUtil.getHumanCount() > 1) { //update current player if needed
|
||||
MatchUtil.setCurrentPlayer(MatchUtil.players.getKey(input.getOwner().getId()));
|
||||
}
|
||||
inputStack.push(input);
|
||||
inputLock.setGui(input.getGui());
|
||||
InputBase.waitForOtherPlayer();
|
||||
|
||||
@@ -11,11 +11,10 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.Range;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
@@ -29,8 +28,6 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.achievement.AchievementCollection;
|
||||
@@ -124,7 +121,6 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
* Cards this player may look at right now, for example when searching a
|
||||
* library.
|
||||
*/
|
||||
private final Set<Card> mayLookAt = Sets.newHashSet();
|
||||
private boolean mayLookAtAllCards = false;
|
||||
|
||||
public PlayerControllerHuman(Game game0, Player p, LobbyPlayer lp, IGuiBase gui) {
|
||||
@@ -163,6 +159,30 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
return mayLookAtAllCards;
|
||||
}
|
||||
|
||||
private final HashSet<Card> tempShownCards = new HashSet<Card>();
|
||||
private void tempShowCard(Card c) {
|
||||
CardView cv = MatchUtil.cards.get(c.getId());
|
||||
if (!cv.mayBeShown()) {
|
||||
cv.setMayBeShown(true);
|
||||
tempShownCards.add(c);
|
||||
}
|
||||
}
|
||||
private void tempShowCards(Iterable<Card> cards) {
|
||||
if (mayLookAtAllCards) { return; } //no needed if this is set
|
||||
|
||||
for (Card c : cards) {
|
||||
tempShowCard(c);
|
||||
}
|
||||
}
|
||||
private void endTempShowCards() {
|
||||
if (tempShownCards.isEmpty()) { return; }
|
||||
|
||||
for (Card c : tempShownCards) {
|
||||
MatchUtil.cards.get(c.getId()).setMayBeShown(false);
|
||||
}
|
||||
tempShownCards.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to {@code true} to enable this player to see all cards any other
|
||||
* player can see.
|
||||
@@ -355,9 +375,9 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
return Lists.newArrayList(sc.getSelected());
|
||||
}
|
||||
|
||||
this.mayLookAt.addAll(sourceList);
|
||||
tempShowCards(sourceList);
|
||||
final List<CardView> choices = SGuiChoose.many(getGui(), title, "Chosen Cards", min, max, gameView.getCardViews(sourceList), gameView.getCardView(sa.getHostCard()));
|
||||
this.mayLookAt.removeAll(sourceList);
|
||||
endTempShowCards();
|
||||
|
||||
return getCards(choices);
|
||||
}
|
||||
@@ -398,11 +418,11 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
for (final T t : options) {
|
||||
if (t instanceof Card) {
|
||||
// assume you may see any card passed through here
|
||||
mayLookAt.add((Card) t);
|
||||
tempShowCard((Card) t);
|
||||
}
|
||||
}
|
||||
final GameEntityView result = isOptional ? SGuiChoose.oneOrNone(getGui(), title, gameView.getGameEntityViews((Iterable<GameEntity>) options)) : SGuiChoose.one(getGui(), title, gameView.getGameEntityViews((Iterable<GameEntity>) options));
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
return (T) gameView.getGameEntity(result);
|
||||
}
|
||||
|
||||
@@ -540,9 +560,9 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
String fm = formatMessage(message, owner);
|
||||
if (!cards.isEmpty()) {
|
||||
mayLookAt.addAll(cards);
|
||||
tempShowCards(cards);
|
||||
SGuiChoose.reveal(getGui(), fm, gameView.getCardViews(cards));
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
}
|
||||
else {
|
||||
SGuiDialog.message(getGui(), formatMessage("There are no cards in {player's} " +
|
||||
@@ -555,7 +575,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
List<Card> toBottom = null;
|
||||
List<Card> toTop = null;
|
||||
|
||||
mayLookAt.addAll(topN);
|
||||
tempShowCards(topN);
|
||||
if (topN.size() == 1) {
|
||||
if (willPutCardOnTop(topN.get(0))) {
|
||||
toTop = topN;
|
||||
@@ -579,7 +599,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
toTop = gameView.getCards(toTopViews);
|
||||
}
|
||||
}
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
return ImmutablePair.of(toTop, toBottom);
|
||||
}
|
||||
|
||||
@@ -594,7 +614,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
@Override
|
||||
public List<Card> orderMoveToZoneList(List<Card> cards, ZoneType destinationZone) {
|
||||
List<CardView> choices;
|
||||
mayLookAt.addAll(cards);
|
||||
tempShowCards(cards);
|
||||
switch (destinationZone) {
|
||||
case Library:
|
||||
choices = SGuiChoose.order(getGui(), "Choose order of cards to put into the library", "Closest to top", getCardViews(cards), null);
|
||||
@@ -616,20 +636,20 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
break;
|
||||
default:
|
||||
System.out.println("ZoneType " + destinationZone + " - Not Ordered");
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
return cards;
|
||||
}
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
return getCards(choices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> valid, int min, int max) {
|
||||
if (p != player) {
|
||||
mayLookAt.addAll(valid);
|
||||
tempShowCards(valid);
|
||||
final List<CardView> choices = SGuiChoose.many(getGui(), "Choose " + min + " card" + (min != 1 ? "s" : "") + " to discard",
|
||||
"Discarded", min, min, gameView.getCardViews(valid), null);
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
return getCards(choices);
|
||||
}
|
||||
|
||||
@@ -1245,28 +1265,17 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
return SGuiDialog.confirm(getGui(), gameView.getCardView(sa.getHostCard()), "Choose a Pile", possibleValues);
|
||||
}
|
||||
|
||||
mayLookAt.addAll(pile1);
|
||||
mayLookAt.addAll(pile2);
|
||||
tempShowCards(pile1);
|
||||
tempShowCards(pile2);
|
||||
|
||||
final int idPile1 = Integer.MIN_VALUE, idPile2 = Integer.MIN_VALUE + 1;
|
||||
final List<CardView> cards = Lists.newArrayListWithCapacity(pile1.size() + pile2.size() + 2);
|
||||
final CardView pileView1 = new CardView(true) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "--- Pile 1 ---";
|
||||
}
|
||||
};
|
||||
pileView1.setId(idPile1);
|
||||
final CardView pileView1 = new CardView(Integer.MIN_VALUE);
|
||||
pileView1.getOriginal().setName("--- Pile 1 ---");
|
||||
cards.add(pileView1);
|
||||
cards.addAll(getCardViews(pile1));
|
||||
|
||||
final CardView pileView2 = new CardView(true) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "--- Pile 2 ---";
|
||||
}
|
||||
};
|
||||
pileView2.setId(idPile2);
|
||||
final CardView pileView2 = new CardView(Integer.MIN_VALUE + 1);
|
||||
pileView2.getOriginal().setName("--- Pile 2 ---");
|
||||
cards.add(pileView2);
|
||||
cards.addAll(getCardViews(pile2));
|
||||
|
||||
@@ -1277,13 +1286,14 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if (chosen.equals(pileView1)) {
|
||||
result = true;
|
||||
break;
|
||||
} else if (chosen.equals(pileView2)) {
|
||||
}
|
||||
if (chosen.equals(pileView2)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mayLookAt.clear();
|
||||
endTempShowCards();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1359,7 +1369,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
|
||||
@Override
|
||||
public boolean canUndoLastAction() {
|
||||
if (!game.stack.canUndo()) {
|
||||
if (!game.stack.canUndo(player)) {
|
||||
return false;
|
||||
}
|
||||
final Player priorityPlayer = game.getPhaseHandler().getPriorityPlayer();
|
||||
@@ -1467,15 +1477,15 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
*/
|
||||
@Override
|
||||
public boolean mayShowCard(final Card c) {
|
||||
if (mayLookAtAllCards()) {
|
||||
if (mayLookAtAllCards) {
|
||||
return true;
|
||||
}
|
||||
return c == null || mayLookAt.contains(c) || c.canBeShownTo(player);
|
||||
return c == null || tempShownCards.contains(c) || c.canBeShownTo(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayShowCardFace(final Card c) {
|
||||
if (mayLookAtAllCards()) {
|
||||
if (mayLookAtAllCards) {
|
||||
return true;
|
||||
}
|
||||
return c == null || !c.isFaceDown() || c.canCardFaceBeShownTo(player);
|
||||
|
||||
@@ -146,6 +146,14 @@ public class Cache<K extends IIdentifiable, V extends IIdentifiable> {
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<K> getKeys() {
|
||||
return inverseCache.values();
|
||||
}
|
||||
|
||||
public Iterable<V> getValues() {
|
||||
return cache.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all the mappings in this Cache, except for any key that exists in
|
||||
* the argument.
|
||||
|
||||
@@ -30,18 +30,14 @@ import forge.game.zone.ZoneType;
|
||||
* @author elcnesh
|
||||
*/
|
||||
public class CardView extends GameEntityView {
|
||||
|
||||
public static final CardView EMPTY = new CardView(true);
|
||||
|
||||
private final CardStateView
|
||||
original = new CardStateView(),
|
||||
alternate = new CardStateView();
|
||||
|
||||
private boolean hasAltState;
|
||||
|
||||
private int id;
|
||||
/** Will be false for {@link forge.game.ability.effects.DetachedCardEffect}. */
|
||||
private final boolean isUiDisplayable;
|
||||
private final int id;
|
||||
private boolean mayBeShown;
|
||||
private PlayerView owner, controller;
|
||||
private ZoneType zone;
|
||||
private boolean isCloned, isFaceDown, isFlipCard, isFlipped, isSplitCard, isTransformed;
|
||||
@@ -68,14 +64,14 @@ public class CardView extends GameEntityView {
|
||||
private Iterable<CardView> mustBlock;
|
||||
private CardView pairedWith;
|
||||
|
||||
public CardView(final boolean isUiDisplayable) {
|
||||
this.isUiDisplayable = isUiDisplayable;
|
||||
public CardView(int id0) {
|
||||
this.id = id0;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
final Iterable<CardView> emptyIterable = ImmutableSet.of();
|
||||
this.id = 0;
|
||||
this.mayBeShown = false;
|
||||
this.hasAltState = false;
|
||||
this.owner = null;
|
||||
this.controller = null;
|
||||
@@ -120,12 +116,11 @@ public class CardView extends GameEntityView {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final int id) {
|
||||
this.id = id;
|
||||
public boolean mayBeShown() {
|
||||
return this.mayBeShown;
|
||||
}
|
||||
|
||||
public boolean isUiDisplayable() {
|
||||
return isUiDisplayable;
|
||||
public void setMayBeShown(boolean b0) {
|
||||
this.mayBeShown = b0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -726,12 +721,19 @@ public class CardView extends GameEntityView {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.getId() <= 0) { //if fake card, just return name
|
||||
return this.getOriginal().getName();
|
||||
}
|
||||
|
||||
if (!mayBeShown) {
|
||||
return "(Unknown card)";
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(this.getOriginal().getName())) {
|
||||
if (this.getId() <= 0) {
|
||||
return "(Unknown card)";
|
||||
} else if (this.hasAltState()) {
|
||||
if (this.hasAltState()) {
|
||||
return "Face-down card (" + this.getAlternate().getName() + ")";
|
||||
}
|
||||
return "(" + this.getId() + ")";
|
||||
}
|
||||
|
||||
return this.getOriginal().getName() + " (" + this.getId() + ")";
|
||||
@@ -765,7 +767,7 @@ public class CardView extends GameEntityView {
|
||||
public void reset() {
|
||||
this.name = "";
|
||||
this.colors = ColorSet.getNullColor();
|
||||
this.imageKey = ImageKeys.TOKEN_PREFIX + ImageKeys.MORPH_IMAGE;
|
||||
this.imageKey = ImageKeys.HIDDEN_CARD;
|
||||
this.type = Collections.emptyList();
|
||||
this.manaCost = ManaCost.NO_COST;
|
||||
this.power = 0;
|
||||
@@ -822,7 +824,7 @@ public class CardView extends GameEntityView {
|
||||
* @return the imageKey
|
||||
*/
|
||||
public String getImageKey() {
|
||||
return imageKey;
|
||||
return mayBeShown ? imageKey : ImageKeys.HIDDEN_CARD;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ public abstract class LocalGameView implements IGameView {
|
||||
protected final InputQueue inputQueue;
|
||||
protected final InputProxy inputProxy;
|
||||
private PlayerView localPlayerView;
|
||||
private int updateDelays;
|
||||
|
||||
public LocalGameView(IGuiBase gui0, Game game0) {
|
||||
game = game0;
|
||||
@@ -349,30 +350,6 @@ public abstract class LocalGameView implements IGameView {
|
||||
return ViewUtil.transformIfNotNull(players, FN_GET_PLAYER_VIEW);
|
||||
}
|
||||
|
||||
public PlayerView getPlayerView(final Player p) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PlayerView view = MatchUtil.players.get(p.getId());
|
||||
if (view != null) {
|
||||
getPlayerView(p, view);
|
||||
}
|
||||
else {
|
||||
view = new PlayerView(p.getLobbyPlayer(), p.getId());
|
||||
MatchUtil.players.put(p, view);
|
||||
getPlayerView(p, view);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
private PlayerView getPlayerViewFast(final Player p) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
return MatchUtil.players.get(p.getId());
|
||||
}
|
||||
|
||||
public Player getPlayer(final PlayerView p) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
@@ -380,7 +357,23 @@ public abstract class LocalGameView implements IGameView {
|
||||
return MatchUtil.players.getKey(p.getId());
|
||||
}
|
||||
|
||||
private void getPlayerView(final Player p, final PlayerView view) {
|
||||
public PlayerView getPlayerView(final Player p) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PlayerView view = MatchUtil.players.get(p.getId());
|
||||
if (view == null) {
|
||||
view = new PlayerView(p.getLobbyPlayer(), p.getId());
|
||||
if (updateDelays == 0) {
|
||||
writePlayerToView(p, view);
|
||||
}
|
||||
MatchUtil.players.put(p, view);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
private void writePlayerToView(final Player p, final PlayerView view) {
|
||||
view.setCommanderInfo(CardFactoryUtil.getCommanderInfo(p).trim().replace("\r\n", "; "));
|
||||
view.setKeywords(p.getKeywords());
|
||||
view.setLife(p.getLife());
|
||||
@@ -408,46 +401,41 @@ public abstract class LocalGameView implements IGameView {
|
||||
}
|
||||
|
||||
public CardView getCardView(final Card c) {
|
||||
if (c == null) {
|
||||
if (c == null || c != c.getCardForUi()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Card cUi = c.getCardForUi();
|
||||
final boolean isDisplayable = cUi == c;
|
||||
final boolean mayShow = mayShowCard(c);
|
||||
|
||||
CardView view = MatchUtil.cards.get(c.getId());
|
||||
final boolean isNewView;
|
||||
if (view != null) {
|
||||
// Update to ensure the Card reference in the cache
|
||||
// is not an outdated Card.
|
||||
if (view.getId() > 0) {
|
||||
MatchUtil.cards.updateKey(view.getId(), c);
|
||||
if (view == null) {
|
||||
view = new CardView(c.getId());
|
||||
if (updateDelays == 0) {
|
||||
writeCardToView(c, view, MatchUtil.getGameView());
|
||||
}
|
||||
isNewView = false;
|
||||
} else if (isDisplayable && mayShow) {
|
||||
view = new CardView(isDisplayable);
|
||||
view.setId(c.getId());
|
||||
MatchUtil.cards.put(c, view);
|
||||
isNewView = true;
|
||||
} else {
|
||||
return CardView.EMPTY;
|
||||
}
|
||||
|
||||
if (mayShow) {
|
||||
writeCardToView(cUi, view);
|
||||
}
|
||||
else if (isDisplayable) {
|
||||
if (!isNewView) {
|
||||
view.reset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public void startUpdateDelay() {
|
||||
updateDelays++;
|
||||
}
|
||||
public void endUpdateDelay() {
|
||||
if (updateDelays > 0 && --updateDelays == 0) {
|
||||
updateViews();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateViews() {
|
||||
if (updateDelays > 0) { return; }
|
||||
|
||||
for (Player p : MatchUtil.players.getKeys()) {
|
||||
writePlayerToView(p, getPlayerView(p));
|
||||
}
|
||||
LocalGameView gameView = MatchUtil.getGameView();
|
||||
for (Card c : MatchUtil.cards.getKeys()) {
|
||||
writeCardToView(c, getCardView(c), gameView);
|
||||
}
|
||||
}
|
||||
|
||||
private final Function<Card, CardView> FN_GET_CARD_VIEW = new Function<Card, CardView>() {
|
||||
@Override
|
||||
@@ -460,41 +448,6 @@ public abstract class LocalGameView implements IGameView {
|
||||
return ViewUtil.transformIfNotNull(cards, FN_GET_CARD_VIEW);
|
||||
}
|
||||
|
||||
public final List<CardView> getRefreshedCardViews(final Iterable<CardView> cardViews) {
|
||||
return ViewUtil.transformIfNotNull(cardViews, new Function<CardView, CardView>() {
|
||||
@Override
|
||||
public CardView apply(final CardView input) {
|
||||
return MatchUtil.cards.getCurrentValue(input);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CardView getCardViewFast(final Card c) {
|
||||
if (c == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CardView view = MatchUtil.cards.get(c.getId());
|
||||
if (mayShowCard(c)) {
|
||||
return view;
|
||||
} else if (view.isUiDisplayable()) {
|
||||
return CardView.EMPTY;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private final Function<Card, CardView> FN_GET_CARDVIEW_FAST = new Function<Card, CardView>() {
|
||||
@Override
|
||||
public CardView apply(Card input) {
|
||||
return getCardViewFast(input);
|
||||
}
|
||||
};
|
||||
|
||||
private List<CardView> getCardViewsFast(final Iterable<Card> cards) {
|
||||
return ViewUtil.transformIfNotNull(cards, FN_GET_CARDVIEW_FAST);
|
||||
}
|
||||
|
||||
public Card getCard(final CardView c) {
|
||||
if (c == null) {
|
||||
return null;
|
||||
@@ -513,29 +466,29 @@ public abstract class LocalGameView implements IGameView {
|
||||
return ViewUtil.transformIfNotNull(cards, FN_GET_CARD);
|
||||
}
|
||||
|
||||
private void writeCardToView(final Card c, final CardView view) {
|
||||
private void writeCardToView(final Card c, final CardView view, final LocalGameView gameView) {
|
||||
// First, write the values independent of other views.
|
||||
ViewUtil.writeNonDependentCardViewProperties(c, view, mayShowCardFace(c));
|
||||
ViewUtil.writeNonDependentCardViewProperties(c, view, gameView.mayShowCard(c), gameView.mayShowCardFace(c));
|
||||
// Next, write the values that depend on other views.
|
||||
final Combat combat = game.getCombat();
|
||||
view.setOwner(getPlayerViewFast(c.getOwner()));
|
||||
view.setController(getPlayerViewFast(c.getController()));
|
||||
view.setOwner(getPlayerView(c.getOwner()));
|
||||
view.setController(getPlayerView(c.getController()));
|
||||
view.setAttacking(combat != null && combat.isAttacking(c));
|
||||
view.setBlocking(combat != null && combat.isBlocking(c));
|
||||
view.setChosenPlayer(getPlayerViewFast(c.getChosenPlayer()));
|
||||
view.setEquipping(getCardViewFast(Iterables.getFirst(c.getEquipping(), null)));
|
||||
view.setEquippedBy(getCardViewsFast(c.getEquippedBy()));
|
||||
view.setEnchantingCard(getCardViewFast(c.getEnchantingCard()));
|
||||
view.setEnchantingPlayer(getPlayerViewFast(c.getEnchantingPlayer()));
|
||||
view.setEnchantedBy(getCardViewsFast(c.getEnchantedBy()));
|
||||
view.setFortifiedBy(getCardViewsFast(c.getFortifiedBy()));
|
||||
view.setGainControlTargets(getCardViewsFast(c.getGainControlTargets()));
|
||||
view.setCloneOrigin(getCardViewFast(c.getCloneOrigin()));
|
||||
view.setImprinted(getCardViewsFast(c.getImprinted()));
|
||||
view.setHauntedBy(getCardViewsFast(c.getHauntedBy()));
|
||||
view.setHaunting(getCardViewFast(c.getHaunting()));
|
||||
view.setMustBlock(c.getMustBlockCards() == null ? Collections.<CardView>emptySet() : getCardViewsFast(c.getMustBlockCards()));
|
||||
view.setPairedWith(getCardViewFast(c.getPairedWith()));
|
||||
view.setChosenPlayer(getPlayerView(c.getChosenPlayer()));
|
||||
view.setEquipping(getCardView(Iterables.getFirst(c.getEquipping(), null)));
|
||||
view.setEquippedBy(getCardViews(c.getEquippedBy()));
|
||||
view.setEnchantingCard(getCardView(c.getEnchantingCard()));
|
||||
view.setEnchantingPlayer(getPlayerView(c.getEnchantingPlayer()));
|
||||
view.setEnchantedBy(getCardViews(c.getEnchantedBy()));
|
||||
view.setFortifiedBy(getCardViews(c.getFortifiedBy()));
|
||||
view.setGainControlTargets(getCardViews(c.getGainControlTargets()));
|
||||
view.setCloneOrigin(getCardView(c.getCloneOrigin()));
|
||||
view.setImprinted(getCardViews(c.getImprinted()));
|
||||
view.setHauntedBy(getCardViews(c.getHauntedBy()));
|
||||
view.setHaunting(getCardView(c.getHaunting()));
|
||||
view.setMustBlock(c.getMustBlockCards() == null ? Collections.<CardView>emptySet() : getCardViews(c.getMustBlockCards()));
|
||||
view.setPairedWith(getCardView(c.getPairedWith()));
|
||||
}
|
||||
|
||||
public SpellAbilityView getSpellAbilityView(final SpellAbility sa) {
|
||||
|
||||
@@ -33,9 +33,9 @@ public final class ViewUtil {
|
||||
* @param view
|
||||
* the {@link CardView} to write to.
|
||||
*/
|
||||
public static void writeNonDependentCardViewProperties(final Card c, final CardView view, final boolean mayShowCardFace) {
|
||||
public static void writeNonDependentCardViewProperties(final Card c, final CardView view, final boolean mayShowCard, final boolean mayShowCardFace) {
|
||||
final boolean hasAltState = c.isDoubleFaced() || c.isFlipCard() || c.isSplitCard() || (c.isFaceDown() && mayShowCardFace);
|
||||
view.setId(c.getUniqueNumber());
|
||||
view.setMayBeShown(mayShowCard);
|
||||
view.setZone(c.getZone() == null ? null : c.getZone().getZoneType());
|
||||
view.setHasAltState(hasAltState);
|
||||
view.setFaceDown(c.isFaceDown());
|
||||
@@ -130,8 +130,11 @@ public final class ViewUtil {
|
||||
|
||||
public static CardView getCardForUi(final IPaperCard pc) {
|
||||
final Card c = Card.getCardForUi(pc);
|
||||
final CardView view = new CardView(true);
|
||||
writeNonDependentCardViewProperties(c, view, c.getCardForUi() == c);
|
||||
if (c.getCardForUi() != c) {
|
||||
return null;
|
||||
}
|
||||
final CardView view = new CardView(c.getId());
|
||||
writeNonDependentCardViewProperties(c, view, true, true);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user