From 67479bb5a4df95102a438f17cd6d1ca886ba89d8 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 26 Nov 2014 01:48:00 +0100 Subject: [PATCH] * Fixed wrong timer handling while other player controlled a player's turn. Attackers now marked with blue frame. Playable cards have a violet frame. If a player has to select cards from hand, the possible cards are marked yellow now. Discard of multiple cards now marks already selected cards and happens in one selection. --- .../main/java/mage/client/game/GamePanel.java | 21 +++++ .../java/mage/client/game/PlayerPanelExt.java | 2 +- .../java/org/mage/card/arcane/CardPanel.java | 17 ++-- Mage.Common/src/mage/view/CardView.java | 13 +++ Mage.Common/src/mage/view/PlayerView.java | 10 ++- .../src/mage/player/ai/ComputerPlayer6.java | 2 +- .../src/mage/player/ai/ComputerPlayer7.java | 4 +- .../java/mage/player/ai/ComputerPlayer.java | 12 ++- .../src/mage/player/human/HumanPlayer.java | 73 ++++++++++------ .../src/main/java/mage/server/User.java | 10 +-- .../java/mage/server/game/GameController.java | 38 ++++----- ...ameSession.java => GameSessionPlayer.java} | 14 ++-- ...meWatcher.java => GameSessionWatcher.java} | 6 +- .../src/mage/sets/magic2011/MindRot.java | 2 +- .../sets/shadowmoor/CragganwickCremator.java | 22 ++--- .../common/discard/DiscardTargetEffect.java | 34 ++------ Mage/src/mage/game/GameImpl.java | 2 +- Mage/src/mage/players/PlayerImpl.java | 83 +++++++++---------- Mage/src/mage/target/TargetImpl.java | 1 + .../src/mage/target/common/TargetDiscard.java | 2 +- 20 files changed, 205 insertions(+), 163 deletions(-) rename Mage.Server/src/main/java/mage/server/game/{GameSession.java => GameSessionPlayer.java} (96%) rename Mage.Server/src/main/java/mage/server/game/{GameWatcher.java => GameSessionWatcher.java} (97%) diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 0d2786f5c9d..d4448864ba5 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -110,6 +110,7 @@ import static mage.constants.PhaseStep.FIRST_COMBAT_DAMAGE; import static mage.constants.PhaseStep.UNTAP; import static mage.constants.PhaseStep.UPKEEP; import mage.constants.PlayerAction; +import mage.constants.Zone; import mage.remote.Session; import mage.view.AbilityPickerView; import mage.view.CardView; @@ -813,6 +814,26 @@ public final class GamePanel extends javax.swing.JPanel { */ public void pickTarget(String message, CardsView cardView, GameView gameView, Set targets, boolean required, Map options, int messageId) { ShowCardsDialog dialog = null; + if (options != null && options.containsKey("targetZone")) { + if (Zone.HAND.equals(options.get("targetZone"))) { // mark selectable target cards in hand + List choosen = null; + if (options.containsKey("chosen")) { + choosen = (List) options.get("chosen"); + } + for(CardView card: gameView.getHand().values()) { + if (targets == null || targets.isEmpty()) { + card.setPlayable(false); + card.setChoosable(true); + } else if (targets.contains(card.getId())) { + card.setPlayable(false); + card.setChoosable(true); + } + if (choosen != null && choosen.contains(card.getId())) { + card.setSelected(true); + } + } + } + } updateGame(gameView); Map options0 = options == null ? new HashMap() : options; if (cardView != null && cardView.size() > 0) { diff --git a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java index 0c24fb445e5..cf22410c3cf 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java @@ -243,7 +243,7 @@ public class PlayerPanelExt extends javax.swing.JPanel { this.avatar.setTopText(priorityTimeValue); this.timerLabel.setText(priorityTimeValue); } - if (player.hasPriority()) { + if (player.isTimerActive()) { this.timer.resume(); } else { this.timer.pause(); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java index da70c0b103e..edded940b77 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java @@ -125,7 +125,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti private boolean isSelected; private boolean isPlayable; private boolean isChoosable; - private boolean canAttack; + private boolean canAttack; private boolean showCastingCost; private boolean hasImage = false; private float alpha = 1.0f; @@ -501,19 +501,17 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti } else if (isChoosable) { g2d.setColor(new Color(250, 250, 0, 230)); g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize); - } - - if (isPlayable) { - g2d.setColor(new Color(250, 250, 0, 200)); - g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize); + } else if (isPlayable) { + g2d.setColor(new Color(153, 102, 204, 200)); + //g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize); + g2d.fillRoundRect(cardXOffset, cardYOffset , cardWidth , cardHeight , cornerSize, cornerSize); } if (canAttack) { - g2d.setColor(new Color(255, 0, 0, 230)); + g2d.setColor(new Color(0, 0, 255, 230)); g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize); } - //TODO:uncomment /* if (gameCard.isAttacking()) { @@ -589,7 +587,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti ptText.setVisible(showText); int titleX = Math.round(cardWidth * (20f / 480)); - int titleY = Math.round(cardHeight * (9f / 680)) + 10; + int titleY = Math.round(cardHeight * (9f / 680)) + 10; // TODO: Set to 0 if it's a card selection with small card offset (ike library search) titleText.setBounds(cardXOffset + titleX, cardYOffset + titleY, cardWidth - titleX, cardHeight - titleY); Dimension ptSize = ptText.getPreferredSize(); @@ -803,6 +801,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti this.isPlayable = card.isPlayable(); this.isChoosable = card.isChoosable(); this.canAttack = card.isCanAttack(); + this.isSelected = card.isSelected(); boolean updateImage = !gameCard.getName().equals(card.getName()) || gameCard.isFaceDown() != card.isFaceDown(); // update after e.g. turning a night/day card this.gameCard = card; diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 352589f0988..6463a56376c 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -112,6 +112,7 @@ public class CardView extends SimpleCardView { protected boolean isPlayable; protected boolean isChoosable; + protected boolean selected; protected boolean canAttack; public CardView(Card card) { @@ -695,6 +696,18 @@ public class CardView extends SimpleCardView { public boolean isChoosable() { return isChoosable; } + + public void setChoosable(boolean isChoosable) { + this.isChoosable = isChoosable; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } public boolean isCanAttack() { return canAttack; diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/mage/view/PlayerView.java index 675c9d8a360..67379692644 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/mage/view/PlayerView.java @@ -60,6 +60,7 @@ public class PlayerView implements Serializable { private final int handCount; private final boolean isActive; private final boolean hasPriority; + private final boolean timerActive; private final boolean hasLeft; private final ManaPoolView manaPool; private final CardsView graveyard = new CardsView(); @@ -87,6 +88,10 @@ public class PlayerView implements Serializable { this.manaPool = new ManaPoolView(player.getManaPool()); this.isActive = (player.getId().equals(state.getActivePlayerId())); this.hasPriority = player.getId().equals(state.getPriorityPlayerId()); + this.priorityTimeLeft = player.getPriorityTimeLeft(); + this.timerActive = (this.hasPriority && player.isGameUnderControl()) || + (player.getPlayersUnderYourControl().contains(state.getPriorityPlayerId())); + this.hasLeft = player.hasLeft(); for (Card card: player.getGraveyard().getCards(game)) { graveyard.put(card.getId(), new CardView(card)); @@ -138,7 +143,6 @@ public class PlayerView implements Serializable { } this.statesSavedSize = player.getStoredBookmark(); - this.priorityTimeLeft = player.getPriorityTimeLeft(); this.passedTurn = player.getPassedTurn(); this.passedUntilEndOfTurn = player.getPassedUntilEndOfTurn(); @@ -244,6 +248,10 @@ public class PlayerView implements Serializable { return hasPriority; } + public boolean isTimerActive() { + return timerActive; + } + public boolean isPassedTurn() { return passedTurn; } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 8b6f711da1d..abb13ee7740 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -68,7 +68,7 @@ import java.util.concurrent.*; * * @author nantuko */ -public class ComputerPlayer6 extends ComputerPlayer implements Player { +public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { private static final transient org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ComputerPlayer6.class); private static final ExecutorService pool = Executors.newFixedThreadPool(1); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 53481ee802f..59bcc9b7ed9 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -93,9 +93,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 { @Override public boolean priority(Game game) { - game.resumeTimer(playerId); + game.resumeTimer(getTurnControlledBy()); boolean result = priorityPlay(game); - game.pauseTimer(playerId); + game.pauseTimer(getTurnControlledBy()); return result; } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 0687612cff9..e4c216e8426 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -165,7 +165,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (int i = unplayable.size() - 1; i >= 0; i--) { if (target.canTarget(unplayable.values().toArray(new Card[0])[i].getId(), game)) { target.add(unplayable.values().toArray(new Card[0])[i].getId(), game); - return true; + if (target.isChosen()) { + return true; + } } } } @@ -173,7 +175,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (int i = 0; i < hand.size(); i++) { if (target.canTarget(hand.toArray(new UUID[0])[i], game)) { target.add(hand.toArray(new UUID[0])[i], game); - return true; + if (target.isChosen()) { + return true; + } } } } @@ -749,10 +753,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public boolean priority(Game game) { - game.resumeTimer(playerId); + game.resumeTimer(getTurnControlledBy()); log.debug("priority"); boolean result = priorityPlay(game); - game.pauseTimer(playerId); + game.pauseTimer(getTurnControlledBy()); return result; } diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 6cbdf379e4b..0b4fc155a08 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -83,13 +83,9 @@ public class HumanPlayer extends PlayerImpl { protected static FilterBlockingCreature filterBlock = new FilterBlockingCreature(); protected static final Choice replacementEffectChoice = new ChoiceImpl(true); - private static final Map staticOptions = new HashMap<>(); - private static final Logger log = Logger.getLogger(HumanPlayer.class); - static { replacementEffectChoice.setMessage("Choose replacement effect to resolve first"); - staticOptions.put("UI.right.btn.text", "Done"); } protected HashSet autoSelectReplacementEffects = new HashSet<>(); @@ -106,7 +102,7 @@ public class HumanPlayer extends PlayerImpl { protected void waitForResponse(Game game) { response.clear(); log.debug("Waiting response from player: " + getId()); - game.resumeTimer(playerId); + game.resumeTimer(getTurnControlledBy()); synchronized(response) { try { response.wait(); @@ -114,7 +110,7 @@ public class HumanPlayer extends PlayerImpl { } catch (InterruptedException ex) { ex.printStackTrace(); } finally { - game.pauseTimer(playerId); + game.pauseTimer(getTurnControlledBy()); } } } @@ -236,7 +232,10 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { - updateGameStatePriority("choose(5)", game); + updateGameStatePriority("choose(5)", game); + if (options == null) { + options = new HashMap<>(); + } while (!abort) { Set targetIds = target.possibleTargets(sourceId, playerId, game); if (targetIds == null || targetIds.isEmpty()) { @@ -246,7 +245,11 @@ public class HumanPlayer extends PlayerImpl { if (target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } - game.fireSelectTargetEvent(playerId, target.getMessage(), targetIds, required, options); + + List chosen = target.getTargets(); + options.put("chosen", (Serializable)chosen); + + game.fireSelectTargetEvent(playerId, target.getMessage(), targetIds, required, getOptions(target, options)); waitForResponse(game); if (response.getUUID() != null) { if (!targetIds.contains(response.getUUID())) { @@ -263,16 +266,24 @@ public class HumanPlayer extends PlayerImpl { MageObject object = game.getObject(sourceId); if (object instanceof Ability) { if (target.canTarget(response.getUUID(), (Ability) object, game)) { - target.add(response.getUUID(), game); - if (target.doneChosing()) { - return true; + if (target.getTargets().contains(response.getUUID())) { // if already included remove it with + target.remove(response.getUUID()); + } else { + target.addTarget(response.getUUID(), (Ability)object, game); + if(target.doneChosing()){ + return true; + } } } } else { if (target.canTarget(response.getUUID(), game)) { - target.add(response.getUUID(), game); - if (target.doneChosing()) { - return true; + if (target.getTargets().contains(response.getUUID())) { // if already included remove it with + target.remove(response.getUUID()); + } else { + target.addTarget(response.getUUID(), null, game); + if(target.doneChosing()){ + return true; + } } } } @@ -299,7 +310,7 @@ public class HumanPlayer extends PlayerImpl { if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } - game.fireSelectTargetEvent(playerId, target.getMessage(), possibleTargets, required, getOptions(target)); + game.fireSelectTargetEvent(playerId, target.getMessage(), possibleTargets, required, getOptions(target, null)); waitForResponse(game); if (response.getUUID() != null) { if (possibleTargets.contains(response.getUUID())) { @@ -337,8 +348,15 @@ public class HumanPlayer extends PlayerImpl { return false; } - private Map getOptions(Target target) { - return target.getTargets().size() >= target.getNumberOfTargets() ? staticOptions : null; + private Map getOptions(Target target, Map options ) { + if (options == null) { + options = new HashMap<>(); + } + if (target.getTargets().size() >= target.getNumberOfTargets() && !options.containsKey("UI.right.btn.text")) { + options.put("UI.right.btn.text", "Done"); + } + options.put("targetZone", target.getZone()); + return options; } @Override @@ -358,11 +376,7 @@ public class HumanPlayer extends PlayerImpl { if (target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } - Map options = getOptions(target); - if (options == null) { - options = new HashMap<>(1); - } - + Map options = getOptions(target, null); List chosen = target.getTargets(); options.put("chosen", (Serializable)chosen); List choosable = new ArrayList<>(); @@ -416,7 +430,7 @@ public class HumanPlayer extends PlayerImpl { if (target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } - game.fireSelectTargetEvent(playerId, target.getMessage(), cards, required, null); + game.fireSelectTargetEvent(playerId, target.getMessage(), cards, required, getOptions(target, null)); waitForResponse(game); if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), cards, game)) { @@ -441,7 +455,10 @@ public class HumanPlayer extends PlayerImpl { public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { updateGameStatePriority("chooseTargetAmount", game); while (!abort) { - game.fireSelectTargetEvent(playerId, target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), target.possibleTargets(source==null?null:source.getSourceId(), playerId, game), target.isRequired(source), null); + game.fireSelectTargetEvent(playerId, target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), + target.possibleTargets(source==null?null:source.getSourceId(), playerId, game), + target.isRequired(source), + getOptions(target, null)); waitForResponse(game); if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), source, game)) { @@ -870,7 +887,7 @@ public class HumanPlayer extends PlayerImpl { protected void selectCombatGroup(UUID defenderId, UUID blockerId, Game game) { updateGameStatePriority("selectCombatGroup", game); TargetAttackingCreature target = new TargetAttackingCreature(); - game.fireSelectTargetEvent(playerId, "Select attacker to block", target.possibleTargets(null, playerId, game), false, null); + game.fireSelectTargetEvent(playerId, "Select attacker to block", target.possibleTargets(null, playerId, game), false, getOptions(target, null)); waitForResponse(game); if (response.getBoolean() != null) { // do nothing @@ -1128,8 +1145,10 @@ public class HumanPlayer extends PlayerImpl { } protected void updateGameStatePriority(String methodName, Game game) { - log.debug("Setting game priority to " + getId() + " [" + methodName + "]"); - game.getState().setPriorityPlayerId(getId()); + if (game.getState().getPriorityPlayerId() != null) { // don't do it if priority was set to null before (e.g. discard in cleanaup) + log.debug("Setting game priority to " + getId() + " [" + methodName + "]"); + game.getState().setPriorityPlayerId(getId()); + } } @Override diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 796c789b364..01525e1bfdb 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -44,7 +44,7 @@ import mage.interfaces.callback.ClientCallback; import mage.players.net.UserData; import mage.server.draft.DraftSession; import mage.server.game.GameManager; -import mage.server.game.GameSession; +import mage.server.game.GameSessionPlayer; import mage.server.tournament.TournamentSession; import mage.server.util.SystemUtil; import mage.view.TableClientMessage; @@ -68,7 +68,7 @@ public class User { private final String host; private final Date connectionTime; private final Map tables; - private final Map gameSessions; + private final Map gameSessions; private final Map draftSessions; private final Map tournamentSessions; private final Map constructing; @@ -269,7 +269,7 @@ public class User { entry.getValue().update(); } - for (Entry entry: gameSessions.entrySet()) { + for (Entry entry: gameSessions.entrySet()) { gameStarted(entry.getValue().getGameId(), entry.getKey()); entry.getValue().init(); GameManager.getInstance().sendPlayerString(entry.getValue().getGameId(), userId, ""); @@ -290,7 +290,7 @@ public class User { } } - public void addGame(UUID playerId, GameSession gameSession) { + public void addGame(UUID playerId, GameSessionPlayer gameSession) { gameSessions.put(playerId, gameSession); } @@ -336,7 +336,7 @@ public class User { public void remove(DisconnectReason reason) { logger.debug("REMOVE " + getName() + " Game sessions: " + gameSessions.size() ); - for (GameSession gameSession: gameSessions.values()) { + for (GameSessionPlayer gameSession: gameSessions.values()) { logger.debug("-- kill game session of gameId: " + gameSession.getGameId() ); gameSession.quitGame(); } diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 6ceb7164ddc..17812911b82 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -95,8 +95,8 @@ public class GameController implements GameCallback { private static final ExecutorService gameExecutor = ThreadExecutor.getInstance().getGameExecutor(); private static final Logger logger = Logger.getLogger(GameController.class); - private ConcurrentHashMap gameSessions = new ConcurrentHashMap<>(); - private ConcurrentHashMap watchers = new ConcurrentHashMap<>(); + private ConcurrentHashMap gameSessions = new ConcurrentHashMap<>(); + private ConcurrentHashMap watchers = new ConcurrentHashMap<>(); private ConcurrentHashMap timers = new ConcurrentHashMap<>(); private ConcurrentHashMap userPlayerMap; @@ -300,10 +300,10 @@ public class GameController implements GameCallback { logger.fatal("Player not found - playerId: " +playerId); return; } - GameSession gameSession = gameSessions.get(playerId); + GameSessionPlayer gameSession = gameSessions.get(playerId); String joinType; if (gameSession == null) { - gameSession = new GameSession(game, userId, playerId, useTimeout); + gameSession = new GameSessionPlayer(game, userId, playerId, useTimeout); gameSessions.put(playerId, gameSession); gameSession.setUserData(user.getUserData()); joinType = "joined"; @@ -318,7 +318,7 @@ public class GameController implements GameCallback { private synchronized void startGame() { if (gameFuture == null) { - for (final Entry entry: gameSessions.entrySet()) { + for (final Entry entry: gameSessions.entrySet()) { if (!entry.getValue().init()) { logger.fatal("Unable to initialize client"); //TODO: generate client error message @@ -363,7 +363,7 @@ public class GameController implements GameCallback { } User user = UserManager.getInstance().getUser(userId); if (user != null) { - GameWatcher gameWatcher = new GameWatcher(userId, game, false); + GameSessionWatcher gameWatcher = new GameSessionWatcher(userId, game, false); watchers.put(userId, gameWatcher); gameWatcher.init(); user.addGameWatchInfo(game.getId()); @@ -400,7 +400,7 @@ public class GameController implements GameCallback { public void quitMatch(UUID userId) { UUID playerId = getPlayerId(userId); if (playerId != null) { - GameSession gameSession = gameSessions.get(playerId); + GameSessionPlayer gameSession = gameSessions.get(playerId); if (gameSession != null) { gameSession.quitGame(); } @@ -456,7 +456,7 @@ public class GameController implements GameCallback { if (grantingPlayer != null) { if (!grantingPlayer.getUsersAllowedToSeeHandCards().contains(userIdRequester)) { if (grantingPlayer.isHuman()) { - GameSession gameSession = gameSessions.get(userIdGranter); + GameSessionPlayer gameSession = gameSessions.get(userIdGranter); if (gameSession != null) { UUID requestingPlayer = getPlayerId(userIdRequester); if (requestingPlayer == null || !requestingPlayer.equals(grantingPlayer.getId())) { // don't allow request for your own cards @@ -527,11 +527,11 @@ public class GameController implements GameCallback { } public void endGame(final String message) throws MageException { - for (final GameSession gameSession: gameSessions.values()) { + for (final GameSessionPlayer gameSession: gameSessions.values()) { gameSession.gameOver(message); gameSession.removeGame(); } - for (final GameWatcher gameWatcher: watchers.values()) { + for (final GameSessionWatcher gameWatcher: watchers.values()) { gameWatcher.gameOver(message); } TableManager.getInstance().endGame(tableId); @@ -601,10 +601,10 @@ public class GameController implements GameCallback { } } } - for (final GameSession gameSession: gameSessions.values()) { + for (final GameSessionPlayer gameSession: gameSessions.values()) { gameSession.update(); } - for (final GameWatcher gameWatcher: watchers.values()) { + for (final GameSessionWatcher gameWatcher: watchers.values()) { gameWatcher.update(); } } @@ -613,7 +613,7 @@ public class GameController implements GameCallback { Table table = TableManager.getInstance().getTable(tableId); if (table != null) { if (table.getMatch() != null) { - for (final GameSession gameSession: gameSessions.values()) { + for (final GameSessionPlayer gameSession: gameSessions.values()) { gameSession.endGameInfo(table); } } @@ -741,12 +741,12 @@ public class GameController implements GameCallback { message.append(game.getStep().getType().toString()).append(" - "); } message.append("Waiting for ").append(game.getPlayer(playerId).getName()); - for (final Entry entry: gameSessions.entrySet()) { + for (final Entry entry: gameSessions.entrySet()) { if (!entry.getKey().equals(playerId)) { entry.getValue().inform(message.toString()); } } - for (final GameWatcher watcher: watchers.values()) { + for (final GameSessionWatcher watcher: watchers.values()) { watcher.inform(message.toString()); } } @@ -761,7 +761,7 @@ public class GameController implements GameCallback { return; } final String message = new StringBuilder(game.getStep().getType().toString()).append(" - Waiting for ").append(controller.getName()).toString(); - for (final Entry entry: gameSessions.entrySet()) { + for (final Entry entry: gameSessions.entrySet()) { boolean skip = false; for (UUID uuid : players) { if (entry.getKey().equals(uuid)) { @@ -773,7 +773,7 @@ public class GameController implements GameCallback { entry.getValue().inform(message); } } - for (final GameWatcher watcher: watchers.values()) { + for (final GameSessionWatcher watcher: watchers.values()) { watcher.inform(message); } } @@ -795,7 +795,7 @@ public class GameController implements GameCallback { for (StackTraceElement e: ex.getStackTrace()) { sb.append(e.toString()).append("\n"); } - for (final Entry entry: gameSessions.entrySet()) { + for (final Entry entry: gameSessions.entrySet()) { entry.getValue().gameError(sb.toString()); } } @@ -898,7 +898,7 @@ public class GameController implements GameCallback { void execute(UUID player); } - private GameSession getGameSession(UUID playerId) { + private GameSessionPlayer getGameSession(UUID playerId) { if (!timers.isEmpty()) { Player player = game.getState().getPlayer(playerId); PriorityTimer timer = timers.get(playerId); diff --git a/Mage.Server/src/main/java/mage/server/game/GameSession.java b/Mage.Server/src/main/java/mage/server/game/GameSessionPlayer.java similarity index 96% rename from Mage.Server/src/main/java/mage/server/game/GameSession.java rename to Mage.Server/src/main/java/mage/server/game/GameSessionPlayer.java index 4ad4e26a202..16368364607 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameSession.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSessionPlayer.java @@ -49,6 +49,7 @@ import mage.game.Table; import mage.interfaces.callback.ClientCallback; import mage.players.Player; import mage.players.net.UserData; +import mage.server.Main; import mage.server.User; import mage.server.UserManager; import mage.server.util.ConfigSettings; @@ -66,9 +67,9 @@ import org.apache.log4j.Logger; * * @author BetaSteward_at_googlemail.com */ -public class GameSession extends GameWatcher { +public class GameSessionPlayer extends GameSessionWatcher { - private static final Logger logger = Logger.getLogger(GameSession.class); + private static final Logger logger = Logger.getLogger(GameSessionPlayer.class); private final UUID playerId; private final boolean useTimeout; @@ -79,7 +80,7 @@ public class GameSession extends GameWatcher { private UserData userData; - public GameSession(Game game, UUID userId, UUID playerId, boolean useTimeout) { + public GameSessionPlayer(Game game, UUID userId, UUID playerId, boolean useTimeout) { super(userId, game, true); this.playerId = playerId; this.useTimeout = useTimeout; @@ -228,7 +229,8 @@ public class GameSession extends GameWatcher { } } }, - ConfigSettings.getInstance().getMaxSecondsIdle(), TimeUnit.SECONDS + Main.isTestMode() ? 3600 :ConfigSettings.getInstance().getMaxSecondsIdle(), + TimeUnit.SECONDS ); } @@ -269,7 +271,9 @@ public class GameSession extends GameWatcher { player.setUserData(this.userData); GameView gameView = new GameView(game.getState(), game, playerId, null); gameView.setHand(new CardsView(player.getHand().getCards(game))); - gameView.setCanPlayInHand(player.getPlayableInHand(game)); + if (gameView.getPriorityPlayerName().equals(player.getName())) { + gameView.setCanPlayInHand(player.getPlayableInHand(game)); + } processControlledPlayers(player, gameView); processWatchedHands(userId, gameView); diff --git a/Mage.Server/src/main/java/mage/server/game/GameWatcher.java b/Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java similarity index 97% rename from Mage.Server/src/main/java/mage/server/game/GameWatcher.java rename to Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java index 177a81e2ee3..2464f19068a 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWatcher.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java @@ -47,16 +47,16 @@ import org.apache.log4j.Logger; * * @author BetaSteward_at_googlemail.com */ -public class GameWatcher { +public class GameSessionWatcher { - protected final static Logger logger = Logger.getLogger(GameWatcher.class); + protected final static Logger logger = Logger.getLogger(GameSessionWatcher.class); protected UUID userId; protected Game game; protected boolean killed = false; protected boolean isPlayer; - public GameWatcher(UUID userId, Game game, boolean isPlayer) { + public GameSessionWatcher(UUID userId, Game game, boolean isPlayer) { this.userId = userId; this.game = game; this.isPlayer = isPlayer; diff --git a/Mage.Sets/src/mage/sets/magic2011/MindRot.java b/Mage.Sets/src/mage/sets/magic2011/MindRot.java index b3e716dfc15..10e20fd7d86 100644 --- a/Mage.Sets/src/mage/sets/magic2011/MindRot.java +++ b/Mage.Sets/src/mage/sets/magic2011/MindRot.java @@ -34,7 +34,7 @@ import java.util.UUID; * * @author BetaSteward_at_googlemail.com */ -public class MindRot extends mage.sets.magic2010.MindRot { +public class MindRot extends mage.sets.tenth.MindRot { public MindRot(UUID ownerId) { super(ownerId); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java b/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java index 868cfd048d5..7260a7696d9 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/CragganwickCremator.java @@ -81,7 +81,7 @@ class CragganwickCrematorEffect extends OneShotEffect { public CragganwickCrematorEffect() { super(Outcome.Neutral); - this.staticText = "discard a card at random. If you discard a creature card this way, deals damage equal to that card's power to target player"; + this.staticText = "discard a card at random. If you discard a creature card this way, {this} deals damage equal to that card's power to target player"; } public CragganwickCrematorEffect(final CragganwickCrematorEffect effect) { @@ -97,20 +97,14 @@ class CragganwickCrematorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Player targetedPlayer = game.getPlayer(source.getFirstTarget()); - if (you != null) { - Effect discardEffect = new DiscardTargetEffect(1, true, true); - discardEffect.setTargetPointer(new FixedTarget(you.getId())); - if (discardEffect.apply(game, source)) { - Card discardedCard = game.getCard(this.getTargetPointer().getFirst(game, source)); - if (discardedCard != null - && discardedCard.getCardType().contains(CardType.CREATURE)) { - int damage = discardedCard.getPower().getValue(); - if (targetedPlayer != null) { - targetedPlayer.damage(damage, source.getSourceId(), game, false, true); - return true; - } - } + if (you != null && targetedPlayer != null) { + Card discardedCard = targetedPlayer.discardOne(true, source, game); + if (discardedCard != null + && discardedCard.getCardType().contains(CardType.CREATURE)) { + int damage = discardedCard.getPower().getValue(); + targetedPlayer.damage(damage, source.getSourceId(), game, false, true); } + return true; } return false; } diff --git a/Mage/src/mage/abilities/effects/common/discard/DiscardTargetEffect.java b/Mage/src/mage/abilities/effects/common/discard/DiscardTargetEffect.java index fe3981ac26f..2715350d8ae 100644 --- a/Mage/src/mage/abilities/effects/common/discard/DiscardTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/discard/DiscardTargetEffect.java @@ -31,13 +31,10 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; /** @@ -48,7 +45,6 @@ public class DiscardTargetEffect extends OneShotEffect { protected DynamicValue amount; protected boolean randomDiscard; - protected boolean setTargetPointer; public DiscardTargetEffect(DynamicValue amount) { this(amount, false); @@ -64,22 +60,22 @@ public class DiscardTargetEffect extends OneShotEffect { this(new StaticValue(amount)); } + /** + * + * @param amount amount of cards to discard + * @param randomDiscard discard the cards by random + * + */ public DiscardTargetEffect(int amount, boolean randomDiscard) { - this(new StaticValue(amount), randomDiscard); - } - - public DiscardTargetEffect(int amount, boolean randomDiscard, boolean setTargetPointer) { super(Outcome.Discard); this.randomDiscard = randomDiscard; this.amount = new StaticValue(amount); - this.setTargetPointer = setTargetPointer; } public DiscardTargetEffect(final DiscardTargetEffect effect) { super(effect); this.amount = effect.amount.copy(); this.randomDiscard = effect.randomDiscard; - this.setTargetPointer = effect.setTargetPointer; } @Override @@ -91,23 +87,7 @@ public class DiscardTargetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); if (player != null) { - if (randomDiscard) { - int maxAmount = Math.min(amount.calculate(game, source, this), player.getHand().size()); - for (int i = 0; i < maxAmount; i++) { - Card card = player.getHand().getRandom(game); - if (card != null) { - player.discard(card, source, game); - if (setTargetPointer) { - for (Effect effect : source.getEffects()) { - effect.setTargetPointer(new FixedTarget(card.getId())); - } - } - } - } - } else { - player.discard(amount.calculate(game, source, this), source, game); - } - + player.discard(amount.calculate(game, source, this), randomDiscard, source, game); return true; } return false; diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index ae08c1d4464..215d983e338 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -988,7 +988,7 @@ public abstract class GameImpl implements Game, Serializable { int deduction = 1; if (freeMulligans > 0) { if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { - int used = usedFreeMulligans.get(player.getId()).intValue(); + int used = usedFreeMulligans.get(player.getId()); if (used < freeMulligans ) { deduction = 0; } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 8afda7b2d19..05740b763a9 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -122,6 +122,7 @@ import mage.target.TargetCard; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetDiscard; +import mage.util.CardUtil; import mage.watchers.common.BloodthirstWatcher; import org.apache.log4j.Logger; @@ -563,6 +564,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public void setGameUnderYourControl(boolean value) { this.isGameUnderControl = value; + if (isGameUnderControl) { + this.turnController = getId(); + } } @Override @@ -623,12 +627,7 @@ public abstract class PlayerImpl implements Player, Serializable { public void discardToMax(Game game) { if (hand.size() > this.maxHandSize) { game.informPlayers(new StringBuilder(getName()).append(" discards down to ").append(this.maxHandSize).append(this.maxHandSize == 1?" hand card":" hand cards").toString()); - while (isInGame() && hand.size() > this.maxHandSize) { - TargetDiscard target = new TargetDiscard(playerId); - target.setTargetName(new StringBuilder(" card to discard (").append(hand.size() - this.maxHandSize).append(" in total)").toString()); - choose(Outcome.Discard, target, null, game); - discard(hand.get(target.getFirstTarget(), game), null, game); - } + discard(hand.size() - this.maxHandSize, null, game); } } @@ -682,21 +681,17 @@ public abstract class PlayerImpl implements Player, Serializable { } return discardedCards; } - int numDiscarded = 0; - while (isInGame() && numDiscarded < amount) { - if (this.getHand().size() == 0) { - break; + if (random) { + for (int i = 0; i < amount; i++) { + Card card = this.getHand().getRandom(game); + discardedCards.add(card); + discard(card, source, game); } - Card card; - if (random) { - card = this.getHand().getRandom(game); - } else { - TargetDiscard target = new TargetDiscard(playerId); - choose(Outcome.Discard, target, source.getSourceId(), game); - card = this.getHand().get(target.getFirstTarget(), game); - } - if (card != null) { - numDiscarded++; + } else { + TargetDiscard target = new TargetDiscard(amount, amount, new FilterCard(CardUtil.numberToText(amount, "a") + " card" + (amount > 1 ?"s":"")), playerId); + choose(Outcome.Discard, target, source == null?null:source.getSourceId(), game); + for (UUID cardId: target.getTargets()) { + Card card = this.getHand().get(cardId, game); discardedCards.add(card); discard(card, source, game); } @@ -2253,36 +2248,40 @@ public abstract class PlayerImpl implements Player, Serializable { return playable; } + /** + * Creates a list of card ids that are currently playable.
+ * Used to mark the playable cards in GameView + * + * @return A Set of cardIds that are playable + * @see mage.server.GameSessionPlayer#getGameView() + * + * @param game + + */ + @Override public Set getPlayableInHand(Game game) { Set playable = new HashSet<>(); if (!shouldSkipGettingPlayable(game)) { - // for clean_up phase show all cards - if (game.getPhase() != null && PhaseStep.CLEANUP.equals(game.getPhase().getStep().getType())) { - for (Card card: hand.getCards(game)) { - playable.add(card.getId()); - } - } else { - ManaOptions available = getManaAvailable(game); - available.addMana(manaPool.getMana()); + ManaOptions available = getManaAvailable(game); + available.addMana(manaPool.getMana()); - for (Card card : hand.getCards(game)) { - for (ActivatedAbility ability : card.getAbilities().getPlayableAbilities(Zone.HAND)) { - if (ability instanceof PlayLandAbility) { - if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) { - break; - } - } - if (canPlay(ability, available, card, game)) { - playable.add(card.getId()); + for (Card card : hand.getCards(game)) { + for (ActivatedAbility ability : card.getAbilities().getPlayableAbilities(Zone.HAND)) { + if (ability instanceof PlayLandAbility) { + if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) { break; } } - for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { - if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, card, game)) { - playable.add(card.getId()); - break; - } + if (canPlay(ability, available, card, game)) { + playable.add(card.getId()); + break; + } + } + for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { + if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, card, game)) { + playable.add(card.getId()); + break; } } } diff --git a/Mage/src/mage/target/TargetImpl.java b/Mage/src/mage/target/TargetImpl.java index d4ae6c750ad..440c545b0fb 100644 --- a/Mage/src/mage/target/TargetImpl.java +++ b/Mage/src/mage/target/TargetImpl.java @@ -28,6 +28,7 @@ package mage.target; +import java.io.Serializable; import mage.constants.Outcome; import mage.constants.Zone; import mage.abilities.Ability; diff --git a/Mage/src/mage/target/common/TargetDiscard.java b/Mage/src/mage/target/common/TargetDiscard.java index 05d12ff9f92..08de102e086 100644 --- a/Mage/src/mage/target/common/TargetDiscard.java +++ b/Mage/src/mage/target/common/TargetDiscard.java @@ -62,7 +62,7 @@ public class TargetDiscard extends TargetCard { super(minNumTargets, maxNumTargets, Zone.HAND, filter); this.filter.add(new OwnerIdPredicate(playerId)); this.playerId = playerId; - this.targetName = "card to discard"; + this.targetName = this.filter.getMessage() + " to discard"; } public TargetDiscard(final TargetDiscard target) {