mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge branch 'fixup' into 'master'
CombatUtil: Fix AI workaround See merge request core-developers/forge!4726
This commit is contained in:
@@ -54,7 +54,6 @@ import forge.util.TextUtil;
|
|||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
|
|
||||||
|
|
||||||
//doesHumanAttackAndWin() uses the global variable AllZone.getComputerPlayer()
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* ComputerUtil_Attack2 class.
|
* ComputerUtil_Attack2 class.
|
||||||
@@ -412,12 +411,10 @@ public class AiAttackController {
|
|||||||
|
|
||||||
final Player opp = this.defendingOpponent;
|
final Player opp = this.defendingOpponent;
|
||||||
|
|
||||||
// Increase the total number of blockers needed by 1 if Finest Hour in
|
// Increase the total number of blockers needed by 1 if Finest Hour in play
|
||||||
// play
|
|
||||||
// (human will get an extra first attack with a creature that untaps)
|
// (human will get an extra first attack with a creature that untaps)
|
||||||
// In addition, if the computer guesses it needs no blockers, make sure
|
// In addition, if the computer guesses it needs no blockers, make sure
|
||||||
// that
|
// that it won't be surprised by Exalted
|
||||||
// it won't be surprised by Exalted
|
|
||||||
final int humanExaltedBonus = opp.countExaltedBonus();
|
final int humanExaltedBonus = opp.countExaltedBonus();
|
||||||
|
|
||||||
if (humanExaltedBonus > 0) {
|
if (humanExaltedBonus > 0) {
|
||||||
@@ -448,7 +445,6 @@ public class AiAttackController {
|
|||||||
return notNeededAsBlockers;
|
return notNeededAsBlockers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this uses a global variable, which isn't perfect
|
|
||||||
public final boolean doesHumanAttackAndWin(final Player ai, final int nBlockingCreatures) {
|
public final boolean doesHumanAttackAndWin(final Player ai, final int nBlockingCreatures) {
|
||||||
int totalAttack = 0;
|
int totalAttack = 0;
|
||||||
int totalPoison = 0;
|
int totalPoison = 0;
|
||||||
@@ -715,7 +711,7 @@ public class AiAttackController {
|
|||||||
int attackMax = restrict.getMax();
|
int attackMax = restrict.getMax();
|
||||||
if (attackMax == -1) {
|
if (attackMax == -1) {
|
||||||
// check with the local limitations vs. the chosen defender
|
// check with the local limitations vs. the chosen defender
|
||||||
attackMax = ComputerUtilCombat.getMaxAttackersFor(defender);
|
attackMax = restrict.getDefenderMax().get(defender) == null ? -1 : restrict.getDefenderMax().get(defender);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attackMax == 0) {
|
if (attackMax == 0) {
|
||||||
@@ -775,7 +771,6 @@ public class AiAttackController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (bAssault) {
|
if (bAssault) {
|
||||||
if (LOG_AI_ATTACKS)
|
if (LOG_AI_ATTACKS)
|
||||||
System.out.println("Assault");
|
System.out.println("Assault");
|
||||||
@@ -850,7 +845,6 @@ public class AiAttackController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// *******************
|
// *******************
|
||||||
// Evaluate the creature forces
|
// Evaluate the creature forces
|
||||||
// *******************
|
// *******************
|
||||||
@@ -1291,8 +1285,8 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (numberOfPossibleBlockers > 2
|
if (numberOfPossibleBlockers > 2
|
||||||
|| (numberOfPossibleBlockers >= 1 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 1, combat))
|
|| (numberOfPossibleBlockers >= 1 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 1, this.defendingOpponent))
|
||||||
|| (numberOfPossibleBlockers == 2 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 2, combat))) {
|
|| (numberOfPossibleBlockers == 2 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 2, this.defendingOpponent))) {
|
||||||
canBeBlocked = true;
|
canBeBlocked = true;
|
||||||
}
|
}
|
||||||
// decide if the creature should attack based on the prevailing strategy choice in aiAggression
|
// decide if the creature should attack based on the prevailing strategy choice in aiAggression
|
||||||
|
|||||||
@@ -180,11 +180,9 @@ public class AiBlockController {
|
|||||||
|
|
||||||
// Good Blocks means a good trade or no trade
|
// Good Blocks means a good trade or no trade
|
||||||
private void makeGoodBlocks(final Combat combat) {
|
private void makeGoodBlocks(final Combat combat) {
|
||||||
|
|
||||||
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
||||||
|
|
||||||
for (final Card attacker : attackersLeft) {
|
for (final Card attacker : attackersLeft) {
|
||||||
|
|
||||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
||||||
|| 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.")
|
||||||
|| attacker.hasKeyword(Keyword.MENACE)) {
|
|| attacker.hasKeyword(Keyword.MENACE)) {
|
||||||
@@ -192,7 +190,6 @@ public class AiBlockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Card blocker = null;
|
Card blocker = null;
|
||||||
|
|
||||||
final List<Card> blockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
|
final List<Card> blockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
|
||||||
|
|
||||||
final List<Card> safeBlockers = getSafeBlockers(combat, attacker, blockers);
|
final List<Card> safeBlockers = getSafeBlockers(combat, attacker, blockers);
|
||||||
@@ -305,7 +302,6 @@ public class AiBlockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Card blocker = null;
|
Card blocker = null;
|
||||||
|
|
||||||
final List<Card> blockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
|
final List<Card> blockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
|
||||||
|
|
||||||
for (Card b : blockers) {
|
for (Card b : blockers) {
|
||||||
@@ -584,12 +580,10 @@ public class AiBlockController {
|
|||||||
* @param combat a {@link forge.game.combat.Combat} object.
|
* @param combat a {@link forge.game.combat.Combat} object.
|
||||||
*/
|
*/
|
||||||
private void makeTradeBlocks(final Combat combat) {
|
private void makeTradeBlocks(final Combat combat) {
|
||||||
|
|
||||||
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
||||||
List<Card> killingBlockers;
|
List<Card> killingBlockers;
|
||||||
|
|
||||||
for (final Card attacker : attackersLeft) {
|
for (final Card attacker : attackersLeft) {
|
||||||
|
|
||||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
||||||
|| attacker.hasKeyword(Keyword.MENACE)
|
|| attacker.hasKeyword(Keyword.MENACE)
|
||||||
|| 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.")) {
|
||||||
@@ -625,7 +619,6 @@ public class AiBlockController {
|
|||||||
|
|
||||||
// Chump Blocks (should only be made if life is in danger)
|
// Chump Blocks (should only be made if life is in danger)
|
||||||
private void makeChumpBlocks(final Combat combat) {
|
private void makeChumpBlocks(final Combat combat) {
|
||||||
|
|
||||||
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
||||||
|
|
||||||
makeChumpBlocks(combat, currentAttackers);
|
makeChumpBlocks(combat, currentAttackers);
|
||||||
@@ -636,7 +629,6 @@ public class AiBlockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void makeChumpBlocks(final Combat combat, List<Card> attackers) {
|
private void makeChumpBlocks(final Combat combat, List<Card> attackers) {
|
||||||
|
|
||||||
if (attackers.isEmpty() || !ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
if (attackers.isEmpty() || !ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -691,11 +683,9 @@ public class AiBlockController {
|
|||||||
|
|
||||||
// Block creatures with "can't be blocked except by two or more creatures"
|
// Block creatures with "can't be blocked except by two or more creatures"
|
||||||
private void makeMultiChumpBlocks(final Combat combat) {
|
private void makeMultiChumpBlocks(final Combat combat) {
|
||||||
|
|
||||||
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
||||||
|
|
||||||
for (final Card attacker : currentAttackers) {
|
for (final Card attacker : currentAttackers) {
|
||||||
|
|
||||||
if (!attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
if (!attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
||||||
&& !attacker.hasKeyword(Keyword.MENACE)
|
&& !attacker.hasKeyword(Keyword.MENACE)
|
||||||
&& !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.")) {
|
||||||
@@ -727,7 +717,6 @@ public class AiBlockController {
|
|||||||
|
|
||||||
/** Reinforce blockers blocking attackers with trample (should only be made if life is in danger) */
|
/** Reinforce blockers blocking attackers with trample (should only be made if life is in danger) */
|
||||||
private void reinforceBlockersAgainstTrample(final Combat combat) {
|
private void reinforceBlockersAgainstTrample(final Combat combat) {
|
||||||
|
|
||||||
List<Card> chumpBlockers;
|
List<Card> chumpBlockers;
|
||||||
|
|
||||||
List<Card> tramplingAttackers = CardLists.getKeyword(attackers, Keyword.TRAMPLE);
|
List<Card> tramplingAttackers = CardLists.getKeyword(attackers, Keyword.TRAMPLE);
|
||||||
@@ -760,7 +749,6 @@ public class AiBlockController {
|
|||||||
|
|
||||||
/** Support blockers not destroying the attacker with more blockers to try to kill the attacker */
|
/** Support blockers not destroying the attacker with more blockers to try to kill the attacker */
|
||||||
private void reinforceBlockersToKill(final Combat combat) {
|
private void reinforceBlockersToKill(final Combat combat) {
|
||||||
|
|
||||||
List<Card> safeBlockers;
|
List<Card> safeBlockers;
|
||||||
List<Card> blockers;
|
List<Card> blockers;
|
||||||
List<Card> targetAttackers = CardLists.filter(blockedButUnkilled, Predicates.not(rampagesOrNeedsManyToBlock));
|
List<Card> targetAttackers = CardLists.filter(blockedButUnkilled, Predicates.not(rampagesOrNeedsManyToBlock));
|
||||||
|
|||||||
@@ -614,7 +614,6 @@ public class AiController {
|
|||||||
sa.setActivatingPlayer(player);
|
sa.setActivatingPlayer(player);
|
||||||
// check everything necessary
|
// check everything necessary
|
||||||
|
|
||||||
|
|
||||||
AiPlayDecision opinion = canPlayAndPayFor(currentSA);
|
AiPlayDecision opinion = canPlayAndPayFor(currentSA);
|
||||||
//PhaseHandler ph = game.getPhaseHandler();
|
//PhaseHandler ph = game.getPhaseHandler();
|
||||||
// System.out.printf("Ai thinks '%s' of %s @ %s %s >>> \n", opinion, sa, Lang.getPossesive(ph.getPlayerTurn().getName()), ph.getPhase());
|
// System.out.printf("Ai thinks '%s' of %s @ %s %s >>> \n", opinion, sa, Lang.getPossesive(ph.getPlayerTurn().getName()), ph.getPhase());
|
||||||
@@ -1726,10 +1725,8 @@ public class AiController {
|
|||||||
for (int i = 0; i < numToExile; i++) {
|
for (int i = 0; i < numToExile; i++) {
|
||||||
Card chosen = null;
|
Card chosen = null;
|
||||||
for (final Card c : grave) { // Exile noncreatures first in
|
for (final Card c : grave) { // Exile noncreatures first in
|
||||||
// case we can revive. Might
|
// case we can revive. Might wanna do some additional
|
||||||
// wanna do some additional
|
// checking here for Flashback and the like.
|
||||||
// checking here for Flashback
|
|
||||||
// and the like.
|
|
||||||
if (!c.isCreature()) {
|
if (!c.isCreature()) {
|
||||||
chosen = c;
|
chosen = c;
|
||||||
break;
|
break;
|
||||||
@@ -1998,7 +1995,6 @@ public class AiController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// this is where the computer cheats
|
// this is where the computer cheats
|
||||||
// changes AllZone.getComputerPlayer().getZone(Zone.Library)
|
// changes AllZone.getComputerPlayer().getZone(Zone.Library)
|
||||||
|
|
||||||
@@ -2278,8 +2274,7 @@ public class AiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI logic for choosing which replacement effect to apply
|
// AI logic for choosing which replacement effect to apply happens here.
|
||||||
// happens here.
|
|
||||||
return Iterables.getFirst(list, null);
|
return Iterables.getFirst(list, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2432,8 +2432,7 @@ public class ComputerUtil {
|
|||||||
if (!source.canReceiveCounters(p1p1Type)) {
|
if (!source.canReceiveCounters(p1p1Type)) {
|
||||||
return opponent ? "Feather" : "Quill";
|
return opponent ? "Feather" : "Quill";
|
||||||
}
|
}
|
||||||
// if source is not on the battlefield anymore, choose +1/+1
|
// if source is not on the battlefield anymore, choose +1/+1 ones
|
||||||
// ones
|
|
||||||
if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) {
|
if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) {
|
||||||
return opponent ? "Feather" : "Quill";
|
return opponent ? "Feather" : "Quill";
|
||||||
}
|
}
|
||||||
@@ -2850,7 +2849,6 @@ public class ComputerUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean lifegainNegative(final Player player, final Card source, final int n) {
|
public static boolean lifegainNegative(final Player player, final Card source, final int n) {
|
||||||
|
|
||||||
if (!player.canGainLife()) {
|
if (!player.canGainLife()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ public class ComputerUtilCombat {
|
|||||||
*/
|
*/
|
||||||
public static int resultingPoison(final Player ai, final Combat combat) {
|
public static int resultingPoison(final Player ai, final Combat combat) {
|
||||||
|
|
||||||
// ai can't get poision counters, so the value can't change
|
// ai can't get poison counters, so the value can't change
|
||||||
if (!ai.canReceiveCounters(CounterEnumType.POISON)) {
|
if (!ai.canReceiveCounters(CounterEnumType.POISON)) {
|
||||||
return ai.getPoisonCounters();
|
return ai.getPoisonCounters();
|
||||||
}
|
}
|
||||||
@@ -491,8 +491,7 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean lifeInSeriousDanger(final Player ai, final Combat combat, final int payment) {
|
public static boolean lifeInSeriousDanger(final Player ai, final Combat combat, final int payment) {
|
||||||
// life in danger only cares about the player's life. Not about a
|
// life in danger only cares about the player's life. Not about a Planeswalkers life
|
||||||
// Planeswalkers life
|
|
||||||
if (ai.cantLose() || combat == null) {
|
if (ai.cantLose() || combat == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -567,8 +566,7 @@ public class ComputerUtilCombat {
|
|||||||
return damage;
|
return damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This calculates the amount of damage a blocker in a blockgang can deal to
|
// This calculates the amount of damage a blocker in a blockgang can deal to the attacker
|
||||||
// the attacker
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* dealsDamageAsBlocker.
|
* dealsDamageAsBlocker.
|
||||||
@@ -581,7 +579,6 @@ public class ComputerUtilCombat {
|
|||||||
* @return a int.
|
* @return a int.
|
||||||
*/
|
*/
|
||||||
public static int dealsDamageAsBlocker(final Card attacker, final Card defender) {
|
public static int dealsDamageAsBlocker(final Card attacker, final Card defender) {
|
||||||
|
|
||||||
int defenderDamage = predictDamageByBlockerWithoutDoubleStrike(attacker, defender);
|
int defenderDamage = predictDamageByBlockerWithoutDoubleStrike(attacker, defender);
|
||||||
|
|
||||||
if (defender.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
if (defender.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
@@ -646,7 +643,6 @@ public class ComputerUtilCombat {
|
|||||||
* @return a int.
|
* @return a int.
|
||||||
*/
|
*/
|
||||||
public static int totalShieldDamage(final Card attacker, final List<Card> defenders) {
|
public static int totalShieldDamage(final Card attacker, final List<Card> defenders) {
|
||||||
|
|
||||||
int defenderDefense = 0;
|
int defenderDefense = 0;
|
||||||
|
|
||||||
for (final Card defender : defenders) {
|
for (final Card defender : defenders) {
|
||||||
@@ -670,7 +666,6 @@ public class ComputerUtilCombat {
|
|||||||
* @return a int.
|
* @return a int.
|
||||||
*/
|
*/
|
||||||
public static int shieldDamage(final Card attacker, final Card blocker) {
|
public static int shieldDamage(final Card attacker, final Card blocker) {
|
||||||
|
|
||||||
if (ComputerUtilCombat.canDestroyBlockerBeforeFirstStrike(blocker, attacker, false)) {
|
if (ComputerUtilCombat.canDestroyBlockerBeforeFirstStrike(blocker, attacker, false)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -931,8 +926,7 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Game game = attacker.getGame();
|
final Game game = attacker.getGame();
|
||||||
// look out for continuous static abilities that only care for blocking
|
// look out for continuous static abilities that only care for blocking creatures
|
||||||
// creatures
|
|
||||||
final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command));
|
final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command));
|
||||||
for (final Card card : cardList) {
|
for (final Card card : cardList) {
|
||||||
for (final StaticAbility stAb : card.getStaticAbilities()) {
|
for (final StaticAbility stAb : card.getStaticAbilities()) {
|
||||||
@@ -1232,8 +1226,7 @@ public class ComputerUtilCombat {
|
|||||||
theTriggers.addAll(blocker.getTriggers());
|
theTriggers.addAll(blocker.getTriggers());
|
||||||
}
|
}
|
||||||
|
|
||||||
// look out for continuous static abilities that only care for attacking
|
// look out for continuous static abilities that only care for attacking creatures
|
||||||
// creatures
|
|
||||||
if (!withoutCombatStaticAbilities) {
|
if (!withoutCombatStaticAbilities) {
|
||||||
final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command));
|
final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command));
|
||||||
for (final Card card : cardList) {
|
for (final Card card : cardList) {
|
||||||
@@ -1420,8 +1413,7 @@ public class ComputerUtilCombat {
|
|||||||
theTriggers.addAll(blocker.getTriggers());
|
theTriggers.addAll(blocker.getTriggers());
|
||||||
}
|
}
|
||||||
|
|
||||||
// look out for continuous static abilities that only care for attacking
|
// look out for continuous static abilities that only care for attacking creatures
|
||||||
// creatures
|
|
||||||
if (!withoutCombatStaticAbilities) {
|
if (!withoutCombatStaticAbilities) {
|
||||||
final CardCollectionView cardList = game.getCardsIn(ZoneType.Battlefield);
|
final CardCollectionView cardList = game.getCardsIn(ZoneType.Battlefield);
|
||||||
for (final Card card : cardList) {
|
for (final Card card : cardList) {
|
||||||
@@ -2256,7 +2248,6 @@ public class ComputerUtilCombat {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public final static int predictDamageTo(final Player target, final int damage, final Card source, final boolean isCombat) {
|
public final static int predictDamageTo(final Player target, final int damage, final Card source, final boolean isCombat) {
|
||||||
|
|
||||||
final Game game = target.getGame();
|
final Game game = target.getGame();
|
||||||
int restDamage = damage;
|
int restDamage = damage;
|
||||||
|
|
||||||
@@ -2317,13 +2308,7 @@ public class ComputerUtilCombat {
|
|||||||
// This function helps the AI calculate the actual amount of damage an
|
// This function helps the AI calculate the actual amount of damage an
|
||||||
// effect would deal
|
// effect would deal
|
||||||
public final static int predictDamageTo(final Card target, final int damage, final Card source, final boolean isCombat) {
|
public final static int predictDamageTo(final Card target, final int damage, final Card source, final boolean isCombat) {
|
||||||
|
return predictDamageTo(target, damage, 0, source, isCombat);
|
||||||
int restDamage = damage;
|
|
||||||
|
|
||||||
restDamage = target.staticReplaceDamage(restDamage, source, isCombat);
|
|
||||||
restDamage = target.staticDamagePrevention(restDamage, 0, source, isCombat);
|
|
||||||
|
|
||||||
return restDamage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2345,7 +2330,6 @@ public class ComputerUtilCombat {
|
|||||||
* @return a int.
|
* @return a int.
|
||||||
*/
|
*/
|
||||||
public final static int predictDamageTo(final Card target, final int damage, final int possiblePrevention, final Card source, final boolean isCombat) {
|
public final static int predictDamageTo(final Card target, final int damage, final int possiblePrevention, final Card source, final boolean isCombat) {
|
||||||
|
|
||||||
int restDamage = damage;
|
int restDamage = damage;
|
||||||
|
|
||||||
restDamage = target.staticReplaceDamage(restDamage, source, isCombat);
|
restDamage = target.staticReplaceDamage(restDamage, source, isCombat);
|
||||||
@@ -2355,7 +2339,6 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final static boolean dealsFirstStrikeDamage(final Card combatant, final boolean withoutAbilities, final Combat combat) {
|
public final static boolean dealsFirstStrikeDamage(final Card combatant, final boolean withoutAbilities, final Combat combat) {
|
||||||
|
|
||||||
if (combatant.hasKeyword(Keyword.DOUBLE_STRIKE) || combatant.hasKeyword(Keyword.FIRST_STRIKE)) {
|
if (combatant.hasKeyword(Keyword.DOUBLE_STRIKE) || combatant.hasKeyword(Keyword.FIRST_STRIKE)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2479,20 +2462,6 @@ public class ComputerUtilCombat {
|
|||||||
return afflictDmg > attacker.getNetPower() || afflictDmg >= aiDefender.getLife();
|
return afflictDmg > attacker.getNetPower() || afflictDmg >= aiDefender.getLife();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMaxAttackersFor(final GameEntity defender) {
|
|
||||||
if (defender instanceof Player) {
|
|
||||||
for (final Card card : ((Player) defender).getCardsIn(ZoneType.Battlefield)) {
|
|
||||||
if (card.hasKeyword("No more than one creature can attack you each combat.")) {
|
|
||||||
return 1;
|
|
||||||
} else if (card.hasKeyword("No more than two creatures can attack you each combat.")) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Card> categorizeAttackersByEvasion(List<Card> attackers) {
|
public static List<Card> categorizeAttackersByEvasion(List<Card> attackers) {
|
||||||
List<Card> categorizedAttackers = Lists.newArrayList();
|
List<Card> categorizedAttackers = Lists.newArrayList();
|
||||||
|
|
||||||
@@ -2582,5 +2551,3 @@ public class ComputerUtilCombat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1079,7 +1079,10 @@ public class CombatUtil {
|
|||||||
} // canBlock()
|
} // canBlock()
|
||||||
|
|
||||||
public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount, Combat combat) {
|
public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount, Combat combat) {
|
||||||
if( amount == 0 )
|
return canAttackerBeBlockedWithAmount(attacker, amount, combat != null ? combat.getDefenderPlayerByAttacker(attacker) : null);
|
||||||
|
}
|
||||||
|
public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount, Player defender) {
|
||||||
|
if(amount == 0 )
|
||||||
return false; // no block
|
return false; // no block
|
||||||
|
|
||||||
List<String> restrictions = Lists.newArrayList();
|
List<String> restrictions = Lists.newArrayList();
|
||||||
@@ -1098,18 +1101,7 @@ public class CombatUtil {
|
|||||||
if (Expressions.compare(amount, operator, operand) )
|
if (Expressions.compare(amount, operator, operand) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (combat != null && attacker.hasKeyword("CARDNAME can't be blocked " +
|
if (defender != null && attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) {
|
||||||
"unless all creatures defending player controls block it.")) {
|
|
||||||
Player defender = combat.getDefenderPlayerByAttacker(attacker);
|
|
||||||
if (defender == null) {
|
|
||||||
// TODO: a better fix is needed here (to prevent a hard NPE, e.g. when the AI attacks with Tromokratis).
|
|
||||||
System.out.println("Warning: defender was 'null' in CombatUtil::canAttackerBeBlockedWithAmount for the card " + attacker + ", attempting to deduce defender.");
|
|
||||||
defender = combat.getDefendingPlayers().getFirst();
|
|
||||||
if (defender == null) {
|
|
||||||
System.out.println("Warning: it was impossible to deduce the defending player in CombatUtil#canAttackerBeBlockedWithAmount, returning 'true' (safest default).");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return amount >= defender.getCreaturesInPlay().size();
|
return amount >= defender.getCreaturesInPlay().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user