- * Sorts a List
- * getBestArtifactAI. - *
- * - * @param list - * @return a {@link forge.game.card.Card} object. - */ - public static Card getBestArtifactAI(final List- * getBestEnchantmentAI. - *
- * - * @param list - * @param spell - * a {@link forge.game.card.Card} object. - * @param targeted - * a boolean. - * @return a {@link forge.game.card.Card} object. - */ - public static Card getBestEnchantmentAI(final List- * getBestLandAI. - *
- * - * @param list - * @return a {@link forge.game.card.Card} object. - */ - public static Card getBestLandAI(final Iterable- * getCheapestPermanentAI. - *
- * - * @param all - * @param spell - * a {@link forge.game.card.Card} object. - * @param targeted - * a boolean. - * @return a {@link forge.game.card.Card} object. - */ - public static Card getCheapestPermanentAI(Iterable- * getBestAI. - *
- * - * @param list - * @return a {@link forge.game.card.Card} object. - */ - public static Card getBestAI(final Iterable- * getWorstCreatureAI. - *
- * - * @param list - * @return a {@link forge.game.card.Card} object. - */ - public static Card getWorstCreatureAI(final Iterable- * getBestCreatureToBounceAI. - *
- * - * @param list - * @return a {@link forge.game.card.Card} object. - */ - public static Card getBestCreatureToBounceAI(final CardCollectionView list) { - final int tokenBonus = 60; - Card biggest = null; - int biggestvalue = -1; - - for (Card card : CardLists.filter(list, CardPredicates.Presets.CREATURES)) { - int newvalue = ComputerUtilCard.evaluateCreature(card); - newvalue += card.isToken() ? tokenBonus : 0; // raise the value of tokens - - if (biggestvalue < newvalue) { - biggest = card; - biggestvalue = newvalue; - } - } - return biggest; - } - - /** - *- * getWorstAI. - *
- * - * @param list - * @return a {@link forge.game.card.Card} object. - */ - public static Card getWorstAI(final Iterable- * getWorstPermanentAI. - *
- * - * @param list - * @param biasEnch - * a boolean. - * @param biasLand - * a boolean. - * @param biasArt - * a boolean. - * @param biasCreature - * a boolean. - * @return a {@link forge.game.card.Card} object. - */ - public static Card getWorstPermanentAI(final Iterable- * evaluateCreature. - *
- * - * @param c - * a {@link forge.game.card.Card} object. - * @return a int. - */ - public static int evaluateCreature(final Card c) { - return creatureEvaluator.evaluateCreature(c); - } - - public static int evaluateCreature(final Card c, final boolean considerPT, final boolean considerCMC) { - return creatureEvaluator.evaluateCreature(c, considerPT, considerCMC); - } - - public static int evaluatePermanentList(final CardCollectionView list) { - int value = 0; - for (int i = 0; i < list.size(); i++) { - value += list.get(i).getCMC() + 1; - } - return value; - } - - public static int evaluateCreatureList(final CardCollectionView list) { - return Aggregates.sum(list, creatureEvaluator); - } - - public static Map- * getMostProminentCreatureType. - *
- * - * @param list - * @return a {@link java.lang.String} object. - */ - public static String getMostProminentCreatureType(final CardCollectionView list) { - return getMostProminentType(list, CardType.getAllCreatureTypes()); - } - - public static String getMostProminentType(final CardCollectionView list, final List- * getMostProminentColor. - *
- * - * @param list - * @return a {@link java.lang.String} object. - */ - public static String getMostProminentColor(final Iterable- * getWorstLand. - *
- * - * @param lands - * @return a {@link forge.game.card.Card} object. - */ - public static Card getWorstLand(final List
+ * Sorts a List
+ * getBestArtifactAI. + *
+ * + * @param list + * @return a {@link forge.game.card.Card} object. + */ + public static Card getBestArtifactAI(final List+ * getBestEnchantmentAI. + *
+ * + * @param list + * @param spell + * a {@link forge.game.card.Card} object. + * @param targeted + * a boolean. + * @return a {@link forge.game.card.Card} object. + */ + public static Card getBestEnchantmentAI(final List+ * getBestLandAI. + *
+ * + * @param list + * @return a {@link forge.game.card.Card} object. + */ + public static Card getBestLandAI(final Iterable+ * getCheapestPermanentAI. + *
+ * + * @param all + * @param spell + * a {@link forge.game.card.Card} object. + * @param targeted + * a boolean. + * @return a {@link forge.game.card.Card} object. + */ + public static Card getCheapestPermanentAI(Iterable+ * getBestAI. + *
+ * + * @param list + * @return a {@link forge.game.card.Card} object. + */ + public static Card getBestAI(final Iterable+ * getWorstCreatureAI. + *
+ * + * @param list + * @return a {@link forge.game.card.Card} object. + */ + public static Card getWorstCreatureAI(final Iterable+ * getBestCreatureToBounceAI. + *
+ * + * @param list + * @return a {@link forge.game.card.Card} object. + */ + public static Card getBestCreatureToBounceAI(final CardCollectionView list) { + final int tokenBonus = 60; + Card biggest = null; + int biggestvalue = -1; + + for (Card card : CardLists.filter(list, CardPredicates.Presets.CREATURES)) { + int newvalue = ComputerUtilCard.evaluateCreature(card); + newvalue += card.isToken() ? tokenBonus : 0; // raise the value of tokens + + if (biggestvalue < newvalue) { + biggest = card; + biggestvalue = newvalue; + } + } + return biggest; + } + + /** + *+ * getWorstAI. + *
+ * + * @param list + * @return a {@link forge.game.card.Card} object. + */ + public static Card getWorstAI(final Iterable+ * getWorstPermanentAI. + *
+ * + * @param list + * @param biasEnch + * a boolean. + * @param biasLand + * a boolean. + * @param biasArt + * a boolean. + * @param biasCreature + * a boolean. + * @return a {@link forge.game.card.Card} object. + */ + public static Card getWorstPermanentAI(final Iterable+ * evaluateCreature. + *
+ * + * @param c + * a {@link forge.game.card.Card} object. + * @return a int. + */ + public static int evaluateCreature(final Card c) { + return creatureEvaluator.evaluateCreature(c); + } + + public static int evaluateCreature(final Card c, final boolean considerPT, final boolean considerCMC) { + return creatureEvaluator.evaluateCreature(c, considerPT, considerCMC); + } + + public static int evaluatePermanentList(final CardCollectionView list) { + int value = 0; + for (int i = 0; i < list.size(); i++) { + value += list.get(i).getCMC() + 1; + } + return value; + } + + public static int evaluateCreatureList(final CardCollectionView list) { + return Aggregates.sum(list, creatureEvaluator); + } + + public static Map+ * getMostProminentCreatureType. + *
+ * + * @param list + * @return a {@link java.lang.String} object. + */ + public static String getMostProminentCreatureType(final CardCollectionView list) { + return getMostProminentType(list, CardType.getAllCreatureTypes()); + } + + public static String getMostProminentType(final CardCollectionView list, final List+ * getMostProminentColor. + *
+ * + * @param list + * @return a {@link java.lang.String} object. + */ + public static String getMostProminentColor(final Iterable+ * getWorstLand. + *
+ * + * @param lands + * @return a {@link forge.game.card.Card} object. + */ + public static Card getWorstLand(final List- * ComputerCombatUtil class. - *
- * - * @author Forge - * @version $Id: ComputerUtil.java 19179 2013-01-25 18:48:29Z Max mtg $ - */ -public class ComputerUtilCombat { - - // A special flag used in ComputerUtil#canRegenerate to avoid recursive reentry and stack overflow - private static boolean dontTestRegen = false; - public static void setCombatRegenTestSuppression(boolean shouldSuppress) { - dontTestRegen = shouldSuppress; - } - - /** - *- * canAttackNextTurn. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @return a boolean. - */ - public static boolean canAttackNextTurn(final Card attacker) { - final Iterable- * canAttackNextTurn. - *
- * - * @param atacker - * a {@link forge.game.card.Card} object. - * @param defender - * the defending {@link GameEntity}. - * @return a boolean. - */ - public static boolean canAttackNextTurn(final Card atacker, final GameEntity defender) { - if (!atacker.isCreature()) { - return false; - } - if (!CombatUtil.canAttackNextTurn(atacker, defender)) { - return false; - } - - for (final KeywordInterface inst : atacker.getKeywords()) { - final String keyword = inst.getOriginal(); - if (keyword.startsWith("CARDNAME attacks specific player each combat if able")) { - final String defined = keyword.split(":")[1]; - final Player player = AbilityUtils.getDefinedPlayers(atacker, defined, null).get(0); - if (!defender.equals(player)) { - return false; - } - } - } - - // The creature won't untap next turn - if (atacker.isTapped() && !Untap.canUntap(atacker)) { - return false; - } - - return true; - } // canAttackNextTurn(Card, GameEntity) - - /** - *- * getTotalFirstStrikeBlockPower. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param player - * a {@link forge.game.player.Player} object. - * @return a int. - */ - public static int getTotalFirstStrikeBlockPower(final Card attacker, final Player player) { - final Card att = attacker; - - List- * getAttack. - *
- * - * @param c - * a {@link forge.game.card.Card} object. - * @return a int. - */ - public static int getAttack(final Card c) { - int n = c.getNetCombatDamage(); - - if (c.hasDoubleStrike()) { - n *= 2; - } - - return n; - } - - - // Returns the damage an unblocked attacker would deal - /** - *- * damageIfUnblocked. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param attacked - * a {@link forge.game.player.Player} object. - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a int. - */ - public static int damageIfUnblocked(final Card attacker, final Player attacked, final Combat combat, boolean withoutAbilities) { - int damage = attacker.getNetCombatDamage(); - int sum = 0; - if (!attacked.canLoseLife()) { - return 0; - } - - if (!attacked.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noPrevention)) { - // ask ReplacementDamage directly - if (isCombatDamagePrevented(attacker, attacked, damage)) { - return 0; - } - } - - damage += ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, null, combat, withoutAbilities); - if (!attacker.hasKeyword("Infect")) { - sum = ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true); - if (attacker.hasKeyword("Double Strike")) { - sum += ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true); - } - } - return sum; - } - - // Returns the poison an unblocked attacker would deal - /** - *- * poisonIfUnblocked. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param attacked - * a {@link forge.game.player.Player} object. - * @return a int. - */ - public static int poisonIfUnblocked(final Card attacker, final Player attacked) { - int damage = attacker.getNetCombatDamage(); - int poison = 0; - damage += ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, null, null, false); - if (attacker.hasKeyword("Infect")) { - poison += ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true); - if (attacker.hasKeyword("Double Strike")) { - poison += ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true); - } - } - if (attacker.hasKeyword("Poisonous") && (damage > 0)) { - poison += attacker.getKeywordMagnitude("Poisonous"); - } - return poison; - } - - // Returns the damage unblocked attackers would deal - /** - *- * sumDamageIfUnblocked. - *
- * - * @param attackers - * @param attacked - * a {@link forge.game.player.Player} object. - * @return a int. - */ - public static int sumDamageIfUnblocked(final Iterable- * sumPoisonIfUnblocked. - *
- * - * @param attackers - * @param attacked - * a {@link forge.game.player.Player} object. - * @return a int. - */ - public static int sumPoisonIfUnblocked(final List- * lifeThatWouldRemain. - *
- * - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a int. - */ - public static int lifeThatWouldRemain(final Player ai, final Combat combat) { - - int damage = 0; - - final List- * resultingPoison. - *
- * - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a int. - */ - public static int resultingPoison(final Player ai, final Combat combat) { - - int poison = 0; - - final List- * lifeInDanger. - *
- * - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a boolean. - */ - public static boolean lifeInDanger(final Player ai, final Combat combat) { - // life in danger only cares about the player's life. Not Planeswalkers' life - if (ai.cantLose() || combat == null || combat.getAttackingPlayer() == ai) { - return false; - } - - CardCollectionView otb = ai.getCardsIn(ZoneType.Battlefield); - // Special cases: - // AI can't lose in combat in presence of Worship (with creatures) - if (!CardLists.filter(otb, CardPredicates.nameEquals("Worship")).isEmpty() && !ai.getCreaturesInPlay().isEmpty()) { - return false; - } - // AI can't lose in combat in presence of Elderscale Wurm (at 7 life or more) - if (!CardLists.filter(otb, CardPredicates.nameEquals("Elderscale Wurm")).isEmpty() && ai.getLife() >= 7) { - return false; - } - - - // check for creatures that must be blocked - final List- * wouldLoseLife. - *
- * - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a boolean. - */ - public static boolean wouldLoseLife(final Player ai, final Combat combat) { - - return (ComputerUtilCombat.lifeThatWouldRemain(ai, combat) < ai.getLife()); - } - - // Checks if the life of the attacked Player/Planeswalker is in danger - /** - *- * lifeInSeriousDanger. - *
- * - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a boolean. - */ - public static boolean lifeInSeriousDanger(final Player ai, final Combat combat) { - // life in danger only cares about the player's life. Not about a - // Planeswalkers life - if (ai.cantLose() || combat == null) { - return false; - } - - final List- * totalDamageOfBlockers. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param defenders - * @return a int. - */ - public static int totalDamageOfBlockers(final Card attacker, final List- * dealsDamageAsBlocker. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param defender - * a {@link forge.game.card.Card} object. - * @return a int. - */ - public static int dealsDamageAsBlocker(final Card attacker, final Card defender) { - - int defenderDamage = predictDamageByBlockerWithoutDoubleStrike(attacker, defender); - - if (defender.hasKeyword("Double Strike")) { - defenderDamage += predictDamageTo(attacker, defenderDamage, defender, true); - } - - return defenderDamage; - } - - /** - * Predicts the damage to an attacker by a defending creature without double-strike. - * @param attacker - * @param defender - * @return - */ - private static int predictDamageByBlockerWithoutDoubleStrike(final Card attacker, final Card defender) { - if (attacker.getName().equals("Sylvan Basilisk") && !defender.hasKeyword("Indestructible")) { - return 0; - } - - int flankingMagnitude = 0; - if (attacker.hasKeyword("Flanking") && !defender.hasKeyword("Flanking")) { - - flankingMagnitude = attacker.getAmountOfKeyword("Flanking"); - - if (flankingMagnitude >= defender.getNetToughness()) { - return 0; - } - if ((flankingMagnitude >= (defender.getNetToughness() - defender.getDamage())) - && !defender.hasKeyword("Indestructible")) { - return 0; - } - - } // flanking - if (attacker.hasKeyword("Indestructible") && !(defender.hasKeyword("Wither") || defender.hasKeyword("Infect"))) { - return 0; - } - - int defenderDamage; - if (defender.toughnessAssignsDamage()) { - defenderDamage = defender.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, defender, true); - } else { - defenderDamage = defender.getNetPower() + ComputerUtilCombat.predictPowerBonusOfBlocker(attacker, defender, true); - } - - // consider static Damage Prevention - defenderDamage = predictDamageTo(attacker, defenderDamage, defender, true); - return defenderDamage; - } - - // This calculates the amount of damage a blocker in a blockgang can take - // from the attacker (for trampling attackers) - /** - *- * totalShieldDamage. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param defenders - * @return a int. - */ - public static int totalShieldDamage(final Card attacker, final List- * shieldDamage. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param blocker - * a {@link forge.game.card.Card} object. - * @return a int. - */ - public static int shieldDamage(final Card attacker, final Card blocker) { - - if (ComputerUtilCombat.canDestroyBlockerBeforeFirstStrike(blocker, attacker, false)) { - return 0; - } - - int flankingMagnitude = 0; - if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) { - - flankingMagnitude = attacker.getAmountOfKeyword("Flanking"); - - if (flankingMagnitude >= blocker.getNetToughness()) { - return 0; - } - if ((flankingMagnitude >= (blocker.getNetToughness() - blocker.getDamage())) - && !blocker.hasKeyword("Indestructible")) { - return 0; - } - - } // flanking - - final int defBushidoMagnitude = blocker.getKeywordMagnitude("Bushido"); - - final int defenderDefense = (blocker.getLethalDamage() - flankingMagnitude) + defBushidoMagnitude; - - return defenderDefense; - } // shieldDamage - - // For AI safety measures like Regeneration - /** - *- * combatantWouldBeDestroyed. - *
- * @param ai - * - * @param combatant - * a {@link forge.game.card.Card} object. - * @return a boolean. - */ - public static boolean combatantWouldBeDestroyed(Player ai, final Card combatant, Combat combat) { - - if (combat.isAttacking(combatant)) { - return ComputerUtilCombat.attackerWouldBeDestroyed(ai, combatant, combat); - } - if (combat.isBlocking(combatant)) { - return ComputerUtilCombat.blockerWouldBeDestroyed(ai, combatant, combat); - } - return false; - } - - // For AI safety measures like Regeneration - /** - *- * attackerWouldBeDestroyed. - *
- * @param ai - * - * @param attacker - * a {@link forge.game.card.Card} object. - * @return a boolean. - */ - public static boolean attackerWouldBeDestroyed(Player ai, final Card attacker, Combat combat) { - final List- * combatTriggerWillTrigger. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param defender - * a {@link forge.game.card.Card} object. - * @param trigger - * a {@link forge.game.trigger.Trigger} object. - * @param combat - * a {@link forge.game.combat.Combat} object. - * @return a boolean. - */ - public static boolean combatTriggerWillTrigger(final Card attacker, final Card defender, final Trigger trigger, - Combat combat) { - final Game game = attacker.getGame(); - final Map- * predictPowerBonusOfBlocker. - *
- * - * @param attacker - * a {@link forge.game.card.Card} object. - * @param blocker - * a {@link forge.game.card.Card} object. - * @return a int. - */ - public static int predictPowerBonusOfBlocker(final Card attacker, final Card blocker, boolean withoutAbilities) { - int power = 0; - - // Apparently, Flanking is predicted below from a trigger, so using the code below results in double - // application of power bonus. A bit more testing may be needed though, so commenting out for now. - /* - if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) { - power -= attacker.getAmountOfKeyword("Flanking"); - }*/ - - // Serene Master switches power with attacker - if (blocker.getName().equals("Serene Master")) { - power += attacker.getNetPower() - blocker.getNetPower(); - } else if (blocker.getName().equals("Shape Stealer")) { - power += attacker.getNetPower() - blocker.getNetPower(); - } - - // if the attacker has first strike and wither the blocker will deal - // less damage than expected - if (dealsFirstStrikeDamage(attacker, withoutAbilities, null) - && (attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect")) - && !dealsFirstStrikeDamage(blocker, withoutAbilities, null) - && !blocker.hasKeyword("CARDNAME can't have counters put on it.")) { - power -= attacker.getNetCombatDamage(); - } - - final Game game = attacker.getGame(); - // look out for continuous static abilities that only care for blocking - // creatures - final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command)); - for (final Card card : cardList) { - for (final StaticAbility stAb : card.getStaticAbilities()) { - final Map