mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
- Fix Crawlspace in multiplayer
- Move a method using getOpponent() to AI (only place it's used, to group the methods using this deprecated function in the AI code)
This commit is contained in:
@@ -394,7 +394,7 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Card attacker : oppList) {
|
for (Card attacker : oppList) {
|
||||||
if (!CombatUtil.canAttackNextTurn(attacker)) {
|
if (!ComputerUtil.canAttackNextTurn(attacker)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (blockersLeft > 0 && CombatUtil.canBeBlocked(attacker, ai)) {
|
if (blockersLeft > 0 && CombatUtil.canBeBlocked(attacker, ai)) {
|
||||||
@@ -657,7 +657,7 @@ public class AiAttackController {
|
|||||||
for (final Card pCard : this.oppList) {
|
for (final Card pCard : this.oppList) {
|
||||||
// if the creature can attack next turn add it to counter attackers
|
// if the creature can attack next turn add it to counter attackers
|
||||||
// list
|
// list
|
||||||
if (CombatUtil.canAttackNextTurn(pCard)) {
|
if (ComputerUtil.canAttackNextTurn(pCard)) {
|
||||||
nextTurnAttackers.add(pCard);
|
nextTurnAttackers.add(pCard);
|
||||||
if (pCard.getNetCombatDamage() > 0) {
|
if (pCard.getNetCombatDamage() > 0) {
|
||||||
candidateCounterAttackDamage += pCard.getNetCombatDamage();
|
candidateCounterAttackDamage += pCard.getNetCombatDamage();
|
||||||
@@ -684,7 +684,7 @@ public class AiAttackController {
|
|||||||
for (final Card pCard : this.myList) {
|
for (final Card pCard : this.myList) {
|
||||||
// if the creature can attack then it's a potential attacker this
|
// if the creature can attack then it's a potential attacker this
|
||||||
// turn, assume summoning sickness creatures will be able to
|
// turn, assume summoning sickness creatures will be able to
|
||||||
if (CombatUtil.canAttackNextTurn(pCard)) {
|
if (ComputerUtil.canAttackNextTurn(pCard)) {
|
||||||
candidateAttackers.add(pCard);
|
candidateAttackers.add(pCard);
|
||||||
if (pCard.getNetCombatDamage() > 0) {
|
if (pCard.getNetCombatDamage() > 0) {
|
||||||
candidateUnblockedDamage += ComputerUtilCombat.damageIfUnblocked(pCard, opp, null);
|
candidateUnblockedDamage += ComputerUtilCombat.damageIfUnblocked(pCard, opp, null);
|
||||||
|
|||||||
@@ -879,7 +879,7 @@ public class ComputerUtil {
|
|||||||
playNow = false;
|
playNow = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!playNow && c.isCreature() && CombatUtil.canAttackNextTurn(c) && c.canBeEquippedBy(card)) {
|
if (!playNow && c.isCreature() && ComputerUtil.canAttackNextTurn(c) && c.canBeEquippedBy(card)) {
|
||||||
playNow = true;
|
playNow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1981,4 +1981,17 @@ public class ComputerUtil {
|
|||||||
return bestBoardPosition;
|
return bestBoardPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* canAttackNextTurn.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -616,7 +616,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final Card c) {
|
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()) {
|
if (!c.isCreature()) {
|
||||||
return true;
|
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
|
// give evasive keywords to creatures that can attack and deal damage
|
||||||
if (evasive) {
|
if (evasive) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| !CombatUtil.canAttackNextTurn(card)
|
|| !ComputerUtil.canAttackNextTurn(card)
|
||||||
|| !CombatUtil.canBeBlocked(card, opponent)) {
|
|| !CombatUtil.canBeBlocked(card, opponent)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1142,20 +1142,20 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|| card.getNetCombatDamage() + powerBonus <= 0
|
|| card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| card.hasKeyword("CARDNAME can attack as though it had haste.")
|
|| card.hasKeyword("CARDNAME can attack as though it had haste.")
|
||||||
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||||
|| !CombatUtil.canAttackNextTurn(card)) {
|
|| !ComputerUtil.canAttackNextTurn(card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.endsWith("Indestructible")) {
|
} else if (keyword.endsWith("Indestructible")) {
|
||||||
return true;
|
return true;
|
||||||
} else if (keyword.endsWith("Deathtouch") || keyword.endsWith("Wither")) {
|
} else if (keyword.endsWith("Deathtouch") || keyword.endsWith("Wither")) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| ((!CombatUtil.canBeBlocked(card, opponent) || !CombatUtil.canAttackNextTurn(card))
|
|| ((!CombatUtil.canBeBlocked(card, opponent) || !ComputerUtil.canAttackNextTurn(card))
|
||||||
&& !CombatUtil.canBlock(card, true))) {
|
&& !CombatUtil.canBlock(card, true))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Double Strike") || keyword.equals("Lifelink")) {
|
} else if (keyword.equals("Double Strike") || keyword.equals("Lifelink")) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| (!CombatUtil.canAttackNextTurn(card) && !CombatUtil.canBlock(card, true))) {
|
|| (!ComputerUtil.canAttackNextTurn(card) && !CombatUtil.canBlock(card, true))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("First Strike")) {
|
} else if (keyword.equals("First Strike")) {
|
||||||
@@ -1164,29 +1164,29 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
} else if (keyword.startsWith("Flanking")) {
|
} else if (keyword.startsWith("Flanking")) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| !CombatUtil.canAttackNextTurn(card)
|
|| !ComputerUtil.canAttackNextTurn(card)
|
||||||
|| !CombatUtil.canBeBlocked(card, opponent)) {
|
|| !CombatUtil.canBeBlocked(card, opponent)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.startsWith("Bushido")) {
|
} 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)) {
|
&& !CombatUtil.canBlock(card, true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Trample")) {
|
} else if (keyword.equals("Trample")) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 1
|
if (card.getNetCombatDamage() + powerBonus <= 1
|
||||||
|| !CombatUtil.canBeBlocked(card, opponent)
|
|| !CombatUtil.canBeBlocked(card, opponent)
|
||||||
|| !CombatUtil.canAttackNextTurn(card)) {
|
|| !ComputerUtil.canAttackNextTurn(card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Infect")) {
|
} else if (keyword.equals("Infect")) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| !CombatUtil.canAttackNextTurn(card)) {
|
|| !ComputerUtil.canAttackNextTurn(card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Vigilance")) {
|
} else if (keyword.equals("Vigilance")) {
|
||||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||||
|| !CombatUtil.canAttackNextTurn(card)
|
|| !ComputerUtil.canAttackNextTurn(card)
|
||||||
|| !CombatUtil.canBlock(card, true)) {
|
|| !CombatUtil.canBlock(card, true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1231,11 +1231,11 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
if (keyword.endsWith("CARDNAME can't attack.") || keyword.equals("Defender")
|
if (keyword.endsWith("CARDNAME can't attack.") || keyword.equals("Defender")
|
||||||
|| keyword.endsWith("CARDNAME can't attack or block.")) {
|
|| keyword.endsWith("CARDNAME can't attack or block.")) {
|
||||||
if (!CombatUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) {
|
if (!ComputerUtil.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.endsWith("CARDNAME attacks each turn if able.") || keyword.endsWith("CARDNAME attacks each combat if able.")) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.endsWith("CARDNAME can't block.") || keyword.contains("CantBlock")) {
|
} else if (keyword.endsWith("CARDNAME can't block.") || keyword.contains("CantBlock")) {
|
||||||
@@ -1250,12 +1250,12 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (keyword.endsWith("Prevent all combat damage that would be dealt by CARDNAME.")) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.endsWith("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")
|
} 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.")) {
|
|| 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;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.endsWith("CARDNAME doesn't untap during your untap step.")) {
|
} else if (keyword.endsWith("CARDNAME doesn't untap during your untap step.")) {
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
package forge.ai.ability;
|
package forge.ai.ability;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
|
import forge.ai.ComputerUtil;
|
||||||
import forge.ai.ComputerUtilCard;
|
import forge.ai.ComputerUtilCard;
|
||||||
import forge.ai.SpellAbilityAi;
|
import forge.ai.SpellAbilityAi;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -78,7 +80,7 @@ public final class EncodeAi extends SpellAbilityAi {
|
|||||||
final List<Card> attackers = CardLists.filter(options, new Predicate<Card>() {
|
final List<Card> attackers = CardLists.filter(options, new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final Card c) {
|
public boolean apply(final Card c) {
|
||||||
return CombatUtil.canAttackNextTurn(c);
|
return ComputerUtil.canAttackNextTurn(c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
final List<Card> unblockables = CardLists.filter(attackers, new Predicate<Card>() {
|
final List<Card> unblockables = CardLists.filter(attackers, new Predicate<Card>() {
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
|||||||
|| newPower <= 0
|
|| newPower <= 0
|
||||||
|| card.hasKeyword("CARDNAME can attack as though it had haste.")
|
|| card.hasKeyword("CARDNAME can attack as though it had haste.")
|
||||||
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||||
|| !CombatUtil.canAttackNextTurn(card)) {
|
|| !ComputerUtil.canAttackNextTurn(card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.endsWith("Indestructible")) {
|
} else if (keyword.endsWith("Indestructible")) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package forge.ai.ability;
|
|||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
import forge.ai.ComputerUtil;
|
||||||
import forge.ai.SpellAbilityAi;
|
import forge.ai.SpellAbilityAi;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -83,7 +85,7 @@ public class TapAllAi extends SpellAbilityAi {
|
|||||||
final boolean any = Iterables.any(validTappables, new Predicate<Card>() {
|
final boolean any = Iterables.any(validTappables, new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final Card c) {
|
public boolean apply(final Card c) {
|
||||||
return CombatUtil.canAttack(c) && CombatUtil.canAttackNextTurn(c);
|
return CombatUtil.canAttack(c) && ComputerUtil.canAttackNextTurn(c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(!any) {
|
if(!any) {
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ public class CombatUtil {
|
|||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public static boolean canAttack(final Card c, final GameEntity def, final Combat combat) {
|
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();
|
final Game game = c.getGame();
|
||||||
|
|
||||||
if (cntAttackers > 0) {
|
if (cntAttackers > 0) {
|
||||||
@@ -741,10 +741,6 @@ public class CombatUtil {
|
|||||||
if (keyword.equals("No more than two creatures can attack each combat.")) {
|
if (keyword.equals("No more than two creatures can attack each combat.")) {
|
||||||
return false;
|
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)) {
|
if (keyword.equals("CARDNAME can only attack alone.") && combat.isAttacking(card)) {
|
||||||
return false;
|
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."))
|
if ((c.hasKeyword("CARDNAME can't attack or block alone.") || c.hasKeyword("CARDNAME can't attack alone."))
|
||||||
&& c.getController().getCreaturesInPlay().size() < 2) {
|
&& c.getController().getCreaturesInPlay().size() < 2) {
|
||||||
return false;
|
return false;
|
||||||
@@ -832,20 +840,8 @@ public class CombatUtil {
|
|||||||
*
|
*
|
||||||
* @param c
|
* @param c
|
||||||
* a {@link forge.game.card.Card} object.
|
* a {@link forge.game.card.Card} object.
|
||||||
* @return a boolean.
|
* @param def
|
||||||
*/
|
* the defending {@link GameEntity}.
|
||||||
public static boolean canAttackNextTurn(final Card c) {
|
|
||||||
return canAttackNextTurn(c, c.getController().getOpponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
// can a creature attack if untapped and without summoning sickness?
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* canAttackNextTurn.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param c
|
|
||||||
* a {@link forge.game.card.Card} object.
|
|
||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public static boolean canAttackNextTurn(final Card c, final GameEntity defender) {
|
public static boolean canAttackNextTurn(final Card c, final GameEntity defender) {
|
||||||
|
|||||||
Reference in New Issue
Block a user