diff --git a/forge-ai/src/main/java/forge/ai/LobbyPlayerAi.java b/forge-ai/src/main/java/forge/ai/LobbyPlayerAi.java index 182d8b961af..939a6eea989 100644 --- a/forge-ai/src/main/java/forge/ai/LobbyPlayerAi.java +++ b/forge-ai/src/main/java/forge/ai/LobbyPlayerAi.java @@ -43,8 +43,8 @@ public class LobbyPlayerAi extends LobbyPlayer implements IGameEntitiesFactory { } @Override - public Player createIngamePlayer(Game game) { - Player ai = new Player(getName(), game); + public Player createIngamePlayer(Game game, final int id) { + Player ai = new Player(getName(), game, id); ai.setFirstController(createControllerFor(ai)); if( rotateProfileEachGame ) { diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 3ce84d3771f..9b895371075 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -168,9 +168,10 @@ public class Game implements IGameStateObject { } } + int plId = 0; for (RegisteredPlayer psc : players0) { IGameEntitiesFactory factory = (IGameEntitiesFactory)psc.getPlayer(); - Player pl = factory.createIngamePlayer(this); + Player pl = factory.createIngamePlayer(this, plId++); players.add(pl); ingamePlayers.add(pl); diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index b89ca547832..7514367c0b6 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -8859,6 +8859,7 @@ public class Card extends GameEntity implements Comparable { Zone zone = this.getZone(); if (zone == null) { return true; } //cards outside any zone are visible to all + final Player controller = this.getController(); switch (zone.getZoneType()) { case Ante: case Command: @@ -8869,23 +8870,23 @@ public class Card extends GameEntity implements Comparable { //cards in these zones are visible to all return true; case Hand: - if (getController().hasKeyword("Play with your hand revealed.")) { + if (controller.hasKeyword("Play with your hand revealed.")) { return true; } //fall through case Sideboard: //face-up cards in these zones are hidden to opponents unless they specify otherwise - if (getController().isOpponentOf(viewer) && !hasKeyword("Your opponent may look at this card.")) { + if (controller.isOpponentOf(viewer) && !hasKeyword("Your opponent may look at this card.")) { break; } return true; case Library: case PlanarDeck: //cards in these zones are hidden to all unless they specify otherwise - if (getController() == viewer && hasKeyword("You may look at this card.")) { + if (controller == viewer && hasKeyword("You may look at this card.")) { return true; } - if (getController().isOpponentOf(viewer) && hasKeyword("Your opponent may look at this card.")) { + if (controller.isOpponentOf(viewer) && hasKeyword("Your opponent may look at this card.")) { return true; } break; @@ -8906,8 +8907,8 @@ public class Card extends GameEntity implements Comparable { } //if viewer is controlled by another player, also check if card can be shown to that player - if (viewer.isMindSlaved()) { - return canBeShownTo(viewer.getMindSlaveMaster()); + if (controller.isMindSlaved() && viewer == controller.getMindSlaveMaster()) { + return canBeShownTo(controller); } return false; diff --git a/forge-game/src/main/java/forge/game/player/IGameEntitiesFactory.java b/forge-game/src/main/java/forge/game/player/IGameEntitiesFactory.java index ae65ff2c700..f8211b1925d 100644 --- a/forge-game/src/main/java/forge/game/player/IGameEntitiesFactory.java +++ b/forge-game/src/main/java/forge/game/player/IGameEntitiesFactory.java @@ -2,10 +2,8 @@ package forge.game.player; import forge.game.Game; - - public interface IGameEntitiesFactory { PlayerController createControllerFor(Player p); - Player createIngamePlayer(Game game); + Player createIngamePlayer(Game game, int id); } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 15cbf7fe95c..a7747d01475 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -71,6 +71,8 @@ import java.util.concurrent.ConcurrentSkipListMap; * @version $Id$ */ public class Player extends GameEntity implements Comparable { + private final int id; + private final Map commanderDamage = new HashMap(); /** The poison counters. */ @@ -206,7 +208,7 @@ public class Player extends GameEntity implements Comparable { * @param myPoisonCounters * a int. */ - public Player(String name, Game game0) { + public Player(String name, Game game0, final int id) { game = game0; for (final ZoneType z : Player.ALL_ZONES) { final PlayerZone toPut = z == ZoneType.Battlefield ? new PlayerZoneBattlefield(z, this) : new PlayerZone(z, this); @@ -214,6 +216,7 @@ public class Player extends GameEntity implements Comparable { } this.setName(chooseName(name)); + this.id = id; } private String chooseName(String originalName) { @@ -234,6 +237,10 @@ public class Player extends GameEntity implements Comparable { return nameCandidate; } + public int getId() { + return this.id; + } + @Override public Game getGame() { // I'll probably regret about this return game; diff --git a/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java b/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java index 5fde8edbaeb..046a4bcb7bc 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java +++ b/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java @@ -182,7 +182,7 @@ public class CardDetailPanel extends SkinnedPanel { final CardStateView state = card.getState(isInAltState); if (state.getManaCost().isNoCost()) { - this.nameCostLabel.setText(state.getName()); + this.nameCostLabel.setText(CardDetailUtil.formatCardName(state)); } else { final String manaCost; if (card.isSplitCard() && card.hasAltState()) { @@ -190,7 +190,7 @@ public class CardDetailPanel extends SkinnedPanel { } else { manaCost = state.getManaCost().toString(); } - this.nameCostLabel.setText(FSkin.encodeSymbols(state.getName() + " - " + manaCost, true)); + this.nameCostLabel.setText(FSkin.encodeSymbols(CardDetailUtil.formatCardName(state) + " - " + manaCost, true)); } this.typeLabel.setText(CardDetailUtil.formatCardType(state)); diff --git a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java index 2ca3f30dd8e..a420b66a5f8 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java +++ b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java @@ -208,8 +208,15 @@ public class GuiChoose { @Override public void valueChanged(final ListSelectionEvent ev) { final T sel = list.getSelectedValue(); + final CardView card; if (sel instanceof CardStateView) { - final CardView card = ((CardStateView) sel).getCard(); + card = ((CardStateView) sel).getCard(); + } else if (sel instanceof CardView) { + card = (CardView) sel; + } else { + card = null; + } + if (card != null) { CMatchUI.SINGLETON_INSTANCE.setCard(card); GuiUtils.clearPanelSelections(); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 97fa5a12980..23c2469ffaf 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -168,7 +168,7 @@ public enum CMatchUI implements ICDoc, IMenuProvider { int i = 0; for (final PlayerView p : sortedPlayers) { - if (localPlayer == null || p.getLobbyPlayer() == localPlayer) { + if (p.getLobbyPlayer().equals(localPlayer) || !p.getHandCards().isEmpty()) { VHand newHand = new VHand(EDocID.Hands[i], p); newHand.getLayoutControl().initialize(); hands.add(newHand); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDock.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDock.java index 6d36f273587..e1b6033a63f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDock.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDock.java @@ -158,6 +158,7 @@ public enum CDock implements ICDoc { /** Attack with everyone. */ public void alphaStrike() { + game.alphaStrike(); /* TODO: rewrite this! final Player p = this.findAffectedPlayer(); final Combat combat = FControl.instance.getObservedGame().getCombat(); diff --git a/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java b/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java index bcbf8eea929..31545edd578 100644 --- a/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java +++ b/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java @@ -119,12 +119,12 @@ public class PlayerDetailsPanel extends JPanel { * @param p0   {@link forge.game.player.Player} */ public void updateZones() { - this.getLblHand().setText("" + player.getHandCards().size()); + this.getLblHand().setText("" + player.getnHandCards()); final String handMaxToolTip = player.hasUnlimitedHandSize() ? "no maximum hand size" : String.valueOf(player.getMaxHandSize()); this.getLblHand().setToolTipText("Cards in hand (max: " + handMaxToolTip + ")"); this.getLblGraveyard().setText("" + player.getGraveCards().size()); - this.getLblLibrary().setText("" + player.getLibraryCards().size()); + this.getLblLibrary().setText("" + player.getnLibraryCards()); this.getLblFlashback().setText("" + player.getFlashbackCards().size()); this.getLblExile().setText("" + player.getExileCards().size()); } diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java index e9ba6fae228..58acf6f4435 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java @@ -609,22 +609,19 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen for (final CardPanel cpa : getCardPanels()) { oldCards.add(cpa.getCard()); } - final List toDelete = Lists.newArrayList(oldCards); - final List toReplace = Lists.newArrayList(); - // delete all cards that differ in timestamp (they have been blinked) + final List toDelete = Lists.newArrayList(oldCards); + final List notToDelete = Lists.newLinkedList(); for (final CardView c : modelCopy) { for (int i = 0; i < toDelete.size(); i++) { final CardView c2 = toDelete.get(i); if (c.getId() == c2.getId()) { - if (c.getTimestamp() == c2.getTimestamp()) { - toDelete.remove(c2); - } else { - toReplace.add(c); - } + notToDelete.add(c2); } } } + toDelete.removeAll(notToDelete); + if (toDelete.size() == getCardPanels().size()) { clear(); } else { @@ -635,7 +632,6 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen final List toAdd = new ArrayList(modelCopy); toAdd.removeAll(oldCards); - toAdd.addAll(toReplace); final List newPanels = new ArrayList(); for (final CardView card : toAdd) { diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/LobbyPlayerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/LobbyPlayerForTests.java index e65d0aa47c2..ef40dfdbf66 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/LobbyPlayerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/LobbyPlayerForTests.java @@ -28,8 +28,8 @@ public class LobbyPlayerForTests extends LobbyPlayer implements IGameEntitiesFac @Override - public Player createIngamePlayer( Game gameState ) { - Player dummyPlayer = new Player( getName(), gameState ); + public Player createIngamePlayer(Game gameState, final int id) { + Player dummyPlayer = new Player(getName(), gameState, id); dummyPlayer.setFirstController( createControllerFor( dummyPlayer ) ); return dummyPlayer; } diff --git a/forge-gui-mobile/src/forge/screens/match/FControl.java b/forge-gui-mobile/src/forge/screens/match/FControl.java index 424140589f1..f9e4117c7e8 100644 --- a/forge-gui-mobile/src/forge/screens/match/FControl.java +++ b/forge-gui-mobile/src/forge/screens/match/FControl.java @@ -40,12 +40,7 @@ import forge.game.GameRules; import forge.game.GameType; import forge.game.Match; import forge.game.card.Card; -import forge.game.card.CardLists; import forge.game.card.CounterType; -import forge.game.card.CardPredicates.Presets; -import forge.game.combat.Combat; -import forge.game.combat.CombatUtil; -import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.RegisteredPlayer; @@ -324,29 +319,7 @@ public class FControl { } public static void alphaStrike() { - final PhaseHandler ph = game.getPhaseHandler(); - - final Player p = getCurrentPlayer(); - final Game game = p.getGame(); - Combat combat = game.getCombat(); - if (combat == null) { return; } - - if (ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, p)) { - List defenders = p.getOpponents(); - - for (Card c : CardLists.filter(p.getCardsIn(ZoneType.Battlefield), Presets.CREATURES)) { - if (combat.isAttacking(c)) { - continue; - } - - for (Player defender : defenders) { - if (CombatUtil.canAttack(c, defender, combat)) { - combat.addAttacker(c, defender); - break; - } - } - } - } + gameView.alphaStrike(); } public static void showCombat(CombatView combat) { @@ -421,6 +394,9 @@ public class FControl { for (Pair kv : zonesToUpdate) { PlayerView owner = kv.getKey(); ZoneType zt = kv.getValue(); + if (owner == null || zt == null) { + continue; + } getPlayerPanel(owner).updateZone(zt); } } diff --git a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java index acbbfa080a1..9898d21a7b3 100644 --- a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java +++ b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java @@ -14,8 +14,6 @@ import forge.assets.TextRenderer; import forge.assets.FSkinColor.Colors; import forge.card.CardRenderer; import forge.card.CardZoom; -import forge.game.card.Card; -import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.item.PaperCard; import forge.screens.match.FControl; @@ -60,13 +58,13 @@ public class FChoiceList extends FList { if (item instanceof PaperCard) { renderer = new PaperCardItemRenderer(); } - else if (item instanceof Card) { + else if (item instanceof CardView) { renderer = new CardItemRenderer(); } else if (item instanceof SpellAbility) { renderer = new SpellAbilityItemRenderer(); } - else if (item instanceof Player) { + else if (item instanceof PlayerView) { renderer = new PlayerItemRenderer(); } else { diff --git a/forge-gui/src/main/java/forge/card/CardDetailUtil.java b/forge-gui/src/main/java/forge/card/CardDetailUtil.java index 928ef6b1d3c..a88b20348e0 100644 --- a/forge-gui/src/main/java/forge/card/CardDetailUtil.java +++ b/forge-gui/src/main/java/forge/card/CardDetailUtil.java @@ -6,6 +6,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.apache.commons.lang3.StringUtils; + import com.google.common.collect.Sets; import forge.game.card.CardUtil; @@ -159,6 +161,11 @@ public class CardDetailUtil { return item.getName(); } + public static String formatCardName(final CardStateView card) { + final String name = card.getName(); + return StringUtils.isEmpty(name) ? "(no name)" : name.trim(); + } + public static String formatCardType(final CardStateView card) { final List list = card.getType(); final StringBuilder sb = new StringBuilder(); @@ -199,7 +206,7 @@ public class CardDetailUtil { sb.append(type).append(" "); } - return sb.toString(); + return sb.toString().trim(); } public static String formatPowerToughness(final CardStateView card) { diff --git a/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java b/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java index cfb6aca676c..7be01868c82 100644 --- a/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java +++ b/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java @@ -355,8 +355,12 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { @Override public Void visit(GameEventCardChangeZone event) { - updateZone(event.from); - updateZone(event.to); + if (event.from != null) { + updateZone(event.from); + } + if (event.to != null) { + updateZone(event.to); + } return null; } diff --git a/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java b/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java index 3b94542b0ba..b19f46e1226 100644 --- a/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java +++ b/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java @@ -25,8 +25,8 @@ public class LobbyPlayerHuman extends LobbyPlayer implements IGameEntitiesFactor } @Override - public Player createIngamePlayer(Game game) { - Player player = new Player(GuiDisplayUtil.personalizeHuman(getName()), game); + public Player createIngamePlayer(Game game, final int id) { + Player player = new Player(GuiDisplayUtil.personalizeHuman(getName()), game, id); player.setFirstController(new PlayerControllerHuman(game, player, this, gui)); if (ForgePreferences.DEV_MODE && FModel.getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND)) { diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 28af6235798..d155fe836bf 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -7,6 +7,7 @@ import java.util.HashMap; 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; @@ -20,6 +21,7 @@ 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.LobbyPlayer; import forge.card.ColorSet; @@ -39,6 +41,8 @@ import forge.game.GameOutcome; import forge.game.GameType; import forge.game.ability.effects.CharmEffect; import forge.game.card.Card; +import forge.game.card.CardLists; +import forge.game.card.CardPredicates.Presets; import forge.game.card.CardShields; import forge.game.card.CounterType; import forge.game.combat.Combat; @@ -101,9 +105,14 @@ import forge.view.StackItemView; */ public class PlayerControllerHuman extends PlayerController { - private final IGuiBase gui; + private IGuiBase gui; private final InputProxy inputProxy; private final GameView gameView; + /** + * Cards this player may look at right now, for example when searching a + * library. + */ + private final Set mayLookAt = Sets.newHashSet(); public PlayerControllerHuman(final Game game0, final Player p, final LobbyPlayer lp, final IGuiBase gui) { super(game0, p, lp); @@ -304,9 +313,11 @@ public class PlayerControllerHuman extends PlayerController { return Lists.newArrayList(sc.getSelected()); } - return SGuiChoose.many(getGui(), title, "Chosen Cards", min, max, sourceList, gameView.getCardView(sa.getHostCard())); + final List choices = SGuiChoose.many(getGui(), title, "Chosen Cards", min, max, gameView.getCardViews(sourceList), gameView.getCardView(sa.getHostCard())); + return getCards(choices); } + @SuppressWarnings("unchecked") @Override public T chooseSingleEntityForEffect(Collection options, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) { // Human is supposed to read the message and understand from it what to choose @@ -338,9 +349,17 @@ public class PlayerControllerHuman extends PlayerController { return Iterables.getFirst(input.getSelected(), null); } - return isOptional ? SGuiChoose.oneOrNone(getGui(), title, options) : SGuiChoose.one(getGui(), title, options); + for (final T t : options) { + if (t instanceof Card) { + // assume you may see any card passed through here + mayLookAt.add((Card) t); + } + } + final GameEntityView result = isOptional ? SGuiChoose.oneOrNone(getGui(), title, gameView.getGameEntityViews((Iterable) options)) : SGuiChoose.one(getGui(), title, gameView.getGameEntityViews((Iterable) options)); + mayLookAt.clear(); + return (T) gameView.getGameEntity(result); } - + @Override public int chooseNumber(SpellAbility sa, String title, int min, int max) { final Integer[] choices = new Integer[max + 1 - min]; @@ -357,8 +376,13 @@ public class PlayerControllerHuman extends PlayerController { @Override public SpellAbility chooseSingleSpellForEffect(java.util.List spells, SpellAbility sa, String title) { + if (spells.size() < 2) { + return spells.get(0); + } + // Human is supposed to read the message and understand from it what to choose - return spells.size() < 2 ? spells.get(0) : SGuiChoose.one(getGui(), title, spells); + final SpellAbilityView choice = SGuiChoose.one(getGui(), title, gameView.getSpellAbilityViews(spells)); + return gameView.getSpellAbility(choice); } /* (non-Javadoc) @@ -469,7 +493,9 @@ public class PlayerControllerHuman extends PlayerController { } String fm = formatMessage(message, owner); if (!cards.isEmpty()) { - SGuiChoose.reveal(getGui(), fm, cards); + mayLookAt.addAll(cards); + SGuiChoose.reveal(getGui(), fm, gameView.getCardViews(cards)); + mayLookAt.clear(); } else { SGuiDialog.message(getGui(), formatMessage("There are no cards in {player's} " + @@ -539,8 +565,9 @@ public class PlayerControllerHuman extends PlayerController { @Override public List chooseCardsToDiscardFrom(Player p, SpellAbility sa, List valid, int min, int max) { if (p != player) { - return SGuiChoose.many(getGui(), "Choose " + min + " card" + (min != 1 ? "s" : "") + " to discard", - "Discarded", min, min, valid, null); + final List choices = SGuiChoose.many(getGui(), "Choose " + min + " card" + (min != 1 ? "s" : "") + " to discard", + "Discarded", min, min, gameView.getCardViews(valid), null); + return getCards(choices); } InputSelectCardsFromList inp = new InputSelectCardsFromList(this, min, max, valid); @@ -570,7 +597,7 @@ public class PlayerControllerHuman extends PlayerController { System.out.println("Delve for " + chosenAmount); for (int i = 0; i < chosenAmount; i++) { - final Card nowChosen = SGuiChoose.oneOrNone(getGui(), "Exile which card?", grave); + final CardView nowChosen = SGuiChoose.oneOrNone(getGui(), "Exile which card?", gameView.getCardViews(grave)); if (nowChosen == null) { // User canceled,abort delving. @@ -579,7 +606,7 @@ public class PlayerControllerHuman extends PlayerController { } grave.remove(nowChosen); - toExile.add(nowChosen); + toExile.add(gameView.getCard(nowChosen)); } return toExile; } @@ -849,8 +876,9 @@ public class PlayerControllerHuman extends PlayerController { if (srcCards.isEmpty()) { return result; } - List chosen = SGuiChoose.many(getGui(), "Choose cards to activate from opening hand and their order", "Activate first", -1, srcCards, null); - for (Card c : chosen) { + final List chosen = SGuiChoose.many(getGui(), "Choose cards to activate from opening hand and their order", "Activate first", -1, gameView.getCardViews(srcCards), null); + for (final CardView view : chosen) { + final Card c = getCard(view); for (SpellAbility sa : usableFromOpeningHand) { if (sa.getHostCard() == c) { result.add(sa); @@ -939,7 +967,7 @@ public class PlayerControllerHuman extends PlayerController { if (sa.isManaAbility()) { game.getGameLog().add(GameLogEntryType.LAND, message); } else { - SGuiDialog.message(getGui(), message, sa.getHostCard() == null ? "" : sa.getHostCard().getName()); + SGuiDialog.message(getGui(), message, sa.getHostCard() == null ? "" : getCardView(sa.getHostCard()).toString()); } } @@ -1098,7 +1126,8 @@ public class PlayerControllerHuman extends PlayerController { public void orderAndPlaySimultaneousSa(List activePlayerSAs) { List orderedSAs = activePlayerSAs; if (activePlayerSAs.size() > 1) { // give a dual list form to create instead of needing to do it one at a time - orderedSAs = SGuiChoose.order(getGui(), "Select order for Simultaneous Spell Abilities", "Resolve first", activePlayerSAs, null); + final List orderedSAViews = SGuiChoose.order(getGui(), "Select order for Simultaneous Spell Abilities", "Resolve first", gameView.getSpellAbilityViews(activePlayerSAs), null); + orderedSAs = getSpellAbilities(orderedSAViews); } int size = orderedSAs.size(); for (int i = size - 1; i >= 0; i--) { @@ -1319,10 +1348,35 @@ public class PlayerControllerHuman extends PlayerController { getInputProxy().selectAbility(sa); } + @Override + public void alphaStrike() { + final Combat combat = game.getCombat(); + if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS) + || combat == null + || game.getPhaseHandler().getPlayerTurn() != player + || !(getGui().getInputQueue().getInput() instanceof InputAttack)) { + return; + } + + final List defenders = player.getOpponents(); + + for (final Card c : CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.CREATURES)) { + if (combat.isAttacking(c)) + continue; + + for (final Player defender : defenders) { + if (CombatUtil.canAttack(c, defender, combat)) { + combat.addAttacker(c, defender); + break; + } + } + } + } + @Override public boolean mayShowCard(final CardView c) { final Card card = getCard(c); - return card == null || card.canBeShownTo(player); + return card == null || mayLookAt.contains(card) || card.canBeShownTo(player); } @Override @@ -1457,21 +1511,12 @@ public class PlayerControllerHuman extends PlayerController { return gameView.getGameEntityView(e); } - /** - * @param players - * @return - * @see forge.view.LocalGameView#getPlayerViews(java.util.List) - */ - public final List getPlayerViews(List players) { - return gameView.getPlayerViews(players); - } - /** * @param players * @return * @see forge.view.LocalGameView#getPlayerViews(java.lang.Iterable) */ - public final Iterable getPlayerViews(Iterable players) { + public final List getPlayerViews(Iterable players) { return gameView.getPlayerViews(players); } @@ -1516,7 +1561,7 @@ public class PlayerControllerHuman extends PlayerController { * @return * @see forge.view.LocalGameView#getCardViews(java.lang.Iterable) */ - public final Iterable getCardViews(Iterable cards) { + public final List getCardViews(Iterable cards) { return gameView.getCardViews(cards); } diff --git a/forge-gui/src/main/java/forge/view/CardView.java b/forge-gui/src/main/java/forge/view/CardView.java index e1c7fea4a9e..b7d324a087d 100644 --- a/forge-gui/src/main/java/forge/view/CardView.java +++ b/forge-gui/src/main/java/forge/view/CardView.java @@ -117,6 +117,17 @@ public class CardView extends GameEntityView { this.id = id; } + @Override + public boolean equals(final Object obj) { + return obj instanceof CardView && this.getId() == ((CardView) obj).getId() + && (this.getId() > 0 || this == obj); + } + + @Override + public int hashCode() { + return id > 0 ? id : super.hashCode(); + } + public boolean isUiDisplayable() { return isUiDisplayable; } diff --git a/forge-gui/src/main/java/forge/view/CombatView.java b/forge-gui/src/main/java/forge/view/CombatView.java index ec48508206e..03ddb8ff142 100644 --- a/forge-gui/src/main/java/forge/view/CombatView.java +++ b/forge-gui/src/main/java/forge/view/CombatView.java @@ -1,18 +1,20 @@ package forge.view; +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.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; public class CombatView { - private Map attackersWithDefenders; - private Map> attackersWithBlockers; - private Map, GameEntityView> bandsWithDefenders; - private Map, Iterable> bandsWithBlockers; + private Map attackersWithDefenders = Maps.newHashMap(); + private Map> attackersWithBlockers = Maps.newHashMap(); + private Map, GameEntityView> bandsWithDefenders = Maps.newHashMap(); + private Map, Iterable> bandsWithBlockers = Maps.newHashMap(); public CombatView() { } @@ -39,6 +41,9 @@ public class CombatView { public boolean isBlocking(final CardView card) { for (final Iterable blockers : attackersWithBlockers.values()) { + if (blockers == null) { + continue; + } if (Iterables.contains(blockers, card)) { return true; } @@ -69,18 +74,20 @@ public class CombatView { } public void addAttackingBand(final Iterable attackingBand, final GameEntityView defender, final Iterable blockers) { - for (final CardView attacker : attackingBand) { - this.attackersWithDefenders.put(attacker, defender); - this.attackersWithBlockers.put(attacker, blockers); + final List attackingBandCopy = Lists.newArrayList(attackingBand), + blockersCopy; + if (blockers == null) { + blockersCopy = null; + } else { + blockersCopy = Lists.newArrayList(blockers); } - this.bandsWithDefenders.put(attackingBand, defender); - this.bandsWithBlockers.put(attackingBand, blockers); + + for (final CardView attacker : attackingBandCopy) { + this.attackersWithDefenders.put(attacker, defender); + this.attackersWithBlockers.put(attacker, blockersCopy); + } + this.bandsWithDefenders.put(attackingBandCopy, defender); + this.bandsWithBlockers.put(attackingBandCopy, blockersCopy); } - public void reset() { - this.attackersWithDefenders = Maps.newHashMap(); - this.attackersWithBlockers = Maps.newHashMap(); - this.bandsWithDefenders = Maps.newHashMap(); - this.bandsWithBlockers = Maps.newHashMap(); - } } diff --git a/forge-gui/src/main/java/forge/view/IGameView.java b/forge-gui/src/main/java/forge/view/IGameView.java index f0aed92bbcb..974573f5529 100644 --- a/forge-gui/src/main/java/forge/view/IGameView.java +++ b/forge-gui/src/main/java/forge/view/IGameView.java @@ -35,8 +35,6 @@ public interface IGameView { public abstract int getGamesWonBy(LobbyPlayer p); public abstract GameOutcome.AnteResult getAnteResult(); - public abstract boolean isCombatDeclareAttackers(); - public abstract boolean isGameOver(); public abstract int getPoisonCountersToLose(); @@ -61,6 +59,7 @@ public interface IGameView { public abstract void selectPlayer(PlayerView player, ITriggerEvent triggerEvent); public abstract boolean selectCard(CardView card, ITriggerEvent triggerEvent); public abstract void selectAbility(SpellAbilityView sa); + public abstract void alphaStrike(); // the following method should eventually be replaced by methods returning // View classes diff --git a/forge-gui/src/main/java/forge/view/LocalGameView.java b/forge-gui/src/main/java/forge/view/LocalGameView.java index 400ab76137a..2e606bedc56 100644 --- a/forge-gui/src/main/java/forge/view/LocalGameView.java +++ b/forge-gui/src/main/java/forge/view/LocalGameView.java @@ -47,8 +47,6 @@ public class LocalGameView implements IGameView { private final Cache spabs = new Cache<>(); /** Cache of stack items. */ private final Cache stackItems = new Cache<>(); - /** Combat view. */ - private final CombatView combatView = new CombatView(); /* (non-Javadoc) * @see forge.view.IGameView#isCommander() @@ -133,15 +131,6 @@ public class LocalGameView implements IGameView { return null; } - /* (non-Javadoc) - * @see forge.view.IGameView#isCombatDeclareAttackers() - */ - @Override - public boolean isCombatDeclareAttackers() { - return game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS) - && game.getCombat() != null; - } - /* (non-Javadoc) * @see forge.view.IGameView#isGameOver() */ @@ -171,22 +160,19 @@ public class LocalGameView implements IGameView { /* (non-Javadoc) * @see forge.view.IGameView#getCombat() */ - public CombatView getCombat(final Combat c) { - if (c == null) { + public CombatView getCombat(final Combat combat) { + if (combat == null) { return null; } - updateCombatView(c); - return combatView; - } - private final void updateCombatView(final Combat combat) { - combatView.reset(); + final CombatView combatView = new CombatView(); for (final AttackingBand b : combat.getAttackingBands()) { if (b == null) continue; final GameEntity defender = combat.getDefenderByAttacker(b); - final List blockers = b.isBlocked() == null ? null : combat.getBlockers(b); + final List blockers = (b.isBlocked() != null && b.isBlocked()) ? combat.getBlockers(b) : null; combatView.addAttackingBand(getCardViews(b.getAttackers()), getGameEntityView(defender), blockers == null ? null : getCardViews(blockers)); } + return combatView; } @Override @@ -256,6 +242,10 @@ public class LocalGameView implements IGameView { public void selectAbility(final SpellAbilityView sa) { } + @Override + public void alphaStrike() { + } + /* (non-Javadoc) * @see forge.view.IGameView#getGuiRegisteredPlayer(forge.LobbyPlayer) */ @@ -351,6 +341,26 @@ public class LocalGameView implements IGameView { return null; } + private final Function FN_GET_GAME_ENTITY_VIEW = new Function() { + @Override + public GameEntityView apply(GameEntity input) { + return getGameEntityView(input); + } + }; + + public final List getGameEntityViews(final Iterable entities) { + return ViewUtil.transformIfNotNull(entities, FN_GET_GAME_ENTITY_VIEW); + } + + public final GameEntity getGameEntity(final GameEntityView view) { + if (view instanceof CardView) { + return getCard((CardView) view); + } else if (view instanceof PlayerView) { + return getPlayer((PlayerView) view); + } + return null; + } + private final Function FN_GET_PLAYER_VIEW = new Function() { @Override public PlayerView apply(final Player input) { @@ -358,12 +368,8 @@ public class LocalGameView implements IGameView { } }; - public final List getPlayerViews(final List players) { - return Lists.transform(players, FN_GET_PLAYER_VIEW); - } - - public final Iterable getPlayerViews(final Iterable players) { - return Iterables.transform(players, FN_GET_PLAYER_VIEW); + public final List getPlayerViews(final Iterable players) { + return ViewUtil.transformIfNotNull(players, FN_GET_PLAYER_VIEW); } public PlayerView getPlayerView(final Player p) { @@ -376,7 +382,7 @@ public class LocalGameView implements IGameView { view = players.get(p); getPlayerView(p, view); } else { - view = new PlayerView(p.getLobbyPlayer(), p.getController()); + view = new PlayerView(p.getLobbyPlayer(), p.getId()); players.put(p, view); getPlayerView(p, view); view.setOpponents(getPlayerViews(p.getOpponents())); @@ -407,8 +413,12 @@ public class LocalGameView implements IGameView { view.setExileCards(getCardViews(p.getCardsIn(ZoneType.Exile))); view.setFlashbackCards(getCardViews(p.getCardsActivableInExternalZones(false))); view.setGraveCards(getCardViews(p.getCardsIn(ZoneType.Graveyard))); - view.setHandCards(getCardViews(p.getCardsIn(ZoneType.Hand))); - view.setLibraryCards(getCardViews(p.getCardsIn(ZoneType.Library))); + final List handCards = p.getCardsIn(ZoneType.Hand), + libraryCards = p.getCardsIn(ZoneType.Library); + view.setHandCards(getCardViews(handCards)); + view.setLibraryCards(getCardViews(libraryCards)); + view.setnHandCards(handCards.size()); + view.setnLibraryCards(libraryCards.size()); for (final byte b : MagicColor.WUBRGC) { view.setMana(b, p.getManaPool().getAmountOfColor(b)); @@ -421,7 +431,8 @@ public class LocalGameView implements IGameView { } final Card cUi = c.getCardForUi(); - final boolean isDisplayable = cUi == c; + final boolean isDisplayable = cUi == c && + !(c.isInZone(ZoneType.Hand) || c.isInZone(ZoneType.Library)); CardView view = cards.get(c); final boolean mayShow; @@ -438,10 +449,12 @@ public class LocalGameView implements IGameView { } } - if (isDisplayable && mayShow) { + if (mayShow) { writeCardToView(cUi, view); - } else { + } else if (isDisplayable) { view.reset(); + } else { + return null; } return view; @@ -454,11 +467,8 @@ public class LocalGameView implements IGameView { } }; - public final List getCardViews(final List cards) { - return Lists.transform(cards, FN_GET_CARD_VIEW); - } - public final Iterable getCardViews(final Iterable cards) { - return Iterables.transform(cards, FN_GET_CARD_VIEW); + public final List getCardViews(final Iterable cards) { + return ViewUtil.transformIfNotNull(cards, FN_GET_CARD_VIEW); } private CardView getCardViewFast(final Card c) { @@ -467,10 +477,14 @@ public class LocalGameView implements IGameView { } final CardView view = cards.get(c); - if (!mayShowCard(view)) { + if (mayShowCard(view)) { + return view; + } else if (view.isUiDisplayable()) { view.reset(); + return view; } - return view; + + return null; } private final Function FN_GET_CARDVIEW_FAST = new Function() { @@ -480,8 +494,8 @@ public class LocalGameView implements IGameView { } }; - private Iterable getCardViewsFast(final Iterable cards) { - return Iterables.transform(cards, FN_GET_CARDVIEW_FAST); + private List getCardViewsFast(final Iterable cards) { + return ViewUtil.transformIfNotNull(cards, FN_GET_CARDVIEW_FAST); } public Card getCard(final CardView c) { @@ -496,7 +510,7 @@ public class LocalGameView implements IGameView { }; public final List getCards(final List cards) { - return Lists.transform(cards, FN_GET_CARD); + return ViewUtil.transformIfNotNull(cards, FN_GET_CARD); } private void writeCardToView(final Card c, final CardView view) { @@ -558,7 +572,7 @@ public class LocalGameView implements IGameView { }; public final List getSpellAbilityViews(final List cards) { - return Lists.transform(cards, FN_GET_SPAB_VIEW); + return ViewUtil.transformIfNotNull(cards, FN_GET_SPAB_VIEW); } public SpellAbility getSpellAbility(final SpellAbilityView c) { @@ -573,7 +587,7 @@ public class LocalGameView implements IGameView { }; public final List getSpellAbilities(final List cards) { - return Lists.transform(cards, FN_GET_SPAB); + return ViewUtil.transformIfNotNull(cards, FN_GET_SPAB); } private void writeSpellAbilityToView(final SpellAbility sa, final SpellAbilityView view) { diff --git a/forge-gui/src/main/java/forge/view/PlayerView.java b/forge-gui/src/main/java/forge/view/PlayerView.java index 03f7d6ed2f2..737ee4a08e2 100644 --- a/forge-gui/src/main/java/forge/view/PlayerView.java +++ b/forge-gui/src/main/java/forge/view/PlayerView.java @@ -11,32 +11,35 @@ import com.google.common.collect.Sets; import forge.LobbyPlayer; import forge.card.MagicColor; -import forge.game.player.PlayerController; import forge.game.zone.ZoneType; public class PlayerView extends GameEntityView { private final LobbyPlayer lobbyPlayer; - private final PlayerController controller; + private final int id; private Set opponents; private int life, poisonCounters, maxHandSize, numDrawnThisTurn, preventNextDamage; private List keywords; private String commanderInfo; - private List anteCards = Lists.newArrayList(), - bfCards = Lists.newArrayList(), - commandCards = Lists.newArrayList(), - exileCards = Lists.newArrayList(), + private List + anteCards = Lists.newArrayList(), + bfCards = Lists.newArrayList(), + commandCards = Lists.newArrayList(), + exileCards = Lists.newArrayList(), flashbackCards = Lists.newArrayList(), - graveCards = Lists.newArrayList(), - handCards = Lists.newArrayList(), - libraryCards = Lists.newArrayList(); + graveCards = Lists.newArrayList(), + handCards = Lists.newArrayList(), + libraryCards = Lists.newArrayList(); + private int + nHandCards, + nLibraryCards; private boolean hasUnlimitedHandSize; private Map mana = Maps.newHashMapWithExpectedSize(MagicColor.NUMBER_OR_COLORS + 1); - public PlayerView(final LobbyPlayer lobbyPlayer, final PlayerController controller) { + public PlayerView(final LobbyPlayer lobbyPlayer, final int id) { this.lobbyPlayer = lobbyPlayer; - this.controller = controller; + this.id = id; } /** @@ -46,6 +49,20 @@ public class PlayerView extends GameEntityView { return lobbyPlayer; } + public int getId() { + return id; + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof PlayerView && this.getId() == ((PlayerView) obj).getId(); + } + + @Override + public int hashCode() { + return id; + } + public void setOpponents(final Iterable opponents) { this.opponents = Sets.newHashSet(opponents); } @@ -54,14 +71,6 @@ public class PlayerView extends GameEntityView { return opponents.contains(other); } - /** - * @return the controller - */ - @Deprecated - public PlayerController getController() { - return controller; - } - public String getName() { return this.getLobbyPlayer().getName(); } @@ -302,6 +311,34 @@ public class PlayerView extends GameEntityView { } } + /** + * @return the nHandCards + */ + public int getnHandCards() { + return nHandCards; + } + + /** + * @param nHandCards the nHandCards to set + */ + public void setnHandCards(int nHandCards) { + this.nHandCards = nHandCards; + } + + /** + * @return the nLibraryCards + */ + public int getnLibraryCards() { + return nLibraryCards; + } + + /** + * @param nLibraryCards the nLibraryCards to set + */ + public void setnLibraryCards(int nLibraryCards) { + this.nLibraryCards = nLibraryCards; + } + /** * @return the hasUnlimitedHandSize */ diff --git a/forge-gui/src/main/java/forge/view/ViewUtil.java b/forge-gui/src/main/java/forge/view/ViewUtil.java index 71e092874db..991c3ac94f4 100644 --- a/forge-gui/src/main/java/forge/view/ViewUtil.java +++ b/forge-gui/src/main/java/forge/view/ViewUtil.java @@ -1,6 +1,10 @@ package forge.view; import java.util.Collections; +import java.util.List; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; import forge.card.CardCharacteristicName; import forge.game.card.Card; @@ -51,8 +55,17 @@ public final class ViewUtil { view.setNamedCard(c.getNamedCard()); if (c.isSplitCard()) { - writeCardStateViewProperties(c, view.getOriginal(), CardCharacteristicName.LeftSplit); - writeCardStateViewProperties(c, view.getAlternate(), CardCharacteristicName.RightSplit); + final CardCharacteristicName orig, alt; + if (c.getCurState() == CardCharacteristicName.RightSplit) { + // If right half on stack, place it first + orig = CardCharacteristicName.RightSplit; + alt = CardCharacteristicName.LeftSplit; + } else { + orig = CardCharacteristicName.LeftSplit; + alt = CardCharacteristicName.RightSplit; + } + writeCardStateViewProperties(c, view.getOriginal(), orig); + writeCardStateViewProperties(c, view.getAlternate(), alt); return; } @@ -114,4 +127,15 @@ public final class ViewUtil { writeNonDependentCardViewProperties(c, view, c.getCardForUi() == c); return view; } + + public static List transformIfNotNull(final Iterable input, final Function transformation) { + final List ret = Lists.newLinkedList(); + for (final T t : input) { + final V v = transformation.apply(t); + if (v != null) { + ret.add(v); + } + } + return ret; + } } diff --git a/forge-net/src/main/java/forge/net/LobbyPlayerRemote.java b/forge-net/src/main/java/forge/net/LobbyPlayerRemote.java index 7e00e671127..73fae4d50cf 100644 --- a/forge-net/src/main/java/forge/net/LobbyPlayerRemote.java +++ b/forge-net/src/main/java/forge/net/LobbyPlayerRemote.java @@ -21,7 +21,7 @@ public class LobbyPlayerRemote extends LobbyPlayer implements IGameEntitiesFacto * @see forge.game.player.LobbyPlayer#getPlayer(forge.game.GameState) */ @Override - public Player createIngamePlayer(Game gameState) { + public Player createIngamePlayer(Game gameState, final int id) { // Cannot create remote players yet throw new UnsupportedOperationException("method is not implemented"); }