diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java
index 1b07b0f4d5a..e1dd250beac 100644
--- a/forge-ai/src/main/java/forge/ai/AiAttackController.java
+++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java
@@ -394,7 +394,7 @@ public class AiAttackController {
}
for (Card attacker : oppList) {
- if (!CombatUtil.canAttackNextTurn(attacker)) {
+ if (!ComputerUtil.canAttackNextTurn(attacker)) {
continue;
}
if (blockersLeft > 0 && CombatUtil.canBeBlocked(attacker, ai)) {
@@ -657,7 +657,7 @@ public class AiAttackController {
for (final Card pCard : this.oppList) {
// if the creature can attack next turn add it to counter attackers
// list
- if (CombatUtil.canAttackNextTurn(pCard)) {
+ if (ComputerUtil.canAttackNextTurn(pCard)) {
nextTurnAttackers.add(pCard);
if (pCard.getNetCombatDamage() > 0) {
candidateCounterAttackDamage += pCard.getNetCombatDamage();
@@ -684,7 +684,7 @@ public class AiAttackController {
for (final Card pCard : this.myList) {
// if the creature can attack then it's a potential attacker this
// turn, assume summoning sickness creatures will be able to
- if (CombatUtil.canAttackNextTurn(pCard)) {
+ if (ComputerUtil.canAttackNextTurn(pCard)) {
candidateAttackers.add(pCard);
if (pCard.getNetCombatDamage() > 0) {
candidateUnblockedDamage += ComputerUtilCombat.damageIfUnblocked(pCard, opp, null);
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
index 6f6ceea1985..a0b5f377480 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
@@ -879,7 +879,7 @@ public class ComputerUtil {
playNow = false;
break;
}
- if (!playNow && c.isCreature() && CombatUtil.canAttackNextTurn(c) && c.canBeEquippedBy(card)) {
+ if (!playNow && c.isCreature() && ComputerUtil.canAttackNextTurn(c) && c.canBeEquippedBy(card)) {
playNow = true;
}
}
@@ -1980,5 +1980,18 @@ public class ComputerUtil {
return bestBoardPosition;
}
+
+ /**
+ *
+ * canAttackNextTurn.
+ *
+ *
+ * @param c
+ * a {@link forge.game.card.Card} object.
+ * @return a boolean.
+ */
+ public static boolean canAttackNextTurn(final Card c) {
+ return CombatUtil.canAttackNextTurn(c, c.getController().getOpponent());
+ }
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java
index d01f459877f..9fa5c4a62a2 100644
--- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java
@@ -616,7 +616,7 @@ public class AttachAi extends SpellAbilityAi {
prefList = CardLists.filter(prefList, new Predicate() {
@Override
public boolean apply(final Card c) {
- return CombatUtil.canAttackNextTurn(c) && c.getNetAttack() > 0;
+ return ComputerUtil.canAttackNextTurn(c) && c.getNetAttack() > 0;
}
});
}
@@ -945,7 +945,7 @@ public class AttachAi extends SpellAbilityAi {
if (!c.isCreature()) {
return true;
}
- return CombatUtil.canAttackNextTurn(c) && powerBonus + c.getNetAttack() > 0;
+ return ComputerUtil.canAttackNextTurn(c) && powerBonus + c.getNetAttack() > 0;
}
});
}
@@ -1133,7 +1133,7 @@ public class AttachAi extends SpellAbilityAi {
// give evasive keywords to creatures that can attack and deal damage
if (evasive) {
if (card.getNetCombatDamage() + powerBonus <= 0
- || !CombatUtil.canAttackNextTurn(card)
+ || !ComputerUtil.canAttackNextTurn(card)
|| !CombatUtil.canBeBlocked(card, opponent)) {
return false;
}
@@ -1142,20 +1142,20 @@ public class AttachAi extends SpellAbilityAi {
|| card.getNetCombatDamage() + powerBonus <= 0
|| card.hasKeyword("CARDNAME can attack as though it had haste.")
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
- || !CombatUtil.canAttackNextTurn(card)) {
+ || !ComputerUtil.canAttackNextTurn(card)) {
return false;
}
} else if (keyword.endsWith("Indestructible")) {
return true;
} else if (keyword.endsWith("Deathtouch") || keyword.endsWith("Wither")) {
if (card.getNetCombatDamage() + powerBonus <= 0
- || ((!CombatUtil.canBeBlocked(card, opponent) || !CombatUtil.canAttackNextTurn(card))
+ || ((!CombatUtil.canBeBlocked(card, opponent) || !ComputerUtil.canAttackNextTurn(card))
&& !CombatUtil.canBlock(card, true))) {
return false;
}
} else if (keyword.equals("Double Strike") || keyword.equals("Lifelink")) {
if (card.getNetCombatDamage() + powerBonus <= 0
- || (!CombatUtil.canAttackNextTurn(card) && !CombatUtil.canBlock(card, true))) {
+ || (!ComputerUtil.canAttackNextTurn(card) && !CombatUtil.canBlock(card, true))) {
return false;
}
} else if (keyword.equals("First Strike")) {
@@ -1164,29 +1164,29 @@ public class AttachAi extends SpellAbilityAi {
}
} else if (keyword.startsWith("Flanking")) {
if (card.getNetCombatDamage() + powerBonus <= 0
- || !CombatUtil.canAttackNextTurn(card)
+ || !ComputerUtil.canAttackNextTurn(card)
|| !CombatUtil.canBeBlocked(card, opponent)) {
return false;
}
} else if (keyword.startsWith("Bushido")) {
- if ((!CombatUtil.canBeBlocked(card, opponent) || !CombatUtil.canAttackNextTurn(card))
+ if ((!CombatUtil.canBeBlocked(card, opponent) || !ComputerUtil.canAttackNextTurn(card))
&& !CombatUtil.canBlock(card, true)) {
return false;
}
} else if (keyword.equals("Trample")) {
if (card.getNetCombatDamage() + powerBonus <= 1
|| !CombatUtil.canBeBlocked(card, opponent)
- || !CombatUtil.canAttackNextTurn(card)) {
+ || !ComputerUtil.canAttackNextTurn(card)) {
return false;
}
} else if (keyword.equals("Infect")) {
if (card.getNetCombatDamage() + powerBonus <= 0
- || !CombatUtil.canAttackNextTurn(card)) {
+ || !ComputerUtil.canAttackNextTurn(card)) {
return false;
}
} else if (keyword.equals("Vigilance")) {
if (card.getNetCombatDamage() + powerBonus <= 0
- || !CombatUtil.canAttackNextTurn(card)
+ || !ComputerUtil.canAttackNextTurn(card)
|| !CombatUtil.canBlock(card, true)) {
return false;
}
@@ -1231,11 +1231,11 @@ public class AttachAi extends SpellAbilityAi {
if (keyword.endsWith("CARDNAME can't attack.") || keyword.equals("Defender")
|| keyword.endsWith("CARDNAME can't attack or block.")) {
- if (!CombatUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) {
+ if (!ComputerUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) {
return false;
}
} else if (keyword.endsWith("CARDNAME attacks each turn if able.") || keyword.endsWith("CARDNAME attacks each combat if able.")) {
- if (!CombatUtil.canAttackNextTurn(card) || !CombatUtil.canBlock(card, true) || ai.getCreaturesInPlay().isEmpty()) {
+ if (!ComputerUtil.canAttackNextTurn(card) || !CombatUtil.canBlock(card, true) || ai.getCreaturesInPlay().isEmpty()) {
return false;
}
} else if (keyword.endsWith("CARDNAME can't block.") || keyword.contains("CantBlock")) {
@@ -1250,12 +1250,12 @@ public class AttachAi extends SpellAbilityAi {
}
return false;
} else if (keyword.endsWith("Prevent all combat damage that would be dealt by CARDNAME.")) {
- if (!CombatUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) {
+ if (!ComputerUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) {
return false;
}
} else if (keyword.endsWith("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")
|| keyword.endsWith("Prevent all damage that would be dealt to and dealt by CARDNAME.")) {
- if (!CombatUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 2) {
+ if (!ComputerUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 2) {
return false;
}
} else if (keyword.endsWith("CARDNAME doesn't untap during your untap step.")) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java b/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java
index 2b534df5d4a..25132e88b78 100644
--- a/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java
@@ -18,6 +18,8 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
+
+import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
@@ -78,7 +80,7 @@ public final class EncodeAi extends SpellAbilityAi {
final List attackers = CardLists.filter(options, new Predicate() {
@Override
public boolean apply(final Card c) {
- return CombatUtil.canAttackNextTurn(c);
+ return ComputerUtil.canAttackNextTurn(c);
}
});
final List unblockables = CardLists.filter(attackers, new Predicate() {
diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java
index fea78825b9c..18cbc5f7e77 100644
--- a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java
+++ b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java
@@ -235,7 +235,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|| newPower <= 0
|| card.hasKeyword("CARDNAME can attack as though it had haste.")
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
- || !CombatUtil.canAttackNextTurn(card)) {
+ || !ComputerUtil.canAttackNextTurn(card)) {
return false;
}
} else if (keyword.endsWith("Indestructible")) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java b/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java
index f946ec986d0..f788af69a22 100644
--- a/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java
@@ -2,6 +2,8 @@ package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+
+import forge.ai.ComputerUtil;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
import forge.game.card.Card;
@@ -83,7 +85,7 @@ public class TapAllAi extends SpellAbilityAi {
final boolean any = Iterables.any(validTappables, new Predicate() {
@Override
public boolean apply(final Card c) {
- return CombatUtil.canAttack(c) && CombatUtil.canAttackNextTurn(c);
+ return CombatUtil.canAttack(c) && ComputerUtil.canAttackNextTurn(c);
}
});
if(!any) {
diff --git a/forge-game/src/main/java/forge/game/combat/CombatUtil.java b/forge-game/src/main/java/forge/game/combat/CombatUtil.java
index 0ef7795ee36..9d83785c529 100644
--- a/forge-game/src/main/java/forge/game/combat/CombatUtil.java
+++ b/forge-game/src/main/java/forge/game/combat/CombatUtil.java
@@ -731,7 +731,7 @@ public class CombatUtil {
* @return a boolean.
*/
public static boolean canAttack(final Card c, final GameEntity def, final Combat combat) {
- int cntAttackers = combat.getAttackers().size();
+ final int cntAttackers = combat.getAttackers().size();
final Game game = c.getGame();
if (cntAttackers > 0) {
@@ -741,10 +741,6 @@ public class CombatUtil {
if (keyword.equals("No more than two creatures can attack each combat.")) {
return false;
}
- if (keyword.equals("No more than two creatures can attack you each combat.") &&
- card.getController().getOpponent().equals(c.getController())) {
- return false;
- }
}
if (keyword.equals("CARDNAME can only attack alone.") && combat.isAttacking(card)) {
return false;
@@ -761,6 +757,18 @@ public class CombatUtil {
}
}
+ final int cntAttackersToDef = combat.getAttackersOf(def).size();
+ if (cntAttackersToDef > 1) {
+ for (final Card card : game.getCardsIn(ZoneType.Battlefield)) {
+ for (final String keyword : card.getKeyword()) {
+ if (keyword.equals("No more than two creatures can attack you each combat.") &&
+ card.getController().equals(def)) {
+ return false;
+ }
+ }
+ }
+ }
+
if ((c.hasKeyword("CARDNAME can't attack or block alone.") || c.hasKeyword("CARDNAME can't attack alone."))
&& c.getController().getCreaturesInPlay().size() < 2) {
return false;
@@ -832,20 +840,8 @@ public class CombatUtil {
*
* @param c
* a {@link forge.game.card.Card} object.
- * @return a boolean.
- */
- public static boolean canAttackNextTurn(final Card c) {
- return canAttackNextTurn(c, c.getController().getOpponent());
- }
-
- // can a creature attack if untapped and without summoning sickness?
- /**
- *
- * canAttackNextTurn.
- *
- *
- * @param c
- * a {@link forge.game.card.Card} object.
+ * @param def
+ * the defending {@link GameEntity}.
* @return a boolean.
*/
public static boolean canAttackNextTurn(final Card c, final GameEntity defender) {