Merge branch 'blockfix' into 'master'

AiBlockController: fix for menace + trample

See merge request core-developers/forge!5614
This commit is contained in:
Michael Kamensky
2021-10-21 12:36:13 +00:00
16 changed files with 43 additions and 52 deletions

View File

@@ -185,7 +185,7 @@ public class AiBlockController {
List<Card> currentAttackers = new ArrayList<>(attackersLeft); List<Card> currentAttackers = new ArrayList<>(attackersLeft);
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() > 1) { if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > 1) {
continue; continue;
} }
@@ -296,7 +296,7 @@ public class AiBlockController {
// 6. Blockers that don't survive until the next turn anyway // 6. Blockers that don't survive until the next turn anyway
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() > 1) { if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > 1) {
continue; continue;
} }
@@ -537,7 +537,7 @@ public class AiBlockController {
// Try to block a Menace attacker with two blockers, neither of which will die // Try to block a Menace attacker with two blockers, neither of which will die
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() <= 1) { if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) <= 1) {
continue; continue;
} }
@@ -593,7 +593,7 @@ public class AiBlockController {
List<Card> killingBlockers; List<Card> killingBlockers;
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() > 1) { if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > 1) {
continue; continue;
} }
if (ComputerUtilCombat.attackerHasThreateningAfflict(attacker, ai)) { if (ComputerUtilCombat.attackerHasThreateningAfflict(attacker, ai)) {
@@ -642,7 +642,7 @@ public class AiBlockController {
Card attacker = attackers.get(0); Card attacker = attackers.get(0);
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() > 1 if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > 1
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.") || attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")
|| ComputerUtilCombat.attackerHasThreateningAfflict(attacker, ai)) { || ComputerUtilCombat.attackerHasThreateningAfflict(attacker, ai)) {
attackers.remove(0); attackers.remove(0);
@@ -691,7 +691,7 @@ public class AiBlockController {
List<Card> currentAttackers = new ArrayList<>(attackersLeft); List<Card> currentAttackers = new ArrayList<>(attackersLeft);
for (final Card attacker : currentAttackers) { for (final Card attacker : currentAttackers) {
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() <= 1) { if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) <= 1) {
continue; continue;
} }
List<Card> possibleBlockers = getPossibleBlockers(combat, attacker, blockersLeft, true); List<Card> possibleBlockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
@@ -729,8 +729,7 @@ public class AiBlockController {
// "Whenever CARDNAME becomes blocked, it gets +1/+1 until end of turn for each creature blocking it." // "Whenever CARDNAME becomes blocked, it gets +1/+1 until end of turn for each creature blocking it."
for (final Card attacker : tramplingAttackers) { for (final Card attacker : tramplingAttackers) {
if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > combat.getBlockers(attacker).size()
if (((StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, combat.getDefenderPlayerByAttacker(attacker)).getLeft() > 1) && !combat.isBlocked(attacker))
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.") || attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")
|| attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) { || attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) {
continue; continue;
@@ -829,7 +828,7 @@ public class AiBlockController {
AiController aic = ((PlayerControllerAi) ai.getController()).getAi(); AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
final int evalThresholdToken = aic.getIntProperty(AiProps.THRESHOLD_TOKEN_CHUMP_TO_SAVE_PLANESWALKER); final int evalThresholdToken = aic.getIntProperty(AiProps.THRESHOLD_TOKEN_CHUMP_TO_SAVE_PLANESWALKER);
final int evalThresholdNonToken = aic.getIntProperty(AiProps.THRESHOLD_TOKEN_CHUMP_TO_SAVE_PLANESWALKER); final int evalThresholdNonToken = aic.getIntProperty(AiProps.THRESHOLD_NONTOKEN_CHUMP_TO_SAVE_PLANESWALKER);
final boolean onlyIfLethal = aic.getBooleanProperty(AiProps.CHUMP_TO_SAVE_PLANESWALKER_ONLY_ON_LETHAL); final boolean onlyIfLethal = aic.getBooleanProperty(AiProps.CHUMP_TO_SAVE_PLANESWALKER_ONLY_ON_LETHAL);
if (evalThresholdToken > 0 || evalThresholdNonToken > 0) { if (evalThresholdToken > 0 || evalThresholdNonToken > 0) {

View File

@@ -1776,8 +1776,7 @@ public class ComputerUtilCombat {
return true; return true;
} }
// Attacker may kill the blocker before he can deal normal // Attacker may kill the blocker before he can deal normal (secondary) damage
// (secondary) damage
if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat) if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) { && !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
if (attackerDamage >= defenderLife) { if (attackerDamage >= defenderLife) {
@@ -1828,7 +1827,7 @@ public class ComputerUtilCombat {
* @return a boolean. * @return a boolean.
*/ */
public static boolean blockerWouldBeDestroyed(Player ai, final Card blocker, Combat combat) { public static boolean blockerWouldBeDestroyed(Player ai, final Card blocker, Combat combat) {
// TODO THis function only checks if a single attacker at a time would destroy a blocker // TODO This function only checks if a single attacker at a time would destroy a blocker
// This needs to expand to tally up damage // This needs to expand to tally up damage
final List<Card> attackers = combat.getAttackersBlockedBy(blocker); final List<Card> attackers = combat.getAttackersBlockedBy(blocker);
@@ -2010,8 +2009,7 @@ public class ComputerUtilCombat {
return true; return true;
} }
// Attacker may kill the blocker before he can deal normal // Attacker may kill the blocker before he can deal normal (secondary) damage
// (secondary) damage
if (dealsFirstStrikeDamage(blocker, withoutAbilities, combat) if (dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
&& !attacker.hasKeyword(Keyword.INDESTRUCTIBLE)) { && !attacker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
if (defenderDamage >= attackerLife) { if (defenderDamage >= attackerLife) {

View File

@@ -413,7 +413,7 @@ public class SpecialCardAi {
if (!isBlocking && combat.getDefenderByAttacker(source) instanceof Card) { if (!isBlocking && combat.getDefenderByAttacker(source) instanceof Card) {
int loyalty = combat.getDefenderByAttacker(source).getCounters(CounterEnumType.LOYALTY); int loyalty = combat.getDefenderByAttacker(source).getCounters(CounterEnumType.LOYALTY);
int totalDamageToPW = 0; int totalDamageToPW = 0;
for (Card atk : (combat.getAttackersOf(combat.getDefenderByAttacker(source)))) { for (Card atk :combat.getAttackersOf(combat.getDefenderByAttacker(source))) {
if (combat.isUnblocked(atk)) { if (combat.isUnblocked(atk)) {
totalDamageToPW += atk.getNetCombatDamage(); totalDamageToPW += atk.getNetCombatDamage();
} }

View File

@@ -26,7 +26,7 @@ public class PlayAi extends SpellAbilityAi {
@Override @Override
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {
final String logic = sa.hasParam("AILogic") ? sa.getParam("AILogic") : ""; final String logic = sa.getParamOrDefault("AILogic", "");
final Game game = ai.getGame(); final Game game = ai.getGame();
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();

View File

@@ -121,7 +121,7 @@ public class SacrificeAi extends SpellAbilityAi {
// Only cast it if Human has the full amount of valid // Only cast it if Human has the full amount of valid
// Only cast it if AI doesn't have the full amount of Valid // Only cast it if AI doesn't have the full amount of Valid
// TODO: Cast if the type is favorable: my "worst" valid is worse than his "worst" valid // TODO: Cast if the type is favorable: my "worst" valid is worse than his "worst" valid
final String num = sa.hasParam("Amount") ? sa.getParam("Amount") : "1"; final String num = sa.getParamOrDefault("Amount", "1");
int amount = AbilityUtils.calculateAmount(source, num, sa); int amount = AbilityUtils.calculateAmount(source, num, sa);
if (num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) { if (num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) {

View File

@@ -1482,7 +1482,7 @@ public class AbilityUtils {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
// The player who has the chance to cancel the ability // The player who has the chance to cancel the ability
final String pays = sa.hasParam("UnlessPayer") ? sa.getParam("UnlessPayer") : "TargetedController"; final String pays = sa.getParamOrDefault("UnlessPayer", "TargetedController");
final FCollectionView<Player> allPayers = getDefinedPlayers(sa.getHostCard(), pays, sa); final FCollectionView<Player> allPayers = getDefinedPlayers(sa.getHostCard(), pays, sa);
final String resolveSubs = sa.getParam("UnlessResolveSubs"); // no value means 'Always' final String resolveSubs = sa.getParam("UnlessResolveSubs"); // no value means 'Always'
final boolean execSubsWhenPaid = "WhenPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs); final boolean execSubsWhenPaid = "WhenPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs);
@@ -1565,7 +1565,7 @@ public class AbilityUtils {
" ", ""), sa); " ", ""), sa);
//Check for XColor //Check for XColor
ManaCostBeingPaid toPay = new ManaCostBeingPaid(ManaCost.ZERO); ManaCostBeingPaid toPay = new ManaCostBeingPaid(ManaCost.ZERO);
byte xColor = ManaAtom.fromName(sa.hasParam("UnlessXColor") ? sa.getParam("UnlessXColor") : "1"); byte xColor = ManaAtom.fromName(sa.getParamOrDefault("UnlessXColor", "1"));
toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost); toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost);
cost = new Cost(toPay.toManaCost(), true); cost = new Cost(toPay.toManaCost(), true);
} }

View File

@@ -261,7 +261,7 @@ public abstract class SpellAbilityEffect {
boolean your = location.startsWith("Your"); boolean your = location.startsWith("Your");
boolean combat = location.endsWith("Combat"); boolean combat = location.endsWith("Combat");
String desc = sa.hasParam("AtEOTDesc") ? sa.getParam("AtEOTDesc") : ""; String desc = sa.getParamOrDefault("AtEOTDesc", "");
if (your) { if (your) {
location = location.substring("Your".length()); location = location.substring("Your".length());

View File

@@ -33,7 +33,7 @@ public class BalanceEffect extends SpellAbilityEffect {
Player activator = sa.getActivatingPlayer(); Player activator = sa.getActivatingPlayer();
Card source = sa.getHostCard(); Card source = sa.getHostCard();
Game game = activator.getGame(); Game game = activator.getGame();
String valid = sa.hasParam("Valid") ? sa.getParam("Valid") : "Card"; String valid = sa.getParamOrDefault("Valid", "Card");
ZoneType zone = sa.hasParam("Zone") ? ZoneType.smartValueOf(sa.getParam("Zone")) : ZoneType.Battlefield; ZoneType zone = sa.hasParam("Zone") ? ZoneType.smartValueOf(sa.getParam("Zone")) : ZoneType.Battlefield;
int min = Integer.MAX_VALUE; int min = Integer.MAX_VALUE;

View File

@@ -182,7 +182,7 @@ public class DiscardEffect extends SpellAbilityEffect {
boolean runDiscard = !sa.hasParam("Optional") || p.getController().confirmAction(sa, PlayerActionConfirmMode.Random, message); boolean runDiscard = !sa.hasParam("Optional") || p.getController().confirmAction(sa, PlayerActionConfirmMode.Random, message);
if (runDiscard) { if (runDiscard) {
final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; final String valid = sa.getParamOrDefault("DiscardValid", "Card");
List<Card> list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), valid, source.getController(), source, sa); List<Card> list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), valid, source.getController(), source, sa);
list = CardLists.filter(list, Presets.NON_TOKEN); list = CardLists.filter(list, Presets.NON_TOKEN);
CardCollection toDiscard = new CardCollection(); CardCollection toDiscard = new CardCollection();
@@ -250,7 +250,7 @@ public class DiscardEffect extends SpellAbilityEffect {
dPHand = p.getController().chooseCardsToRevealFromHand(amount, amount, dPHand); dPHand = p.getController().chooseCardsToRevealFromHand(amount, amount, dPHand);
} }
final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; final String valid = sa.getParamOrDefault("DiscardValid", "Card");
String[] dValid = valid.split(","); String[] dValid = valid.split(",");
CardCollection validCards = CardLists.getValidCards(dPHand, dValid, source.getController(), source, sa); CardCollection validCards = CardLists.getValidCards(dPHand, dValid, source.getController(), source, sa);

View File

@@ -220,7 +220,7 @@ public class FlipCoinEffect extends SpellAbilityEffect {
* @return a boolean. * @return a boolean.
*/ */
public static boolean flipCoinCall(final Player caller, final SpellAbility sa, final int multiplier) { public static boolean flipCoinCall(final Player caller, final SpellAbility sa, final int multiplier) {
String varName = sa.hasParam("SaveNumFlipsToSVar") ? sa.getParam("SaveNumFlipsToSVar") : "X"; String varName = sa.getParamOrDefault("SaveNumFlipsToSVar", "X");
return flipCoinCall(caller, sa, multiplier, varName); return flipCoinCall(caller, sa, multiplier, varName);
} }
public static boolean flipCoinCall(final Player caller, final SpellAbility sa, final int multiplier, final String varName) { public static boolean flipCoinCall(final Player caller, final SpellAbility sa, final int multiplier, final String varName) {

View File

@@ -15,7 +15,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
final Player player = sa.getActivatingPlayer(); final Player player = sa.getActivatingPlayer();
final Game game = player.getGame(); final Game game = player.getGame();
String name = sa.hasParam("Name") ? sa.getParam("Name") : sa.getHostCard().getName(); String name = sa.getParamOrDefault("Name", sa.getHostCard().getName());
if (name.equals("ChosenName")) { if (name.equals("ChosenName")) {
name = sa.getHostCard().getChosenName(); name = sa.getHostCard().getChosenName();
} }

View File

@@ -292,7 +292,7 @@ public class PumpEffect extends SpellAbilityEffect {
} }
} }
if (sa.hasParam("RandomKeyword")) { if (sa.hasParam("RandomKeyword")) {
final String num = sa.hasParam("RandomKWNum") ? sa.getParam("RandomKWNum") : "1"; final String num = sa.getParamOrDefault("RandomKWNum", "1");
final int numkw = AbilityUtils.calculateAmount(host, num, sa); final int numkw = AbilityUtils.calculateAmount(host, num, sa);
List<String> choice = Lists.newArrayList(); List<String> choice = Lists.newArrayList();
List<String> total = Lists.newArrayList(keywords); List<String> total = Lists.newArrayList(keywords);

View File

@@ -32,7 +32,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
ZoneType leaveZone = ZoneType.smartValueOf(sa.hasParam("RestrictFromZone") ? sa.getParam("RestrictFromZone") : null); ZoneType leaveZone = ZoneType.smartValueOf(sa.hasParam("RestrictFromZone") ? sa.getParam("RestrictFromZone") : null);
restartZones.remove(leaveZone); restartZones.remove(leaveZone);
String leaveRestriction = sa.hasParam("RestrictFromValid") ? sa.getParam("RestrictFromValid") : "Card"; String leaveRestriction = sa.getParamOrDefault("RestrictFromValid", "Card");
//Card.resetUniqueNumber(); //Card.resetUniqueNumber();
// need this code here, otherwise observables fail // need this code here, otherwise observables fail

View File

@@ -26,7 +26,6 @@ public class AttackingBand {
public void addAttacker(Card card) { attackers.add(card); } public void addAttacker(Card card) { attackers.add(card); }
public void removeAttacker(Card card) { attackers.remove(card); } public void removeAttacker(Card card) { attackers.remove(card); }
public static boolean isValidBand(List<Card> band, boolean shareDamage) { public static boolean isValidBand(List<Card> band, boolean shareDamage) {
if (band.isEmpty()) { if (band.isEmpty()) {
// An empty band is not a valid band // An empty band is not a valid band
@@ -73,7 +72,6 @@ public class AttackingBand {
return isValidBand(newBand, false); return isValidBand(newBand, false);
} }
public boolean contains(Card c) { public boolean contains(Card c) {
return attackers.contains(c); return attackers.contains(c);
} }

View File

@@ -345,13 +345,6 @@ public class Combat {
return result; return result;
} }
public final CardCollection getBlockers(final Card card) {
// If requesting the ordered blocking list pass true, directly.
AttackingBand band = getBandOfAttacker(card);
Collection<Card> blockers = blockedBands.get(band);
return blockers == null ? new CardCollection() : new CardCollection(blockers);
}
public final boolean isBlocked(final Card attacker) { public final boolean isBlocked(final Card attacker) {
AttackingBand band = getBandOfAttacker(attacker); AttackingBand band = getBandOfAttacker(attacker);
return band != null && Boolean.TRUE.equals(band.isBlocked()); return band != null && Boolean.TRUE.equals(band.isBlocked());
@@ -408,6 +401,10 @@ public class Combat {
return result; return result;
} }
public final CardCollection getBlockers(final Card card) {
// If requesting the ordered blocking list pass true, directly.
return getBlockers(getBandOfAttacker(card));
}
public final CardCollection getBlockers(final AttackingBand band) { public final CardCollection getBlockers(final AttackingBand band) {
Collection<Card> blockers = blockedBands.get(band); Collection<Card> blockers = blockedBands.get(band);
return blockers == null ? new CardCollection() : new CardCollection(blockers); return blockers == null ? new CardCollection() : new CardCollection(blockers);
@@ -512,8 +509,7 @@ public class Combat {
final CardCollection oldBlockers = blockersOrderedForDamageAssignment.get(attacker); final CardCollection oldBlockers = blockersOrderedForDamageAssignment.get(attacker);
if (oldBlockers == null || oldBlockers.isEmpty()) { if (oldBlockers == null || oldBlockers.isEmpty()) {
blockersOrderedForDamageAssignment.put(attacker, new CardCollection(blocker)); blockersOrderedForDamageAssignment.put(attacker, new CardCollection(blocker));
} } else {
else {
CardCollection orderedBlockers = playerWhoAttacks.getController().orderBlocker(attacker, blocker, oldBlockers); CardCollection orderedBlockers = playerWhoAttacks.getController().orderBlocker(attacker, blocker, oldBlockers);
blockersOrderedForDamageAssignment.put(attacker, orderedBlockers); blockersOrderedForDamageAssignment.put(attacker, orderedBlockers);
} }

View File

@@ -501,7 +501,7 @@ public class CombatUtil {
return true; return true;
} }
if ( combat != null ) { if (combat != null) {
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defendingPlayer).getRight() == combat.getBlockers(attacker).size()) { if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defendingPlayer).getRight() == combat.getBlockers(attacker).size()) {
return false; return false;
} }
@@ -763,7 +763,7 @@ public class CombatUtil {
for (final Card attacker : attackers) { for (final Card attacker : attackers) {
if (canBlock(attacker, blocker, combat)) { if (canBlock(attacker, blocker, combat)) {
boolean must = true; boolean must = true;
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defending).getLeft() > 1) { if (getMinNumBlockersForAttacker(attacker, defending) > 1) {
final List<Card> possibleBlockers = Lists.newArrayList(defendersArmy); final List<Card> possibleBlockers = Lists.newArrayList(defendersArmy);
possibleBlockers.remove(blocker); possibleBlockers.remove(blocker);
if (!canBeBlocked(attacker, possibleBlockers, combat)) { if (!canBeBlocked(attacker, possibleBlockers, combat)) {
@@ -875,7 +875,7 @@ public class CombatUtil {
Player defendingPlayer = combat.getDefenderPlayerByAttacker(attacker); Player defendingPlayer = combat.getDefenderPlayerByAttacker(attacker);
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defendingPlayer).getLeft() > 1) { if (getMinNumBlockersForAttacker(attacker, defendingPlayer) > 1) {
final List<Card> blockers = defendingPlayer.getCreaturesInPlay(); final List<Card> blockers = defendingPlayer.getCreaturesInPlay();
blockers.remove(blocker); blockers.remove(blocker);
if (!canBeBlocked(attacker, blockers, combat)) { if (!canBeBlocked(attacker, blockers, combat)) {
@@ -894,7 +894,7 @@ public class CombatUtil {
&& combat.isAttacking(attacker)) { && combat.isAttacking(attacker)) {
boolean canBe = true; boolean canBe = true;
Player defendingPlayer = combat.getDefenderPlayerByAttacker(attacker); Player defendingPlayer = combat.getDefenderPlayerByAttacker(attacker);
if (StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defendingPlayer).getLeft() > 1) { if (getMinNumBlockersForAttacker(attacker, defendingPlayer) > 1) {
final List<Card> blockers = freeBlockers != null ? new CardCollection(freeBlockers) : defendingPlayer.getCreaturesInPlay(); final List<Card> blockers = freeBlockers != null ? new CardCollection(freeBlockers) : defendingPlayer.getCreaturesInPlay();
blockers.remove(blocker); blockers.remove(blocker);
if (!canBeBlocked(attacker, blockers, combat)) { if (!canBeBlocked(attacker, blockers, combat)) {
@@ -1099,4 +1099,4 @@ public class CombatUtil {
public static int getMinNumBlockersForAttacker(Card attacker, Player defender) { public static int getMinNumBlockersForAttacker(Card attacker, Player defender) {
return StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defender).getLeft(); return StaticAbilityCantAttackBlock.getMinMaxBlocker(attacker, defender).getLeft();
} }
} // end class CombatUtil }