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 fb19b6707df..4370c59f4a8 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -696,6 +696,13 @@ public final class GamePanel extends javax.swing.JPanel { } } + List possibleBlockers = new ArrayList<>(); + if (options != null && options.containsKey(Constants.Option.POSSIBLE_BLOCKERS)) { + if (options.get(Constants.Option.POSSIBLE_BLOCKERS) instanceof List) { + possibleBlockers.addAll((List) options.get(Constants.Option.POSSIBLE_BLOCKERS)); + } + } + for (PlayerView player : game.getPlayers()) { if (players.containsKey(player.getPlayerId())) { if (!possibleAttackers.isEmpty()) { @@ -705,6 +712,13 @@ public final class GamePanel extends javax.swing.JPanel { } } } + if (!possibleBlockers.isEmpty()) { + for (UUID permanentId : possibleBlockers) { + if (player.getBattlefield().containsKey(permanentId)) { + player.getBattlefield().get(permanentId).setCanBlock(true); + } + } + } players.get(player.getPlayerId()).update(player); if (player.getPlayerId().equals(playerId)) { skipButtons.updateFromPlayer(player); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java index bdfde25d5c3..a237318a174 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java @@ -1,17 +1,5 @@ package org.mage.card.arcane; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.StringTokenizer; -import java.util.UUID; - -import javax.swing.*; - -import org.apache.log4j.Logger; -import org.jdesktop.swingx.graphics.GraphicsUtilities; -import org.mage.plugins.card.images.ImageCache; -import org.mage.plugins.card.utils.impl.ImageManagerImpl; - import mage.cards.action.ActionCallback; import mage.client.constants.Constants; import mage.client.dialog.PreferencesDialog; @@ -25,6 +13,16 @@ import mage.view.CardView; import mage.view.CounterView; import mage.view.PermanentView; import mage.view.StackAbilityView; +import org.apache.log4j.Logger; +import org.jdesktop.swingx.graphics.GraphicsUtilities; +import org.mage.plugins.card.images.ImageCache; +import org.mage.plugins.card.utils.impl.ImageManagerImpl; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.StringTokenizer; +import java.util.UUID; /** * Class for drawing the mage card object by using a form based JComponent @@ -117,8 +115,9 @@ public class CardPanelComponentImpl extends CardPanel { final boolean isChoosable; final boolean isPlayable; final boolean canAttack; + final boolean canBlock; - public Key(int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack) { + public Key(int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack, boolean canBlock) { this.width = width; this.height = height; this.cardWidth = cardWidth; @@ -130,6 +129,7 @@ public class CardPanelComponentImpl extends CardPanel { this.isChoosable = isChoosable; this.isPlayable = isPlayable; this.canAttack = canAttack; + this.canBlock = canBlock; } @Override @@ -146,6 +146,7 @@ public class CardPanelComponentImpl extends CardPanel { hash = 19 * hash + (this.isChoosable ? 1 : 0); hash = 19 * hash + (this.isPlayable ? 1 : 0); hash = 19 * hash + (this.canAttack ? 1 : 0); + hash = 19 * hash + (this.canBlock ? 1 : 0); return hash; } @@ -194,7 +195,7 @@ public class CardPanelComponentImpl extends CardPanel { if (this.canAttack != other.canAttack) { return false; } - return true; + return this.canBlock == other.canBlock; } } @@ -202,20 +203,20 @@ public class CardPanelComponentImpl extends CardPanel { IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(CardPanelComponentImpl::createImage)); } - static private boolean canShowCardIcons(int cardFullWidth, boolean cardHasImage){ + static private boolean canShowCardIcons(int cardFullWidth, boolean cardHasImage) { // cards without images show icons and text always // TODO: apply "card names on card" setting to icon too? // TODO: fix card min-max size to hide (compare to settings size, not direct 60 and 200) return ((cardFullWidth > 60) && (cardFullWidth < 200)) || (!cardHasImage); } - private static class CardSizes{ + private static class CardSizes { Rectangle rectFull; Rectangle rectSelection; Rectangle rectBorder; Rectangle rectCard; - CardSizes(int offsetX, int offsetY, int fullWidth, int fullHeight){ + CardSizes(int offsetX, int offsetY, int fullWidth, int fullHeight) { int realBorderSizeX = Math.round(fullWidth * BLACK_BORDER_SIZE); int realBorderSizeY = Math.round(fullWidth * BLACK_BORDER_SIZE); @@ -406,7 +407,8 @@ public class CardPanelComponentImpl extends CardPanel { g2d.drawImage( IMAGE_CACHE.getOrThrow( new Key(getWidth(), getHeight(), getCardWidth(), getCardHeight(), getCardXOffset(), getCardYOffset(), - hasImage, isSelected(), isChoosable(), getGameCard().isPlayable(), getGameCard().isCanAttack())), + hasImage, isSelected(), isChoosable(), getGameCard().isPlayable(), getGameCard().isCanAttack(), + getGameCard().isCanBlock())), 0, 0, null); g2d.dispose(); } @@ -442,6 +444,12 @@ public class CardPanelComponentImpl extends CardPanel { g2d.fillRoundRect(sizes.rectSelection.x, sizes.rectSelection.y, sizes.rectSelection.width, sizes.rectSelection.height, cornerSizeSelection, cornerSizeSelection); } + // draw attack or block border (?inner part of selection?) + if (key.canAttack || key.canBlock) { + g2d.setColor(new Color(255, 50, 50, 230)); + g2d.fillRoundRect(sizes.rectSelection.x + 1, sizes.rectSelection.y + 1, sizes.rectSelection.width - 2, sizes.rectSelection.height - 2, cornerSizeSelection, cornerSizeSelection); + } + // draw empty card with border if (!key.hasImage) { // gray 1 px border @@ -452,12 +460,6 @@ public class CardPanelComponentImpl extends CardPanel { g2d.fillRoundRect(sizes.rectBorder.x + 1, sizes.rectBorder.y + 1, sizes.rectBorder.width - 2, sizes.rectBorder.height - 2, cornerSizeBorder, cornerSizeBorder); } - // draw attack border (inner part of selection) - if (key.canAttack) { - g2d.setColor(new Color(0, 0, 255, 230)); - g2d.fillRoundRect(sizes.rectBorder.x + 1, sizes.rectBorder.y + 1, sizes.rectBorder.width - 2, sizes.rectBorder.height - 2, cornerSizeBorder, cornerSizeBorder); - } - // draw real card by component (see imagePanel and other layout's items) //TODO:uncomment @@ -521,7 +523,7 @@ public class CardPanelComponentImpl extends CardPanel { StringTokenizer tok = new StringTokenizer(manaCost, " "); while (tok.hasMoreTokens()) { tok.nextToken(); - if(width != 0) { + if (width != 0) { width += symbolMarginX; } width += getSymbolWidth(); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java index b00b0e5c521..cf62e7cb439 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java @@ -1,17 +1,7 @@ package org.mage.card.arcane; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.UUID; -import java.util.concurrent.ExecutionException; - -import org.apache.log4j.Logger; -import org.jdesktop.swingx.graphics.GraphicsUtilities; -import org.mage.plugins.card.images.ImageCache; - import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; - import mage.cards.action.ActionCallback; import mage.client.constants.Constants; import mage.constants.CardType; @@ -21,6 +11,14 @@ import mage.view.CardView; import mage.view.CounterView; import mage.view.PermanentView; import mage.view.StackAbilityView; +import org.apache.log4j.Logger; +import org.jdesktop.swingx.graphics.GraphicsUtilities; +import org.mage.plugins.card.images.ImageCache; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.UUID; +import java.util.concurrent.ExecutionException; public class CardPanelRenderImpl extends CardPanel { @@ -107,9 +105,7 @@ public class CardPanelRenderImpl extends CardPanel { // are the same for a and b return false; } - if (aa.getDamage() != bb.getDamage()) { - return false; - } + return aa.getDamage() == bb.getDamage(); } return true; } @@ -143,6 +139,7 @@ public class CardPanelRenderImpl extends CardPanel { sb.append((char) (isChoosable ? 1 : 0)); sb.append((char) (this.view.isPlayable() ? 1 : 0)); sb.append((char) (this.view.isCanAttack() ? 1 : 0)); + sb.append((char) (this.view.isCanBlock() ? 1 : 0)); sb.append((char) (this.view.isFaceDown() ? 1 : 0)); sb.append((char) this.view.getFrameStyle().ordinal()); if (this.view instanceof PermanentView) { @@ -266,8 +263,8 @@ public class CardPanelRenderImpl extends CardPanel { // Try to get card image from cache based on our card characteristics ImageKey key = new ImageKey(getGameCard(), artImage, - getCardWidth(), getCardHeight(), - isChoosable(), isSelected()); + getCardWidth(), getCardHeight(), + isChoosable(), isSelected()); try { cardImage = IMAGE_CACHE.get(key, this::renderCard); } catch (ExecutionException e) { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java index baab2a7858d..d70f8fea3ed 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java @@ -5,24 +5,6 @@ */ package org.mage.card.arcane; -import java.awt.*; -import java.awt.font.*; -import java.awt.geom.Arc2D; -import java.awt.geom.Area; -import java.awt.geom.Path2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; -import java.text.CharacterIterator; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import javax.swing.*; import mage.ObjectColor; import mage.cards.ArtRect; import mage.cards.FrameStyle; @@ -34,6 +16,22 @@ import mage.util.SubTypeList; import mage.view.CardView; import mage.view.PermanentView; import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.text.CharacterIterator; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol; @@ -56,9 +54,10 @@ import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol; render.draw(g, cardWidth, cardHeight); } */ + /** * @author stravant@gmail.com - * + *

* Base rendering class for new border cards */ public class ModernCardRenderer extends CardRenderer { @@ -98,6 +97,7 @@ public class ModernCardRenderer extends CardRenderer { } return new Font("Arial", Font.PLAIN, 1); } + public static final Font BASE_BELEREN_FONT = loadFont("beleren-bold"); public static final Paint BG_TEXTURE_WHITE = loadBackgroundTexture("white"); @@ -275,7 +275,9 @@ public class ModernCardRenderer extends CardRenderer { } else if (cardView.isPlayable()) { borderColor = new Color(153, 102, 204, 200); } else if (cardView.isCanAttack()) { - borderColor = new Color(0, 0, 255, 230); + borderColor = new Color(255, 50, 50, 230); + } else if (cardView.isCanBlock()) { + borderColor = new Color(255, 50, 50, 230); } else { borderColor = Color.BLACK; } @@ -659,7 +661,7 @@ public class ModernCardRenderer extends CardRenderer { } public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, - Color boxColor, Paint paint) { + Color boxColor, Paint paint) { BufferedImage artToUse = faceArtImage; boolean hadToUseFullArt = false; @@ -707,8 +709,8 @@ public class ModernCardRenderer extends CardRenderer { } public void drawBFZCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, - int topxdelta, int endydelta, - Color boxColor, Paint paint) { + int topxdelta, int endydelta, + Color boxColor, Paint paint) { BufferedImage artToUse = faceArtImage; boolean hadToUseFullArt = false; if (faceArtImage == null) { @@ -764,10 +766,10 @@ public class ModernCardRenderer extends CardRenderer { } public void drawUSTCurves(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, - int topxdelta, int endydelta, - Color boxColor, Paint paint) { + int topxdelta, int endydelta, + Color boxColor, Paint paint) { BufferedImage artToUse = artImage; - + int srcW = x2; int srcH = y2; if (artToUse != null) { @@ -999,23 +1001,23 @@ public class ModernCardRenderer extends CardRenderer { Polygon symbol = new Polygon( new int[]{ - x + w / 2, - (int) (x + w * 0.9), - x + w, - (int) (x + w * 0.6), - x + w / 2, - (int) (x + w * 0.4), - x, - (int) (x + w * 0.1),}, + x + w / 2, + (int) (x + w * 0.9), + x + w, + (int) (x + w * 0.6), + x + w / 2, + (int) (x + w * 0.4), + x, + (int) (x + w * 0.1),}, new int[]{ - y + h, - (int) (y + 0.8 * h), - y, - (int) (y - 0.2 * h), - y, - (int) (y - 0.2 * h), - y, - (int) (y + 0.8 * h),}, + y + h, + (int) (y + 0.8 * h), + y, + (int) (y - 0.2 * h), + y, + (int) (y - 0.2 * h), + y, + (int) (y + 0.8 * h),}, 8); // Draw + stroke @@ -1124,7 +1126,7 @@ public class ModernCardRenderer extends CardRenderer { drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); return; } else // Big circle in the middle for Zendikar lands - if (allRules.size() == 1) { + if (allRules.size() == 1) { // Size of mana symbol = 9/4 * h, 3/4h above line if (allRules.get(0) instanceof TextboxBasicManaRule) { drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); @@ -1278,45 +1280,45 @@ public class ModernCardRenderer extends CardRenderer { if (loyaltyRule.loyaltyChange < 0 || loyaltyRule.loyaltyChange == TextboxLoyaltyRule.MINUS_X) { symbol = new Polygon( new int[]{ - symbolX, - symbolX + symbolWidth, - symbolX + symbolWidth, - symbolX + symbolWidth / 2, - symbolX,}, + symbolX, + symbolX + symbolWidth, + symbolX + symbolWidth, + symbolX + symbolWidth / 2, + symbolX,}, new int[]{ - symbolY, - symbolY, - symbolY + symbolHeight - 3, - symbolY + symbolHeight + 3, - symbolY + symbolHeight - 3,}, + symbolY, + symbolY, + symbolY + symbolHeight - 3, + symbolY + symbolHeight + 3, + symbolY + symbolHeight - 3,}, 5); } else if (loyaltyRule.loyaltyChange > 0) { symbol = new Polygon( new int[]{ - symbolX, - symbolX + symbolWidth / 2, - symbolX + symbolWidth, - symbolX + symbolWidth, - symbolX,}, + symbolX, + symbolX + symbolWidth / 2, + symbolX + symbolWidth, + symbolX + symbolWidth, + symbolX,}, new int[]{ - symbolY + 3, - symbolY - 3, - symbolY + 3, - symbolY + symbolHeight, - symbolY + symbolHeight,}, + symbolY + 3, + symbolY - 3, + symbolY + 3, + symbolY + symbolHeight, + symbolY + symbolHeight,}, 5); } else { symbol = new Polygon( new int[]{ - symbolX, - symbolX + symbolWidth, - symbolX + symbolWidth, - symbolX,}, + symbolX, + symbolX + symbolWidth, + symbolX + symbolWidth, + symbolX,}, new int[]{ - symbolY, - symbolY, - symbolY + symbolHeight, - symbolY + symbolHeight,}, + symbolY, + symbolY, + symbolY + symbolHeight, + symbolY + symbolHeight,}, 4); } g.setColor(new Color(0, 0, 0, 128)); @@ -1610,13 +1612,13 @@ public class ModernCardRenderer extends CardRenderer { Color[] translatedColors; if (types.contains(CardType.LAND)) { translatedColors = new Color[]{ - getLandTextboxColor(twoColors.get(0)), - getLandTextboxColor(twoColors.get(1)) + getLandTextboxColor(twoColors.get(0)), + getLandTextboxColor(twoColors.get(1)) }; } else { translatedColors = new Color[]{ - getTextboxColor(twoColors.get(0)), - getTextboxColor(twoColors.get(1)) + getTextboxColor(twoColors.get(0)), + getTextboxColor(twoColors.get(1)) }; } diff --git a/Mage.Common/src/main/java/mage/constants/Constants.java b/Mage.Common/src/main/java/mage/constants/Constants.java index dbcc0301015..400b9df9eff 100644 --- a/Mage.Common/src/main/java/mage/constants/Constants.java +++ b/Mage.Common/src/main/java/mage/constants/Constants.java @@ -1,8 +1,6 @@ - package mage.constants; /** - * * @author BetaSteward_at_googlemail.com */ public final class Constants { @@ -50,19 +48,14 @@ public final class Constants { */ public static final int PRIORITY_TIME_SEC = 1200; - - public enum Option { - ; - public static final String POSSIBLE_ATTACKERS = "possibleAttackers"; + public static final String POSSIBLE_BLOCKERS = "possibleBlockers"; public static final String SPECIAL_BUTTON = "specialButton"; // used to control automatic answers of optional effects public static final String ORIGINAL_ID = "originalId"; public static final String SECOND_MESSAGE = "secondMessage"; public static final String HINT_TEXT = "hintText"; - } - } diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 69b8cd568b8..8505589a475 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -1,4 +1,3 @@ - package mage.view; import com.google.gson.annotations.Expose; @@ -109,6 +108,7 @@ public class CardView extends SimpleCardView { protected boolean isChoosable; protected boolean selected; protected boolean canAttack; + protected boolean canBlock; protected boolean inViewerOnly; protected Card originalCard = null; @@ -202,6 +202,7 @@ public class CardView extends SimpleCardView { this.isChoosable = cardView.isChoosable; this.selected = cardView.selected; this.canAttack = cardView.canAttack; + this.canBlock = cardView.canBlock; this.inViewerOnly = cardView.inViewerOnly; this.originalCard = cardView.originalCard.copy(); } @@ -286,7 +287,7 @@ public class CardView extends SimpleCardView { this.power = Integer.toString(card.getPower().getValue()); this.toughness = Integer.toString(card.getToughness().getValue()); this.cardTypes = card.getCardType(); - this.faceDown = ((Permanent) card).isFaceDown(game); + this.faceDown = card.isFaceDown(game); } else { // this.hideInfo = true; return; @@ -296,9 +297,9 @@ public class CardView extends SimpleCardView { SplitCard splitCard = null; if (card.isSplitCard()) { splitCard = (SplitCard) card; - rotate = (((SplitCard) card).getSpellAbility().getSpellAbilityType()) != SpellAbilityType.SPLIT_AFTERMATH; + rotate = (card.getSpellAbility().getSpellAbilityType()) != SpellAbilityType.SPLIT_AFTERMATH; } else if (card instanceof Spell) { - switch (((Spell) card).getSpellAbility().getSpellAbilityType()) { + switch (card.getSpellAbility().getSpellAbilityType()) { case SPLIT_FUSED: splitCard = (SplitCard) ((Spell) card).getCard(); rotate = true; @@ -390,12 +391,12 @@ public class CardView extends SimpleCardView { this.cardNumber = ((PermanentToken) card).getToken().getOriginalCardNumber(); } else { // a created token - this.expansionSetCode = ((PermanentToken) card).getExpansionSetCode(); - this.tokenDescriptor = ((PermanentToken) card).getTokenDescriptor(); + this.expansionSetCode = card.getExpansionSetCode(); + this.tokenDescriptor = card.getTokenDescriptor(); } // // set code und card number for token copies to get the image - this.rules = ((PermanentToken) card).getRules(game); + this.rules = card.getRules(game); this.type = ((PermanentToken) card).getToken().getTokenType(); } else { this.rarity = card.getRarity(); @@ -995,6 +996,14 @@ public class CardView extends SimpleCardView { this.canAttack = canAttack; } + public boolean isCanBlock() { + return canBlock; + } + + public void setCanBlock(boolean canBlock) { + this.canBlock = canBlock; + } + public boolean isCreature() { return cardTypes.contains(CardType.CREATURE); } 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 a476ee084f0..f55aea830f4 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 @@ -51,6 +51,7 @@ import java.io.Serializable; import java.util.List; import java.util.Queue; import java.util.*; +import java.util.stream.Collectors; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL; import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL; @@ -1432,7 +1433,12 @@ public class HumanPlayer extends PlayerImpl { while (!abort) { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectEvent(playerId, "Select blockers"); + Map options = new HashMap<>(); + List possibleBlockers = game.getBattlefield().getActivePermanents(filter, playerId, game).stream() + .map(p -> p.getId()) + .collect(Collectors.toList()); + options.put(Constants.Option.POSSIBLE_BLOCKERS, (Serializable) possibleBlockers); + game.fireSelectEvent(playerId, "Select blockers", options); } waitForResponse(game); if (response.getBoolean() != null) { @@ -1504,9 +1510,21 @@ public class HumanPlayer extends PlayerImpl { TargetAttackingCreature target = new TargetAttackingCreature(); prepareForResponse(game); if (!isExecutingMacro()) { + // possible attackers to block + Set attackers = target.possibleTargets(null, playerId, game); + Permanent blocker = game.getPermanent(blockerId); + Set possibleTargets = new HashSet<>(); + for (UUID attackerId : attackers) { + CombatGroup group = game.getCombat().findGroup(attackerId); + if (group != null && blocker != null && group.canBlock(blocker, game)) { + possibleTargets.add(attackerId); + } + } + game.fireSelectTargetEvent(playerId, new MessageToClient("Select attacker to block", getRelatedObjectName(blockerId, game)), - target.possibleTargets(null, playerId, game), false, getOptions(target, null)); + possibleTargets, false, getOptions(target, null)); } + waitForResponse(game); if (response.getBoolean() != null) { // do nothing